Skip to content

Commit 31d0319

Browse files
committed
bug fixes, API improvment
1 parent 32d134a commit 31d0319

File tree

1 file changed

+105
-40
lines changed

1 file changed

+105
-40
lines changed

lib/include/cpp-json/json.h

Lines changed: 105 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,12 @@ inline bool is_null(const value &v) noexcept;
6565
// conversion (you get a copy)
6666
inline std::string to_string(const value &v);
6767
inline bool to_bool(const value &v);
68-
inline double to_number(const value &v);
69-
inline int64_t to_integer(const value &v);
7068
inline object to_object(const value &v);
7169
inline array to_array(const value &v);
7270

71+
template <class T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
72+
T to_number(const value &v);
73+
7374
// interpretation (you get a reference)
7475
inline object &as_object(value &v);
7576
inline array &as_array(value &v);
@@ -91,9 +92,9 @@ inline value parse(NS::string_view s);
9192

9293
// convert a value to a JSON string
9394
enum Options {
94-
None = 0x00,
95-
EscapeUnicode = 0x01,
96-
PrettyPrint = 0x02,
95+
None = 0x00,
96+
EscapeUnicode = 0x01,
97+
PrettyPrint = 0x02,
9798
};
9899

99100
constexpr inline Options operator&(Options lhs, Options rhs) noexcept {
@@ -205,6 +206,32 @@ void surrogate_pair_to_utf8(uint16_t w1, uint16_t w2, Out &out) {
205206
*out++ = static_cast<uint8_t>(0x80 | (cp & 0x3f));
206207
}
207208
}
209+
210+
template <class T>
211+
struct to_number_helper {};
212+
213+
template <> struct to_number_helper<float> { float convert(const value &v) { return stof(as_string(v), nullptr); } };
214+
template <> struct to_number_helper<double> { double convert(const value &v) { return stod(as_string(v), nullptr); } };
215+
216+
template <> struct to_number_helper<uint8_t> { uint8_t convert(const value &v) { return static_cast<uint8_t>(stoul(as_string(v), nullptr)); } };
217+
template <> struct to_number_helper<uint16_t> { uint16_t convert(const value &v) { return static_cast<uint16_t>(stoul(as_string(v), nullptr)); } };
218+
template <> struct to_number_helper<uint32_t> { uint32_t convert(const value &v) { return static_cast<uint32_t>(stoul(as_string(v), nullptr)); } };
219+
template <> struct to_number_helper<uint64_t> { uint64_t convert(const value &v) { return stoull(as_string(v), nullptr); } };
220+
221+
template <> struct to_number_helper<int8_t> { int8_t convert(const value &v) { return static_cast<int8_t>(stol(as_string(v), nullptr)); } };
222+
template <> struct to_number_helper<int16_t> { int16_t convert(const value &v) { return static_cast<int16_t>(stol(as_string(v), nullptr)); } };
223+
template <> struct to_number_helper<int32_t> { int32_t convert(const value &v) { return static_cast<int32_t>(stol(as_string(v), nullptr)); } };
224+
template <> struct to_number_helper<int64_t> { int64_t convert(const value &v) { return stoll(as_string(v), nullptr); } };
225+
}
226+
227+
template <class T, class>
228+
T to_number(const value &v) {
229+
if (!is_number(v)) {
230+
throw invalid_type_cast();
231+
}
232+
233+
detail::to_number_helper<T> helper;
234+
return helper.convert(v);
208235
}
209236

210237
/**
@@ -632,8 +659,8 @@ class value {
632659

633660
public:
634661
// intialize from basic types
635-
value(const array &a);
636-
value(const object &o);
662+
explicit value(const array &a);
663+
explicit value(const object &o);
637664

638665
value(array &&a);
639666
value(object &&o);
@@ -723,6 +750,8 @@ class value {
723750
value operator[](const ptr &ptr) const;
724751
value &operator[](const ptr &ptr);
725752

753+
value &create(const ptr &ptr);
754+
726755
public:
727756
// array like interface
728757
template <class T>
@@ -1124,28 +1153,32 @@ inline bool to_bool(const value &v) {
11241153
return NS::get<value::Boolean>(v.storage_) == value::Boolean::True;
11251154
}
11261155

1127-
inline double to_number(const value &v) {
1128-
if (!is_number(v)) {
1129-
throw invalid_type_cast();
1130-
}
1156+
inline object to_object(const value &v) {
1157+
return as_object(v);
1158+
}
11311159

1132-
return stod(as_string(v), nullptr);
1160+
inline array to_array(const value &v) {
1161+
return as_array(v);
11331162
}
11341163

1135-
inline int64_t to_integer(const value &v) {
1136-
if (!is_number(v)) {
1137-
throw invalid_type_cast();
1138-
}
1164+
inline object &as_object(array &v) {
1165+
(void)v;
1166+
throw invalid_type_cast();
1167+
}
11391168

1140-
return stoll(as_string(v), nullptr);
1169+
inline array &as_array(object &v) {
1170+
(void)v;
1171+
throw invalid_type_cast();
11411172
}
11421173

1143-
inline object to_object(const value &v) {
1144-
return as_object(v);
1174+
inline const object &as_object(const array &v) {
1175+
(void)v;
1176+
throw invalid_type_cast();
11451177
}
11461178

1147-
inline array to_array(const value &v) {
1148-
return as_array(v);
1179+
inline const array &as_array(const object &v) {
1180+
(void)v;
1181+
throw invalid_type_cast();
11491182
}
11501183

11511184
inline object &as_object(value &v) {
@@ -1294,7 +1327,14 @@ inline std::string escape_string(NS::string_view s, Options options) {
12941327
r += "\\t";
12951328
break;
12961329
default:
1297-
r += *it;
1330+
if(!isprint(*it)) {
1331+
r += "\\u";
1332+
char buf[5];
1333+
snprintf(buf, sizeof(buf), "%04X", *it);
1334+
r += buf;
1335+
} else {
1336+
r += *it;
1337+
}
12981338
break;
12991339
}
13001340
} else if ((ch & 0xe0) == 0xc0) {
@@ -1514,43 +1554,43 @@ inline void value_to_string(std::ostream &os, const value &v, Options options) {
15141554
}
15151555

15161556
// serialize, not pretty printed
1517-
inline void serialize_to_stream(std::ostream &os, const value &v, Options options);
1557+
inline void serialize(std::ostream &os, const value &v, Options options);
15181558

1519-
inline void serialize_to_stream(std::ostream &os, const array &a, Options options) {
1559+
inline void serialize(std::ostream &os, const array &a, Options options) {
15201560
os << "[";
15211561
if (!a.empty()) {
15221562
auto it = a.begin();
15231563
auto e = a.end();
15241564

1525-
serialize_to_stream(os, *it++, options);
1565+
serialize(os, *it++, options);
15261566

15271567
for (; it != e; ++it) {
15281568
os << ',';
1529-
serialize_to_stream(os, *it, options);
1569+
serialize(os, *it, options);
15301570
}
15311571
}
15321572
os << "]";
15331573
}
15341574

1535-
inline void serialize_to_stream(std::ostream &os, const object &o, Options options) {
1575+
inline void serialize(std::ostream &os, const object &o, Options options) {
15361576
os << "{";
15371577
if (!o.empty()) {
15381578
auto it = o.begin();
15391579
auto e = o.end();
15401580

15411581
os << '"' << escape_string(it->first, options) << "\":";
1542-
serialize_to_stream(os, it->second, options);
1582+
serialize(os, it->second, options);
15431583
++it;
15441584
for (; it != e; ++it) {
15451585
os << ',';
15461586
os << '"' << escape_string(it->first, options) << "\":";
1547-
serialize_to_stream(os, it->second, options);
1587+
serialize(os, it->second, options);
15481588
}
15491589
}
15501590
os << "}";
15511591
}
15521592

1553-
inline void serialize_to_stream(std::ostream &os, const value &v, Options options) {
1593+
inline void serialize(std::ostream &os, const value &v, Options options) {
15541594

15551595
switch(v.type()) {
15561596
case value::type_string:
@@ -1566,11 +1606,11 @@ inline void serialize_to_stream(std::ostream &os, const value &v, Options option
15661606
os << (to_bool(v) ? "true" : "false");
15671607
break;
15681608
case value::type_object: {
1569-
serialize_to_stream(os, as_object(v), options);
1609+
serialize(os, as_object(v), options);
15701610
break;
15711611
}
15721612
case value::type_array: {
1573-
serialize_to_stream(os, as_array(v), options);
1613+
serialize(os, as_array(v), options);
15741614
break;
15751615
}
15761616
case value::type_invalid:
@@ -1579,24 +1619,24 @@ inline void serialize_to_stream(std::ostream &os, const value &v, Options option
15791619
}
15801620

15811621
template <class T, class = typename std::enable_if<std::is_same<T, value>::value || std::is_same<T, object>::value || std::is_same<T, array>::value>::type>
1582-
std::string serialize_to_string(const T &v, Options options) {
1622+
std::string serialize(const T &v, Options options) {
15831623
std::stringstream ss;
15841624

15851625
std::locale c_locale("C");
15861626
ss.imbue(c_locale);
15871627

1588-
serialize_to_stream(ss, v, options);
1628+
serialize(ss, v, options);
15891629
return ss.str();
15901630
}
15911631

15921632
template <class T, class = typename std::enable_if<std::is_same<T, value>::value || std::is_same<T, object>::value || std::is_same<T, array>::value>::type>
15931633
std::string pretty_print(const T &v, Options options) {
1594-
return value_to_string(v, options);
1634+
return value_to_string(value(v), options);
15951635
}
15961636

15971637
template <class T, class = typename std::enable_if<std::is_same<T, value>::value || std::is_same<T, object>::value || std::is_same<T, array>::value>::type>
15981638
void pretty_print(std::ostream &os, const T &v, Options options) {
1599-
value_to_string(os, v, options);
1639+
value_to_string(os, value(v), options);
16001640
}
16011641

16021642
}
@@ -1606,7 +1646,7 @@ std::string stringify(const T &v, Options options) {
16061646
if (options & Options::PrettyPrint) {
16071647
return detail::pretty_print(v, options);
16081648
} else {
1609-
return detail::serialize_to_string(v, options);
1649+
return detail::serialize(v, options);
16101650
}
16111651
}
16121652

@@ -1619,7 +1659,7 @@ void stringify(std::ostream &os, const T &v, Options options) {
16191659
if (options & Options::PrettyPrint) {
16201660
detail::pretty_print(os, v, options);
16211661
} else {
1622-
detail::serialize_to_stream(os, v, options);
1662+
detail::serialize(os, v, options);
16231663
}
16241664
}
16251665

@@ -1898,7 +1938,6 @@ inline value value::operator[](const ptr &ptr) const {
18981938
} else {
18991939
throw invalid_path();
19001940
}
1901-
19021941
}
19031942

19041943
return *result;
@@ -1922,7 +1961,31 @@ inline value &value::operator[](const ptr &ptr) {
19221961
} else {
19231962
throw invalid_path();
19241963
}
1964+
}
19251965

1966+
return *result;
1967+
}
1968+
1969+
inline value &value::create(const ptr &ptr) {
1970+
value *result = this;
1971+
for(const std::string &ref : ptr) {
1972+
1973+
if(result->is_object()) {
1974+
if(!has_key(result, ref)) {
1975+
result->insert(ref, object());
1976+
}
1977+
result = &result->at(ref);
1978+
} else if(result->is_array()) {
1979+
if(ref == "-") {
1980+
result->push_back(value());
1981+
result = &result->at(result->size() - 1);
1982+
} else {
1983+
std::size_t n = std::stoul(ref);
1984+
result = &result->at(n);
1985+
}
1986+
} else {
1987+
throw invalid_path();
1988+
}
19261989
}
19271990

19281991
return *result;
@@ -1976,7 +2039,7 @@ inline bool operator==(const value &lhs, const value &rhs) {
19762039
case value::type_string:
19772040
return as_string(lhs) == as_string(rhs);
19782041
case value::type_number:
1979-
return to_number(lhs) == to_number(rhs);
2042+
return to_number<double>(lhs) == to_number<double>(rhs);
19802043
case value::type_null:
19812044
return true;
19822045
case value::type_boolean:
@@ -2239,6 +2302,8 @@ std::pair<object::iterator, bool> value::insert(std::pair<std::string, T> &&p) {
22392302
}
22402303

22412304

2305+
2306+
22422307
}
22432308

22442309
#endif

0 commit comments

Comments
 (0)