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.
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
10 #include "mojo/public/cpp/bindings/buffer.h"
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/passable.h"
16 template <typename T> class Array;
21 struct ArrayDataTraits {
22 typedef T StorageType;
23 typedef Array<T> Wrapper;
25 typedef T const& ConstRef;
27 static size_t GetStorageSize(size_t num_elements) {
28 return sizeof(StorageType) * num_elements;
30 static Ref ToRef(StorageType* storage, size_t offset) {
31 return storage[offset];
33 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
34 return storage[offset];
39 struct ArrayDataTraits<P*> {
40 typedef StructPointer<P> StorageType;
41 typedef Array<typename P::Wrapper> Wrapper;
43 typedef P* const& ConstRef;
45 static size_t GetStorageSize(size_t num_elements) {
46 return sizeof(StorageType) * num_elements;
48 static Ref ToRef(StorageType* storage, size_t offset) {
49 return storage[offset].ptr;
51 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
52 return storage[offset].ptr;
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.
62 struct ArrayDataTraits<bool> {
63 // Helper class to emulate a reference to a bool, used for direct element
68 BitRef& operator=(bool value);
69 BitRef& operator=(const BitRef& value);
70 operator bool() const;
72 friend struct ArrayDataTraits<bool>;
73 BitRef(uint8_t* storage, uint8_t mask);
79 typedef uint8_t StorageType;
80 typedef Array<bool> Wrapper;
82 typedef bool ConstRef;
84 static size_t GetStorageSize(size_t num_elements) {
85 return ((num_elements + 7) / 8);
87 static BitRef ToRef(StorageType* storage, size_t offset) {
88 return BitRef(&storage[offset / 8], 1 << (offset % 8));
90 static bool ToConstRef(const StorageType* storage, size_t offset) {
91 return (storage[offset / 8] & (1 << (offset % 8))) != 0;
95 // What follows is code to support the serialization of Array_Data<T>. There
96 // are two interesting cases: arrays of primitives and arrays of objects.
97 // Arrays of objects are represented as arrays of pointers to objects.
99 template <typename T, bool kIsHandle> struct ArraySerializationHelper;
101 template <typename T>
102 struct ArraySerializationHelper<T, false> {
103 typedef typename ArrayDataTraits<T>::StorageType ElementType;
105 static size_t ComputeSizeOfElements(const ArrayHeader* header,
106 const ElementType* elements) {
110 static void CloneElements(const ArrayHeader* header,
111 ElementType* elements,
115 static void ClearHandles(const ArrayHeader* header, ElementType* elements) {
118 static void CloseHandles(const ArrayHeader* header,
119 ElementType* elements) {
122 static void EncodePointersAndHandles(const ArrayHeader* header,
123 ElementType* elements,
124 std::vector<Handle>* handles) {
127 static bool DecodePointersAndHandles(const ArrayHeader* header,
128 ElementType* elements,
135 struct ArraySerializationHelper<Handle, true> {
136 typedef ArrayDataTraits<Handle>::StorageType ElementType;
138 static size_t ComputeSizeOfElements(const ArrayHeader* header,
139 const ElementType* elements) {
143 static void CloneElements(const ArrayHeader* header,
144 ElementType* elements,
148 static void ClearHandles(const ArrayHeader* header, ElementType* elements);
150 static void CloseHandles(const ArrayHeader* header, ElementType* elements);
152 static void EncodePointersAndHandles(const ArrayHeader* header,
153 ElementType* elements,
154 std::vector<Handle>* handles);
156 static bool DecodePointersAndHandles(const ArrayHeader* header,
157 ElementType* elements,
161 template <typename H>
162 struct ArraySerializationHelper<H, true> {
163 typedef typename ArrayDataTraits<H>::StorageType ElementType;
165 static size_t ComputeSizeOfElements(const ArrayHeader* header,
166 const ElementType* elements) {
170 static void CloneElements(const ArrayHeader* header,
171 ElementType* elements,
175 static void ClearHandles(const ArrayHeader* header, ElementType* elements) {
176 ArraySerializationHelper<Handle, true>::ClearHandles(header, elements);
179 static void CloseHandles(const ArrayHeader* header, ElementType* elements) {
180 ArraySerializationHelper<Handle, true>::CloseHandles(header, elements);
183 static void EncodePointersAndHandles(const ArrayHeader* header,
184 ElementType* elements,
185 std::vector<Handle>* handles) {
186 ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
187 header, elements, handles);
190 static bool DecodePointersAndHandles(const ArrayHeader* header,
191 ElementType* elements,
193 return ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
194 header, elements, message);
198 template <typename P>
199 struct ArraySerializationHelper<P*, false> {
200 typedef typename ArrayDataTraits<P*>::StorageType ElementType;
202 static size_t ComputeSizeOfElements(const ArrayHeader* header,
203 const ElementType* elements) {
205 for (uint32_t i = 0; i < header->num_elements; ++i) {
207 result += elements[i].ptr->ComputeSize();
212 static void CloneElements(const ArrayHeader* header,
213 ElementType* elements,
215 for (uint32_t i = 0; i < header->num_elements; ++i) {
217 elements[i].ptr = elements[i].ptr->Clone(buf);
221 static void ClearHandles(const ArrayHeader* header, ElementType* elements) {
224 static void CloseHandles(const ArrayHeader* header,
225 ElementType* elements) {
226 for (uint32_t i = 0; i < header->num_elements; ++i) {
228 elements[i].ptr->CloseHandles();
232 static void EncodePointersAndHandles(const ArrayHeader* header,
233 ElementType* elements,
234 std::vector<Handle>* handles) {
235 for (uint32_t i = 0; i < header->num_elements; ++i)
236 Encode(&elements[i], handles);
239 static bool DecodePointersAndHandles(const ArrayHeader* header,
240 ElementType* elements,
242 for (uint32_t i = 0; i < header->num_elements; ++i) {
243 if (!Decode(&elements[i], message))
250 template <typename T>
253 typedef ArrayDataTraits<T> Traits;
254 typedef typename Traits::StorageType StorageType;
255 typedef typename Traits::Wrapper Wrapper;
256 typedef typename Traits::Ref Ref;
257 typedef typename Traits::ConstRef ConstRef;
258 typedef ArraySerializationHelper<T, TypeTraits<T>::kIsHandle> Helper;
260 static Array_Data<T>* New(size_t num_elements, Buffer* buf,
261 Buffer::Destructor dtor = NULL) {
262 size_t num_bytes = sizeof(Array_Data<T>) +
263 Traits::GetStorageSize(num_elements);
264 return new (buf->Allocate(num_bytes, dtor)) Array_Data<T>(num_bytes,
268 static void Destructor(void* address) {
269 static_cast<Array_Data*>(address)->CloseHandles();
272 size_t size() const { return header_.num_elements; }
274 Ref at(size_t offset) {
275 assert(offset < static_cast<size_t>(header_.num_elements));
276 return Traits::ToRef(storage(), offset);
279 ConstRef at(size_t offset) const {
280 assert(offset < static_cast<size_t>(header_.num_elements));
281 return Traits::ToConstRef(storage(), offset);
284 StorageType* storage() {
285 return reinterpret_cast<StorageType*>(
286 reinterpret_cast<char*>(this) + sizeof(*this));
289 const StorageType* storage() const {
290 return reinterpret_cast<const StorageType*>(
291 reinterpret_cast<const char*>(this) + sizeof(*this));
294 size_t ComputeSize() const {
295 return Align(header_.num_bytes) +
296 Helper::ComputeSizeOfElements(&header_, storage());
299 Array_Data<T>* Clone(Buffer* buf) {
300 Array_Data<T>* clone = New(header_.num_elements, buf);
301 memcpy(clone->storage(),
303 header_.num_bytes - sizeof(Array_Data<T>));
304 Helper::CloneElements(&clone->header_, clone->storage(), buf);
306 // Zero-out handles in the original storage as they have been transferred
308 Helper::ClearHandles(&header_, storage());
312 void CloseHandles() {
313 Helper::CloseHandles(&header_, storage());
316 void EncodePointersAndHandles(std::vector<Handle>* handles) {
317 Helper::EncodePointersAndHandles(&header_, storage(), handles);
320 bool DecodePointersAndHandles(Message* message) {
321 return Helper::DecodePointersAndHandles(&header_, storage(), message);
325 Array_Data(size_t num_bytes, size_t num_elements) {
326 header_.num_bytes = static_cast<uint32_t>(num_bytes);
327 header_.num_elements = static_cast<uint32_t>(num_elements);
331 internal::ArrayHeader header_;
333 // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
335 MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
338 typedef Array_Data<char> String_Data;
340 template <typename T, bool kIsObject, bool kIsHandle> struct ArrayTraits {};
342 // When T is an object type:
343 template <typename T> struct ArrayTraits<T, true, false> {
344 typedef Array_Data<typename T::Data*> DataType;
345 typedef const T& ConstRef;
347 static Buffer::Destructor GetDestructor() {
350 static typename T::Data* ToArrayElement(const T& value) {
351 return Unwrap(value);
353 // Something sketchy is indeed happening here...
354 static Ref ToRef(typename T::Data*& data) {
355 return *reinterpret_cast<T*>(&data);
357 static ConstRef ToConstRef(typename T::Data* const& data) {
358 return *reinterpret_cast<const T*>(&data);
362 // When T is a primitive (non-bool) type:
363 template <typename T> struct ArrayTraits<T, false, false> {
364 typedef Array_Data<T> DataType;
365 typedef const T& ConstRef;
367 static Buffer::Destructor GetDestructor() {
370 static T ToArrayElement(const T& value) {
373 static Ref ToRef(T& data) { return data; }
374 static ConstRef ToConstRef(const T& data) { return data; }
377 // When T is a bool type:
378 template <> struct ArrayTraits<bool, false, false> {
379 typedef Array_Data<bool> DataType;
380 typedef bool ConstRef;
381 typedef ArrayDataTraits<bool>::Ref Ref;
382 static Buffer::Destructor GetDestructor() {
385 static bool ToArrayElement(const bool& value) {
388 static Ref ToRef(const Ref& data) { return data; }
389 static ConstRef ToConstRef(ConstRef data) { return data; }
392 // When T is a handle type:
393 template <typename H> struct ArrayTraits<H, false, true> {
394 typedef Array_Data<H> DataType;
395 typedef Passable<H> ConstRef;
396 typedef AssignableAndPassable<H> Ref;
397 static Buffer::Destructor GetDestructor() {
398 return &DataType::Destructor;
400 static H ToArrayElement(const H& value) {
403 static Ref ToRef(H& data) { return Ref(&data); }
404 static ConstRef ToConstRef(const H& data) {
405 return ConstRef(const_cast<H*>(&data));
409 } // namespace internal
412 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_