Chris@64: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors Chris@64: // Licensed under the MIT License: Chris@64: // Chris@64: // Permission is hereby granted, free of charge, to any person obtaining a copy Chris@64: // of this software and associated documentation files (the "Software"), to deal Chris@64: // in the Software without restriction, including without limitation the rights Chris@64: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell Chris@64: // copies of the Software, and to permit persons to whom the Software is Chris@64: // furnished to do so, subject to the following conditions: Chris@64: // Chris@64: // The above copyright notice and this permission notice shall be included in Chris@64: // all copies or substantial portions of the Software. Chris@64: // Chris@64: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR Chris@64: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, Chris@64: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE Chris@64: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER Chris@64: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, Chris@64: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN Chris@64: // THE SOFTWARE. Chris@64: Chris@64: // This file contains types which are intended to help detect incorrect usage at compile Chris@64: // time, but should then be optimized down to basic primitives (usually, integers) by the Chris@64: // compiler. Chris@64: Chris@64: #ifndef CAPNP_COMMON_H_ Chris@64: #define CAPNP_COMMON_H_ Chris@64: Chris@64: #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) Chris@64: #pragma GCC system_header Chris@64: #endif Chris@64: Chris@64: #include Chris@64: #include Chris@64: #include Chris@64: Chris@64: #if CAPNP_DEBUG_TYPES Chris@64: #include Chris@64: #endif Chris@64: Chris@64: namespace capnp { Chris@64: Chris@64: #define CAPNP_VERSION_MAJOR 0 Chris@64: #define CAPNP_VERSION_MINOR 6 Chris@64: #define CAPNP_VERSION_MICRO 0 Chris@64: Chris@64: #define CAPNP_VERSION \ Chris@64: (CAPNP_VERSION_MAJOR * 1000000 + CAPNP_VERSION_MINOR * 1000 + CAPNP_VERSION_MICRO) Chris@64: Chris@64: #ifndef CAPNP_LITE Chris@64: #define CAPNP_LITE 0 Chris@64: #endif Chris@64: Chris@64: typedef unsigned int uint; Chris@64: Chris@64: struct Void { Chris@64: // Type used for Void fields. Using C++'s "void" type creates a bunch of issues since it behaves Chris@64: // differently from other types. Chris@64: Chris@64: inline constexpr bool operator==(Void other) const { return true; } Chris@64: inline constexpr bool operator!=(Void other) const { return false; } Chris@64: }; Chris@64: Chris@64: static constexpr Void VOID = Void(); Chris@64: // Constant value for `Void`, which is an empty struct. Chris@64: Chris@64: inline kj::StringPtr KJ_STRINGIFY(Void) { return "void"; } Chris@64: Chris@64: struct Text; Chris@64: struct Data; Chris@64: Chris@64: enum class Kind: uint8_t { Chris@64: PRIMITIVE, Chris@64: BLOB, Chris@64: ENUM, Chris@64: STRUCT, Chris@64: UNION, Chris@64: INTERFACE, Chris@64: LIST, Chris@64: Chris@64: OTHER Chris@64: // Some other type which is often a type parameter to Cap'n Proto templates, but which needs Chris@64: // special handling. This includes types like AnyPointer, Dynamic*, etc. Chris@64: }; Chris@64: Chris@64: enum class Style: uint8_t { Chris@64: PRIMITIVE, Chris@64: POINTER, // other than struct Chris@64: STRUCT, Chris@64: CAPABILITY Chris@64: }; Chris@64: Chris@64: enum class ElementSize: uint8_t { Chris@64: // Size of a list element. Chris@64: Chris@64: VOID = 0, Chris@64: BIT = 1, Chris@64: BYTE = 2, Chris@64: TWO_BYTES = 3, Chris@64: FOUR_BYTES = 4, Chris@64: EIGHT_BYTES = 5, Chris@64: Chris@64: POINTER = 6, Chris@64: Chris@64: INLINE_COMPOSITE = 7 Chris@64: }; Chris@64: Chris@64: enum class PointerType { Chris@64: // Various wire types a pointer field can take Chris@64: Chris@64: NULL_, Chris@64: // Should be NULL, but that's #defined in stddef.h Chris@64: Chris@64: STRUCT, Chris@64: LIST, Chris@64: CAPABILITY Chris@64: }; Chris@64: Chris@64: namespace schemas { Chris@64: Chris@64: template Chris@64: struct EnumInfo; Chris@64: Chris@64: } // namespace schemas Chris@64: Chris@64: namespace _ { // private Chris@64: Chris@64: template struct Kind_; Chris@64: Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; Chris@64: template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; Chris@64: Chris@64: template struct Kind_> { Chris@64: static constexpr Kind kind = Kind::STRUCT; Chris@64: }; Chris@64: template struct Kind_> { Chris@64: static constexpr Kind kind = Kind::INTERFACE; Chris@64: }; Chris@64: template struct Kind_::IsEnum>> { Chris@64: static constexpr Kind kind = Kind::ENUM; Chris@64: }; Chris@64: Chris@64: } // namespace _ (private) Chris@64: Chris@64: template ::kind> Chris@64: inline constexpr Kind kind() { Chris@64: // This overload of kind() matches types which have a Kind_ specialization. Chris@64: Chris@64: return k; Chris@64: } Chris@64: Chris@64: #if CAPNP_LITE Chris@64: Chris@64: #define CAPNP_KIND(T) ::capnp::_::Kind_::kind Chris@64: // Avoid constexpr methods in lite mode (MSVC is bad at constexpr). Chris@64: Chris@64: #else // CAPNP_LITE Chris@64: Chris@64: #define CAPNP_KIND(T) ::capnp::kind() Chris@64: // Use this macro rather than kind() in any code which must work in lite mode. Chris@64: Chris@64: template ()> Chris@64: inline constexpr Style style() { Chris@64: return k == Kind::PRIMITIVE || k == Kind::ENUM ? Style::PRIMITIVE Chris@64: : k == Kind::STRUCT ? Style::STRUCT Chris@64: : k == Kind::INTERFACE ? Style::CAPABILITY : Style::POINTER; Chris@64: } Chris@64: Chris@64: #endif // CAPNP_LITE, else Chris@64: Chris@64: template Chris@64: struct List; Chris@64: Chris@64: #if _MSC_VER Chris@64: Chris@64: template Chris@64: struct List {}; Chris@64: // For some reason, without this declaration, MSVC will error out on some uses of List Chris@64: // claiming that "T" -- as used in the default initializer for the second template param, "k" -- Chris@64: // is not defined. I do not understand this error, but adding this empty default declaration fixes Chris@64: // it. Chris@64: Chris@64: #endif Chris@64: Chris@64: template struct ListElementType_; Chris@64: template struct ListElementType_> { typedef T Type; }; Chris@64: template using ListElementType = typename ListElementType_::Type; Chris@64: Chris@64: namespace _ { // private Chris@64: template struct Kind_> { Chris@64: static constexpr Kind kind = Kind::LIST; Chris@64: }; Chris@64: } // namespace _ (private) Chris@64: Chris@64: template struct ReaderFor_ { typedef typename T::Reader Type; }; Chris@64: template struct ReaderFor_ { typedef T Type; }; Chris@64: template struct ReaderFor_ { typedef T Type; }; Chris@64: template struct ReaderFor_ { typedef typename T::Client Type; }; Chris@64: template using ReaderFor = typename ReaderFor_::Type; Chris@64: // The type returned by List::Reader::operator[]. Chris@64: Chris@64: template struct BuilderFor_ { typedef typename T::Builder Type; }; Chris@64: template struct BuilderFor_ { typedef T Type; }; Chris@64: template struct BuilderFor_ { typedef T Type; }; Chris@64: template struct BuilderFor_ { typedef typename T::Client Type; }; Chris@64: template using BuilderFor = typename BuilderFor_::Type; Chris@64: // The type returned by List::Builder::operator[]. Chris@64: Chris@64: template struct PipelineFor_ { typedef typename T::Pipeline Type;}; Chris@64: template struct PipelineFor_ { typedef typename T::Client Type; }; Chris@64: template using PipelineFor = typename PipelineFor_::Type; Chris@64: Chris@64: template struct TypeIfEnum_; Chris@64: template struct TypeIfEnum_ { typedef T Type; }; Chris@64: Chris@64: template Chris@64: using TypeIfEnum = typename TypeIfEnum_>::Type; Chris@64: Chris@64: template Chris@64: using FromReader = typename kj::Decay::Reads; Chris@64: // FromReader = MyType (for any Cap'n Proto type). Chris@64: Chris@64: template Chris@64: using FromBuilder = typename kj::Decay::Builds; Chris@64: // FromBuilder = MyType (for any Cap'n Proto type). Chris@64: Chris@64: template Chris@64: using FromPipeline = typename kj::Decay::Pipelines; Chris@64: // FromBuilder = MyType (for any Cap'n Proto type). Chris@64: Chris@64: template Chris@64: using FromClient = typename kj::Decay::Calls; Chris@64: // FromReader = MyType (for any Cap'n Proto interface type). Chris@64: Chris@64: template Chris@64: using FromServer = typename kj::Decay::Serves; Chris@64: // FromBuilder = MyType (for any Cap'n Proto interface type). Chris@64: Chris@64: template Chris@64: struct FromAny_; Chris@64: Chris@64: template Chris@64: struct FromAny_>> { Chris@64: using Type = FromReader; Chris@64: }; Chris@64: Chris@64: template Chris@64: struct FromAny_>> { Chris@64: using Type = FromBuilder; Chris@64: }; Chris@64: Chris@64: template Chris@64: struct FromAny_>> { Chris@64: using Type = FromPipeline; Chris@64: }; Chris@64: Chris@64: // Note that T::Client is covered by FromReader Chris@64: Chris@64: template Chris@64: struct FromAny_, kj::VoidSfinae>> { Chris@64: using Type = FromServer; Chris@64: }; Chris@64: Chris@64: template Chris@64: struct FromAny_::kind == Kind::PRIMITIVE || _::Kind_::kind == Kind::ENUM>> { Chris@64: // TODO(msvc): Ideally the EnableIf condition would be `style() == Style::PRIMITIVE`, but MSVC Chris@64: // cannot yet use style() in this constexpr context. Chris@64: Chris@64: using Type = kj::Decay; Chris@64: }; Chris@64: Chris@64: template Chris@64: using FromAny = typename FromAny_::Type; Chris@64: // Given any Cap'n Proto value type as an input, return the Cap'n Proto base type. That is: Chris@64: // Chris@64: // Foo::Reader -> Foo Chris@64: // Foo::Builder -> Foo Chris@64: // Foo::Pipeline -> Foo Chris@64: // Foo::Client -> Foo Chris@64: // Own -> Foo Chris@64: // uint32_t -> uint32_t Chris@64: Chris@64: namespace _ { // private Chris@64: Chris@64: template Chris@64: struct PointerHelpers; Chris@64: Chris@64: #if _MSC_VER Chris@64: Chris@64: template Chris@64: struct PointerHelpers {}; Chris@64: // For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers Chris@64: // claiming that "T" -- as used in the default initializer for the second template param, "k" -- Chris@64: // is not defined. I do not understand this error, but adding this empty default declaration fixes Chris@64: // it. Chris@64: Chris@64: #endif Chris@64: Chris@64: } // namespace _ (private) Chris@64: Chris@64: struct MessageSize { Chris@64: // Size of a message. Every struct type has a method `.totalSize()` that returns this. Chris@64: uint64_t wordCount; Chris@64: uint capCount; Chris@64: }; Chris@64: Chris@64: // ======================================================================================= Chris@64: // Raw memory types and measures Chris@64: Chris@64: using kj::byte; Chris@64: Chris@64: class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public: word() = default; }; Chris@64: // word is an opaque type with size of 64 bits. This type is useful only to make pointer Chris@64: // arithmetic clearer. Since the contents are private, the only way to access them is to first Chris@64: // reinterpret_cast to some other pointer type. Chris@64: // Chris@64: // Copying is disallowed because you should always use memcpy(). Otherwise, you may run afoul of Chris@64: // aliasing rules. Chris@64: // Chris@64: // A pointer of type word* should always be word-aligned even if won't actually be dereferenced as Chris@64: // that type. Chris@64: Chris@64: static_assert(sizeof(byte) == 1, "uint8_t is not one byte?"); Chris@64: static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?"); Chris@64: Chris@64: #if CAPNP_DEBUG_TYPES Chris@64: // Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are Chris@64: // used. All the code should still operate exactly the same, we just lose compile-time checking. Chris@64: // Note that this will also change symbol names, so it's important that the library and any clients Chris@64: // be compiled with the same setting here. Chris@64: // Chris@64: // We disable this by default to reduce symbol name size and avoid any possibility of the compiler Chris@64: // failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this Chris@64: // during development and testing. Chris@64: Chris@64: namespace _ { class BitLabel; class ElementLabel; struct WirePointer; } Chris@64: Chris@64: template Chris@64: using BitCountN = kj::Quantity(), T>, _::BitLabel>; Chris@64: template Chris@64: using ByteCountN = kj::Quantity(), T>, byte>; Chris@64: template Chris@64: using WordCountN = kj::Quantity(), T>, word>; Chris@64: template Chris@64: using ElementCountN = kj::Quantity(), T>, _::ElementLabel>; Chris@64: template Chris@64: using WirePointerCountN = kj::Quantity(), T>, _::WirePointer>; Chris@64: Chris@64: typedef BitCountN<8, uint8_t> BitCount8; Chris@64: typedef BitCountN<16, uint16_t> BitCount16; Chris@64: typedef BitCountN<32, uint32_t> BitCount32; Chris@64: typedef BitCountN<64, uint64_t> BitCount64; Chris@64: typedef BitCountN BitCount; Chris@64: Chris@64: typedef ByteCountN<8, uint8_t> ByteCount8; Chris@64: typedef ByteCountN<16, uint16_t> ByteCount16; Chris@64: typedef ByteCountN<32, uint32_t> ByteCount32; Chris@64: typedef ByteCountN<64, uint64_t> ByteCount64; Chris@64: typedef ByteCountN ByteCount; Chris@64: Chris@64: typedef WordCountN<8, uint8_t> WordCount8; Chris@64: typedef WordCountN<16, uint16_t> WordCount16; Chris@64: typedef WordCountN<32, uint32_t> WordCount32; Chris@64: typedef WordCountN<64, uint64_t> WordCount64; Chris@64: typedef WordCountN WordCount; Chris@64: Chris@64: typedef ElementCountN<8, uint8_t> ElementCount8; Chris@64: typedef ElementCountN<16, uint16_t> ElementCount16; Chris@64: typedef ElementCountN<32, uint32_t> ElementCount32; Chris@64: typedef ElementCountN<64, uint64_t> ElementCount64; Chris@64: typedef ElementCountN ElementCount; Chris@64: Chris@64: typedef WirePointerCountN<8, uint8_t> WirePointerCount8; Chris@64: typedef WirePointerCountN<16, uint16_t> WirePointerCount16; Chris@64: typedef WirePointerCountN<32, uint32_t> WirePointerCount32; Chris@64: typedef WirePointerCountN<64, uint64_t> WirePointerCount64; Chris@64: typedef WirePointerCountN WirePointerCount; Chris@64: Chris@64: template Chris@64: using BitsPerElementN = decltype(BitCountN() / ElementCountN()); Chris@64: template Chris@64: using BytesPerElementN = decltype(ByteCountN() / ElementCountN()); Chris@64: template Chris@64: using WordsPerElementN = decltype(WordCountN() / ElementCountN()); Chris@64: template Chris@64: using PointersPerElementN = decltype(WirePointerCountN() / ElementCountN()); Chris@64: Chris@64: using kj::bounded; Chris@64: using kj::unbound; Chris@64: using kj::unboundAs; Chris@64: using kj::unboundMax; Chris@64: using kj::unboundMaxBits; Chris@64: using kj::assertMax; Chris@64: using kj::assertMaxBits; Chris@64: using kj::upgradeBound; Chris@64: using kj::ThrowOverflow; Chris@64: using kj::assumeBits; Chris@64: using kj::assumeMax; Chris@64: using kj::subtractChecked; Chris@64: using kj::trySubtract; Chris@64: Chris@64: template Chris@64: inline constexpr U* operator+(U* ptr, kj::Quantity offset) { Chris@64: return ptr + unbound(offset / kj::unit>()); Chris@64: } Chris@64: template Chris@64: inline constexpr const U* operator+(const U* ptr, kj::Quantity offset) { Chris@64: return ptr + unbound(offset / kj::unit>()); Chris@64: } Chris@64: template Chris@64: inline constexpr U* operator+=(U*& ptr, kj::Quantity offset) { Chris@64: return ptr = ptr + unbound(offset / kj::unit>()); Chris@64: } Chris@64: template Chris@64: inline constexpr const U* operator+=(const U*& ptr, kj::Quantity offset) { Chris@64: return ptr = ptr + unbound(offset / kj::unit>()); Chris@64: } Chris@64: Chris@64: template Chris@64: inline constexpr U* operator-(U* ptr, kj::Quantity offset) { Chris@64: return ptr - unbound(offset / kj::unit>()); Chris@64: } Chris@64: template Chris@64: inline constexpr const U* operator-(const U* ptr, kj::Quantity offset) { Chris@64: return ptr - unbound(offset / kj::unit>()); Chris@64: } Chris@64: template Chris@64: inline constexpr U* operator-=(U*& ptr, kj::Quantity offset) { Chris@64: return ptr = ptr - unbound(offset / kj::unit>()); Chris@64: } Chris@64: template Chris@64: inline constexpr const U* operator-=(const U*& ptr, kj::Quantity offset) { Chris@64: return ptr = ptr - unbound(offset / kj::unit>()); Chris@64: } Chris@64: Chris@64: constexpr auto BITS = kj::unit>(); Chris@64: constexpr auto BYTES = kj::unit>(); Chris@64: constexpr auto WORDS = kj::unit>(); Chris@64: constexpr auto ELEMENTS = kj::unit>(); Chris@64: constexpr auto POINTERS = kj::unit>(); Chris@64: Chris@64: constexpr auto ZERO = kj::bounded<0>(); Chris@64: constexpr auto ONE = kj::bounded<1>(); Chris@64: Chris@64: // GCC 4.7 actually gives unused warnings on these constants in opt mode... Chris@64: constexpr auto BITS_PER_BYTE KJ_UNUSED = bounded<8>() * BITS / BYTES; Chris@64: constexpr auto BITS_PER_WORD KJ_UNUSED = bounded<64>() * BITS / WORDS; Chris@64: constexpr auto BYTES_PER_WORD KJ_UNUSED = bounded<8>() * BYTES / WORDS; Chris@64: Chris@64: constexpr auto BITS_PER_POINTER KJ_UNUSED = bounded<64>() * BITS / POINTERS; Chris@64: constexpr auto BYTES_PER_POINTER KJ_UNUSED = bounded<8>() * BYTES / POINTERS; Chris@64: constexpr auto WORDS_PER_POINTER KJ_UNUSED = ONE * WORDS / POINTERS; Chris@64: Chris@64: constexpr auto POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER; Chris@64: Chris@64: constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment. Chris@64: constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list. Chris@64: constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section. Chris@64: constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section. Chris@64: constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob. Chris@64: Chris@64: typedef WordCountN SegmentWordCount; Chris@64: typedef ElementCountN ListElementCount; Chris@64: typedef WordCountN StructDataWordCount; Chris@64: typedef WirePointerCountN StructPointerCount; Chris@64: typedef ByteCountN BlobSize; Chris@64: Chris@64: constexpr auto MAX_SEGMENT_WORDS = Chris@64: bounded()>() * WORDS; Chris@64: constexpr auto MAX_LIST_ELEMENTS = Chris@64: bounded()>() * ELEMENTS; Chris@64: constexpr auto MAX_STUCT_DATA_WORDS = Chris@64: bounded()>() * WORDS; Chris@64: constexpr auto MAX_STRUCT_POINTER_COUNT = Chris@64: bounded()>() * POINTERS; Chris@64: Chris@64: using StructDataBitCount = decltype(WordCountN() * BITS_PER_WORD); Chris@64: // Number of bits in a Struct data segment (should come out to BitCountN<22>). Chris@64: Chris@64: using StructDataOffset = decltype(StructDataBitCount() * (ONE * ELEMENTS / BITS)); Chris@64: using StructPointerOffset = StructPointerCount; Chris@64: // Type of a field offset. Chris@64: Chris@64: inline StructDataOffset assumeDataOffset(uint32_t offset) { Chris@64: return assumeMax(MAX_STUCT_DATA_WORDS * BITS_PER_WORD * (ONE * ELEMENTS / BITS), Chris@64: bounded(offset) * ELEMENTS); Chris@64: } Chris@64: Chris@64: inline StructPointerOffset assumePointerOffset(uint32_t offset) { Chris@64: return assumeMax(MAX_STRUCT_POINTER_COUNT, bounded(offset) * POINTERS); Chris@64: } Chris@64: Chris@64: constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits() - 1; Chris@64: typedef kj::Quantity, byte> TextSize; Chris@64: // Not including NUL terminator. Chris@64: Chris@64: template Chris@64: inline KJ_CONSTEXPR() decltype(bounded() * BYTES / ELEMENTS) bytesPerElement() { Chris@64: return bounded() * BYTES / ELEMENTS; Chris@64: } Chris@64: Chris@64: template Chris@64: inline KJ_CONSTEXPR() decltype(bounded() * BITS / ELEMENTS) bitsPerElement() { Chris@64: return bounded() * BITS / ELEMENTS; Chris@64: } Chris@64: Chris@64: template Chris@64: inline constexpr kj::Quantity, T> Chris@64: intervalLength(const T* a, const T* b, kj::Quantity, T>) { Chris@64: return kj::assumeMax(b - a) * kj::unit, T>>(); Chris@64: } Chris@64: Chris@64: template Chris@64: inline constexpr kj::ArrayPtr arrayPtr(const U* ptr, kj::Quantity size) { Chris@64: return kj::ArrayPtr(ptr, unbound(size / kj::unit>())); Chris@64: } Chris@64: template Chris@64: inline constexpr kj::ArrayPtr arrayPtr(U* ptr, kj::Quantity size) { Chris@64: return kj::ArrayPtr(ptr, unbound(size / kj::unit>())); Chris@64: } Chris@64: Chris@64: #else Chris@64: Chris@64: template Chris@64: using BitCountN = T; Chris@64: template Chris@64: using ByteCountN = T; Chris@64: template Chris@64: using WordCountN = T; Chris@64: template Chris@64: using ElementCountN = T; Chris@64: template Chris@64: using WirePointerCountN = T; Chris@64: Chris@64: Chris@64: // XXX Chris@64: typedef BitCountN<8, uint8_t> BitCount8; Chris@64: typedef BitCountN<16, uint16_t> BitCount16; Chris@64: typedef BitCountN<32, uint32_t> BitCount32; Chris@64: typedef BitCountN<64, uint64_t> BitCount64; Chris@64: typedef BitCountN BitCount; Chris@64: Chris@64: typedef ByteCountN<8, uint8_t> ByteCount8; Chris@64: typedef ByteCountN<16, uint16_t> ByteCount16; Chris@64: typedef ByteCountN<32, uint32_t> ByteCount32; Chris@64: typedef ByteCountN<64, uint64_t> ByteCount64; Chris@64: typedef ByteCountN ByteCount; Chris@64: Chris@64: typedef WordCountN<8, uint8_t> WordCount8; Chris@64: typedef WordCountN<16, uint16_t> WordCount16; Chris@64: typedef WordCountN<32, uint32_t> WordCount32; Chris@64: typedef WordCountN<64, uint64_t> WordCount64; Chris@64: typedef WordCountN WordCount; Chris@64: Chris@64: typedef ElementCountN<8, uint8_t> ElementCount8; Chris@64: typedef ElementCountN<16, uint16_t> ElementCount16; Chris@64: typedef ElementCountN<32, uint32_t> ElementCount32; Chris@64: typedef ElementCountN<64, uint64_t> ElementCount64; Chris@64: typedef ElementCountN ElementCount; Chris@64: Chris@64: typedef WirePointerCountN<8, uint8_t> WirePointerCount8; Chris@64: typedef WirePointerCountN<16, uint16_t> WirePointerCount16; Chris@64: typedef WirePointerCountN<32, uint32_t> WirePointerCount32; Chris@64: typedef WirePointerCountN<64, uint64_t> WirePointerCount64; Chris@64: typedef WirePointerCountN WirePointerCount; Chris@64: Chris@64: template Chris@64: using BitsPerElementN = decltype(BitCountN() / ElementCountN()); Chris@64: template Chris@64: using BytesPerElementN = decltype(ByteCountN() / ElementCountN()); Chris@64: template Chris@64: using WordsPerElementN = decltype(WordCountN() / ElementCountN()); Chris@64: template Chris@64: using PointersPerElementN = decltype(WirePointerCountN() / ElementCountN()); Chris@64: Chris@64: using kj::ThrowOverflow; Chris@64: // YYY Chris@64: Chris@64: template inline constexpr uint bounded() { return i; } Chris@64: template inline constexpr T bounded(T i) { return i; } Chris@64: template inline constexpr T unbound(T i) { return i; } Chris@64: Chris@64: template inline constexpr T unboundAs(U i) { return i; } Chris@64: Chris@64: template inline constexpr uint unboundMax(T i) { return i; } Chris@64: template inline constexpr uint unboundMaxBits(T i) { return i; } Chris@64: Chris@64: template Chris@64: inline T assertMax(T value, ErrorFunc&& func) { Chris@64: if (KJ_UNLIKELY(value > newMax)) func(); Chris@64: return value; Chris@64: } Chris@64: Chris@64: template Chris@64: inline T assertMax(uint newMax, T value, ErrorFunc&& func) { Chris@64: if (KJ_UNLIKELY(value > newMax)) func(); Chris@64: return value; Chris@64: } Chris@64: Chris@64: template Chris@64: inline T assertMaxBits(T value, ErrorFunc&& func = ErrorFunc()) { Chris@64: if (KJ_UNLIKELY(value > kj::maxValueForBits())) func(); Chris@64: return value; Chris@64: } Chris@64: Chris@64: template Chris@64: inline T assertMaxBits(uint bits, T value, ErrorFunc&& func = ErrorFunc()) { Chris@64: if (KJ_UNLIKELY(value > (1ull << bits) - 1)) func(); Chris@64: return value; Chris@64: } Chris@64: Chris@64: template inline constexpr T upgradeBound(U i) { return i; } Chris@64: Chris@64: template inline constexpr T assumeBits(T i) { return i; } Chris@64: template inline constexpr T assumeMax(T i) { return i; } Chris@64: Chris@64: template Chris@64: inline auto subtractChecked(T a, U b, ErrorFunc&& errorFunc = ErrorFunc()) Chris@64: -> decltype(a - b) { Chris@64: if (b > a) errorFunc(); Chris@64: return a - b; Chris@64: } Chris@64: Chris@64: template Chris@64: inline auto trySubtract(T a, U b) -> kj::Maybe { Chris@64: if (b > a) { Chris@64: return nullptr; Chris@64: } else { Chris@64: return a - b; Chris@64: } Chris@64: } Chris@64: Chris@64: constexpr uint BITS = 1; Chris@64: constexpr uint BYTES = 1; Chris@64: constexpr uint WORDS = 1; Chris@64: constexpr uint ELEMENTS = 1; Chris@64: constexpr uint POINTERS = 1; Chris@64: Chris@64: constexpr uint ZERO = 0; Chris@64: constexpr uint ONE = 1; Chris@64: Chris@64: // GCC 4.7 actually gives unused warnings on these constants in opt mode... Chris@64: constexpr uint BITS_PER_BYTE KJ_UNUSED = 8; Chris@64: constexpr uint BITS_PER_WORD KJ_UNUSED = 64; Chris@64: constexpr uint BYTES_PER_WORD KJ_UNUSED = 8; Chris@64: Chris@64: constexpr uint BITS_PER_POINTER KJ_UNUSED = 64; Chris@64: constexpr uint BYTES_PER_POINTER KJ_UNUSED = 8; Chris@64: constexpr uint WORDS_PER_POINTER KJ_UNUSED = 1; Chris@64: Chris@64: // XXX Chris@64: constexpr uint POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER; Chris@64: Chris@64: constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment. Chris@64: constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list. Chris@64: constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section. Chris@64: constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section. Chris@64: constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob. Chris@64: Chris@64: typedef WordCountN SegmentWordCount; Chris@64: typedef ElementCountN ListElementCount; Chris@64: typedef WordCountN StructDataWordCount; Chris@64: typedef WirePointerCountN StructPointerCount; Chris@64: typedef ByteCountN BlobSize; Chris@64: // YYY Chris@64: Chris@64: constexpr auto MAX_SEGMENT_WORDS = kj::maxValueForBits(); Chris@64: constexpr auto MAX_LIST_ELEMENTS = kj::maxValueForBits(); Chris@64: constexpr auto MAX_STUCT_DATA_WORDS = kj::maxValueForBits(); Chris@64: constexpr auto MAX_STRUCT_POINTER_COUNT = kj::maxValueForBits(); Chris@64: Chris@64: typedef uint StructDataBitCount; Chris@64: typedef uint StructDataOffset; Chris@64: typedef uint StructPointerOffset; Chris@64: Chris@64: inline StructDataOffset assumeDataOffset(uint32_t offset) { return offset; } Chris@64: inline StructPointerOffset assumePointerOffset(uint32_t offset) { return offset; } Chris@64: Chris@64: constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits() - 1; Chris@64: typedef uint TextSize; Chris@64: Chris@64: template Chris@64: inline KJ_CONSTEXPR() size_t bytesPerElement() { return sizeof(T); } Chris@64: Chris@64: template Chris@64: inline KJ_CONSTEXPR() size_t bitsPerElement() { return sizeof(T) * 8; } Chris@64: Chris@64: template Chris@64: inline constexpr ptrdiff_t intervalLength(const T* a, const T* b, uint) { Chris@64: return b - a; Chris@64: } Chris@64: Chris@64: template Chris@64: inline constexpr kj::ArrayPtr arrayPtr(const U* ptr, T size) { Chris@64: return kj::arrayPtr(ptr, size); Chris@64: } Chris@64: template Chris@64: inline constexpr kj::ArrayPtr arrayPtr(U* ptr, T size) { Chris@64: return kj::arrayPtr(ptr, size); Chris@64: } Chris@64: Chris@64: #endif Chris@64: Chris@64: } // namespace capnp Chris@64: Chris@64: #endif // CAPNP_COMMON_H_