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.
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
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/template_util.h"
17 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
18 #include "mojo/public/cpp/environment/logging.h"
21 template <typename T
> class Array
;
26 // std::numeric_limits<uint32_t>::max() is not a compile-time constant (until
28 const uint32_t kMaxUint32
= 0xFFFFFFFF;
30 std::string
MakeMessageWithArrayIndex(const char* message
,
34 std::string
MakeMessageWithExpectedArraySize(const char* message
,
36 size_t expected_size
);
39 struct ArrayDataTraits
{
40 typedef T StorageType
;
42 typedef T
const& ConstRef
;
44 static const uint32_t kMaxNumElements
=
45 (kMaxUint32
- sizeof(ArrayHeader
)) / sizeof(StorageType
);
47 static uint32_t GetStorageSize(uint32_t num_elements
) {
48 MOJO_DCHECK(num_elements
<= kMaxNumElements
);
49 return sizeof(ArrayHeader
) + sizeof(StorageType
) * num_elements
;
51 static Ref
ToRef(StorageType
* storage
, size_t offset
) {
52 return storage
[offset
];
54 static ConstRef
ToConstRef(const StorageType
* storage
, size_t offset
) {
55 return storage
[offset
];
60 struct ArrayDataTraits
<P
*> {
61 typedef StructPointer
<P
> StorageType
;
63 typedef P
* const& ConstRef
;
65 static const uint32_t kMaxNumElements
=
66 (kMaxUint32
- sizeof(ArrayHeader
)) / sizeof(StorageType
);
68 static uint32_t GetStorageSize(uint32_t num_elements
) {
69 MOJO_DCHECK(num_elements
<= kMaxNumElements
);
70 return sizeof(ArrayHeader
) + sizeof(StorageType
) * num_elements
;
72 static Ref
ToRef(StorageType
* storage
, size_t offset
) {
73 return storage
[offset
].ptr
;
75 static ConstRef
ToConstRef(const StorageType
* storage
, size_t offset
) {
76 return storage
[offset
].ptr
;
81 struct ArrayDataTraits
<Array_Data
<T
>*> {
82 typedef ArrayPointer
<T
> StorageType
;
83 typedef Array_Data
<T
>*& Ref
;
84 typedef Array_Data
<T
>* const& ConstRef
;
86 static const uint32_t kMaxNumElements
=
87 (kMaxUint32
- sizeof(ArrayHeader
)) / sizeof(StorageType
);
89 static uint32_t GetStorageSize(uint32_t num_elements
) {
90 MOJO_DCHECK(num_elements
<= kMaxNumElements
);
91 return sizeof(ArrayHeader
) + sizeof(StorageType
) * num_elements
;
93 static Ref
ToRef(StorageType
* storage
, size_t offset
) {
94 return storage
[offset
].ptr
;
96 static ConstRef
ToConstRef(const StorageType
* storage
, size_t offset
) {
97 return storage
[offset
].ptr
;
101 // Specialization of Arrays for bools, optimized for space. It has the
102 // following differences from a generalized Array:
103 // * Each element takes up a single bit of memory.
104 // * Accessing a non-const single element uses a helper class |BitRef|, which
105 // emulates a reference to a bool.
107 struct ArrayDataTraits
<bool> {
108 // Helper class to emulate a reference to a bool, used for direct element
113 BitRef
& operator=(bool value
);
114 BitRef
& operator=(const BitRef
& value
);
115 operator bool() const;
117 friend struct ArrayDataTraits
<bool>;
118 BitRef(uint8_t* storage
, uint8_t mask
);
124 // Because each element consumes only 1/8 byte.
125 static const uint32_t kMaxNumElements
= kMaxUint32
;
127 typedef uint8_t StorageType
;
129 typedef bool ConstRef
;
131 static uint32_t GetStorageSize(uint32_t num_elements
) {
132 return sizeof(ArrayHeader
) + ((num_elements
+ 7) / 8);
134 static BitRef
ToRef(StorageType
* storage
, size_t offset
) {
135 return BitRef(&storage
[offset
/ 8], 1 << (offset
% 8));
137 static bool ToConstRef(const StorageType
* storage
, size_t offset
) {
138 return (storage
[offset
/ 8] & (1 << (offset
% 8))) != 0;
142 // Array type information needed for valdiation.
143 template <uint32_t in_expected_num_elements
,
144 bool in_element_is_nullable
,
145 typename InElementValidateParams
>
146 class ArrayValidateParams
{
148 // Validation information for elements. It is either another specialization of
149 // ArrayValidateParams (if elements are arrays) or NoValidateParams.
150 typedef InElementValidateParams ElementValidateParams
;
152 // If |expected_num_elements| is not 0, the array is expected to have exactly
153 // that number of elements.
154 static const uint32_t expected_num_elements
= in_expected_num_elements
;
155 // Whether the elements are nullable.
156 static const bool element_is_nullable
= in_element_is_nullable
;
159 // NoValidateParams is used to indicate the end of an ArrayValidateParams chain.
160 class NoValidateParams
{
163 // What follows is code to support the serialization of Array_Data<T>. There
164 // are two interesting cases: arrays of primitives and arrays of objects.
165 // Arrays of objects are represented as arrays of pointers to objects.
167 template <typename T
, bool is_handle
> struct ArraySerializationHelper
;
169 template <typename T
>
170 struct ArraySerializationHelper
<T
, false> {
171 typedef typename ArrayDataTraits
<T
>::StorageType ElementType
;
173 static void EncodePointersAndHandles(const ArrayHeader
* header
,
174 ElementType
* elements
,
175 std::vector
<Handle
>* handles
) {
178 static void DecodePointersAndHandles(const ArrayHeader
* header
,
179 ElementType
* elements
,
180 std::vector
<Handle
>* handles
) {
183 template <bool element_is_nullable
, typename ElementValidateParams
>
184 static bool ValidateElements(const ArrayHeader
* header
,
185 const ElementType
* elements
,
186 BoundsChecker
* bounds_checker
) {
187 MOJO_COMPILE_ASSERT(!element_is_nullable
,
188 Primitive_type_should_be_non_nullable
);
190 (IsSame
<ElementValidateParams
, NoValidateParams
>::value
),
191 Primitive_type_should_not_have_array_validate_params
);
197 struct ArraySerializationHelper
<Handle
, true> {
198 typedef ArrayDataTraits
<Handle
>::StorageType ElementType
;
200 static void EncodePointersAndHandles(const ArrayHeader
* header
,
201 ElementType
* elements
,
202 std::vector
<Handle
>* handles
);
204 static void DecodePointersAndHandles(const ArrayHeader
* header
,
205 ElementType
* elements
,
206 std::vector
<Handle
>* handles
);
208 template <bool element_is_nullable
, typename ElementValidateParams
>
209 static bool ValidateElements(const ArrayHeader
* header
,
210 const ElementType
* elements
,
211 BoundsChecker
* bounds_checker
) {
213 (IsSame
<ElementValidateParams
, NoValidateParams
>::value
),
214 Handle_type_should_not_have_array_validate_params
);
216 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
) {
217 if (!element_is_nullable
&&
218 elements
[i
].value() == kEncodedInvalidHandleValue
) {
219 ReportValidationError(
220 VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE
,
221 MakeMessageWithArrayIndex(
222 "invalid handle in array expecting valid handles",
223 header
->num_elements
, i
).c_str());
226 if (!bounds_checker
->ClaimHandle(elements
[i
])) {
227 ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE
);
235 template <typename H
>
236 struct ArraySerializationHelper
<H
, true> {
237 typedef typename ArrayDataTraits
<H
>::StorageType ElementType
;
239 static void EncodePointersAndHandles(const ArrayHeader
* header
,
240 ElementType
* elements
,
241 std::vector
<Handle
>* handles
) {
242 ArraySerializationHelper
<Handle
, true>::EncodePointersAndHandles(
243 header
, elements
, handles
);
246 static void DecodePointersAndHandles(const ArrayHeader
* header
,
247 ElementType
* elements
,
248 std::vector
<Handle
>* handles
) {
249 ArraySerializationHelper
<Handle
, true>::DecodePointersAndHandles(
250 header
, elements
, handles
);
253 template <bool element_is_nullable
, typename ElementValidateParams
>
254 static bool ValidateElements(const ArrayHeader
* header
,
255 const ElementType
* elements
,
256 BoundsChecker
* bounds_checker
) {
257 return ArraySerializationHelper
<Handle
, true>::
258 ValidateElements
<element_is_nullable
, ElementValidateParams
>(
259 header
, elements
, bounds_checker
);
263 template <typename P
>
264 struct ArraySerializationHelper
<P
*, false> {
265 typedef typename ArrayDataTraits
<P
*>::StorageType ElementType
;
267 static void EncodePointersAndHandles(const ArrayHeader
* header
,
268 ElementType
* elements
,
269 std::vector
<Handle
>* handles
) {
270 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
)
271 Encode(&elements
[i
], handles
);
274 static void DecodePointersAndHandles(const ArrayHeader
* header
,
275 ElementType
* elements
,
276 std::vector
<Handle
>* handles
) {
277 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
)
278 Decode(&elements
[i
], handles
);
281 template <bool element_is_nullable
, typename ElementValidateParams
>
282 static bool ValidateElements(const ArrayHeader
* header
,
283 const ElementType
* elements
,
284 BoundsChecker
* bounds_checker
) {
285 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
) {
286 if (!element_is_nullable
&& !elements
[i
].offset
) {
287 ReportValidationError(
288 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
,
289 MakeMessageWithArrayIndex(
290 "null in array expecting valid pointers",
291 header
->num_elements
, i
).c_str());
294 if (!ValidateEncodedPointer(&elements
[i
].offset
)) {
295 ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER
);
298 if (!ValidateCaller
<P
, ElementValidateParams
>::Run(
299 DecodePointerRaw(&elements
[i
].offset
), bounds_checker
)) {
307 template <typename T
, typename Params
>
308 struct ValidateCaller
{
309 static bool Run(const void* data
, BoundsChecker
* bounds_checker
) {
311 (IsSame
<Params
, NoValidateParams
>::value
),
312 Struct_type_should_not_have_array_validate_params
);
314 return T::Validate(data
, bounds_checker
);
318 template <typename T
, typename Params
>
319 struct ValidateCaller
<Array_Data
<T
>, Params
> {
320 static bool Run(const void* data
, BoundsChecker
* bounds_checker
) {
321 return Array_Data
<T
>::template Validate
<Params
>(data
, bounds_checker
);
326 template <typename T
>
329 typedef ArrayDataTraits
<T
> Traits
;
330 typedef typename
Traits::StorageType StorageType
;
331 typedef typename
Traits::Ref Ref
;
332 typedef typename
Traits::ConstRef ConstRef
;
333 typedef ArraySerializationHelper
<T
, IsHandle
<T
>::value
> Helper
;
335 // Returns NULL if |num_elements| or the corresponding storage size cannot be
336 // stored in uint32_t.
337 static Array_Data
<T
>* New(size_t num_elements
, Buffer
* buf
) {
338 if (num_elements
> Traits::kMaxNumElements
)
342 Traits::GetStorageSize(static_cast<uint32_t>(num_elements
));
343 return new (buf
->Allocate(num_bytes
)) Array_Data
<T
>(
344 num_bytes
, static_cast<uint32_t>(num_elements
));
347 template <typename Params
>
348 static bool Validate(const void* data
, BoundsChecker
* bounds_checker
) {
351 if (!IsAligned(data
)) {
352 ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT
);
355 if (!bounds_checker
->IsValidRange(data
, sizeof(ArrayHeader
))) {
356 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
);
359 const ArrayHeader
* header
= static_cast<const ArrayHeader
*>(data
);
360 if (header
->num_elements
> Traits::kMaxNumElements
||
361 header
->num_bytes
< Traits::GetStorageSize(header
->num_elements
)) {
362 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
);
365 if (Params::expected_num_elements
!= 0 &&
366 header
->num_elements
!= Params::expected_num_elements
) {
367 ReportValidationError(
368 VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
,
369 MakeMessageWithExpectedArraySize(
370 "fixed-size array has wrong number of elements",
371 header
->num_elements
, Params::expected_num_elements
).c_str());
374 if (!bounds_checker
->ClaimMemory(data
, header
->num_bytes
)) {
375 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
);
379 const Array_Data
<T
>* object
= static_cast<const Array_Data
<T
>*>(data
);
380 return Helper::template ValidateElements
<
381 Params::element_is_nullable
, typename
Params::ElementValidateParams
>(
382 &object
->header_
, object
->storage(), bounds_checker
);
385 size_t size() const { return header_
.num_elements
; }
387 Ref
at(size_t offset
) {
388 MOJO_DCHECK(offset
< static_cast<size_t>(header_
.num_elements
));
389 return Traits::ToRef(storage(), offset
);
392 ConstRef
at(size_t offset
) const {
393 MOJO_DCHECK(offset
< static_cast<size_t>(header_
.num_elements
));
394 return Traits::ToConstRef(storage(), offset
);
397 StorageType
* storage() {
398 return reinterpret_cast<StorageType
*>(
399 reinterpret_cast<char*>(this) + sizeof(*this));
402 const StorageType
* storage() const {
403 return reinterpret_cast<const StorageType
*>(
404 reinterpret_cast<const char*>(this) + sizeof(*this));
407 void EncodePointersAndHandles(std::vector
<Handle
>* handles
) {
408 Helper::EncodePointersAndHandles(&header_
, storage(), handles
);
411 void DecodePointersAndHandles(std::vector
<Handle
>* handles
) {
412 Helper::DecodePointersAndHandles(&header_
, storage(), handles
);
416 Array_Data(uint32_t num_bytes
, uint32_t num_elements
) {
417 header_
.num_bytes
= num_bytes
;
418 header_
.num_elements
= num_elements
;
422 internal::ArrayHeader header_
;
424 // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
426 MOJO_COMPILE_ASSERT(sizeof(Array_Data
<char>) == 8, bad_sizeof_Array_Data
);
429 typedef Array_Data
<char> String_Data
;
431 template <typename T
, bool kIsMoveOnlyType
> struct ArrayTraits
{};
433 template <typename T
> struct ArrayTraits
<T
, false> {
434 typedef T StorageType
;
435 typedef typename
std::vector
<T
>::reference RefType
;
436 typedef typename
std::vector
<T
>::const_reference ConstRefType
;
437 typedef ConstRefType ForwardType
;
438 static inline void Initialize(std::vector
<T
>* vec
) {
440 static inline void Finalize(std::vector
<T
>* vec
) {
442 static inline ConstRefType
at(const std::vector
<T
>* vec
, size_t offset
) {
443 return vec
->at(offset
);
445 static inline RefType
at(std::vector
<T
>* vec
, size_t offset
) {
446 return vec
->at(offset
);
448 static inline void Resize(std::vector
<T
>* vec
, size_t size
) {
451 static inline void PushBack(std::vector
<T
>* vec
, ForwardType value
) {
452 vec
->push_back(value
);
456 template <typename T
> struct ArrayTraits
<T
, true> {
458 char buf
[sizeof(T
) + (8 - (sizeof(T
) % 8)) % 8]; // Make 8-byte aligned.
461 typedef const T
& ConstRefType
;
462 typedef T ForwardType
;
463 static inline void Initialize(std::vector
<StorageType
>* vec
) {
464 for (size_t i
= 0; i
< vec
->size(); ++i
)
465 new (vec
->at(i
).buf
) T();
467 static inline void Finalize(std::vector
<StorageType
>* vec
) {
468 for (size_t i
= 0; i
< vec
->size(); ++i
)
469 reinterpret_cast<T
*>(vec
->at(i
).buf
)->~T();
471 static inline ConstRefType
at(const std::vector
<StorageType
>* vec
,
473 return *reinterpret_cast<const T
*>(vec
->at(offset
).buf
);
475 static inline RefType
at(std::vector
<StorageType
>* vec
, size_t offset
) {
476 return *reinterpret_cast<T
*>(vec
->at(offset
).buf
);
478 static inline void Resize(std::vector
<StorageType
>* vec
, size_t size
) {
479 size_t old_size
= vec
->size();
480 for (size_t i
= size
; i
< old_size
; i
++)
481 reinterpret_cast<T
*>(vec
->at(i
).buf
)->~T();
482 ResizeStorage(vec
, size
);
483 for (size_t i
= old_size
; i
< vec
->size(); i
++)
484 new (vec
->at(i
).buf
) T();
486 static inline void PushBack(std::vector
<StorageType
>* vec
, RefType value
) {
487 size_t old_size
= vec
->size();
488 ResizeStorage(vec
, old_size
+ 1);
489 new (vec
->at(old_size
).buf
) T(value
.Pass());
491 static inline void ResizeStorage(std::vector
<StorageType
>* vec
, size_t size
) {
492 if (size
<= vec
->capacity()) {
496 std::vector
<StorageType
> new_storage(size
);
497 for (size_t i
= 0; i
< vec
->size(); i
++)
498 new (new_storage
.at(i
).buf
) T(at(vec
, i
).Pass());
499 vec
->swap(new_storage
);
500 Finalize(&new_storage
);
504 template <> struct WrapperTraits
<String
, false> {
505 typedef String_Data
* DataType
;
508 } // namespace internal
511 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_