|
|
@@ -30,328 +30,40 @@ namespace json {
|
|
|
template <typename T>
|
|
|
class binder {
|
|
|
public:
|
|
|
- binder() : impl(nullptr), owned(false) {}
|
|
|
- binder(binder const& other) : impl(other.impl->clone()), owned(true) {}
|
|
|
- binder(binder_impl<T> const* p) : impl(p), owned(true) {}
|
|
|
- binder(binder_impl<T> const& r) : impl(&r), owned(false) {}
|
|
|
- ~binder() { if (impl && owned) delete impl; }
|
|
|
-
|
|
|
- void parse(T& object, char const*& data) const {
|
|
|
- if (!impl) return;
|
|
|
- impl->parse(object, data);
|
|
|
- }
|
|
|
-
|
|
|
- void write(T const& object, std::string & data) const {
|
|
|
- if (!impl) return;
|
|
|
- impl->write(object, data);
|
|
|
- }
|
|
|
- private:
|
|
|
- binder_impl<T> const* impl;
|
|
|
- bool owned;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T, typename E>
|
|
|
- class direct_binder : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(E T::*p, binder<E> const& i) : ptr(p), impl(i) {}
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
-
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
- impl.parse(val.*ptr, data);
|
|
|
- }
|
|
|
-
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- impl.write(val.*ptr, data);
|
|
|
- }
|
|
|
- private:
|
|
|
- E T::*ptr;
|
|
|
- binder<E> impl;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class direct_binder<T, bool> : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(bool T::*p) : ptr(p) {}
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
-
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
- if (!strncmp(data, "true", 4)) {
|
|
|
- val.*ptr = true;
|
|
|
- } else if (!strncmp(data, "false", 5)) {
|
|
|
- val.*ptr = false;
|
|
|
- } else {
|
|
|
- throw json::malformed_json_exception("Expected a boolean type here");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- data += (val.*ptr ? "true" : "false");
|
|
|
- }
|
|
|
-
|
|
|
- private:
|
|
|
- bool T::*ptr;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class direct_binder<T, int> : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(int T::*p) : ptr(p) {}
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
-
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
-// if (false) {
|
|
|
- json::helper::parse_numeric(val.*ptr, data);
|
|
|
-// } else {
|
|
|
-// throw json::malformed_json_exception("Expected an integral type here");
|
|
|
-// }
|
|
|
+ binder() :
|
|
|
+ impl(nullptr) {
|
|
|
}
|
|
|
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- char buffer[16] = { '\0' };
|
|
|
- snprintf(buffer, sizeof(buffer), "%d", val.*ptr);
|
|
|
- data += buffer;
|
|
|
- }
|
|
|
- private:
|
|
|
- int T::*ptr;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class direct_binder<T, double> : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(double T::*p) : ptr(p) {}
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
-
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
-// if (false) {
|
|
|
- json::helper::parse_numeric(val.*ptr, data);
|
|
|
-// } else {
|
|
|
-// throw json::malformed_json_exception("Expected a floating point type here");
|
|
|
-// }
|
|
|
+ binder(binder const& other) :
|
|
|
+ impl(other.impl->clone()) {
|
|
|
}
|
|
|
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- char buffer[32] = { '\0' };
|
|
|
- snprintf(buffer, sizeof(buffer), "%lf", val.*ptr);
|
|
|
- data += buffer;
|
|
|
- }
|
|
|
- private:
|
|
|
- double T::*ptr;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class direct_binder<T, std::string> : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(std::string T::*p) : ptr(p) {}
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
-
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
- json::helper::parse_string(val.*ptr, data);
|
|
|
+ binder(binder_impl<T> const* p) :
|
|
|
+ impl(p) {
|
|
|
}
|
|
|
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- data += "\"" + val.*ptr + "\"";
|
|
|
+ binder(binder_impl<T> const& r) :
|
|
|
+ impl(r.clone()) {
|
|
|
}
|
|
|
- private:
|
|
|
- std::string T::*ptr;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T, typename V>
|
|
|
- class direct_binder<T, std::vector<V> > : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(std::vector<V> T::*p, binder<V> const&i);
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
- const char ch = json::helper::get_next_element(data);
|
|
|
- if (ch != '[') {
|
|
|
- throw json::malformed_json_exception("Expected an array type");
|
|
|
+ ~binder() {
|
|
|
+ if (impl) {
|
|
|
+ delete impl;
|
|
|
+ impl = nullptr;
|
|
|
}
|
|
|
- ++data;
|
|
|
-
|
|
|
- V to_make;
|
|
|
- std::vector<V>& vec = val.*ptr;
|
|
|
- while (*data && *data != ']') {
|
|
|
- impl.parse(to_make, data);
|
|
|
- vec.emplace_back(to_make);
|
|
|
- json::helper::advance_to_boundary<']'>(data);
|
|
|
- }
|
|
|
- if (*data) ++data;
|
|
|
- else throw json::malformed_json_exception("Reached end of parse string without finding array end");
|
|
|
}
|
|
|
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- data += "[";
|
|
|
- std::vector<V> const & vec = val.*ptr;
|
|
|
- for (typename std::vector<V>::const_iterator it = vec.begin(),
|
|
|
- end = vec.end(); it != end; ++it) {
|
|
|
- impl.write(*it, data);
|
|
|
- data += ",";
|
|
|
- }
|
|
|
- data.back() = ']';
|
|
|
- }
|
|
|
- private:
|
|
|
- std::vector<V> T::*ptr;
|
|
|
- binder<V> impl;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T, typename V>
|
|
|
- class direct_binder<T, std::map<std::string, V> > : public binder_impl<T> {
|
|
|
- public:
|
|
|
- direct_binder(std::vector<V> T::*p, binder<V> const&i);
|
|
|
- virtual binder_impl<T>* clone() const override { return new direct_binder(*this); }
|
|
|
-
|
|
|
- virtual void parse(T& val, char const*& data) const override {
|
|
|
- const char ch = json::helper::get_next_element(data);
|
|
|
- if (ch != '{') {
|
|
|
- throw json::malformed_json_exception("Expected an array type");
|
|
|
- }
|
|
|
- ++data;
|
|
|
-
|
|
|
- V to_make;
|
|
|
- std::map<std::string, V>& vec = val.*ptr;
|
|
|
- std::string key;
|
|
|
- while (*data && *data != '}') {
|
|
|
- json::helper::parse_string(key, data);
|
|
|
- if (json::helper::get_next_element(data) != ':') {
|
|
|
- throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead");
|
|
|
- }
|
|
|
- impl.parse(to_make, ++data);
|
|
|
- vec.emplace(key, to_make);
|
|
|
- json::helper::advance_to_boundary<'}'>(data);
|
|
|
- }
|
|
|
- if (*data) ++data;
|
|
|
- else throw json::malformed_json_exception("Reached end of parse string without finding object end");
|
|
|
- }
|
|
|
-
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- data += "{";
|
|
|
- std::map<std::string, V> const & map = val.*ptr;
|
|
|
- for (typename std::map<std::string, V>::const_iterator it = map.begin(),
|
|
|
- end = map.end(); it != end; ++it) {
|
|
|
- data += "\"" + it->first + "\":";
|
|
|
- impl.write(it->second, data);
|
|
|
- data += ",";
|
|
|
- }
|
|
|
- data.back() = '}';
|
|
|
- }
|
|
|
- private:
|
|
|
- std::map<std::string, V> T::*ptr;
|
|
|
- binder<V> impl;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class object_binder : public binder_impl<T> {
|
|
|
- public:
|
|
|
- object_binder() {}
|
|
|
- virtual binder_impl<T>* clone() const override { return new object_binder(*this); }
|
|
|
-
|
|
|
- template <typename V>
|
|
|
- object_binder& operator()(std::string const&k, V T::*ptr, binder_impl<V> const&v) {
|
|
|
- return (*this)(k, binder<T>(new direct_binder<T, V>(ptr, binder<V>(v) )));
|
|
|
- }
|
|
|
-
|
|
|
- object_binder& operator()(std::string const&k, binder<T> const&v) {
|
|
|
- mapping.emplace(k, v);
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- virtual void parse(T& object, char const*& data) const override {
|
|
|
- const char ch = json::helper::get_next_element(data);
|
|
|
- if (ch == '{') {
|
|
|
- parse_object(object, ++data);
|
|
|
- } else {
|
|
|
- throw json::malformed_json_exception(std::string("Expected an object type for binding to ") + typeid(T).name());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- data += "{";
|
|
|
- for (typename std::map<std::string, binder<T>>::const_iterator it = mapping.begin(),
|
|
|
- end = mapping.end(); it != end; ++it) {
|
|
|
- data += "\"" + it->first + "\":";
|
|
|
- it->second.write(val, data);
|
|
|
- data += ",";
|
|
|
- }
|
|
|
- data.back() = '}';
|
|
|
- }
|
|
|
-
|
|
|
- void parse_object(T& object, char const*& data) const {
|
|
|
- std::string key;
|
|
|
- while (*data && *data != '}') {
|
|
|
- json::helper::parse_string(key, data);
|
|
|
- if (json::helper::get_next_element(data) != ':') {
|
|
|
- throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead");
|
|
|
- }
|
|
|
- auto it = mapping.find(key);
|
|
|
- if (it != mapping.end()) {
|
|
|
- it->second.parse(object, ++data);
|
|
|
- } else {
|
|
|
- throw json::malformed_json_exception("Unexpected key " + key);
|
|
|
- }
|
|
|
- json::helper::advance_to_boundary<'}'>(data);
|
|
|
- }
|
|
|
- if (*data) ++data;
|
|
|
- else throw json::malformed_json_exception("Reached end of parse string without finding object end");
|
|
|
- }
|
|
|
-
|
|
|
- template <typename E>
|
|
|
- object_binder& operator()(std::string const& s, E T::*p) {
|
|
|
- return operator()(s, binder<T>(new direct_binder<T, E>(p)));
|
|
|
- }
|
|
|
- private:
|
|
|
- std::map<std::string, binder<T>> mapping;
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class tuple_binder : public binder_impl<T> {
|
|
|
- public:
|
|
|
- virtual binder_impl<T>* clone() const override { return new tuple_binder(*this); }
|
|
|
-
|
|
|
- tuple_binder& operator()(binder<T> const&b) {
|
|
|
- members.push_back(b);
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- virtual void parse(T& object, char const*& data) const override {
|
|
|
- const char ch = json::helper::get_next_element(data);
|
|
|
- if (ch == '[') {
|
|
|
- parse_tuple(object, ++data);
|
|
|
- } else {
|
|
|
- throw json::malformed_json_exception(std::string("Expected an object type for binding to ") + typeid(T).name());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- virtual void write(T const& val, std::string & data) const override {
|
|
|
- data += "[";
|
|
|
- for (typename std::vector<binder<T>>::const_iterator it = members.begin(),
|
|
|
- end = members.end(); it != end; ++it) {
|
|
|
- it->write(val, data);
|
|
|
- data += ",";
|
|
|
- }
|
|
|
- data.back() = ']';
|
|
|
+ void parse(T& object, char const*& data) const {
|
|
|
+ if (!impl) return;
|
|
|
+ impl->parse(object, data);
|
|
|
}
|
|
|
|
|
|
- void parse_tuple(T& object, char const*& data) const {
|
|
|
- auto it = members.begin();
|
|
|
- while (*data && *data != ']' && it != members.end()) {
|
|
|
- it->parse(object, data);
|
|
|
- json::helper::advance_to_boundary<']'>(data);
|
|
|
- ++it;
|
|
|
- }
|
|
|
- if (it != members.end()) {
|
|
|
- throw json::malformed_json_exception("Failed to parse every member of tuple");
|
|
|
- }
|
|
|
- if (*data) ++data;
|
|
|
- else throw json::malformed_json_exception("Reached end of parse string without finding array end");
|
|
|
- }
|
|
|
-
|
|
|
- template <typename E>
|
|
|
- tuple_binder& operator()(E T::*p) {
|
|
|
- return operator()(binder<T>(new direct_binder<T, E>(p)));
|
|
|
+ void write(T const& object, std::string & data) const {
|
|
|
+ if (!impl) return;
|
|
|
+ impl->write(object, data);
|
|
|
}
|
|
|
-
|
|
|
private:
|
|
|
- std::vector<binder<T>> members;
|
|
|
+ binder_impl<T> const* impl;
|
|
|
};
|
|
|
|
|
|
template <typename T, typename S = T>
|
|
|
@@ -389,7 +101,13 @@ namespace json {
|
|
|
visitor.write(data);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
+#include "json/json_direct_binder.hpp"
|
|
|
+#include "json/json_tuple_binder.hpp"
|
|
|
+#include "json/json_object_binder.hpp"
|
|
|
+#include "json/json_direct_map_binder.hpp"
|
|
|
+#include "json/json_direct_scalar_binder.hpp"
|
|
|
+#include "json/json_direct_vector_binder.hpp"
|
|
|
+
|
|
|
#endif /* json_binder_h */
|