#ifndef GRAPH_UTILS_JSON_HPP
#define GRAPH_UTILS_JSON_HPP
#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <unordered_map>
namespace dnnl {
namespace impl {
namespace graph {
namespace utils {
namespace json {
template <bool cond, typename Then, typename Else>
struct if_else_type;
template <typename T>
struct json_handler_t;
template <typename T>
struct common_json_t;
class json_writer_t {
public:
json_writer_t(std::ostream *os) : os_(os) {}
inline void begin_object();
inline void end_object();
template <typename valuetype>
inline void write_keyvalue(const std::string &key, const valuetype &value);
template <typename valuetype>
inline void write_number(const valuetype &v);
inline void write_string(const std::string &s);
inline void begin_array(bool multi_line = true);
inline void end_array();
inline void write_array_seperator();
template <typename valuetype>
inline void write_array_item(const valuetype &value);
inline void write_newline();
private:
std::ostream *os_;
std::vector<size_t> scope_count_;
std::vector<bool> scope_multi_line_;
inline void write_seperator();
};
class json_reader_t {
public:
explicit json_reader_t(std::istream *is) : is_(is) {}
inline void read_string(std::string *out_str);
template <typename valuetype>
inline void read_number(valuetype *out_value);
inline void begin_object();
inline void begin_array();
inline bool next_object_item(std::string *out_key);
inline bool next_array_item();
template <typename valuetype>
inline void read(valuetype *out_value);
private:
std::istream *is_;
std::vector<size_t> scope_count_;
inline int next_nonspace();
inline int peeknext_nonspace();
inline int next_char();
inline int peeknext_char();
};
class read_helper_t {
public:
template <typename T>
inline void declare_field(const std::string &key, T *addr) {
if (map_.count(key) == 0) {
entry_t e;
e.func = reader_function<T>;
e.addr = static_cast<void *>(addr);
map_[key] = e;
}
}
inline bool read_fields(json_reader_t *reader);
private:
template <typename T>
inline static void reader_function(json_reader_t *reader, void *addr);
using readfunc = void (*)(json_reader_t *reader, void *addr);
struct entry_t {
readfunc func;
void *addr;
};
std::map<std::string, entry_t> map_;
};
template <typename then, typename other>
struct if_else_type<true, then, other> {
using type = then;
};
template <typename then, typename other>
struct if_else_type<false, then, other> {
using type = other;
};
template <typename valuetype>
struct num_json_t {
inline static void write(json_writer_t *writer, const valuetype &value) {
writer->write_number<valuetype>(value);
}
inline static void read(json_reader_t *reader, valuetype *value) {
reader->read_number<valuetype>(value);
}
};
template <typename valuetype>
struct common_json_t {
inline static void write(json_writer_t *writer, const valuetype &value) {
value.save(writer);
}
inline static void read(json_reader_t *reader, valuetype *value) {
value->load(reader);
}
};
template <typename valuetype>
struct common_json_t<std::shared_ptr<valuetype>> {
inline static void write(
json_writer_t *writer, const std::shared_ptr<valuetype> &value) {
auto *v = value.get();
v->save(writer);
}
inline static void read(
json_reader_t *reader, std::shared_ptr<valuetype> *value) {
auto ptr = std::make_shared<valuetype>();
auto *v = ptr.get();
v->load(reader);
*value = std::move(ptr);
}
};
template <typename CT>
struct array_json_t {
inline static void write(json_writer_t *writer, const CT &array) {
writer->begin_array();
for (typename CT::const_iterator it = array.begin(); it != array.end();
++it) {
writer->write_array_item(*it);
}
writer->end_array();
}
inline static void read(json_reader_t *reader, CT *array) {
using elemtype = typename CT::value_type;
array->clear();
reader->begin_array();
while (reader->next_array_item()) {
elemtype value;
json_handler_t<elemtype>::read(reader, &value);
array->insert(array->end(), value);
}
}
};
template <typename CT>
struct map_json_t {
inline static void write(json_writer_t *writer, const CT &map) {
writer->begin_object();
for (typename CT::const_iterator it = map.begin(); it != map.end();
++it) {
writer->write_keyvalue(it->first, it->second);
}
writer->end_object();
}
inline static void read(json_reader_t *reader, CT *map) {
using elemtype = typename CT::mapped_type;
map->clear();
reader->begin_object();
std::string key;
while (reader->next_object_item(&key)) {
elemtype value;
reader->read(&value);
(*map)[key] = std::move(value);
}
}
};
template <>
struct json_handler_t<std::string> {
inline static void write(json_writer_t *writer, const std::string &value) {
writer->write_string(value);
}
inline static void read(json_reader_t *reader, std::string *str) {
reader->read_string(str);
}
};
template <typename T>
struct json_handler_t<std::map<std::string, T>>
: public map_json_t<std::map<std::string, T>> {};
template <typename T>
struct json_handler_t<std::unordered_map<std::string, T>>
: public map_json_t<std::unordered_map<std::string, T>> {};
template <typename T>
struct json_handler_t<std::vector<T>> : public array_json_t<std::vector<T>> {};
template <typename T>
struct json_handler_t<std::list<T>> : public array_json_t<std::list<T>> {};
template <typename T>
struct json_handler_t {
inline static void write(json_writer_t *writer, const T &data) {
using Tjson = typename if_else_type<std::is_arithmetic<T>::value,
num_json_t<T>, common_json_t<T>>::type;
Tjson::write(writer, data);
}
inline static void read(json_reader_t *reader, T *data) {
using Tjson = typename if_else_type<std::is_arithmetic<T>::value,
num_json_t<T>, common_json_t<T>>::type;
Tjson::read(reader, data);
}
};
inline void json_writer_t::begin_object() {
*os_ << "{";
scope_multi_line_.push_back(true);
scope_count_.push_back(0);
}
template <typename valuetype>
inline void json_writer_t::write_keyvalue(
const std::string &key, const valuetype &value) {
if (scope_count_.back() > 0) { *os_ << ","; }
write_seperator();
*os_ << '\"';
*os_ << key;
*os_ << "\": ";
scope_count_.back() += 1;
json_handler_t<valuetype>::write(this, value);
}
template <typename valuetype>
inline void json_writer_t::write_number(const valuetype &v) {
*os_ << v;
}
inline void json_writer_t::write_string(const std::string &s) {
*os_ << '\"';
for (size_t i = 0; i < s.length(); ++i) {
char ch = s[i];
switch (ch) {
case '\r': *os_ << "\\r"; break;
case '\n': *os_ << "\\n"; break;
case '\\': *os_ << "\\\\"; break;
case '\t': *os_ << "\\t"; break;
case '\"': *os_ << "\\\""; break;
default: *os_ << ch;
}
}
*os_ << '\"';
}
inline void json_writer_t::begin_array(bool multi_line) {
*os_ << '[';
scope_multi_line_.push_back(multi_line);
scope_count_.push_back(0);
}
inline void json_writer_t::end_array() {
if (!scope_count_.empty() && !scope_multi_line_.empty()) {
bool newline = scope_multi_line_.back();
size_t nelem = scope_count_.back();
scope_multi_line_.pop_back();
scope_count_.pop_back();
if (newline && nelem != 0) write_seperator();
}
*os_ << ']';
}
inline void json_writer_t::write_array_seperator() {
if (scope_count_.back() != 0) { *os_ << ","; }
scope_count_.back() += 1;
write_seperator();
}
template <typename valuetype>
inline void json_writer_t::write_array_item(const valuetype &value) {
this->write_array_seperator();
json::json_handler_t<valuetype>::write(this, value);
}
inline void json_writer_t::end_object() {
if (!scope_count_.empty() && !scope_multi_line_.empty()) {
bool newline = scope_multi_line_.back();
size_t nelem = scope_count_.back();
scope_multi_line_.pop_back();
scope_count_.pop_back();
if (newline && nelem != 0) write_seperator();
}
*os_ << '}';
}
inline void json_writer_t::write_seperator() {
if (scope_multi_line_.empty() || scope_multi_line_.back()) {
*os_ << '\n';
*os_ << std::string(scope_multi_line_.size() * 2, ' ');
}
}
inline void json_writer_t::write_newline() {
*os_ << '\n';
}
inline int json_reader_t::next_char() {
return is_->get();
}
inline int json_reader_t::peeknext_char() {
return is_->peek();
}
inline int json_reader_t::next_nonspace() {
int ch;
do {
ch = next_char();
} while (isspace(ch));
return ch;
}
inline int json_reader_t::peeknext_nonspace() {
int ch;
while (true) {
ch = peeknext_char();
if (!isspace(ch)) break;
next_char();
}
return ch;
}
inline void json_reader_t::read_string(std::string *out_str) {
int ch = next_nonspace();
if (ch == '\"') {
std::ostringstream output;
while (true) {
ch = next_char();
if (ch == '\\') {
char sch = static_cast<char>(next_char());
switch (sch) {
case 'r': output << "\r"; break;
case 'n': output << "\r"; break;
case '\\': output << "\r"; break;
case 't': output << "\r"; break;
case '\"': output << "\r"; break;
default: throw("unknown string escape.");
}
} else {
if (ch == '\"') break;
output << static_cast<char>(ch);
}
if (ch == EOF || ch == '\r' || ch == '\n') {
throw("error at!");
return;
}
}
*out_str = output.str();
}
}
template <typename valuetype>
inline void json_reader_t::read_number(valuetype *out_value) {
*is_ >> *out_value;
}
inline void json_reader_t::begin_object() {
int ch = next_nonspace();
if (ch == '{') { scope_count_.push_back(0); }
}
inline void json_reader_t::begin_array() {
int ch = next_nonspace();
if (ch == '[') { scope_count_.push_back(0); }
}
inline bool json_reader_t::next_object_item(std::string *out_key) {
bool next = true;
if (scope_count_.empty()) { return false; }
if (scope_count_.back() != 0) {
int ch = next_nonspace();
if (ch == EOF) {
next = false;
} else if (ch == '}') {
next = false;
} else {
if (ch != ',') { return false; }
}
} else {
int ch = peeknext_nonspace();
if (ch == '}') {
next_char();
next = false;
}
}
if (!next) {
scope_count_.pop_back();
return false;
} else {
scope_count_.back() += 1;
read_string(out_key);
int ch = next_nonspace();
return (ch == ':');
}
}
inline bool json_reader_t::next_array_item() {
bool next = true;
if (scope_count_.empty()) { return false; }
if (scope_count_.back() != 0) {
int ch = next_nonspace();
if (ch == EOF) {
next = false;
} else if (ch == ']') {
next = false;
} else {
if (ch != ',') { return false; }
}
} else {
int ch = peeknext_nonspace();
if (ch == ']') {
next_char();
next = false;
}
}
if (!next) {
scope_count_.pop_back();
return false;
} else {
scope_count_.back() += 1;
return true;
}
}
template <typename valuetype>
inline void json_reader_t::read(valuetype *out_value) {
json::json_handler_t<valuetype>::read(this, out_value);
}
inline bool read_helper_t::read_fields(json_reader_t *reader) {
reader->begin_object();
std::map<std::string, int> visited;
std::string key;
while (reader->next_object_item(&key)) {
if (map_.count(key) != 0) {
entry_t e = map_[key];
(*e.func)(reader, e.addr);
visited[key] = 0;
}
}
if (visited.size() != map_.size()) {
for (std::map<std::string, entry_t>::iterator it = map_.begin();
it != map_.end(); ++it) {
if (visited.count(it->first) != 1) { return false; }
}
}
return true;
}
template <typename T>
inline void read_helper_t::reader_function(json_reader_t *reader, void *addr) {
json::json_handler_t<T>::read(reader, static_cast<T *>(addr));
}
} } } } }
#endif