[Drive] Handle error cases earlier in FakeDriveService
[chromium-blink-merge.git] / mojo / public / cpp / bindings / lib / array_internal.h
blobf74c857a35930e243010c459d1806c4694db4b06
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_
8 #include <new>
9 #include <vector>
11 #include "mojo/public/c/system/macros.h"
12 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
13 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
14 #include "mojo/public/cpp/bindings/lib/bounds_checker.h"
15 #include "mojo/public/cpp/bindings/lib/buffer.h"
16 #include "mojo/public/cpp/bindings/lib/template_util.h"
17 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
18 #include "mojo/public/cpp/environment/logging.h"
20 namespace mojo {
21 template <typename T> class Array;
22 class String;
24 namespace internal {
26 template <typename T>
27 struct ArrayDataTraits {
28 typedef T StorageType;
29 typedef T& Ref;
30 typedef T const& ConstRef;
32 static size_t GetStorageSize(size_t num_elements) {
33 return sizeof(StorageType) * num_elements;
35 static Ref ToRef(StorageType* storage, size_t offset) {
36 return storage[offset];
38 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
39 return storage[offset];
43 template <typename P>
44 struct ArrayDataTraits<P*> {
45 typedef StructPointer<P> StorageType;
46 typedef P*& Ref;
47 typedef P* const& ConstRef;
49 static size_t GetStorageSize(size_t num_elements) {
50 return sizeof(StorageType) * num_elements;
52 static Ref ToRef(StorageType* storage, size_t offset) {
53 return storage[offset].ptr;
55 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
56 return storage[offset].ptr;
60 template <typename T>
61 struct ArrayDataTraits<Array_Data<T>*> {
62 typedef ArrayPointer<T> StorageType;
63 typedef Array_Data<T>*& Ref;
64 typedef Array_Data<T>* const& ConstRef;
66 static size_t GetStorageSize(size_t num_elements) {
67 return sizeof(StorageType) * num_elements;
69 static Ref ToRef(StorageType* storage, size_t offset) {
70 return storage[offset].ptr;
72 static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
73 return storage[offset].ptr;
77 // Specialization of Arrays for bools, optimized for space. It has the
78 // following differences from a generalized Array:
79 // * Each element takes up a single bit of memory.
80 // * Accessing a non-const single element uses a helper class |BitRef|, which
81 // emulates a reference to a bool.
82 template <>
83 struct ArrayDataTraits<bool> {
84 // Helper class to emulate a reference to a bool, used for direct element
85 // access.
86 class BitRef {
87 public:
88 ~BitRef();
89 BitRef& operator=(bool value);
90 BitRef& operator=(const BitRef& value);
91 operator bool() const;
92 private:
93 friend struct ArrayDataTraits<bool>;
94 BitRef(uint8_t* storage, uint8_t mask);
95 BitRef();
96 uint8_t* storage_;
97 uint8_t mask_;
100 typedef uint8_t StorageType;
101 typedef BitRef Ref;
102 typedef bool ConstRef;
104 static size_t GetStorageSize(size_t num_elements) {
105 return ((num_elements + 7) / 8);
107 static BitRef ToRef(StorageType* storage, size_t offset) {
108 return BitRef(&storage[offset / 8], 1 << (offset % 8));
110 static bool ToConstRef(const StorageType* storage, size_t offset) {
111 return (storage[offset / 8] & (1 << (offset % 8))) != 0;
115 // Array type information needed for valdiation.
116 template <uint32_t in_expected_num_elements,
117 bool in_element_nullable,
118 typename InElementValidateParams>
119 class ArrayValidateParams {
120 public:
121 // Validation information for elements. It is either another specialization of
122 // ArrayValidateParams (if elements are arrays) or NoValidateParams.
123 typedef InElementValidateParams ElementValidateParams;
125 // If |expected_num_elements| is not 0, the array is expected to have exactly
126 // that number of elements.
127 static const uint32_t expected_num_elements = in_expected_num_elements;
128 // Whether the elements are nullable.
129 static const bool element_nullable = in_element_nullable;
132 // NoValidateParams is used to indicate the end of an ArrayValidateParams chain.
133 class NoValidateParams {
136 // What follows is code to support the serialization of Array_Data<T>. There
137 // are two interesting cases: arrays of primitives and arrays of objects.
138 // Arrays of objects are represented as arrays of pointers to objects.
140 template <typename T, bool is_handle> struct ArraySerializationHelper;
142 template <typename T>
143 struct ArraySerializationHelper<T, false> {
144 typedef typename ArrayDataTraits<T>::StorageType ElementType;
146 static void EncodePointersAndHandles(const ArrayHeader* header,
147 ElementType* elements,
148 std::vector<Handle>* handles) {
151 static void DecodePointersAndHandles(const ArrayHeader* header,
152 ElementType* elements,
153 std::vector<Handle>* handles) {
156 template <bool element_nullable, typename ElementValidateParams>
157 static bool ValidateElements(const ArrayHeader* header,
158 const ElementType* elements,
159 BoundsChecker* bounds_checker) {
160 MOJO_COMPILE_ASSERT(!element_nullable,
161 Primitive_type_should_be_non_nullable);
162 MOJO_COMPILE_ASSERT(
163 (IsSame<ElementValidateParams, NoValidateParams>::value),
164 Primitive_type_should_not_have_array_validate_params);
165 return true;
169 template <>
170 struct ArraySerializationHelper<Handle, true> {
171 typedef ArrayDataTraits<Handle>::StorageType ElementType;
173 static void EncodePointersAndHandles(const ArrayHeader* header,
174 ElementType* elements,
175 std::vector<Handle>* handles);
177 static void DecodePointersAndHandles(const ArrayHeader* header,
178 ElementType* elements,
179 std::vector<Handle>* handles);
181 template <bool element_nullable, typename ElementValidateParams>
182 static bool ValidateElements(const ArrayHeader* header,
183 const ElementType* elements,
184 BoundsChecker* bounds_checker) {
185 MOJO_COMPILE_ASSERT(
186 (IsSame<ElementValidateParams, NoValidateParams>::value),
187 Handle_type_should_not_have_array_validate_params);
189 for (uint32_t i = 0; i < header->num_elements; ++i) {
190 if (IsNonNullableValidationEnabled() && !element_nullable &&
191 elements[i].value() == kEncodedInvalidHandleValue) {
192 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE);
193 return false;
195 if (!bounds_checker->ClaimHandle(elements[i])) {
196 ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE);
197 return false;
200 return true;
204 template <typename H>
205 struct ArraySerializationHelper<H, true> {
206 typedef typename ArrayDataTraits<H>::StorageType ElementType;
208 static void EncodePointersAndHandles(const ArrayHeader* header,
209 ElementType* elements,
210 std::vector<Handle>* handles) {
211 ArraySerializationHelper<Handle, true>::EncodePointersAndHandles(
212 header, elements, handles);
215 static void DecodePointersAndHandles(const ArrayHeader* header,
216 ElementType* elements,
217 std::vector<Handle>* handles) {
218 ArraySerializationHelper<Handle, true>::DecodePointersAndHandles(
219 header, elements, handles);
222 template <bool element_nullable, typename ElementValidateParams>
223 static bool ValidateElements(const ArrayHeader* header,
224 const ElementType* elements,
225 BoundsChecker* bounds_checker) {
226 return ArraySerializationHelper<Handle, true>::
227 ValidateElements<element_nullable, ElementValidateParams>(
228 header, elements, bounds_checker);
232 template <typename P>
233 struct ArraySerializationHelper<P*, false> {
234 typedef typename ArrayDataTraits<P*>::StorageType ElementType;
236 static void EncodePointersAndHandles(const ArrayHeader* header,
237 ElementType* elements,
238 std::vector<Handle>* handles) {
239 for (uint32_t i = 0; i < header->num_elements; ++i)
240 Encode(&elements[i], handles);
243 static void DecodePointersAndHandles(const ArrayHeader* header,
244 ElementType* elements,
245 std::vector<Handle>* handles) {
246 for (uint32_t i = 0; i < header->num_elements; ++i)
247 Decode(&elements[i], handles);
250 template <bool element_nullable, typename ElementValidateParams>
251 static bool ValidateElements(const ArrayHeader* header,
252 const ElementType* elements,
253 BoundsChecker* bounds_checker) {
254 for (uint32_t i = 0; i < header->num_elements; ++i) {
255 if (IsNonNullableValidationEnabled() && !element_nullable &&
256 !elements[i].offset) {
257 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_NULL_POINTER);
258 return false;
260 if (!ValidateEncodedPointer(&elements[i].offset)) {
261 ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER);
262 return false;
264 if (!ValidateCaller<P, ElementValidateParams>::Run(
265 DecodePointerRaw(&elements[i].offset), bounds_checker)) {
266 return false;
269 return true;
272 private:
273 template <typename T, typename Params>
274 struct ValidateCaller {
275 static bool Run(const void* data, BoundsChecker* bounds_checker) {
276 MOJO_COMPILE_ASSERT(
277 (IsSame<Params, NoValidateParams>::value),
278 Struct_type_should_not_have_array_validate_params);
280 return T::Validate(data, bounds_checker);
284 template <typename T, typename Params>
285 struct ValidateCaller<Array_Data<T>, Params> {
286 static bool Run(const void* data, BoundsChecker* bounds_checker) {
287 return Array_Data<T>::template Validate<Params>(data, bounds_checker);
292 template <typename T>
293 class Array_Data {
294 public:
295 typedef ArrayDataTraits<T> Traits;
296 typedef typename Traits::StorageType StorageType;
297 typedef typename Traits::Ref Ref;
298 typedef typename Traits::ConstRef ConstRef;
299 typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper;
301 static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
302 size_t num_bytes = sizeof(Array_Data<T>) +
303 Traits::GetStorageSize(num_elements);
304 return new (buf->Allocate(num_bytes)) Array_Data<T>(num_bytes,
305 num_elements);
308 template <typename Params>
309 static bool Validate(const void* data, BoundsChecker* bounds_checker) {
310 if (!data)
311 return true;
312 if (!IsAligned(data)) {
313 ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
314 return false;
316 if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) {
317 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
318 return false;
320 const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
321 if (header->num_bytes < (sizeof(Array_Data<T>) +
322 Traits::GetStorageSize(header->num_elements))) {
323 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
324 return false;
326 if (Params::expected_num_elements != 0 &&
327 header->num_elements != Params::expected_num_elements) {
328 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
329 return false;
331 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
332 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
333 return false;
336 const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
337 return Helper::template ValidateElements<
338 Params::element_nullable, typename Params::ElementValidateParams>(
339 &object->header_, object->storage(), bounds_checker);
342 size_t size() const { return header_.num_elements; }
344 Ref at(size_t offset) {
345 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
346 return Traits::ToRef(storage(), offset);
349 ConstRef at(size_t offset) const {
350 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements));
351 return Traits::ToConstRef(storage(), offset);
354 StorageType* storage() {
355 return reinterpret_cast<StorageType*>(
356 reinterpret_cast<char*>(this) + sizeof(*this));
359 const StorageType* storage() const {
360 return reinterpret_cast<const StorageType*>(
361 reinterpret_cast<const char*>(this) + sizeof(*this));
364 void EncodePointersAndHandles(std::vector<Handle>* handles) {
365 Helper::EncodePointersAndHandles(&header_, storage(), handles);
368 void DecodePointersAndHandles(std::vector<Handle>* handles) {
369 Helper::DecodePointersAndHandles(&header_, storage(), handles);
372 private:
373 Array_Data(size_t num_bytes, size_t num_elements) {
374 header_.num_bytes = static_cast<uint32_t>(num_bytes);
375 header_.num_elements = static_cast<uint32_t>(num_elements);
377 ~Array_Data() {}
379 internal::ArrayHeader header_;
381 // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
383 MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data);
385 // UTF-8 encoded
386 typedef Array_Data<char> String_Data;
388 template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {};
390 template <typename T> struct ArrayTraits<T, false> {
391 typedef T StorageType;
392 typedef typename std::vector<T>::reference RefType;
393 typedef typename std::vector<T>::const_reference ConstRefType;
394 typedef ConstRefType ForwardType;
395 static inline void Initialize(std::vector<T>* vec) {
397 static inline void Finalize(std::vector<T>* vec) {
399 static inline ConstRefType at(const std::vector<T>* vec, size_t offset) {
400 return vec->at(offset);
402 static inline RefType at(std::vector<T>* vec, size_t offset) {
403 return vec->at(offset);
405 static inline void Resize(std::vector<T>* vec, size_t size) {
406 vec->resize(size);
408 static inline void PushBack(std::vector<T>* vec, ForwardType value) {
409 vec->push_back(value);
413 template <typename T> struct ArrayTraits<T, true> {
414 struct StorageType {
415 char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8]; // Make 8-byte aligned.
417 typedef T& RefType;
418 typedef const T& ConstRefType;
419 typedef T ForwardType;
420 static inline void Initialize(std::vector<StorageType>* vec) {
421 for (size_t i = 0; i < vec->size(); ++i)
422 new (vec->at(i).buf) T();
424 static inline void Finalize(std::vector<StorageType>* vec) {
425 for (size_t i = 0; i < vec->size(); ++i)
426 reinterpret_cast<T*>(vec->at(i).buf)->~T();
428 static inline ConstRefType at(const std::vector<StorageType>* vec,
429 size_t offset) {
430 return *reinterpret_cast<const T*>(vec->at(offset).buf);
432 static inline RefType at(std::vector<StorageType>* vec, size_t offset) {
433 return *reinterpret_cast<T*>(vec->at(offset).buf);
435 static inline void Resize(std::vector<StorageType>* vec, size_t size) {
436 size_t old_size = vec->size();
437 for (size_t i = size; i < old_size; i++)
438 reinterpret_cast<T*>(vec->at(i).buf)->~T();
439 ResizeStorage(vec, size);
440 for (size_t i = old_size; i < vec->size(); i++)
441 new (vec->at(i).buf) T();
443 static inline void PushBack(std::vector<StorageType>* vec, RefType value) {
444 size_t old_size = vec->size();
445 ResizeStorage(vec, old_size + 1);
446 new (vec->at(old_size).buf) T(value.Pass());
448 static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) {
449 if (size <= vec->capacity()) {
450 vec->resize(size);
451 return;
453 std::vector<StorageType> new_storage(size);
454 for (size_t i = 0; i < vec->size(); i++)
455 new (new_storage.at(i).buf) T(at(vec, i).Pass());
456 vec->swap(new_storage);
457 Finalize(&new_storage);
461 template <> struct WrapperTraits<String, false> {
462 typedef String_Data* DataType;
465 } // namespace internal
466 } // namespace mojo
468 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_