Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / public / cpp / bindings / lib / array_internal.h
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/template_util.h"
17 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
18 #include "mojo/public/cpp/environment/logging.h"
19
20 namespace mojo {
21 template <typename T> class Array;
22 class String;
23
24 namespace internal {
25
26 // std::numeric_limits<uint32_t>::max() is not a compile-time constant (until
27 // C++11).
28 const uint32_t kMaxUint32 = 0xFFFFFFFF;
29
30 std::string MakeMessageWithArrayIndex(const char* message,
31                                       size_t size,
32                                       size_t index);
33
34 std::string MakeMessageWithExpectedArraySize(const char* message,
35                                              size_t size,
36                                              size_t expected_size);
37
38 template <typename T>
39 struct ArrayDataTraits {
40   typedef T StorageType;
41   typedef T& Ref;
42   typedef T const& ConstRef;
43
44   static const uint32_t kMaxNumElements =
45       (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
46
47   static uint32_t GetStorageSize(uint32_t num_elements) {
48     MOJO_DCHECK(num_elements <= kMaxNumElements);
49     return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
50   }
51   static Ref ToRef(StorageType* storage, size_t offset) {
52     return storage[offset];
53   }
54   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
55     return storage[offset];
56   }
57 };
58
59 template <typename P>
60 struct ArrayDataTraits<P*> {
61   typedef StructPointer<P> StorageType;
62   typedef P*& Ref;
63   typedef P* const& ConstRef;
64
65   static const uint32_t kMaxNumElements =
66       (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
67
68   static uint32_t GetStorageSize(uint32_t num_elements) {
69     MOJO_DCHECK(num_elements <= kMaxNumElements);
70     return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
71   }
72   static Ref ToRef(StorageType* storage, size_t offset) {
73     return storage[offset].ptr;
74   }
75   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
76     return storage[offset].ptr;
77   }
78 };
79
80 template <typename T>
81 struct ArrayDataTraits<Array_Data<T>*> {
82   typedef ArrayPointer<T> StorageType;
83   typedef Array_Data<T>*& Ref;
84   typedef Array_Data<T>* const& ConstRef;
85
86   static const uint32_t kMaxNumElements =
87       (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
88
89   static uint32_t GetStorageSize(uint32_t num_elements) {
90     MOJO_DCHECK(num_elements <= kMaxNumElements);
91     return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
92   }
93   static Ref ToRef(StorageType* storage, size_t offset) {
94     return storage[offset].ptr;
95   }
96   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
97     return storage[offset].ptr;
98   }
99 };
100
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.
106 template <>
107 struct ArrayDataTraits<bool> {
108   // Helper class to emulate a reference to a bool, used for direct element
109   // access.
110   class BitRef {
111    public:
112     ~BitRef();
113     BitRef& operator=(bool value);
114     BitRef& operator=(const BitRef& value);
115     operator bool() const;
116    private:
117     friend struct ArrayDataTraits<bool>;
118     BitRef(uint8_t* storage, uint8_t mask);
119     BitRef();
120     uint8_t* storage_;
121     uint8_t mask_;
122   };
123
124   // Because each element consumes only 1/8 byte.
125   static const uint32_t kMaxNumElements = kMaxUint32;
126
127   typedef uint8_t StorageType;
128   typedef BitRef Ref;
129   typedef bool ConstRef;
130
131   static uint32_t GetStorageSize(uint32_t num_elements) {
132     return sizeof(ArrayHeader) + ((num_elements + 7) / 8);
133   }
134   static BitRef ToRef(StorageType* storage, size_t offset) {
135     return BitRef(&storage[offset / 8], 1 << (offset % 8));
136   }
137   static bool ToConstRef(const StorageType* storage, size_t offset) {
138     return (storage[offset / 8] & (1 << (offset % 8))) != 0;
139   }
140 };
141
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 {
147  public:
148   // Validation information for elements. It is either another specialization of
149   // ArrayValidateParams (if elements are arrays) or NoValidateParams.
150   typedef InElementValidateParams ElementValidateParams;
151
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;
157 };
158
159 // NoValidateParams is used to indicate the end of an ArrayValidateParams chain.
160 class NoValidateParams {
161 };
162
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.
166
167 template <typename T, bool is_handle> struct ArraySerializationHelper;
168
169 template <typename T>
170 struct ArraySerializationHelper<T, false> {
171   typedef typename ArrayDataTraits<T>::StorageType ElementType;
172
173   static void EncodePointersAndHandles(const ArrayHeader* header,
174                                        ElementType* elements,
175                                        std::vector<Handle>* handles) {
176   }
177
178   static void DecodePointersAndHandles(const ArrayHeader* header,
179                                        ElementType* elements,
180                                        std::vector<Handle>* handles) {
181   }
182
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);
189     MOJO_COMPILE_ASSERT(
190         (IsSame<ElementValidateParams, NoValidateParams>::value),
191         Primitive_type_should_not_have_array_validate_params);
192     return true;
193   }
194 };
195
196 template <>
197 struct ArraySerializationHelper<Handle, true> {
198   typedef ArrayDataTraits<Handle>::StorageType ElementType;
199
200   static void EncodePointersAndHandles(const ArrayHeader* header,
201                                        ElementType* elements,
202                                        std::vector<Handle>* handles);
203
204   static void DecodePointersAndHandles(const ArrayHeader* header,
205                                        ElementType* elements,
206                                        std::vector<Handle>* handles);
207
208   template <bool element_is_nullable, typename ElementValidateParams>
209   static bool ValidateElements(const ArrayHeader* header,
210                                const ElementType* elements,
211                                BoundsChecker* bounds_checker) {
212     MOJO_COMPILE_ASSERT(
213         (IsSame<ElementValidateParams, NoValidateParams>::value),
214         Handle_type_should_not_have_array_validate_params);
215
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());
224         return false;
225       }
226       if (!bounds_checker->ClaimHandle(elements[i])) {
227         ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE);
228         return false;
229       }
230     }
231     return true;
232   }
233 };
234
235 template <typename H>
236 struct ArraySerializationHelper<H, true> {
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>::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>::DecodePointersAndHandles(
250         header, elements, handles);
251   }
252
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);
260   }
261 };
262
263 template <typename P>
264 struct ArraySerializationHelper<P*, false> {
265   typedef typename ArrayDataTraits<P*>::StorageType ElementType;
266
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);
272   }
273
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);
279   }
280
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());
292         return false;
293       }
294       if (!ValidateEncodedPointer(&elements[i].offset)) {
295         ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER);
296         return false;
297       }
298       if (!ValidateCaller<P, ElementValidateParams>::Run(
299               DecodePointerRaw(&elements[i].offset), bounds_checker)) {
300         return false;
301       }
302     }
303     return true;
304   }
305
306  private:
307   template <typename T, typename Params>
308   struct ValidateCaller {
309     static bool Run(const void* data, BoundsChecker* bounds_checker) {
310       MOJO_COMPILE_ASSERT(
311           (IsSame<Params, NoValidateParams>::value),
312           Struct_type_should_not_have_array_validate_params);
313
314       return T::Validate(data, bounds_checker);
315     }
316   };
317
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);
322     }
323   };
324 };
325
326 template <typename T>
327 class Array_Data {
328  public:
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;
334
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)
339       return NULL;
340
341     uint32_t num_bytes =
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));
345   }
346
347   template <typename Params>
348   static bool Validate(const void* data, BoundsChecker* bounds_checker) {
349     if (!data)
350       return true;
351     if (!IsAligned(data)) {
352       ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
353       return false;
354     }
355     if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
356       ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
357       return false;
358     }
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);
363       return false;
364     }
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());
372       return false;
373     }
374     if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
375       ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
376       return false;
377     }
378
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);
383   }
384
385   size_t size() const { return header_.num_elements; }
386
387   Ref at(size_t offset) {
388     MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
389     return Traits::ToRef(storage(), offset);
390   }
391
392   ConstRef at(size_t offset) const {
393     MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
394     return Traits::ToConstRef(storage(), offset);
395   }
396
397   StorageType* storage() {
398     return reinterpret_cast<StorageType*>(
399         reinterpret_cast<char*>(this) + sizeof(*this));
400   }
401
402   const StorageType* storage() const {
403     return reinterpret_cast<const StorageType*>(
404         reinterpret_cast<const char*>(this) + sizeof(*this));
405   }
406
407   void EncodePointersAndHandles(std::vector<Handle>* handles) {
408     Helper::EncodePointersAndHandles(&header_, storage(), handles);
409   }
410
411   void DecodePointersAndHandles(std::vector<Handle>* handles) {
412     Helper::DecodePointersAndHandles(&header_, storage(), handles);
413   }
414
415  private:
416   Array_Data(uint32_t num_bytes, uint32_t num_elements) {
417     header_.num_bytes = num_bytes;
418     header_.num_elements = num_elements;
419   }
420   ~Array_Data() {}
421
422   internal::ArrayHeader header_;
423
424   // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
425 };
426 MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
427
428 // UTF-8 encoded
429 typedef Array_Data<char> String_Data;
430
431 template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {};
432
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) {
439   }
440   static inline void Finalize(std::vector<T>* vec) {
441   }
442   static inline ConstRefType at(const std::vector<T>* vec, size_t offset) {
443     return vec->at(offset);
444   }
445   static inline RefType at(std::vector<T>* vec, size_t offset) {
446     return vec->at(offset);
447   }
448   static inline void Resize(std::vector<T>* vec, size_t size) {
449     vec->resize(size);
450   }
451   static inline void PushBack(std::vector<T>* vec, ForwardType value) {
452     vec->push_back(value);
453   }
454 };
455
456 template <typename T> struct ArrayTraits<T, true> {
457   struct StorageType {
458     char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8];  // Make 8-byte aligned.
459   };
460   typedef T& RefType;
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();
466   }
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();
470   }
471   static inline ConstRefType at(const std::vector<StorageType>* vec,
472                                 size_t offset) {
473     return *reinterpret_cast<const T*>(vec->at(offset).buf);
474   }
475   static inline RefType at(std::vector<StorageType>* vec, size_t offset) {
476     return *reinterpret_cast<T*>(vec->at(offset).buf);
477   }
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();
485   }
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());
490   }
491   static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) {
492     if (size <= vec->capacity()) {
493       vec->resize(size);
494       return;
495     }
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);
501   }
502 };
503
504 template <> struct WrapperTraits<String, false> {
505   typedef String_Data* DataType;
506 };
507
508 }  // namespace internal
509 }  // namespace mojo
510
511 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_