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