Serialization improvements #17

Merged
merged 7 commits into from Apr 24, 2012
View
@@ -48,13 +48,17 @@ class JSave {
save_mode mode() const { return _mode; }
unsigned version() const { return _version; }
+ // make one like the other but without memory
+ JSave clone() const { return JSave(_version, _mode); }
+
// public value extraction
friend json result(const JSave &ar) { return ar._j; }
friend json result( JSave &&ar) { return move(ar._j); }
- // operator << works on save only
- template <class T>
- JSave & operator << (T &&t) { return *this & t; }
+ // operator << works on save only,
+ template <class T> JSave & operator << (T &t) { return *this & t; }
+ template <class V> JSave & operator << ( KV<V &> f) { return *this & f; }
+ template <class V> JSave & operator << (ConstKV<V &> f) { return *this & f; }
// save functions
@@ -65,7 +69,7 @@ class JSave {
}
template <class T, class X = typename std::enable_if<json_traits<T>::can_make>::type>
- JSave & operator & (T &&t) {
+ JSave & operator & (const T &t) {
json j(to_json(t));
req_empty_for(j);
_j = move(j);
@@ -77,7 +81,7 @@ class JSave {
template <class V>
JSave & operator & (KV<V> f) {
req_obj_for(f.key);
- JSave js(_version, _mode);
+ auto js = clone();
auto jv = result(js & f.value);
if (jv)
_j.set(f.key, move(jv));
@@ -120,9 +124,13 @@ class JLoad {
json source() const { return _j; }
unsigned version() const { return _version; }
- // operator >> works on load only
- template <class T>
- JLoad & operator >> (T &t) { return *this & t; }
+ // make one like the other but without memory
+ JLoad clone() const { return JLoad(_version); }
+
+ // operator >> works on load only,
+ template <class T> JLoad & operator >> (T &t) { return *this & t; }
+ template <class V> JLoad & operator >> ( KV<V &> f) { return *this & f; } // not ref
+ template <class V> JLoad & operator >> (ConstKV<V &> f) { return *this & f; } // not ref
// load functions
@@ -137,14 +145,6 @@ class JLoad {
return *this;
}
- // kv pair specialization
-
- // operator >> is respecialized because parameter is not ref
- template <class V>
- JLoad & operator >> (KV<V &> f) {
- return *this & f;
- }
-
template <class V>
JLoad & operator & (KV<V &> f) {
req_obj_for(f.key);
@@ -0,0 +1,37 @@
+#ifndef LIBTEN_JSERIAL_ENUM_HH
+#define LIBTEN_JSERIAL_ENUM_HH
+
+#include "ten/jserial.hh"
+#include <array>
+
+namespace ten {
+using std::string;
+
+// first define an std::array<const char *, N> of enum names
+// then call this as the body of your enum's operator &
+
+template <class AR, class E, size_t NameCount>
+inline AR & serialize_enum(AR &ar, E &e, const std::array<const char *, NameCount> &names) {
+ if (AR::is_save) {
+ // this is a kludge for unified archiving. constness is a PITA
+ json j(names[(size_t)e]);
+ return ar & j;
+ }
+ else {
+ json j;
+ ar & j;
+ if (j.is_string()) {
+ for (size_t i = 0; i < NameCount; ++i) {
+ if (!strcmp(names[i], j.c_str())) {
+ e = E(i);
+ return ar;
+ }
+ }
+ }
+ throw errorx("invalid %s: %s", typeid(E).name(), j.dump().c_str());
+ }
+}
+
+} // ten
+
+#endif // LIBTEN_JSERIAL_MAYBE_HH
@@ -8,20 +8,30 @@
namespace ten {
using std::move;
-template <class AR, class T, class X = typename std::enable_if<AR::is_save>::type>
-inline AR & operator >> (AR &ar, maybe<T> &m) {
- if (ar.source()) {
- T t;
- ar >> t;
- m = move(t);
- }
- return ar;
+namespace detail {
+ template <bool Save> struct serialize_maybe;
+ template <> struct serialize_maybe<true> {
+ template <class AR, class T>
+ static void serialize(AR &ar, maybe<T> &m) {
+ if (m.ok())
+ ar << m.get_ref();
+ }
+ };
+ template <> struct serialize_maybe<false> {
+ template <class AR, class T>
+ static void serialize(AR &ar, maybe<T> &m) {
+ if (ar.source()) {
+ T t;
+ ar >> t;
+ m = move(t);
+ }
+ }
+ };
}
-template <class AR, class T, class X = typename std::enable_if<AR::is_load>::type>
-inline AR & operator << (AR &ar, maybe<T> &m) {
- if (m.ok())
- ar << m.get_ref();
+template <class AR, class T>
+inline AR & operator & (AR &ar, maybe<T> &m) {
+ detail::serialize_maybe<AR::is_save>::serialize(ar, m);
return ar;
}
@@ -18,7 +18,7 @@ inline json to_json(SafeInt<I> i) { return to_json(i.Ref()); }
template <class AR, class I, class X = typename std::enable_if<AR::is_archive>::type>
inline AR & operator & (AR &ar, SafeInt<I> &si) {
- ar & si.Ref();
+ ar & *si.Ptr();
return ar;
}
View
@@ -28,10 +28,10 @@ const intptr_t nullptr = 0;
//----------------------------------------------------------------
-// streams meet json_t
+// streams meet json_t (just barely)
//
-std::ostream & operator << (std::ostream &o, const json_t *j);
+void dump(std::ostream &o, const json_t *j, unsigned flags = JSON_ENCODE_ANY);
//----------------------------------------------------------------
@@ -75,7 +75,10 @@ public:
return p ? &shared_json_ptr::true_value : nullptr;
}
- friend std::ostream & operator << (std::ostream &o, const shared_json_ptr &jp) { return o << jp.get(); }
+ friend std::ostream & operator << (std::ostream &o, const shared_json_ptr &jp) {
+ dump(o, jp.get());
+ return o;
+ }
};
typedef shared_json_ptr< json_t> json_ptr;
@@ -199,14 +202,19 @@ class json {
return !(lhs == rhs);
}
- // parse and ouput
+ // parse and output
static json load(const string &s, unsigned flags = JSON_DECODE_ANY) { return load(s.data(), s.size(), flags); }
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) const;
+ friend std::ostream & operator << (std::ostream &o, const json &j) {
+ ten::dump(o, j.get());
+ return o;
+ }
+
// type access
ten_json_type type() const { json_t *j = get(); return j ? (ten_json_type)json_typeof(j) : JSON_INVALID; }
@@ -364,8 +372,6 @@ class json {
arr_view arr() { return arr_view(get()); }
};
-inline std::ostream & operator << (std::ostream &o, const json &j) { return o << j.get(); }
-
//----------------------------------------------------------------
// to_json(), by analogy with to_string()
View
@@ -15,16 +15,15 @@ using namespace std;
extern "C" {
static int ostream_json_dump_callback(const char *buffer, size_t size, void *osptr) {
- ostream *o = (ostream *)osptr;
+ ostream *o = reinterpret_cast<ostream *>(osptr);
o->write(buffer, size);
return 0;
}
} // "C"
-ostream & operator << (ostream &o, const json_t *j) {
+void dump(ostream &o, const json_t *j, unsigned flags) {
if (j)
- json_dump_callback(j, ostream_json_dump_callback, &o, JSON_ENCODE_ANY);
- return o;
+ json_dump_callback(j, ostream_json_dump_callback, &o, flags);
}
string json::dump(unsigned flags) const {
View
@@ -2,8 +2,10 @@
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#include <ten/jserial.hh>
+#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
+#include <ten/jserial_enum.hh>
using namespace std;
using namespace ten;
@@ -210,6 +212,15 @@ inline bool operator == (const corge &a, const corge &b) {
return a.foo == b.foo && a.bar == b.bar;
}
+
+enum captain { kirk, picard, janeway, sisko };
+constexpr array<const char *, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
+template <class AR>
+inline AR & operator & (AR &ar, captain &c) {
+ return serialize_enum(ar, c, captain_names);
+}
+
+
BOOST_AUTO_TEST_CASE(json_serial) {
corge c1(42, 17);
auto j = jsave_all(c1);
@@ -234,4 +245,26 @@ BOOST_AUTO_TEST_CASE(json_serial) {
BOOST_CHECK_EQUAL(f["foo"], 42);
BOOST_CHECK_EQUAL(f["bar"], 17);
#endif
+
+ maybe<int> a;
+ j = jsave_all(a);
+ BOOST_CHECK(!j);
+ a = 42;
+ j = jsave_all(a);
+ BOOST_CHECK_EQUAL(j, 42);
+
+ a.reset();
+ BOOST_CHECK(!a.ok());
+ j = 17;
+ JLoad(j) >> a;
+ BOOST_CHECK(a.ok());
+ BOOST_CHECK_EQUAL(a.get(), 17);
+
+
+ captain c = janeway;
+ j = jsave_all(c);
+ BOOST_CHECK_EQUAL(j, "janeway");
+ j = "kirk";
+ JLoad(j) >> c;
+ BOOST_CHECK_EQUAL(c, kirk);
}