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