Permalink
Browse files

add json_traits<> and to_json() for conversion metaprogramming

  • Loading branch information...
Chip Salzenberg
Chip Salzenberg committed Apr 17, 2012
1 parent 733eb88 commit 7c378c7696278ecf158a01396695cd97f95f1db3
Showing with 118 additions and 3 deletions.
  1. +57 −1 include/ten/json.hh
  2. +61 −2 src/json.cc
View
@@ -5,6 +5,7 @@
#include <string.h>
#include <string>
#include <functional>
+#include <type_traits>
#include <limits.h>
#ifndef JSON_INTEGER_IS_LONG_LONG
@@ -201,7 +202,7 @@ class json {
static json load(const char *s, unsigned flags = JSON_DECODE_ANY) { return load(s, strlen(s), flags); }
static json load(const char *s, size_t len, unsigned flags);
- string dump(unsigned flags = JSON_ENCODE_ANY);
+ string dump(unsigned flags = JSON_ENCODE_ANY) const;
// type access
@@ -367,6 +368,8 @@ inline ostream & operator << (ostream &o, const json &j) { return o << j.get();
// to_json(), by analogy with to_string()
//
+inline json to_json(const json & j) { return j; }
+inline json to_json( json &&j) { return j; }
inline json to_json(const char *s) { return json(s); }
inline json to_json(const string &s) { return json(s); }
inline json to_json(int i) { return json(i); }
@@ -379,6 +382,59 @@ inline json to_json(unsigned long u) { return json(u); }
inline json to_json(double d) { return json(d); }
inline json to_json(bool b) { return json(b); }
+
+//----------------------------------------------------------------
+// metaprogramming
+//
+
+// conversions do not work for unspecified types
+template <class T> struct json_traits {
+ typedef T type;
+ static const bool can_make = false; // to_json(T) works
+ static const bool can_cast = false; // trait<T>::cast() works
+};
+
+// convenience base class for conversions that work
+template <class T> struct json_traits_conv {
+ typedef T type;
+ static const bool can_make = true;
+ static const bool can_cast = true;
+ static T cast(const json &j); // default decl for most cases
+};
+
+// json_cast<> function, a la lexical_cast<>
+template <class T, class TT = typename std::enable_if<json_traits<T>::can_cast>::type>
+inline T json_cast(const json &j) {
+ return json_traits<T>::cast(j);
+}
+
+
+// string
+template <> struct json_traits<string> : public json_traits_conv<string> {};
+template <> struct json_traits<const char *> {
+ typedef const char *type;
+ static const bool can_make = true; // makes copy
+ static const bool can_cast = false; // sorry, private pointer
+};
+
+// integer
+template <> struct json_traits<short > : public json_traits_conv<short > {};
+template <> struct json_traits<int > : public json_traits_conv<int > {};
+template <> struct json_traits<long > : public json_traits_conv<long > {};
+template <> struct json_traits<long long > : public json_traits_conv<long long > {};
+template <> struct json_traits<unsigned > : public json_traits_conv<unsigned > {};
+#if ULONG_MAX < LLONG_MAX
+template <> struct json_traits<unsigned long> : public json_traits_conv<unsigned long> {};
+#endif
+
+// real
+template <> struct json_traits<double> : public json_traits_conv<double> {};
+template <> struct json_traits<float> : public json_traits_conv<float> {};
+
+// boolean
+template <> struct json_traits<bool> : public json_traits_conv<bool> {};
+
+
} // ten
#endif // LIBTEN_JSON_HH
View
@@ -27,7 +27,7 @@ ostream & operator << (ostream &o, const json_t *j) {
return o;
}
-string json::dump(unsigned flags) {
+string json::dump(unsigned flags) const {
ostringstream ss;
if (_p)
json_dump_callback(_p.get(), ostream_json_dump_callback, static_cast<ostream *>(&ss), flags);
@@ -42,7 +42,63 @@ json json::load(const char *s, size_t len, unsigned flags) {
return j;
}
+//
+// metaprogramming for conversions
+//
+
+// json integer
+
+template <class T> inline T integral_cast(const json &j) {
+ if (!j.is_integer()) throw errorx("not integral: %s", j.dump().c_str());
+ auto i = j.integer();
+ if ((numeric_limits<T>::is_signed
+ ? i < numeric_limits<T>::min()
+ : i < 0)
+ || i > numeric_limits<T>::max())
+ throw errorx("%lld: out of range for %s", i, typeid(T).name());
+ return static_cast<T>(i);
+};
+template <> short json_traits_conv<short >::cast(const json &j) { return integral_cast<short >(j); }
+template <> int json_traits_conv<int >::cast(const json &j) { return integral_cast<int >(j); }
+template <> long json_traits_conv<long >::cast(const json &j) { return integral_cast<long >(j); }
+template <> long long json_traits_conv<long long >::cast(const json &j) { return integral_cast<long long >(j); }
+template <> unsigned json_traits_conv<unsigned >::cast(const json &j) { return integral_cast<unsigned >(j); }
+#if ULONG_MAX < LLONG_MAX
+template <> unsigned long json_traits_conv<unsigned long>::cast(const json &j) { return integral_cast<unsigned long>(j); }
+#endif
+
+// json string
+
+template <> string json_traits_conv<string>::cast(const json &j) {
+ if (!j.is_string()) throw errorx("not string: %s", j.dump().c_str());
+ return j.str();
+}
+
+// json real
+
+template <> double json_traits_conv<double>::cast(const json &j) {
+ if (!j.is_real()) throw errorx("not real: %s", j.dump().c_str());
+ return j.real();
+}
+template <> float json_traits_conv<float>::cast(const json &j) {
+ if (!j.is_real()) throw errorx("not real: %s", j.dump().c_str());
+ auto n = j.real();
+ if (n < numeric_limits<float>::min() || n > numeric_limits<float>::max())
+ throw errorx("out of range for float: %g", n);
+ return j.real();
+}
+
+// json boolean
+
+template <> bool json_traits_conv<bool>::cast(const json &j) {
+ if (!j.is_boolean()) throw errorx("not boolean: %s", j.dump().c_str());
+ return j.boolean();
+}
+
+
+//
// simple visit of all objects
+//
#ifdef TEN_JSON_CXX11
void json::visit(const json::visitor_func_t &visitor) {
@@ -76,7 +132,10 @@ void json::visit(const json::visitor_func_t &visitor) {
}
#endif
-// for debugging
+//
+// path
+//
+
static ostream & operator << (ostream &o, const vector<string> &v) {
for (size_t i = 0; i < v.size(); ++i) {
if (i) o << " ";

0 comments on commit 7c378c7

Please sign in to comment.