annotate win64-msvc/include/capnp/layout.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 0f2d93caa50c
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_