You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2013/07/31 03:11:16 UTC

[lucy-commits] [4/6] git commit: refs/heads/move-dumpable - Add dump() and load() to Freezer.

Add dump() and load() to Freezer.


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/6589307a
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/6589307a
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/6589307a

Branch: refs/heads/move-dumpable
Commit: 6589307a013eb4190a6a0345c92219af95e44fdb
Parents: 105a7e9
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Wed Jul 24 17:38:34 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Tue Jul 30 17:57:23 2013 -0700

----------------------------------------------------------------------
 core/Lucy/Test/Util/TestFreezer.c |  54 ++++++++---
 core/Lucy/Util/Freezer.c          | 168 +++++++++++++++++++++++++++++++++
 core/Lucy/Util/Freezer.cfh        |  15 +++
 3 files changed, 226 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/6589307a/core/Lucy/Test/Util/TestFreezer.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestFreezer.c b/core/Lucy/Test/Util/TestFreezer.c
index fd8b172..ac45db7 100644
--- a/core/Lucy/Test/Util/TestFreezer.c
+++ b/core/Lucy/Test/Util/TestFreezer.c
@@ -52,6 +52,20 @@ S_freeze_thaw(Obj *object) {
     }
 }
 
+// Return the result of round-tripping the object through dump() and load().
+static Obj*
+S_dump_load(Obj *object) {
+    if (object) {
+        Obj *dump = Freezer_dump(object);
+        Obj *loaded = Freezer_load(dump);
+        DECREF(dump);
+        return loaded;
+    }
+    else {
+        return NULL;
+    }
+}
+
 static void
 test_bytebuf(TestBatchRunner *runner) {
     ByteBuf *wanted = BB_new_bytes("foobar", 6);
@@ -75,7 +89,6 @@ test_charbuf(TestBatchRunner *runner) {
 static void
 test_hash(TestBatchRunner *runner) {
     Hash  *wanted = Hash_new(0);
-    Hash  *got;
 
     for (uint32_t i = 0; i < 10; i++) {
         CharBuf *cb = TestUtils_random_string(rand() % 1200);
@@ -84,11 +97,20 @@ test_hash(TestBatchRunner *runner) {
         Hash_Store(wanted, (Obj*)num, (Obj*)cb);
     }
 
-    got = (Hash*)S_freeze_thaw((Obj*)wanted);
-    TEST_TRUE(runner, got && Hash_Equals(wanted, (Obj*)got),
-              "Round trip through serialization.");
+    {
+        Hash *got = (Hash*)S_freeze_thaw((Obj*)wanted);
+        TEST_TRUE(runner, got && Hash_Equals(wanted, (Obj*)got),
+                  "Round trip through serialization.");
+        DECREF(got);
+    }
+
+    {
+        Obj *got = S_dump_load((Obj*)wanted);
+        TEST_TRUE(runner, Hash_Equals(wanted, got),
+                  "Dump => Load round trip");
+        DECREF(got);
+    }
 
-    DECREF(got);
     DECREF(wanted);
 }
 
@@ -128,19 +150,29 @@ test_num(TestBatchRunner *runner) {
 static void
 test_varray(TestBatchRunner *runner) {
     VArray *array = VA_new(0);
-    VArray *dupe;
     VA_Store(array, 1, (Obj*)CB_newf("foo"));
     VA_Store(array, 3, (Obj*)CB_newf("bar"));
-    dupe = (VArray*)S_freeze_thaw((Obj*)array);
-    TEST_TRUE(runner, dupe && VA_Equals(array, (Obj*)dupe),
-              "Round trip through FREEZE/THAW");
-    DECREF(dupe);
+
+    {
+        Obj *got = S_freeze_thaw((Obj*)array);
+        TEST_TRUE(runner, got && VA_Equals(array, got),
+                  "Round trip through FREEZE/THAW");
+        DECREF(got);
+    }
+
+    {
+        Obj *got = S_dump_load((Obj*)array);
+        TEST_TRUE(runner, got && VA_Equals(array, got),
+                  "Dump => Load round trip");
+        DECREF(got);
+    }
+
     DECREF(array);
 }
 
 void
 TestFreezer_run(TestFreezer *self, TestBatchRunner *runner) {
-    TestBatchRunner_Plan(runner, (TestBatch*)self, 9);
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 10);
     test_bytebuf(runner);
     test_charbuf(runner);
     test_hash(runner);

http://git-wip-us.apache.org/repos/asf/lucy/blob/6589307a/core/Lucy/Util/Freezer.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Util/Freezer.c b/core/Lucy/Util/Freezer.c
index fecd092..2f9bf63 100644
--- a/core/Lucy/Util/Freezer.c
+++ b/core/Lucy/Util/Freezer.c
@@ -20,10 +20,13 @@
 #include "Lucy/Util/Freezer.h"
 #include "Lucy/Store/InStream.h"
 #include "Lucy/Store/OutStream.h"
+#include "Lucy/Analysis/Analyzer.h"
 #include "Lucy/Document/Doc.h"
 #include "Lucy/Index/Similarity.h"
 #include "Lucy/Index/DocVector.h"
 #include "Lucy/Index/TermVector.h"
+#include "Lucy/Plan/FieldType.h"
+#include "Lucy/Plan/Schema.h"
 #include "Lucy/Search/Query.h"
 #include "Lucy/Search/SortRule.h"
 #include "Lucy/Search/SortSpec.h"
@@ -358,3 +361,168 @@ Freezer_read_hash(InStream *instream) {
     return Freezer_deserialize_hash(hash, instream);
 }
 
+static Obj*
+S_dump_array(VArray *array) {
+    VArray *dump = VA_new(VA_Get_Size(array));
+    for (uint32_t i = 0, max = VA_Get_Size(array); i < max; i++) {
+        Obj *elem = VA_Fetch(array, i);
+        if (elem) {
+            VA_Store(dump, i, Freezer_dump(elem));
+        }
+    }
+    return (Obj*)dump;
+}
+
+Obj*
+S_dump_hash(Hash *hash) {
+    Hash *dump = Hash_new(Hash_Get_Size(hash));
+    Obj *key;
+    Obj *value;
+
+    Hash_Iterate(hash);
+    while (Hash_Next(hash, &key, &value)) {
+        // Since JSON only supports text hash keys, dump() can only support
+        // text hash keys.
+        CERTIFY(key, CHARBUF);
+        Hash_Store(dump, key, Obj_Dump(value));
+    }
+
+    return (Obj*)dump;
+}
+
+Obj*
+Freezer_dump(Obj *obj) {
+    if (Obj_Is_A(obj, CHARBUF)) {
+        return (Obj*)Obj_To_String(obj);
+    }
+    else if (Obj_Is_A(obj, VARRAY)) {
+        return S_dump_array((VArray*)obj);
+    }
+    else if (Obj_Is_A(obj, HASH)) {
+        return S_dump_hash((Hash*)obj);
+    }
+    else if (Obj_Is_A(obj, ANALYZER)) {
+        return Analyzer_Dump((Analyzer*)obj);
+    }
+    else if (Obj_Is_A(obj, DOC)) {
+        return (Obj*)Doc_Dump((Doc*)obj);
+    }
+    else if (Obj_Is_A(obj, SIMILARITY)) {
+        return Sim_Dump((Similarity*)obj);
+    }
+    else if (Obj_Is_A(obj, FIELDTYPE)) {
+        return FType_Dump((FieldType*)obj);
+    }
+    else if (Obj_Is_A(obj, SCHEMA)) {
+        return (Obj*)Schema_Dump((Schema*)obj);
+    }
+    else if (Obj_Is_A(obj, QUERY)) {
+        return Query_Dump((Query*)obj);
+    }
+    else {
+        return (Obj*)Obj_To_String(obj);
+    }
+}
+
+static Obj*
+S_load_via_load_method(VTable *vtable, Obj *dump) {
+    Obj *dummy = VTable_Make_Obj(vtable);
+    Obj *loaded = NULL;
+    if (Obj_Is_A(dummy, ANALYZER)) {
+        loaded = Analyzer_Load((Analyzer*)dummy, dump);
+    }
+    else if (Obj_Is_A(dummy, DOC)) {
+        loaded = (Obj*)Doc_Load((Doc*)dummy, dump);
+    }
+    else if (Obj_Is_A(dummy, SIMILARITY)) {
+        loaded = (Obj*)Sim_Load((Similarity*)dummy, dump);
+    }
+    else if (Obj_Is_A(dummy, FIELDTYPE)) {
+        loaded = FType_Load((FieldType*)dummy, dump);
+    }
+    else if (Obj_Is_A(dummy, SCHEMA)) {
+        loaded = (Obj*)Schema_Load((Schema*)dummy, dump);
+    }
+    else if (Obj_Is_A(dummy, QUERY)) {
+        loaded = Query_Load((Query*)dummy, dump);
+    }
+    else {
+        DECREF(dummy);
+        THROW(ERR, "Don't know how to load '%o'", VTable_Get_Name(vtable));
+    }
+
+    DECREF(dummy);
+    return loaded;
+}
+
+static Obj*
+S_load_from_hash(Hash *dump) {
+    CharBuf *class_name = (CharBuf*)Hash_Fetch_Str(dump, "_class", 6);
+
+    // Assume that the presence of the "_class" key paired with a valid class
+    // name indicates the output of a dump() rather than an ordinary Hash.
+    if (class_name && CB_Is_A(class_name, CHARBUF)) {
+        VTable *vtable = VTable_fetch_vtable(class_name);
+
+        if (!vtable) {
+            CharBuf *parent_class = VTable_find_parent_class(class_name);
+            if (parent_class) {
+                VTable *parent = VTable_singleton(parent_class, NULL);
+                vtable = VTable_singleton(class_name, parent);
+                DECREF(parent_class);
+            }
+            else {
+                // TODO: Fix load() so that it works with ordinary hash keys
+                // named "_class".
+                THROW(ERR, "Can't find class '%o'", class_name);
+            }
+        }
+
+        // Dispatch to an alternate Load() method.
+        if (vtable) {
+            return S_load_via_load_method(vtable, (Obj*)dump);
+        }
+
+    }
+
+    // It's an ordinary Hash.
+    Hash *loaded = Hash_new(Hash_Get_Size(dump));
+    Obj *key;
+    Obj *value;
+    Hash_Iterate(dump);
+    while (Hash_Next(dump, &key, &value)) {
+        Hash_Store(loaded, key, Freezer_load(value));
+    }
+
+    return (Obj*)loaded;
+
+}
+
+
+Obj*
+S_load_from_array(VArray *dump) {
+    VArray *loaded = VA_new(VA_Get_Size(dump));
+
+    for (uint32_t i = 0, max = VA_Get_Size(dump); i < max; i++) {
+        Obj *elem_dump = VA_Fetch(dump, i);
+        if (elem_dump) {
+            VA_Store(loaded, i, Freezer_load(elem_dump));
+        }
+    }
+
+    return (Obj*)loaded;
+}
+
+Obj*
+Freezer_load(Obj *obj) {
+    if (Obj_Is_A(obj, HASH)) {
+        return S_load_from_hash((Hash*)obj);
+    }
+    else if (Obj_Is_A(obj, VARRAY)) {
+        return S_load_from_array((VArray*)obj);
+    }
+    else {
+        return Obj_Clone(obj);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/6589307a/core/Lucy/Util/Freezer.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Util/Freezer.cfh b/core/Lucy/Util/Freezer.cfh
index d84ec88..93b152f 100644
--- a/core/Lucy/Util/Freezer.cfh
+++ b/core/Lucy/Util/Freezer.cfh
@@ -40,6 +40,21 @@ inert class Lucy::Util::Freezer {
     inert incremented Obj*
     deserialize(Obj *obj, InStream *instream);
 
+    /** Return a representation of the object using only scalars, hashes, and
+     * arrays.  Some classes support JSON serialization via dump() and its
+     * companion, load(); for others, dump() is only a debugging aid.
+     * The default simply calls To_String().
+     */
+    inert incremented Obj*
+    dump(Obj *obj);
+
+    /** Create an object from the output of a call to dump().
+     *
+     * @param dump The output of dump().
+     */
+    inert incremented Obj*
+    load(Obj *dump);
+
     inert void
     serialize_charbuf(CharBuf *charbuf, OutStream *outstream);