Fix EOF handling; BigNum
This commit is contained in:
parent
8788a72a8d
commit
60f23286e2
|
@ -1,9 +1,11 @@
|
|||
CXX=g++ -std=c++14 -Wall -Wextra -Werror -O0 -I googletest
|
||||
CXX=g++ -std=c++14 -Wall -Wextra -Werror -g -O0 -I googletest
|
||||
|
||||
test: m
|
||||
test: all
|
||||
./m
|
||||
|
||||
m: main.cpp preserves.hpp preserves_text.hpp googletest.a
|
||||
all: m
|
||||
|
||||
m: main.cpp preserves.hpp preserves_text.hpp preserves_binary.hpp googletest.a
|
||||
$(CXX) -o $@ main.cpp googletest.a
|
||||
|
||||
googletest.a: googletest/src/gtest-all.o googletest/src/gtest_main.o
|
||||
|
|
|
@ -63,6 +63,7 @@ namespace Preserves {
|
|||
|
||||
static Value from_unsigned(uint64_t i) { return from_int(i); }
|
||||
static Value from_signed(int64_t i) { return from_int(i); }
|
||||
static Value from_bignum(std::vector<uint8_t> const& v);
|
||||
|
||||
static Value from_number(uint64_t i) { return from_int(i); }
|
||||
static Value from_number(int64_t i) { return from_int(i); }
|
||||
|
@ -120,6 +121,9 @@ namespace Preserves {
|
|||
boost::optional<int64_t> as_signed() const;
|
||||
int64_t to_signed() const { return as_signed().value(); }
|
||||
|
||||
boost::optional<std::vector<uint8_t> const&> as_bignum() const;
|
||||
std::vector<uint8_t> const& to_bignum() const { return as_bignum().value(); }
|
||||
|
||||
boost::optional<std::string const&> as_string() const;
|
||||
std::string const& to_string() const { return as_string().value(); }
|
||||
|
||||
|
@ -166,6 +170,7 @@ namespace Preserves {
|
|||
virtual boost::optional<double> as_double() const { return boost::none; }
|
||||
virtual boost::optional<uint64_t> as_unsigned() const { return boost::none; }
|
||||
virtual boost::optional<int64_t> as_signed() const { return boost::none; }
|
||||
virtual boost::optional<std::vector<uint8_t> const&> as_bignum() const { return boost::none; }
|
||||
virtual boost::optional<std::string const&> as_string() const { return boost::none; }
|
||||
virtual boost::optional<std::vector<uint8_t> const&> as_bytes() const { return boost::none; }
|
||||
virtual boost::optional<std::string const&> as_symbol() const { return boost::none; }
|
||||
|
@ -267,6 +272,7 @@ namespace Preserves {
|
|||
return boost::none;
|
||||
}
|
||||
});
|
||||
PRESERVES_ATOMIC_VALUE_CLASS(BigNum, std::vector<uint8_t>, std::vector<uint8_t> const&, ValueKind::SignedInteger, as_bignum,);
|
||||
PRESERVES_ATOMIC_VALUE_CLASS(String, std::string, std::string const&, ValueKind::String, as_string,);
|
||||
PRESERVES_ATOMIC_VALUE_CLASS(ByteString, std::vector<uint8_t>, std::vector<uint8_t> const&, ValueKind::ByteString, as_bytes,);
|
||||
PRESERVES_ATOMIC_VALUE_CLASS(Symbol, std::string, std::string const&, ValueKind::Symbol, as_symbol,);
|
||||
|
@ -458,6 +464,7 @@ namespace Preserves {
|
|||
PRESERVES_DELEGATE_CAST(double, as_double);
|
||||
PRESERVES_DELEGATE_CAST(uint64_t, as_unsigned);
|
||||
PRESERVES_DELEGATE_CAST(int64_t, as_signed);
|
||||
PRESERVES_DELEGATE_CAST(std::vector<uint8_t> const&, as_bignum);
|
||||
PRESERVES_DELEGATE_CAST(std::string const&, as_string);
|
||||
PRESERVES_DELEGATE_CAST(std::vector<uint8_t> const&, as_bytes);
|
||||
PRESERVES_DELEGATE_CAST(std::string const&, as_symbol);
|
||||
|
@ -473,6 +480,21 @@ namespace Preserves {
|
|||
template <typename T> boost::optional<Value<T>> Value<T>::get(size_t index) const { return p->get(index); }
|
||||
template <typename T> size_t Value<T>::size() const { return p->size(); }
|
||||
|
||||
bool bignum_lt(std::vector<uint8_t> const& a, std::vector<uint8_t> const& b) {
|
||||
bool aNegative = (a.size() > 0) && (a[0] & 0x80);
|
||||
bool bNegative = (b.size() > 0) && (b[0] & 0x80);
|
||||
if (aNegative != bNegative) return aNegative;
|
||||
if (aNegative) {
|
||||
if (a.size() > b.size()) return true;
|
||||
if (a.size() < b.size()) return false;
|
||||
return a < b;
|
||||
} else {
|
||||
if (a.size() > b.size()) return false;
|
||||
if (a.size() < b.size()) return true;
|
||||
return a < b;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator<(Value<T> const& a, Value<T> const &b) {
|
||||
auto aKind = a.value_kind();
|
||||
|
@ -494,7 +516,19 @@ namespace Preserves {
|
|||
if (auto bv = b.as_signed()) {
|
||||
return false;
|
||||
} else {
|
||||
return a.to_unsigned() < b.to_unsigned();
|
||||
if (auto av = a.as_unsigned()) {
|
||||
if (auto bv = b.as_unsigned()) {
|
||||
return *av < *bv;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (auto bv = b.as_unsigned()) {
|
||||
return false;
|
||||
} else {
|
||||
return bignum_lt(a.to_bignum(), b.to_bignum());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,11 @@ namespace Preserves {
|
|||
// Can read max 9 bytes, each with 7 bits of payload, for 9*7 = 63 bits.
|
||||
for (size_t count = 0; count < 9; count++) {
|
||||
int b = i.get();
|
||||
if (b == i.eof()) return boost::none;
|
||||
if (i.eof()) return boost::none;
|
||||
n |= (b & 0x7f) << (count * 7);
|
||||
if ((b & 0x80) == 0) return n;
|
||||
if ((b & 0x80) == 0) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
@ -87,6 +89,13 @@ namespace Preserves {
|
|||
return v;
|
||||
}
|
||||
|
||||
boost::optional<Value<T>> next_bignum(size_t n) {
|
||||
auto b = std::make_shared<BigNum<T>>(std::vector<uint8_t>());
|
||||
b->_value().resize(n);
|
||||
if (!next_chunk(&b->_value()[0], n)) return boost::none;
|
||||
return Value<T>(b);
|
||||
}
|
||||
|
||||
boost::optional<Value<T>> next() {
|
||||
bool end_sentinel;
|
||||
return _next(end_sentinel);
|
||||
|
@ -95,7 +104,10 @@ namespace Preserves {
|
|||
boost::optional<Value<T>> _next(bool& end_sentinel) {
|
||||
more:
|
||||
end_sentinel = false;
|
||||
switch (auto tag = BinaryTag(i.get())) {
|
||||
auto tag = BinaryTag(i.get());
|
||||
// std::cout << "tag " << std::hex << int(tag) << " pos " << i.tellg() - 1 << std::endl;
|
||||
if (i.eof()) return boost::none;
|
||||
switch (tag) {
|
||||
case BinaryTag::False: return Value<T>::from_bool(false);
|
||||
case BinaryTag::True: return Value<T>::from_bool(true);
|
||||
case BinaryTag::Float: return next_float().map(Value<T>::from_float);
|
||||
|
@ -117,13 +129,14 @@ namespace Preserves {
|
|||
return next_unsigned(n).map([](uint64_t v) { return Value<T>::from_int(int64_t(v)); });
|
||||
}
|
||||
if (n == 9) {
|
||||
// We can only handle this if it's unsigned and the first byte is 0.
|
||||
if (i.get() != 0) return boost::none;
|
||||
return next_unsigned(8).map(Value<T>::from_unsigned);
|
||||
// We can handle this with uint64_t if it's unsigned and the first byte is 0.
|
||||
if (i.get() == 0) return next_unsigned(8).map(Value<T>::from_unsigned);
|
||||
}
|
||||
return boost::none;
|
||||
return next_bignum(n);
|
||||
}
|
||||
case BinaryTag::SignedInteger: return boost::none;
|
||||
case BinaryTag::SignedInteger: return varint(i).flat_map([&](size_t len) {
|
||||
return next_bignum(len);
|
||||
});
|
||||
case BinaryTag::String: return varint(i).flat_map([&](size_t len)-> boost::optional<Value<T>> {
|
||||
auto s = std::make_shared<String<T>>(std::string());
|
||||
s->_value().resize(len);
|
||||
|
|
Loading…
Reference in New Issue