Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

value.set(T&&) is problematic #147

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions picojson.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ class value {
template <typename T> T &get();
template <typename T> void set(const T &);
#if PICOJSON_USE_RVALUE_REFERENCE
template <typename T> void set(T &&);
void set(std::string &&);
void set(object &&);
void set(array &&);
#endif
bool evaluate_as_boolean() const;
const value &get(const size_t idx) const;
Expand Down Expand Up @@ -251,7 +253,7 @@ inline value::value(double n) : type_(number_type), u_() {
#else
isnan(n) || isinf(n)
#endif
) {
) {
throw std::overflow_error("");
}
u_.number_ = n;
Expand Down Expand Up @@ -349,9 +351,7 @@ inline void value::swap(value &x) PICOJSON_NOEXCEPT {
}

#define IS(ctype, jtype) \
template <> inline bool value::is<ctype>() const { \
return type_ == jtype##_type; \
}
template <> inline bool value::is<ctype>() const { return type_ == jtype##_type; }
IS(null, null)
IS(bool, boolean)
#ifdef PICOJSON_USE_INT64
Expand Down Expand Up @@ -410,7 +410,7 @@ SET(int64_t, int64, u_.int64_ = _val;)

#if PICOJSON_USE_RVALUE_REFERENCE
#define MOVESET(ctype, jtype, setter) \
template <> inline void value::set<ctype>(ctype && _val) { \
inline void value::set(ctype &&_val) { \
clear(); \
type_ = jtype##_type; \
setter \
Expand Down Expand Up @@ -1136,7 +1136,9 @@ inline std::string parse(value &out, std::istream &is) {
return err;
}

template <typename T> struct last_error_t { static std::string s; };
template <typename T> struct last_error_t {
static std::string s;
};
template <typename T> std::string last_error_t<T>::s;

inline void set_last_error(const std::string &s) {
Expand Down Expand Up @@ -1169,14 +1171,14 @@ inline bool operator==(const value &x, const value &y) {
inline bool operator!=(const value &x, const value &y) {
return !(x == y);
}
}
} // namespace picojson

#if !PICOJSON_USE_RVALUE_REFERENCE
namespace std {
template <> inline void swap(picojson::value &x, picojson::value &y) {
x.swap(y);
}
}
} // namespace std
#endif

inline std::istream &operator>>(std::istream &is, picojson::value &x) {
Expand Down
151 changes: 79 additions & 72 deletions test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "picotest/picotest.h"

#ifdef _MSC_VER
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4127) // conditional expression is constant
#endif

using namespace std;
Expand All @@ -41,22 +41,20 @@ using namespace std;
#include <float.h>
#include <limits.h>

int main(void)
{
int main(void) {
#if PICOJSON_USE_LOCALE
setlocale(LC_ALL, "");
#endif

// constructors
#define TEST(expr, expected) \
is(picojson::value expr .serialize(), string(expected), "picojson::value" #expr)

TEST( (true), "true");
TEST( (false), "false");
TEST( (42.0), "42");
TEST( (string("hello")), "\"hello\"");
TEST( ("hello"), "\"hello\"");
TEST( ("hello", 4), "\"hell\"");
#define TEST(expr, expected) is(picojson::value expr.serialize(), string(expected), "picojson::value" #expr)

TEST((true), "true");
TEST((false), "false");
TEST((42.0), "42");
TEST((string("hello")), "\"hello\"");
TEST(("hello"), "\"hello\"");
TEST(("hello", 4), "\"hell\"");

{
double a = 1;
Expand All @@ -73,30 +71,36 @@ int main(void)
a *= 2;
}
}

#undef TEST

#define TEST(in, type, cmp, serialize_test) { \
picojson::value v; \
const char* s = in; \
string err = picojson::parse(v, s, s + strlen(s)); \
_ok(err.empty(), in " no error"); \
_ok(v.is<type>(), in " check type"); \
is(v.get<type>(), static_cast<type>(cmp), in " correct output"); \
is(*s, '\0', in " read to eof"); \
if (serialize_test) { \
is(v.serialize(), string(in), in " serialize"); \
} \

#define TEST(in, type, cmp, serialize_test) \
{ \
picojson::value v; \
const char *s = in; \
string err = picojson::parse(v, s, s + strlen(s)); \
_ok(err.empty(), in " no error"); \
_ok(v.is<type>(), in " check type"); \
is(v.get<type>(), static_cast<type>(cmp), in " correct output"); \
is(*s, '\0', in " read to eof"); \
if (serialize_test) { \
is(v.serialize(), string(in), in " serialize"); \
} \
picojson::value rvaluetest, nonconst_lvaluetest; \
rvaluetest.set(static_cast<type>(cmp)); \
is(rvaluetest.get<type>(), static_cast<type>(cmp), in " correct output"); \
type lvaluesrc{cmp}; \
nonconst_lvaluetest.set(lvaluesrc); \
is(nonconst_lvaluetest.get<type>(), static_cast<type>(cmp), in " correct output"); \
}

TEST("false", bool, false, true);
TEST("true", bool, true, true);
TEST("90.5", double, 90.5, false);
TEST("1.7976931348623157e+308", double, DBL_MAX, false);
TEST("\"hello\"", string, string("hello"), true);
TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"),
true);
TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string,
string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"), true);
TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string, string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
#ifdef PICOJSON_USE_INT64
TEST("0", int64_t, 0, true);
Expand All @@ -105,18 +109,19 @@ int main(void)
#endif
#undef TEST

#define TEST(type, expr) { \
picojson::value v; \
const char *s = expr; \
string err = picojson::parse(v, s, s + strlen(s)); \
_ok(err.empty(), "empty " #type " no error"); \
_ok(v.is<picojson::type>(), "empty " #type " check type"); \
_ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
#define TEST(type, expr) \
{ \
picojson::value v; \
const char *s = expr; \
string err = picojson::parse(v, s, s + strlen(s)); \
_ok(err.empty(), "empty " #type " no error"); \
_ok(v.is<picojson::type>(), "empty " #type " check type"); \
_ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
}
TEST(array, "[]");
TEST(object, "{}");
#undef TEST

{
picojson::value v;
const char *s = "[1,true,\"hello\"]";
Expand All @@ -135,7 +140,7 @@ int main(void)
is(v.get(2).get<string>(), string("hello"), "check array[2] value");
_ok(!v.contains(3), "check not contains array[3]");
}

{
picojson::value v;
const char *s = "{ \"a\": true }";
Expand All @@ -152,28 +157,29 @@ int main(void)

{
picojson::value v1;
v1.set<picojson::object>(picojson::object());
v1.get<picojson::object>()["114"] = picojson::value("514");
v1.get<picojson::object>()["364"].set<picojson::array>(picojson::array());
v1.get<picojson::object>()["364"].get<picojson::array>().push_back(picojson::value(334.0));
picojson::value &v2 = v1.get<picojson::object>()["1919"];
v2.set<picojson::object>(picojson::object());
v2.get<picojson::object>()["893"] = picojson::value(810.0);
v1.set<picojson::object>(picojson::object());
v1.get<picojson::object>()["114"] = picojson::value("514");
v1.get<picojson::object>()["364"].set<picojson::array>(picojson::array());
v1.get<picojson::object>()["364"].get<picojson::array>().push_back(picojson::value(334.0));
picojson::value &v2 = v1.get<picojson::object>()["1919"];
v2.set<picojson::object>(picojson::object());
v2.get<picojson::object>()["893"] = picojson::value(810.0);
is(v1.serialize(), string("{\"114\":\"514\",\"1919\":{\"893\":810},\"364\":[334]}"), "modification succeed");
}

#define TEST(json, msg) do { \
picojson::value v; \
const char *s = json; \
string err = picojson::parse(v, s, s + strlen(s)); \
is(err, string("syntax error at line " msg), msg); \
#define TEST(json, msg) \
do { \
picojson::value v; \
const char *s = json; \
string err = picojson::parse(v, s, s + strlen(s)); \
is(err, string("syntax error at line " msg), msg); \
} while (0)
TEST("falsoa", "1 near: oa");
TEST("{]", "1 near: ]");
TEST("\n\bbell", "2 near: bell");
TEST("\"abc\nd\"", "1 near: ");
#undef TEST

{
picojson::value v1, v2;
const char *s;
Expand Down Expand Up @@ -213,9 +219,9 @@ int main(void)
string err;
s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
err = picojson::parse(v1, s, s + strlen(s));
picojson::object& o = v1.get<picojson::object>();
picojson::object &o = v1.get<picojson::object>();
o.erase("b");
picojson::array& a = o["a"].get<picojson::array>();
picojson::array &a = o["a"].get<picojson::array>();
picojson::array::iterator i;
i = std::remove(a.begin(), a.end(), picojson::value(std::string("three")));
a.erase(i, a.end());
Expand All @@ -224,17 +230,16 @@ int main(void)
_ok((v1 == v2), "check erase()");
}

_ok(picojson::value(3.0).serialize() == "3",
"integral number should be serialized as a integer");

_ok(picojson::value(3.0).serialize() == "3", "integral number should be serialized as a integer");

{
const char* s = "{ \"a\": [1,2], \"d\": 2 }";
const char *s = "{ \"a\": [1,2], \"d\": 2 }";
picojson::null_parse_context ctx;
string err;
picojson::_parse(ctx, s, s + strlen(s), &err);
_ok(err.empty(), "null_parse_context");
}

{
picojson::value v1, v2;
v1 = picojson::value(true);
Expand All @@ -254,37 +259,39 @@ int main(void)
_ok(v1.is<picojson::array>(), "swap (array)");
_ok(v2.is<picojson::object>(), "swap (object)");
}

{
picojson::value v;
const char *s = "{ \"a\": 1, \"b\": [ 2, { \"b1\": \"abc\" } ], \"c\": {}, \"d\": [] }";
string err;
err = picojson::parse(v, s, s + strlen(s));
_ok(err.empty(), "parse test data for prettifying output");
_ok(v.serialize() == "{\"a\":1,\"b\":[2,{\"b1\":\"abc\"}],\"c\":{},\"d\":[]}", "non-prettifying output");
_ok(v.serialize(true) == "{\n \"a\": 1,\n \"b\": [\n 2,\n {\n \"b1\": \"abc\"\n }\n ],\n \"c\": {},\n \"d\": []\n}\n", "prettifying output");
_ok(v.serialize(true) ==
"{\n \"a\": 1,\n \"b\": [\n 2,\n {\n \"b1\": \"abc\"\n }\n ],\n \"c\": {},\n \"d\": []\n}\n",
"prettifying output");
}

try {
picojson::value v(std::numeric_limits<double>::quiet_NaN());
_ok(false, "should not accept NaN");
} catch (std::overflow_error& e) {
} catch (std::overflow_error &e) {
_ok(true, "should not accept NaN");
}

try {
picojson::value v(std::numeric_limits<double>::infinity());
_ok(false, "should not accept infinity");
} catch (std::overflow_error& e) {
} catch (std::overflow_error &e) {
_ok(true, "should not accept infinity");
}

try {
picojson::value v(123.);
_ok(! v.is<bool>(), "is<wrong_type>() should return false");
_ok(!v.is<bool>(), "is<wrong_type>() should return false");
v.get<bool>();
_ok(false, "get<wrong_type>() should raise an error");
} catch (std::runtime_error& e) {
} catch (std::runtime_error &e) {
_ok(true, "get<wrong_type>() should raise an error");
}

Expand All @@ -297,12 +304,12 @@ int main(void)
_ok(v1.get<int64_t>() == 123, "value is correct as int64_t");
_ok(v1.get<double>(), "value is correct as double");

_ok(! v1.is<int64_t>(), "is no more int64_type once get<double>() is called");
_ok(!v1.is<int64_t>(), "is no more int64_type once get<double>() is called");
_ok(v1.is<double>(), "and is still a double");

const char *s = "-9223372036854775809";
_ok(picojson::parse(v1, s, s + strlen(s)).empty(), "parse underflowing int64_t");
_ok(! v1.is<int64_t>(), "underflowing int is not int64_t");
_ok(!v1.is<int64_t>(), "underflowing int is not int64_t");
_ok(v1.is<double>(), "underflowing int is double");
_ok(v1.get<double>() + 9.22337203685478e+18 < 65536, "double value is somewhat correct");
}
Expand All @@ -321,14 +328,14 @@ int main(void)
}

{
picojson::value v1((double) 0);
_ok(! v1.evaluate_as_boolean(), "((double) 0) is false");
picojson::value v2((double) 1);
picojson::value v1((double)0);
_ok(!v1.evaluate_as_boolean(), "((double) 0) is false");
picojson::value v2((double)1);
_ok(v2.evaluate_as_boolean(), "((double) 1) is true");
#ifdef PICOJSON_USE_INT64
picojson::value v3((int64_t) 0);
_ok(! v3.evaluate_as_boolean(), "((int64_t) 0) is false");
picojson::value v4((int64_t) 1);
picojson::value v3((int64_t)0);
_ok(!v3.evaluate_as_boolean(), "((int64_t) 0) is false");
picojson::value v4((int64_t)1);
_ok(v4.evaluate_as_boolean(), "((int64_t) 1) is true");
#endif
}
Expand Down