Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Side by Side Diff: mojo/public/cpp/bindings/lib/array_internal.h

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/public/cpp/bindings/lib/TODO ('k') | mojo/public/cpp/bindings/lib/array_internal.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
7
8 #include <new>
9 #include <vector>
10
11 #include "mojo/public/c/system/macros.h"
12 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
13 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
14 #include "mojo/public/cpp/bindings/lib/bounds_checker.h"
15 #include "mojo/public/cpp/bindings/lib/buffer.h"
16 #include "mojo/public/cpp/bindings/lib/map_data_internal.h"
17 #include "mojo/public/cpp/bindings/lib/template_util.h"
18 #include "mojo/public/cpp/bindings/lib/validate_params.h"
19 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
20 #include "mojo/public/cpp/environment/logging.h"
21
22 namespace mojo {
23 template <typename T>
24 class Array;
25 class String;
26
27 namespace internal {
28
29 // std::numeric_limits<uint32_t>::max() is not a compile-time constant (until
30 // C++11).
31 const uint32_t kMaxUint32 = 0xFFFFFFFF;
32
33 std::string MakeMessageWithArrayIndex(const char* message,
34 size_t size,
35 size_t index);
36
37 std::string MakeMessageWithExpectedArraySize(const char* message,
38 size_t size,
39 size_t expected_size);
40
41 template <typename T>
42 struct ArrayDataTraits {
43 typedef T StorageType;
44 typedef T& Ref;
45 typedef T const& ConstRef;
46
47 static const uint32_t kMaxNumElements =
48 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
49
50 static uint32_t GetStorageSize(uint32_t num_elements) {
51 MOJO_DCHECK(num_elements <= kMaxNumElements);
52 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
53 }
54 static Ref ToRef(StorageType* storage, size_t offset) {
55 return storage[offset];
56 }
57 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
58 return storage[offset];
59 }
60 };
61
62 template <typename P>
63 struct ArrayDataTraits<P*> {
64 typedef StructPointer<P> StorageType;
65 typedef P*& Ref;
66 typedef P* const& ConstRef;
67
68 static const uint32_t kMaxNumElements =
69 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
70
71 static uint32_t GetStorageSize(uint32_t num_elements) {
72 MOJO_DCHECK(num_elements <= kMaxNumElements);
73 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
74 }
75 static Ref ToRef(StorageType* storage, size_t offset) {
76 return storage[offset].ptr;
77 }
78 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
79 return storage[offset].ptr;
80 }
81 };
82
83 template <typename T>
84 struct ArrayDataTraits<Array_Data<T>*> {
85 typedef ArrayPointer<T> StorageType;
86 typedef Array_Data<T>*& Ref;
87 typedef Array_Data<T>* const& ConstRef;
88
89 static const uint32_t kMaxNumElements =
90 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
91
92 static uint32_t GetStorageSize(uint32_t num_elements) {
93 MOJO_DCHECK(num_elements <= kMaxNumElements);
94 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
95 }
96 static Ref ToRef(StorageType* storage, size_t offset) {
97 return storage[offset].ptr;
98 }
99 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
100 return storage[offset].ptr;
101 }
102 };
103
104 // Specialization of Arrays for bools, optimized for space. It has the
105 // following differences from a generalized Array:
106 // * Each element takes up a single bit of memory.
107 // * Accessing a non-const single element uses a helper class |BitRef|, which
108 // emulates a reference to a bool.
109 template <>
110 struct ArrayDataTraits<bool> {
111 // Helper class to emulate a reference to a bool, used for direct element
112 // access.
113 class BitRef {
114 public:
115 ~BitRef();
116 BitRef& operator=(bool value);
117 BitRef& operator=(const BitRef& value);
118 operator bool() const;
119
120 private:
121 friend struct ArrayDataTraits<bool>;
122 BitRef(uint8_t* storage, uint8_t mask);
123 BitRef();
124 uint8_t* storage_;
125 uint8_t mask_;
126 };
127
128 // Because each element consumes only 1/8 byte.
129 static const uint32_t kMaxNumElements = kMaxUint32;
130
131 typedef uint8_t StorageType;
132 typedef BitRef Ref;
133 typedef bool ConstRef;
134
135 static uint32_t GetStorageSize(uint32_t num_elements) {
136 return sizeof(ArrayHeader) + ((num_elements + 7) / 8);
137 }
138 static BitRef ToRef(StorageType* storage, size_t offset) {
139 return BitRef(&storage[offset / 8], 1 << (offset % 8));
140 }
141 static bool ToConstRef(const StorageType* storage, size_t offset) {
142 return (storage[offset / 8] & (1 << (offset % 8))) != 0;
143 }
144 };
145
146 // What follows is code to support the serialization of Array_Data<T>. There
147 // are two interesting cases: arrays of primitives and arrays of objects.
148 // Arrays of objects are represented as arrays of pointers to objects.
149
150 template <typename T, bool is_handle>
151 struct ArraySerializationHelper;
152
153 template <typename T>
154 struct ArraySerializationHelper<T, false> {
155 typedef typename ArrayDataTraits<T>::StorageType ElementType;
156
157 static void EncodePointersAndHandles(const ArrayHeader* header,
158 ElementType* elements,
159 std::vector<Handle>* handles) {}
160
161 static void DecodePointersAndHandles(const ArrayHeader* header,
162 ElementType* elements,
163 std::vector<Handle>* handles) {}
164
165 template <bool element_is_nullable, typename ElementValidateParams>
166 static bool ValidateElements(const ArrayHeader* header,
167 const ElementType* elements,
168 BoundsChecker* bounds_checker) {
169 static_assert(!element_is_nullable,
170 "Primitive type should be non-nullable");
171 static_assert((IsSame<ElementValidateParams, NoValidateParams>::value),
172 "Primitive type should not have array validate params");
173 return true;
174 }
175 };
176
177 template <>
178 struct ArraySerializationHelper<Handle, true> {
179 typedef ArrayDataTraits<Handle>::StorageType ElementType;
180
181 static void EncodePointersAndHandles(const ArrayHeader* header,
182 ElementType* elements,
183 std::vector<Handle>* handles);
184
185 static void DecodePointersAndHandles(const ArrayHeader* header,
186 ElementType* elements,
187 std::vector<Handle>* handles);
188
189 template <bool element_is_nullable, typename ElementValidateParams>
190 static bool ValidateElements(const ArrayHeader* header,
191 const ElementType* elements,
192 BoundsChecker* bounds_checker) {
193 static_assert((IsSame<ElementValidateParams, NoValidateParams>::value),
194 "Handle type should not have array validate params");
195
196 for (uint32_t i = 0; i < header->num_elements; ++i) {
197 if (!element_is_nullable &&
198 elements[i].value() == kEncodedInvalidHandleValue) {
199 ReportValidationError(
200 VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
201 MakeMessageWithArrayIndex(
202 "invalid handle in array expecting valid handles",
203 header->num_elements,
204 i).c_str());
205 return false;
206 }
207 if (!bounds_checker->ClaimHandle(elements[i])) {
208 ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE);
209 return false;
210 }
211 }
212 return true;
213 }
214 };
215
216 template <typename H>
217 struct ArraySerializationHelper<H, true> {
218 typedef typename ArrayDataTraits<H>::StorageType ElementType;
219
220 static void EncodePointersAndHandles(const ArrayHeader* header,
221 ElementType* elements,
222 std::vector<Handle>* handles) {
223 ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
224 header, elements, handles);
225 }
226
227 static void DecodePointersAndHandles(const ArrayHeader* header,
228 ElementType* elements,
229 std::vector<Handle>* handles) {
230 ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
231 header, elements, handles);
232 }
233
234 template <bool element_is_nullable, typename ElementValidateParams>
235 static bool ValidateElements(const ArrayHeader* header,
236 const ElementType* elements,
237 BoundsChecker* bounds_checker) {
238 return ArraySerializationHelper<Handle, true>::ValidateElements<
239 element_is_nullable,
240 ElementValidateParams>(header, elements, bounds_checker);
241 }
242 };
243
244 template <typename P>
245 struct ArraySerializationHelper<P*, false> {
246 typedef typename ArrayDataTraits<P*>::StorageType ElementType;
247
248 static void EncodePointersAndHandles(const ArrayHeader* header,
249 ElementType* elements,
250 std::vector<Handle>* handles) {
251 for (uint32_t i = 0; i < header->num_elements; ++i)
252 Encode(&elements[i], handles);
253 }
254
255 static void DecodePointersAndHandles(const ArrayHeader* header,
256 ElementType* elements,
257 std::vector<Handle>* handles) {
258 for (uint32_t i = 0; i < header->num_elements; ++i)
259 Decode(&elements[i], handles);
260 }
261
262 template <bool element_is_nullable, typename ElementValidateParams>
263 static bool ValidateElements(const ArrayHeader* header,
264 const ElementType* elements,
265 BoundsChecker* bounds_checker) {
266 for (uint32_t i = 0; i < header->num_elements; ++i) {
267 if (!element_is_nullable && !elements[i].offset) {
268 ReportValidationError(
269 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
270 MakeMessageWithArrayIndex("null in array expecting valid pointers",
271 header->num_elements,
272 i).c_str());
273 return false;
274 }
275 if (!ValidateEncodedPointer(&elements[i].offset)) {
276 ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER);
277 return false;
278 }
279 if (!ValidateCaller<P, ElementValidateParams>::Run(
280 DecodePointerRaw(&elements[i].offset), bounds_checker)) {
281 return false;
282 }
283 }
284 return true;
285 }
286
287 private:
288 template <typename T, typename Params>
289 struct ValidateCaller {
290 static bool Run(const void* data, BoundsChecker* bounds_checker) {
291 static_assert((IsSame<Params, NoValidateParams>::value),
292 "Struct type should not have array validate params");
293
294 return T::Validate(data, bounds_checker);
295 }
296 };
297
298 template <typename Key, typename Value, typename Params>
299 struct ValidateCaller<Map_Data<Key, Value>, Params> {
300 static bool Run(const void* data, BoundsChecker* bounds_checker) {
301 return Map_Data<Key, Value>::template Validate<Params>(data,
302 bounds_checker);
303 }
304 };
305
306 template <typename T, typename Params>
307 struct ValidateCaller<Array_Data<T>, Params> {
308 static bool Run(const void* data, BoundsChecker* bounds_checker) {
309 return Array_Data<T>::template Validate<Params>(data, bounds_checker);
310 }
311 };
312 };
313
314 template <typename T>
315 class Array_Data {
316 public:
317 typedef ArrayDataTraits<T> Traits;
318 typedef typename Traits::StorageType StorageType;
319 typedef typename Traits::Ref Ref;
320 typedef typename Traits::ConstRef ConstRef;
321 typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper;
322
323 // Returns null if |num_elements| or the corresponding storage size cannot be
324 // stored in uint32_t.
325 static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
326 if (num_elements > Traits::kMaxNumElements)
327 return nullptr;
328
329 uint32_t num_bytes =
330 Traits::GetStorageSize(static_cast<uint32_t>(num_elements));
331 return new (buf->Allocate(num_bytes))
332 Array_Data<T>(num_bytes, static_cast<uint32_t>(num_elements));
333 }
334
335 template <typename Params>
336 static bool Validate(const void* data, BoundsChecker* bounds_checker) {
337 if (!data)
338 return true;
339 if (!IsAligned(data)) {
340 ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
341 return false;
342 }
343 if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
344 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
345 return false;
346 }
347 const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
348 if (header->num_elements > Traits::kMaxNumElements ||
349 header->num_bytes < Traits::GetStorageSize(header->num_elements)) {
350 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
351 return false;
352 }
353 if (Params::expected_num_elements != 0 &&
354 header->num_elements != Params::expected_num_elements) {
355 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
356 MakeMessageWithExpectedArraySize(
357 "fixed-size array has wrong number of elements",
358 header->num_elements,
359 Params::expected_num_elements).c_str());
360 return false;
361 }
362 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
363 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
364 return false;
365 }
366
367 const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
368 return Helper::template ValidateElements<
369 Params::element_is_nullable,
370 typename Params::ElementValidateParams>(
371 &object->header_, object->storage(), bounds_checker);
372 }
373
374 size_t size() const { return header_.num_elements; }
375
376 Ref at(size_t offset) {
377 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
378 return Traits::ToRef(storage(), offset);
379 }
380
381 ConstRef at(size_t offset) const {
382 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
383 return Traits::ToConstRef(storage(), offset);
384 }
385
386 StorageType* storage() {
387 return reinterpret_cast<StorageType*>(reinterpret_cast<char*>(this) +
388 sizeof(*this));
389 }
390
391 const StorageType* storage() const {
392 return reinterpret_cast<const StorageType*>(
393 reinterpret_cast<const char*>(this) + sizeof(*this));
394 }
395
396 void EncodePointersAndHandles(std::vector<Handle>* handles) {
397 Helper::EncodePointersAndHandles(&header_, storage(), handles);
398 }
399
400 void DecodePointersAndHandles(std::vector<Handle>* handles) {
401 Helper::DecodePointersAndHandles(&header_, storage(), handles);
402 }
403
404 private:
405 Array_Data(uint32_t num_bytes, uint32_t num_elements) {
406 header_.num_bytes = num_bytes;
407 header_.num_elements = num_elements;
408 }
409 ~Array_Data() = delete;
410
411 internal::ArrayHeader header_;
412
413 // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
414 };
415 static_assert(sizeof(Array_Data<char>) == 8, "Bad sizeof(Array_Data)");
416
417 // UTF-8 encoded
418 typedef Array_Data<char> String_Data;
419
420 template <typename T, bool kIsMoveOnlyType>
421 struct ArrayTraits {};
422
423 template <typename T>
424 struct ArrayTraits<T, false> {
425 typedef T StorageType;
426 typedef typename std::vector<T>::reference RefType;
427 typedef typename std::vector<T>::const_reference ConstRefType;
428 typedef ConstRefType ForwardType;
429 static inline void Initialize(std::vector<T>* vec) {}
430 static inline void Finalize(std::vector<T>* vec) {}
431 static inline ConstRefType at(const std::vector<T>* vec, size_t offset) {
432 return vec->at(offset);
433 }
434 static inline RefType at(std::vector<T>* vec, size_t offset) {
435 return vec->at(offset);
436 }
437 static inline void Resize(std::vector<T>* vec, size_t size) {
438 vec->resize(size);
439 }
440 static inline void PushBack(std::vector<T>* vec, ForwardType value) {
441 vec->push_back(value);
442 }
443 static inline void Clone(const std::vector<T>& src_vec,
444 std::vector<T>* dest_vec) {
445 dest_vec->assign(src_vec.begin(), src_vec.end());
446 }
447 };
448
449 template <typename T>
450 struct ArrayTraits<T, true> {
451 struct StorageType {
452 char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8]; // Make 8-byte aligned.
453 };
454 typedef T& RefType;
455 typedef const T& ConstRefType;
456 typedef T ForwardType;
457 static inline void Initialize(std::vector<StorageType>* vec) {
458 for (size_t i = 0; i < vec->size(); ++i)
459 new (vec->at(i).buf) T();
460 }
461 static inline void Finalize(std::vector<StorageType>* vec) {
462 for (size_t i = 0; i < vec->size(); ++i)
463 reinterpret_cast<T*>(vec->at(i).buf)->~T();
464 }
465 static inline ConstRefType at(const std::vector<StorageType>* vec,
466 size_t offset) {
467 return *reinterpret_cast<const T*>(vec->at(offset).buf);
468 }
469 static inline RefType at(std::vector<StorageType>* vec, size_t offset) {
470 return *reinterpret_cast<T*>(vec->at(offset).buf);
471 }
472 static inline void Resize(std::vector<StorageType>* vec, size_t size) {
473 size_t old_size = vec->size();
474 for (size_t i = size; i < old_size; i++)
475 reinterpret_cast<T*>(vec->at(i).buf)->~T();
476 ResizeStorage(vec, size);
477 for (size_t i = old_size; i < vec->size(); i++)
478 new (vec->at(i).buf) T();
479 }
480 static inline void PushBack(std::vector<StorageType>* vec, RefType value) {
481 size_t old_size = vec->size();
482 ResizeStorage(vec, old_size + 1);
483 new (vec->at(old_size).buf) T(value.Pass());
484 }
485 static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) {
486 if (size <= vec->capacity()) {
487 vec->resize(size);
488 return;
489 }
490 std::vector<StorageType> new_storage(size);
491 for (size_t i = 0; i < vec->size(); i++)
492 new (new_storage.at(i).buf) T(at(vec, i).Pass());
493 vec->swap(new_storage);
494 Finalize(&new_storage);
495 }
496 static inline void Clone(const std::vector<StorageType>& src_vec,
497 std::vector<StorageType>* dest_vec) {
498 Resize(dest_vec, src_vec.size());
499 for (size_t i = 0; i < src_vec.size(); ++i)
500 at(dest_vec, i) = at(&src_vec, i).Clone();
501 }
502 };
503
504 template <>
505 struct WrapperTraits<String, false> {
506 typedef String_Data* DataType;
507 };
508
509 } // namespace internal
510 } // namespace mojo
511
512 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/lib/TODO ('k') | mojo/public/cpp/bindings/lib/array_internal.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698