Mercurial > hg > sv-dependency-builds
comparison osx/include/capnp/layout.h @ 49:3ab5a40c4e3b
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
48:9530b331f8c1 | 49:3ab5a40c4e3b |
---|---|
1 // Copyright (c) 2013-2016 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 // This file is NOT intended for use by clients, except in generated code. | |
23 // | |
24 // This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout | |
25 // (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes, | |
26 // as does other parts of the Cap'n proto library which provide a higher-level interface for | |
27 // dynamic introspection. | |
28 | |
29 #ifndef CAPNP_LAYOUT_H_ | |
30 #define CAPNP_LAYOUT_H_ | |
31 | |
32 #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) | |
33 #pragma GCC system_header | |
34 #endif | |
35 | |
36 #include <kj/common.h> | |
37 #include <kj/memory.h> | |
38 #include "common.h" | |
39 #include "blob.h" | |
40 #include "endian.h" | |
41 | |
42 #if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN) | |
43 #define CAPNP_CANONICALIZE_NAN 1 | |
44 // Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by | |
45 // __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN | |
46 // signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in | |
47 // particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world. | |
48 // Canonicalizing them makes output consistent (which is important!), but hurts performance | |
49 // slightly. | |
50 // | |
51 // Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work. | |
52 // Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs. | |
53 // everyone else. It would be great if we could just flip that bit, but we can't, because if the | |
54 // significand is all-zero, then the value is infinity rather than NaN. This means that on most | |
55 // machines, where the bit indicates quietness, there is one more quiet NaN value than signalling | |
56 // NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic | |
57 // mapping that properly preserves quietness. Instead of doing something hacky, we just give up | |
58 // and blow away NaN payloads, because no one uses them anyway. | |
59 #endif | |
60 | |
61 namespace capnp { | |
62 | |
63 #if !CAPNP_LITE | |
64 class ClientHook; | |
65 #endif // !CAPNP_LITE | |
66 | |
67 namespace _ { // private | |
68 | |
69 class PointerBuilder; | |
70 class PointerReader; | |
71 class StructBuilder; | |
72 class StructReader; | |
73 class ListBuilder; | |
74 class ListReader; | |
75 class OrphanBuilder; | |
76 struct WirePointer; | |
77 struct WireHelpers; | |
78 class SegmentReader; | |
79 class SegmentBuilder; | |
80 class Arena; | |
81 class BuilderArena; | |
82 | |
83 // ============================================================================= | |
84 | |
85 typedef decltype(BITS / ELEMENTS) BitsPerElement; | |
86 typedef decltype(POINTERS / ELEMENTS) PointersPerElement; | |
87 | |
88 static constexpr BitsPerElement BITS_PER_ELEMENT_TABLE[8] = { | |
89 0 * BITS / ELEMENTS, | |
90 1 * BITS / ELEMENTS, | |
91 8 * BITS / ELEMENTS, | |
92 16 * BITS / ELEMENTS, | |
93 32 * BITS / ELEMENTS, | |
94 64 * BITS / ELEMENTS, | |
95 0 * BITS / ELEMENTS, | |
96 0 * BITS / ELEMENTS | |
97 }; | |
98 | |
99 inline KJ_CONSTEXPR() BitsPerElement dataBitsPerElement(ElementSize size) { | |
100 return _::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)]; | |
101 } | |
102 | |
103 inline constexpr PointersPerElement pointersPerElement(ElementSize size) { | |
104 return size == ElementSize::POINTER ? 1 * POINTERS / ELEMENTS : 0 * POINTERS / ELEMENTS; | |
105 } | |
106 | |
107 template <size_t size> struct ElementSizeForByteSize; | |
108 template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; }; | |
109 template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; }; | |
110 template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; }; | |
111 template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; }; | |
112 | |
113 template <typename T> struct ElementSizeForType { | |
114 static constexpr ElementSize value = | |
115 // Primitive types that aren't special-cased below can be determined from sizeof(). | |
116 CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize<sizeof(T)>::value : | |
117 CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES : | |
118 CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE : | |
119 | |
120 // Everything else is a pointer. | |
121 ElementSize::POINTER; | |
122 }; | |
123 | |
124 // Void and bool are special. | |
125 template <> struct ElementSizeForType<Void> { static constexpr ElementSize value = ElementSize::VOID; }; | |
126 template <> struct ElementSizeForType<bool> { static constexpr ElementSize value = ElementSize::BIT; }; | |
127 | |
128 // Lists and blobs are pointers, not structs. | |
129 template <typename T, bool b> struct ElementSizeForType<List<T, b>> { | |
130 static constexpr ElementSize value = ElementSize::POINTER; | |
131 }; | |
132 template <> struct ElementSizeForType<Text> { | |
133 static constexpr ElementSize value = ElementSize::POINTER; | |
134 }; | |
135 template <> struct ElementSizeForType<Data> { | |
136 static constexpr ElementSize value = ElementSize::POINTER; | |
137 }; | |
138 | |
139 template <typename T> | |
140 inline constexpr ElementSize elementSizeForType() { | |
141 return ElementSizeForType<T>::value; | |
142 } | |
143 | |
144 struct MessageSizeCounts { | |
145 WordCount64 wordCount; | |
146 uint capCount; | |
147 | |
148 MessageSizeCounts& operator+=(const MessageSizeCounts& other) { | |
149 wordCount += other.wordCount; | |
150 capCount += other.capCount; | |
151 return *this; | |
152 } | |
153 | |
154 MessageSize asPublic() { | |
155 return MessageSize { wordCount / WORDS, capCount }; | |
156 } | |
157 }; | |
158 | |
159 // ============================================================================= | |
160 | |
161 template <int wordCount> | |
162 union AlignedData { | |
163 // Useful for declaring static constant data blobs as an array of bytes, but forcing those | |
164 // bytes to be word-aligned. | |
165 | |
166 uint8_t bytes[wordCount * sizeof(word)]; | |
167 word words[wordCount]; | |
168 }; | |
169 | |
170 struct StructSize { | |
171 WordCount16 data; | |
172 WirePointerCount16 pointers; | |
173 | |
174 inline constexpr WordCount total() const { return data + pointers * WORDS_PER_POINTER; } | |
175 | |
176 StructSize() = default; | |
177 inline constexpr StructSize(WordCount data, WirePointerCount pointers) | |
178 : data(data), pointers(pointers) {} | |
179 }; | |
180 | |
181 template <typename T, typename CapnpPrivate = typename T::_capnpPrivate> | |
182 inline constexpr StructSize structSize() { | |
183 return StructSize(CapnpPrivate::dataWordSize * WORDS, CapnpPrivate::pointerCount * POINTERS); | |
184 } | |
185 | |
186 template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, | |
187 typename = kj::EnableIf<CAPNP_KIND(T) == Kind::STRUCT>> | |
188 inline constexpr StructSize minStructSizeForElement() { | |
189 // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough | |
190 // to hold a T. | |
191 | |
192 return StructSize(CapnpPrivate::dataWordSize * WORDS, CapnpPrivate::pointerCount * POINTERS); | |
193 } | |
194 | |
195 template <typename T, typename = kj::EnableIf<CAPNP_KIND(T) != Kind::STRUCT>> | |
196 inline constexpr StructSize minStructSizeForElement() { | |
197 // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough | |
198 // to hold a T. | |
199 | |
200 return StructSize( | |
201 dataBitsPerElement(elementSizeForType<T>()) * ELEMENTS > 0 * BITS ? 1 * WORDS : 0 * WORDS, | |
202 pointersPerElement(elementSizeForType<T>()) * ELEMENTS); | |
203 } | |
204 | |
205 // ------------------------------------------------------------------- | |
206 // Masking of default values | |
207 | |
208 template <typename T, Kind kind = CAPNP_KIND(T)> struct Mask_; | |
209 template <typename T> struct Mask_<T, Kind::PRIMITIVE> { typedef T Type; }; | |
210 template <typename T> struct Mask_<T, Kind::ENUM> { typedef uint16_t Type; }; | |
211 template <> struct Mask_<float, Kind::PRIMITIVE> { typedef uint32_t Type; }; | |
212 template <> struct Mask_<double, Kind::PRIMITIVE> { typedef uint64_t Type; }; | |
213 | |
214 template <typename T> struct Mask_<T, Kind::OTHER> { | |
215 // Union discriminants end up here. | |
216 static_assert(sizeof(T) == 2, "Don't know how to mask this type."); | |
217 typedef uint16_t Type; | |
218 }; | |
219 | |
220 template <typename T> | |
221 using Mask = typename Mask_<T>::Type; | |
222 | |
223 template <typename T> | |
224 KJ_ALWAYS_INLINE(Mask<T> mask(T value, Mask<T> mask)); | |
225 template <typename T> | |
226 KJ_ALWAYS_INLINE(T unmask(Mask<T> value, Mask<T> mask)); | |
227 | |
228 template <typename T> | |
229 inline Mask<T> mask(T value, Mask<T> mask) { | |
230 return static_cast<Mask<T> >(value) ^ mask; | |
231 } | |
232 | |
233 template <> | |
234 inline uint32_t mask<float>(float value, uint32_t mask) { | |
235 #if CAPNP_CANONICALIZE_NAN | |
236 if (value != value) { | |
237 return 0x7fc00000u ^ mask; | |
238 } | |
239 #endif | |
240 | |
241 uint32_t i; | |
242 static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?"); | |
243 memcpy(&i, &value, sizeof(value)); | |
244 return i ^ mask; | |
245 } | |
246 | |
247 template <> | |
248 inline uint64_t mask<double>(double value, uint64_t mask) { | |
249 #if CAPNP_CANONICALIZE_NAN | |
250 if (value != value) { | |
251 return 0x7ff8000000000000ull ^ mask; | |
252 } | |
253 #endif | |
254 | |
255 uint64_t i; | |
256 static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?"); | |
257 memcpy(&i, &value, sizeof(value)); | |
258 return i ^ mask; | |
259 } | |
260 | |
261 template <typename T> | |
262 inline T unmask(Mask<T> value, Mask<T> mask) { | |
263 return static_cast<T>(value ^ mask); | |
264 } | |
265 | |
266 template <> | |
267 inline float unmask<float>(uint32_t value, uint32_t mask) { | |
268 value ^= mask; | |
269 float result; | |
270 static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?"); | |
271 memcpy(&result, &value, sizeof(value)); | |
272 return result; | |
273 } | |
274 | |
275 template <> | |
276 inline double unmask<double>(uint64_t value, uint64_t mask) { | |
277 value ^= mask; | |
278 double result; | |
279 static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?"); | |
280 memcpy(&result, &value, sizeof(value)); | |
281 return result; | |
282 } | |
283 | |
284 // ------------------------------------------------------------------- | |
285 | |
286 class CapTableReader { | |
287 public: | |
288 #if !CAPNP_LITE | |
289 virtual kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) = 0; | |
290 // Extract the capability at the given index. If the index is invalid, returns null. | |
291 #endif // !CAPNP_LITE | |
292 }; | |
293 | |
294 class CapTableBuilder: public CapTableReader { | |
295 public: | |
296 #if !CAPNP_LITE | |
297 virtual uint injectCap(kj::Own<ClientHook>&& cap) = 0; | |
298 // Add the capability to the message and return its index. If the same ClientHook is injected | |
299 // twice, this may return the same index both times, but in this case dropCap() needs to be | |
300 // called an equal number of times to actually remove the cap. | |
301 | |
302 virtual void dropCap(uint index) = 0; | |
303 // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out. | |
304 #endif // !CAPNP_LITE | |
305 }; | |
306 | |
307 // ------------------------------------------------------------------- | |
308 | |
309 class PointerBuilder: public kj::DisallowConstCopy { | |
310 // Represents a single pointer, usually embedded in a struct or a list. | |
311 | |
312 public: | |
313 inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {} | |
314 | |
315 static inline PointerBuilder getRoot( | |
316 SegmentBuilder* segment, CapTableBuilder* capTable, word* location); | |
317 // Get a PointerBuilder representing a message root located in the given segment at the given | |
318 // location. | |
319 | |
320 inline bool isNull() { return getPointerType() == PointerType::NULL_; } | |
321 PointerType getPointerType(); | |
322 | |
323 StructBuilder getStruct(StructSize size, const word* defaultValue); | |
324 ListBuilder getList(ElementSize elementSize, const word* defaultValue); | |
325 ListBuilder getStructList(StructSize elementSize, const word* defaultValue); | |
326 ListBuilder getListAnySize(const word* defaultValue); | |
327 template <typename T> typename T::Builder getBlob(const void* defaultValue,ByteCount defaultSize); | |
328 #if !CAPNP_LITE | |
329 kj::Own<ClientHook> getCapability(); | |
330 #endif // !CAPNP_LITE | |
331 // Get methods: Get the value. If it is null, initialize it to a copy of the default value. | |
332 // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a | |
333 // simple byte array for blobs. | |
334 | |
335 StructBuilder initStruct(StructSize size); | |
336 ListBuilder initList(ElementSize elementSize, ElementCount elementCount); | |
337 ListBuilder initStructList(ElementCount elementCount, StructSize size); | |
338 template <typename T> typename T::Builder initBlob(ByteCount size); | |
339 // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing | |
340 // object. | |
341 | |
342 void setStruct(const StructReader& value, bool canonical = false); | |
343 void setList(const ListReader& value, bool canonical = false); | |
344 template <typename T> void setBlob(typename T::Reader value); | |
345 #if !CAPNP_LITE | |
346 void setCapability(kj::Own<ClientHook>&& cap); | |
347 #endif // !CAPNP_LITE | |
348 // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding | |
349 // the existing object. | |
350 | |
351 void adopt(OrphanBuilder&& orphan); | |
352 // Set the pointer to point at the given orphaned value. | |
353 | |
354 OrphanBuilder disown(); | |
355 // Set the pointer to null and return its previous value as an orphan. | |
356 | |
357 void clear(); | |
358 // Clear the pointer to null, discarding its previous value. | |
359 | |
360 void transferFrom(PointerBuilder other); | |
361 // Equivalent to `adopt(other.disown())`. | |
362 | |
363 void copyFrom(PointerReader other, bool canonical = false); | |
364 // Equivalent to `set(other.get())`. | |
365 // If you set the canonical flag, it will attempt to lay the target out | |
366 // canonically, provided enough space is available. | |
367 | |
368 PointerReader asReader() const; | |
369 | |
370 BuilderArena* getArena() const; | |
371 // Get the arena containing this pointer. | |
372 | |
373 CapTableBuilder* getCapTable(); | |
374 // Gets the capability context in which this object is operating. | |
375 | |
376 PointerBuilder imbue(CapTableBuilder* capTable); | |
377 // Return a copy of this builder except using the given capability context. | |
378 | |
379 private: | |
380 SegmentBuilder* segment; // Memory segment in which the pointer resides. | |
381 CapTableBuilder* capTable; // Table of capability indexes. | |
382 WirePointer* pointer; // Pointer to the pointer. | |
383 | |
384 inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer) | |
385 : segment(segment), capTable(capTable), pointer(pointer) {} | |
386 | |
387 friend class StructBuilder; | |
388 friend class ListBuilder; | |
389 friend class OrphanBuilder; | |
390 }; | |
391 | |
392 class PointerReader { | |
393 public: | |
394 inline PointerReader() | |
395 : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {} | |
396 | |
397 static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable, | |
398 const word* location, int nestingLimit); | |
399 // Get a PointerReader representing a message root located in the given segment at the given | |
400 // location. | |
401 | |
402 static inline PointerReader getRootUnchecked(const word* location); | |
403 // Get a PointerReader for an unchecked message. | |
404 | |
405 MessageSizeCounts targetSize() const; | |
406 // Return the total size of the target object and everything to which it points. Does not count | |
407 // far pointer overhead. This is useful for deciding how much space is needed to copy the object | |
408 // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, | |
409 // use the result as a hint for allocating the first segment, do the copy, and then throw an | |
410 // exception if it overruns. | |
411 | |
412 inline bool isNull() const { return getPointerType() == PointerType::NULL_; } | |
413 PointerType getPointerType() const; | |
414 | |
415 StructReader getStruct(const word* defaultValue) const; | |
416 ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const; | |
417 ListReader getListAnySize(const word* defaultValue) const; | |
418 template <typename T> | |
419 typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; | |
420 #if !CAPNP_LITE | |
421 kj::Own<ClientHook> getCapability() const; | |
422 #endif // !CAPNP_LITE | |
423 // Get methods: Get the value. If it is null, return the default value instead. | |
424 // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a | |
425 // simple byte array for blobs. | |
426 | |
427 const word* getUnchecked() const; | |
428 // If this is an unchecked message, get a word* pointing at the location of the pointer. This | |
429 // word* can actually be passed to readUnchecked() to read the designated sub-object later. If | |
430 // this isn't an unchecked message, throws an exception. | |
431 | |
432 kj::Maybe<Arena&> getArena() const; | |
433 // Get the arena containing this pointer. | |
434 | |
435 CapTableReader* getCapTable(); | |
436 // Gets the capability context in which this object is operating. | |
437 | |
438 PointerReader imbue(CapTableReader* capTable) const; | |
439 // Return a copy of this reader except using the given capability context. | |
440 | |
441 bool isCanonical(const word **readHead); | |
442 // Validate this pointer's canonicity, subject to the conditions: | |
443 // * All data to the left of readHead has been read thus far (for pointer | |
444 // ordering) | |
445 // * All pointers in preorder have already been checked | |
446 // * This pointer is in the first and only segment of the message | |
447 | |
448 private: | |
449 SegmentReader* segment; // Memory segment in which the pointer resides. | |
450 CapTableReader* capTable; // Table of capability indexes. | |
451 const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. | |
452 | |
453 int nestingLimit; | |
454 // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. | |
455 // Once this reaches zero, further pointers will be pruned. | |
456 | |
457 inline PointerReader(SegmentReader* segment, CapTableReader* capTable, | |
458 const WirePointer* pointer, int nestingLimit) | |
459 : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {} | |
460 | |
461 friend class StructReader; | |
462 friend class ListReader; | |
463 friend class PointerBuilder; | |
464 friend class OrphanBuilder; | |
465 }; | |
466 | |
467 // ------------------------------------------------------------------- | |
468 | |
469 class StructBuilder: public kj::DisallowConstCopy { | |
470 public: | |
471 inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {} | |
472 | |
473 inline word* getLocation() { return reinterpret_cast<word*>(data); } | |
474 // Get the object's location. Only valid for independently-allocated objects (i.e. not list | |
475 // elements). | |
476 | |
477 inline BitCount getDataSectionSize() const { return dataSize; } | |
478 inline WirePointerCount getPointerSectionSize() const { return pointerCount; } | |
479 inline kj::ArrayPtr<byte> getDataSectionAsBlob(); | |
480 inline _::ListBuilder getPointerSectionAsList(); | |
481 | |
482 template <typename T> | |
483 KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset)); | |
484 // Return true if the field is set to something other than its default value. | |
485 | |
486 template <typename T> | |
487 KJ_ALWAYS_INLINE(T getDataField(ElementCount offset)); | |
488 // Gets the data field value of the given type at the given offset. The offset is measured in | |
489 // multiples of the field size, determined by the type. | |
490 | |
491 template <typename T> | |
492 KJ_ALWAYS_INLINE(T getDataField(ElementCount offset, Mask<T> mask)); | |
493 // Like getDataField() but applies the given XOR mask to the data on load. Used for reading | |
494 // fields with non-zero default values. | |
495 | |
496 template <typename T> | |
497 KJ_ALWAYS_INLINE(void setDataField( | |
498 ElementCount offset, kj::NoInfer<T> value)); | |
499 // Sets the data field value at the given offset. | |
500 | |
501 template <typename T> | |
502 KJ_ALWAYS_INLINE(void setDataField( | |
503 ElementCount offset, kj::NoInfer<T> value, Mask<T> mask)); | |
504 // Like setDataField() but applies the given XOR mask before storing. Used for writing fields | |
505 // with non-zero default values. | |
506 | |
507 KJ_ALWAYS_INLINE(PointerBuilder getPointerField(WirePointerCount ptrIndex)); | |
508 // Get a builder for a pointer field given the index within the pointer section. | |
509 | |
510 void clearAll(); | |
511 // Clear all pointers and data. | |
512 | |
513 void transferContentFrom(StructBuilder other); | |
514 // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger | |
515 // than this, the extra data is not transferred, meaning there is a risk of data loss when | |
516 // transferring from messages built with future versions of the protocol. | |
517 | |
518 void copyContentFrom(StructReader other); | |
519 // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not | |
520 // copied, meaning there is a risk of data loss when copying from messages built with future | |
521 // versions of the protocol. | |
522 | |
523 StructReader asReader() const; | |
524 // Gets a StructReader pointing at the same memory. | |
525 | |
526 BuilderArena* getArena(); | |
527 // Gets the arena in which this object is allocated. | |
528 | |
529 CapTableBuilder* getCapTable(); | |
530 // Gets the capability context in which this object is operating. | |
531 | |
532 StructBuilder imbue(CapTableBuilder* capTable); | |
533 // Return a copy of this builder except using the given capability context. | |
534 | |
535 private: | |
536 SegmentBuilder* segment; // Memory segment in which the struct resides. | |
537 CapTableBuilder* capTable; // Table of capability indexes. | |
538 void* data; // Pointer to the encoded data. | |
539 WirePointer* pointers; // Pointer to the encoded pointers. | |
540 | |
541 BitCount32 dataSize; | |
542 // Size of data section. We use a bit count rather than a word count to more easily handle the | |
543 // case of struct lists encoded with less than a word per element. | |
544 | |
545 WirePointerCount16 pointerCount; // Size of the pointer section. | |
546 | |
547 inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, | |
548 void* data, WirePointer* pointers, | |
549 BitCount dataSize, WirePointerCount pointerCount) | |
550 : segment(segment), capTable(capTable), data(data), pointers(pointers), | |
551 dataSize(dataSize), pointerCount(pointerCount) {} | |
552 | |
553 friend class ListBuilder; | |
554 friend struct WireHelpers; | |
555 friend class OrphanBuilder; | |
556 }; | |
557 | |
558 class StructReader { | |
559 public: | |
560 inline StructReader() | |
561 : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr), dataSize(0), | |
562 pointerCount(0), nestingLimit(0x7fffffff) {} | |
563 inline StructReader(kj::ArrayPtr<const word> data) | |
564 : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr), | |
565 dataSize(data.size() * WORDS * BITS_PER_WORD), pointerCount(0), nestingLimit(0x7fffffff) {} | |
566 | |
567 const void* getLocation() const { return data; } | |
568 | |
569 inline BitCount getDataSectionSize() const { return dataSize; } | |
570 inline WirePointerCount getPointerSectionSize() const { return pointerCount; } | |
571 inline kj::ArrayPtr<const byte> getDataSectionAsBlob(); | |
572 inline _::ListReader getPointerSectionAsList(); | |
573 | |
574 kj::Array<word> canonicalize(); | |
575 | |
576 template <typename T> | |
577 KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const); | |
578 // Return true if the field is set to something other than its default value. | |
579 | |
580 template <typename T> | |
581 KJ_ALWAYS_INLINE(T getDataField(ElementCount offset) const); | |
582 // Get the data field value of the given type at the given offset. The offset is measured in | |
583 // multiples of the field size, determined by the type. Returns zero if the offset is past the | |
584 // end of the struct's data section. | |
585 | |
586 template <typename T> | |
587 KJ_ALWAYS_INLINE( | |
588 T getDataField(ElementCount offset, Mask<T> mask) const); | |
589 // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading | |
590 // fields with non-zero default values. | |
591 | |
592 KJ_ALWAYS_INLINE(PointerReader getPointerField(WirePointerCount ptrIndex) const); | |
593 // Get a reader for a pointer field given the index within the pointer section. If the index | |
594 // is out-of-bounds, returns a null pointer. | |
595 | |
596 MessageSizeCounts totalSize() const; | |
597 // Return the total size of the struct and everything to which it points. Does not count far | |
598 // pointer overhead. This is useful for deciding how much space is needed to copy the struct | |
599 // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, | |
600 // use the result as a hint for allocating the first segment, do the copy, and then throw an | |
601 // exception if it overruns. | |
602 | |
603 CapTableReader* getCapTable(); | |
604 // Gets the capability context in which this object is operating. | |
605 | |
606 StructReader imbue(CapTableReader* capTable) const; | |
607 // Return a copy of this reader except using the given capability context. | |
608 | |
609 bool isCanonical(const word **readHead, const word **ptrHead, | |
610 bool *dataTrunc, bool *ptrTrunc); | |
611 // Validate this pointer's canonicity, subject to the conditions: | |
612 // * All data to the left of readHead has been read thus far (for pointer | |
613 // ordering) | |
614 // * All pointers in preorder have already been checked | |
615 // * This pointer is in the first and only segment of the message | |
616 // | |
617 // If this function returns false, the struct is non-canonical. If it | |
618 // returns true, then: | |
619 // * If it is a composite in a list, it is canonical if at least one struct | |
620 // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1 | |
621 // * If it is derived from a struct pointer, it is canonical if | |
622 // dataTrunc = 1 AND ptrTrunc = 1 | |
623 | |
624 private: | |
625 SegmentReader* segment; // Memory segment in which the struct resides. | |
626 CapTableReader* capTable; // Table of capability indexes. | |
627 | |
628 const void* data; | |
629 const WirePointer* pointers; | |
630 | |
631 BitCount32 dataSize; | |
632 // Size of data section. We use a bit count rather than a word count to more easily handle the | |
633 // case of struct lists encoded with less than a word per element. | |
634 | |
635 WirePointerCount16 pointerCount; // Size of the pointer section. | |
636 | |
637 int nestingLimit; | |
638 // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. | |
639 // Once this reaches zero, further pointers will be pruned. | |
640 // TODO(perf): Limit to 16 bits for better packing? | |
641 | |
642 inline StructReader(SegmentReader* segment, CapTableReader* capTable, | |
643 const void* data, const WirePointer* pointers, | |
644 BitCount dataSize, WirePointerCount pointerCount, int nestingLimit) | |
645 : segment(segment), capTable(capTable), data(data), pointers(pointers), | |
646 dataSize(dataSize), pointerCount(pointerCount), | |
647 nestingLimit(nestingLimit) {} | |
648 | |
649 friend class ListReader; | |
650 friend class StructBuilder; | |
651 friend struct WireHelpers; | |
652 }; | |
653 | |
654 // ------------------------------------------------------------------- | |
655 | |
656 class ListBuilder: public kj::DisallowConstCopy { | |
657 public: | |
658 inline explicit ListBuilder(ElementSize elementSize) | |
659 : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS), | |
660 step(0 * BITS / ELEMENTS), structDataSize(0 * BITS), structPointerCount(0 * POINTERS), | |
661 elementSize(elementSize) {} | |
662 | |
663 inline word* getLocation() { | |
664 // Get the object's location. | |
665 | |
666 if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) { | |
667 return reinterpret_cast<word*>(ptr) - POINTER_SIZE_IN_WORDS; | |
668 } else { | |
669 return reinterpret_cast<word*>(ptr); | |
670 } | |
671 } | |
672 | |
673 inline ElementSize getElementSize() const { return elementSize; } | |
674 | |
675 inline ElementCount size() const; | |
676 // The number of elements in the list. | |
677 | |
678 Text::Builder asText(); | |
679 Data::Builder asData(); | |
680 // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. | |
681 | |
682 template <typename T> | |
683 KJ_ALWAYS_INLINE(T getDataElement(ElementCount index)); | |
684 // Get the element of the given type at the given index. | |
685 | |
686 template <typename T> | |
687 KJ_ALWAYS_INLINE(void setDataElement( | |
688 ElementCount index, kj::NoInfer<T> value)); | |
689 // Set the element at the given index. | |
690 | |
691 KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index)); | |
692 | |
693 StructBuilder getStructElement(ElementCount index); | |
694 | |
695 ListReader asReader() const; | |
696 // Get a ListReader pointing at the same memory. | |
697 | |
698 BuilderArena* getArena(); | |
699 // Gets the arena in which this object is allocated. | |
700 | |
701 CapTableBuilder* getCapTable(); | |
702 // Gets the capability context in which this object is operating. | |
703 | |
704 ListBuilder imbue(CapTableBuilder* capTable); | |
705 // Return a copy of this builder except using the given capability context. | |
706 | |
707 private: | |
708 SegmentBuilder* segment; // Memory segment in which the list resides. | |
709 CapTableBuilder* capTable; // Table of capability indexes. | |
710 | |
711 byte* ptr; // Pointer to list content. | |
712 | |
713 ElementCount elementCount; // Number of elements in the list. | |
714 | |
715 decltype(BITS / ELEMENTS) step; | |
716 // The distance between elements. | |
717 | |
718 BitCount32 structDataSize; | |
719 WirePointerCount16 structPointerCount; | |
720 // The struct properties to use when interpreting the elements as structs. All lists can be | |
721 // interpreted as struct lists, so these are always filled in. | |
722 | |
723 ElementSize elementSize; | |
724 // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE | |
725 // from other types when the overall size is exactly zero or one words. | |
726 | |
727 inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr, | |
728 decltype(BITS / ELEMENTS) step, ElementCount size, | |
729 BitCount structDataSize, WirePointerCount structPointerCount, | |
730 ElementSize elementSize) | |
731 : segment(segment), capTable(capTable), ptr(reinterpret_cast<byte*>(ptr)), | |
732 elementCount(size), step(step), structDataSize(structDataSize), | |
733 structPointerCount(structPointerCount), elementSize(elementSize) {} | |
734 | |
735 friend class StructBuilder; | |
736 friend struct WireHelpers; | |
737 friend class OrphanBuilder; | |
738 }; | |
739 | |
740 class ListReader { | |
741 public: | |
742 inline explicit ListReader(ElementSize elementSize) | |
743 : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0), | |
744 step(0 * BITS / ELEMENTS), structDataSize(0), structPointerCount(0), | |
745 elementSize(elementSize), nestingLimit(0x7fffffff) {} | |
746 | |
747 inline ElementCount size() const; | |
748 // The number of elements in the list. | |
749 | |
750 inline ElementSize getElementSize() const { return elementSize; } | |
751 | |
752 Text::Reader asText(); | |
753 Data::Reader asData(); | |
754 // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. | |
755 | |
756 kj::ArrayPtr<const byte> asRawBytes(); | |
757 | |
758 template <typename T> | |
759 KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const); | |
760 // Get the element of the given type at the given index. | |
761 | |
762 KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const); | |
763 | |
764 StructReader getStructElement(ElementCount index) const; | |
765 | |
766 CapTableReader* getCapTable(); | |
767 // Gets the capability context in which this object is operating. | |
768 | |
769 ListReader imbue(CapTableReader* capTable) const; | |
770 // Return a copy of this reader except using the given capability context. | |
771 | |
772 bool isCanonical(const word **readHead); | |
773 // Validate this pointer's canonicity, subject to the conditions: | |
774 // * All data to the left of readHead has been read thus far (for pointer | |
775 // ordering) | |
776 // * All pointers in preorder have already been checked | |
777 // * This pointer is in the first and only segment of the message | |
778 | |
779 private: | |
780 SegmentReader* segment; // Memory segment in which the list resides. | |
781 CapTableReader* capTable; // Table of capability indexes. | |
782 | |
783 const byte* ptr; // Pointer to list content. | |
784 | |
785 ElementCount elementCount; // Number of elements in the list. | |
786 | |
787 decltype(BITS / ELEMENTS) step; | |
788 // The distance between elements. | |
789 | |
790 BitCount32 structDataSize; | |
791 WirePointerCount16 structPointerCount; | |
792 // The struct properties to use when interpreting the elements as structs. All lists can be | |
793 // interpreted as struct lists, so these are always filled in. | |
794 | |
795 ElementSize elementSize; | |
796 // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE | |
797 // from other types when the overall size is exactly zero or one words. | |
798 | |
799 int nestingLimit; | |
800 // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. | |
801 // Once this reaches zero, further pointers will be pruned. | |
802 | |
803 inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr, | |
804 ElementCount elementCount, decltype(BITS / ELEMENTS) step, | |
805 BitCount structDataSize, WirePointerCount structPointerCount, | |
806 ElementSize elementSize, int nestingLimit) | |
807 : segment(segment), capTable(capTable), ptr(reinterpret_cast<const byte*>(ptr)), | |
808 elementCount(elementCount), step(step), structDataSize(structDataSize), | |
809 structPointerCount(structPointerCount), elementSize(elementSize), | |
810 nestingLimit(nestingLimit) {} | |
811 | |
812 friend class StructReader; | |
813 friend class ListBuilder; | |
814 friend struct WireHelpers; | |
815 friend class OrphanBuilder; | |
816 }; | |
817 | |
818 // ------------------------------------------------------------------- | |
819 | |
820 class OrphanBuilder { | |
821 public: | |
822 inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) { | |
823 memset(&tag, 0, sizeof(tag)); | |
824 } | |
825 OrphanBuilder(const OrphanBuilder& other) = delete; | |
826 inline OrphanBuilder(OrphanBuilder&& other) noexcept; | |
827 inline ~OrphanBuilder() noexcept(false); | |
828 | |
829 static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size); | |
830 static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable, | |
831 ElementCount elementCount, ElementSize elementSize); | |
832 static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable, | |
833 ElementCount elementCount, StructSize elementSize); | |
834 static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); | |
835 static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); | |
836 | |
837 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom); | |
838 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom); | |
839 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom); | |
840 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom); | |
841 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom); | |
842 #if !CAPNP_LITE | |
843 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, | |
844 kj::Own<ClientHook> copyFrom); | |
845 #endif // !CAPNP_LITE | |
846 | |
847 static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable, | |
848 ElementSize expectedElementSize, StructSize expectedStructSize, | |
849 kj::ArrayPtr<const ListReader> lists); | |
850 | |
851 static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data); | |
852 | |
853 OrphanBuilder& operator=(const OrphanBuilder& other) = delete; | |
854 inline OrphanBuilder& operator=(OrphanBuilder&& other); | |
855 | |
856 inline bool operator==(decltype(nullptr)) const { return location == nullptr; } | |
857 inline bool operator!=(decltype(nullptr)) const { return location != nullptr; } | |
858 | |
859 StructBuilder asStruct(StructSize size); | |
860 // Interpret as a struct, or throw an exception if not a struct. | |
861 | |
862 ListBuilder asList(ElementSize elementSize); | |
863 // Interpret as a list, or throw an exception if not a list. elementSize cannot be | |
864 // INLINE_COMPOSITE -- use asStructList() instead. | |
865 | |
866 ListBuilder asStructList(StructSize elementSize); | |
867 // Interpret as a struct list, or throw an exception if not a list. | |
868 | |
869 Text::Builder asText(); | |
870 Data::Builder asData(); | |
871 // Interpret as a blob, or throw an exception if not a blob. | |
872 | |
873 StructReader asStructReader(StructSize size) const; | |
874 ListReader asListReader(ElementSize elementSize) const; | |
875 #if !CAPNP_LITE | |
876 kj::Own<ClientHook> asCapability() const; | |
877 #endif // !CAPNP_LITE | |
878 Text::Reader asTextReader() const; | |
879 Data::Reader asDataReader() const; | |
880 | |
881 bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT; | |
882 // Resize the orphan list to the given size. Returns false if the list is currently empty but | |
883 // the requested size is non-zero, in which case the caller will need to allocate a new list. | |
884 | |
885 void truncate(ElementCount size, ElementSize elementSize); | |
886 void truncate(ElementCount size, StructSize elementSize); | |
887 void truncateText(ElementCount size); | |
888 // Versions of truncate() that know how to allocate a new list if needed. | |
889 | |
890 private: | |
891 static_assert(1 * POINTERS * WORDS_PER_POINTER == 1 * WORDS, | |
892 "This struct assumes a pointer is one word."); | |
893 word tag; | |
894 // Contains an encoded WirePointer representing this object. WirePointer is defined in | |
895 // layout.c++, but fits in a word. | |
896 // | |
897 // This may be a FAR pointer. Even in that case, `location` points to the eventual destination | |
898 // of that far pointer. The reason we keep the far pointer around rather than just making `tag` | |
899 // represent the final destination is because if the eventual adopter of the pointer is not in | |
900 // the target's segment then it may be useful to reuse the far pointer landing pad. | |
901 // | |
902 // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual | |
903 // target. | |
904 | |
905 SegmentBuilder* segment; | |
906 // Segment in which the object resides. | |
907 | |
908 CapTableBuilder* capTable; | |
909 // Table of capability indexes. | |
910 | |
911 word* location; | |
912 // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this | |
913 // 0x1 just so that it is non-null for operator==, but it is never used. | |
914 | |
915 inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, | |
916 CapTableBuilder* capTable, word* location) | |
917 : segment(segment), capTable(capTable), location(location) { | |
918 memcpy(&tag, tagPtr, sizeof(tag)); | |
919 } | |
920 | |
921 inline WirePointer* tagAsPtr() { return reinterpret_cast<WirePointer*>(&tag); } | |
922 inline const WirePointer* tagAsPtr() const { return reinterpret_cast<const WirePointer*>(&tag); } | |
923 | |
924 void euthanize(); | |
925 // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when | |
926 // the OrphanBuilder is being destroyed or overwritten and it is non-null. | |
927 | |
928 friend struct WireHelpers; | |
929 }; | |
930 | |
931 // ======================================================================================= | |
932 // Internal implementation details... | |
933 | |
934 // These are defined in the source file. | |
935 template <> typename Text::Builder PointerBuilder::initBlob<Text>(ByteCount size); | |
936 template <> void PointerBuilder::setBlob<Text>(typename Text::Reader value); | |
937 template <> typename Text::Builder PointerBuilder::getBlob<Text>(const void* defaultValue, ByteCount defaultSize); | |
938 template <> typename Text::Reader PointerReader::getBlob<Text>(const void* defaultValue, ByteCount defaultSize) const; | |
939 | |
940 template <> typename Data::Builder PointerBuilder::initBlob<Data>(ByteCount size); | |
941 template <> void PointerBuilder::setBlob<Data>(typename Data::Reader value); | |
942 template <> typename Data::Builder PointerBuilder::getBlob<Data>(const void* defaultValue, ByteCount defaultSize); | |
943 template <> typename Data::Reader PointerReader::getBlob<Data>(const void* defaultValue, ByteCount defaultSize) const; | |
944 | |
945 inline PointerBuilder PointerBuilder::getRoot( | |
946 SegmentBuilder* segment, CapTableBuilder* capTable, word* location) { | |
947 return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(location)); | |
948 } | |
949 | |
950 inline PointerReader PointerReader::getRootUnchecked(const word* location) { | |
951 return PointerReader(nullptr, nullptr, | |
952 reinterpret_cast<const WirePointer*>(location), 0x7fffffff); | |
953 } | |
954 | |
955 // ------------------------------------------------------------------- | |
956 | |
957 inline kj::ArrayPtr<byte> StructBuilder::getDataSectionAsBlob() { | |
958 return kj::ArrayPtr<byte>(reinterpret_cast<byte*>(data), dataSize / BITS_PER_BYTE / BYTES); | |
959 } | |
960 | |
961 inline _::ListBuilder StructBuilder::getPointerSectionAsList() { | |
962 return _::ListBuilder(segment, capTable, pointers, 1 * POINTERS * BITS_PER_POINTER / ELEMENTS, | |
963 pointerCount * (1 * ELEMENTS / POINTERS), | |
964 0 * BITS, 1 * POINTERS, ElementSize::POINTER); | |
965 } | |
966 | |
967 template <typename T> | |
968 inline bool StructBuilder::hasDataField(ElementCount offset) { | |
969 return getDataField<Mask<T>>(offset) != 0; | |
970 } | |
971 | |
972 template <> | |
973 inline bool StructBuilder::hasDataField<Void>(ElementCount offset) { | |
974 return false; | |
975 } | |
976 | |
977 template <typename T> | |
978 inline T StructBuilder::getDataField(ElementCount offset) { | |
979 return reinterpret_cast<WireValue<T>*>(data)[offset / ELEMENTS].get(); | |
980 } | |
981 | |
982 template <> | |
983 inline bool StructBuilder::getDataField<bool>(ElementCount offset) { | |
984 BitCount boffset = offset * (1 * BITS / ELEMENTS); | |
985 byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE; | |
986 return (*reinterpret_cast<uint8_t*>(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; | |
987 } | |
988 | |
989 template <> | |
990 inline Void StructBuilder::getDataField<Void>(ElementCount offset) { | |
991 return VOID; | |
992 } | |
993 | |
994 template <typename T> | |
995 inline T StructBuilder::getDataField(ElementCount offset, Mask<T> mask) { | |
996 return unmask<T>(getDataField<Mask<T> >(offset), mask); | |
997 } | |
998 | |
999 template <typename T> | |
1000 inline void StructBuilder::setDataField(ElementCount offset, kj::NoInfer<T> value) { | |
1001 reinterpret_cast<WireValue<T>*>(data)[offset / ELEMENTS].set(value); | |
1002 } | |
1003 | |
1004 #if CAPNP_CANONICALIZE_NAN | |
1005 // Use mask() on floats and doubles to make sure we canonicalize NaNs. | |
1006 template <> | |
1007 inline void StructBuilder::setDataField<float>(ElementCount offset, float value) { | |
1008 setDataField<uint32_t>(offset, mask<float>(value, 0)); | |
1009 } | |
1010 template <> | |
1011 inline void StructBuilder::setDataField<double>(ElementCount offset, double value) { | |
1012 setDataField<uint64_t>(offset, mask<double>(value, 0)); | |
1013 } | |
1014 #endif | |
1015 | |
1016 template <> | |
1017 inline void StructBuilder::setDataField<bool>(ElementCount offset, bool value) { | |
1018 BitCount boffset = offset * (1 * BITS / ELEMENTS); | |
1019 byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE; | |
1020 uint bitnum = boffset % BITS_PER_BYTE / BITS; | |
1021 *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum)) | |
1022 | (static_cast<uint8_t>(value) << bitnum); | |
1023 } | |
1024 | |
1025 template <> | |
1026 inline void StructBuilder::setDataField<Void>(ElementCount offset, Void value) {} | |
1027 | |
1028 template <typename T> | |
1029 inline void StructBuilder::setDataField(ElementCount offset, kj::NoInfer<T> value, Mask<T> m) { | |
1030 setDataField<Mask<T> >(offset, mask<T>(value, m)); | |
1031 } | |
1032 | |
1033 inline PointerBuilder StructBuilder::getPointerField(WirePointerCount ptrIndex) { | |
1034 // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). | |
1035 return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>( | |
1036 reinterpret_cast<word*>(pointers) + ptrIndex * WORDS_PER_POINTER)); | |
1037 } | |
1038 | |
1039 // ------------------------------------------------------------------- | |
1040 | |
1041 inline kj::ArrayPtr<const byte> StructReader::getDataSectionAsBlob() { | |
1042 return kj::ArrayPtr<const byte>(reinterpret_cast<const byte*>(data), dataSize / BITS_PER_BYTE / BYTES); | |
1043 } | |
1044 | |
1045 inline _::ListReader StructReader::getPointerSectionAsList() { | |
1046 return _::ListReader(segment, capTable, pointers, pointerCount * (1 * ELEMENTS / POINTERS), | |
1047 1 * POINTERS * BITS_PER_POINTER / ELEMENTS, 0 * BITS, 1 * POINTERS, | |
1048 ElementSize::POINTER, nestingLimit); | |
1049 } | |
1050 | |
1051 template <typename T> | |
1052 inline bool StructReader::hasDataField(ElementCount offset) const { | |
1053 return getDataField<Mask<T>>(offset) != 0; | |
1054 } | |
1055 | |
1056 template <> | |
1057 inline bool StructReader::hasDataField<Void>(ElementCount offset) const { | |
1058 return false; | |
1059 } | |
1060 | |
1061 template <typename T> | |
1062 inline T StructReader::getDataField(ElementCount offset) const { | |
1063 if ((offset + 1 * ELEMENTS) * capnp::bitsPerElement<T>() <= dataSize) { | |
1064 return reinterpret_cast<const WireValue<T>*>(data)[offset / ELEMENTS].get(); | |
1065 } else { | |
1066 return static_cast<T>(0); | |
1067 } | |
1068 } | |
1069 | |
1070 template <> | |
1071 inline bool StructReader::getDataField<bool>(ElementCount offset) const { | |
1072 BitCount boffset = offset * (1 * BITS / ELEMENTS); | |
1073 if (boffset < dataSize) { | |
1074 const byte* b = reinterpret_cast<const byte*>(data) + boffset / BITS_PER_BYTE; | |
1075 return (*reinterpret_cast<const uint8_t*>(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; | |
1076 } else { | |
1077 return false; | |
1078 } | |
1079 } | |
1080 | |
1081 template <> | |
1082 inline Void StructReader::getDataField<Void>(ElementCount offset) const { | |
1083 return VOID; | |
1084 } | |
1085 | |
1086 template <typename T> | |
1087 T StructReader::getDataField(ElementCount offset, Mask<T> mask) const { | |
1088 return unmask<T>(getDataField<Mask<T> >(offset), mask); | |
1089 } | |
1090 | |
1091 inline PointerReader StructReader::getPointerField(WirePointerCount ptrIndex) const { | |
1092 if (ptrIndex < pointerCount) { | |
1093 // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). | |
1094 return PointerReader(segment, capTable, reinterpret_cast<const WirePointer*>( | |
1095 reinterpret_cast<const word*>(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit); | |
1096 } else{ | |
1097 return PointerReader(); | |
1098 } | |
1099 } | |
1100 | |
1101 // ------------------------------------------------------------------- | |
1102 | |
1103 inline ElementCount ListBuilder::size() const { return elementCount; } | |
1104 | |
1105 template <typename T> | |
1106 inline T ListBuilder::getDataElement(ElementCount index) { | |
1107 return reinterpret_cast<WireValue<T>*>(ptr + index * step / BITS_PER_BYTE)->get(); | |
1108 | |
1109 // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of | |
1110 // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and | |
1111 // the various non-inline methods that look up pointers. | |
1112 // Also if using this, consider changing ptr back to void* instead of byte*. | |
1113 // return reinterpret_cast<WireValue<T>*>(ptr)[ | |
1114 // index / ELEMENTS * (step / capnp::bitsPerElement<T>())].get(); | |
1115 } | |
1116 | |
1117 template <> | |
1118 inline bool ListBuilder::getDataElement<bool>(ElementCount index) { | |
1119 // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. | |
1120 BitCount bindex = index * (1 * BITS / ELEMENTS); | |
1121 byte* b = ptr + bindex / BITS_PER_BYTE; | |
1122 return (*reinterpret_cast<uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; | |
1123 } | |
1124 | |
1125 template <> | |
1126 inline Void ListBuilder::getDataElement<Void>(ElementCount index) { | |
1127 return VOID; | |
1128 } | |
1129 | |
1130 template <typename T> | |
1131 inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer<T> value) { | |
1132 reinterpret_cast<WireValue<T>*>(ptr + index * step / BITS_PER_BYTE)->set(value); | |
1133 } | |
1134 | |
1135 #if CAPNP_CANONICALIZE_NAN | |
1136 // Use mask() on floats and doubles to make sure we canonicalize NaNs. | |
1137 template <> | |
1138 inline void ListBuilder::setDataElement<float>(ElementCount index, float value) { | |
1139 setDataElement<uint32_t>(index, mask<float>(value, 0)); | |
1140 } | |
1141 template <> | |
1142 inline void ListBuilder::setDataElement<double>(ElementCount index, double value) { | |
1143 setDataElement<uint64_t>(index, mask<double>(value, 0)); | |
1144 } | |
1145 #endif | |
1146 | |
1147 template <> | |
1148 inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) { | |
1149 // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists. | |
1150 BitCount bindex = index * (1 * BITS / ELEMENTS); | |
1151 byte* b = ptr + bindex / BITS_PER_BYTE; | |
1152 uint bitnum = bindex % BITS_PER_BYTE / BITS; | |
1153 *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum)) | |
1154 | (static_cast<uint8_t>(value) << bitnum); | |
1155 } | |
1156 | |
1157 template <> | |
1158 inline void ListBuilder::setDataElement<Void>(ElementCount index, Void value) {} | |
1159 | |
1160 inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) { | |
1161 return PointerBuilder(segment, capTable, | |
1162 reinterpret_cast<WirePointer*>(ptr + index * step / BITS_PER_BYTE)); | |
1163 } | |
1164 | |
1165 // ------------------------------------------------------------------- | |
1166 | |
1167 inline ElementCount ListReader::size() const { return elementCount; } | |
1168 | |
1169 template <typename T> | |
1170 inline T ListReader::getDataElement(ElementCount index) const { | |
1171 return reinterpret_cast<const WireValue<T>*>(ptr + index * step / BITS_PER_BYTE)->get(); | |
1172 } | |
1173 | |
1174 template <> | |
1175 inline bool ListReader::getDataElement<bool>(ElementCount index) const { | |
1176 // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. | |
1177 BitCount bindex = index * (1 * BITS / ELEMENTS); | |
1178 const byte* b = ptr + bindex / BITS_PER_BYTE; | |
1179 return (*reinterpret_cast<const uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; | |
1180 } | |
1181 | |
1182 template <> | |
1183 inline Void ListReader::getDataElement<Void>(ElementCount index) const { | |
1184 return VOID; | |
1185 } | |
1186 | |
1187 inline PointerReader ListReader::getPointerElement(ElementCount index) const { | |
1188 return PointerReader(segment, capTable, | |
1189 reinterpret_cast<const WirePointer*>(ptr + index * step / BITS_PER_BYTE), nestingLimit); | |
1190 } | |
1191 | |
1192 // ------------------------------------------------------------------- | |
1193 | |
1194 inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept | |
1195 : segment(other.segment), capTable(other.capTable), location(other.location) { | |
1196 memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. | |
1197 other.segment = nullptr; | |
1198 other.location = nullptr; | |
1199 } | |
1200 | |
1201 inline OrphanBuilder::~OrphanBuilder() noexcept(false) { | |
1202 if (segment != nullptr) euthanize(); | |
1203 } | |
1204 | |
1205 inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) { | |
1206 // With normal smart pointers, it's important to handle the case where the incoming pointer | |
1207 // is actually transitively owned by this one. In this case, euthanize() would destroy `other` | |
1208 // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only | |
1209 // owns message objects, and `other` is not itself a message object, therefore cannot possibly | |
1210 // be transitively owned by `this`. | |
1211 | |
1212 if (segment != nullptr) euthanize(); | |
1213 segment = other.segment; | |
1214 capTable = other.capTable; | |
1215 location = other.location; | |
1216 memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. | |
1217 other.segment = nullptr; | |
1218 other.location = nullptr; | |
1219 return *this; | |
1220 } | |
1221 | |
1222 } // namespace _ (private) | |
1223 } // namespace capnp | |
1224 | |
1225 #endif // CAPNP_LAYOUT_H_ |