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_BINDINGS_LIB_ARRAY_INTERNAL_H_
      6 #define MOJO_PUBLIC_BINDINGS_LIB_ARRAY_INTERNAL_H_
      7 
      8 #include <new>
      9 
     10 #include "mojo/public/bindings/lib/bindings_internal.h"
     11 #include "mojo/public/bindings/lib/buffer.h"
     12 #include "mojo/public/bindings/lib/passable.h"
     13 #include "mojo/public/system/core_cpp.h"
     14 
     15 namespace mojo {
     16 template <typename T> class Array;
     17 
     18 namespace internal {
     19 
     20 template <typename T>
     21 struct ArrayDataTraits {
     22   typedef T StorageType;
     23   typedef Array<T> Wrapper;
     24   typedef T& Ref;
     25   typedef T const& ConstRef;
     26 
     27   static size_t GetStorageSize(size_t num_elements) {
     28     return sizeof(StorageType) * num_elements;
     29   }
     30   static Ref ToRef(StorageType* storage, size_t offset) {
     31     return storage[offset];
     32   }
     33   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
     34     return storage[offset];
     35   }
     36 };
     37 
     38 template <typename P>
     39 struct ArrayDataTraits<P*> {
     40   typedef StructPointer<P> StorageType;
     41   typedef Array<typename P::Wrapper> Wrapper;
     42   typedef P*& Ref;
     43   typedef P* const& ConstRef;
     44 
     45   static size_t GetStorageSize(size_t num_elements) {
     46     return sizeof(StorageType) * num_elements;
     47   }
     48   static Ref ToRef(StorageType* storage, size_t offset) {
     49     return storage[offset].ptr;
     50   }
     51   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
     52     return storage[offset].ptr;
     53   }
     54 };
     55 
     56 // Specialization of Arrays for bools, optimized for space. It has the
     57 // following differences from a generalized Array:
     58 // * Each element takes up a single bit of memory.
     59 // * Accessing a non-const single element uses a helper class |BitRef|, which
     60 // emulates a reference to a bool.
     61 template <>
     62 struct ArrayDataTraits<bool> {
     63   // Helper class to emulate a reference to a bool, used for direct element
     64   // access.
     65   class BitRef {
     66    public:
     67     ~BitRef();
     68     BitRef& operator=(bool value);
     69     BitRef& operator=(const BitRef& value);
     70     operator bool() const;
     71    private:
     72     friend struct ArrayDataTraits<bool>;
     73     BitRef(uint8_t* storage, uint8_t mask);
     74     BitRef();
     75     uint8_t* storage_;
     76     uint8_t mask_;
     77   };
     78 
     79   typedef uint8_t StorageType;
     80   typedef Array<bool> Wrapper;
     81   typedef BitRef Ref;
     82   typedef bool ConstRef;
     83 
     84   static size_t GetStorageSize(size_t num_elements) {
     85     return ((num_elements + 7) / 8);
     86   }
     87   static BitRef ToRef(StorageType* storage, size_t offset) {
     88     return BitRef(&storage[offset / 8], 1 << (offset % 8));
     89   }
     90   static bool ToConstRef(const StorageType* storage, size_t offset) {
     91     return (storage[offset / 8] & (1 << (offset % 8))) != 0;
     92   }
     93 };
     94 
     95 template <typename T>
     96 class Array_Data {
     97  public:
     98   typedef ArrayDataTraits<T> Traits;
     99   typedef typename Traits::StorageType StorageType;
    100   typedef typename Traits::Wrapper Wrapper;
    101   typedef typename Traits::Ref Ref;
    102   typedef typename Traits::ConstRef ConstRef;
    103 
    104   static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
    105     size_t num_bytes = sizeof(Array_Data<T>) +
    106                        Traits::GetStorageSize(num_elements);
    107     return new (buf->Allocate(num_bytes)) Array_Data<T>(num_bytes,
    108                                                         num_elements);
    109   }
    110 
    111   size_t size() const { return header_.num_elements; }
    112 
    113   Ref at(size_t offset) {
    114     assert(offset < static_cast<size_t>(header_.num_elements));
    115     return Traits::ToRef(storage(), offset);
    116   }
    117 
    118   ConstRef at(size_t offset) const {
    119     assert(offset < static_cast<size_t>(header_.num_elements));
    120     return Traits::ToConstRef(storage(), offset);
    121   }
    122 
    123   StorageType* storage() {
    124     return reinterpret_cast<StorageType*>(
    125         reinterpret_cast<char*>(this) + sizeof(*this));
    126   }
    127 
    128   const StorageType* storage() const {
    129     return reinterpret_cast<const StorageType*>(
    130         reinterpret_cast<const char*>(this) + sizeof(*this));
    131   }
    132 
    133  private:
    134   friend class internal::ObjectTraits<Array_Data<T> >;
    135 
    136   Array_Data(size_t num_bytes, size_t num_elements) {
    137     header_.num_bytes = static_cast<uint32_t>(num_bytes);
    138     header_.num_elements = static_cast<uint32_t>(num_elements);
    139   }
    140   ~Array_Data() {}
    141 
    142   internal::ArrayHeader header_;
    143 
    144   // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
    145 };
    146 MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
    147 
    148 // UTF-8 encoded
    149 typedef Array_Data<char> String_Data;
    150 
    151 template <typename T, bool kIsObject> struct ArrayTraits {};
    152 
    153 template <typename T> struct ArrayTraits<T, true> {
    154   typedef Array_Data<typename T::Data*> DataType;
    155   typedef const T& ConstRef;
    156   typedef T& Ref;
    157   static typename T::Data* ToArrayElement(const T& value) {
    158     return Unwrap(value);
    159   }
    160   // Something sketchy is indeed happening here...
    161   static Ref ToRef(typename T::Data*& data) {
    162     return *reinterpret_cast<T*>(&data);
    163   }
    164   static ConstRef ToConstRef(typename T::Data* const& data) {
    165     return *reinterpret_cast<const T*>(&data);
    166   }
    167 };
    168 
    169 template <typename T> struct ArrayTraits<T, false> {
    170   typedef Array_Data<T> DataType;
    171   typedef const T& ConstRef;
    172   typedef T& Ref;
    173   static T ToArrayElement(const T& value) {
    174     return value;
    175   }
    176   static Ref ToRef(T& data) { return data; }
    177   static ConstRef ToConstRef(const T& data) { return data; }
    178 };
    179 
    180 template <> struct ArrayTraits<bool, false> {
    181   typedef Array_Data<bool> DataType;
    182   typedef bool ConstRef;
    183   typedef ArrayDataTraits<bool>::Ref Ref;
    184   static bool ToArrayElement(const bool& value) {
    185     return value;
    186   }
    187   static Ref ToRef(const Ref& data) { return data; }
    188   static ConstRef ToConstRef(ConstRef data) { return data; }
    189 };
    190 
    191 template <> struct ArrayTraits<Handle, false> {
    192   typedef Array_Data<Handle> DataType;
    193   typedef Passable<Handle> ConstRef;
    194   typedef AssignableAndPassable<Handle> Ref;
    195   static Handle ToArrayElement(const Handle& value) {
    196     return value;
    197   }
    198   static Ref ToRef(Handle& data) { return Ref(&data); }
    199   static ConstRef ToConstRef(const Handle& data) {
    200     return ConstRef(const_cast<Handle*>(&data));
    201   }
    202 };
    203 
    204 template <> struct ArrayTraits<MessagePipeHandle, false> {
    205   typedef Array_Data<MessagePipeHandle> DataType;
    206   typedef Passable<MessagePipeHandle> ConstRef;
    207   typedef AssignableAndPassable<MessagePipeHandle> Ref;
    208   static MessagePipeHandle ToArrayElement(const MessagePipeHandle& value) {
    209     return value;
    210   }
    211   static Ref ToRef(MessagePipeHandle& data) { return Ref(&data); }
    212   static ConstRef ToConstRef(const MessagePipeHandle& data) {
    213     return ConstRef(const_cast<MessagePipeHandle*>(&data));
    214   }
    215 };
    216 
    217 }  // namespace internal
    218 }  // namespace mojo
    219 
    220 #endif  // MOJO_PUBLIC_BINDINGS_LIB_ARRAY_INTERNAL_H_
    221