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
;
27 struct ArrayDataTraits
{
28 typedef T StorageType
;
30 typedef T
const& ConstRef
;
32 static size_t GetStorageSize(size_t num_elements
) {
33 return sizeof(StorageType
) * num_elements
;
35 static Ref
ToRef(StorageType
* storage
, size_t offset
) {
36 return storage
[offset
];
38 static ConstRef
ToConstRef(const StorageType
* storage
, size_t offset
) {
39 return storage
[offset
];
44 struct ArrayDataTraits
<P
*> {
45 typedef StructPointer
<P
> StorageType
;
47 typedef P
* const& ConstRef
;
49 static size_t GetStorageSize(size_t num_elements
) {
50 return sizeof(StorageType
) * num_elements
;
52 static Ref
ToRef(StorageType
* storage
, size_t offset
) {
53 return storage
[offset
].ptr
;
55 static ConstRef
ToConstRef(const StorageType
* storage
, size_t offset
) {
56 return storage
[offset
].ptr
;
61 struct ArrayDataTraits
<Array_Data
<T
>*> {
62 typedef ArrayPointer
<T
> StorageType
;
63 typedef Array_Data
<T
>*& Ref
;
64 typedef Array_Data
<T
>* const& ConstRef
;
66 static size_t GetStorageSize(size_t num_elements
) {
67 return sizeof(StorageType
) * num_elements
;
69 static Ref
ToRef(StorageType
* storage
, size_t offset
) {
70 return storage
[offset
].ptr
;
72 static ConstRef
ToConstRef(const StorageType
* storage
, size_t offset
) {
73 return storage
[offset
].ptr
;
77 // Specialization of Arrays for bools, optimized for space. It has the
78 // following differences from a generalized Array:
79 // * Each element takes up a single bit of memory.
80 // * Accessing a non-const single element uses a helper class |BitRef|, which
81 // emulates a reference to a bool.
83 struct ArrayDataTraits
<bool> {
84 // Helper class to emulate a reference to a bool, used for direct element
89 BitRef
& operator=(bool value
);
90 BitRef
& operator=(const BitRef
& value
);
91 operator bool() const;
93 friend struct ArrayDataTraits
<bool>;
94 BitRef(uint8_t* storage
, uint8_t mask
);
100 typedef uint8_t StorageType
;
102 typedef bool ConstRef
;
104 static size_t GetStorageSize(size_t num_elements
) {
105 return ((num_elements
+ 7) / 8);
107 static BitRef
ToRef(StorageType
* storage
, size_t offset
) {
108 return BitRef(&storage
[offset
/ 8], 1 << (offset
% 8));
110 static bool ToConstRef(const StorageType
* storage
, size_t offset
) {
111 return (storage
[offset
/ 8] & (1 << (offset
% 8))) != 0;
115 // Array type information needed for valdiation.
116 template <uint32_t in_expected_num_elements
,
117 bool in_element_nullable
,
118 typename InElementValidateParams
>
119 class ArrayValidateParams
{
121 // Validation information for elements. It is either another specialization of
122 // ArrayValidateParams (if elements are arrays) or NoValidateParams.
123 typedef InElementValidateParams ElementValidateParams
;
125 // If |expected_num_elements| is not 0, the array is expected to have exactly
126 // that number of elements.
127 static const uint32_t expected_num_elements
= in_expected_num_elements
;
128 // Whether the elements are nullable.
129 static const bool element_nullable
= in_element_nullable
;
132 // NoValidateParams is used to indicate the end of an ArrayValidateParams chain.
133 class NoValidateParams
{
136 // What follows is code to support the serialization of Array_Data<T>. There
137 // are two interesting cases: arrays of primitives and arrays of objects.
138 // Arrays of objects are represented as arrays of pointers to objects.
140 template <typename T
, bool is_handle
> struct ArraySerializationHelper
;
142 template <typename T
>
143 struct ArraySerializationHelper
<T
, false> {
144 typedef typename ArrayDataTraits
<T
>::StorageType ElementType
;
146 static void EncodePointersAndHandles(const ArrayHeader
* header
,
147 ElementType
* elements
,
148 std::vector
<Handle
>* handles
) {
151 static void DecodePointersAndHandles(const ArrayHeader
* header
,
152 ElementType
* elements
,
153 std::vector
<Handle
>* handles
) {
156 template <bool element_nullable
, typename ElementValidateParams
>
157 static bool ValidateElements(const ArrayHeader
* header
,
158 const ElementType
* elements
,
159 BoundsChecker
* bounds_checker
) {
160 MOJO_COMPILE_ASSERT(!element_nullable
,
161 Primitive_type_should_be_non_nullable
);
163 (IsSame
<ElementValidateParams
, NoValidateParams
>::value
),
164 Primitive_type_should_not_have_array_validate_params
);
170 struct ArraySerializationHelper
<Handle
, true> {
171 typedef ArrayDataTraits
<Handle
>::StorageType ElementType
;
173 static void EncodePointersAndHandles(const ArrayHeader
* header
,
174 ElementType
* elements
,
175 std::vector
<Handle
>* handles
);
177 static void DecodePointersAndHandles(const ArrayHeader
* header
,
178 ElementType
* elements
,
179 std::vector
<Handle
>* handles
);
181 template <bool element_nullable
, typename ElementValidateParams
>
182 static bool ValidateElements(const ArrayHeader
* header
,
183 const ElementType
* elements
,
184 BoundsChecker
* bounds_checker
) {
186 (IsSame
<ElementValidateParams
, NoValidateParams
>::value
),
187 Handle_type_should_not_have_array_validate_params
);
189 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
) {
190 if (IsNonNullableValidationEnabled() && !element_nullable
&&
191 elements
[i
].value() == kEncodedInvalidHandleValue
) {
192 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE
);
195 if (!bounds_checker
->ClaimHandle(elements
[i
])) {
196 ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE
);
204 template <typename H
>
205 struct ArraySerializationHelper
<H
, true> {
206 typedef typename ArrayDataTraits
<H
>::StorageType ElementType
;
208 static void EncodePointersAndHandles(const ArrayHeader
* header
,
209 ElementType
* elements
,
210 std::vector
<Handle
>* handles
) {
211 ArraySerializationHelper
<Handle
, true>::EncodePointersAndHandles(
212 header
, elements
, handles
);
215 static void DecodePointersAndHandles(const ArrayHeader
* header
,
216 ElementType
* elements
,
217 std::vector
<Handle
>* handles
) {
218 ArraySerializationHelper
<Handle
, true>::DecodePointersAndHandles(
219 header
, elements
, handles
);
222 template <bool element_nullable
, typename ElementValidateParams
>
223 static bool ValidateElements(const ArrayHeader
* header
,
224 const ElementType
* elements
,
225 BoundsChecker
* bounds_checker
) {
226 return ArraySerializationHelper
<Handle
, true>::
227 ValidateElements
<element_nullable
, ElementValidateParams
>(
228 header
, elements
, bounds_checker
);
232 template <typename P
>
233 struct ArraySerializationHelper
<P
*, false> {
234 typedef typename ArrayDataTraits
<P
*>::StorageType ElementType
;
236 static void EncodePointersAndHandles(const ArrayHeader
* header
,
237 ElementType
* elements
,
238 std::vector
<Handle
>* handles
) {
239 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
)
240 Encode(&elements
[i
], handles
);
243 static void DecodePointersAndHandles(const ArrayHeader
* header
,
244 ElementType
* elements
,
245 std::vector
<Handle
>* handles
) {
246 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
)
247 Decode(&elements
[i
], handles
);
250 template <bool element_nullable
, typename ElementValidateParams
>
251 static bool ValidateElements(const ArrayHeader
* header
,
252 const ElementType
* elements
,
253 BoundsChecker
* bounds_checker
) {
254 for (uint32_t i
= 0; i
< header
->num_elements
; ++i
) {
255 if (IsNonNullableValidationEnabled() && !element_nullable
&&
256 !elements
[i
].offset
) {
257 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_NULL_POINTER
);
260 if (!ValidateEncodedPointer(&elements
[i
].offset
)) {
261 ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER
);
264 if (!ValidateCaller
<P
, ElementValidateParams
>::Run(
265 DecodePointerRaw(&elements
[i
].offset
), bounds_checker
)) {
273 template <typename T
, typename Params
>
274 struct ValidateCaller
{
275 static bool Run(const void* data
, BoundsChecker
* bounds_checker
) {
277 (IsSame
<Params
, NoValidateParams
>::value
),
278 Struct_type_should_not_have_array_validate_params
);
280 return T::Validate(data
, bounds_checker
);
284 template <typename T
, typename Params
>
285 struct ValidateCaller
<Array_Data
<T
>, Params
> {
286 static bool Run(const void* data
, BoundsChecker
* bounds_checker
) {
287 return Array_Data
<T
>::template Validate
<Params
>(data
, bounds_checker
);
292 template <typename T
>
295 typedef ArrayDataTraits
<T
> Traits
;
296 typedef typename
Traits::StorageType StorageType
;
297 typedef typename
Traits::Ref Ref
;
298 typedef typename
Traits::ConstRef ConstRef
;
299 typedef ArraySerializationHelper
<T
, IsHandle
<T
>::value
> Helper
;
301 static Array_Data
<T
>* New(size_t num_elements
, Buffer
* buf
) {
302 size_t num_bytes
= sizeof(Array_Data
<T
>) +
303 Traits::GetStorageSize(num_elements
);
304 return new (buf
->Allocate(num_bytes
)) Array_Data
<T
>(num_bytes
,
308 template <typename Params
>
309 static bool Validate(const void* data
, BoundsChecker
* bounds_checker
) {
312 if (!IsAligned(data
)) {
313 ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT
);
316 if (!bounds_checker
->IsValidRange(data
, sizeof(ArrayHeader
))) {
317 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
);
320 const ArrayHeader
* header
= static_cast<const ArrayHeader
*>(data
);
321 if (header
->num_bytes
< (sizeof(Array_Data
<T
>) +
322 Traits::GetStorageSize(header
->num_elements
))) {
323 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
);
326 if (Params::expected_num_elements
!= 0 &&
327 header
->num_elements
!= Params::expected_num_elements
) {
328 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER
);
331 if (!bounds_checker
->ClaimMemory(data
, header
->num_bytes
)) {
332 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE
);
336 const Array_Data
<T
>* object
= static_cast<const Array_Data
<T
>*>(data
);
337 return Helper::template ValidateElements
<
338 Params::element_nullable
, typename
Params::ElementValidateParams
>(
339 &object
->header_
, object
->storage(), bounds_checker
);
342 size_t size() const { return header_
.num_elements
; }
344 Ref
at(size_t offset
) {
345 MOJO_DCHECK(offset
< static_cast<size_t>(header_
.num_elements
));
346 return Traits::ToRef(storage(), offset
);
349 ConstRef
at(size_t offset
) const {
350 MOJO_DCHECK(offset
< static_cast<size_t>(header_
.num_elements
));
351 return Traits::ToConstRef(storage(), offset
);
354 StorageType
* storage() {
355 return reinterpret_cast<StorageType
*>(
356 reinterpret_cast<char*>(this) + sizeof(*this));
359 const StorageType
* storage() const {
360 return reinterpret_cast<const StorageType
*>(
361 reinterpret_cast<const char*>(this) + sizeof(*this));
364 void EncodePointersAndHandles(std::vector
<Handle
>* handles
) {
365 Helper::EncodePointersAndHandles(&header_
, storage(), handles
);
368 void DecodePointersAndHandles(std::vector
<Handle
>* handles
) {
369 Helper::DecodePointersAndHandles(&header_
, storage(), handles
);
373 Array_Data(size_t num_bytes
, size_t num_elements
) {
374 header_
.num_bytes
= static_cast<uint32_t>(num_bytes
);
375 header_
.num_elements
= static_cast<uint32_t>(num_elements
);
379 internal::ArrayHeader header_
;
381 // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
383 MOJO_COMPILE_ASSERT(sizeof(Array_Data
<char>) == 8, bad_sizeof_Array_Data
);
386 typedef Array_Data
<char> String_Data
;
388 template <typename T
, bool kIsMoveOnlyType
> struct ArrayTraits
{};
390 template <typename T
> struct ArrayTraits
<T
, false> {
391 typedef T StorageType
;
392 typedef typename
std::vector
<T
>::reference RefType
;
393 typedef typename
std::vector
<T
>::const_reference ConstRefType
;
394 typedef ConstRefType ForwardType
;
395 static inline void Initialize(std::vector
<T
>* vec
) {
397 static inline void Finalize(std::vector
<T
>* vec
) {
399 static inline ConstRefType
at(const std::vector
<T
>* vec
, size_t offset
) {
400 return vec
->at(offset
);
402 static inline RefType
at(std::vector
<T
>* vec
, size_t offset
) {
403 return vec
->at(offset
);
405 static inline void Resize(std::vector
<T
>* vec
, size_t size
) {
408 static inline void PushBack(std::vector
<T
>* vec
, ForwardType value
) {
409 vec
->push_back(value
);
413 template <typename T
> struct ArrayTraits
<T
, true> {
415 char buf
[sizeof(T
) + (8 - (sizeof(T
) % 8)) % 8]; // Make 8-byte aligned.
418 typedef const T
& ConstRefType
;
419 typedef T ForwardType
;
420 static inline void Initialize(std::vector
<StorageType
>* vec
) {
421 for (size_t i
= 0; i
< vec
->size(); ++i
)
422 new (vec
->at(i
).buf
) T();
424 static inline void Finalize(std::vector
<StorageType
>* vec
) {
425 for (size_t i
= 0; i
< vec
->size(); ++i
)
426 reinterpret_cast<T
*>(vec
->at(i
).buf
)->~T();
428 static inline ConstRefType
at(const std::vector
<StorageType
>* vec
,
430 return *reinterpret_cast<const T
*>(vec
->at(offset
).buf
);
432 static inline RefType
at(std::vector
<StorageType
>* vec
, size_t offset
) {
433 return *reinterpret_cast<T
*>(vec
->at(offset
).buf
);
435 static inline void Resize(std::vector
<StorageType
>* vec
, size_t size
) {
436 size_t old_size
= vec
->size();
437 for (size_t i
= size
; i
< old_size
; i
++)
438 reinterpret_cast<T
*>(vec
->at(i
).buf
)->~T();
439 ResizeStorage(vec
, size
);
440 for (size_t i
= old_size
; i
< vec
->size(); i
++)
441 new (vec
->at(i
).buf
) T();
443 static inline void PushBack(std::vector
<StorageType
>* vec
, RefType value
) {
444 size_t old_size
= vec
->size();
445 ResizeStorage(vec
, old_size
+ 1);
446 new (vec
->at(old_size
).buf
) T(value
.Pass());
448 static inline void ResizeStorage(std::vector
<StorageType
>* vec
, size_t size
) {
449 if (size
<= vec
->capacity()) {
453 std::vector
<StorageType
> new_storage(size
);
454 for (size_t i
= 0; i
< vec
->size(); i
++)
455 new (new_storage
.at(i
).buf
) T(at(vec
, i
).Pass());
456 vec
->swap(new_storage
);
457 Finalize(&new_storage
);
461 template <> struct WrapperTraits
<String
, false> {
462 typedef String_Data
* DataType
;
465 } // namespace internal
468 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_