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