// // json_direct_map_binder.hpp // json // // Created by Sam Jaffe on 4/23/16. // #pragma once namespace json { namespace binder { template class associative_binder : public binder_impl { public: associative_binder(C T::*p) : ptr(p), impl(value_binder()) {} associative_binder(C T::*p, binder const & i) : ptr(p), impl(i) {} virtual binder_impl* clone() const override { return new associative_binder(*this); } virtual void parse(T& val, char const*& data, parser::options opts) const override { const char ch = json::helper::get_next_element(data); if (ch != '{') { throw json::malformed_json_exception("Expected an object type"); } ++data; V to_make; C & map = 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, opts); map.emplace(key, std::move(to_make)); json::helper::advance_to_boundary('}', data); } if (*data) ++data; else throw json::unterminated_json_exception("Reached end of parse string without finding object end"); } virtual void write(T const& val, std::ostream & data) const override { data << '{'; std::map const & map = val.*ptr; typename std::map::const_iterator it = map.begin(), end = map.end(); if (it != end) { data << '"' << it->first << '"' << ':'; impl.write(it->second, data); for (++it; it != end; ++it) { data << ','; data << '"' << it->first << '"' << ':'; impl.write(it->second, data); } } data << '}'; } private: std::map T::*ptr; binder impl; }; #define ASSOCIATIVE_DIRECT_BINDER( C ) \ template \ class direct_binder > : \ public associative_binder> { \ public: \ using associative_binder>::associative_binder; \ } ASSOCIATIVE_DIRECT_BINDER( std::map ); // ASSOCIATIVE_DIRECT_BINDER( std::unordered_map ); } }