aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/crow/json.h126
-rw-r--r--include/crow/websocket.h9
-rw-r--r--tests/unittest.cpp33
3 files changed, 143 insertions, 25 deletions
diff --git a/include/crow/json.h b/include/crow/json.h
index 1aa303e..85344fd 100644
--- a/include/crow/json.h
+++ b/include/crow/json.h
@@ -96,6 +96,13 @@ namespace crow
}
}
+ enum class num_type : char {
+ Signed_integer,
+ Unsigned_integer,
+ Floating_point,
+ Null
+ };
+
class rvalue;
rvalue load(const char* data, size_t size);
@@ -217,13 +224,16 @@ namespace crow
: start_{s},
end_{e},
t_{t}
- {}
+ {
+ determine_num_type();
+ }
rvalue(const rvalue& r)
: start_(r.start_),
end_(r.end_),
key_(r.key_),
t_(r.t_),
+ nt_(r.nt_),
option_(r.option_)
{
copy_l(r);
@@ -241,6 +251,7 @@ namespace crow
key_ = r.key_;
copy_l(r);
t_ = r.t_;
+ nt_ = r.nt_;
option_ = r.option_;
return *this;
}
@@ -253,6 +264,7 @@ namespace crow
lsize_ = r.lsize_;
lremain_ = r.lremain_;
t_ = r.t_;
+ nt_ = r.nt_;
option_ = r.option_;
return *this;
}
@@ -288,6 +300,17 @@ namespace crow
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
{
#ifndef CROW_JSON_NO_ERROR_CHECK
@@ -592,6 +615,28 @@ namespace crow
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* end_;
detail::r_string key_;
@@ -599,6 +644,7 @@ namespace crow
uint32_t lsize_;
uint16_t lremain_;
type t_;
+ num_type nt_{num_type::Null};
mutable uint8_t option_{0};
friend rvalue load_nocopy_internal(char* data, size_t size);
@@ -611,7 +657,17 @@ namespace crow
case type::Null: os << "null"; break;
case type::False: os << "false"; 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::List:
{
@@ -1093,7 +1149,12 @@ namespace crow
type t() const { return t_; }
private:
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::unique_ptr<std::vector<wvalue>> l;
std::unique_ptr<std::unordered_map<std::string, wvalue>> o;
@@ -1111,7 +1172,13 @@ namespace crow
case type::True:
return;
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;
case type::String:
s = r.s();
@@ -1141,7 +1208,7 @@ namespace crow
wvalue& operator = (wvalue&& r)
{
t_ = r.t_;
- d = r.d;
+ num = r.num;
s = std::move(r.s);
l = std::move(r.l);
o = std::move(r.o);
@@ -1150,9 +1217,7 @@ namespace crow
void clear()
{
- t_ = type::Null;
- l.reset();
- o.reset();
+ reset();
}
void reset()
@@ -1181,7 +1246,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = value;
+ num.d = value;
+ nt = num_type::Floating_point;
return *this;
}
@@ -1189,7 +1255,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.ui = value;
+ nt = num_type::Unsigned_integer;
return *this;
}
@@ -1197,7 +1264,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.si = value;
+ nt = num_type::Signed_integer;
return *this;
}
@@ -1205,7 +1273,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.si = value;
+ nt = num_type::Signed_integer;
return *this;
}
@@ -1213,7 +1282,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.si = value;
+ nt = num_type::Signed_integer;
return *this;
}
@@ -1221,7 +1291,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.si = value;
+ nt = num_type::Signed_integer;
return *this;
}
@@ -1229,7 +1300,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.ui = value;
+ nt = num_type::Unsigned_integer;
return *this;
}
@@ -1237,7 +1309,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.ui = value;
+ nt = num_type::Unsigned_integer;
return *this;
}
@@ -1245,7 +1318,8 @@ namespace crow
{
reset();
t_ = type::Number;
- d = (double)value;
+ num.ui = value;
+ nt = num_type::Unsigned_integer;
return *this;
}
@@ -1407,11 +1481,23 @@ namespace crow
{
char outbuf[128];
#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
- sprintf(outbuf, "%g", v.d);
+#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE))
#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;
}
break;
diff --git a/include/crow/websocket.h b/include/crow/websocket.h
index ee0885f..c2dc3f8 100644
--- a/include/crow/websocket.h
+++ b/include/crow/websocket.h
@@ -152,7 +152,7 @@ namespace crow
else
{
buf[1] += 127;
- *(uint64_t*)(buf+2) = ((1==htonl(1)) ? (uint64_t)size : ((uint64_t)htonl((size) & 0xFFFFFFFF) << 32) | htonl((size) >> 32));
+ *reinterpret_cast<uint64_t*>(buf+2) = ((1==htonl(1)) ? static_cast<uint64_t>(size) : (static_cast<uint64_t>(htonl((size) & 0xFFFFFFFF)) << 32) | htonl(static_cast<uint64_t>(size) >> 32));
return {buf, buf+10};
}
}
@@ -191,7 +191,7 @@ namespace crow
{
is_reading = false;
- mini_header_ = htons(mini_header_);
+ mini_header_ = ntohs(mini_header_);
#ifdef CROW_ENABLE_DEBUG
if (!ec && bytes_transferred != 2)
@@ -231,9 +231,9 @@ namespace crow
case WebSocketReadState::Len16:
{
remaining_length_ = 0;
- uint16_t remaining_length16_ = 0;
+ remaining_length16_ = 0;
boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length16_, 2),
- [this,&remaining_length16_](const boost::system::error_code& ec, std::size_t
+ [this](const boost::system::error_code& ec, std::size_t
#ifdef CROW_ENABLE_DEBUG
bytes_transferred
#endif
@@ -502,6 +502,7 @@ namespace crow
std::string message_;
std::string fragment_;
WebSocketReadState state_{WebSocketReadState::MiniHeader};
+ uint16_t remaining_length16_{0};
uint64_t remaining_length_{0};
bool close_connection_{false};
bool is_reading{false};
diff --git a/tests/unittest.cpp b/tests/unittest.cpp
index bffdd60..6fe1bbd 100644
--- a/tests/unittest.cpp
+++ b/tests/unittest.cpp
@@ -501,7 +501,7 @@ TEST(json_read)
//ASSERT_THROW(3 == x["message"]);
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);
ASSERT_EQUAL(3, y["int"]);
ASSERT_EQUAL(3.0, y["int"]);
@@ -519,6 +519,7 @@ TEST(json_read)
ASSERT_EQUAL(2, q);
q = y["ints"][2].i();
ASSERT_EQUAL(3, q);
+ ASSERT_EQUAL(1234567890, y["bigint"]);
std::string s2 = R"({"bools":[true, false], "doubles":[1.2, -3.4]})";
auto z = json::load(s2);
@@ -532,6 +533,10 @@ TEST(json_read)
std::string s3 = R"({"uint64": 18446744073709551615})";
auto z1 = json::load(s3);
ASSERT_EQUAL(18446744073709551615ull, z1["uint64"].u());
+
+ std::ostringstream os;
+ os << z1["uint64"];
+ ASSERT_EQUAL("18446744073709551615", os.str());
}
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));
x["message"] = 5.5;
ASSERT_EQUAL(R"({"message":5.5})", json::dump(x));
+ x["message"] = 1234567890;
+ ASSERT_EQUAL(R"({"message":1234567890})", json::dump(x));
json::wvalue y;
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)
{
auto t = crow::mustache::compile(R"---(attack of {{name}})---");