Skip to content

Implemented as<T>() and is<T>() with accompanying tests #1075

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

Closed
wants to merge 3 commits into from
Closed
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
47 changes: 47 additions & 0 deletions include/json/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,33 @@ class JSON_API Value {
double asDouble() const;
bool asBool() const;

template <class T> struct asLookupHelper;

#define defAsLookupHelper(type, lookup) \
template <> struct asLookupHelper<type> { \
static type as(const Value& val) { return val.lookup(); } \
}

defAsLookupHelper(const char*, asCString);
defAsLookupHelper(String, asString);
#ifdef JSON_USE_CPPTL
defAsLookupHelper(CppTL::ConstString, asConstString);
#endif
defAsLookupHelper(Int, asInt);
defAsLookupHelper(UInt, asUInt);
#if defined(JSON_HAS_INT64)
defAsLookupHelper(Int64, asInt64);
defAsLookupHelper(UInt64, asUInt64);
#endif // if defined(JSON_HAS_INT64)
// (U)LargestInt is a type alias of int or int64 and thus cannot be defined
defAsLookupHelper(float, asFloat);
defAsLookupHelper(double, asDouble);
defAsLookupHelper(bool, asBool);

#undef defAsLookupHelper

template <class T> T as() const { return asLookupHelper<T>::as(*this); }

bool isNull() const;
bool isBool() const;
bool isInt() const;
Expand All @@ -412,6 +439,26 @@ class JSON_API Value {
bool isArray() const;
bool isObject() const;

template <class T> struct isLookupHelper;

#define defIsLookupHelper(type, lookup) \
template <> struct isLookupHelper<type> { \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can avoid macros here. There are only a few types.
The "helper" structs are not needed.
They should have better names if they remain, and not be public.

We should be able to implement the as<T> and is<T> as member function template specializations directly, without forwarding to a helper struct.

static bool is(const Value& val) { return val.lookup(); } \
}

defIsLookupHelper(bool, isBool);
defIsLookupHelper(Int, isInt);
defIsLookupHelper(Int64, isInt64);
defIsLookupHelper(UInt, isUInt);
defIsLookupHelper(UInt64, isUInt64);
defIsLookupHelper(double, isDouble);
defIsLookupHelper(const char*, isString);
defIsLookupHelper(String, isString);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you've invented a new accessor: is<const char*>.
It does the same thing as is<String> but has a distinct name. I think that's confusing and we should remove the const char* specialization.


#undef defIsLookupHelper

template <class T> bool is() const { return isLookupHelper<T>::is(*this); }

bool isConvertibleTo(ValueType other) const;

/// Number of values in array or object
Expand Down
111 changes: 111 additions & 0 deletions src/test_lib_json/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3361,6 +3361,117 @@ int main(int argc, const char* argv[]) {
return runner.runCommandLine(argc, argv);
}

struct TemplatedAs : JsonTest::TestCase {};

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorCString) {
Json::Value json = "hello world";
JSONTEST_ASSERT_STRING_EQUAL(json.asCString(), json.as<const char*>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorString) {
Json::Value json = "hello world";
JSONTEST_ASSERT_STRING_EQUAL(json.asString(), json.as<Json::String>());
}

#ifdef JSON_USE_CPPTL
JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorConstString) {
Json::Value json = "hello world";
JSONTEST_ASSERT_STRING_EQUAL(json.asConstString(),
json.as<CppTL::ConstString>());
}
#endif

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorInt) {
Json::Value json = Json::Int(64);
JSONTEST_ASSERT_EQUAL(json.asInt(), json.as<Json::Int>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorUInt) {
Json::Value json = Json::UInt(64);
JSONTEST_ASSERT_EQUAL(json.asUInt(), json.as<Json::UInt>());
}

#if defined(JSON_HAS_INT64)
JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorInt64) {
Json::Value json = Json::Int64(64);
JSONTEST_ASSERT_EQUAL(json.asUInt64(), json.as<Json::Int64>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorUInt64) {
Json::Value json = Json::UInt64(64);
JSONTEST_ASSERT_EQUAL(json.asUInt64(), json.as<Json::UInt64>());
}
#endif // if defined(JSON_HAS_INT64)

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorLargestInt) {
Json::Value json = Json::LargestInt(64);
JSONTEST_ASSERT_EQUAL(json.asLargestInt(), json.as<Json::LargestInt>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorLargestUInt) {
Json::Value json = Json::LargestUInt(64);
JSONTEST_ASSERT_EQUAL(json.asLargestUInt(), json.as<Json::LargestUInt>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorFloat) {
Json::Value json = float(69.69);
JSONTEST_ASSERT_EQUAL(json.asFloat(), json.as<float>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorDouble) {
Json::Value json = double(69.69);
JSONTEST_ASSERT_EQUAL(json.asDouble(), json.as<double>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedAs, equalBehaviorBool) {
Json::Value jsonTrue = true;
Json::Value jsonFalse = false;
JSONTEST_ASSERT_EQUAL(jsonTrue.asBool(), jsonTrue.as<bool>());
JSONTEST_ASSERT_EQUAL(jsonFalse.asBool(), jsonFalse.as<bool>());
}

struct TemplatedIs : JsonTest::TestCase {};

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsBool) {
Json::Value json = true;
JSONTEST_ASSERT_EQUAL(json.isBool(), json.is<bool>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsInt) {
Json::Value json = 142;
JSONTEST_ASSERT_EQUAL(json.isInt(), json.is<Json::Int>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsInt64) {
Json::Value json = 142;
JSONTEST_ASSERT_EQUAL(json.isInt64(), json.is<Json::Int64>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsUInt) {
Json::Value json = 142;
JSONTEST_ASSERT_EQUAL(json.isUInt(), json.is<Json::UInt>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsUInt64) {
Json::Value json = 142;
JSONTEST_ASSERT_EQUAL(json.isUInt64(), json.is<Json::UInt64>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsDouble) {
Json::Value json = 40.63;
JSONTEST_ASSERT_EQUAL(json.isDouble(), json.is<double>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsCString) {
Json::Value json = "hello world";
JSONTEST_ASSERT_EQUAL(json.isString(), json.is<const char*>());
}

JSONTEST_FIXTURE_LOCAL(TemplatedIs, equalBehaviorIsString) {
Json::Value json = "hello world";
JSONTEST_ASSERT_EQUAL(json.isString(), json.is<Json::String>());
}

#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif