diff --git a/c++/src/capnproto/encoding-test.c++ b/c++/src/capnproto/encoding-test.c++ index 80aa71a056caa6098672cb07e821dba336f865d3..a1638a2462d05ba033884c3ebd8195336b2b097b 100644 --- a/c++/src/capnproto/encoding-test.c++ +++ b/c++/src/capnproto/encoding-test.c++ @@ -39,27 +39,107 @@ TEST(Encoding, Simple) { EXPECT_EQ(1234, builder.getA()); EXPECT_EQ(-1, builder.getB()); EXPECT_EQ(200, builder.getC()); - ASSERT_EQ(0, builder.getNums().size()); + ASSERT_EQ(0u, builder.getNums().size()); builder.setA(321); builder.setB(45); builder.setC(67); builder.initD().setX(55.25); - List<int32_t>::Builder listBuilder = builder.initNums(5); - ASSERT_EQ(5, listBuilder.size()); - listBuilder[0] = 12; - listBuilder[1] = 34; - listBuilder[2] = 56; - listBuilder[3] = 78; - listBuilder[4] = 90; + { + List<int32_t>::Builder listBuilder = builder.initNums(5); + ASSERT_EQ(5u, listBuilder.size()); + listBuilder.set(0, 12); + listBuilder.set(1, 34); + listBuilder.set(2, 56); + listBuilder.set(3, 78); + listBuilder.set(4, 90); + + EXPECT_EQ(12, listBuilder[0]); + EXPECT_EQ(34, listBuilder[1]); + EXPECT_EQ(56, listBuilder[2]); + EXPECT_EQ(78, listBuilder[3]); + EXPECT_EQ(90, listBuilder[4]); + + { + int sum = 0; + for (int32_t i: listBuilder) { + sum += i; + } + EXPECT_EQ(12 + 34 + 56 + 78 + 90, sum); + } + } + + { + List<Bar>::Builder structListBuilder = builder.initBars(3); + ASSERT_EQ(3u, structListBuilder.size()); + + structListBuilder[0].setX(123); + structListBuilder[1].setX(456); + structListBuilder[2].setX(789); + + EXPECT_EQ(123, structListBuilder[0].getX()); + EXPECT_EQ(456, structListBuilder[1].getX()); + EXPECT_EQ(789, structListBuilder[2].getX()); + + { + double sum = 0; + for (auto bar: structListBuilder) { + sum += bar.getX(); + } + EXPECT_EQ(123 + 456 + 789, sum); + } + } { - int sum = 0; - for (int32_t i: listBuilder) { - sum += i; + List<Bar>::Builder structListBuilder = builder.getBars(); + ASSERT_EQ(3u, structListBuilder.size()); + + EXPECT_EQ(123, structListBuilder[0].getX()); + EXPECT_EQ(456, structListBuilder[1].getX()); + EXPECT_EQ(789, structListBuilder[2].getX()); + + { + double sum = 0; + for (auto bar: structListBuilder) { + sum += bar.getX(); + } + EXPECT_EQ(123 + 456 + 789, sum); } - EXPECT_EQ(12 + 34 + 56 + 78 + 90, sum); + } + + { + List<List<int32_t>>::Builder listListBuilder = builder.initPrimListList(2); + ASSERT_EQ(2u, listListBuilder.size()); + + List<int32_t>::Builder sublist = listListBuilder.init(0, 2); + ASSERT_EQ(2u, sublist.size()); + sublist.set(0, 1234); + sublist.set(1, 5678); + + sublist = listListBuilder.init(1, 4); + ASSERT_EQ(4u, sublist.size()); + sublist.set(0, 21); + sublist.set(1, 43); + sublist.set(2, 65); + sublist.set(3, 87); + } + + { + List<List<Bar>>::Builder listListBuilder = builder.initStructListList(2); + ASSERT_EQ(2u, listListBuilder.size()); + + List<Bar>::Builder sublist = listListBuilder.init(0, 2); + ASSERT_EQ(2u, sublist.size()); + sublist[0].setX(1234); + sublist[1].setX(5678); + + sublist = listListBuilder.init(1, 4); + ASSERT_EQ(4u, sublist.size()); + sublist[0].setX(21); + sublist[1].setX(43); + sublist[2].setX(65); + sublist[3].setX(87); } EXPECT_EQ(321, builder.getA()); @@ -75,20 +155,73 @@ TEST(Encoding, Simple) { EXPECT_EQ(67, reader.getC()); EXPECT_EQ(55.25, reader.getD().getX()); - List<int32_t>::Reader listReader = reader.getNums(); - ASSERT_EQ(5, listReader.size()); - EXPECT_EQ(12, listReader[0]); - EXPECT_EQ(34, listReader[1]); - EXPECT_EQ(56, listReader[2]); - EXPECT_EQ(78, listReader[3]); - EXPECT_EQ(90, listReader[4]); + { + List<int32_t>::Reader listReader = reader.getNums(); + ASSERT_EQ(5u, listReader.size()); + EXPECT_EQ(12, listReader[0]); + EXPECT_EQ(34, listReader[1]); + EXPECT_EQ(56, listReader[2]); + EXPECT_EQ(78, listReader[3]); + EXPECT_EQ(90, listReader[4]); + + { + int sum = 0; + for (int32_t i: listReader) { + sum += i; + } + EXPECT_EQ(12 + 34 + 56 + 78 + 90, sum); + } + } { - int sum = 0; - for (int32_t i: listReader) { - sum += i; + List<Bar>::Reader structListReader = reader.getBars(); + ASSERT_EQ(3u, structListReader.size()); + + EXPECT_EQ(123, structListReader[0].getX()); + EXPECT_EQ(456, structListReader[1].getX()); + EXPECT_EQ(789, structListReader[2].getX()); + + { + double sum = 0; + for (auto bar: structListReader) { + sum += bar.getX(); + } + EXPECT_EQ(123 + 456 + 789, sum); } - EXPECT_EQ(12 + 34 + 56 + 78 + 90, sum); + } + + { + List<List<int32_t>>::Reader listListReader = reader.getPrimListList(); + ASSERT_EQ(2u, listListReader.size()); + + List<int32_t>::Reader sublist = listListReader[0]; + ASSERT_EQ(2u, sublist.size()); + EXPECT_EQ(1234, sublist[0]); + EXPECT_EQ(5678, sublist[1]); + + sublist = listListReader[1]; + ASSERT_EQ(4u, sublist.size()); + EXPECT_EQ(21, sublist[0]); + EXPECT_EQ(43, sublist[1]); + EXPECT_EQ(65, sublist[2]); + EXPECT_EQ(87, sublist[3]); + } + + { + List<List<Bar>>::Reader listListReader = reader.getStructListList(); + ASSERT_EQ(2u, listListReader.size()); + + List<Bar>::Reader sublist = listListReader[0]; + ASSERT_EQ(2u, sublist.size()); + EXPECT_EQ(1234, sublist[0].getX()); + EXPECT_EQ(5678, sublist[1].getX()); + + sublist = listListReader[1]; + ASSERT_EQ(4u, sublist.size()); + EXPECT_EQ(21, sublist[0].getX()); + EXPECT_EQ(43, sublist[1].getX()); + EXPECT_EQ(65, sublist[2].getX()); + EXPECT_EQ(87, sublist[3].getX()); } } diff --git a/c++/src/capnproto/list.h b/c++/src/capnproto/list.h index 0c2df00e51c263bedebe2f2ef00b84f9931ee0a3..1264a8e46c12e1dfc129dd4992f35c4854276ec8 100644 --- a/c++/src/capnproto/list.h +++ b/c++/src/capnproto/list.h @@ -25,9 +25,17 @@ #define CAPNPROTO_LIST_H_ #include "wire-format.h" +#include "descriptor.h" // only for FieldSize; TODO: Eliminate this namespace capnproto { +namespace internal { +template <typename T> struct IsPrimitive; +} // namespace internal + +template <typename T, bool isPrimitive = internal::IsPrimitive<T>::value> +struct List; + namespace internal { template <typename T> struct IsPrimitive { static constexpr bool value = false; }; @@ -44,6 +52,27 @@ template <> struct IsPrimitive<uint32_t> { static constexpr bool value = true; } template <> struct IsPrimitive<uint64_t> { static constexpr bool value = true; }; template <> struct IsPrimitive<float> { static constexpr bool value = true; }; template <> struct IsPrimitive<double> { static constexpr bool value = true; }; +template <typename T, bool b> struct IsPrimitive<List<T, b>> { + static constexpr bool value = IsPrimitive<T>::value; +}; + +template <typename T> struct FieldSizeForType { static constexpr FieldSize value = FieldSize::INLINE_COMPOSITE; }; + +template <> struct FieldSizeForType<void> { static constexpr FieldSize value = FieldSize::VOID; }; +template <> struct FieldSizeForType<bool> { static constexpr FieldSize value = FieldSize::BIT; }; +template <> struct FieldSizeForType<int8_t> { static constexpr FieldSize value = FieldSize::BYTE; }; +template <> struct FieldSizeForType<int16_t> { static constexpr FieldSize value = FieldSize::TWO_BYTES; }; +template <> struct FieldSizeForType<int32_t> { static constexpr FieldSize value = FieldSize::FOUR_BYTES; }; +template <> struct FieldSizeForType<int64_t> { static constexpr FieldSize value = FieldSize::EIGHT_BYTES; }; +template <> struct FieldSizeForType<uint8_t> { static constexpr FieldSize value = FieldSize::BYTE; }; +template <> struct FieldSizeForType<uint16_t> { static constexpr FieldSize value = FieldSize::TWO_BYTES; }; +template <> struct FieldSizeForType<uint32_t> { static constexpr FieldSize value = FieldSize::FOUR_BYTES; }; +template <> struct FieldSizeForType<uint64_t> { static constexpr FieldSize value = FieldSize::EIGHT_BYTES; }; +template <> struct FieldSizeForType<float> { static constexpr FieldSize value = FieldSize::FOUR_BYTES; }; +template <> struct FieldSizeForType<double> { static constexpr FieldSize value = FieldSize::EIGHT_BYTES; }; +template <typename T, bool b> struct FieldSizeForType<List<T, b>> { + static constexpr FieldSize value = FieldSize::REFERENCE; +}; template<typename T> constexpr T&& move(T& t) noexcept { return static_cast<T&&>(t); } // Like std::move. Unfortunately, #including <utility> brings in tons of unnecessary stuff. @@ -64,15 +93,17 @@ private: T value; }; -template <typename Container, typename Element, typename Reference> +template <typename Container, typename Element> class IndexingIterator { public: IndexingIterator() = default; - inline Reference operator*() { return (*container)[index]; } - inline Reference operator->() { return TemporaryPointer<Element>((*container)[index]); } - inline Reference operator[]( int off) { return (*container)[index]; } - inline Reference operator[](uint off) { return (*container)[index]; } + inline Element operator*() { return (*container)[index]; } + inline TemporaryPointer<Element> operator->() { + return TemporaryPointer<Element>((*container)[index]); + } + inline Element operator[]( int off) { return (*container)[index]; } + inline Element operator[](uint off) { return (*container)[index]; } inline IndexingIterator& operator++() { ++index; return *this; } inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; } @@ -105,14 +136,11 @@ private: uint index; friend Container; - IndexingIterator(Container* builder, uint index): container(container), index(index) {} + inline IndexingIterator(Container* container, uint index): container(container), index(index) {} }; } // namespace internal -template <typename T, bool isPrimitive = internal::IsPrimitive<T>::value> -struct List; - template <typename T> struct List<T, true> { class Reader { @@ -120,11 +148,10 @@ struct List<T, true> { Reader() = default; inline explicit Reader(internal::ListReader reader): reader(reader) {} - typedef internal::IndexingIterator<Reader, T, T> iterator; - - inline T operator[](uint index) { return reader.template getDataElement<T>(index * ELEMENTS); } inline uint size() { return reader.size() / ELEMENTS; } + inline T operator[](uint index) { return reader.template getDataElement<T>(index * ELEMENTS); } + typedef internal::IndexingIterator<Reader, T> iterator; inline iterator begin() { return iterator(this, 0); } inline iterator end() { return iterator(this, size()); } @@ -137,36 +164,62 @@ struct List<T, true> { Builder() = default; inline explicit Builder(internal::ListBuilder builder): builder(builder) {} - class reference { - public: - reference() = default; + inline uint size() { return builder.size() / ELEMENTS; } + inline T operator[](uint index) { + return builder.template getDataElement<T>(index * ELEMENTS); + } + inline void set(uint index, T value) { + // Alas, it is not possible to make operator[] return a reference to which you can assign, + // since the encoded representation does not necessarily match the compiler's representation + // of the type. We can't even return a clever class that implements operator T() and + // operator=() because it will lead to surprising behavior when using type inference (e.g. + // calling a template function with inferred argument types, or using "auto" or "decltype"). + + builder.template setDataElement<T>(index * ELEMENTS, value); + } - inline operator T() { return (*builder)[index]; } - inline reference& operator=(T value) { - builder->builder.template setDataElement<T>(index * ELEMENTS, value); - return *this; - } + typedef internal::IndexingIterator<Builder, T> iterator; + inline iterator begin() { return iterator(this, 0); } + inline iterator end() { return iterator(this, size()); } - T* operator&() { - static_assert(sizeof(T) < 0, - "You can't take the address of a list member because they are not stored in memory " - "in a directly-usable format."); - return nullptr; - } + private: + internal::ListBuilder builder; + }; +}; + +template <typename T> +struct List<T, false> { + class Reader { + public: + Reader() = default; + inline explicit Reader(internal::ListReader reader): reader(reader) {} + + inline uint size() { return reader.size() / ELEMENTS; } + inline typename T::Reader operator[](uint index) { + return typename T::Reader(reader.getStructElement(index * ELEMENTS, T::DEFAULT.words)); + } - private: - Builder* builder; - uint index; + typedef internal::IndexingIterator<Reader, typename T::Reader> iterator; + inline iterator begin() { return iterator(this, 0); } + inline iterator end() { return iterator(this, size()); } - friend class Builder; - reference(Builder* builder, uint index): builder(builder), index(index) {} - }; + private: + internal::ListReader reader; + }; - typedef internal::IndexingIterator<Builder, T, reference> iterator; + class Builder { + public: + Builder() = default; + inline explicit Builder(internal::ListBuilder builder): builder(builder) {} - inline reference operator[](uint index) { return reference(this, index); } inline uint size() { return builder.size() / ELEMENTS; } + inline typename T::Builder operator[](uint index) { + return typename T::Builder(builder.getStructElement(index * ELEMENTS, + (T::DATA_SIZE + T::REFERENCE_COUNT * WORDS_PER_REFERENCE) / ELEMENTS, + T::DATA_SIZE)); + } + typedef internal::IndexingIterator<Builder, typename T::Builder> iterator; inline iterator begin() { return iterator(this, 0); } inline iterator end() { return iterator(this, size()); } @@ -176,19 +229,19 @@ struct List<T, true> { }; template <typename T> -struct List<T, false> { +struct List<List<T>, true> { class Reader { public: Reader() = default; inline explicit Reader(internal::ListReader reader): reader(reader) {} - typedef internal::IndexingIterator<Reader, typename T::Reader, typename T::Reader> iterator; - - inline typename T::Reader operator[](uint index) { - return typename T::Reader(reader.getStructElement(index * ELEMENTS, T::DEFAULT.words)); - } inline uint size() { return reader.size() / ELEMENTS; } + inline typename List<T>::Reader operator[](uint index) { + return typename List<T>::Reader(reader.getListElement(index * REFERENCES, + internal::FieldSizeForType<T>::value)); + } + typedef internal::IndexingIterator<Reader, typename List<T>::Reader> iterator; inline iterator begin() { return iterator(this, 0); } inline iterator end() { return iterator(this, size()); } @@ -201,38 +254,60 @@ struct List<T, false> { Builder() = default; inline explicit Builder(internal::ListBuilder builder): builder(builder) {} - class reference { - public: - reference() = default; + inline uint size() { return builder.size() / ELEMENTS; } + inline typename List<T>::Builder operator[](uint index) { + return typename List<T>::Builder(builder.getListElement(index * REFERENCES)); + } + inline typename List<T>::Builder init(uint index, uint size) { + return typename List<T>::Builder(builder.initListElement( + index * REFERENCES, internal::FieldSizeForType<T>::value, size * ELEMENTS)); + } - inline operator typename T::Builder() { return (*builder)[index]; } + typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator; + inline iterator begin() { return iterator(this, 0); } + inline iterator end() { return iterator(this, size()); } - // TODO: operator= to accept ownership transfer. + private: + internal::ListBuilder builder; + }; +}; + +template <typename T> +struct List<List<T>, false> { + class Reader { + public: + Reader() = default; + inline explicit Reader(internal::ListReader reader): reader(reader) {} - T* operator&() { - static_assert(sizeof(T) < 0, - "You can't take the address of a list member because they are not stored in memory " - "in a directly-usable format."); - return nullptr; - } + inline uint size() { return reader.size() / ELEMENTS; } + inline typename List<T>::Reader operator[](uint index) { + return typename List<T>::Reader(reader.getListElement(index * REFERENCES, + internal::FieldSizeForType<T>::value)); + } - private: - Builder* builder; - uint index; + typedef internal::IndexingIterator<Reader, typename List<T>::Reader> iterator; + inline iterator begin() { return iterator(this, 0); } + inline iterator end() { return iterator(this, size()); } - friend class Builder; - reference(Builder* builder, uint index): builder(builder), index(index) {} - }; + private: + internal::ListReader reader; + }; - typedef internal::IndexingIterator<Builder, typename T::Builder, reference> iterator; + class Builder { + public: + Builder() = default; + inline explicit Builder(internal::ListBuilder builder): builder(builder) {} - inline typename T::Builder operator[](uint index) { - return typename T::Builder(builder.getStructElement(index * ELEMENTS, - (T::DATA_SIZE + T::REFERENCE_COUNT * WORDS_PER_REFERENCE) / ELEMENTS, - T::DATA_SIZE)); - } inline uint size() { return builder.size() / ELEMENTS; } + inline typename List<T>::Builder operator[](uint index) { + return typename List<T>::Builder(builder.getListElement(index * REFERENCES)); + } + inline typename List<T>::Builder init(uint index, uint size) { + return typename List<T>::Builder(builder.initStructListElement( + index * REFERENCES, size * ELEMENTS, T::DEFAULT.words)); + } + typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator; inline iterator begin() { return iterator(this, 0); } inline iterator end() { return iterator(this, size()); } diff --git a/c++/src/capnproto/wire-format-test.c++ b/c++/src/capnproto/wire-format-test.c++ index 0c6686fec52749e9a3a89d864f77a54d05dd2999..9b01ee72237de135e5c4ac953be6a01bc2497da4 100644 --- a/c++/src/capnproto/wire-format-test.c++ +++ b/c++/src/capnproto/wire-format-test.c++ @@ -200,7 +200,7 @@ static void checkStruct(StructBuilder builder) { ListBuilder list = builder.getListField(3 * REFERENCES, nullptr); ASSERT_EQ(5 * ELEMENTS, list.size()); for (uint i = 0; i < 5; i++) { - ListBuilder element = list.getListElement(i * REFERENCES, FieldSize::TWO_BYTES); + ListBuilder element = list.getListElement(i * REFERENCES); ASSERT_EQ((i + 1) * ELEMENTS, element.size()); for (uint j = 0; j <= i; j++) { EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS)); @@ -253,7 +253,7 @@ static void checkStruct(StructReader reader) { ListReader list = reader.getListField(3 * REFERENCES, FieldSize::REFERENCE, nullptr); ASSERT_EQ(5 * ELEMENTS, list.size()); for (uint i = 0; i < 5; i++) { - ListReader element = list.getListElement(i * REFERENCES, FieldSize::TWO_BYTES, nullptr); + ListReader element = list.getListElement(i * REFERENCES, FieldSize::TWO_BYTES); ASSERT_EQ((i + 1) * ELEMENTS, element.size()); for (uint j = 0; j <= i; j++) { EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS)); diff --git a/c++/src/capnproto/wire-format.c++ b/c++/src/capnproto/wire-format.c++ index 033bb3cbf851f1043568e08a3c206e0120e29f7a..ee549abfdc3a5306a1de4477ba627ebf99ec1e52 100644 --- a/c++/src/capnproto/wire-format.c++ +++ b/c++/src/capnproto/wire-format.c++ @@ -863,7 +863,7 @@ ListBuilder ListBuilder::initStructListElement( elementCount, elementDefaultValue); } -ListBuilder ListBuilder::getListElement(WireReferenceCount index, FieldSize elementSize) const { +ListBuilder ListBuilder::getListElement(WireReferenceCount index) const { return WireHelpers::getWritableListReference( reinterpret_cast<WireReference*>(ptr) + index, segment, nullptr); } @@ -900,10 +900,10 @@ StructReader ListReader::getStructElement(ElementCount index, const word* defaul } ListReader ListReader::getListElement( - WireReferenceCount index, FieldSize expectedElementSize, const word* defaultValue) const { + WireReferenceCount index, FieldSize expectedElementSize) const { return WireHelpers::readListReference( segment, reinterpret_cast<const WireReference*>(ptr) + index, - defaultValue, expectedElementSize, recursionLimit); + nullptr, expectedElementSize, recursionLimit); } } // namespace internal diff --git a/c++/src/capnproto/wire-format.h b/c++/src/capnproto/wire-format.h index e20463634fcee9a9079d31ecca9284b151eb505c..5cd80fb35f3b63929f10b7f46a062afa46c8c792 100644 --- a/c++/src/capnproto/wire-format.h +++ b/c++/src/capnproto/wire-format.h @@ -240,7 +240,7 @@ public: // elementDefaultValue. As with StructBuilder::initStructListElement(), this should be the // default value for the *type*, with all-null references. - ListBuilder getListElement(WireReferenceCount index, FieldSize elementSize) const; + ListBuilder getListElement(WireReferenceCount index) const; // Get the existing list element at the given index. Returns an empty list if the element is // not initialized. @@ -280,8 +280,7 @@ public: StructReader getStructElement(ElementCount index, const word* defaultValue) const; // Get the struct element at the given index. - ListReader getListElement(WireReferenceCount index, FieldSize expectedElementSize, - const word* defaultValue) const; + ListReader getListElement(WireReferenceCount index, FieldSize expectedElementSize) const; // Get the list element at the given index. private: diff --git a/compiler/src/CxxGenerator.hs b/compiler/src/CxxGenerator.hs index 903854f2e995f0951297e7ad3e21b7f515ac19e9..64e7970557052cabae15e1f3497916d73770e668 100644 --- a/compiler/src/CxxGenerator.hs +++ b/compiler/src/CxxGenerator.hs @@ -61,30 +61,30 @@ isStruct _ = False isList (ListType _) = True isList _ = False -isPrimitiveList (ListType t) = isPrimitive t -isPrimitiveList _ = False +isNonStructList (ListType t) = not $ isStruct t +isNonStructList _ = False isStructList (ListType t) = isStruct t isStructList _ = False cxxTypeString (BuiltinType BuiltinVoid) = "void" cxxTypeString (BuiltinType BuiltinBool) = "bool" -cxxTypeString (BuiltinType BuiltinInt8) = "int8_t" -cxxTypeString (BuiltinType BuiltinInt16) = "int16_t" -cxxTypeString (BuiltinType BuiltinInt32) = "int32_t" -cxxTypeString (BuiltinType BuiltinInt64) = "int64_t" -cxxTypeString (BuiltinType BuiltinUInt8) = "uint8_t" -cxxTypeString (BuiltinType BuiltinUInt16) = "uint16_t" -cxxTypeString (BuiltinType BuiltinUInt32) = "uint32_t" -cxxTypeString (BuiltinType BuiltinUInt64) = "uint64_t" +cxxTypeString (BuiltinType BuiltinInt8) = " ::int8_t" +cxxTypeString (BuiltinType BuiltinInt16) = " ::int16_t" +cxxTypeString (BuiltinType BuiltinInt32) = " ::int32_t" +cxxTypeString (BuiltinType BuiltinInt64) = " ::int64_t" +cxxTypeString (BuiltinType BuiltinUInt8) = " ::uint8_t" +cxxTypeString (BuiltinType BuiltinUInt16) = " ::uint16_t" +cxxTypeString (BuiltinType BuiltinUInt32) = " ::uint32_t" +cxxTypeString (BuiltinType BuiltinUInt64) = " ::uint64_t" cxxTypeString (BuiltinType BuiltinFloat32) = "float" cxxTypeString (BuiltinType BuiltinFloat64) = "double" cxxTypeString (BuiltinType BuiltinText) = "TODO" cxxTypeString (BuiltinType BuiltinData) = "TODO" -cxxTypeString (EnumType desc) = enumName desc -cxxTypeString (StructType desc) = structName desc -cxxTypeString (InterfaceType desc) = interfaceName desc -cxxTypeString (ListType t) = concat ["::capnproto::List<", cxxTypeString t, ">"] +cxxTypeString (EnumType desc) = enumName desc -- TODO: full name +cxxTypeString (StructType desc) = structName desc -- TODO: full name +cxxTypeString (InterfaceType desc) = interfaceName desc -- TODO: full name +cxxTypeString (ListType t) = concat [" ::capnproto::List<", cxxTypeString t, ">"] cxxFieldSizeString Size0 = "VOID"; cxxFieldSizeString Size1 = "BIT"; @@ -161,7 +161,7 @@ fieldContext parent desc = mkStrContext context where context "fieldIsPrimitive" = MuBool $ isPrimitive $ fieldType desc context "fieldIsStruct" = MuBool $ isStruct $ fieldType desc context "fieldIsList" = MuBool $ isList $ fieldType desc - context "fieldIsPrimitiveList" = MuBool $ isPrimitiveList $ fieldType desc + context "fieldIsNonStructList" = MuBool $ isNonStructList $ fieldType desc context "fieldIsStructList" = MuBool $ isStructList $ fieldType desc context "fieldDefaultBytes" = case fieldDefaultValue desc >>= defaultValueBytes (fieldType desc) of @@ -173,12 +173,16 @@ fieldContext parent desc = mkStrContext context where Just v -> MuVariable $ cxxValueString v Nothing -> MuVariable $ cxxDefaultDefault $ fieldType desc context "fieldElementSize" = - MuVariable $ cxxFieldSizeString $ fieldSize $ elementType $ fieldType desc + MuVariable $ cxxFieldSizeString $ elementSize $ elementType $ fieldType desc + context "fieldElementType" = + MuVariable $ cxxTypeString $ elementType $ fieldType desc context s = parent s structContext parent desc = mkStrContext context where context "structName" = MuVariable $ structName desc context "structFields" = MuList $ map (fieldContext context) $ structFields desc + context "structDataSize" = MuVariable $ packingDataSize $ structPacking desc + context "structReferenceCount" = MuVariable $ packingReferenceCount $ structPacking desc context "structChildren" = MuList [] -- TODO context "structDefault" = MuList [defaultBytesContext context (encodeMessage (StructType desc) (StructValueDesc []))] @@ -191,7 +195,7 @@ fileContext desc = mkStrContext context where "CAPNPROTO_INCLUDED_" ++ hashString (fileName desc) context "fileNamespaces" = MuList [] -- TODO context "fileStructs" = MuList $ map (structContext context) $ fileStructs desc - context s = MuVariable $ concat ["@@@", s, "@@@"] + context s = error ("Template variable not defined: " ++ s) headerTemplate :: String headerTemplate = ByteStringUTF8.toString $(embedFile "src/c++-header.mustache") diff --git a/compiler/src/c++-header.mustache b/compiler/src/c++-header.mustache index 4488db06aee644506765ee852896241e73371907..f17d813627f2c8ca641abc4a30d81a03ce9aa458 100644 --- a/compiler/src/c++-header.mustache +++ b/compiler/src/c++-header.mustache @@ -41,6 +41,9 @@ struct {{structName}} { struct {{structChildName}}; {{/structChildren}} + static constexpr ::capnproto::WordCount DATA_SIZE = {{structDataSize}} * ::capnproto::WORDS; + static constexpr ::capnproto::WireReferenceCount REFERENCE_COUNT = + {{structReferenceCount}} * ::capnproto::REFERENCES; {{#structDefault}} static const ::capnproto::internal::AlignedData<{{defaultWordCount}}> DEFAULT; {{/structDefault}} @@ -91,10 +94,10 @@ public: inline {{fieldType}}::Builder init{{fieldTitleCase}}(); inline {{fieldType}}::Builder get{{fieldTitleCase}}(); {{/fieldIsStruct}} -{{#fieldIsPrimitiveList}} +{{#fieldIsNonStructList}} inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size); inline {{fieldType}}::Builder get{{fieldTitleCase}}(); -{{/fieldIsPrimitiveList}} +{{/fieldIsNonStructList}} {{#fieldIsStructList}} inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size); inline {{fieldType}}::Builder get{{fieldTitleCase}}(); @@ -160,7 +163,7 @@ inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() { {{^fieldDefaultBytes}}{{fieldType}}::DEFAULT.words{{/fieldDefaultBytes}})); } {{/fieldIsStruct}} -{{#fieldIsPrimitiveList}} +{{#fieldIsNonStructList}} inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(unsigned int size) { return {{fieldType}}::Builder(_builder.initListField( {{fieldOffset}} * ::capnproto::REFERENCES, @@ -173,12 +176,12 @@ inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() { {{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}} {{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}})); } -{{/fieldIsPrimitiveList}} +{{/fieldIsNonStructList}} {{#fieldIsStructList}} inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(unsigned int size) { return {{fieldType}}::Builder(_builder.initStructListField( {{fieldOffset}} * ::capnproto::REFERENCES, size * ::capnproto::ELEMENTS, - {{fieldType}}::DEFAULT.words)); + {{fieldElementType}}::DEFAULT.words)); } inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() { return {{fieldType}}::Builder(_builder.getListField( diff --git a/compiler/src/c++-source.mustache b/compiler/src/c++-source.mustache index ebb9a851edadb1b8f1a4379fe9285e92caf4ec9f..ca0c85bf7f20d69e6aba040ea53bd43e06aea9d1 100644 --- a/compiler/src/c++-source.mustache +++ b/compiler/src/c++-source.mustache @@ -32,6 +32,8 @@ namespace {{namespaceName}} { {{/fileNamespaces}} {{#fileStructs}} +constexpr ::capnproto::WordCount {{structName}}::DATA_SIZE; +constexpr ::capnproto::WireReferenceCount {{structName}}::REFERENCE_COUNT; {{#structDefault}} const ::capnproto::internal::AlignedData<{{defaultWordCount}}> {{structName}}::DEFAULT = { { {{defaultByteList}} }