annotate osx/include/capnp/layout.h @ 83:ae30d91d2ffe

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