annotate osx/include/capnp/layout.h @ 62:0994c39f1e94

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