annotate win64-msvc/include/capnp/layout.h @ 63:0f2d93caa50c

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