1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
6e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <new>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <vector>
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "mojo/public/c/system/macros.h"
12e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
13e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "mojo/public/cpp/bindings/lib/buffer.h"
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "mojo/public/cpp/bindings/lib/template_util.h"
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/public/cpp/bindings/lib/validation_errors.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "mojo/public/cpp/environment/logging.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace mojo {
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)template <typename T> class Array;
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class String;
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace internal {
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// std::numeric_limits<uint32_t>::max() is not a compile-time constant (until
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// C++11).
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const uint32_t kMaxUint32 = 0xFFFFFFFF;
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)std::string MakeMessageWithArrayIndex(const char* message,
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                      size_t size,
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                      size_t index);
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)std::string MakeMessageWithExpectedArraySize(const char* message,
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                             size_t size,
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                             size_t expected_size);
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)template <typename T>
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct ArrayDataTraits {
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef T StorageType;
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef T& Ref;
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef T const& ConstRef;
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static const uint32_t kMaxNumElements =
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static uint32_t GetStorageSize(uint32_t num_elements) {
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    MOJO_DCHECK(num_elements <= kMaxNumElements);
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static Ref ToRef(StorageType* storage, size_t offset) {
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return storage[offset];
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return storage[offset];
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)template <typename P>
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct ArrayDataTraits<P*> {
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef StructPointer<P> StorageType;
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef P*& Ref;
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef P* const& ConstRef;
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static const uint32_t kMaxNumElements =
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static uint32_t GetStorageSize(uint32_t num_elements) {
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    MOJO_DCHECK(num_elements <= kMaxNumElements);
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  static Ref ToRef(StorageType* storage, size_t offset) {
736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return storage[offset].ptr;
746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return storage[offset].ptr;
776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)};
796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)template <typename T>
816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)struct ArrayDataTraits<Array_Data<T>*> {
826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  typedef ArrayPointer<T> StorageType;
836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  typedef Array_Data<T>*& Ref;
846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  typedef Array_Data<T>* const& ConstRef;
856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static const uint32_t kMaxNumElements =
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType);
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static uint32_t GetStorageSize(uint32_t num_elements) {
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    MOJO_DCHECK(num_elements <= kMaxNumElements);
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static Ref ToRef(StorageType* storage, size_t offset) {
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return storage[offset].ptr;
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return storage[offset].ptr;
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Specialization of Arrays for bools, optimized for space. It has the
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// following differences from a generalized Array:
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// * Each element takes up a single bit of memory.
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// * Accessing a non-const single element uses a helper class |BitRef|, which
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// emulates a reference to a bool.
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)template <>
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct ArrayDataTraits<bool> {
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Helper class to emulate a reference to a bool, used for direct element
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // access.
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  class BitRef {
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   public:
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ~BitRef();
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BitRef& operator=(bool value);
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BitRef& operator=(const BitRef& value);
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    operator bool() const;
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   private:
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    friend struct ArrayDataTraits<bool>;
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BitRef(uint8_t* storage, uint8_t mask);
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BitRef();
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    uint8_t* storage_;
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    uint8_t mask_;
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Because each element consumes only 1/8 byte.
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static const uint32_t kMaxNumElements = kMaxUint32;
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef uint8_t StorageType;
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef BitRef Ref;
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef bool ConstRef;
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static uint32_t GetStorageSize(uint32_t num_elements) {
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return sizeof(ArrayHeader) + ((num_elements + 7) / 8);
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static BitRef ToRef(StorageType* storage, size_t offset) {
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return BitRef(&storage[offset / 8], 1 << (offset % 8));
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static bool ToConstRef(const StorageType* storage, size_t offset) {
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return (storage[offset / 8] & (1 << (offset % 8))) != 0;
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Array type information needed for valdiation.
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)template <uint32_t in_expected_num_elements,
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          bool in_element_is_nullable,
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          typename InElementValidateParams>
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class ArrayValidateParams {
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) public:
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Validation information for elements. It is either another specialization of
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // ArrayValidateParams (if elements are arrays) or NoValidateParams.
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  typedef InElementValidateParams ElementValidateParams;
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If |expected_num_elements| is not 0, the array is expected to have exactly
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // that number of elements.
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  static const uint32_t expected_num_elements = in_expected_num_elements;
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Whether the elements are nullable.
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  static const bool element_is_nullable = in_element_is_nullable;
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)};
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// NoValidateParams is used to indicate the end of an ArrayValidateParams chain.
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class NoValidateParams {
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)};
1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// What follows is code to support the serialization of Array_Data<T>. There
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// are two interesting cases: arrays of primitives and arrays of objects.
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Arrays of objects are represented as arrays of pointers to objects.
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)template <typename T, bool is_handle> struct ArraySerializationHelper;
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template <typename T>
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstruct ArraySerializationHelper<T, false> {
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef typename ArrayDataTraits<T>::StorageType ElementType;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static void EncodePointersAndHandles(const ArrayHeader* header,
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ElementType* elements,
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       std::vector<Handle>* handles) {
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static void DecodePointersAndHandles(const ArrayHeader* header,
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ElementType* elements,
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       std::vector<Handle>* handles) {
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  template <bool element_is_nullable, typename ElementValidateParams>
18446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static bool ValidateElements(const ArrayHeader* header,
18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               const ElementType* elements,
18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               BoundsChecker* bounds_checker) {
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    MOJO_COMPILE_ASSERT(!element_is_nullable,
1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                        Primitive_type_should_be_non_nullable);
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    MOJO_COMPILE_ASSERT(
1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        (IsSame<ElementValidateParams, NoValidateParams>::value),
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Primitive_type_should_not_have_array_validate_params);
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template <>
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstruct ArraySerializationHelper<Handle, true> {
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef ArrayDataTraits<Handle>::StorageType ElementType;
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static void EncodePointersAndHandles(const ArrayHeader* header,
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ElementType* elements,
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       std::vector<Handle>* handles);
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static void DecodePointersAndHandles(const ArrayHeader* header,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ElementType* elements,
20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       std::vector<Handle>* handles);
20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
20803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  template <bool element_is_nullable, typename ElementValidateParams>
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static bool ValidateElements(const ArrayHeader* header,
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               const ElementType* elements,
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                               BoundsChecker* bounds_checker) {
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    MOJO_COMPILE_ASSERT(
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        (IsSame<ElementValidateParams, NoValidateParams>::value),
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Handle_type_should_not_have_array_validate_params);
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for (uint32_t i = 0; i < header->num_elements; ++i) {
21703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (!element_is_nullable &&
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          elements[i].value() == kEncodedInvalidHandleValue) {
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ReportValidationError(
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            MakeMessageWithArrayIndex(
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                "invalid handle in array expecting valid handles",
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                header->num_elements, i).c_str());
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return false;
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (!bounds_checker->ClaimHandle(elements[i])) {
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE);
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return false;
2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochtemplate <typename H>
2360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstruct ArraySerializationHelper<H, true> {
2370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef typename ArrayDataTraits<H>::StorageType ElementType;
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  static void EncodePointersAndHandles(const ArrayHeader* header,
2400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       ElementType* elements,
2410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       std::vector<Handle>* handles) {
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        header, elements, handles);
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
24646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static void DecodePointersAndHandles(const ArrayHeader* header,
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       ElementType* elements,
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       std::vector<Handle>* handles) {
24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        header, elements, handles);
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
25303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  template <bool element_is_nullable, typename ElementValidateParams>
25446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static bool ValidateElements(const ArrayHeader* header,
25546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               const ElementType* elements,
25646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               BoundsChecker* bounds_checker) {
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ArraySerializationHelper<Handle, true>::
25803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        ValidateElements<element_is_nullable, ElementValidateParams>(
2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            header, elements, bounds_checker);
2600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch};
2620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template <typename P>
2640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstruct ArraySerializationHelper<P*, false> {
2650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef typename ArrayDataTraits<P*>::StorageType ElementType;
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static void EncodePointersAndHandles(const ArrayHeader* header,
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ElementType* elements,
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       std::vector<Handle>* handles) {
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (uint32_t i = 0; i < header->num_elements; ++i)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Encode(&elements[i], handles);
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static void DecodePointersAndHandles(const ArrayHeader* header,
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       ElementType* elements,
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       std::vector<Handle>* handles) {
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    for (uint32_t i = 0; i < header->num_elements; ++i)
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      Decode(&elements[i], handles);
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  template <bool element_is_nullable, typename ElementValidateParams>
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static bool ValidateElements(const ArrayHeader* header,
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               const ElementType* elements,
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               BoundsChecker* bounds_checker) {
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (uint32_t i = 0; i < header->num_elements; ++i) {
28603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (!element_is_nullable && !elements[i].offset) {
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ReportValidationError(
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            MakeMessageWithArrayIndex(
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                "null in array expecting valid pointers",
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                header->num_elements, i).c_str());
2926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return false;
2936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
29446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!ValidateEncodedPointer(&elements[i].offset)) {
29546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER);
29646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return false;
29746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
2986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (!ValidateCaller<P, ElementValidateParams>::Run(
2996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              DecodePointerRaw(&elements[i].offset), bounds_checker)) {
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private:
3076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  template <typename T, typename Params>
3086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  struct ValidateCaller {
3096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    static bool Run(const void* data, BoundsChecker* bounds_checker) {
3106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      MOJO_COMPILE_ASSERT(
3116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          (IsSame<Params, NoValidateParams>::value),
3126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          Struct_type_should_not_have_array_validate_params);
3136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return T::Validate(data, bounds_checker);
3156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
3166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  };
3176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  template <typename T, typename Params>
3196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  struct ValidateCaller<Array_Data<T>, Params> {
3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    static bool Run(const void* data, BoundsChecker* bounds_checker) {
3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return Array_Data<T>::template Validate<Params>(data, bounds_checker);
3226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
3236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  };
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
326a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)template <typename T>
327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class Array_Data {
328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef ArrayDataTraits<T> Traits;
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef typename Traits::StorageType StorageType;
331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef typename Traits::Ref Ref;
332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef typename Traits::ConstRef ConstRef;
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper;
334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
33503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Returns NULL if |num_elements| or the corresponding storage size cannot be
33603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // stored in uint32_t.
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (num_elements > Traits::kMaxNumElements)
33903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return NULL;
34003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
34103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    uint32_t num_bytes =
34203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        Traits::GetStorageSize(static_cast<uint32_t>(num_elements));
34303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return new (buf->Allocate(num_bytes)) Array_Data<T>(
34403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        num_bytes, static_cast<uint32_t>(num_elements));
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
3476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  template <typename Params>
3486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  static bool Validate(const void* data, BoundsChecker* bounds_checker) {
34946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!data)
35046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return true;
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!IsAligned(data)) {
35246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
35346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return false;
35446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
35646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
35746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return false;
35846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
35946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
36003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (header->num_elements > Traits::kMaxNumElements ||
36103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        header->num_bytes < Traits::GetStorageSize(header->num_elements)) {
36246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
36346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return false;
36446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
3656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (Params::expected_num_elements != 0 &&
3666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        header->num_elements != Params::expected_num_elements) {
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ReportValidationError(
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          MakeMessageWithExpectedArraySize(
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              "fixed-size array has wrong number of elements",
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              header->num_elements, Params::expected_num_elements).c_str());
372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
37446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
37546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
37646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return false;
37746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
37846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
37946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return Helper::template ValidateElements<
38103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        Params::element_is_nullable, typename Params::ElementValidateParams>(
3826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            &object->header_, object->storage(), bounds_checker);
38346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
38446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  size_t size() const { return header_.num_elements; }
386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Ref at(size_t offset) {
3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return Traits::ToRef(storage(), offset);
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ConstRef at(size_t offset) const {
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return Traits::ToConstRef(storage(), offset);
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  StorageType* storage() {
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return reinterpret_cast<StorageType*>(
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        reinterpret_cast<char*>(this) + sizeof(*this));
400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const StorageType* storage() const {
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return reinterpret_cast<const StorageType*>(
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        reinterpret_cast<const char*>(this) + sizeof(*this));
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void EncodePointersAndHandles(std::vector<Handle>* handles) {
4080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Helper::EncodePointersAndHandles(&header_, storage(), handles);
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
41146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void DecodePointersAndHandles(std::vector<Handle>* handles) {
41246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    Helper::DecodePointersAndHandles(&header_, storage(), handles);
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
41603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Array_Data(uint32_t num_bytes, uint32_t num_elements) {
41703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    header_.num_bytes = num_bytes;
41803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    header_.num_elements = num_elements;
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ~Array_Data() {}
421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  internal::ArrayHeader header_;
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// UTF-8 encoded
429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)typedef Array_Data<char> String_Data;
430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
431cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {};
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
433cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)template <typename T> struct ArrayTraits<T, false> {
434cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef T StorageType;
435cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef typename std::vector<T>::reference RefType;
436cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef typename std::vector<T>::const_reference ConstRefType;
437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  typedef ConstRefType ForwardType;
438cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline void Initialize(std::vector<T>* vec) {
4390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
440cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline void Finalize(std::vector<T>* vec) {
441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
442cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline ConstRefType at(const std::vector<T>* vec, size_t offset) {
443cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return vec->at(offset);
444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline RefType at(std::vector<T>* vec, size_t offset) {
446cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return vec->at(offset);
447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
448f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static inline void Resize(std::vector<T>* vec, size_t size) {
449f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    vec->resize(size);
450f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
451f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static inline void PushBack(std::vector<T>* vec, ForwardType value) {
452f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    vec->push_back(value);
453f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)template <typename T> struct ArrayTraits<T, true> {
457cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  struct StorageType {
458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8];  // Make 8-byte aligned.
459cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
460cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef T& RefType;
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef const T& ConstRefType;
462f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  typedef T ForwardType;
463cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline void Initialize(std::vector<StorageType>* vec) {
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (size_t i = 0; i < vec->size(); ++i)
465cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new (vec->at(i).buf) T();
4660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
467cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline void Finalize(std::vector<StorageType>* vec) {
468cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (size_t i = 0; i < vec->size(); ++i)
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      reinterpret_cast<T*>(vec->at(i).buf)->~T();
470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline ConstRefType at(const std::vector<StorageType>* vec,
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                size_t offset) {
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return *reinterpret_cast<const T*>(vec->at(offset).buf);
4740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static inline RefType at(std::vector<StorageType>* vec, size_t offset) {
476cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return *reinterpret_cast<T*>(vec->at(offset).buf);
477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
478f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static inline void Resize(std::vector<StorageType>* vec, size_t size) {
479f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    size_t old_size = vec->size();
480f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (size_t i = size; i < old_size; i++)
481f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      reinterpret_cast<T*>(vec->at(i).buf)->~T();
482f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ResizeStorage(vec, size);
483f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (size_t i = old_size; i < vec->size(); i++)
484f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new (vec->at(i).buf) T();
485f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static inline void PushBack(std::vector<StorageType>* vec, RefType value) {
487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    size_t old_size = vec->size();
488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ResizeStorage(vec, old_size + 1);
489f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    new (vec->at(old_size).buf) T(value.Pass());
490f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) {
492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (size <= vec->capacity()) {
493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      vec->resize(size);
494f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return;
495f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
496f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<StorageType> new_storage(size);
497f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (size_t i = 0; i < vec->size(); i++)
498f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new (new_storage.at(i).buf) T(at(vec, i).Pass());
499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    vec->swap(new_storage);
500f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Finalize(&new_storage);
501f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
503a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)template <> struct WrapperTraits<String, false> {
505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef String_Data* DataType;
506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace internal
509a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace mojo
510a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
511e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
512