list.h (21180B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #pragma once 23 24 #include "layout.h" 25 #include "orphan.h" 26 #include <initializer_list> 27 28 CAPNP_BEGIN_HEADER 29 30 namespace capnp { 31 namespace _ { // private 32 33 template <typename T> 34 class TemporaryPointer { 35 // This class is a little hack which lets us define operator->() in cases where it needs to 36 // return a pointer to a temporary value. We instead construct a TemporaryPointer and return that 37 // (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is 38 // able to return a real pointer to its member. 39 40 public: 41 TemporaryPointer(T&& value): value(kj::mv(value)) {} 42 TemporaryPointer(const T& value): value(value) {} 43 44 inline T* operator->() { return &value; } 45 private: 46 T value; 47 }; 48 49 // By default this isn't compatible with STL algorithms. To add STL support either define 50 // KJ_STD_COMPAT at the top of your compilation unit or include capnp/compat/std-iterator.h. 51 template <typename Container, typename Element> 52 class IndexingIterator { 53 public: 54 IndexingIterator() = default; 55 56 inline Element operator*() const { return (*container)[index]; } 57 inline TemporaryPointer<Element> operator->() const { 58 return TemporaryPointer<Element>((*container)[index]); 59 } 60 inline Element operator[]( int off) const { return (*container)[index]; } 61 inline Element operator[](uint off) const { return (*container)[index]; } 62 63 inline IndexingIterator& operator++() { ++index; return *this; } 64 inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; } 65 inline IndexingIterator& operator--() { --index; return *this; } 66 inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; } 67 68 inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); } 69 inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); } 70 inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); } 71 inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); } 72 73 inline int operator-(const IndexingIterator& other) const { return index - other.index; } 74 75 inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; } 76 inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; } 77 inline IndexingIterator& operator+=( int amount) { index += amount; return *this; } 78 inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; } 79 80 // STL says comparing iterators of different containers is not allowed, so we only compare 81 // indices here. 82 inline bool operator==(const IndexingIterator& other) const { return index == other.index; } 83 inline bool operator!=(const IndexingIterator& other) const { return index != other.index; } 84 inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; } 85 inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; } 86 inline bool operator< (const IndexingIterator& other) const { return index < other.index; } 87 inline bool operator> (const IndexingIterator& other) const { return index > other.index; } 88 89 private: 90 Container* container; 91 uint index; 92 93 friend Container; 94 inline IndexingIterator(Container* container, uint index) 95 : container(container), index(index) {} 96 }; 97 98 } // namespace _ (private) 99 100 template <typename T> 101 struct List<T, Kind::PRIMITIVE> { 102 // List of primitives. 103 104 List() = delete; 105 106 class Reader { 107 public: 108 typedef List<T> Reads; 109 110 inline Reader(): reader(_::elementSizeForType<T>()) {} 111 inline explicit Reader(_::ListReader reader): reader(reader) {} 112 113 inline uint size() const { return unbound(reader.size() / ELEMENTS); } 114 inline T operator[](uint index) const { 115 KJ_IREQUIRE(index < size()); 116 return reader.template getDataElement<T>(bounded(index) * ELEMENTS); 117 } 118 119 typedef _::IndexingIterator<const Reader, T> Iterator; 120 inline Iterator begin() const { return Iterator(this, 0); } 121 inline Iterator end() const { return Iterator(this, size()); } 122 123 inline MessageSize totalSize() const { 124 return reader.totalSize().asPublic(); 125 } 126 127 private: 128 _::ListReader reader; 129 template <typename U, Kind K> 130 friend struct _::PointerHelpers; 131 template <typename U, Kind K> 132 friend struct List; 133 friend class Orphanage; 134 template <typename U, Kind K> 135 friend struct ToDynamic_; 136 }; 137 138 class Builder { 139 public: 140 typedef List<T> Builds; 141 142 inline Builder(): builder(_::elementSizeForType<T>()) {} 143 inline Builder(decltype(nullptr)): Builder() {} 144 inline explicit Builder(_::ListBuilder builder): builder(builder) {} 145 146 inline operator Reader() const { return Reader(builder.asReader()); } 147 inline Reader asReader() const { return Reader(builder.asReader()); } 148 149 inline uint size() const { return unbound(builder.size() / ELEMENTS); } 150 inline T operator[](uint index) { 151 KJ_IREQUIRE(index < size()); 152 return builder.template getDataElement<T>(bounded(index) * ELEMENTS); 153 } 154 inline void set(uint index, T value) { 155 // Alas, it is not possible to make operator[] return a reference to which you can assign, 156 // since the encoded representation does not necessarily match the compiler's representation 157 // of the type. We can't even return a clever class that implements operator T() and 158 // operator=() because it will lead to surprising behavior when using type inference (e.g. 159 // calling a template function with inferred argument types, or using "auto" or "decltype"). 160 161 builder.template setDataElement<T>(bounded(index) * ELEMENTS, value); 162 } 163 164 typedef _::IndexingIterator<Builder, T> Iterator; 165 inline Iterator begin() { return Iterator(this, 0); } 166 inline Iterator end() { return Iterator(this, size()); } 167 168 private: 169 _::ListBuilder builder; 170 template <typename U, Kind K> 171 friend struct _::PointerHelpers; 172 friend class Orphanage; 173 template <typename U, Kind K> 174 friend struct ToDynamic_; 175 }; 176 177 class Pipeline {}; 178 179 private: 180 inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { 181 return builder.initList(_::elementSizeForType<T>(), bounded(size) * ELEMENTS); 182 } 183 inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { 184 return builder.getList(_::elementSizeForType<T>(), defaultValue); 185 } 186 inline static _::ListReader getFromPointer( 187 const _::PointerReader& reader, const word* defaultValue) { 188 return reader.getList(_::elementSizeForType<T>(), defaultValue); 189 } 190 191 template <typename U, Kind k> 192 friend struct List; 193 template <typename U, Kind K> 194 friend struct _::PointerHelpers; 195 }; 196 197 template <typename T> 198 struct List<T, Kind::ENUM>: public List<T, Kind::PRIMITIVE> {}; 199 200 template <typename T> 201 struct List<T, Kind::STRUCT> { 202 // List of structs. 203 204 List() = delete; 205 206 class Reader { 207 public: 208 typedef List<T> Reads; 209 210 inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} 211 inline explicit Reader(_::ListReader reader): reader(reader) {} 212 213 inline uint size() const { return unbound(reader.size() / ELEMENTS); } 214 inline typename T::Reader operator[](uint index) const { 215 KJ_IREQUIRE(index < size()); 216 return typename T::Reader(reader.getStructElement(bounded(index) * ELEMENTS)); 217 } 218 219 typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator; 220 inline Iterator begin() const { return Iterator(this, 0); } 221 inline Iterator end() const { return Iterator(this, size()); } 222 223 inline MessageSize totalSize() const { 224 return reader.totalSize().asPublic(); 225 } 226 227 private: 228 _::ListReader reader; 229 template <typename U, Kind K> 230 friend struct _::PointerHelpers; 231 template <typename U, Kind K> 232 friend struct List; 233 friend class Orphanage; 234 template <typename U, Kind K> 235 friend struct ToDynamic_; 236 }; 237 238 class Builder { 239 public: 240 typedef List<T> Builds; 241 242 inline Builder(): builder(ElementSize::INLINE_COMPOSITE) {} 243 inline Builder(decltype(nullptr)): Builder() {} 244 inline explicit Builder(_::ListBuilder builder): builder(builder) {} 245 246 inline operator Reader() const { return Reader(builder.asReader()); } 247 inline Reader asReader() const { return Reader(builder.asReader()); } 248 249 inline uint size() const { return unbound(builder.size() / ELEMENTS); } 250 inline typename T::Builder operator[](uint index) { 251 KJ_IREQUIRE(index < size()); 252 return typename T::Builder(builder.getStructElement(bounded(index) * ELEMENTS)); 253 } 254 255 inline void adoptWithCaveats(uint index, Orphan<T>&& orphan) { 256 // Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from 257 // the fact that structs in a struct list are allocated inline rather than by pointer: 258 // * This actually performs a shallow copy, effectively adopting each of the orphan's 259 // children rather than adopting the orphan itself. The orphan ends up being discarded, 260 // possibly wasting space in the message object. 261 // * If the orphan is larger than the target struct -- say, because the orphan was built 262 // using a newer version of the schema that has additional fields -- it will be truncated, 263 // losing data. 264 265 KJ_IREQUIRE(index < size()); 266 267 // We pass a zero-valued StructSize to asStruct() because we do not want the struct to be 268 // expanded under any circumstances. We're just going to throw it away anyway, and 269 // transferContentFrom() already carefully compares the struct sizes before transferring. 270 builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom( 271 orphan.builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); 272 } 273 inline void setWithCaveats(uint index, const typename T::Reader& reader) { 274 // Mostly behaves like you'd expect `set` to behave, but with a caveat originating from 275 // the fact that structs in a struct list are allocated inline rather than by pointer: 276 // If the source struct is larger than the target struct -- say, because the source was built 277 // using a newer version of the schema that has additional fields -- it will be truncated, 278 // losing data. 279 // 280 // Note: If you are trying to concatenate some lists, use Orphanage::newOrphanConcat() to 281 // do it without losing any data in case the source lists come from a newer version of the 282 // protocol. (Plus, it's easier to use anyhow.) 283 284 KJ_IREQUIRE(index < size()); 285 builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(reader._reader); 286 } 287 288 // There are no init(), set(), adopt(), or disown() methods for lists of structs because the 289 // elements of the list are inlined and are initialized when the list is initialized. This 290 // means that init() would be redundant, and set() would risk data loss if the input struct 291 // were from a newer version of the protocol. 292 293 typedef _::IndexingIterator<Builder, typename T::Builder> Iterator; 294 inline Iterator begin() { return Iterator(this, 0); } 295 inline Iterator end() { return Iterator(this, size()); } 296 297 private: 298 _::ListBuilder builder; 299 template <typename U, Kind K> 300 friend struct _::PointerHelpers; 301 friend class Orphanage; 302 template <typename U, Kind K> 303 friend struct ToDynamic_; 304 }; 305 306 class Pipeline {}; 307 308 private: 309 inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { 310 return builder.initStructList(bounded(size) * ELEMENTS, _::structSize<T>()); 311 } 312 inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { 313 return builder.getStructList(_::structSize<T>(), defaultValue); 314 } 315 inline static _::ListReader getFromPointer( 316 const _::PointerReader& reader, const word* defaultValue) { 317 return reader.getList(ElementSize::INLINE_COMPOSITE, defaultValue); 318 } 319 320 template <typename U, Kind k> 321 friend struct List; 322 template <typename U, Kind K> 323 friend struct _::PointerHelpers; 324 }; 325 326 template <typename T> 327 struct List<List<T>, Kind::LIST> { 328 // List of lists. 329 330 List() = delete; 331 332 class Reader { 333 public: 334 typedef List<List<T>> Reads; 335 336 inline Reader(): reader(ElementSize::POINTER) {} 337 inline explicit Reader(_::ListReader reader): reader(reader) {} 338 339 inline uint size() const { return unbound(reader.size() / ELEMENTS); } 340 inline typename List<T>::Reader operator[](uint index) const { 341 KJ_IREQUIRE(index < size()); 342 return typename List<T>::Reader(_::PointerHelpers<List<T>>::get( 343 reader.getPointerElement(bounded(index) * ELEMENTS))); 344 } 345 346 typedef _::IndexingIterator<const Reader, typename List<T>::Reader> Iterator; 347 inline Iterator begin() const { return Iterator(this, 0); } 348 inline Iterator end() const { return Iterator(this, size()); } 349 350 inline MessageSize totalSize() const { 351 return reader.totalSize().asPublic(); 352 } 353 354 private: 355 _::ListReader reader; 356 template <typename U, Kind K> 357 friend struct _::PointerHelpers; 358 template <typename U, Kind K> 359 friend struct List; 360 friend class Orphanage; 361 template <typename U, Kind K> 362 friend struct ToDynamic_; 363 }; 364 365 class Builder { 366 public: 367 typedef List<List<T>> Builds; 368 369 inline Builder(): builder(ElementSize::POINTER) {} 370 inline Builder(decltype(nullptr)): Builder() {} 371 inline explicit Builder(_::ListBuilder builder): builder(builder) {} 372 373 inline operator Reader() const { return Reader(builder.asReader()); } 374 inline Reader asReader() const { return Reader(builder.asReader()); } 375 376 inline uint size() const { return unbound(builder.size() / ELEMENTS); } 377 inline typename List<T>::Builder operator[](uint index) { 378 KJ_IREQUIRE(index < size()); 379 return typename List<T>::Builder(_::PointerHelpers<List<T>>::get( 380 builder.getPointerElement(bounded(index) * ELEMENTS))); 381 } 382 inline typename List<T>::Builder init(uint index, uint size) { 383 KJ_IREQUIRE(index < this->size()); 384 return typename List<T>::Builder(_::PointerHelpers<List<T>>::init( 385 builder.getPointerElement(bounded(index) * ELEMENTS), size)); 386 } 387 inline void set(uint index, typename List<T>::Reader value) { 388 KJ_IREQUIRE(index < size()); 389 builder.getPointerElement(bounded(index) * ELEMENTS).setList(value.reader); 390 } 391 void set(uint index, std::initializer_list<ReaderFor<T>> value) { 392 KJ_IREQUIRE(index < size()); 393 auto l = init(index, value.size()); 394 uint i = 0; 395 for (auto& element: value) { 396 l.set(i++, element); 397 } 398 } 399 inline void adopt(uint index, Orphan<List<T>>&& value) { 400 KJ_IREQUIRE(index < size()); 401 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder)); 402 } 403 inline Orphan<List<T>> disown(uint index) { 404 KJ_IREQUIRE(index < size()); 405 return Orphan<List<T>>(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); 406 } 407 408 typedef _::IndexingIterator<Builder, typename List<T>::Builder> Iterator; 409 inline Iterator begin() { return Iterator(this, 0); } 410 inline Iterator end() { return Iterator(this, size()); } 411 412 private: 413 _::ListBuilder builder; 414 template <typename U, Kind K> 415 friend struct _::PointerHelpers; 416 friend class Orphanage; 417 template <typename U, Kind K> 418 friend struct ToDynamic_; 419 }; 420 421 class Pipeline {}; 422 423 private: 424 inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { 425 return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); 426 } 427 inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { 428 return builder.getList(ElementSize::POINTER, defaultValue); 429 } 430 inline static _::ListReader getFromPointer( 431 const _::PointerReader& reader, const word* defaultValue) { 432 return reader.getList(ElementSize::POINTER, defaultValue); 433 } 434 435 template <typename U, Kind k> 436 friend struct List; 437 template <typename U, Kind K> 438 friend struct _::PointerHelpers; 439 }; 440 441 template <typename T> 442 struct List<T, Kind::BLOB> { 443 List() = delete; 444 445 class Reader { 446 public: 447 typedef List<T> Reads; 448 449 inline Reader(): reader(ElementSize::POINTER) {} 450 inline explicit Reader(_::ListReader reader): reader(reader) {} 451 452 inline uint size() const { return unbound(reader.size() / ELEMENTS); } 453 inline typename T::Reader operator[](uint index) const { 454 KJ_IREQUIRE(index < size()); 455 return reader.getPointerElement(bounded(index) * ELEMENTS) 456 .template getBlob<T>(nullptr, ZERO * BYTES); 457 } 458 459 typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator; 460 inline Iterator begin() const { return Iterator(this, 0); } 461 inline Iterator end() const { return Iterator(this, size()); } 462 463 inline MessageSize totalSize() const { 464 return reader.totalSize().asPublic(); 465 } 466 467 private: 468 _::ListReader reader; 469 template <typename U, Kind K> 470 friend struct _::PointerHelpers; 471 template <typename U, Kind K> 472 friend struct List; 473 friend class Orphanage; 474 template <typename U, Kind K> 475 friend struct ToDynamic_; 476 }; 477 478 class Builder { 479 public: 480 typedef List<T> Builds; 481 482 inline Builder(): builder(ElementSize::POINTER) {} 483 inline Builder(decltype(nullptr)): Builder() {} 484 inline explicit Builder(_::ListBuilder builder): builder(builder) {} 485 486 inline operator Reader() const { return Reader(builder.asReader()); } 487 inline Reader asReader() const { return Reader(builder.asReader()); } 488 489 inline uint size() const { return unbound(builder.size() / ELEMENTS); } 490 inline typename T::Builder operator[](uint index) { 491 KJ_IREQUIRE(index < size()); 492 return builder.getPointerElement(bounded(index) * ELEMENTS) 493 .template getBlob<T>(nullptr, ZERO * BYTES); 494 } 495 inline void set(uint index, typename T::Reader value) { 496 KJ_IREQUIRE(index < size()); 497 builder.getPointerElement(bounded(index) * ELEMENTS).template setBlob<T>(value); 498 } 499 inline typename T::Builder init(uint index, uint size) { 500 KJ_IREQUIRE(index < this->size()); 501 return builder.getPointerElement(bounded(index) * ELEMENTS) 502 .template initBlob<T>(bounded(size) * BYTES); 503 } 504 inline void adopt(uint index, Orphan<T>&& value) { 505 KJ_IREQUIRE(index < size()); 506 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder)); 507 } 508 inline Orphan<T> disown(uint index) { 509 KJ_IREQUIRE(index < size()); 510 return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); 511 } 512 513 typedef _::IndexingIterator<Builder, typename T::Builder> Iterator; 514 inline Iterator begin() { return Iterator(this, 0); } 515 inline Iterator end() { return Iterator(this, size()); } 516 517 private: 518 _::ListBuilder builder; 519 template <typename U, Kind K> 520 friend struct _::PointerHelpers; 521 friend class Orphanage; 522 template <typename U, Kind K> 523 friend struct ToDynamic_; 524 }; 525 526 class Pipeline {}; 527 528 private: 529 inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { 530 return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); 531 } 532 inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { 533 return builder.getList(ElementSize::POINTER, defaultValue); 534 } 535 inline static _::ListReader getFromPointer( 536 const _::PointerReader& reader, const word* defaultValue) { 537 return reader.getList(ElementSize::POINTER, defaultValue); 538 } 539 540 template <typename U, Kind k> 541 friend struct List; 542 template <typename U, Kind K> 543 friend struct _::PointerHelpers; 544 }; 545 546 } // namespace capnp 547 548 #ifdef KJ_STD_COMPAT 549 #include "compat/std-iterator.h" 550 #endif // KJ_STD_COMPAT 551 552 CAPNP_END_HEADER