annotate win32-mingw/include/capnp/layout.h @ 79:91c729825bca pa_catalina

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