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

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

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 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 <string>
10 #include <type_traits>
11 #include <vector>
12
13 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
14 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
15 #include "mojo/public/cpp/bindings/lib/bounds_checker.h"
16 #include "mojo/public/cpp/bindings/lib/buffer.h"
17 #include "mojo/public/cpp/bindings/lib/map_data_internal.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 // TODO(vardhan): Get rid of the following 2 functions.
34 std::string MakeMessageWithArrayIndex(const char* message,
35 size_t size,
36 size_t index);
37
38 std::string MakeMessageWithExpectedArraySize(const char* message,
39 size_t size,
40 size_t expected_size);
41
42 template <typename T>
43 struct ArrayDataTraits {
44 typedef T StorageType;
45 typedef T& Ref;
46 typedef T const& ConstRef;
47
48 static const uint32_t kMaxNumElements =
49 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
50
51 static uint32_t GetStorageSize(uint32_t num_elements) {
52 MOJO_DCHECK(num_elements <= kMaxNumElements);
53 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
54 }
55 static Ref ToRef(StorageType* storage, size_t offset) {
56 return storage[offset];
57 }
58 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
59 return storage[offset];
60 }
61 };
62
63 template <typename P, bool is_union>
64 struct ObjectStorageType;
65
66 template <typename P>
67 struct ObjectStorageType<P, true> {
68 typedef P Type;
69 };
70
71 template <typename P>
72 struct ObjectStorageType<P, false> {
73 typedef StructPointer<P> Type;
74 };
75
76 template <typename P>
77 struct ArrayDataTraits<P*> {
78 typedef typename ObjectStorageType<P, IsUnionDataType<P>::value>::Type
79 StorageType;
80 typedef P*& Ref;
81 typedef P* const& ConstRef;
82
83 static const uint32_t kMaxNumElements =
84 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
85
86 static uint32_t GetStorageSize(uint32_t num_elements) {
87 MOJO_DCHECK(num_elements <= kMaxNumElements);
88 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
89 }
90 static Ref ToRef(StorageType* storage, size_t offset) {
91 return storage[offset].ptr;
92 }
93 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
94 return storage[offset].ptr;
95 }
96 };
97
98 template <typename T>
99 struct ArrayDataTraits<Array_Data<T>*> {
100 typedef ArrayPointer<T> StorageType;
101 typedef Array_Data<T>*& Ref;
102 typedef Array_Data<T>* const& ConstRef;
103
104 static const uint32_t kMaxNumElements =
105 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
106
107 static uint32_t GetStorageSize(uint32_t num_elements) {
108 MOJO_DCHECK(num_elements <= kMaxNumElements);
109 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
110 }
111 static Ref ToRef(StorageType* storage, size_t offset) {
112 return storage[offset].ptr;
113 }
114 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
115 return storage[offset].ptr;
116 }
117 };
118
119 // Specialization of Arrays for bools, optimized for space. It has the
120 // following differences from a generalized Array:
121 // * Each element takes up a single bit of memory.
122 // * Accessing a non-const single element uses a helper class |BitRef|, which
123 // emulates a reference to a bool.
124 template <>
125 struct ArrayDataTraits<bool> {
126 // Helper class to emulate a reference to a bool, used for direct element
127 // access.
128 class BitRef {
129 public:
130 ~BitRef();
131 BitRef& operator=(bool value);
132 BitRef& operator=(const BitRef& value);
133 operator bool() const;
134
135 private:
136 friend struct ArrayDataTraits<bool>;
137 BitRef(uint8_t* storage, uint8_t mask);
138 BitRef();
139 uint8_t* storage_;
140 uint8_t mask_;
141 };
142
143 // Because each element consumes only 1/8 byte.
144 static const uint32_t kMaxNumElements = kMaxUint32;
145
146 typedef uint8_t StorageType;
147 typedef BitRef Ref;
148 typedef bool ConstRef;
149
150 static uint32_t GetStorageSize(uint32_t num_elements) {
151 return sizeof(ArrayHeader) + ((num_elements + 7) / 8);
152 }
153 static BitRef ToRef(StorageType* storage, size_t offset) {
154 return BitRef(&storage[offset / 8], 1 << (offset % 8));
155 }
156 static bool ToConstRef(const StorageType* storage, size_t offset) {
157 return (storage[offset / 8] & (1 << (offset % 8))) != 0;
158 }
159 };
160
161 // What follows is code to support the serialization of Array_Data<T>. There
162 // are two interesting cases: arrays of primitives/unions, arrays of non-union
163 // objects (structs, arrays and maps).
164 // Arrays of non-union objects are represented as arrays of pointers to objects.
165 // Arrays of primitives or unions are represented as arrays of the values
166 // themselves.
167
168 template <typename T, bool is_handle, bool is_union>
169 struct ArraySerializationHelper;
170
171 template <typename T>
172 struct ArraySerializationHelper<T, false, false> {
173 typedef typename ArrayDataTraits<T>::StorageType ElementType;
174
175 static void EncodePointersAndHandles(const ArrayHeader* header,
176 ElementType* elements,
177 std::vector<Handle>* handles) {}
178
179 static void DecodePointersAndHandles(const ArrayHeader* header,
180 ElementType* elements,
181 std::vector<Handle>* handles) {}
182
183 static ValidationError ValidateElements(
184 const ArrayHeader* header,
185 const ElementType* elements,
186 BoundsChecker* bounds_checker,
187 const ArrayValidateParams* validate_params,
188 std::string* err) {
189 MOJO_DCHECK(!validate_params->element_is_nullable)
190 << "Primitive type should be non-nullable";
191 MOJO_DCHECK(!validate_params->element_validate_params)
192 << "Primitive type should not have array validate params";
193 return ValidationError::NONE;
194 }
195 };
196
197 template <>
198 struct ArraySerializationHelper<Handle, true, false> {
199 typedef ArrayDataTraits<Handle>::StorageType ElementType;
200
201 static void EncodePointersAndHandles(const ArrayHeader* header,
202 ElementType* elements,
203 std::vector<Handle>* handles);
204
205 static void DecodePointersAndHandles(const ArrayHeader* header,
206 ElementType* elements,
207 std::vector<Handle>* handles);
208
209 static ValidationError ValidateElements(
210 const ArrayHeader* header,
211 const ElementType* elements,
212 BoundsChecker* bounds_checker,
213 const ArrayValidateParams* validate_params,
214 std::string* err) {
215 MOJO_DCHECK(!validate_params->element_validate_params)
216 << "Handle type should not have array validate params";
217
218 for (uint32_t i = 0; i < header->num_elements; ++i) {
219 if (!validate_params->element_is_nullable &&
220 elements[i].value() == kEncodedInvalidHandleValue) {
221 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
222 << "invalid handle in array expecting valid handles (array size="
223 << header->num_elements << ", index = " << i << ")";
224 return ValidationError::UNEXPECTED_INVALID_HANDLE;
225 }
226 if (!bounds_checker->ClaimHandle(elements[i])) {
227 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "";
228 return ValidationError::ILLEGAL_HANDLE;
229 }
230 }
231 return ValidationError::NONE;
232 }
233 };
234
235 template <typename H>
236 struct ArraySerializationHelper<H, true, false> {
237 typedef typename ArrayDataTraits<H>::StorageType ElementType;
238
239 static void EncodePointersAndHandles(const ArrayHeader* header,
240 ElementType* elements,
241 std::vector<Handle>* handles) {
242 ArraySerializationHelper<Handle, true, false>::EncodePointersAndHandles(
243 header, elements, handles);
244 }
245
246 static void DecodePointersAndHandles(const ArrayHeader* header,
247 ElementType* elements,
248 std::vector<Handle>* handles) {
249 ArraySerializationHelper<Handle, true, false>::DecodePointersAndHandles(
250 header, elements, handles);
251 }
252
253 static ValidationError ValidateElements(
254 const ArrayHeader* header,
255 const ElementType* elements,
256 BoundsChecker* bounds_checker,
257 const ArrayValidateParams* validate_params,
258 std::string* err) {
259 return ArraySerializationHelper<Handle, true, false>::ValidateElements(
260 header, elements, bounds_checker, validate_params, err);
261 }
262 };
263
264 template <typename P>
265 struct ArraySerializationHelper<P*, false, false> {
266 typedef typename ArrayDataTraits<P*>::StorageType ElementType;
267
268 static void EncodePointersAndHandles(const ArrayHeader* header,
269 ElementType* elements,
270 std::vector<Handle>* handles) {
271 for (uint32_t i = 0; i < header->num_elements; ++i)
272 Encode(&elements[i], handles);
273 }
274
275 static void DecodePointersAndHandles(const ArrayHeader* header,
276 ElementType* elements,
277 std::vector<Handle>* handles) {
278 for (uint32_t i = 0; i < header->num_elements; ++i)
279 Decode(&elements[i], handles);
280 }
281
282 static ValidationError ValidateElements(
283 const ArrayHeader* header,
284 const ElementType* elements,
285 BoundsChecker* bounds_checker,
286 const ArrayValidateParams* validate_params,
287 std::string* err) {
288 for (uint32_t i = 0; i < header->num_elements; ++i) {
289 if (!validate_params->element_is_nullable && !elements[i].offset) {
290 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
291 << "null in array expecting valid pointers (size="
292 << header->num_elements << ", index = " << i << ")";
293 return ValidationError::UNEXPECTED_NULL_POINTER;
294 }
295
296 if (!ValidateEncodedPointer(&elements[i].offset)) {
297 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "";
298 return ValidationError::ILLEGAL_POINTER;
299 }
300
301 auto retval = ValidateCaller<P>::Run(
302 DecodePointerRaw(&elements[i].offset), bounds_checker,
303 validate_params->element_validate_params, err);
304 if (retval != ValidationError::NONE)
305 return retval;
306 }
307 return ValidationError::NONE;
308 }
309
310 private:
311 template <typename T>
312 struct ValidateCaller {
313 static ValidationError Run(const void* data,
314 BoundsChecker* bounds_checker,
315 const ArrayValidateParams* validate_params,
316 std::string* err) {
317 MOJO_DCHECK(!validate_params)
318 << "Struct type should not have array validate params";
319
320 return T::Validate(data, bounds_checker, err);
321 }
322 };
323
324 template <typename Key, typename Value>
325 struct ValidateCaller<Map_Data<Key, Value>> {
326 static ValidationError Run(const void* data,
327 BoundsChecker* bounds_checker,
328 const ArrayValidateParams* validate_params,
329 std::string* err) {
330 return Map_Data<Key, Value>::Validate(data, bounds_checker,
331 validate_params, err);
332 }
333 };
334
335 template <typename T>
336 struct ValidateCaller<Array_Data<T>> {
337 static ValidationError Run(const void* data,
338 BoundsChecker* bounds_checker,
339 const ArrayValidateParams* validate_params,
340 std::string* err) {
341 return Array_Data<T>::Validate(data, bounds_checker, validate_params,
342 err);
343 }
344 };
345 };
346
347 // Array Serialization Helper for unions.
348 template <typename P>
349 struct ArraySerializationHelper<P, false, true> {
350 typedef P ElementType;
351
352 static void EncodePointersAndHandles(const ArrayHeader* header,
353 ElementType* elements,
354 std::vector<Handle>* handles) {
355 for (uint32_t i = 0; i < header->num_elements; ++i)
356 elements[i].EncodePointersAndHandles(handles);
357 }
358
359 static void DecodePointersAndHandles(const ArrayHeader* header,
360 ElementType* elements,
361 std::vector<Handle>* handles) {
362 for (uint32_t i = 0; i < header->num_elements; ++i)
363 elements[i].DecodePointersAndHandles(handles);
364 }
365
366 static ValidationError ValidateElements(
367 const ArrayHeader* header,
368 const ElementType* elements,
369 BoundsChecker* bounds_checker,
370 const ArrayValidateParams* validate_params,
371 std::string* err) {
372 MOJO_DCHECK(!validate_params->element_validate_params)
373 << "Union type should not have array validate params";
374 for (uint32_t i = 0; i < header->num_elements; ++i) {
375 if (!validate_params->element_is_nullable && elements[i].is_null()) {
376 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
377 << "null union in array expecting non-null unions (size="
378 << header->num_elements << ", index = " << i << ")";
379 return ValidationError::UNEXPECTED_NULL_UNION;
380 }
381
382 auto retval = ElementType::Validate(
383 static_cast<const void*>(&elements[i]), bounds_checker, true, err);
384 if (retval != ValidationError::NONE)
385 return retval;
386 }
387 return ValidationError::NONE;
388 }
389 };
390
391 template <typename T>
392 class Array_Data {
393 public:
394 typedef ArrayDataTraits<T> Traits;
395 typedef typename Traits::StorageType StorageType;
396 typedef typename Traits::Ref Ref;
397 typedef typename Traits::ConstRef ConstRef;
398 typedef ArraySerializationHelper<
399 T,
400 IsHandle<T>::value,
401 IsUnionDataType<typename std::remove_pointer<T>::type>::value> Helper;
402
403 // Returns null if |num_elements| or the corresponding storage size cannot be
404 // stored in uint32_t.
405 static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
406 if (num_elements > Traits::kMaxNumElements)
407 return nullptr;
408
409 uint32_t num_bytes =
410 Traits::GetStorageSize(static_cast<uint32_t>(num_elements));
411 return new (buf->Allocate(num_bytes))
412 Array_Data<T>(num_bytes, static_cast<uint32_t>(num_elements));
413 }
414
415 static ValidationError Validate(const void* data,
416 BoundsChecker* bounds_checker,
417 const ArrayValidateParams* validate_params,
418 std::string* err) {
419 if (!data)
420 return ValidationError::NONE;
421 if (!IsAligned(data)) {
422 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "";
423 return ValidationError::MISALIGNED_OBJECT;
424 }
425 if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
426 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "";
427 return ValidationError::ILLEGAL_MEMORY_RANGE;
428 }
429
430 const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
431 if (header->num_elements > Traits::kMaxNumElements ||
432 header->num_bytes < Traits::GetStorageSize(header->num_elements)) {
433 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "";
434 return ValidationError::UNEXPECTED_ARRAY_HEADER;
435 }
436
437 if (validate_params->expected_num_elements != 0 &&
438 header->num_elements != validate_params->expected_num_elements) {
439 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
440 << "fixed-size array has wrong number of elements (size="
441 << header->num_elements
442 << ", expected size=" << validate_params->expected_num_elements
443 << ")";
444 return ValidationError::UNEXPECTED_ARRAY_HEADER;
445 }
446
447 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
448 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "";
449 return ValidationError::ILLEGAL_MEMORY_RANGE;
450 }
451
452 const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
453 return Helper::ValidateElements(&object->header_, object->storage(),
454 bounds_checker, validate_params, err);
455 }
456
457 size_t size() const { return header_.num_elements; }
458
459 Ref at(size_t offset) {
460 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
461 return Traits::ToRef(storage(), offset);
462 }
463
464 ConstRef at(size_t offset) const {
465 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
466 return Traits::ToConstRef(storage(), offset);
467 }
468
469 StorageType* storage() {
470 return reinterpret_cast<StorageType*>(reinterpret_cast<char*>(this) +
471 sizeof(*this));
472 }
473
474 const StorageType* storage() const {
475 return reinterpret_cast<const StorageType*>(
476 reinterpret_cast<const char*>(this) + sizeof(*this));
477 }
478
479 void EncodePointersAndHandles(std::vector<Handle>* handles) {
480 Helper::EncodePointersAndHandles(&header_, storage(), handles);
481 }
482
483 void DecodePointersAndHandles(std::vector<Handle>* handles) {
484 Helper::DecodePointersAndHandles(&header_, storage(), handles);
485 }
486
487 private:
488 Array_Data(uint32_t num_bytes, uint32_t num_elements) {
489 header_.num_bytes = num_bytes;
490 header_.num_elements = num_elements;
491 }
492 ~Array_Data() = delete;
493
494 internal::ArrayHeader header_;
495
496 // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
497 };
498 static_assert(sizeof(Array_Data<char>) == 8, "Bad sizeof(Array_Data)");
499
500 // UTF-8 encoded
501 typedef Array_Data<char> String_Data;
502
503 template <typename T, bool kIsMoveOnlyType>
504 struct ArrayTraits {};
505
506 template <typename T>
507 struct ArrayTraits<T, false> {
508 typedef typename std::vector<T>::const_reference ForwardType;
509 static inline void PushBack(std::vector<T>* vec, ForwardType value) {
510 vec->push_back(value);
511 }
512 static inline void Clone(const std::vector<T>& src_vec,
513 std::vector<T>* dest_vec) {
514 dest_vec->assign(src_vec.begin(), src_vec.end());
515 }
516 };
517
518 template <typename T>
519 struct ArrayTraits<T, true> {
520 typedef T ForwardType;
521 static inline void PushBack(std::vector<T>* vec, T& value) {
522 vec->push_back(value.Pass());
523 }
524 static inline void Clone(const std::vector<T>& src_vec,
525 std::vector<T>* dest_vec) {
526 dest_vec->resize(src_vec.size());
527 for (size_t i = 0; i < src_vec.size(); ++i)
528 dest_vec->at(i) = src_vec.at(i).Clone();
529 }
530 };
531
532 template <>
533 struct WrapperTraits<String, false> {
534 typedef String_Data* DataType;
535 };
536
537 } // namespace internal
538 } // namespace mojo
539
540 #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