mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge pull request #258 from erikaldsund/fix_handling_of_big_integers
Fix handling of big integers
This commit is contained in:
commit
01cc7a3508
@ -96,6 +96,13 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class num_type : char {
|
||||||
|
Signed_integer,
|
||||||
|
Unsigned_integer,
|
||||||
|
Floating_point,
|
||||||
|
Null
|
||||||
|
};
|
||||||
|
|
||||||
class rvalue;
|
class rvalue;
|
||||||
rvalue load(const char* data, size_t size);
|
rvalue load(const char* data, size_t size);
|
||||||
|
|
||||||
@ -216,13 +223,16 @@ namespace crow
|
|||||||
: start_{s},
|
: start_{s},
|
||||||
end_{e},
|
end_{e},
|
||||||
t_{t}
|
t_{t}
|
||||||
{}
|
{
|
||||||
|
determine_num_type();
|
||||||
|
}
|
||||||
|
|
||||||
rvalue(const rvalue& r)
|
rvalue(const rvalue& r)
|
||||||
: start_(r.start_),
|
: start_(r.start_),
|
||||||
end_(r.end_),
|
end_(r.end_),
|
||||||
key_(r.key_),
|
key_(r.key_),
|
||||||
t_(r.t_),
|
t_(r.t_),
|
||||||
|
nt_(r.nt_),
|
||||||
option_(r.option_)
|
option_(r.option_)
|
||||||
{
|
{
|
||||||
copy_l(r);
|
copy_l(r);
|
||||||
@ -240,6 +250,7 @@ namespace crow
|
|||||||
key_ = r.key_;
|
key_ = r.key_;
|
||||||
copy_l(r);
|
copy_l(r);
|
||||||
t_ = r.t_;
|
t_ = r.t_;
|
||||||
|
nt_ = r.nt_;
|
||||||
option_ = r.option_;
|
option_ = r.option_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -252,6 +263,7 @@ namespace crow
|
|||||||
lsize_ = r.lsize_;
|
lsize_ = r.lsize_;
|
||||||
lremain_ = r.lremain_;
|
lremain_ = r.lremain_;
|
||||||
t_ = r.t_;
|
t_ = r.t_;
|
||||||
|
nt_ = r.nt_;
|
||||||
option_ = r.option_;
|
option_ = r.option_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -287,6 +299,17 @@ namespace crow
|
|||||||
return t_;
|
return t_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
num_type nt() const
|
||||||
|
{
|
||||||
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
|
if (option_ & error_bit)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid json object");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return nt_;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t i() const
|
int64_t i() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -591,6 +614,28 @@ namespace crow
|
|||||||
lremain_ --;
|
lremain_ --;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// determines num_type from the string
|
||||||
|
void determine_num_type()
|
||||||
|
{
|
||||||
|
if (t_ != type::Number)
|
||||||
|
{
|
||||||
|
nt_ = num_type::Null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t len = end_ - start_;
|
||||||
|
const bool has_minus = std::memchr(start_, '-', len) != nullptr;
|
||||||
|
const bool has_e = std::memchr(start_, 'e', len) != nullptr
|
||||||
|
|| std::memchr(start_, 'E', len) != nullptr;
|
||||||
|
const bool has_dec_sep = std::memchr(start_, '.', len) != nullptr;
|
||||||
|
if (has_dec_sep || has_e)
|
||||||
|
nt_ = num_type::Floating_point;
|
||||||
|
else if (has_minus)
|
||||||
|
nt_ = num_type::Signed_integer;
|
||||||
|
else
|
||||||
|
nt_ = num_type::Unsigned_integer;
|
||||||
|
}
|
||||||
|
|
||||||
mutable char* start_;
|
mutable char* start_;
|
||||||
mutable char* end_;
|
mutable char* end_;
|
||||||
detail::r_string key_;
|
detail::r_string key_;
|
||||||
@ -598,6 +643,7 @@ namespace crow
|
|||||||
uint32_t lsize_;
|
uint32_t lsize_;
|
||||||
uint16_t lremain_;
|
uint16_t lremain_;
|
||||||
type t_;
|
type t_;
|
||||||
|
num_type nt_{num_type::Null};
|
||||||
mutable uint8_t option_{0};
|
mutable uint8_t option_{0};
|
||||||
|
|
||||||
friend rvalue load_nocopy_internal(char* data, size_t size);
|
friend rvalue load_nocopy_internal(char* data, size_t size);
|
||||||
@ -610,7 +656,17 @@ namespace crow
|
|||||||
case type::Null: os << "null"; break;
|
case type::Null: os << "null"; break;
|
||||||
case type::False: os << "false"; break;
|
case type::False: os << "false"; break;
|
||||||
case type::True: os << "true"; break;
|
case type::True: os << "true"; break;
|
||||||
case type::Number: os << r.d(); break;
|
case type::Number:
|
||||||
|
{
|
||||||
|
switch (r.nt())
|
||||||
|
{
|
||||||
|
case num_type::Floating_point: os << r.d(); break;
|
||||||
|
case num_type::Signed_integer: os << r.i(); break;
|
||||||
|
case num_type::Unsigned_integer: os << r.u(); break;
|
||||||
|
case num_type::Null: throw std::runtime_error("Number with num_type Null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case type::String: os << '"' << r.s() << '"'; break;
|
case type::String: os << '"' << r.s() << '"'; break;
|
||||||
case type::List:
|
case type::List:
|
||||||
{
|
{
|
||||||
@ -1092,7 +1148,12 @@ namespace crow
|
|||||||
type t() const { return t_; }
|
type t() const { return t_; }
|
||||||
private:
|
private:
|
||||||
type t_{type::Null};
|
type t_{type::Null};
|
||||||
double d {};
|
num_type nt{num_type::Null};
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
int64_t si;
|
||||||
|
uint64_t ui {};
|
||||||
|
} num;
|
||||||
std::string s;
|
std::string s;
|
||||||
std::unique_ptr<std::vector<wvalue>> l;
|
std::unique_ptr<std::vector<wvalue>> l;
|
||||||
std::unique_ptr<std::unordered_map<std::string, wvalue>> o;
|
std::unique_ptr<std::unordered_map<std::string, wvalue>> o;
|
||||||
@ -1110,7 +1171,13 @@ namespace crow
|
|||||||
case type::True:
|
case type::True:
|
||||||
return;
|
return;
|
||||||
case type::Number:
|
case type::Number:
|
||||||
d = r.d();
|
nt = r.nt();
|
||||||
|
if (nt == num_type::Floating_point)
|
||||||
|
num.d = r.d();
|
||||||
|
else if (nt == num_type::Signed_integer)
|
||||||
|
num.si = r.i();
|
||||||
|
else
|
||||||
|
num.ui = r.u();
|
||||||
return;
|
return;
|
||||||
case type::String:
|
case type::String:
|
||||||
s = r.s();
|
s = r.s();
|
||||||
@ -1140,7 +1207,7 @@ namespace crow
|
|||||||
wvalue& operator = (wvalue&& r)
|
wvalue& operator = (wvalue&& r)
|
||||||
{
|
{
|
||||||
t_ = r.t_;
|
t_ = r.t_;
|
||||||
d = r.d;
|
num = r.num;
|
||||||
s = std::move(r.s);
|
s = std::move(r.s);
|
||||||
l = std::move(r.l);
|
l = std::move(r.l);
|
||||||
o = std::move(r.o);
|
o = std::move(r.o);
|
||||||
@ -1149,9 +1216,7 @@ namespace crow
|
|||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
t_ = type::Null;
|
reset();
|
||||||
l.reset();
|
|
||||||
o.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
@ -1180,7 +1245,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = value;
|
num.d = value;
|
||||||
|
nt = num_type::Floating_point;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1188,7 +1254,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.ui = value;
|
||||||
|
nt = num_type::Unsigned_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1196,7 +1263,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.si = value;
|
||||||
|
nt = num_type::Signed_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,7 +1272,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.si = value;
|
||||||
|
nt = num_type::Signed_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1212,7 +1281,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.si = value;
|
||||||
|
nt = num_type::Signed_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1220,7 +1290,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.si = value;
|
||||||
|
nt = num_type::Signed_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,7 +1299,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.ui = value;
|
||||||
|
nt = num_type::Unsigned_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1236,7 +1308,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.ui = value;
|
||||||
|
nt = num_type::Unsigned_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1244,7 +1317,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
t_ = type::Number;
|
t_ = type::Number;
|
||||||
d = (double)value;
|
num.ui = value;
|
||||||
|
nt = num_type::Unsigned_integer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,11 +1480,23 @@ namespace crow
|
|||||||
{
|
{
|
||||||
char outbuf[128];
|
char outbuf[128];
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
sprintf_s(outbuf, 128, "%g", v.d);
|
#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf_s((BUFFER_PTR), 128, (FORMAT_PTR), (VALUE))
|
||||||
#else
|
#else
|
||||||
sprintf(outbuf, "%g", v.d);
|
#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE))
|
||||||
#endif
|
#endif
|
||||||
|
if (v.nt == num_type::Floating_point)
|
||||||
|
{
|
||||||
|
MSC_COMPATIBLE_SPRINTF(outbuf, "%g", v.num.d);
|
||||||
|
}
|
||||||
|
else if (v.nt == num_type::Signed_integer)
|
||||||
|
{
|
||||||
|
MSC_COMPATIBLE_SPRINTF(outbuf, "%lld", v.num.si);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MSC_COMPATIBLE_SPRINTF(outbuf, "%llu", v.num.ui);
|
||||||
|
}
|
||||||
|
#undef MSC_COMPATIBLE_SPRINTF
|
||||||
out += outbuf;
|
out += outbuf;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -501,7 +501,7 @@ TEST(json_read)
|
|||||||
//ASSERT_THROW(3 == x["message"]);
|
//ASSERT_THROW(3 == x["message"]);
|
||||||
ASSERT_EQUAL(12, x["message"].size());
|
ASSERT_EQUAL(12, x["message"].size());
|
||||||
|
|
||||||
std::string s = R"({"int":3, "ints" :[1,2,3,4,5] })";
|
std::string s = R"({"int":3, "ints" :[1,2,3,4,5], "bigint":1234567890 })";
|
||||||
auto y = json::load(s);
|
auto y = json::load(s);
|
||||||
ASSERT_EQUAL(3, y["int"]);
|
ASSERT_EQUAL(3, y["int"]);
|
||||||
ASSERT_EQUAL(3.0, y["int"]);
|
ASSERT_EQUAL(3.0, y["int"]);
|
||||||
@ -519,6 +519,7 @@ TEST(json_read)
|
|||||||
ASSERT_EQUAL(2, q);
|
ASSERT_EQUAL(2, q);
|
||||||
q = y["ints"][2].i();
|
q = y["ints"][2].i();
|
||||||
ASSERT_EQUAL(3, q);
|
ASSERT_EQUAL(3, q);
|
||||||
|
ASSERT_EQUAL(1234567890, y["bigint"]);
|
||||||
|
|
||||||
std::string s2 = R"({"bools":[true, false], "doubles":[1.2, -3.4]})";
|
std::string s2 = R"({"bools":[true, false], "doubles":[1.2, -3.4]})";
|
||||||
auto z = json::load(s2);
|
auto z = json::load(s2);
|
||||||
@ -532,6 +533,10 @@ TEST(json_read)
|
|||||||
std::string s3 = R"({"uint64": 18446744073709551615})";
|
std::string s3 = R"({"uint64": 18446744073709551615})";
|
||||||
auto z1 = json::load(s3);
|
auto z1 = json::load(s3);
|
||||||
ASSERT_EQUAL(18446744073709551615ull, z1["uint64"].u());
|
ASSERT_EQUAL(18446744073709551615ull, z1["uint64"].u());
|
||||||
|
|
||||||
|
std::ostringstream os;
|
||||||
|
os << z1["uint64"];
|
||||||
|
ASSERT_EQUAL("18446744073709551615", os.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_read_real)
|
TEST(json_read_real)
|
||||||
@ -596,6 +601,8 @@ TEST(json_write)
|
|||||||
ASSERT_TRUE(R"({"message":{"x":3,"y":5}})" == json::dump(x) || R"({"message":{"y":5,"x":3}})" == json::dump(x));
|
ASSERT_TRUE(R"({"message":{"x":3,"y":5}})" == json::dump(x) || R"({"message":{"y":5,"x":3}})" == json::dump(x));
|
||||||
x["message"] = 5.5;
|
x["message"] = 5.5;
|
||||||
ASSERT_EQUAL(R"({"message":5.5})", json::dump(x));
|
ASSERT_EQUAL(R"({"message":5.5})", json::dump(x));
|
||||||
|
x["message"] = 1234567890;
|
||||||
|
ASSERT_EQUAL(R"({"message":1234567890})", json::dump(x));
|
||||||
|
|
||||||
json::wvalue y;
|
json::wvalue y;
|
||||||
y["scores"][0] = 1;
|
y["scores"][0] = 1;
|
||||||
@ -616,6 +623,30 @@ TEST(json_write)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(json_copy_r_to_w_to_r)
|
||||||
|
{
|
||||||
|
json::rvalue r = json::load(R"({"smallint":2,"bigint":2147483647,"fp":23.43,"fpsc":2.343e1,"str":"a string","trueval":true,"falseval":false,"nullval":null,"listval":[1,2,"foo","bar"],"obj":{"member":23,"other":"baz"}})");
|
||||||
|
json::wvalue w{r};
|
||||||
|
json::rvalue x = json::load(json::dump(w)); // why no copy-ctor wvalue -> rvalue?
|
||||||
|
ASSERT_EQUAL(2, x["smallint"]);
|
||||||
|
ASSERT_EQUAL(2147483647, x["bigint"]);
|
||||||
|
ASSERT_EQUAL(23.43, x["fp"]);
|
||||||
|
ASSERT_EQUAL(23.43, x["fpsc"]);
|
||||||
|
ASSERT_EQUAL("a string", x["str"]);
|
||||||
|
ASSERT_TRUE(true == x["trueval"].b());
|
||||||
|
ASSERT_TRUE(false == x["falseval"].b());
|
||||||
|
ASSERT_TRUE(json::type::Null == x["nullval"].t());
|
||||||
|
ASSERT_EQUAL(4u, x["listval"].size());
|
||||||
|
ASSERT_EQUAL(1, x["listval"][0]);
|
||||||
|
ASSERT_EQUAL(2, x["listval"][1]);
|
||||||
|
ASSERT_EQUAL("foo", x["listval"][2]);
|
||||||
|
ASSERT_EQUAL("bar", x["listval"][3]);
|
||||||
|
ASSERT_EQUAL(23, x["obj"]["member"]);
|
||||||
|
ASSERT_EQUAL("member", x["obj"]["member"].key());
|
||||||
|
ASSERT_EQUAL("baz", x["obj"]["other"]);
|
||||||
|
ASSERT_EQUAL("other", x["obj"]["other"].key());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(template_basic)
|
TEST(template_basic)
|
||||||
{
|
{
|
||||||
auto t = crow::mustache::compile(R"---(attack of {{name}})---");
|
auto t = crow::mustache::compile(R"---(attack of {{name}})---");
|
||||||
|
Loading…
Reference in New Issue
Block a user