annotate win64-msvc/include/capnp/layout.h @ 148:b4bfdf10c4b3

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