Home | History | Annotate | Download | only in lib
      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 
     29   static size_t GetStorageSize(size_t num_elements) {
     30     return sizeof(StorageType) * num_elements;
     31   }
     32   static Ref ToRef(StorageType* storage, size_t offset) {
     33     return storage[offset];
     34   }
     35   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