• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/cpp/bindings/lib/bindings_internal.h"
12 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
13 #include "mojo/public/cpp/bindings/lib/bounds_checker.h"
14 #include "mojo/public/cpp/bindings/lib/buffer.h"
15 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
16 
17 namespace mojo {
18 template <typename T> class Array;
19 class String;
20 
21 namespace internal {
22 
23 template <typename T>
24 struct ArrayDataTraits {
25   typedef T StorageType;
26   typedef T& Ref;
27   typedef T const& ConstRef;
28 
GetStorageSizeArrayDataTraits29   static size_t GetStorageSize(size_t num_elements) {
30     return sizeof(StorageType) * num_elements;
31   }
ToRefArrayDataTraits32   static Ref ToRef(StorageType* storage, size_t offset) {
33     return storage[offset];
34   }
ToConstRefArrayDataTraits35   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
36     return storage[offset];
37   }
38 };
39 
40 template <typename P>
41 struct ArrayDataTraits<P*> {
42   typedef StructPointer<P> StorageType;
43   typedef P*& Ref;
44   typedef P* const& ConstRef;
45 
46   static size_t GetStorageSize(size_t num_elements) {
47     return sizeof(StorageType) * num_elements;
48   }
49   static Ref ToRef(StorageType* storage, size_t offset) {
50     return storage[offset].ptr;
51   }
52   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
53     return storage[offset].ptr;
54   }
55 };
56 
57 template <typename T>
58 struct ArrayDataTraits<Array_Data<T>*> {
59   typedef ArrayPointer<T> StorageType;
60   typedef Array_Data<T>*& Ref;
61   typedef Array_Data<T>* const& ConstRef;
62 
63   static size_t GetStorageSize(size_t num_elements) {
64     return sizeof(StorageType) * num_elements;
65   }
66   static Ref ToRef(StorageType* storage, size_t offset) {
67     return storage[offset].ptr;
68   }
69   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
70     return storage[offset].ptr;
71   }
72 };
73 
74 // Specialization of Arrays for bools, optimized for space. It has the
75 // following differences from a generalized Array:
76 // * Each element takes up a single bit of memory.
77 // * Accessing a non-const single element uses a helper class |BitRef|, which
78 // emulates a reference to a bool.
79 template <>
80 struct ArrayDataTraits<bool> {
81   // Helper class to emulate a reference to a bool, used for direct element
82   // access.
83   class BitRef {
84    public:
85     ~BitRef();
86     BitRef& operator=(bool value);
87     BitRef& operator=(const BitRef& value);
88     operator bool() const;
89    private:
90     friend struct ArrayDataTraits<bool>;
91     BitRef(uint8_t* storage, uint8_t mask);
92     BitRef();
93     uint8_t* storage_;
94     uint8_t mask_;
95   };
96 
97   typedef uint8_t StorageType;
98   typedef BitRef Ref;
99   typedef bool ConstRef;
100 
101   static size_t GetStorageSize(size_t num_elements) {
102     return ((num_elements + 7) / 8);
103   }
104   static BitRef ToRef(StorageType* storage, size_t offset) {
105     return BitRef(&storage[offset / 8], 1 << (offset % 8));
106   }
107   static bool ToConstRef(const StorageType* storage, size_t offset) {
108     return (storage[offset / 8] & (1 << (offset % 8))) != 0;
109   }
110 };
111 
112 // What follows is code to support the serialization of Array_Data<T>. There
113 // are two interesting cases: arrays of primitives and arrays of objects.
114 // Arrays of objects are represented as arrays of pointers to objects.
115 
116 template <typename T, bool kIsHandle> struct ArraySerializationHelper;
117 
118 template <typename T>
119 struct ArraySerializationHelper<T, false> {
120   typedef typename ArrayDataTraits<T>::StorageType ElementType;
121 
122   static void EncodePointersAndHandles(const ArrayHeader* header,
123                                        ElementType* elements,
124                                        std::vector<Handle>* handles) {
125   }
126 
127   static void DecodePointersAndHandles(const ArrayHeader* header,
128                                        ElementType* elements,
129                                        std::vector<Handle>* handles) {
130   }
131 
132   static bool ValidateElements(const ArrayHeader* header,
133                                const ElementType* elements,
134                                BoundsChecker* bounds_checker) {
135     return true;
136   }
137 };
138 
139 template <>
140 struct ArraySerializationHelper<Handle, true> {
141   typedef ArrayDataTraits<Handle>::StorageType ElementType;
142 
143   static void EncodePointersAndHandles(const ArrayHeader* header,
144                                        ElementType* elements,
145                                        std::vector<Handle>* handles);
146 
147   static void DecodePointersAndHandles(const ArrayHeader* header,
148                                        ElementType* elements,
149                                        std::vector<Handle>* handles);
150 
151   static bool ValidateElements(const ArrayHeader* header,
152                                const ElementType* elements,
153                                BoundsChecker* bounds_checker);
154 };
155 
156 template <typename H>
157 struct ArraySerializationHelper<H, true> {
158   typedef typename ArrayDataTraits<H>::StorageType ElementType;
159 
160   static void EncodePointersAndHandles(const ArrayHeader* header,
161                                        ElementType* elements,
162                                        std::vector<Handle>* handles) {
163     ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
164         header, elements, handles);
165   }
166 
167   static void DecodePointersAndHandles(const ArrayHeader* header,
168                                        ElementType* elements,
169                                        std::vector<Handle>* handles) {
170     ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
171         header, elements, handles);
172   }
173 
174   static bool ValidateElements(const ArrayHeader* header,
175                                const ElementType* elements,
176                                BoundsChecker* bounds_checker) {
177     return ArraySerializationHelper<Handle, true>::ValidateElements(
178         header, elements, bounds_checker);
179   }
180 };
181 
182 template <typename P>
183 struct ArraySerializationHelper<P*, false> {
184   typedef typename ArrayDataTraits<P*>::StorageType ElementType;
185 
186   static void EncodePointersAndHandles(const ArrayHeader* header,
187                                        ElementType* elements,
188                                        std::vector<Handle>* handles) {
189     for (uint32_t i = 0; i < header->num_elements; ++i)
190       Encode(&elements[i], handles);
191   }
192 
193   static void DecodePointersAndHandles(const ArrayHeader* header,
194                                        ElementType* elements,
195                                        std::vector<Handle>* handles) {
196     for (uint32_t i = 0; i < header->num_elements; ++i)
197       Decode(&elements[i], handles);
198   }
199 
200   static bool ValidateElements(const ArrayHeader* header,
201                                const ElementType* elements,
202                                BoundsChecker* bounds_checker) {
203     for (uint32_t i = 0; i < header->num_elements; ++i) {
204       if (!ValidateEncodedPointer(&elements[i].offset)) {
205         ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER);
206         return false;
207       }
208       if (!P::Validate(DecodePointerRaw(&elements[i].offset), bounds_checker))
209         return false;
210     }
211     return true;
212   }
213 };
214 
215 template <typename T>
216 class Array_Data {
217  public:
218   typedef ArrayDataTraits<T> Traits;
219   typedef typename Traits::StorageType StorageType;
220   typedef typename Traits::Ref Ref;
221   typedef typename Traits::ConstRef ConstRef;
222   typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper;
223 
224   static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
225     size_t num_bytes = sizeof(Array_Data<T>) +
226                        Traits::GetStorageSize(num_elements);
227     return new (buf->Allocate(num_bytes)) Array_Data<T>(num_bytes,
228                                                         num_elements);
229   }
230 
231   static bool Validate(const void* data, BoundsChecker* bounds_checker) {
232     if (!data)
233       return true;
234     if (!IsAligned(data)) {
235       ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
236       return false;
237     }
238     if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
239       ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
240       return false;
241     }
242     const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
243     if (header->num_bytes < (sizeof(Array_Data<T>) +
244                              Traits::GetStorageSize(header->num_elements))) {
245       ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
246       return false;
247     }
248     if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
249       ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
250       return false;
251     }
252 
253     const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
254     return Helper::ValidateElements(&object->header_, object->storage(),
255                                     bounds_checker);
256   }
257 
258   size_t size() const { return header_.num_elements; }
259 
260   Ref at(size_t offset) {
261     assert(offset < static_cast<size_t>(header_.num_elements));
262     return Traits::ToRef(storage(), offset);
263   }
264 
265   ConstRef at(size_t offset) const {
266     assert(offset < static_cast<size_t>(header_.num_elements));
267     return Traits::ToConstRef(storage(), offset);
268   }
269 
270   StorageType* storage() {
271     return reinterpret_cast<StorageType*>(
272         reinterpret_cast<char*>(this) + sizeof(*this));
273   }
274 
275   const StorageType* storage() const {
276     return reinterpret_cast<const StorageType*>(
277         reinterpret_cast<const char*>(this) + sizeof(*this));
278   }
279 
280   void EncodePointersAndHandles(std::vector<Handle>* handles) {
281     Helper::EncodePointersAndHandles(&header_, storage(), handles);
282   }
283 
284   void DecodePointersAndHandles(std::vector<Handle>* handles) {
285     Helper::DecodePointersAndHandles(&header_, storage(), handles);
286   }
287 
288  private:
289   Array_Data(size_t num_bytes, size_t num_elements) {
290     header_.num_bytes = static_cast<uint32_t>(num_bytes);
291     header_.num_elements = static_cast<uint32_t>(num_elements);
292   }
293   ~Array_Data() {}
294 
295   internal::ArrayHeader header_;
296 
297   // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
298 };
299 MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
300 
301 // UTF-8 encoded
302 typedef Array_Data<char> String_Data;
303 
304 template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {};
305 
306 template <typename T> struct ArrayTraits<T, false> {
307   typedef T StorageType;
308   typedef typename std::vector<T>::reference RefType;
309   typedef typename std::vector<T>::const_reference ConstRefType;
310   typedef ConstRefType ForwardType;
311   static inline void Initialize(std::vector<T>* vec) {
312   }
313   static inline void Finalize(std::vector<T>* vec) {
314   }
315   static inline ConstRefType at(const std::vector<T>* vec, size_t offset) {
316     return vec->at(offset);
317   }
318   static inline RefType at(std::vector<T>* vec, size_t offset) {
319     return vec->at(offset);
320   }
321   static inline void Resize(std::vector<T>* vec, size_t size) {
322     vec->resize(size);
323   }
324   static inline void PushBack(std::vector<T>* vec, ForwardType value) {
325     vec->push_back(value);
326   }
327 };
328 
329 template <typename T> struct ArrayTraits<T, true> {
330   struct StorageType {
331     char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8];  // Make 8-byte aligned.
332   };
333   typedef T& RefType;
334   typedef const T& ConstRefType;
335   typedef T ForwardType;
336   static inline void Initialize(std::vector<StorageType>* vec) {
337     for (size_t i = 0; i < vec->size(); ++i)
338       new (vec->at(i).buf) T();
339   }
340   static inline void Finalize(std::vector<StorageType>* vec) {
341     for (size_t i = 0; i < vec->size(); ++i)
342       reinterpret_cast<T*>(vec->at(i).buf)->~T();
343   }
344   static inline ConstRefType at(const std::vector<StorageType>* vec,
345                                 size_t offset) {
346     return *reinterpret_cast<const T*>(vec->at(offset).buf);
347   }
348   static inline RefType at(std::vector<StorageType>* vec, size_t offset) {
349     return *reinterpret_cast<T*>(vec->at(offset).buf);
350   }
351   static inline void Resize(std::vector<StorageType>* vec, size_t size) {
352     size_t old_size = vec->size();
353     for (size_t i = size; i < old_size; i++)
354       reinterpret_cast<T*>(vec->at(i).buf)->~T();
355     ResizeStorage(vec, size);
356     for (size_t i = old_size; i < vec->size(); i++)
357       new (vec->at(i).buf) T();
358   }
359   static inline void PushBack(std::vector<StorageType>* vec, RefType value) {
360     size_t old_size = vec->size();
361     ResizeStorage(vec, old_size + 1);
362     new (vec->at(old_size).buf) T(value.Pass());
363   }
364   static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) {
365     if (size <= vec->capacity()) {
366       vec->resize(size);
367       return;
368     }
369     std::vector<StorageType> new_storage(size);
370     for (size_t i = 0; i < vec->size(); i++)
371       new (new_storage.at(i).buf) T(at(vec, i).Pass());
372     vec->swap(new_storage);
373     Finalize(&new_storage);
374   }
375 };
376 
377 template <> struct WrapperTraits<String, false> {
378   typedef String_Data* DataType;
379 };
380 
381 }  // namespace internal
382 }  // namespace mojo
383 
384 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
385