capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

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