Skip to content

Commit

Permalink
Merge pull request #115 from qicosmos/add_get
Browse files Browse the repository at this point in the history
add get
  • Loading branch information
qicosmos authored Dec 10, 2022
2 parents c45ef05 + d581832 commit f9df3c4
Show file tree
Hide file tree
Showing 6 changed files with 447 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:

- name: test
working-directory: ${{ github.workspace }}/build
run: ctest -C ${{ matrix.mode }} -j `nproc` -V
run: ctest -C ${{ matrix.mode }} -j 1 `nproc` -V
51 changes: 50 additions & 1 deletion iguana/error_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace iguana {
class iguana_category : public std::error_category {
public:
virtual const char *name() const noexcept override {
return "iguna::category";
return "iguana::category";
}
virtual std::string message(int err_val) const override {
for (auto &pair : err_map_) {
Expand Down Expand Up @@ -46,4 +46,53 @@ inline std::error_code make_error_code(const std::string data = "") {
auto err = iguana::category().add_message(data);
return std::error_code(err, iguana::category());
}

// dom parse error code
enum class dom_errc {
ok = 0,
wrong_type,
};

class iguana_dom_category : public std::error_category {
public:
virtual const char *name() const noexcept override {
return "iguana::dom_category";
}
virtual std::string message(int err_val) const override {
switch (static_cast<dom_errc>(err_val)) {
case dom_errc::ok:
return "ok";
case dom_errc::wrong_type: {
auto it = detail_msg_map_.find(dom_errc::wrong_type);
if (it != detail_msg_map_.end()) {
return std::string("wrong type, ")
.append("real type is ")
.append(it->second);
} else {
return "wrong type";
}
}
default:
return "(unrecognized error)";
}
}

// private:
std::map<iguana::dom_errc, std::string> detail_msg_map_;
};

iguana::iguana_dom_category &dom_category() {
static iguana::iguana_dom_category instance;
return instance;
}

inline std::error_code make_error_code(iguana::dom_errc err,
const std::string &error_msg) {
auto &instance = iguana::dom_category();
if (!error_msg.empty()) {
instance.detail_msg_map_.emplace(err, error_msg);
}

return std::error_code((int)err, instance);
}
} // namespace iguana
29 changes: 24 additions & 5 deletions iguana/json_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
match<'"'>(it, end);
}

inline void skip_object_value(auto &&it, auto &&end) {
IGUANA_INLINE void skip_object_value(auto &&it, auto &&end) {
skip_ws(it, end);
while (it != end) {
switch (*it) {
Expand Down Expand Up @@ -627,8 +627,10 @@ template <typename It>
inline void parse_array(jarray &result, It &&it, It &&end) {
skip_ws(it, end);
match<'['>(it, end);
if (*it == ']')
if (*it == ']') [[unlikely]] {
++it;
return;
}
while (true) {
if (it == end) {
break;
Expand All @@ -637,20 +639,22 @@ inline void parse_array(jarray &result, It &&it, It &&end) {

parse(result.back(), it, end);

if (*it == ']') {
if (*it == ']') [[unlikely]] {
++it;
return;
}

match<','>(it, end);
}
throw std::runtime_error("Expected ]");
}

template <typename It>
inline void parse_object(jobject &result, It &&it, It &&end) {
skip_ws(it, end);
match<'{'>(it, end);
if (*it == '}') {
if (*it == '}') [[unlikely]] {
++it;
return;
}

Expand All @@ -671,7 +675,7 @@ inline void parse_object(jobject &result, It &&it, It &&end) {

parse(emplaced.first->second, it, end);

if (*it == '}') {
if (*it == '}') [[unlikely]] {
++it;
return;
}
Expand Down Expand Up @@ -742,6 +746,21 @@ inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) {
}
}

template <typename T, json_view View>
inline void parse(T &result, const View &view) {
parse(result, std::begin(view), std::end(view));
}

template <typename T, json_view View>
inline void parse(T &result, const View &view, std::error_code &ec) noexcept {
try {
parse(result, view);
ec = {};
} catch (std::runtime_error &e) {
ec = iguana::make_error_code(e.what());
}
}

template <typename T, typename It>
IGUANA_INLINE void from_json(T &value, It &&it, It &&end) {
static_assert(!sizeof(T), "The type is not support, please check if you have "
Expand Down
130 changes: 102 additions & 28 deletions iguana/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <variant>
#include <vector>

#include "error_code.h"

namespace iguana {

#define GCC_COMPILER (defined(__GNUC__) && !defined(__clang__))
Expand All @@ -19,6 +21,8 @@ template <class Key, class T, typename... Args>
using json_map = std::unordered_map<Key, T, Args...>;
#endif

enum dom_parse_error { ok, wrong_type };

template <typename CharT>
struct basic_json_value
: std::variant<
Expand All @@ -34,6 +38,11 @@ struct basic_json_value

using base_type::base_type;

inline const static std::unordered_map<size_t, std::string> type_map_ = {
{0, "undefined type"}, {1, "null type"}, {2, "bool type"},
{3, "double type"}, {4, "int type"}, {5, "string type"},
{6, "array type"}, {7, "object type"}};

basic_json_value() : base_type(std::in_place_type<std::monostate>) {}

basic_json_value(CharT const *value)
Expand All @@ -54,40 +63,105 @@ struct basic_json_value
bool is_array() const { return std::holds_alternative<array_type>(*this); }
bool is_object() const { return std::holds_alternative<object_type>(*this); }

array_type to_array() const {
if (is_array())
return std::get<array_type>(*this);
return {};
// if type is not match, will throw exception, if pass std::error_code, won't
// throw exception
template <typename T> T get() const {
try {
return std::get<T>(*this);
} catch (std::exception &e) {
auto it = type_map_.find(this->index());
if (it == type_map_.end()) {
throw std::invalid_argument("undefined type");
} else {
throw std::invalid_argument(it->second);
}
} catch (...) {
throw std::invalid_argument("unknown exception");
}
}

template <typename T> T get(std::error_code &ec) const {
try {
return get<T>();
} catch (std::exception &e) {
ec = iguana::make_error_code(iguana::dom_errc::wrong_type, e.what());
return T{};
}
}

template <typename T> std::error_code get_to(T &v) const {
std::error_code ec;
v = get<T>(ec);
return ec;
}

template <typename T> T at(const std::string &key) {
const auto &map = get<object_type>();
auto it = map.find(key);
if (it == map.end()) {
throw std::invalid_argument("the key is unknown");
}
return it->second.template get<T>();
}

template <typename T> T at(const std::string &key, std::error_code &ec) {
const auto &map = get<object_type>(ec);
if (ec) {
return T{};
}

auto it = map.find(key);
if (it == map.end()) {
ec = std::make_error_code(std::errc::invalid_argument);
return T{};
}
return it->second.template get<T>(ec);
}

template <typename T> T at(size_t idx) {
const auto &arr = get<array_type>();
if (idx >= arr.size()) {
throw std::out_of_range("idx is out of range");
}
return arr[idx].template get<T>();
}

object_type to_object() const {
if (is_object())
return std::get<object_type>(*this);
return {};
template <typename T> T at(size_t idx, std::error_code &ec) {
const auto &arr = get<array_type>(ec);
if (ec) {
return T{};
}

if (idx >= arr.size()) {
ec = std::make_error_code(std::errc::result_out_of_range);
return T{};
}

return arr[idx].template get<T>(ec);
}

double to_double(bool *ok = nullptr) const {
if (ok)
*ok = true;
if (is_double())
return std::get<double>(*this);
if (is_int())
return static_cast<double>(std::get<int>(*this));
if (ok)
*ok = false;
return {};
object_type to_object() const { return get<object_type>(); }
object_type to_object(std::error_code &ec) const {
return get<object_type>(ec);
}

double to_int(bool *ok = nullptr) const {
if (ok)
*ok = true;
if (is_double())
return static_cast<int>(std::get<double>(*this));
if (is_int())
return std::get<int>(*this);
if (ok)
*ok = false;
return {};
array_type to_array() const { return get<array_type>(); }
array_type to_array(std::error_code &ec) const { return get<array_type>(ec); }

double to_double() const { return get<double>(); }
double to_double(std::error_code &ec) const { return get<double>(ec); }

int to_int() const { return get<int>(); }
int to_int(std::error_code &ec) const { return get<int>(ec); }

bool to_bool() const { return get<bool>(); }
bool to_bool(std::error_code &ec) const { return get<bool>(ec); }

std::basic_string<CharT> to_string() const {
return get<std::basic_string<CharT>>();
}
std::basic_string<CharT> to_string(std::error_code &ec) const {
return get<std::basic_string<CharT>>(ec);
}
};

Expand Down
Loading

0 comments on commit f9df3c4

Please sign in to comment.