Mercurial > hg > sv-dependency-builds
diff osx/include/capnp/layout.h @ 147:45360b968bf4
Cap'n Proto v0.6 + build for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 22 May 2017 10:01:37 +0100 |
parents | 41e769c91eca |
children |
line wrap: on
line diff
--- a/osx/include/capnp/layout.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/layout.h Mon May 22 10:01:37 2017 +0100 @@ -1,1225 +1,1274 @@ -// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file is NOT intended for use by clients, except in generated code. -// -// This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout -// (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes, -// as does other parts of the Cap'n proto library which provide a higher-level interface for -// dynamic introspection. - -#ifndef CAPNP_LAYOUT_H_ -#define CAPNP_LAYOUT_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include <kj/common.h> -#include <kj/memory.h> -#include "common.h" -#include "blob.h" -#include "endian.h" - -#if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN) -#define CAPNP_CANONICALIZE_NAN 1 -// Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by -// __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN -// signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in -// particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world. -// Canonicalizing them makes output consistent (which is important!), but hurts performance -// slightly. -// -// Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work. -// Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs. -// everyone else. It would be great if we could just flip that bit, but we can't, because if the -// significand is all-zero, then the value is infinity rather than NaN. This means that on most -// machines, where the bit indicates quietness, there is one more quiet NaN value than signalling -// NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic -// mapping that properly preserves quietness. Instead of doing something hacky, we just give up -// and blow away NaN payloads, because no one uses them anyway. -#endif - -namespace capnp { - -#if !CAPNP_LITE -class ClientHook; -#endif // !CAPNP_LITE - -namespace _ { // private - -class PointerBuilder; -class PointerReader; -class StructBuilder; -class StructReader; -class ListBuilder; -class ListReader; -class OrphanBuilder; -struct WirePointer; -struct WireHelpers; -class SegmentReader; -class SegmentBuilder; -class Arena; -class BuilderArena; - -// ============================================================================= - -typedef decltype(BITS / ELEMENTS) BitsPerElement; -typedef decltype(POINTERS / ELEMENTS) PointersPerElement; - -static constexpr BitsPerElement BITS_PER_ELEMENT_TABLE[8] = { - 0 * BITS / ELEMENTS, - 1 * BITS / ELEMENTS, - 8 * BITS / ELEMENTS, - 16 * BITS / ELEMENTS, - 32 * BITS / ELEMENTS, - 64 * BITS / ELEMENTS, - 0 * BITS / ELEMENTS, - 0 * BITS / ELEMENTS -}; - -inline KJ_CONSTEXPR() BitsPerElement dataBitsPerElement(ElementSize size) { - return _::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)]; -} - -inline constexpr PointersPerElement pointersPerElement(ElementSize size) { - return size == ElementSize::POINTER ? 1 * POINTERS / ELEMENTS : 0 * POINTERS / ELEMENTS; -} - -template <size_t size> struct ElementSizeForByteSize; -template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; }; -template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; }; -template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; }; -template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; }; - -template <typename T> struct ElementSizeForType { - static constexpr ElementSize value = - // Primitive types that aren't special-cased below can be determined from sizeof(). - CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize<sizeof(T)>::value : - CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES : - CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE : - - // Everything else is a pointer. - ElementSize::POINTER; -}; - -// Void and bool are special. -template <> struct ElementSizeForType<Void> { static constexpr ElementSize value = ElementSize::VOID; }; -template <> struct ElementSizeForType<bool> { static constexpr ElementSize value = ElementSize::BIT; }; - -// Lists and blobs are pointers, not structs. -template <typename T, bool b> struct ElementSizeForType<List<T, b>> { - static constexpr ElementSize value = ElementSize::POINTER; -}; -template <> struct ElementSizeForType<Text> { - static constexpr ElementSize value = ElementSize::POINTER; -}; -template <> struct ElementSizeForType<Data> { - static constexpr ElementSize value = ElementSize::POINTER; -}; - -template <typename T> -inline constexpr ElementSize elementSizeForType() { - return ElementSizeForType<T>::value; -} - -struct MessageSizeCounts { - WordCount64 wordCount; - uint capCount; - - MessageSizeCounts& operator+=(const MessageSizeCounts& other) { - wordCount += other.wordCount; - capCount += other.capCount; - return *this; - } - - MessageSize asPublic() { - return MessageSize { wordCount / WORDS, capCount }; - } -}; - -// ============================================================================= - -template <int wordCount> -union AlignedData { - // Useful for declaring static constant data blobs as an array of bytes, but forcing those - // bytes to be word-aligned. - - uint8_t bytes[wordCount * sizeof(word)]; - word words[wordCount]; -}; - -struct StructSize { - WordCount16 data; - WirePointerCount16 pointers; - - inline constexpr WordCount total() const { return data + pointers * WORDS_PER_POINTER; } - - StructSize() = default; - inline constexpr StructSize(WordCount data, WirePointerCount pointers) - : data(data), pointers(pointers) {} -}; - -template <typename T, typename CapnpPrivate = typename T::_capnpPrivate> -inline constexpr StructSize structSize() { - return StructSize(CapnpPrivate::dataWordSize * WORDS, CapnpPrivate::pointerCount * POINTERS); -} - -template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, - typename = kj::EnableIf<CAPNP_KIND(T) == Kind::STRUCT>> -inline constexpr StructSize minStructSizeForElement() { - // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough - // to hold a T. - - return StructSize(CapnpPrivate::dataWordSize * WORDS, CapnpPrivate::pointerCount * POINTERS); -} - -template <typename T, typename = kj::EnableIf<CAPNP_KIND(T) != Kind::STRUCT>> -inline constexpr StructSize minStructSizeForElement() { - // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough - // to hold a T. - - return StructSize( - dataBitsPerElement(elementSizeForType<T>()) * ELEMENTS > 0 * BITS ? 1 * WORDS : 0 * WORDS, - pointersPerElement(elementSizeForType<T>()) * ELEMENTS); -} - -// ------------------------------------------------------------------- -// Masking of default values - -template <typename T, Kind kind = CAPNP_KIND(T)> struct Mask_; -template <typename T> struct Mask_<T, Kind::PRIMITIVE> { typedef T Type; }; -template <typename T> struct Mask_<T, Kind::ENUM> { typedef uint16_t Type; }; -template <> struct Mask_<float, Kind::PRIMITIVE> { typedef uint32_t Type; }; -template <> struct Mask_<double, Kind::PRIMITIVE> { typedef uint64_t Type; }; - -template <typename T> struct Mask_<T, Kind::OTHER> { - // Union discriminants end up here. - static_assert(sizeof(T) == 2, "Don't know how to mask this type."); - typedef uint16_t Type; -}; - -template <typename T> -using Mask = typename Mask_<T>::Type; - -template <typename T> -KJ_ALWAYS_INLINE(Mask<T> mask(T value, Mask<T> mask)); -template <typename T> -KJ_ALWAYS_INLINE(T unmask(Mask<T> value, Mask<T> mask)); - -template <typename T> -inline Mask<T> mask(T value, Mask<T> mask) { - return static_cast<Mask<T> >(value) ^ mask; -} - -template <> -inline uint32_t mask<float>(float value, uint32_t mask) { -#if CAPNP_CANONICALIZE_NAN - if (value != value) { - return 0x7fc00000u ^ mask; - } -#endif - - uint32_t i; - static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?"); - memcpy(&i, &value, sizeof(value)); - return i ^ mask; -} - -template <> -inline uint64_t mask<double>(double value, uint64_t mask) { -#if CAPNP_CANONICALIZE_NAN - if (value != value) { - return 0x7ff8000000000000ull ^ mask; - } -#endif - - uint64_t i; - static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?"); - memcpy(&i, &value, sizeof(value)); - return i ^ mask; -} - -template <typename T> -inline T unmask(Mask<T> value, Mask<T> mask) { - return static_cast<T>(value ^ mask); -} - -template <> -inline float unmask<float>(uint32_t value, uint32_t mask) { - value ^= mask; - float result; - static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?"); - memcpy(&result, &value, sizeof(value)); - return result; -} - -template <> -inline double unmask<double>(uint64_t value, uint64_t mask) { - value ^= mask; - double result; - static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?"); - memcpy(&result, &value, sizeof(value)); - return result; -} - -// ------------------------------------------------------------------- - -class CapTableReader { -public: -#if !CAPNP_LITE - virtual kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) = 0; - // Extract the capability at the given index. If the index is invalid, returns null. -#endif // !CAPNP_LITE -}; - -class CapTableBuilder: public CapTableReader { -public: -#if !CAPNP_LITE - virtual uint injectCap(kj::Own<ClientHook>&& cap) = 0; - // Add the capability to the message and return its index. If the same ClientHook is injected - // twice, this may return the same index both times, but in this case dropCap() needs to be - // called an equal number of times to actually remove the cap. - - virtual void dropCap(uint index) = 0; - // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out. -#endif // !CAPNP_LITE -}; - -// ------------------------------------------------------------------- - -class PointerBuilder: public kj::DisallowConstCopy { - // Represents a single pointer, usually embedded in a struct or a list. - -public: - inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {} - - static inline PointerBuilder getRoot( - SegmentBuilder* segment, CapTableBuilder* capTable, word* location); - // Get a PointerBuilder representing a message root located in the given segment at the given - // location. - - inline bool isNull() { return getPointerType() == PointerType::NULL_; } - PointerType getPointerType(); - - StructBuilder getStruct(StructSize size, const word* defaultValue); - ListBuilder getList(ElementSize elementSize, const word* defaultValue); - ListBuilder getStructList(StructSize elementSize, const word* defaultValue); - ListBuilder getListAnySize(const word* defaultValue); - template <typename T> typename T::Builder getBlob(const void* defaultValue,ByteCount defaultSize); -#if !CAPNP_LITE - kj::Own<ClientHook> getCapability(); -#endif // !CAPNP_LITE - // Get methods: Get the value. If it is null, initialize it to a copy of the default value. - // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a - // simple byte array for blobs. - - StructBuilder initStruct(StructSize size); - ListBuilder initList(ElementSize elementSize, ElementCount elementCount); - ListBuilder initStructList(ElementCount elementCount, StructSize size); - template <typename T> typename T::Builder initBlob(ByteCount size); - // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing - // object. - - void setStruct(const StructReader& value, bool canonical = false); - void setList(const ListReader& value, bool canonical = false); - template <typename T> void setBlob(typename T::Reader value); -#if !CAPNP_LITE - void setCapability(kj::Own<ClientHook>&& cap); -#endif // !CAPNP_LITE - // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding - // the existing object. - - void adopt(OrphanBuilder&& orphan); - // Set the pointer to point at the given orphaned value. - - OrphanBuilder disown(); - // Set the pointer to null and return its previous value as an orphan. - - void clear(); - // Clear the pointer to null, discarding its previous value. - - void transferFrom(PointerBuilder other); - // Equivalent to `adopt(other.disown())`. - - void copyFrom(PointerReader other, bool canonical = false); - // Equivalent to `set(other.get())`. - // If you set the canonical flag, it will attempt to lay the target out - // canonically, provided enough space is available. - - PointerReader asReader() const; - - BuilderArena* getArena() const; - // Get the arena containing this pointer. - - CapTableBuilder* getCapTable(); - // Gets the capability context in which this object is operating. - - PointerBuilder imbue(CapTableBuilder* capTable); - // Return a copy of this builder except using the given capability context. - -private: - SegmentBuilder* segment; // Memory segment in which the pointer resides. - CapTableBuilder* capTable; // Table of capability indexes. - WirePointer* pointer; // Pointer to the pointer. - - inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer) - : segment(segment), capTable(capTable), pointer(pointer) {} - - friend class StructBuilder; - friend class ListBuilder; - friend class OrphanBuilder; -}; - -class PointerReader { -public: - inline PointerReader() - : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {} - - static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable, - const word* location, int nestingLimit); - // Get a PointerReader representing a message root located in the given segment at the given - // location. - - static inline PointerReader getRootUnchecked(const word* location); - // Get a PointerReader for an unchecked message. - - MessageSizeCounts targetSize() const; - // Return the total size of the target object and everything to which it points. Does not count - // far pointer overhead. This is useful for deciding how much space is needed to copy the object - // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, - // use the result as a hint for allocating the first segment, do the copy, and then throw an - // exception if it overruns. - - inline bool isNull() const { return getPointerType() == PointerType::NULL_; } - PointerType getPointerType() const; - - StructReader getStruct(const word* defaultValue) const; - ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const; - ListReader getListAnySize(const word* defaultValue) const; - template <typename T> - typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; -#if !CAPNP_LITE - kj::Own<ClientHook> getCapability() const; -#endif // !CAPNP_LITE - // Get methods: Get the value. If it is null, return the default value instead. - // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a - // simple byte array for blobs. - - const word* getUnchecked() const; - // If this is an unchecked message, get a word* pointing at the location of the pointer. This - // word* can actually be passed to readUnchecked() to read the designated sub-object later. If - // this isn't an unchecked message, throws an exception. - - kj::Maybe<Arena&> getArena() const; - // Get the arena containing this pointer. - - CapTableReader* getCapTable(); - // Gets the capability context in which this object is operating. - - PointerReader imbue(CapTableReader* capTable) const; - // Return a copy of this reader except using the given capability context. - - bool isCanonical(const word **readHead); - // Validate this pointer's canonicity, subject to the conditions: - // * All data to the left of readHead has been read thus far (for pointer - // ordering) - // * All pointers in preorder have already been checked - // * This pointer is in the first and only segment of the message - -private: - SegmentReader* segment; // Memory segment in which the pointer resides. - CapTableReader* capTable; // Table of capability indexes. - const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. - - int nestingLimit; - // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. - // Once this reaches zero, further pointers will be pruned. - - inline PointerReader(SegmentReader* segment, CapTableReader* capTable, - const WirePointer* pointer, int nestingLimit) - : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {} - - friend class StructReader; - friend class ListReader; - friend class PointerBuilder; - friend class OrphanBuilder; -}; - -// ------------------------------------------------------------------- - -class StructBuilder: public kj::DisallowConstCopy { -public: - inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {} - - inline word* getLocation() { return reinterpret_cast<word*>(data); } - // Get the object's location. Only valid for independently-allocated objects (i.e. not list - // elements). - - inline BitCount getDataSectionSize() const { return dataSize; } - inline WirePointerCount getPointerSectionSize() const { return pointerCount; } - inline kj::ArrayPtr<byte> getDataSectionAsBlob(); - inline _::ListBuilder getPointerSectionAsList(); - - template <typename T> - KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset)); - // Return true if the field is set to something other than its default value. - - template <typename T> - KJ_ALWAYS_INLINE(T getDataField(ElementCount offset)); - // Gets the data field value of the given type at the given offset. The offset is measured in - // multiples of the field size, determined by the type. - - template <typename T> - KJ_ALWAYS_INLINE(T getDataField(ElementCount offset, Mask<T> mask)); - // Like getDataField() but applies the given XOR mask to the data on load. Used for reading - // fields with non-zero default values. - - template <typename T> - KJ_ALWAYS_INLINE(void setDataField( - ElementCount offset, kj::NoInfer<T> value)); - // Sets the data field value at the given offset. - - template <typename T> - KJ_ALWAYS_INLINE(void setDataField( - ElementCount offset, kj::NoInfer<T> value, Mask<T> mask)); - // Like setDataField() but applies the given XOR mask before storing. Used for writing fields - // with non-zero default values. - - KJ_ALWAYS_INLINE(PointerBuilder getPointerField(WirePointerCount ptrIndex)); - // Get a builder for a pointer field given the index within the pointer section. - - void clearAll(); - // Clear all pointers and data. - - void transferContentFrom(StructBuilder other); - // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger - // than this, the extra data is not transferred, meaning there is a risk of data loss when - // transferring from messages built with future versions of the protocol. - - void copyContentFrom(StructReader other); - // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not - // copied, meaning there is a risk of data loss when copying from messages built with future - // versions of the protocol. - - StructReader asReader() const; - // Gets a StructReader pointing at the same memory. - - BuilderArena* getArena(); - // Gets the arena in which this object is allocated. - - CapTableBuilder* getCapTable(); - // Gets the capability context in which this object is operating. - - StructBuilder imbue(CapTableBuilder* capTable); - // Return a copy of this builder except using the given capability context. - -private: - SegmentBuilder* segment; // Memory segment in which the struct resides. - CapTableBuilder* capTable; // Table of capability indexes. - void* data; // Pointer to the encoded data. - WirePointer* pointers; // Pointer to the encoded pointers. - - BitCount32 dataSize; - // Size of data section. We use a bit count rather than a word count to more easily handle the - // case of struct lists encoded with less than a word per element. - - WirePointerCount16 pointerCount; // Size of the pointer section. - - inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, - void* data, WirePointer* pointers, - BitCount dataSize, WirePointerCount pointerCount) - : segment(segment), capTable(capTable), data(data), pointers(pointers), - dataSize(dataSize), pointerCount(pointerCount) {} - - friend class ListBuilder; - friend struct WireHelpers; - friend class OrphanBuilder; -}; - -class StructReader { -public: - inline StructReader() - : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr), dataSize(0), - pointerCount(0), nestingLimit(0x7fffffff) {} - inline StructReader(kj::ArrayPtr<const word> data) - : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr), - dataSize(data.size() * WORDS * BITS_PER_WORD), pointerCount(0), nestingLimit(0x7fffffff) {} - - const void* getLocation() const { return data; } - - inline BitCount getDataSectionSize() const { return dataSize; } - inline WirePointerCount getPointerSectionSize() const { return pointerCount; } - inline kj::ArrayPtr<const byte> getDataSectionAsBlob(); - inline _::ListReader getPointerSectionAsList(); - - kj::Array<word> canonicalize(); - - template <typename T> - KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const); - // Return true if the field is set to something other than its default value. - - template <typename T> - KJ_ALWAYS_INLINE(T getDataField(ElementCount offset) const); - // Get the data field value of the given type at the given offset. The offset is measured in - // multiples of the field size, determined by the type. Returns zero if the offset is past the - // end of the struct's data section. - - template <typename T> - KJ_ALWAYS_INLINE( - T getDataField(ElementCount offset, Mask<T> mask) const); - // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading - // fields with non-zero default values. - - KJ_ALWAYS_INLINE(PointerReader getPointerField(WirePointerCount ptrIndex) const); - // Get a reader for a pointer field given the index within the pointer section. If the index - // is out-of-bounds, returns a null pointer. - - MessageSizeCounts totalSize() const; - // Return the total size of the struct and everything to which it points. Does not count far - // pointer overhead. This is useful for deciding how much space is needed to copy the struct - // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, - // use the result as a hint for allocating the first segment, do the copy, and then throw an - // exception if it overruns. - - CapTableReader* getCapTable(); - // Gets the capability context in which this object is operating. - - StructReader imbue(CapTableReader* capTable) const; - // Return a copy of this reader except using the given capability context. - - bool isCanonical(const word **readHead, const word **ptrHead, - bool *dataTrunc, bool *ptrTrunc); - // Validate this pointer's canonicity, subject to the conditions: - // * All data to the left of readHead has been read thus far (for pointer - // ordering) - // * All pointers in preorder have already been checked - // * This pointer is in the first and only segment of the message - // - // If this function returns false, the struct is non-canonical. If it - // returns true, then: - // * If it is a composite in a list, it is canonical if at least one struct - // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1 - // * If it is derived from a struct pointer, it is canonical if - // dataTrunc = 1 AND ptrTrunc = 1 - -private: - SegmentReader* segment; // Memory segment in which the struct resides. - CapTableReader* capTable; // Table of capability indexes. - - const void* data; - const WirePointer* pointers; - - BitCount32 dataSize; - // Size of data section. We use a bit count rather than a word count to more easily handle the - // case of struct lists encoded with less than a word per element. - - WirePointerCount16 pointerCount; // Size of the pointer section. - - int nestingLimit; - // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. - // Once this reaches zero, further pointers will be pruned. - // TODO(perf): Limit to 16 bits for better packing? - - inline StructReader(SegmentReader* segment, CapTableReader* capTable, - const void* data, const WirePointer* pointers, - BitCount dataSize, WirePointerCount pointerCount, int nestingLimit) - : segment(segment), capTable(capTable), data(data), pointers(pointers), - dataSize(dataSize), pointerCount(pointerCount), - nestingLimit(nestingLimit) {} - - friend class ListReader; - friend class StructBuilder; - friend struct WireHelpers; -}; - -// ------------------------------------------------------------------- - -class ListBuilder: public kj::DisallowConstCopy { -public: - inline explicit ListBuilder(ElementSize elementSize) - : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS), - step(0 * BITS / ELEMENTS), structDataSize(0 * BITS), structPointerCount(0 * POINTERS), - elementSize(elementSize) {} - - inline word* getLocation() { - // Get the object's location. - - if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) { - return reinterpret_cast<word*>(ptr) - POINTER_SIZE_IN_WORDS; - } else { - return reinterpret_cast<word*>(ptr); - } - } - - inline ElementSize getElementSize() const { return elementSize; } - - inline ElementCount size() const; - // The number of elements in the list. - - Text::Builder asText(); - Data::Builder asData(); - // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. - - template <typename T> - KJ_ALWAYS_INLINE(T getDataElement(ElementCount index)); - // Get the element of the given type at the given index. - - template <typename T> - KJ_ALWAYS_INLINE(void setDataElement( - ElementCount index, kj::NoInfer<T> value)); - // Set the element at the given index. - - KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index)); - - StructBuilder getStructElement(ElementCount index); - - ListReader asReader() const; - // Get a ListReader pointing at the same memory. - - BuilderArena* getArena(); - // Gets the arena in which this object is allocated. - - CapTableBuilder* getCapTable(); - // Gets the capability context in which this object is operating. - - ListBuilder imbue(CapTableBuilder* capTable); - // Return a copy of this builder except using the given capability context. - -private: - SegmentBuilder* segment; // Memory segment in which the list resides. - CapTableBuilder* capTable; // Table of capability indexes. - - byte* ptr; // Pointer to list content. - - ElementCount elementCount; // Number of elements in the list. - - decltype(BITS / ELEMENTS) step; - // The distance between elements. - - BitCount32 structDataSize; - WirePointerCount16 structPointerCount; - // The struct properties to use when interpreting the elements as structs. All lists can be - // interpreted as struct lists, so these are always filled in. - - ElementSize elementSize; - // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE - // from other types when the overall size is exactly zero or one words. - - inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr, - decltype(BITS / ELEMENTS) step, ElementCount size, - BitCount structDataSize, WirePointerCount structPointerCount, - ElementSize elementSize) - : segment(segment), capTable(capTable), ptr(reinterpret_cast<byte*>(ptr)), - elementCount(size), step(step), structDataSize(structDataSize), - structPointerCount(structPointerCount), elementSize(elementSize) {} - - friend class StructBuilder; - friend struct WireHelpers; - friend class OrphanBuilder; -}; - -class ListReader { -public: - inline explicit ListReader(ElementSize elementSize) - : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0), - step(0 * BITS / ELEMENTS), structDataSize(0), structPointerCount(0), - elementSize(elementSize), nestingLimit(0x7fffffff) {} - - inline ElementCount size() const; - // The number of elements in the list. - - inline ElementSize getElementSize() const { return elementSize; } - - Text::Reader asText(); - Data::Reader asData(); - // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. - - kj::ArrayPtr<const byte> asRawBytes(); - - template <typename T> - KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const); - // Get the element of the given type at the given index. - - KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const); - - StructReader getStructElement(ElementCount index) const; - - CapTableReader* getCapTable(); - // Gets the capability context in which this object is operating. - - ListReader imbue(CapTableReader* capTable) const; - // Return a copy of this reader except using the given capability context. - - bool isCanonical(const word **readHead); - // Validate this pointer's canonicity, subject to the conditions: - // * All data to the left of readHead has been read thus far (for pointer - // ordering) - // * All pointers in preorder have already been checked - // * This pointer is in the first and only segment of the message - -private: - SegmentReader* segment; // Memory segment in which the list resides. - CapTableReader* capTable; // Table of capability indexes. - - const byte* ptr; // Pointer to list content. - - ElementCount elementCount; // Number of elements in the list. - - decltype(BITS / ELEMENTS) step; - // The distance between elements. - - BitCount32 structDataSize; - WirePointerCount16 structPointerCount; - // The struct properties to use when interpreting the elements as structs. All lists can be - // interpreted as struct lists, so these are always filled in. - - ElementSize elementSize; - // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE - // from other types when the overall size is exactly zero or one words. - - int nestingLimit; - // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. - // Once this reaches zero, further pointers will be pruned. - - inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr, - ElementCount elementCount, decltype(BITS / ELEMENTS) step, - BitCount structDataSize, WirePointerCount structPointerCount, - ElementSize elementSize, int nestingLimit) - : segment(segment), capTable(capTable), ptr(reinterpret_cast<const byte*>(ptr)), - elementCount(elementCount), step(step), structDataSize(structDataSize), - structPointerCount(structPointerCount), elementSize(elementSize), - nestingLimit(nestingLimit) {} - - friend class StructReader; - friend class ListBuilder; - friend struct WireHelpers; - friend class OrphanBuilder; -}; - -// ------------------------------------------------------------------- - -class OrphanBuilder { -public: - inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) { - memset(&tag, 0, sizeof(tag)); - } - OrphanBuilder(const OrphanBuilder& other) = delete; - inline OrphanBuilder(OrphanBuilder&& other) noexcept; - inline ~OrphanBuilder() noexcept(false); - - static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size); - static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable, - ElementCount elementCount, ElementSize elementSize); - static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable, - ElementCount elementCount, StructSize elementSize); - static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); - static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); - - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom); -#if !CAPNP_LITE - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, - kj::Own<ClientHook> copyFrom); -#endif // !CAPNP_LITE - - static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable, - ElementSize expectedElementSize, StructSize expectedStructSize, - kj::ArrayPtr<const ListReader> lists); - - static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data); - - OrphanBuilder& operator=(const OrphanBuilder& other) = delete; - inline OrphanBuilder& operator=(OrphanBuilder&& other); - - inline bool operator==(decltype(nullptr)) const { return location == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return location != nullptr; } - - StructBuilder asStruct(StructSize size); - // Interpret as a struct, or throw an exception if not a struct. - - ListBuilder asList(ElementSize elementSize); - // Interpret as a list, or throw an exception if not a list. elementSize cannot be - // INLINE_COMPOSITE -- use asStructList() instead. - - ListBuilder asStructList(StructSize elementSize); - // Interpret as a struct list, or throw an exception if not a list. - - Text::Builder asText(); - Data::Builder asData(); - // Interpret as a blob, or throw an exception if not a blob. - - StructReader asStructReader(StructSize size) const; - ListReader asListReader(ElementSize elementSize) const; -#if !CAPNP_LITE - kj::Own<ClientHook> asCapability() const; -#endif // !CAPNP_LITE - Text::Reader asTextReader() const; - Data::Reader asDataReader() const; - - bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT; - // Resize the orphan list to the given size. Returns false if the list is currently empty but - // the requested size is non-zero, in which case the caller will need to allocate a new list. - - void truncate(ElementCount size, ElementSize elementSize); - void truncate(ElementCount size, StructSize elementSize); - void truncateText(ElementCount size); - // Versions of truncate() that know how to allocate a new list if needed. - -private: - static_assert(1 * POINTERS * WORDS_PER_POINTER == 1 * WORDS, - "This struct assumes a pointer is one word."); - word tag; - // Contains an encoded WirePointer representing this object. WirePointer is defined in - // layout.c++, but fits in a word. - // - // This may be a FAR pointer. Even in that case, `location` points to the eventual destination - // of that far pointer. The reason we keep the far pointer around rather than just making `tag` - // represent the final destination is because if the eventual adopter of the pointer is not in - // the target's segment then it may be useful to reuse the far pointer landing pad. - // - // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual - // target. - - SegmentBuilder* segment; - // Segment in which the object resides. - - CapTableBuilder* capTable; - // Table of capability indexes. - - word* location; - // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this - // 0x1 just so that it is non-null for operator==, but it is never used. - - inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, - CapTableBuilder* capTable, word* location) - : segment(segment), capTable(capTable), location(location) { - memcpy(&tag, tagPtr, sizeof(tag)); - } - - inline WirePointer* tagAsPtr() { return reinterpret_cast<WirePointer*>(&tag); } - inline const WirePointer* tagAsPtr() const { return reinterpret_cast<const WirePointer*>(&tag); } - - void euthanize(); - // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when - // the OrphanBuilder is being destroyed or overwritten and it is non-null. - - friend struct WireHelpers; -}; - -// ======================================================================================= -// Internal implementation details... - -// These are defined in the source file. -template <> typename Text::Builder PointerBuilder::initBlob<Text>(ByteCount size); -template <> void PointerBuilder::setBlob<Text>(typename Text::Reader value); -template <> typename Text::Builder PointerBuilder::getBlob<Text>(const void* defaultValue, ByteCount defaultSize); -template <> typename Text::Reader PointerReader::getBlob<Text>(const void* defaultValue, ByteCount defaultSize) const; - -template <> typename Data::Builder PointerBuilder::initBlob<Data>(ByteCount size); -template <> void PointerBuilder::setBlob<Data>(typename Data::Reader value); -template <> typename Data::Builder PointerBuilder::getBlob<Data>(const void* defaultValue, ByteCount defaultSize); -template <> typename Data::Reader PointerReader::getBlob<Data>(const void* defaultValue, ByteCount defaultSize) const; - -inline PointerBuilder PointerBuilder::getRoot( - SegmentBuilder* segment, CapTableBuilder* capTable, word* location) { - return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(location)); -} - -inline PointerReader PointerReader::getRootUnchecked(const word* location) { - return PointerReader(nullptr, nullptr, - reinterpret_cast<const WirePointer*>(location), 0x7fffffff); -} - -// ------------------------------------------------------------------- - -inline kj::ArrayPtr<byte> StructBuilder::getDataSectionAsBlob() { - return kj::ArrayPtr<byte>(reinterpret_cast<byte*>(data), dataSize / BITS_PER_BYTE / BYTES); -} - -inline _::ListBuilder StructBuilder::getPointerSectionAsList() { - return _::ListBuilder(segment, capTable, pointers, 1 * POINTERS * BITS_PER_POINTER / ELEMENTS, - pointerCount * (1 * ELEMENTS / POINTERS), - 0 * BITS, 1 * POINTERS, ElementSize::POINTER); -} - -template <typename T> -inline bool StructBuilder::hasDataField(ElementCount offset) { - return getDataField<Mask<T>>(offset) != 0; -} - -template <> -inline bool StructBuilder::hasDataField<Void>(ElementCount offset) { - return false; -} - -template <typename T> -inline T StructBuilder::getDataField(ElementCount offset) { - return reinterpret_cast<WireValue<T>*>(data)[offset / ELEMENTS].get(); -} - -template <> -inline bool StructBuilder::getDataField<bool>(ElementCount offset) { - BitCount boffset = offset * (1 * BITS / ELEMENTS); - byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE; - return (*reinterpret_cast<uint8_t*>(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; -} - -template <> -inline Void StructBuilder::getDataField<Void>(ElementCount offset) { - return VOID; -} - -template <typename T> -inline T StructBuilder::getDataField(ElementCount offset, Mask<T> mask) { - return unmask<T>(getDataField<Mask<T> >(offset), mask); -} - -template <typename T> -inline void StructBuilder::setDataField(ElementCount offset, kj::NoInfer<T> value) { - reinterpret_cast<WireValue<T>*>(data)[offset / ELEMENTS].set(value); -} - -#if CAPNP_CANONICALIZE_NAN -// Use mask() on floats and doubles to make sure we canonicalize NaNs. -template <> -inline void StructBuilder::setDataField<float>(ElementCount offset, float value) { - setDataField<uint32_t>(offset, mask<float>(value, 0)); -} -template <> -inline void StructBuilder::setDataField<double>(ElementCount offset, double value) { - setDataField<uint64_t>(offset, mask<double>(value, 0)); -} -#endif - -template <> -inline void StructBuilder::setDataField<bool>(ElementCount offset, bool value) { - BitCount boffset = offset * (1 * BITS / ELEMENTS); - byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE; - uint bitnum = boffset % BITS_PER_BYTE / BITS; - *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum)) - | (static_cast<uint8_t>(value) << bitnum); -} - -template <> -inline void StructBuilder::setDataField<Void>(ElementCount offset, Void value) {} - -template <typename T> -inline void StructBuilder::setDataField(ElementCount offset, kj::NoInfer<T> value, Mask<T> m) { - setDataField<Mask<T> >(offset, mask<T>(value, m)); -} - -inline PointerBuilder StructBuilder::getPointerField(WirePointerCount ptrIndex) { - // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). - return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>( - reinterpret_cast<word*>(pointers) + ptrIndex * WORDS_PER_POINTER)); -} - -// ------------------------------------------------------------------- - -inline kj::ArrayPtr<const byte> StructReader::getDataSectionAsBlob() { - return kj::ArrayPtr<const byte>(reinterpret_cast<const byte*>(data), dataSize / BITS_PER_BYTE / BYTES); -} - -inline _::ListReader StructReader::getPointerSectionAsList() { - return _::ListReader(segment, capTable, pointers, pointerCount * (1 * ELEMENTS / POINTERS), - 1 * POINTERS * BITS_PER_POINTER / ELEMENTS, 0 * BITS, 1 * POINTERS, - ElementSize::POINTER, nestingLimit); -} - -template <typename T> -inline bool StructReader::hasDataField(ElementCount offset) const { - return getDataField<Mask<T>>(offset) != 0; -} - -template <> -inline bool StructReader::hasDataField<Void>(ElementCount offset) const { - return false; -} - -template <typename T> -inline T StructReader::getDataField(ElementCount offset) const { - if ((offset + 1 * ELEMENTS) * capnp::bitsPerElement<T>() <= dataSize) { - return reinterpret_cast<const WireValue<T>*>(data)[offset / ELEMENTS].get(); - } else { - return static_cast<T>(0); - } -} - -template <> -inline bool StructReader::getDataField<bool>(ElementCount offset) const { - BitCount boffset = offset * (1 * BITS / ELEMENTS); - if (boffset < dataSize) { - const byte* b = reinterpret_cast<const byte*>(data) + boffset / BITS_PER_BYTE; - return (*reinterpret_cast<const uint8_t*>(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; - } else { - return false; - } -} - -template <> -inline Void StructReader::getDataField<Void>(ElementCount offset) const { - return VOID; -} - -template <typename T> -T StructReader::getDataField(ElementCount offset, Mask<T> mask) const { - return unmask<T>(getDataField<Mask<T> >(offset), mask); -} - -inline PointerReader StructReader::getPointerField(WirePointerCount ptrIndex) const { - if (ptrIndex < pointerCount) { - // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). - return PointerReader(segment, capTable, reinterpret_cast<const WirePointer*>( - reinterpret_cast<const word*>(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit); - } else{ - return PointerReader(); - } -} - -// ------------------------------------------------------------------- - -inline ElementCount ListBuilder::size() const { return elementCount; } - -template <typename T> -inline T ListBuilder::getDataElement(ElementCount index) { - return reinterpret_cast<WireValue<T>*>(ptr + index * step / BITS_PER_BYTE)->get(); - - // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of - // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and - // the various non-inline methods that look up pointers. - // Also if using this, consider changing ptr back to void* instead of byte*. -// return reinterpret_cast<WireValue<T>*>(ptr)[ -// index / ELEMENTS * (step / capnp::bitsPerElement<T>())].get(); -} - -template <> -inline bool ListBuilder::getDataElement<bool>(ElementCount index) { - // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. - BitCount bindex = index * (1 * BITS / ELEMENTS); - byte* b = ptr + bindex / BITS_PER_BYTE; - return (*reinterpret_cast<uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; -} - -template <> -inline Void ListBuilder::getDataElement<Void>(ElementCount index) { - return VOID; -} - -template <typename T> -inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer<T> value) { - reinterpret_cast<WireValue<T>*>(ptr + index * step / BITS_PER_BYTE)->set(value); -} - -#if CAPNP_CANONICALIZE_NAN -// Use mask() on floats and doubles to make sure we canonicalize NaNs. -template <> -inline void ListBuilder::setDataElement<float>(ElementCount index, float value) { - setDataElement<uint32_t>(index, mask<float>(value, 0)); -} -template <> -inline void ListBuilder::setDataElement<double>(ElementCount index, double value) { - setDataElement<uint64_t>(index, mask<double>(value, 0)); -} -#endif - -template <> -inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) { - // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists. - BitCount bindex = index * (1 * BITS / ELEMENTS); - byte* b = ptr + bindex / BITS_PER_BYTE; - uint bitnum = bindex % BITS_PER_BYTE / BITS; - *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum)) - | (static_cast<uint8_t>(value) << bitnum); -} - -template <> -inline void ListBuilder::setDataElement<Void>(ElementCount index, Void value) {} - -inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) { - return PointerBuilder(segment, capTable, - reinterpret_cast<WirePointer*>(ptr + index * step / BITS_PER_BYTE)); -} - -// ------------------------------------------------------------------- - -inline ElementCount ListReader::size() const { return elementCount; } - -template <typename T> -inline T ListReader::getDataElement(ElementCount index) const { - return reinterpret_cast<const WireValue<T>*>(ptr + index * step / BITS_PER_BYTE)->get(); -} - -template <> -inline bool ListReader::getDataElement<bool>(ElementCount index) const { - // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. - BitCount bindex = index * (1 * BITS / ELEMENTS); - const byte* b = ptr + bindex / BITS_PER_BYTE; - return (*reinterpret_cast<const uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; -} - -template <> -inline Void ListReader::getDataElement<Void>(ElementCount index) const { - return VOID; -} - -inline PointerReader ListReader::getPointerElement(ElementCount index) const { - return PointerReader(segment, capTable, - reinterpret_cast<const WirePointer*>(ptr + index * step / BITS_PER_BYTE), nestingLimit); -} - -// ------------------------------------------------------------------- - -inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept - : segment(other.segment), capTable(other.capTable), location(other.location) { - memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. - other.segment = nullptr; - other.location = nullptr; -} - -inline OrphanBuilder::~OrphanBuilder() noexcept(false) { - if (segment != nullptr) euthanize(); -} - -inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) { - // With normal smart pointers, it's important to handle the case where the incoming pointer - // is actually transitively owned by this one. In this case, euthanize() would destroy `other` - // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only - // owns message objects, and `other` is not itself a message object, therefore cannot possibly - // be transitively owned by `this`. - - if (segment != nullptr) euthanize(); - segment = other.segment; - capTable = other.capTable; - location = other.location; - memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. - other.segment = nullptr; - other.location = nullptr; - return *this; -} - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_LAYOUT_H_ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file is NOT intended for use by clients, except in generated code. +// +// This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout +// (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes, +// as does other parts of the Cap'n proto library which provide a higher-level interface for +// dynamic introspection. + +#ifndef CAPNP_LAYOUT_H_ +#define CAPNP_LAYOUT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include <kj/common.h> +#include <kj/memory.h> +#include "common.h" +#include "blob.h" +#include "endian.h" + +#if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN) +#define CAPNP_CANONICALIZE_NAN 1 +// Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by +// __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN +// signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in +// particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world. +// Canonicalizing them makes output consistent (which is important!), but hurts performance +// slightly. +// +// Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work. +// Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs. +// everyone else. It would be great if we could just flip that bit, but we can't, because if the +// significand is all-zero, then the value is infinity rather than NaN. This means that on most +// machines, where the bit indicates quietness, there is one more quiet NaN value than signalling +// NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic +// mapping that properly preserves quietness. Instead of doing something hacky, we just give up +// and blow away NaN payloads, because no one uses them anyway. +#endif + +namespace capnp { + +#if !CAPNP_LITE +class ClientHook; +#endif // !CAPNP_LITE + +namespace _ { // private + +class PointerBuilder; +class PointerReader; +class StructBuilder; +class StructReader; +class ListBuilder; +class ListReader; +class OrphanBuilder; +struct WirePointer; +struct WireHelpers; +class SegmentReader; +class SegmentBuilder; +class Arena; +class BuilderArena; + +// ============================================================================= + +#if CAPNP_DEBUG_TYPES +typedef kj::UnitRatio<kj::Bounded<64, uint>, BitLabel, ElementLabel> BitsPerElementTableType; +#else +typedef uint BitsPerElementTableType; +#endif + +static constexpr BitsPerElementTableType BITS_PER_ELEMENT_TABLE[8] = { + bounded< 0>() * BITS / ELEMENTS, + bounded< 1>() * BITS / ELEMENTS, + bounded< 8>() * BITS / ELEMENTS, + bounded<16>() * BITS / ELEMENTS, + bounded<32>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS +}; + +inline KJ_CONSTEXPR() BitsPerElementTableType dataBitsPerElement(ElementSize size) { + return _::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)]; +} + +inline constexpr PointersPerElementN<1> pointersPerElement(ElementSize size) { + return size == ElementSize::POINTER + ? PointersPerElementN<1>(ONE * POINTERS / ELEMENTS) + : PointersPerElementN<1>(ZERO * POINTERS / ELEMENTS); +} + +static constexpr BitsPerElementTableType BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[8] = { + bounded< 0>() * BITS / ELEMENTS, + bounded< 1>() * BITS / ELEMENTS, + bounded< 8>() * BITS / ELEMENTS, + bounded<16>() * BITS / ELEMENTS, + bounded<32>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS +}; + +inline KJ_CONSTEXPR() BitsPerElementTableType bitsPerElementIncludingPointers(ElementSize size) { + return _::BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[static_cast<int>(size)]; +} + +template <size_t size> struct ElementSizeForByteSize; +template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; }; +template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; }; +template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; }; +template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; }; + +template <typename T> struct ElementSizeForType { + static constexpr ElementSize value = + // Primitive types that aren't special-cased below can be determined from sizeof(). + CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize<sizeof(T)>::value : + CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES : + CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE : + + // Everything else is a pointer. + ElementSize::POINTER; +}; + +// Void and bool are special. +template <> struct ElementSizeForType<Void> { static constexpr ElementSize value = ElementSize::VOID; }; +template <> struct ElementSizeForType<bool> { static constexpr ElementSize value = ElementSize::BIT; }; + +// Lists and blobs are pointers, not structs. +template <typename T, Kind K> struct ElementSizeForType<List<T, K>> { + static constexpr ElementSize value = ElementSize::POINTER; +}; +template <> struct ElementSizeForType<Text> { + static constexpr ElementSize value = ElementSize::POINTER; +}; +template <> struct ElementSizeForType<Data> { + static constexpr ElementSize value = ElementSize::POINTER; +}; + +template <typename T> +inline constexpr ElementSize elementSizeForType() { + return ElementSizeForType<T>::value; +} + +struct MessageSizeCounts { + WordCountN<61, uint64_t> wordCount; // 2^64 bytes + uint capCount; + + MessageSizeCounts& operator+=(const MessageSizeCounts& other) { + // OK to truncate unchecked because this class is used to count actual stuff in memory, and + // we couldn't possibly have anywhere near 2^61 words. + wordCount = assumeBits<61>(wordCount + other.wordCount); + capCount += other.capCount; + return *this; + } + + void addWords(WordCountN<61, uint64_t> other) { + wordCount = assumeBits<61>(wordCount + other); + } + + MessageSize asPublic() { + return MessageSize { unbound(wordCount / WORDS), capCount }; + } +}; + +// ============================================================================= + +template <int wordCount> +union AlignedData { + // Useful for declaring static constant data blobs as an array of bytes, but forcing those + // bytes to be word-aligned. + + uint8_t bytes[wordCount * sizeof(word)]; + word words[wordCount]; +}; + +struct StructSize { + StructDataWordCount data; + StructPointerCount pointers; + + inline constexpr WordCountN<17> total() const { return data + pointers * WORDS_PER_POINTER; } + + StructSize() = default; + inline constexpr StructSize(StructDataWordCount data, StructPointerCount pointers) + : data(data), pointers(pointers) {} +}; + +template <typename T, typename CapnpPrivate = typename T::_capnpPrivate> +inline constexpr StructSize structSize() { + return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS, + bounded(CapnpPrivate::pointerCount) * POINTERS); +} + +template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, + typename = kj::EnableIf<CAPNP_KIND(T) == Kind::STRUCT>> +inline constexpr StructSize minStructSizeForElement() { + // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough + // to hold a T. + + return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS, + bounded(CapnpPrivate::pointerCount) * POINTERS); +} + +template <typename T, typename = kj::EnableIf<CAPNP_KIND(T) != Kind::STRUCT>> +inline constexpr StructSize minStructSizeForElement() { + // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough + // to hold a T. + + return StructSize( + dataBitsPerElement(elementSizeForType<T>()) * ELEMENTS > ZERO * BITS + ? StructDataWordCount(ONE * WORDS) : StructDataWordCount(ZERO * WORDS), + pointersPerElement(elementSizeForType<T>()) * ELEMENTS); +} + +// ------------------------------------------------------------------- +// Masking of default values + +template <typename T, Kind kind = CAPNP_KIND(T)> struct Mask_; +template <typename T> struct Mask_<T, Kind::PRIMITIVE> { typedef T Type; }; +template <typename T> struct Mask_<T, Kind::ENUM> { typedef uint16_t Type; }; +template <> struct Mask_<float, Kind::PRIMITIVE> { typedef uint32_t Type; }; +template <> struct Mask_<double, Kind::PRIMITIVE> { typedef uint64_t Type; }; + +template <typename T> struct Mask_<T, Kind::OTHER> { + // Union discriminants end up here. + static_assert(sizeof(T) == 2, "Don't know how to mask this type."); + typedef uint16_t Type; +}; + +template <typename T> +using Mask = typename Mask_<T>::Type; + +template <typename T> +KJ_ALWAYS_INLINE(Mask<T> mask(T value, Mask<T> mask)); +template <typename T> +KJ_ALWAYS_INLINE(T unmask(Mask<T> value, Mask<T> mask)); + +template <typename T> +inline Mask<T> mask(T value, Mask<T> mask) { + return static_cast<Mask<T> >(value) ^ mask; +} + +template <> +inline uint32_t mask<float>(float value, uint32_t mask) { +#if CAPNP_CANONICALIZE_NAN + if (value != value) { + return 0x7fc00000u ^ mask; + } +#endif + + uint32_t i; + static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?"); + memcpy(&i, &value, sizeof(value)); + return i ^ mask; +} + +template <> +inline uint64_t mask<double>(double value, uint64_t mask) { +#if CAPNP_CANONICALIZE_NAN + if (value != value) { + return 0x7ff8000000000000ull ^ mask; + } +#endif + + uint64_t i; + static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?"); + memcpy(&i, &value, sizeof(value)); + return i ^ mask; +} + +template <typename T> +inline T unmask(Mask<T> value, Mask<T> mask) { + return static_cast<T>(value ^ mask); +} + +template <> +inline float unmask<float>(uint32_t value, uint32_t mask) { + value ^= mask; + float result; + static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?"); + memcpy(&result, &value, sizeof(value)); + return result; +} + +template <> +inline double unmask<double>(uint64_t value, uint64_t mask) { + value ^= mask; + double result; + static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?"); + memcpy(&result, &value, sizeof(value)); + return result; +} + +// ------------------------------------------------------------------- + +class CapTableReader { +public: +#if !CAPNP_LITE + virtual kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) = 0; + // Extract the capability at the given index. If the index is invalid, returns null. +#endif // !CAPNP_LITE +}; + +class CapTableBuilder: public CapTableReader { +public: +#if !CAPNP_LITE + virtual uint injectCap(kj::Own<ClientHook>&& cap) = 0; + // Add the capability to the message and return its index. If the same ClientHook is injected + // twice, this may return the same index both times, but in this case dropCap() needs to be + // called an equal number of times to actually remove the cap. + + virtual void dropCap(uint index) = 0; + // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out. +#endif // !CAPNP_LITE +}; + +// ------------------------------------------------------------------- + +class PointerBuilder: public kj::DisallowConstCopy { + // Represents a single pointer, usually embedded in a struct or a list. + +public: + inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {} + + static inline PointerBuilder getRoot( + SegmentBuilder* segment, CapTableBuilder* capTable, word* location); + // Get a PointerBuilder representing a message root located in the given segment at the given + // location. + + inline bool isNull() { return getPointerType() == PointerType::NULL_; } + PointerType getPointerType() const; + + StructBuilder getStruct(StructSize size, const word* defaultValue); + ListBuilder getList(ElementSize elementSize, const word* defaultValue); + ListBuilder getStructList(StructSize elementSize, const word* defaultValue); + ListBuilder getListAnySize(const word* defaultValue); + template <typename T> typename T::Builder getBlob( + const void* defaultValue, ByteCount defaultSize); +#if !CAPNP_LITE + kj::Own<ClientHook> getCapability(); +#endif // !CAPNP_LITE + // Get methods: Get the value. If it is null, initialize it to a copy of the default value. + // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a + // simple byte array for blobs. + + StructBuilder initStruct(StructSize size); + ListBuilder initList(ElementSize elementSize, ElementCount elementCount); + ListBuilder initStructList(ElementCount elementCount, StructSize size); + template <typename T> typename T::Builder initBlob(ByteCount size); + // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing + // object. + + void setStruct(const StructReader& value, bool canonical = false); + void setList(const ListReader& value, bool canonical = false); + template <typename T> void setBlob(typename T::Reader value); +#if !CAPNP_LITE + void setCapability(kj::Own<ClientHook>&& cap); +#endif // !CAPNP_LITE + // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding + // the existing object. + + void adopt(OrphanBuilder&& orphan); + // Set the pointer to point at the given orphaned value. + + OrphanBuilder disown(); + // Set the pointer to null and return its previous value as an orphan. + + void clear(); + // Clear the pointer to null, discarding its previous value. + + void transferFrom(PointerBuilder other); + // Equivalent to `adopt(other.disown())`. + + void copyFrom(PointerReader other, bool canonical = false); + // Equivalent to `set(other.get())`. + // If you set the canonical flag, it will attempt to lay the target out + // canonically, provided enough space is available. + + PointerReader asReader() const; + + BuilderArena* getArena() const; + // Get the arena containing this pointer. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + PointerBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the pointer resides. + CapTableBuilder* capTable; // Table of capability indexes. + WirePointer* pointer; // Pointer to the pointer. + + inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer) + : segment(segment), capTable(capTable), pointer(pointer) {} + + friend class StructBuilder; + friend class ListBuilder; + friend class OrphanBuilder; +}; + +class PointerReader { +public: + inline PointerReader() + : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {} + + static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable, + const word* location, int nestingLimit); + // Get a PointerReader representing a message root located in the given segment at the given + // location. + + static inline PointerReader getRootUnchecked(const word* location); + // Get a PointerReader for an unchecked message. + + MessageSizeCounts targetSize() const; + // Return the total size of the target object and everything to which it points. Does not count + // far pointer overhead. This is useful for deciding how much space is needed to copy the object + // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, + // use the result as a hint for allocating the first segment, do the copy, and then throw an + // exception if it overruns. + + inline bool isNull() const { return getPointerType() == PointerType::NULL_; } + PointerType getPointerType() const; + + StructReader getStruct(const word* defaultValue) const; + ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const; + ListReader getListAnySize(const word* defaultValue) const; + template <typename T> + typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; +#if !CAPNP_LITE + kj::Own<ClientHook> getCapability() const; +#endif // !CAPNP_LITE + // Get methods: Get the value. If it is null, return the default value instead. + // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a + // simple byte array for blobs. + + const word* getUnchecked() const; + // If this is an unchecked message, get a word* pointing at the location of the pointer. This + // word* can actually be passed to readUnchecked() to read the designated sub-object later. If + // this isn't an unchecked message, throws an exception. + + kj::Maybe<Arena&> getArena() const; + // Get the arena containing this pointer. + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + PointerReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + +private: + SegmentReader* segment; // Memory segment in which the pointer resides. + CapTableReader* capTable; // Table of capability indexes. + const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + + inline PointerReader(SegmentReader* segment, CapTableReader* capTable, + const WirePointer* pointer, int nestingLimit) + : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {} + + friend class StructReader; + friend class ListReader; + friend class PointerBuilder; + friend class OrphanBuilder; +}; + +// ------------------------------------------------------------------- + +class StructBuilder: public kj::DisallowConstCopy { +public: + inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {} + + inline word* getLocation() { return reinterpret_cast<word*>(data); } + // Get the object's location. Only valid for independently-allocated objects (i.e. not list + // elements). + + inline StructDataBitCount getDataSectionSize() const { return dataSize; } + inline StructPointerCount getPointerSectionSize() const { return pointerCount; } + inline kj::ArrayPtr<byte> getDataSectionAsBlob(); + inline _::ListBuilder getPointerSectionAsList(); + + template <typename T> + KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset)); + // Return true if the field is set to something other than its default value. + + template <typename T> + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset)); + // Gets the data field value of the given type at the given offset. The offset is measured in + // multiples of the field size, determined by the type. + + template <typename T> + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask<T> mask)); + // Like getDataField() but applies the given XOR mask to the data on load. Used for reading + // fields with non-zero default values. + + template <typename T> + KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, kj::NoInfer<T> value)); + // Sets the data field value at the given offset. + + template <typename T> + KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, + kj::NoInfer<T> value, Mask<T> mask)); + // Like setDataField() but applies the given XOR mask before storing. Used for writing fields + // with non-zero default values. + + KJ_ALWAYS_INLINE(PointerBuilder getPointerField(StructPointerOffset ptrIndex)); + // Get a builder for a pointer field given the index within the pointer section. + + void clearAll(); + // Clear all pointers and data. + + void transferContentFrom(StructBuilder other); + // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger + // than this, the extra data is not transferred, meaning there is a risk of data loss when + // transferring from messages built with future versions of the protocol. + + void copyContentFrom(StructReader other); + // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not + // copied, meaning there is a risk of data loss when copying from messages built with future + // versions of the protocol. + + StructReader asReader() const; + // Gets a StructReader pointing at the same memory. + + BuilderArena* getArena(); + // Gets the arena in which this object is allocated. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + StructBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the struct resides. + CapTableBuilder* capTable; // Table of capability indexes. + void* data; // Pointer to the encoded data. + WirePointer* pointers; // Pointer to the encoded pointers. + + StructDataBitCount dataSize; + // Size of data section. We use a bit count rather than a word count to more easily handle the + // case of struct lists encoded with less than a word per element. + + StructPointerCount pointerCount; // Size of the pointer section. + + inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, + void* data, WirePointer* pointers, + StructDataBitCount dataSize, StructPointerCount pointerCount) + : segment(segment), capTable(capTable), data(data), pointers(pointers), + dataSize(dataSize), pointerCount(pointerCount) {} + + friend class ListBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +class StructReader { +public: + inline StructReader() + : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr), + dataSize(ZERO * BITS), pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {} + inline StructReader(kj::ArrayPtr<const word> data) + : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr), + dataSize(assumeBits<STRUCT_DATA_WORD_COUNT_BITS>(data.size()) * WORDS * BITS_PER_WORD), + pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {} + + const void* getLocation() const { return data; } + + inline StructDataBitCount getDataSectionSize() const { return dataSize; } + inline StructPointerCount getPointerSectionSize() const { return pointerCount; } + inline kj::ArrayPtr<const byte> getDataSectionAsBlob(); + inline _::ListReader getPointerSectionAsList(); + + kj::Array<word> canonicalize(); + + template <typename T> + KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset) const); + // Return true if the field is set to something other than its default value. + + template <typename T> + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset) const); + // Get the data field value of the given type at the given offset. The offset is measured in + // multiples of the field size, determined by the type. Returns zero if the offset is past the + // end of the struct's data section. + + template <typename T> + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask<T> mask) const); + // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading + // fields with non-zero default values. + + KJ_ALWAYS_INLINE(PointerReader getPointerField(StructPointerOffset ptrIndex) const); + // Get a reader for a pointer field given the index within the pointer section. If the index + // is out-of-bounds, returns a null pointer. + + MessageSizeCounts totalSize() const; + // Return the total size of the struct and everything to which it points. Does not count far + // pointer overhead. This is useful for deciding how much space is needed to copy the struct + // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, + // use the result as a hint for allocating the first segment, do the copy, and then throw an + // exception if it overruns. + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + StructReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead, const word **ptrHead, + bool *dataTrunc, bool *ptrTrunc); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + // + // If this function returns false, the struct is non-canonical. If it + // returns true, then: + // * If it is a composite in a list, it is canonical if at least one struct + // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1 + // * If it is derived from a struct pointer, it is canonical if + // dataTrunc = 1 AND ptrTrunc = 1 + +private: + SegmentReader* segment; // Memory segment in which the struct resides. + CapTableReader* capTable; // Table of capability indexes. + + const void* data; + const WirePointer* pointers; + + StructDataBitCount dataSize; + // Size of data section. We use a bit count rather than a word count to more easily handle the + // case of struct lists encoded with less than a word per element. + + StructPointerCount pointerCount; // Size of the pointer section. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + // TODO(perf): Limit to 16 bits for better packing? + + inline StructReader(SegmentReader* segment, CapTableReader* capTable, + const void* data, const WirePointer* pointers, + StructDataBitCount dataSize, StructPointerCount pointerCount, + int nestingLimit) + : segment(segment), capTable(capTable), data(data), pointers(pointers), + dataSize(dataSize), pointerCount(pointerCount), + nestingLimit(nestingLimit) {} + + friend class ListReader; + friend class StructBuilder; + friend struct WireHelpers; +}; + +// ------------------------------------------------------------------- + +class ListBuilder: public kj::DisallowConstCopy { +public: + inline explicit ListBuilder(ElementSize elementSize) + : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS), + step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS), + structPointerCount(ZERO * POINTERS), elementSize(elementSize) {} + + inline word* getLocation() { + // Get the object's location. + + if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) { + return reinterpret_cast<word*>(ptr) - POINTER_SIZE_IN_WORDS; + } else { + return reinterpret_cast<word*>(ptr); + } + } + + inline ElementSize getElementSize() const { return elementSize; } + + inline ListElementCount size() const; + // The number of elements in the list. + + Text::Builder asText(); + Data::Builder asData(); + // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. + + template <typename T> + KJ_ALWAYS_INLINE(T getDataElement(ElementCount index)); + // Get the element of the given type at the given index. + + template <typename T> + KJ_ALWAYS_INLINE(void setDataElement(ElementCount index, kj::NoInfer<T> value)); + // Set the element at the given index. + + KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index)); + + StructBuilder getStructElement(ElementCount index); + + ListReader asReader() const; + // Get a ListReader pointing at the same memory. + + BuilderArena* getArena(); + // Gets the arena in which this object is allocated. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + ListBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the list resides. + CapTableBuilder* capTable; // Table of capability indexes. + + byte* ptr; // Pointer to list content. + + ListElementCount elementCount; // Number of elements in the list. + + BitsPerElementN<23> step; + // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data + // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 128 bits. + + StructDataBitCount structDataSize; + StructPointerCount structPointerCount; + // The struct properties to use when interpreting the elements as structs. All lists can be + // interpreted as struct lists, so these are always filled in. + + ElementSize elementSize; + // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE + // from other types when the overall size is exactly zero or one words. + + inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr, + BitsPerElementN<23> step, ListElementCount size, + StructDataBitCount structDataSize, StructPointerCount structPointerCount, + ElementSize elementSize) + : segment(segment), capTable(capTable), ptr(reinterpret_cast<byte*>(ptr)), + elementCount(size), step(step), structDataSize(structDataSize), + structPointerCount(structPointerCount), elementSize(elementSize) {} + + friend class StructBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +class ListReader { +public: + inline explicit ListReader(ElementSize elementSize) + : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS), + step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS), + structPointerCount(ZERO * POINTERS), elementSize(elementSize), nestingLimit(0x7fffffff) {} + + inline ListElementCount size() const; + // The number of elements in the list. + + inline ElementSize getElementSize() const { return elementSize; } + + Text::Reader asText(); + Data::Reader asData(); + // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. + + kj::ArrayPtr<const byte> asRawBytes(); + + template <typename T> + KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const); + // Get the element of the given type at the given index. + + KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const); + + StructReader getStructElement(ElementCount index) const; + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + ListReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead, const WirePointer* ref); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + +private: + SegmentReader* segment; // Memory segment in which the list resides. + CapTableReader* capTable; // Table of capability indexes. + + const byte* ptr; // Pointer to list content. + + ListElementCount elementCount; // Number of elements in the list. + + BitsPerElementN<23> step; + // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data + // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 2 bits. + + StructDataBitCount structDataSize; + StructPointerCount structPointerCount; + // The struct properties to use when interpreting the elements as structs. All lists can be + // interpreted as struct lists, so these are always filled in. + + ElementSize elementSize; + // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE + // from other types when the overall size is exactly zero or one words. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + + inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr, + ListElementCount elementCount, BitsPerElementN<23> step, + StructDataBitCount structDataSize, StructPointerCount structPointerCount, + ElementSize elementSize, int nestingLimit) + : segment(segment), capTable(capTable), ptr(reinterpret_cast<const byte*>(ptr)), + elementCount(elementCount), step(step), structDataSize(structDataSize), + structPointerCount(structPointerCount), elementSize(elementSize), + nestingLimit(nestingLimit) {} + + friend class StructReader; + friend class ListBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +// ------------------------------------------------------------------- + +class OrphanBuilder { +public: + inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) { + memset(&tag, 0, sizeof(tag)); + } + OrphanBuilder(const OrphanBuilder& other) = delete; + inline OrphanBuilder(OrphanBuilder&& other) noexcept; + inline ~OrphanBuilder() noexcept(false); + + static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size); + static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, ElementSize elementSize); + static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, StructSize elementSize); + static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); + static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); + + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom); +#if !CAPNP_LITE + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, + kj::Own<ClientHook> copyFrom); +#endif // !CAPNP_LITE + + static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable, + ElementSize expectedElementSize, StructSize expectedStructSize, + kj::ArrayPtr<const ListReader> lists); + + static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data); + + OrphanBuilder& operator=(const OrphanBuilder& other) = delete; + inline OrphanBuilder& operator=(OrphanBuilder&& other); + + inline bool operator==(decltype(nullptr)) const { return location == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return location != nullptr; } + + StructBuilder asStruct(StructSize size); + // Interpret as a struct, or throw an exception if not a struct. + + ListBuilder asList(ElementSize elementSize); + // Interpret as a list, or throw an exception if not a list. elementSize cannot be + // INLINE_COMPOSITE -- use asStructList() instead. + + ListBuilder asStructList(StructSize elementSize); + // Interpret as a struct list, or throw an exception if not a list. + + ListBuilder asListAnySize(); + // For AnyList. + + Text::Builder asText(); + Data::Builder asData(); + // Interpret as a blob, or throw an exception if not a blob. + + StructReader asStructReader(StructSize size) const; + ListReader asListReader(ElementSize elementSize) const; + ListReader asListReaderAnySize() const; +#if !CAPNP_LITE + kj::Own<ClientHook> asCapability() const; +#endif // !CAPNP_LITE + Text::Reader asTextReader() const; + Data::Reader asDataReader() const; + + bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT; + // Resize the orphan list to the given size. Returns false if the list is currently empty but + // the requested size is non-zero, in which case the caller will need to allocate a new list. + + void truncate(ElementCount size, ElementSize elementSize); + void truncate(ElementCount size, StructSize elementSize); + void truncateText(ElementCount size); + // Versions of truncate() that know how to allocate a new list if needed. + +private: + static_assert(ONE * POINTERS * WORDS_PER_POINTER == ONE * WORDS, + "This struct assumes a pointer is one word."); + word tag; + // Contains an encoded WirePointer representing this object. WirePointer is defined in + // layout.c++, but fits in a word. + // + // This may be a FAR pointer. Even in that case, `location` points to the eventual destination + // of that far pointer. The reason we keep the far pointer around rather than just making `tag` + // represent the final destination is because if the eventual adopter of the pointer is not in + // the target's segment then it may be useful to reuse the far pointer landing pad. + // + // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual + // target. + + SegmentBuilder* segment; + // Segment in which the object resides. + + CapTableBuilder* capTable; + // Table of capability indexes. + + word* location; + // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this + // 0x1 just so that it is non-null for operator==, but it is never used. + + inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, + CapTableBuilder* capTable, word* location) + : segment(segment), capTable(capTable), location(location) { + memcpy(&tag, tagPtr, sizeof(tag)); + } + + inline WirePointer* tagAsPtr() { return reinterpret_cast<WirePointer*>(&tag); } + inline const WirePointer* tagAsPtr() const { return reinterpret_cast<const WirePointer*>(&tag); } + + void euthanize(); + // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when + // the OrphanBuilder is being destroyed or overwritten and it is non-null. + + friend struct WireHelpers; +}; + +// ======================================================================================= +// Internal implementation details... + +// These are defined in the source file. +template <> typename Text::Builder PointerBuilder::initBlob<Text>(ByteCount size); +template <> void PointerBuilder::setBlob<Text>(typename Text::Reader value); +template <> typename Text::Builder PointerBuilder::getBlob<Text>( + const void* defaultValue, ByteCount defaultSize); +template <> typename Text::Reader PointerReader::getBlob<Text>( + const void* defaultValue, ByteCount defaultSize) const; + +template <> typename Data::Builder PointerBuilder::initBlob<Data>(ByteCount size); +template <> void PointerBuilder::setBlob<Data>(typename Data::Reader value); +template <> typename Data::Builder PointerBuilder::getBlob<Data>( + const void* defaultValue, ByteCount defaultSize); +template <> typename Data::Reader PointerReader::getBlob<Data>( + const void* defaultValue, ByteCount defaultSize) const; + +inline PointerBuilder PointerBuilder::getRoot( + SegmentBuilder* segment, CapTableBuilder* capTable, word* location) { + return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(location)); +} + +inline PointerReader PointerReader::getRootUnchecked(const word* location) { + return PointerReader(nullptr, nullptr, + reinterpret_cast<const WirePointer*>(location), 0x7fffffff); +} + +// ------------------------------------------------------------------- + +inline kj::ArrayPtr<byte> StructBuilder::getDataSectionAsBlob() { + return kj::ArrayPtr<byte>(reinterpret_cast<byte*>(data), + unbound(dataSize / BITS_PER_BYTE / BYTES)); +} + +inline _::ListBuilder StructBuilder::getPointerSectionAsList() { + return _::ListBuilder(segment, capTable, pointers, ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, + pointerCount * (ONE * ELEMENTS / POINTERS), + ZERO * BITS, ONE * POINTERS, ElementSize::POINTER); +} + +template <typename T> +inline bool StructBuilder::hasDataField(StructDataOffset offset) { + return getDataField<Mask<T>>(offset) != 0; +} + +template <> +inline bool StructBuilder::hasDataField<Void>(StructDataOffset offset) { + return false; +} + +template <typename T> +inline T StructBuilder::getDataField(StructDataOffset offset) { + return reinterpret_cast<WireValue<T>*>(data)[unbound(offset / ELEMENTS)].get(); +} + +template <> +inline bool StructBuilder::getDataField<bool>(StructDataOffset offset) { + BitCount32 boffset = offset * (ONE * BITS / ELEMENTS); + byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE; + return (*reinterpret_cast<uint8_t*>(b) & + unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void StructBuilder::getDataField<Void>(StructDataOffset offset) { + return VOID; +} + +template <typename T> +inline T StructBuilder::getDataField(StructDataOffset offset, Mask<T> mask) { + return unmask<T>(getDataField<Mask<T> >(offset), mask); +} + +template <typename T> +inline void StructBuilder::setDataField(StructDataOffset offset, kj::NoInfer<T> value) { + reinterpret_cast<WireValue<T>*>(data)[unbound(offset / ELEMENTS)].set(value); +} + +#if CAPNP_CANONICALIZE_NAN +// Use mask() on floats and doubles to make sure we canonicalize NaNs. +template <> +inline void StructBuilder::setDataField<float>(StructDataOffset offset, float value) { + setDataField<uint32_t>(offset, mask<float>(value, 0)); +} +template <> +inline void StructBuilder::setDataField<double>(StructDataOffset offset, double value) { + setDataField<uint64_t>(offset, mask<double>(value, 0)); +} +#endif + +template <> +inline void StructBuilder::setDataField<bool>(StructDataOffset offset, bool value) { + auto boffset = offset * (ONE * BITS / ELEMENTS); + byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE; + uint bitnum = unboundMaxBits<3>(boffset % BITS_PER_BYTE / BITS); + *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum)) + | (static_cast<uint8_t>(value) << bitnum); +} + +template <> +inline void StructBuilder::setDataField<Void>(StructDataOffset offset, Void value) {} + +template <typename T> +inline void StructBuilder::setDataField(StructDataOffset offset, + kj::NoInfer<T> value, Mask<T> m) { + setDataField<Mask<T> >(offset, mask<T>(value, m)); +} + +inline PointerBuilder StructBuilder::getPointerField(StructPointerOffset ptrIndex) { + // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). + return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>( + reinterpret_cast<word*>(pointers) + ptrIndex * WORDS_PER_POINTER)); +} + +// ------------------------------------------------------------------- + +inline kj::ArrayPtr<const byte> StructReader::getDataSectionAsBlob() { + return kj::ArrayPtr<const byte>(reinterpret_cast<const byte*>(data), + unbound(dataSize / BITS_PER_BYTE / BYTES)); +} + +inline _::ListReader StructReader::getPointerSectionAsList() { + return _::ListReader(segment, capTable, pointers, pointerCount * (ONE * ELEMENTS / POINTERS), + ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, ZERO * BITS, ONE * POINTERS, + ElementSize::POINTER, nestingLimit); +} + +template <typename T> +inline bool StructReader::hasDataField(StructDataOffset offset) const { + return getDataField<Mask<T>>(offset) != 0; +} + +template <> +inline bool StructReader::hasDataField<Void>(StructDataOffset offset) const { + return false; +} + +template <typename T> +inline T StructReader::getDataField(StructDataOffset offset) const { + if ((offset + ONE * ELEMENTS) * capnp::bitsPerElement<T>() <= dataSize) { + return reinterpret_cast<const WireValue<T>*>(data)[unbound(offset / ELEMENTS)].get(); + } else { + return static_cast<T>(0); + } +} + +template <> +inline bool StructReader::getDataField<bool>(StructDataOffset offset) const { + auto boffset = offset * (ONE * BITS / ELEMENTS); + if (boffset < dataSize) { + const byte* b = reinterpret_cast<const byte*>(data) + boffset / BITS_PER_BYTE; + return (*reinterpret_cast<const uint8_t*>(b) & + unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0; + } else { + return false; + } +} + +template <> +inline Void StructReader::getDataField<Void>(StructDataOffset offset) const { + return VOID; +} + +template <typename T> +T StructReader::getDataField(StructDataOffset offset, Mask<T> mask) const { + return unmask<T>(getDataField<Mask<T> >(offset), mask); +} + +inline PointerReader StructReader::getPointerField(StructPointerOffset ptrIndex) const { + if (ptrIndex < pointerCount) { + // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). + return PointerReader(segment, capTable, reinterpret_cast<const WirePointer*>( + reinterpret_cast<const word*>(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit); + } else{ + return PointerReader(); + } +} + +// ------------------------------------------------------------------- + +inline ListElementCount ListBuilder::size() const { return elementCount; } + +template <typename T> +inline T ListBuilder::getDataElement(ElementCount index) { + return reinterpret_cast<WireValue<T>*>( + ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)->get(); + + // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of + // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and + // the various non-inline methods that look up pointers. + // Also if using this, consider changing ptr back to void* instead of byte*. +// return reinterpret_cast<WireValue<T>*>(ptr)[ +// index / ELEMENTS * (step / capnp::bitsPerElement<T>())].get(); +} + +template <> +inline bool ListBuilder::getDataElement<bool>(ElementCount index) { + // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + byte* b = ptr + bindex / BITS_PER_BYTE; + return (*reinterpret_cast<uint8_t*>(b) & + unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void ListBuilder::getDataElement<Void>(ElementCount index) { + return VOID; +} + +template <typename T> +inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer<T> value) { + reinterpret_cast<WireValue<T>*>( + ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)->set(value); +} + +#if CAPNP_CANONICALIZE_NAN +// Use mask() on floats and doubles to make sure we canonicalize NaNs. +template <> +inline void ListBuilder::setDataElement<float>(ElementCount index, float value) { + setDataElement<uint32_t>(index, mask<float>(value, 0)); +} +template <> +inline void ListBuilder::setDataElement<double>(ElementCount index, double value) { + setDataElement<uint64_t>(index, mask<double>(value, 0)); +} +#endif + +template <> +inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) { + // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + byte* b = ptr + bindex / BITS_PER_BYTE; + auto bitnum = bindex % BITS_PER_BYTE / BITS; + *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << unbound(bitnum))) + | (static_cast<uint8_t>(value) << unbound(bitnum)); +} + +template <> +inline void ListBuilder::setDataElement<Void>(ElementCount index, Void value) {} + +inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) { + return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(ptr + + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)); +} + +// ------------------------------------------------------------------- + +inline ListElementCount ListReader::size() const { return elementCount; } + +template <typename T> +inline T ListReader::getDataElement(ElementCount index) const { + return reinterpret_cast<const WireValue<T>*>( + ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)->get(); +} + +template <> +inline bool ListReader::getDataElement<bool>(ElementCount index) const { + // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + const byte* b = ptr + bindex / BITS_PER_BYTE; + return (*reinterpret_cast<const uint8_t*>(b) & + unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void ListReader::getDataElement<Void>(ElementCount index) const { + return VOID; +} + +inline PointerReader ListReader::getPointerElement(ElementCount index) const { + return PointerReader(segment, capTable, reinterpret_cast<const WirePointer*>( + ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE), nestingLimit); +} + +// ------------------------------------------------------------------- + +inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept + : segment(other.segment), capTable(other.capTable), location(other.location) { + memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. + other.segment = nullptr; + other.location = nullptr; +} + +inline OrphanBuilder::~OrphanBuilder() noexcept(false) { + if (segment != nullptr) euthanize(); +} + +inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) { + // With normal smart pointers, it's important to handle the case where the incoming pointer + // is actually transitively owned by this one. In this case, euthanize() would destroy `other` + // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only + // owns message objects, and `other` is not itself a message object, therefore cannot possibly + // be transitively owned by `this`. + + if (segment != nullptr) euthanize(); + segment = other.segment; + capTable = other.capTable; + location = other.location; + memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. + other.segment = nullptr; + other.location = nullptr; + return *this; +} + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_LAYOUT_H_