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