OLD | NEW |
| (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_ | |
OLD | NEW |