Skip to content

Commit

Permalink
is_[type] for json_t along with empty() and size() (#1082)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenberry authored Jun 12, 2024
1 parent bf90daf commit 21c62fb
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 17 deletions.
88 changes: 77 additions & 11 deletions include/glaze/json/json_t.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,31 @@ namespace glz
val_t data{};

template <class T>
T& get()
[[nodiscard]] T& get()
{
return std::get<T>(data);
}

template <class T>
const T& get() const
[[nodiscard]] const T& get() const
{
return std::get<T>(data);
}

template <class T>
T* get_if() noexcept
[[nodiscard]] T* get_if() noexcept
{
return std::get_if<T>(&data);
}

template <class T>
const T* get_if() const noexcept
[[nodiscard]] const T* get_if() const noexcept
{
return std::get_if<T>(&data);
}

template <class T>
bool holds() const noexcept
[[nodiscard]] bool holds() const noexcept
{
return std::holds_alternative<T>(data);
}
Expand Down Expand Up @@ -79,11 +79,11 @@ namespace glz
return iter->second;
}

json_t& at(std::convertible_to<std::string_view> auto&& key) { return operator[](key); }
[[nodiscard]] json_t& at(std::convertible_to<std::string_view> auto&& key) { return operator[](key); }

const json_t& at(std::convertible_to<std::string_view> auto&& key) const { return operator[](key); }
[[nodiscard]] const json_t& at(std::convertible_to<std::string_view> auto&& key) const { return operator[](key); }

bool contains(std::convertible_to<std::string_view> auto&& key) const
[[nodiscard]] bool contains(std::convertible_to<std::string_view> auto&& key) const
{
if (!holds<object_t>()) return false;
auto& object = std::get<object_t>(data);
Expand Down Expand Up @@ -145,28 +145,94 @@ namespace glz
}

template <class T>
T as() const
[[nodiscard]] T as() const
{
// Prefer get becuase it returns a reference
return get<T>();
}

template <class T>
requires std::convertible_to<double, T>
T as() const
[[nodiscard]] T as() const
{
// Can be used for int and the like
return static_cast<T>(get<double>());
}

template <class T>
requires std::convertible_to<std::string, T>
T as() const
[[nodiscard]] T as() const
{
// Can be used for string_view and the like
return get<std::string>();
}

[[nodiscard]] bool is_array() const noexcept {
return holds<json_t::array_t>();
}

[[nodiscard]] bool is_object() const noexcept {
return holds<json_t::object_t>();
}

[[nodiscard]] bool is_number() const noexcept {
return holds<double>();
}

[[nodiscard]] bool is_string() const noexcept {
return holds<std::string>();
}

[[nodiscard]] bool is_null() const noexcept {
return holds<std::nullptr_t>();
}

// empty() returns true if the value is an empty JSON object, array, or string, or a null value
// otherwise returns false
[[nodiscard]] bool empty() const noexcept {
if (auto* v = get_if<object_t>(); v) {
return v->empty();
}
else if (auto* v = get_if<array_t>(); v) {
return v->empty();
}
else if (auto* v = get_if<std::string>(); v) {
return v->empty();
}
else if (is_null()) {
return true;
}
else {
return false;
}
}

// returns the count of items in an object or an array, or the size of a string, otherwise returns zero
[[nodiscard]] size_t size() const noexcept {
if (auto* v = get_if<object_t>(); v) {
return v->size();
}
else if (auto* v = get_if<array_t>(); v) {
return v->size();
}
else if (auto* v = get_if<std::string>(); v) {
return v->size();
}
else {
return 0;
}
}
};

[[nodiscard]] inline bool is_array(const json_t& value) { return value.is_array(); }

[[nodiscard]] inline bool is_object(const json_t& value) { return value.is_object(); }

[[nodiscard]] inline bool is_number(const json_t& value) { return value.is_number(); }

[[nodiscard]] inline bool is_string(const json_t& value) { return value.is_string(); }

[[nodiscard]] inline bool is_null(const json_t& value) { return value.is_null(); }
}

template <>
Expand Down
78 changes: 72 additions & 6 deletions tests/json_test/json_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3112,6 +3112,78 @@ suite generic_json_tests = [] {
expect(not glz::write_json(glz::json_t(*(glz::read_json<glz::json_t>("{}"))), s));
expect(s == "{}") << s;
};

"json_t is_object"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, "{}"));
expect(json.is_object());
expect(glz::is_object(json));
expect(json.empty());
expect(json.size() == 0);
};

"json_t is_object"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, R"({"age":"22","name":"Noah"})"));
expect(json.is_object());
expect(glz::is_object(json));
expect(not json.empty());
expect(json.size() == 2);
};

"json_t is_array"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, "[]"));
expect(json.is_array());
expect(glz::is_array(json));
expect(json.empty());
expect(json.size() == 0);
};

"json_t is_array"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, "[1,2,3]"));
expect(json.is_array());
expect(glz::is_array(json));
expect(not json.empty());
expect(json.size() == 3);
};

"json_t is_string"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, R"("")"));
expect(json.is_string());
expect(glz::is_string(json));
expect(json.empty());
expect(json.size() == 0);
};

"json_t is_string"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, R"("Beautiful beginning")"));
expect(json.is_string());
expect(glz::is_string(json));
expect(not json.empty());
expect(json.size() == 19);
};

"json_t is_number"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, "3.882e2"));
expect(json.is_number());
expect(glz::is_number(json));
expect(not json.empty());
expect(json.size() == 0);
};

"json_t is_null"_test = [] {
glz::json_t json{};
expect(not glz::read_json(json, "null"));
expect(json.is_null());
expect(glz::is_null(json));
expect(json.empty());
expect(json.size() == 0);
};
};

struct holder0_t
Expand Down Expand Up @@ -4413,12 +4485,6 @@ suite validation_tests = [] {
expect(ec_fail17 != glz::error_code::none);
expect(glz::validate_json(fail17) != glz::error_code::none);

// JSON spec does not specify a nesting limit to my knowledge
// std::string fail18 = R"([[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]])";
// auto ec_fail18 = glz::read<glz::opts{.force_conformance = true}>(json, fail18);
// expect(ec_fail18 != glz::error_code::none);
// expect(glz::validate_json(fail18) != glz::error_code::none);

std::string fail19 = R"({"Missing colon" null})";
auto ec_fail19 = glz::read<glz::opts{.force_conformance = true}>(json, fail19);
expect(ec_fail19 != glz::error_code::none);
Expand Down

0 comments on commit 21c62fb

Please sign in to comment.