list.h 19.1 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
21

Kenton Varda's avatar
Kenton Varda committed
22 23
#ifndef CAPNP_LIST_H_
#define CAPNP_LIST_H_
24

25
#include "layout.h"
26
#include "orphan.h"
27
#include <initializer_list>
28
#ifdef KJ_STD_COMPAT
29
#include <iterator>
30
#endif  // KJ_STD_COMPAT
31

32
namespace capnp {
33
namespace _ {  // private
34

35 36 37 38 39 40 41 42
template <typename T>
class TemporaryPointer {
  // This class is a little hack which lets us define operator->() in cases where it needs to
  // return a pointer to a temporary value.  We instead construct a TemporaryPointer and return that
  // (by value).  The compiler then invokes operator->() on the TemporaryPointer, which itself is
  // able to return a real pointer to its member.

public:
Kenton Varda's avatar
Kenton Varda committed
43
  TemporaryPointer(T&& value): value(kj::mv(value)) {}
44 45 46 47 48 49 50
  TemporaryPointer(const T& value): value(value) {}

  inline T* operator->() { return &value; }
private:
  T value;
};

Kenton Varda's avatar
Kenton Varda committed
51
template <typename Container, typename Element>
52
class IndexingIterator {
53 54 55
public:
  IndexingIterator() = default;

Kenton Varda's avatar
Kenton Varda committed
56 57
  inline Element operator*() const { return (*container)[index]; }
  inline TemporaryPointer<Element> operator->() const {
Kenton Varda's avatar
Kenton Varda committed
58 59
    return TemporaryPointer<Element>((*container)[index]);
  }
Kenton Varda's avatar
Kenton Varda committed
60 61
  inline Element operator[]( int off) const { return (*container)[index]; }
  inline Element operator[](uint off) const { return (*container)[index]; }
62 63 64 65 66 67

  inline IndexingIterator& operator++() { ++index; return *this; }
  inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; }
  inline IndexingIterator& operator--() { --index; return *this; }
  inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; }

Kenton Varda's avatar
Kenton Varda committed
68 69 70 71
  inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); }
  inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); }
  inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); }
  inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); }
72

Kenton Varda's avatar
Kenton Varda committed
73
  inline int operator-(const IndexingIterator& other) const { return index - other.index; }
74 75 76 77 78 79 80 81

  inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; }
  inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; }
  inline IndexingIterator& operator+=( int amount) { index += amount; return *this; }
  inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; }

  // STL says comparing iterators of different containers is not allowed, so we only compare
  // indices here.
Kenton Varda's avatar
Kenton Varda committed
82 83 84 85 86 87
  inline bool operator==(const IndexingIterator& other) const { return index == other.index; }
  inline bool operator!=(const IndexingIterator& other) const { return index != other.index; }
  inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; }
  inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; }
  inline bool operator< (const IndexingIterator& other) const { return index <  other.index; }
  inline bool operator> (const IndexingIterator& other) const { return index >  other.index; }
88 89

private:
90
  Container* container;
91 92 93
  uint index;

  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 103
  // List of primitives.

104 105
  List() = delete;

106 107
  class Reader {
  public:
108 109
    typedef List<T> Reads;

110
    Reader() = default;
111
    inline explicit Reader(_::ListReader reader): reader(reader) {}
112

113 114
    inline uint size() const { return reader.size() / ELEMENTS; }
    inline T operator[](uint index) const {
115
      KJ_IREQUIRE(index < size());
116 117
      return reader.template getDataElement<T>(index * ELEMENTS);
    }
118

119
    typedef _::IndexingIterator<const Reader, T> Iterator;
120 121
    inline Iterator begin() const { return Iterator(this, 0); }
    inline Iterator end() const { return Iterator(this, size()); }
122 123

  private:
124
    _::ListReader reader;
125
    template <typename U, Kind K>
126
    friend struct _::PointerHelpers;
127 128
    template <typename U, Kind K>
    friend struct List;
129 130 131
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
132 133 134 135
  };

  class Builder {
  public:
136 137
    typedef List<T> Builds;

138 139
    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
140
    inline explicit Builder(_::ListBuilder builder): builder(builder) {}
141

142 143 144
    inline operator Reader() { return Reader(builder.asReader()); }
    inline Reader asReader() { return Reader(builder.asReader()); }

145
    inline uint size() const { return builder.size() / ELEMENTS; }
146
    inline T operator[](uint index) {
147
      KJ_IREQUIRE(index < size());
Kenton Varda's avatar
Kenton Varda committed
148 149 150 151 152 153 154 155 156 157 158
      return builder.template getDataElement<T>(index * ELEMENTS);
    }
    inline void set(uint index, T value) {
      // Alas, it is not possible to make operator[] return a reference to which you can assign,
      // since the encoded representation does not necessarily match the compiler's representation
      // of the type.  We can't even return a clever class that implements operator T() and
      // operator=() because it will lead to surprising behavior when using type inference (e.g.
      // calling a template function with inferred argument types, or using "auto" or "decltype").

      builder.template setDataElement<T>(index * ELEMENTS, value);
    }
159

160
    typedef _::IndexingIterator<Builder, T> Iterator;
161 162
    inline Iterator begin() { return Iterator(this, 0); }
    inline Iterator end() { return Iterator(this, size()); }
163

Kenton Varda's avatar
Kenton Varda committed
164
  private:
165
    _::ListBuilder builder;
166 167 168
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
169
  };
170 171

private:
172 173
  inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
    return builder.initList(_::elementSizeForType<T>(), size * ELEMENTS);
174
  }
175 176
  inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
    return builder.getList(_::elementSizeForType<T>(), defaultValue);
177
  }
178 179 180
  inline static _::ListReader getFromPointer(
      const _::PointerReader& reader, const word* defaultValue) {
    return reader.getList(_::elementSizeForType<T>(), defaultValue);
181 182
  }

183
  template <typename U, Kind k>
Kenton Varda's avatar
Kenton Varda committed
184
  friend struct List;
185
  template <typename U, Kind K>
186
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
187 188 189
};

template <typename T>
190 191 192 193
struct List<T, Kind::ENUM>: public List<T, Kind::PRIMITIVE> {};

template <typename T>
struct List<T, Kind::STRUCT> {
194 195
  // List of structs.

196 197
  List() = delete;

Kenton Varda's avatar
Kenton Varda committed
198 199
  class Reader {
  public:
200 201
    typedef List<T> Reads;

Kenton Varda's avatar
Kenton Varda committed
202
    Reader() = default;
203
    inline explicit Reader(_::ListReader reader): reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
204

205 206
    inline uint size() const { return reader.size() / ELEMENTS; }
    inline typename T::Reader operator[](uint index) const {
207
      KJ_IREQUIRE(index < size());
208
      return typename T::Reader(reader.getStructElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
209
    }
210

211
    typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
212 213
    inline Iterator begin() const { return Iterator(this, 0); }
    inline Iterator end() const { return Iterator(this, size()); }
214

Kenton Varda's avatar
Kenton Varda committed
215
  private:
216
    _::ListReader reader;
217
    template <typename U, Kind K>
218
    friend struct _::PointerHelpers;
219 220
    template <typename U, Kind K>
    friend struct List;
221 222 223
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
224
  };
225

Kenton Varda's avatar
Kenton Varda committed
226 227
  class Builder {
  public:
228 229
    typedef List<T> Builds;

230 231
    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
232
    inline explicit Builder(_::ListBuilder builder): builder(builder) {}
233

234 235 236
    inline operator Reader() { return Reader(builder.asReader()); }
    inline Reader asReader() { return Reader(builder.asReader()); }

237
    inline uint size() const { return builder.size() / ELEMENTS; }
238
    inline typename T::Builder operator[](uint index) {
239
      KJ_IREQUIRE(index < size());
Kenton Varda's avatar
Kenton Varda committed
240
      return typename T::Builder(builder.getStructElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
241
    }
242

243 244 245 246 247 248 249 250 251 252
    inline void adoptWithCaveats(uint index, Orphan<T>&& orphan) {
      // Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from
      // the fact that structs in a struct list are allocated inline rather than by pointer:
      // * This actually performs a shallow copy, effectively adopting each of the orphan's
      //   children rather than adopting the orphan itself.  The orphan ends up being discarded,
      //   possibly wasting space in the message object.
      // * If the orphan is larger than the target struct -- say, because the orphan was built
      //   using a newer version of the schema that has additional fields -- it will be truncated,
      //   losing data.

253 254
      KJ_IREQUIRE(index < size());

255 256 257 258 259 260 261
      // We pass a zero-valued StructSize to asStruct() because we do not want the struct to be
      // expanded under any circumstances.  We're just going to throw it away anyway, and
      // transferContentFrom() already carefully compares the struct sizes before transferring.
      builder.getStructElement(index * ELEMENTS).transferContentFrom(
          orphan.builder.asStruct(_::StructSize(
              0 * WORDS, 0 * POINTERS, _::FieldSize::VOID)));
    }
262 263 264 265 266 267 268
    inline void setWithCaveats(uint index, const typename T::Reader& reader) {
      // Mostly behaves like you'd expect `set` to behave, but with a caveat originating from
      // the fact that structs in a struct list are allocated inline rather than by pointer:
      // If the source struct is larger than the target struct -- say, because the source was built
      // using a newer version of the schema that has additional fields -- it will be truncated,
      // losing data.

269
      KJ_IREQUIRE(index < size());
270 271
      builder.getStructElement(index * ELEMENTS).copyContentFrom(reader._reader);
    }
272

273 274 275 276
    // There are no init(), set(), adopt(), or disown() methods for lists of structs because the
    // elements of the list are inlined and are initialized when the list is initialized.  This
    // means that init() would be redundant, and set() would risk data loss if the input struct
    // were from a newer version of the protocol.
277

278
    typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
279 280
    inline Iterator begin() { return Iterator(this, 0); }
    inline Iterator end() { return Iterator(this, size()); }
281 282

  private:
283
    _::ListBuilder builder;
284 285 286
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
287
  };
288 289

private:
290 291
  inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
    return builder.initStructList(size * ELEMENTS, _::structSize<T>());
292
  }
293 294
  inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
    return builder.getStructList(_::structSize<T>(), defaultValue);
295
  }
296 297 298
  inline static _::ListReader getFromPointer(
      const _::PointerReader& reader, const word* defaultValue) {
    return reader.getList(_::FieldSize::INLINE_COMPOSITE, defaultValue);
299 300
  }

301
  template <typename U, Kind k>
Kenton Varda's avatar
Kenton Varda committed
302
  friend struct List;
303
  template <typename U, Kind K>
304
  friend struct _::PointerHelpers;
305 306 307
};

template <typename T>
308
struct List<List<T>, Kind::LIST> {
309 310
  // List of lists.

311 312
  List() = delete;

313 314
  class Reader {
  public:
315 316
    typedef List<List<T>> Reads;

317
    Reader() = default;
318
    inline explicit Reader(_::ListReader reader): reader(reader) {}
319

320 321
    inline uint size() const { return reader.size() / ELEMENTS; }
    inline typename List<T>::Reader operator[](uint index) const {
322
      KJ_IREQUIRE(index < size());
323 324
      return typename List<T>::Reader(
          _::PointerHelpers<List<T>>::get(reader.getPointerElement(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
325
    }
326

327
    typedef _::IndexingIterator<const Reader, typename List<T>::Reader> Iterator;
328 329
    inline Iterator begin() const { return Iterator(this, 0); }
    inline Iterator end() const { return Iterator(this, size()); }
330 331

  private:
332
    _::ListReader reader;
333
    template <typename U, Kind K>
334
    friend struct _::PointerHelpers;
335 336
    template <typename U, Kind K>
    friend struct List;
337 338 339
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
340 341 342 343
  };

  class Builder {
  public:
344 345
    typedef List<List<T>> Builds;

346 347
    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
348
    inline explicit Builder(_::ListBuilder builder): builder(builder) {}
349

350 351 352
    inline operator Reader() { return Reader(builder.asReader()); }
    inline Reader asReader() { return Reader(builder.asReader()); }

353
    inline uint size() const { return builder.size() / ELEMENTS; }
354
    inline typename List<T>::Builder operator[](uint index) {
355
      KJ_IREQUIRE(index < size());
356 357
      return typename List<T>::Builder(
          _::PointerHelpers<List<T>>::get(builder.getPointerElement(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
358 359
    }
    inline typename List<T>::Builder init(uint index, uint size) {
360
      KJ_IREQUIRE(index < this->size());
361 362
      return typename List<T>::Builder(
          _::PointerHelpers<List<T>>::init(builder.getPointerElement(index * ELEMENTS), size));
Kenton Varda's avatar
Kenton Varda committed
363
    }
364
    inline void set(uint index, typename List<T>::Reader value) {
365
      KJ_IREQUIRE(index < size());
366
      builder.getPointerElement(index * ELEMENTS).setList(value.reader);
367 368
    }
    void set(uint index, std::initializer_list<ReaderFor<T>> value) {
369
      KJ_IREQUIRE(index < size());
370 371 372 373 374 375
      auto l = init(index, value.size());
      uint i = 0;
      for (auto& element: value) {
        l.set(i++, element);
      }
    }
376
    inline void adopt(uint index, Orphan<T>&& value) {
377
      KJ_IREQUIRE(index < size());
378
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value));
379 380
    }
    inline Orphan<T> disown(uint index) {
381
      KJ_IREQUIRE(index < size());
382
      return Orphan<T>(builder.getPointerElement(index * ELEMENTS).disown());
383
    }
384

385
    typedef _::IndexingIterator<Builder, typename List<T>::Builder> Iterator;
386 387
    inline Iterator begin() { return Iterator(this, 0); }
    inline Iterator end() { return Iterator(this, size()); }
388

Kenton Varda's avatar
Kenton Varda committed
389
  private:
390
    _::ListBuilder builder;
391 392 393
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
394
  };
395 396

private:
397 398
  inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
    return builder.initList(_::FieldSize::POINTER, size * ELEMENTS);
399
  }
400 401
  inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
    return builder.getList(_::FieldSize::POINTER, defaultValue);
402
  }
403 404 405
  inline static _::ListReader getFromPointer(
      const _::PointerReader& reader, const word* defaultValue) {
    return reader.getList(_::FieldSize::POINTER, defaultValue);
406 407
  }

408
  template <typename U, Kind k>
Kenton Varda's avatar
Kenton Varda committed
409
  friend struct List;
410
  template <typename U, Kind K>
411
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
412 413
};

414 415
template <typename T>
struct List<T, Kind::BLOB> {
416 417
  List() = delete;

Kenton Varda's avatar
Kenton Varda committed
418 419
  class Reader {
  public:
420 421
    typedef List<T> Reads;

Kenton Varda's avatar
Kenton Varda committed
422
    Reader() = default;
423
    inline explicit Reader(_::ListReader reader): reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
424

425 426
    inline uint size() const { return reader.size() / ELEMENTS; }
    inline typename T::Reader operator[](uint index) const {
427
      KJ_IREQUIRE(index < size());
428
      return reader.getPointerElement(index * ELEMENTS).template getBlob<T>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
429 430
    }

431
    typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
432 433
    inline Iterator begin() const { return Iterator(this, 0); }
    inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
434 435

  private:
436
    _::ListReader reader;
437
    template <typename U, Kind K>
438
    friend struct _::PointerHelpers;
439 440
    template <typename U, Kind K>
    friend struct List;
441 442 443
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
444 445 446 447
  };

  class Builder {
  public:
448 449
    typedef List<T> Builds;

450 451
    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
452
    inline explicit Builder(_::ListBuilder builder): builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
453

454 455 456
    inline operator Reader() { return Reader(builder.asReader()); }
    inline Reader asReader() { return Reader(builder.asReader()); }

457
    inline uint size() const { return builder.size() / ELEMENTS; }
458
    inline typename T::Builder operator[](uint index) {
459
      KJ_IREQUIRE(index < size());
460
      return builder.getPointerElement(index * ELEMENTS).template getBlob<T>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
461
    }
462
    inline void set(uint index, typename T::Reader value) {
463
      KJ_IREQUIRE(index < size());
464
      builder.getPointerElement(index * ELEMENTS).template setBlob<T>(value);
465
    }
466
    inline typename T::Builder init(uint index, uint size) {
467
      KJ_IREQUIRE(index < this->size());
468
      return builder.getPointerElement(index * ELEMENTS).template initBlob<T>(size * BYTES);
Kenton Varda's avatar
Kenton Varda committed
469
    }
470
    inline void adopt(uint index, Orphan<T>&& value) {
471
      KJ_IREQUIRE(index < size());
472
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value));
473 474
    }
    inline Orphan<T> disown(uint index) {
475
      KJ_IREQUIRE(index < size());
476
      return Orphan<T>(builder.getPointerElement(index * ELEMENTS).disown());
477
    }
Kenton Varda's avatar
Kenton Varda committed
478

479
    typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
480 481
    inline Iterator begin() { return Iterator(this, 0); }
    inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
482 483

  private:
484
    _::ListBuilder builder;
485 486 487
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
488
  };
489 490

private:
491 492
  inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
    return builder.initList(_::FieldSize::POINTER, size * ELEMENTS);
493
  }
494 495
  inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
    return builder.getList(_::FieldSize::POINTER, defaultValue);
496
  }
497 498 499
  inline static _::ListReader getFromPointer(
      const _::PointerReader& reader, const word* defaultValue) {
    return reader.getList(_::FieldSize::POINTER, defaultValue);
500 501
  }

502
  template <typename U, Kind k>
Kenton Varda's avatar
Kenton Varda committed
503
  friend struct List;
504
  template <typename U, Kind K>
505
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
506 507
};

508
}  // namespace capnp
509

510 511 512 513 514 515 516 517 518 519
#ifdef KJ_STD_COMPAT
namespace std {

template <typename Container, typename Element>
struct iterator_traits<capnp::_::IndexingIterator<Container, Element>>
      : public std::iterator<std::random_access_iterator_tag, Element, int> {};

}  // namespace std
#endif  // KJ_STD_COMPAT

Kenton Varda's avatar
Kenton Varda committed
520
#endif  // CAPNP_LIST_H_