| OLD | NEW |
| (Empty) |
| 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_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ | |
| 6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ | |
| 7 | |
| 8 #include <new> | |
| 9 #include <string> | |
| 10 #include <type_traits> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" | |
| 14 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" | |
| 15 #include "mojo/public/cpp/bindings/lib/bounds_checker.h" | |
| 16 #include "mojo/public/cpp/bindings/lib/buffer.h" | |
| 17 #include "mojo/public/cpp/bindings/lib/map_data_internal.h" | |
| 18 #include "mojo/public/cpp/bindings/lib/validate_params.h" | |
| 19 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | |
| 20 #include "mojo/public/cpp/environment/logging.h" | |
| 21 | |
| 22 namespace mojo { | |
| 23 template <typename T> | |
| 24 class Array; | |
| 25 class String; | |
| 26 | |
| 27 namespace internal { | |
| 28 | |
| 29 // std::numeric_limits<uint32_t>::max() is not a compile-time constant (until | |
| 30 // C++11). | |
| 31 const uint32_t kMaxUint32 = 0xFFFFFFFF; | |
| 32 | |
| 33 // TODO(vardhan): Get rid of the following 2 functions. | |
| 34 std::string MakeMessageWithArrayIndex(const char* message, | |
| 35 size_t size, | |
| 36 size_t index); | |
| 37 | |
| 38 std::string MakeMessageWithExpectedArraySize(const char* message, | |
| 39 size_t size, | |
| 40 size_t expected_size); | |
| 41 | |
| 42 template <typename T> | |
| 43 struct ArrayDataTraits { | |
| 44 typedef T StorageType; | |
| 45 typedef T& Ref; | |
| 46 typedef T const& ConstRef; | |
| 47 | |
| 48 static const uint32_t kMaxNumElements = | |
| 49 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); | |
| 50 | |
| 51 static uint32_t GetStorageSize(uint32_t num_elements) { | |
| 52 MOJO_DCHECK(num_elements <= kMaxNumElements); | |
| 53 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; | |
| 54 } | |
| 55 static Ref ToRef(StorageType* storage, size_t offset) { | |
| 56 return storage[offset]; | |
| 57 } | |
| 58 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { | |
| 59 return storage[offset]; | |
| 60 } | |
| 61 }; | |
| 62 | |
| 63 template <typename P, bool is_union> | |
| 64 struct ObjectStorageType; | |
| 65 | |
| 66 template <typename P> | |
| 67 struct ObjectStorageType<P, true> { | |
| 68 typedef P Type; | |
| 69 }; | |
| 70 | |
| 71 template <typename P> | |
| 72 struct ObjectStorageType<P, false> { | |
| 73 typedef StructPointer<P> Type; | |
| 74 }; | |
| 75 | |
| 76 template <typename P> | |
| 77 struct ArrayDataTraits<P*> { | |
| 78 typedef typename ObjectStorageType<P, IsUnionDataType<P>::value>::Type | |
| 79 StorageType; | |
| 80 typedef P*& Ref; | |
| 81 typedef P* const& ConstRef; | |
| 82 | |
| 83 static const uint32_t kMaxNumElements = | |
| 84 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); | |
| 85 | |
| 86 static uint32_t GetStorageSize(uint32_t num_elements) { | |
| 87 MOJO_DCHECK(num_elements <= kMaxNumElements); | |
| 88 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; | |
| 89 } | |
| 90 static Ref ToRef(StorageType* storage, size_t offset) { | |
| 91 return storage[offset].ptr; | |
| 92 } | |
| 93 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { | |
| 94 return storage[offset].ptr; | |
| 95 } | |
| 96 }; | |
| 97 | |
| 98 template <typename T> | |
| 99 struct ArrayDataTraits<Array_Data<T>*> { | |
| 100 typedef ArrayPointer<T> StorageType; | |
| 101 typedef Array_Data<T>*& Ref; | |
| 102 typedef Array_Data<T>* const& ConstRef; | |
| 103 | |
| 104 static const uint32_t kMaxNumElements = | |
| 105 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); | |
| 106 | |
| 107 static uint32_t GetStorageSize(uint32_t num_elements) { | |
| 108 MOJO_DCHECK(num_elements <= kMaxNumElements); | |
| 109 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; | |
| 110 } | |
| 111 static Ref ToRef(StorageType* storage, size_t offset) { | |
| 112 return storage[offset].ptr; | |
| 113 } | |
| 114 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { | |
| 115 return storage[offset].ptr; | |
| 116 } | |
| 117 }; | |
| 118 | |
| 119 // Specialization of Arrays for bools, optimized for space. It has the | |
| 120 // following differences from a generalized Array: | |
| 121 // * Each element takes up a single bit of memory. | |
| 122 // * Accessing a non-const single element uses a helper class |BitRef|, which | |
| 123 // emulates a reference to a bool. | |
| 124 template <> | |
| 125 struct ArrayDataTraits<bool> { | |
| 126 // Helper class to emulate a reference to a bool, used for direct element | |
| 127 // access. | |
| 128 class BitRef { | |
| 129 public: | |
| 130 ~BitRef(); | |
| 131 BitRef& operator=(bool value); | |
| 132 BitRef& operator=(const BitRef& value); | |
| 133 operator bool() const; | |
| 134 | |
| 135 private: | |
| 136 friend struct ArrayDataTraits<bool>; | |
| 137 BitRef(uint8_t* storage, uint8_t mask); | |
| 138 BitRef(); | |
| 139 uint8_t* storage_; | |
| 140 uint8_t mask_; | |
| 141 }; | |
| 142 | |
| 143 // Because each element consumes only 1/8 byte. | |
| 144 static const uint32_t kMaxNumElements = kMaxUint32; | |
| 145 | |
| 146 typedef uint8_t StorageType; | |
| 147 typedef BitRef Ref; | |
| 148 typedef bool ConstRef; | |
| 149 | |
| 150 static uint32_t GetStorageSize(uint32_t num_elements) { | |
| 151 return sizeof(ArrayHeader) + ((num_elements + 7) / 8); | |
| 152 } | |
| 153 static BitRef ToRef(StorageType* storage, size_t offset) { | |
| 154 return BitRef(&storage[offset / 8], 1 << (offset % 8)); | |
| 155 } | |
| 156 static bool ToConstRef(const StorageType* storage, size_t offset) { | |
| 157 return (storage[offset / 8] & (1 << (offset % 8))) != 0; | |
| 158 } | |
| 159 }; | |
| 160 | |
| 161 // What follows is code to support the serialization of Array_Data<T>. There | |
| 162 // are two interesting cases: arrays of primitives/unions, arrays of non-union | |
| 163 // objects (structs, arrays and maps). | |
| 164 // Arrays of non-union objects are represented as arrays of pointers to objects. | |
| 165 // Arrays of primitives or unions are represented as arrays of the values | |
| 166 // themselves. | |
| 167 | |
| 168 template <typename T, bool is_handle, bool is_union> | |
| 169 struct ArraySerializationHelper; | |
| 170 | |
| 171 template <typename T> | |
| 172 struct ArraySerializationHelper<T, false, false> { | |
| 173 typedef typename ArrayDataTraits<T>::StorageType ElementType; | |
| 174 | |
| 175 static void EncodePointersAndHandles(const ArrayHeader* header, | |
| 176 ElementType* elements, | |
| 177 std::vector<Handle>* handles) {} | |
| 178 | |
| 179 static void DecodePointersAndHandles(const ArrayHeader* header, | |
| 180 ElementType* elements, | |
| 181 std::vector<Handle>* handles) {} | |
| 182 | |
| 183 static ValidationError ValidateElements( | |
| 184 const ArrayHeader* header, | |
| 185 const ElementType* elements, | |
| 186 BoundsChecker* bounds_checker, | |
| 187 const ArrayValidateParams* validate_params, | |
| 188 std::string* err) { | |
| 189 MOJO_DCHECK(!validate_params->element_is_nullable) | |
| 190 << "Primitive type should be non-nullable"; | |
| 191 MOJO_DCHECK(!validate_params->element_validate_params) | |
| 192 << "Primitive type should not have array validate params"; | |
| 193 return ValidationError::NONE; | |
| 194 } | |
| 195 }; | |
| 196 | |
| 197 template <> | |
| 198 struct ArraySerializationHelper<Handle, true, false> { | |
| 199 typedef ArrayDataTraits<Handle>::StorageType ElementType; | |
| 200 | |
| 201 static void EncodePointersAndHandles(const ArrayHeader* header, | |
| 202 ElementType* elements, | |
| 203 std::vector<Handle>* handles); | |
| 204 | |
| 205 static void DecodePointersAndHandles(const ArrayHeader* header, | |
| 206 ElementType* elements, | |
| 207 std::vector<Handle>* handles); | |
| 208 | |
| 209 static ValidationError ValidateElements( | |
| 210 const ArrayHeader* header, | |
| 211 const ElementType* elements, | |
| 212 BoundsChecker* bounds_checker, | |
| 213 const ArrayValidateParams* validate_params, | |
| 214 std::string* err) { | |
| 215 MOJO_DCHECK(!validate_params->element_validate_params) | |
| 216 << "Handle type should not have array validate params"; | |
| 217 | |
| 218 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
| 219 if (!validate_params->element_is_nullable && | |
| 220 elements[i].value() == kEncodedInvalidHandleValue) { | |
| 221 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
| 222 << "invalid handle in array expecting valid handles (array size=" | |
| 223 << header->num_elements << ", index = " << i << ")"; | |
| 224 return ValidationError::UNEXPECTED_INVALID_HANDLE; | |
| 225 } | |
| 226 if (!bounds_checker->ClaimHandle(elements[i])) { | |
| 227 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
| 228 return ValidationError::ILLEGAL_HANDLE; | |
| 229 } | |
| 230 } | |
| 231 return ValidationError::NONE; | |
| 232 } | |
| 233 }; | |
| 234 | |
| 235 template <typename H> | |
| 236 struct ArraySerializationHelper<H, true, false> { | |
| 237 typedef typename ArrayDataTraits<H>::StorageType ElementType; | |
| 238 | |
| 239 static void EncodePointersAndHandles(const ArrayHeader* header, | |
| 240 ElementType* elements, | |
| 241 std::vector<Handle>* handles) { | |
| 242 ArraySerializationHelper<Handle, true, false>::EncodePointersAndHandles( | |
| 243 header, elements, handles); | |
| 244 } | |
| 245 | |
| 246 static void DecodePointersAndHandles(const ArrayHeader* header, | |
| 247 ElementType* elements, | |
| 248 std::vector<Handle>* handles) { | |
| 249 ArraySerializationHelper<Handle, true, false>::DecodePointersAndHandles( | |
| 250 header, elements, handles); | |
| 251 } | |
| 252 | |
| 253 static ValidationError ValidateElements( | |
| 254 const ArrayHeader* header, | |
| 255 const ElementType* elements, | |
| 256 BoundsChecker* bounds_checker, | |
| 257 const ArrayValidateParams* validate_params, | |
| 258 std::string* err) { | |
| 259 return ArraySerializationHelper<Handle, true, false>::ValidateElements( | |
| 260 header, elements, bounds_checker, validate_params, err); | |
| 261 } | |
| 262 }; | |
| 263 | |
| 264 template <typename P> | |
| 265 struct ArraySerializationHelper<P*, false, false> { | |
| 266 typedef typename ArrayDataTraits<P*>::StorageType ElementType; | |
| 267 | |
| 268 static void EncodePointersAndHandles(const ArrayHeader* header, | |
| 269 ElementType* elements, | |
| 270 std::vector<Handle>* handles) { | |
| 271 for (uint32_t i = 0; i < header->num_elements; ++i) | |
| 272 Encode(&elements[i], handles); | |
| 273 } | |
| 274 | |
| 275 static void DecodePointersAndHandles(const ArrayHeader* header, | |
| 276 ElementType* elements, | |
| 277 std::vector<Handle>* handles) { | |
| 278 for (uint32_t i = 0; i < header->num_elements; ++i) | |
| 279 Decode(&elements[i], handles); | |
| 280 } | |
| 281 | |
| 282 static ValidationError ValidateElements( | |
| 283 const ArrayHeader* header, | |
| 284 const ElementType* elements, | |
| 285 BoundsChecker* bounds_checker, | |
| 286 const ArrayValidateParams* validate_params, | |
| 287 std::string* err) { | |
| 288 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
| 289 if (!validate_params->element_is_nullable && !elements[i].offset) { | |
| 290 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
| 291 << "null in array expecting valid pointers (size=" | |
| 292 << header->num_elements << ", index = " << i << ")"; | |
| 293 return ValidationError::UNEXPECTED_NULL_POINTER; | |
| 294 } | |
| 295 | |
| 296 if (!ValidateEncodedPointer(&elements[i].offset)) { | |
| 297 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
| 298 return ValidationError::ILLEGAL_POINTER; | |
| 299 } | |
| 300 | |
| 301 auto retval = ValidateCaller<P>::Run( | |
| 302 DecodePointerRaw(&elements[i].offset), bounds_checker, | |
| 303 validate_params->element_validate_params, err); | |
| 304 if (retval != ValidationError::NONE) | |
| 305 return retval; | |
| 306 } | |
| 307 return ValidationError::NONE; | |
| 308 } | |
| 309 | |
| 310 private: | |
| 311 template <typename T> | |
| 312 struct ValidateCaller { | |
| 313 static ValidationError Run(const void* data, | |
| 314 BoundsChecker* bounds_checker, | |
| 315 const ArrayValidateParams* validate_params, | |
| 316 std::string* err) { | |
| 317 MOJO_DCHECK(!validate_params) | |
| 318 << "Struct type should not have array validate params"; | |
| 319 | |
| 320 return T::Validate(data, bounds_checker, err); | |
| 321 } | |
| 322 }; | |
| 323 | |
| 324 template <typename Key, typename Value> | |
| 325 struct ValidateCaller<Map_Data<Key, Value>> { | |
| 326 static ValidationError Run(const void* data, | |
| 327 BoundsChecker* bounds_checker, | |
| 328 const ArrayValidateParams* validate_params, | |
| 329 std::string* err) { | |
| 330 return Map_Data<Key, Value>::Validate(data, bounds_checker, | |
| 331 validate_params, err); | |
| 332 } | |
| 333 }; | |
| 334 | |
| 335 template <typename T> | |
| 336 struct ValidateCaller<Array_Data<T>> { | |
| 337 static ValidationError Run(const void* data, | |
| 338 BoundsChecker* bounds_checker, | |
| 339 const ArrayValidateParams* validate_params, | |
| 340 std::string* err) { | |
| 341 return Array_Data<T>::Validate(data, bounds_checker, validate_params, | |
| 342 err); | |
| 343 } | |
| 344 }; | |
| 345 }; | |
| 346 | |
| 347 // Array Serialization Helper for unions. | |
| 348 template <typename P> | |
| 349 struct ArraySerializationHelper<P, false, true> { | |
| 350 typedef P ElementType; | |
| 351 | |
| 352 static void EncodePointersAndHandles(const ArrayHeader* header, | |
| 353 ElementType* elements, | |
| 354 std::vector<Handle>* handles) { | |
| 355 for (uint32_t i = 0; i < header->num_elements; ++i) | |
| 356 elements[i].EncodePointersAndHandles(handles); | |
| 357 } | |
| 358 | |
| 359 static void DecodePointersAndHandles(const ArrayHeader* header, | |
| 360 ElementType* elements, | |
| 361 std::vector<Handle>* handles) { | |
| 362 for (uint32_t i = 0; i < header->num_elements; ++i) | |
| 363 elements[i].DecodePointersAndHandles(handles); | |
| 364 } | |
| 365 | |
| 366 static ValidationError ValidateElements( | |
| 367 const ArrayHeader* header, | |
| 368 const ElementType* elements, | |
| 369 BoundsChecker* bounds_checker, | |
| 370 const ArrayValidateParams* validate_params, | |
| 371 std::string* err) { | |
| 372 MOJO_DCHECK(!validate_params->element_validate_params) | |
| 373 << "Union type should not have array validate params"; | |
| 374 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
| 375 if (!validate_params->element_is_nullable && elements[i].is_null()) { | |
| 376 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
| 377 << "null union in array expecting non-null unions (size=" | |
| 378 << header->num_elements << ", index = " << i << ")"; | |
| 379 return ValidationError::UNEXPECTED_NULL_UNION; | |
| 380 } | |
| 381 | |
| 382 auto retval = ElementType::Validate( | |
| 383 static_cast<const void*>(&elements[i]), bounds_checker, true, err); | |
| 384 if (retval != ValidationError::NONE) | |
| 385 return retval; | |
| 386 } | |
| 387 return ValidationError::NONE; | |
| 388 } | |
| 389 }; | |
| 390 | |
| 391 template <typename T> | |
| 392 class Array_Data { | |
| 393 public: | |
| 394 typedef ArrayDataTraits<T> Traits; | |
| 395 typedef typename Traits::StorageType StorageType; | |
| 396 typedef typename Traits::Ref Ref; | |
| 397 typedef typename Traits::ConstRef ConstRef; | |
| 398 typedef ArraySerializationHelper< | |
| 399 T, | |
| 400 IsHandle<T>::value, | |
| 401 IsUnionDataType<typename std::remove_pointer<T>::type>::value> Helper; | |
| 402 | |
| 403 // Returns null if |num_elements| or the corresponding storage size cannot be | |
| 404 // stored in uint32_t. | |
| 405 static Array_Data<T>* New(size_t num_elements, Buffer* buf) { | |
| 406 if (num_elements > Traits::kMaxNumElements) | |
| 407 return nullptr; | |
| 408 | |
| 409 uint32_t num_bytes = | |
| 410 Traits::GetStorageSize(static_cast<uint32_t>(num_elements)); | |
| 411 return new (buf->Allocate(num_bytes)) | |
| 412 Array_Data<T>(num_bytes, static_cast<uint32_t>(num_elements)); | |
| 413 } | |
| 414 | |
| 415 static ValidationError Validate(const void* data, | |
| 416 BoundsChecker* bounds_checker, | |
| 417 const ArrayValidateParams* validate_params, | |
| 418 std::string* err) { | |
| 419 if (!data) | |
| 420 return ValidationError::NONE; | |
| 421 if (!IsAligned(data)) { | |
| 422 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
| 423 return ValidationError::MISALIGNED_OBJECT; | |
| 424 } | |
| 425 if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) { | |
| 426 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
| 427 return ValidationError::ILLEGAL_MEMORY_RANGE; | |
| 428 } | |
| 429 | |
| 430 const ArrayHeader* header = static_cast<const ArrayHeader*>(data); | |
| 431 if (header->num_elements > Traits::kMaxNumElements || | |
| 432 header->num_bytes < Traits::GetStorageSize(header->num_elements)) { | |
| 433 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
| 434 return ValidationError::UNEXPECTED_ARRAY_HEADER; | |
| 435 } | |
| 436 | |
| 437 if (validate_params->expected_num_elements != 0 && | |
| 438 header->num_elements != validate_params->expected_num_elements) { | |
| 439 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
| 440 << "fixed-size array has wrong number of elements (size=" | |
| 441 << header->num_elements | |
| 442 << ", expected size=" << validate_params->expected_num_elements | |
| 443 << ")"; | |
| 444 return ValidationError::UNEXPECTED_ARRAY_HEADER; | |
| 445 } | |
| 446 | |
| 447 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { | |
| 448 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
| 449 return ValidationError::ILLEGAL_MEMORY_RANGE; | |
| 450 } | |
| 451 | |
| 452 const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data); | |
| 453 return Helper::ValidateElements(&object->header_, object->storage(), | |
| 454 bounds_checker, validate_params, err); | |
| 455 } | |
| 456 | |
| 457 size_t size() const { return header_.num_elements; } | |
| 458 | |
| 459 Ref at(size_t offset) { | |
| 460 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements)); | |
| 461 return Traits::ToRef(storage(), offset); | |
| 462 } | |
| 463 | |
| 464 ConstRef at(size_t offset) const { | |
| 465 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements)); | |
| 466 return Traits::ToConstRef(storage(), offset); | |
| 467 } | |
| 468 | |
| 469 StorageType* storage() { | |
| 470 return reinterpret_cast<StorageType*>(reinterpret_cast<char*>(this) + | |
| 471 sizeof(*this)); | |
| 472 } | |
| 473 | |
| 474 const StorageType* storage() const { | |
| 475 return reinterpret_cast<const StorageType*>( | |
| 476 reinterpret_cast<const char*>(this) + sizeof(*this)); | |
| 477 } | |
| 478 | |
| 479 void EncodePointersAndHandles(std::vector<Handle>* handles) { | |
| 480 Helper::EncodePointersAndHandles(&header_, storage(), handles); | |
| 481 } | |
| 482 | |
| 483 void DecodePointersAndHandles(std::vector<Handle>* handles) { | |
| 484 Helper::DecodePointersAndHandles(&header_, storage(), handles); | |
| 485 } | |
| 486 | |
| 487 private: | |
| 488 Array_Data(uint32_t num_bytes, uint32_t num_elements) { | |
| 489 header_.num_bytes = num_bytes; | |
| 490 header_.num_elements = num_elements; | |
| 491 } | |
| 492 ~Array_Data() = delete; | |
| 493 | |
| 494 internal::ArrayHeader header_; | |
| 495 | |
| 496 // Elements of type internal::ArrayDataTraits<T>::StorageType follow. | |
| 497 }; | |
| 498 static_assert(sizeof(Array_Data<char>) == 8, "Bad sizeof(Array_Data)"); | |
| 499 | |
| 500 // UTF-8 encoded | |
| 501 typedef Array_Data<char> String_Data; | |
| 502 | |
| 503 template <typename T, bool kIsMoveOnlyType> | |
| 504 struct ArrayTraits {}; | |
| 505 | |
| 506 template <typename T> | |
| 507 struct ArrayTraits<T, false> { | |
| 508 typedef typename std::vector<T>::const_reference ForwardType; | |
| 509 static inline void PushBack(std::vector<T>* vec, ForwardType value) { | |
| 510 vec->push_back(value); | |
| 511 } | |
| 512 static inline void Clone(const std::vector<T>& src_vec, | |
| 513 std::vector<T>* dest_vec) { | |
| 514 dest_vec->assign(src_vec.begin(), src_vec.end()); | |
| 515 } | |
| 516 }; | |
| 517 | |
| 518 template <typename T> | |
| 519 struct ArrayTraits<T, true> { | |
| 520 typedef T ForwardType; | |
| 521 static inline void PushBack(std::vector<T>* vec, T& value) { | |
| 522 vec->push_back(value.Pass()); | |
| 523 } | |
| 524 static inline void Clone(const std::vector<T>& src_vec, | |
| 525 std::vector<T>* dest_vec) { | |
| 526 dest_vec->resize(src_vec.size()); | |
| 527 for (size_t i = 0; i < src_vec.size(); ++i) | |
| 528 dest_vec->at(i) = src_vec.at(i).Clone(); | |
| 529 } | |
| 530 }; | |
| 531 | |
| 532 template <> | |
| 533 struct WrapperTraits<String, false> { | |
| 534 typedef String_Data* DataType; | |
| 535 }; | |
| 536 | |
| 537 } // namespace internal | |
| 538 } // namespace mojo | |
| 539 | |
| 540 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ | |
| OLD | NEW |