annotate win32-mingw/include/capnp/layout.h @ 141:1b5b6dfd0d0e

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