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