From ae02cff81d21137980065b8fcef0ef636e4e88a0 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 23 Jun 2023 22:28:31 +0200 Subject: [PATCH] Fix annotations; progress on integers --- implementations/cpp/main.cpp | 36 +++- .../cpp/preserves_binary_reader.hpp | 26 ++- .../cpp/preserves_binary_writer.hpp | 197 ++++++++++-------- implementations/cpp/preserves_impl.hpp | 9 +- 4 files changed, 163 insertions(+), 105 deletions(-) diff --git a/implementations/cpp/main.cpp b/implementations/cpp/main.cpp index c06f028..cea80e0 100644 --- a/implementations/cpp/main.cpp +++ b/implementations/cpp/main.cpp @@ -1,6 +1,7 @@ #include "preserves.hpp" #include +#include #include "googletest/gtest/gtest.h" @@ -22,10 +23,43 @@ TEST(Value, Basics) { ASSERT_EQ(ValueKind::String, vs[2].value_kind()); } +TEST(BinaryReader, Negative257) { + istringstream input("\xA1\xFE\xFF"); + auto v = BinaryReader<>(input).next(); + ASSERT_TRUE(v); + ASSERT_EQ(v->to_signed(), -257); +} + +TEST(BinaryReader, Negative127) { + istringstream input("\xA0\x81"); + auto v = BinaryReader<>(input).next(); + ASSERT_TRUE(v); + ASSERT_EQ(v->to_signed(), -127); +} + +TEST(BinaryWriter, Negative257) { + ostringstream s; + BinaryWriter w(s); + w << -257; + std::string output(s.str()); + ASSERT_EQ(output[0], char(BinaryTag::MediumInteger_lo) + 1); + ASSERT_EQ(output[1], char(0xFE)); + ASSERT_EQ(output[2], char(0xFF)); +} + +TEST(BinaryWriter, Negative127) { + ostringstream s; + BinaryWriter w(s); + w << -127; + std::string output(s.str()); + ASSERT_EQ(output[0], char(BinaryTag::MediumInteger_lo)); + ASSERT_EQ(output[1], char(0x81)); +} + TEST(BinaryReader, ReadSamples) { ifstream f("../../tests/samples.bin", ios::binary); BinaryReader<> r(f, &GenericEmbedded::wrap); auto v = r.next(); ASSERT_TRUE(v); - BinaryWriter(cerr) << *v; + // BinaryWriter(cerr) << *v; } \ No newline at end of file diff --git a/implementations/cpp/preserves_binary_reader.hpp b/implementations/cpp/preserves_binary_reader.hpp index 1bbc853..4176e2c 100644 --- a/implementations/cpp/preserves_binary_reader.hpp +++ b/implementations/cpp/preserves_binary_reader.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace Preserves { template @@ -31,6 +32,10 @@ namespace Preserves { return boost::none; } + BinaryReader(typename std::enable_if::value, std::istream&>::type i) : + BinaryReader(i, &GenericEmbedded::wrap) + {} + BinaryReader(std::istream& i, std::function(Value<>)> decodeEmbedded) : i(i), decodeEmbedded(decodeEmbedded) @@ -89,14 +94,21 @@ namespace Preserves { case BinaryTag::Float: return next_float().map(Value::from_float); case BinaryTag::Double: return next_double().map(Value::from_double); case BinaryTag::End: end_sentinel = true; return boost::none; - case BinaryTag::Annotation: return next().flat_map([&](Value const& ann) -> boost::optional> { - return next().flat_map([&](Value const& v) -> boost::optional> { - return v.annotate(ann); - }); - }); + case BinaryTag::Annotation: { + std::vector> annotations; + while (true) { + auto ann = next(); + if (!ann) return boost::none; + annotations.push_back(*ann); + if (BinaryTag(i.peek()) != BinaryTag::Annotation) break; + i.get(); + } + auto underlying = next(); + if (!underlying) return boost::none; + return Value(new AnnotatedValue(std::move(annotations), *underlying)); + } case BinaryTag::Embedded: - return BinaryReader(i, &GenericEmbedded::wrap) - .next().map(decodeEmbedded).map(Value::from_embedded); + return BinaryReader<>(i).next().map(decodeEmbedded).map(Value::from_embedded); case BinaryTag::SmallInteger_lo ... BinaryTag::SmallInteger_hi: { int64_t n = int64_t(tag) - int64_t(BinaryTag::SmallInteger_lo); return Value::from_int(n <= 12 ? n : n - 16); diff --git a/implementations/cpp/preserves_binary_writer.hpp b/implementations/cpp/preserves_binary_writer.hpp index f8a399e..6feb4a4 100644 --- a/implementations/cpp/preserves_binary_writer.hpp +++ b/implementations/cpp/preserves_binary_writer.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace Preserves { enum class BinaryTag { @@ -28,9 +30,32 @@ namespace Preserves { Dictionary = 0xb7, }; + template + int _shift_for(uint64_t u) { + int shift = 56; + while (true) { + if (shift == 0) break; + if (((u >> shift) & 0xff) != wholeTest) break; + shift -= 8; + if (((u >> shift) & 0x80) != bitTest) { + shift += 8; + break; + } + } + return shift; + } + class BinaryWriter { std::ostream& o; + template + struct _iterable { + Collection const& c; + }; + + template + _iterable iterable(Collection const& c) { return _iterable{c}; } + public: BinaryWriter(std::ostream& o) : o(o) {} @@ -134,23 +159,98 @@ namespace Preserves { } template - BinaryWriter& operator<<(Collection const& c) { - return writeseq(c.begin(), c.end()); + BinaryWriter& operator<<(_iterable const& c) { + return writeseq(c.c.begin(), c.c.end()); + } + + BinaryWriter& operator<<(bool b) { + return (*this) << (b ? BinaryTag::True : BinaryTag::False); + } + + BinaryWriter& operator<<(float f) { + uint32_t n; + memcpy(&n, &f, sizeof(f)); + uint8_t buf[4]; + buf[0] = (n >> 24) & 0xff; + buf[1] = (n >> 16) & 0xff; + buf[2] = (n >> 8) & 0xff; + buf[3] = (n) & 0xff; + (*this) << BinaryTag::Float; + return write(buf, sizeof(buf)); + } + + BinaryWriter& operator<<(double d) { + uint64_t n; + memcpy(&n, &d, sizeof(d)); + uint8_t buf[8]; + buf[0] = (n >> 56) & 0xff; + buf[1] = (n >> 48) & 0xff; + buf[2] = (n >> 40) & 0xff; + buf[3] = (n >> 32) & 0xff; + buf[4] = (n >> 24) & 0xff; + buf[5] = (n >> 16) & 0xff; + buf[6] = (n >> 8) & 0xff; + buf[7] = (n) & 0xff; + (*this) << BinaryTag::Double; + return write(buf, sizeof(buf)); + } + + BinaryWriter& _put_medium_int(uint64_t u, int shift, int extra) { + put(uint8_t(int(BinaryTag::MediumInteger_lo) + (shift >> 3) + extra)); + if (extra) put(0); + while (shift >= 0) { + put(uint8_t((u >> shift) & 0xff)); + shift -= 8; + } + return *this; + } + + template + typename std::enable_if::value, BinaryWriter&>::type operator<<(T t) { + if (std::numeric_limits::is_signed) { + auto i = static_cast(t); + if (i < 0) { + if (i >= -3) { + return put(uint8_t(int(BinaryTag::SmallInteger_lo) + 16 + i)); + } else { + uint64_t u; + memcpy(&u, &i, sizeof(i)); + return _put_medium_int(u, _shift_for<0xff, 0x80>(u), 0); + } + } else { + if (i <= 12) { + return put(uint8_t(int(BinaryTag::SmallInteger_lo) + i)); + } else { + uint64_t u; + memcpy(&u, &i, sizeof(i)); + return _put_medium_int(u, _shift_for<0x00, 0x00>(u), 0); + } + } + } else { + auto u = static_cast(t); + if (u <= 12) { + return put(uint8_t(int(BinaryTag::SmallInteger_lo) + u)); + } else if ((u & 0x8000000000000000) != 0) { + return _put_medium_int(u, 56, 1); + } else { + return _put_medium_int(u, _shift_for<0x00, 0x00>(u), 0); + } + } } template BinaryWriter& record(Value const& label, std::vector> const& fields) { - return (*this) << BinaryTag::Record << label << fields << BinaryTag::End; + return (*this) << BinaryTag::Record << label << iterable(fields) << BinaryTag::End; } template BinaryWriter& sequence(std::vector> const& vs) { - return (*this) << BinaryTag::Sequence << vs << BinaryTag::End; + return (*this) << BinaryTag::Sequence << iterable(vs) << BinaryTag::End; } template BinaryWriter& set(std::set> const& vs) { - return (*this) << BinaryTag::Set << vs << BinaryTag::End; + return (*this) << BinaryTag::Set << iterable(vs) << BinaryTag::End; } template @@ -160,91 +260,4 @@ namespace Preserves { return (*this) << BinaryTag::End; } }; - - inline BinaryWriter& operator<<(BinaryWriter& w, bool b) { - return w << (b ? BinaryTag::True : BinaryTag::False); - } - - inline BinaryWriter& operator<<(BinaryWriter& w, float f) { - uint32_t n; - memcpy(&n, &f, sizeof(f)); - uint8_t buf[4]; - buf[0] = (n >> 24) & 0xff; - buf[1] = (n >> 16) & 0xff; - buf[2] = (n >> 8) & 0xff; - buf[3] = (n) & 0xff; - w << BinaryTag::Float; - return w.write(buf, sizeof(buf)); - } - - inline BinaryWriter& operator<<(BinaryWriter& w, double d) { - uint64_t n; - memcpy(&n, &d, sizeof(d)); - uint8_t buf[8]; - buf[0] = (n >> 56) & 0xff; - buf[1] = (n >> 48) & 0xff; - buf[2] = (n >> 40) & 0xff; - buf[3] = (n >> 32) & 0xff; - buf[4] = (n >> 24) & 0xff; - buf[5] = (n >> 16) & 0xff; - buf[6] = (n >> 8) & 0xff; - buf[7] = (n) & 0xff; - w << BinaryTag::Double; - return w.write(buf, sizeof(buf)); - } - - template - int _shift_for(uint64_t u) { - int shift = 56; - while (true) { - if (shift == 0) break; - if (((u >> shift) & 0xff) != wholeTest) break; - shift -= 8; - if (((u >> shift) & 0x80) != bitTest) { - shift += 8; - break; - } - } - return shift; - } - - inline BinaryWriter& _put_medium_int(BinaryWriter& w, uint64_t u, int shift, int extra) { - w.put(uint8_t(int(BinaryTag::MediumInteger_lo) + (shift >> 3) + extra)); - if (extra) w.put(0); - while (shift >= 0) { - w.put(uint8_t((u >> shift) & 0xff)); - shift -= 8; - } - return w; - } - - inline BinaryWriter& operator<<(BinaryWriter& w, int64_t i) { - if (i < 0) { - if (i >= -3) { - return w.put(uint8_t(int(BinaryTag::SmallInteger_lo) + 16 + i)); - } else { - uint64_t u; - memcpy(&u, &i, sizeof(i)); - return _put_medium_int(w, u, _shift_for<0xff, 0x80>(u), 0); - } - } else { - if (i <= 12) { - return w.put(uint8_t(int(BinaryTag::SmallInteger_lo) + i)); - } else { - uint64_t u; - memcpy(&u, &i, sizeof(i)); - return _put_medium_int(w, u, _shift_for<0x00, 0x00>(u), 0); - } - } - } - - inline BinaryWriter& operator<<(BinaryWriter& w, uint64_t u) { - if (u <= 12) { - return w.put(uint8_t(int(BinaryTag::SmallInteger_lo) + u)); - } else if ((u & 0x8000000000000000) != 0) { - return _put_medium_int(w, u, 56, 1); - } else { - return _put_medium_int(w, u, _shift_for<0x00, 0x00>(u), 0); - } - } } diff --git a/implementations/cpp/preserves_impl.hpp b/implementations/cpp/preserves_impl.hpp index 3c26653..ee50d5d 100644 --- a/implementations/cpp/preserves_impl.hpp +++ b/implementations/cpp/preserves_impl.hpp @@ -271,8 +271,8 @@ namespace Preserves { template class AnnotatedValue: public ValueImpl { - Value underlying; std::vector> anns; + Value underlying; friend class ValueImpl; @@ -282,15 +282,14 @@ namespace Preserves { anns.push_back(ann); return self; } else { - auto a = std::make_shared>(underlying); - a->anns.insert(a->anns.end(), anns.begin(), anns.end()); + auto a = std::make_shared>(std::vector>(anns), underlying); a->anns.push_back(ann); return Value(a); } } public: - AnnotatedValue(Value const& v) : underlying(v) {} + AnnotatedValue(std::vector> &&anns, Value const& v) : anns(anns), underlying(v) {} ValueKind value_kind() const override { return underlying.value_kind(); } bool is_mutable() const override { return underlying.is_mutable(); } @@ -346,7 +345,7 @@ namespace Preserves { template Value ValueImpl::internal_annotate(std::shared_ptr> const& self, Value const &ann) { - auto a = std::make_shared>(Value(self)); + auto a = std::make_shared>(std::vector>(), Value(self)); a->anns.push_back(ann); return Value(a); }