Skip to content

Commit 0c168b1

Browse files
authored
Merge pull request #13579 from ethereum/refactor-json
[libsolutil] Add new JSON helper functions.
2 parents 7ac4c70 + 74be278 commit 0c168b1

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

libsolutil/JSON.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,66 @@ std::string jsonPrint(Json::Value const& _input, JsonFormat const& _format);
6767
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
6868
bool jsonParseStrict(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr);
6969

70+
namespace detail
71+
{
72+
73+
template<typename T>
74+
struct helper;
75+
76+
template<typename T, bool(Json::Value::*checkMember)() const, T(Json::Value::*convertMember)() const>
77+
struct helper_impl
78+
{
79+
static bool isOfType(Json::Value const& _input)
80+
{
81+
return (_input.*checkMember)();
82+
}
83+
static T get(Json::Value const& _input)
84+
{
85+
return (_input.*convertMember)();
86+
}
87+
static T getOrDefault(Json::Value const& _input, T _default = {})
88+
{
89+
T result = _default;
90+
if (isOfType(_input))
91+
result = (_input.*convertMember)();
92+
return result;
93+
}
94+
};
95+
96+
template<> struct helper<float>: helper_impl<float, &Json::Value::isDouble, &Json::Value::asFloat> {};
97+
template<> struct helper<double>: helper_impl<double, &Json::Value::isDouble, &Json::Value::asDouble> {};
98+
template<> struct helper<std::string>: helper_impl<std::string, &Json::Value::isString, &Json::Value::asString> {};
99+
template<> struct helper<Json::Int>: helper_impl<Json::Int, &Json::Value::isInt, &Json::Value::asInt> {};
100+
template<> struct helper<Json::Int64>: helper_impl<Json::Int64, &Json::Value::isInt64, &Json::Value::asInt64> {};
101+
template<> struct helper<Json::UInt>: helper_impl<Json::UInt, &Json::Value::isUInt, &Json::Value::asUInt> {};
102+
template<> struct helper<Json::UInt64>: helper_impl<Json::UInt64, &Json::Value::isUInt64, &Json::Value::asUInt64> {};
103+
104+
} // namespace detail
105+
106+
template<typename T>
107+
bool isOfType(Json::Value const& _input)
108+
{
109+
return detail::helper<T>::isOfType(_input);
110+
}
111+
112+
template<typename T>
113+
bool isOfTypeIfExists(Json::Value const& _input, std::string const& _name)
114+
{
115+
if (_input.isMember(_name))
116+
return isOfType<T>(_input[_name]);
117+
return true;
70118
}
119+
120+
template<typename T>
121+
T get(Json::Value const& _input)
122+
{
123+
return detail::helper<T>::get(_input);
124+
}
125+
126+
template<typename T>
127+
T getOrDefault(Json::Value const& _input, T _default = {})
128+
{
129+
return detail::helper<T>::getOrDefault(_input, _default);
130+
}
131+
132+
} // namespace solidity::util

test/libsolutil/JSON.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,131 @@ BOOST_AUTO_TEST_CASE(parse_json_strict)
184184
BOOST_CHECK(json[0] == "😊");
185185
}
186186

187+
BOOST_AUTO_TEST_CASE(json_isOfType)
188+
{
189+
Json::Value json;
190+
191+
json["float"] = 3.1f;
192+
json["double"] = 3.1;
193+
json["int"] = 2;
194+
json["int64"] = Json::Int64{0x4000000000000000};
195+
json["string"] = "Hello World!";
196+
197+
BOOST_CHECK(isOfType<float>(json["float"]));
198+
BOOST_CHECK(isOfType<double>(json["double"]));
199+
BOOST_CHECK(isOfType<int>(json["int"]));
200+
BOOST_CHECK(isOfType<Json::Int>(json["int"]));
201+
BOOST_CHECK(isOfType<Json::UInt>(json["int"]));
202+
BOOST_CHECK(isOfType<Json::Int64>(json["int"]));
203+
BOOST_CHECK(isOfType<Json::Int64>(json["int64"]));
204+
BOOST_CHECK(isOfType<Json::UInt64>(json["int64"]));
205+
BOOST_CHECK(isOfType<std::string>(json["string"]));
206+
BOOST_CHECK(!isOfType<Json::Int>(json["int64"]));
207+
BOOST_CHECK(!isOfType<int>(json["double"]));
208+
BOOST_CHECK(!isOfType<float>(json["string"]));
209+
BOOST_CHECK(!isOfType<double>(json["string"]));
210+
BOOST_CHECK(!isOfType<Json::Int>(json["string"]));
211+
BOOST_CHECK(!isOfType<Json::Int64>(json["string"]));
212+
BOOST_CHECK(!isOfType<Json::UInt>(json["string"]));
213+
BOOST_CHECK(!isOfType<Json::UInt64>(json["string"]));
214+
}
215+
216+
BOOST_AUTO_TEST_CASE(json_isisOfTypeIfExists)
217+
{
218+
Json::Value json;
219+
220+
json["float"] = 3.1f;
221+
json["double"] = 3.1;
222+
json["int"] = 2;
223+
json["int64"] = Json::Int64{0x4000000000000000};
224+
json["string"] = "Hello World!";
225+
226+
BOOST_CHECK(isOfTypeIfExists<float>(json, "float"));
227+
BOOST_CHECK(isOfTypeIfExists<double>(json, "double"));
228+
BOOST_CHECK(isOfTypeIfExists<int>(json, "int"));
229+
BOOST_CHECK(isOfTypeIfExists<Json::Int>(json, "int"));
230+
BOOST_CHECK(isOfTypeIfExists<Json::UInt>(json, "int"));
231+
BOOST_CHECK(isOfTypeIfExists<Json::Int64>(json, "int"));
232+
BOOST_CHECK(isOfTypeIfExists<Json::Int64>(json, "int64"));
233+
BOOST_CHECK(isOfTypeIfExists<Json::UInt64>(json, "int64"));
234+
BOOST_CHECK(isOfTypeIfExists<std::string>(json, "string"));
235+
BOOST_CHECK(!isOfTypeIfExists<Json::Int>(json, "int64"));
236+
BOOST_CHECK(!isOfTypeIfExists<int>(json, "double"));
237+
BOOST_CHECK(!isOfTypeIfExists<float>(json, "string"));
238+
BOOST_CHECK(!isOfTypeIfExists<double>(json, "string"));
239+
BOOST_CHECK(!isOfTypeIfExists<Json::Int>(json, "string"));
240+
BOOST_CHECK(!isOfTypeIfExists<Json::Int64>(json, "string"));
241+
BOOST_CHECK(!isOfTypeIfExists<Json::UInt>(json, "string"));
242+
BOOST_CHECK(!isOfTypeIfExists<Json::UInt64>(json, "string"));
243+
BOOST_CHECK(isOfTypeIfExists<Json::UInt64>(json, "NOT_EXISTING"));
244+
}
245+
246+
BOOST_AUTO_TEST_CASE(json_getOrDefault)
247+
{
248+
Json::Value json;
249+
250+
json["float"] = 3.1f;
251+
json["double"] = 3.1;
252+
json["int"] = 2;
253+
json["int64"] = Json::Int64{0x4000000000000000};
254+
json["uint64"] = Json::UInt64{0x5000000000000000};
255+
json["string"] = "Hello World!";
256+
257+
BOOST_CHECK(getOrDefault<float>(json["float"]) == 3.1f);
258+
BOOST_CHECK(getOrDefault<float>(json["float"], -1.1f) == 3.1f);
259+
BOOST_CHECK(getOrDefault<float>(json["no_float"], -1.1f) == -1.1f);
260+
BOOST_CHECK(getOrDefault<double>(json["double"]) == 3.1);
261+
BOOST_CHECK(getOrDefault<double>(json["double"], -1) == 3.1);
262+
BOOST_CHECK(getOrDefault<double>(json["no_double"], -1.1) == -1.1);
263+
BOOST_CHECK(getOrDefault<int>(json["int"]) == 2);
264+
BOOST_CHECK(getOrDefault<int>(json["int"], -1) == 2);
265+
BOOST_CHECK(getOrDefault<int>(json["no_int"], -1) == -1);
266+
BOOST_CHECK(getOrDefault<Json::Int>(json["int"]) == 2);
267+
BOOST_CHECK(getOrDefault<Json::Int>(json["int"], -1) == 2);
268+
BOOST_CHECK(getOrDefault<Json::Int>(json["no_int"], -1) == -1);
269+
BOOST_CHECK(getOrDefault<Json::UInt>(json["int"]) == 2);
270+
BOOST_CHECK(getOrDefault<Json::UInt>(json["int"], 1) == 2);
271+
BOOST_CHECK(getOrDefault<Json::UInt>(json["no_int"], 1) == 1);
272+
BOOST_CHECK(getOrDefault<Json::Int64>(json["int"]) == 2);
273+
BOOST_CHECK(getOrDefault<Json::Int64>(json["int"], -1) == 2);
274+
BOOST_CHECK(getOrDefault<Json::Int64>(json["no_int"], -1) == -1);
275+
BOOST_CHECK(getOrDefault<Json::Int64>(json["int64"]) == 0x4000000000000000);
276+
BOOST_CHECK(getOrDefault<Json::Int64>(json["int64"], -1) == 0x4000000000000000);
277+
BOOST_CHECK(getOrDefault<Json::Int64>(json["no_int64"], -1) == -1);
278+
BOOST_CHECK(getOrDefault<Json::UInt64>(json["int64"]) == 0x4000000000000000);
279+
BOOST_CHECK(getOrDefault<Json::UInt64>(json["int64"], 1) == 0x4000000000000000);
280+
BOOST_CHECK(getOrDefault<Json::UInt64>(json["no_int64"], 1) == 1);
281+
BOOST_CHECK(getOrDefault<Json::UInt64>(json["uint64"]) == 0x5000000000000000);
282+
BOOST_CHECK(getOrDefault<Json::UInt64>(json["uint64"], 1) == 0x5000000000000000);
283+
BOOST_CHECK(getOrDefault<Json::UInt64>(json["no_uint64"], 1) == 1);
284+
BOOST_CHECK(getOrDefault<std::string>(json["string"], "ERROR") == "Hello World!");
285+
BOOST_CHECK(getOrDefault<std::string>(json["no_string"]).empty());
286+
BOOST_CHECK(getOrDefault<std::string>(json["no_string"], "ERROR") == "ERROR");
287+
}
288+
289+
BOOST_AUTO_TEST_CASE(json_get)
290+
{
291+
Json::Value json;
292+
293+
json["float"] = 3.1f;
294+
json["double"] = 3.1;
295+
json["int"] = 2;
296+
json["int64"] = Json::Int64{0x4000000000000000};
297+
json["uint64"] = Json::UInt64{0x5000000000000000};
298+
json["string"] = "Hello World!";
299+
300+
BOOST_CHECK(get<float>(json["float"]) == 3.1f);
301+
BOOST_CHECK(get<double>(json["double"]) == 3.1);
302+
BOOST_CHECK(get<int>(json["int"]) == 2);
303+
BOOST_CHECK(get<Json::Int>(json["int"]) == 2);
304+
BOOST_CHECK(get<Json::UInt>(json["int"]) == 2);
305+
BOOST_CHECK(get<Json::Int64>(json["int"]) == 2);
306+
BOOST_CHECK(get<Json::Int64>(json["int64"]) == 0x4000000000000000);
307+
BOOST_CHECK(get<Json::UInt64>(json["int64"]) == 0x4000000000000000);
308+
BOOST_CHECK(get<Json::UInt64>(json["uint64"]) == 0x5000000000000000);
309+
BOOST_CHECK(get<std::string>(json["string"]) == "Hello World!");
310+
}
311+
187312
BOOST_AUTO_TEST_SUITE_END()
188313

189314
}

0 commit comments

Comments
 (0)