Fix annotations; progress on integers
This commit is contained in:
parent
3c76819687
commit
ae02cff81d
|
@ -1,6 +1,7 @@
|
|||
#include "preserves.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Preserves {
|
||||
template <typename T = class GenericEmbedded>
|
||||
|
@ -31,6 +32,10 @@ namespace Preserves {
|
|||
return boost::none;
|
||||
}
|
||||
|
||||
BinaryReader(typename std::enable_if<std::is_same<T, GenericEmbedded>::value, std::istream&>::type i) :
|
||||
BinaryReader(i, &GenericEmbedded::wrap)
|
||||
{}
|
||||
|
||||
BinaryReader(std::istream& i, std::function<std::shared_ptr<T>(Value<>)> decodeEmbedded) :
|
||||
i(i),
|
||||
decodeEmbedded(decodeEmbedded)
|
||||
|
@ -89,14 +94,21 @@ namespace Preserves {
|
|||
case BinaryTag::Float: return next_float().map(Value<T>::from_float);
|
||||
case BinaryTag::Double: return next_double().map(Value<T>::from_double);
|
||||
case BinaryTag::End: end_sentinel = true; return boost::none;
|
||||
case BinaryTag::Annotation: return next().flat_map([&](Value<T> const& ann) -> boost::optional<Value<T>> {
|
||||
return next().flat_map([&](Value<T> const& v) -> boost::optional<Value<T>> {
|
||||
return v.annotate(ann);
|
||||
});
|
||||
});
|
||||
case BinaryTag::Annotation: {
|
||||
std::vector<Value<T>> 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<T>(new AnnotatedValue<T>(std::move(annotations), *underlying));
|
||||
}
|
||||
case BinaryTag::Embedded:
|
||||
return BinaryReader<GenericEmbedded>(i, &GenericEmbedded::wrap)
|
||||
.next().map(decodeEmbedded).map(Value<T>::from_embedded);
|
||||
return BinaryReader<>(i).next().map(decodeEmbedded).map(Value<T>::from_embedded);
|
||||
case BinaryTag::SmallInteger_lo ... BinaryTag::SmallInteger_hi: {
|
||||
int64_t n = int64_t(tag) - int64_t(BinaryTag::SmallInteger_lo);
|
||||
return Value<T>::from_int(n <= 12 ? n : n - 16);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
namespace Preserves {
|
||||
enum class BinaryTag {
|
||||
|
@ -28,9 +30,32 @@ namespace Preserves {
|
|||
Dictionary = 0xb7,
|
||||
};
|
||||
|
||||
template <uint64_t wholeTest, uint64_t bitTest>
|
||||
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 <typename Collection>
|
||||
struct _iterable {
|
||||
Collection const& c;
|
||||
};
|
||||
|
||||
template <typename Collection>
|
||||
_iterable<Collection> iterable(Collection const& c) { return _iterable<Collection>{c}; }
|
||||
|
||||
public:
|
||||
BinaryWriter(std::ostream& o) : o(o) {}
|
||||
|
||||
|
@ -134,23 +159,98 @@ namespace Preserves {
|
|||
}
|
||||
|
||||
template <typename Collection>
|
||||
BinaryWriter& operator<<(Collection const& c) {
|
||||
return writeseq(c.begin(), c.end());
|
||||
BinaryWriter& operator<<(_iterable<Collection> 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 T>
|
||||
typename std::enable_if<std::is_integral<T>::value, BinaryWriter&>::type operator<<(T t) {
|
||||
if (std::numeric_limits<T>::is_signed) {
|
||||
auto i = static_cast<int64_t>(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<uint64_t>(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 <typename T>
|
||||
BinaryWriter& record(Value<T> const& label, std::vector<Value<T>> const& fields) {
|
||||
return (*this) << BinaryTag::Record << label << fields << BinaryTag::End;
|
||||
return (*this) << BinaryTag::Record << label << iterable(fields) << BinaryTag::End;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
BinaryWriter& sequence(std::vector<Value<T>> const& vs) {
|
||||
return (*this) << BinaryTag::Sequence << vs << BinaryTag::End;
|
||||
return (*this) << BinaryTag::Sequence << iterable(vs) << BinaryTag::End;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
BinaryWriter& set(std::set<Value<T>> const& vs) {
|
||||
return (*this) << BinaryTag::Set << vs << BinaryTag::End;
|
||||
return (*this) << BinaryTag::Set << iterable(vs) << BinaryTag::End;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -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 <uint64_t wholeTest, uint64_t bitTest>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,8 +271,8 @@ namespace Preserves {
|
|||
|
||||
template <typename T>
|
||||
class AnnotatedValue: public ValueImpl<T> {
|
||||
Value<T> underlying;
|
||||
std::vector<Value<T>> anns;
|
||||
Value<T> underlying;
|
||||
|
||||
friend class ValueImpl<T>;
|
||||
|
||||
|
@ -282,15 +282,14 @@ namespace Preserves {
|
|||
anns.push_back(ann);
|
||||
return self;
|
||||
} else {
|
||||
auto a = std::make_shared<AnnotatedValue<T>>(underlying);
|
||||
a->anns.insert(a->anns.end(), anns.begin(), anns.end());
|
||||
auto a = std::make_shared<AnnotatedValue<T>>(std::vector<Value<T>>(anns), underlying);
|
||||
a->anns.push_back(ann);
|
||||
return Value<T>(a);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AnnotatedValue(Value<T> const& v) : underlying(v) {}
|
||||
AnnotatedValue(std::vector<Value<T>> &&anns, Value<T> 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 <typename T>
|
||||
Value<T> ValueImpl<T>::internal_annotate(std::shared_ptr<ValueImpl<T>> const& self, Value<T> const &ann) {
|
||||
auto a = std::make_shared<AnnotatedValue<T>>(Value<T>(self));
|
||||
auto a = std::make_shared<AnnotatedValue<T>>(std::vector<Value<T>>(), Value<T>(self));
|
||||
a->anns.push_back(ann);
|
||||
return Value<T>(a);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue