Author: jsdelfino
Date: Mon Oct  5 08:21:40 2009
New Revision: 821715

URL: http://svn.apache.org/viewvc?rev=821715&view=rev
Log:
Changed XML and JSON databindings to use lazy lists and writer functions 
instead of STL streams, to help integrate them with HTTPD and CURL, which don't 
use streams.

Added:
    tuscany/cpp/sca/kernel/slist.hpp
Modified:
    tuscany/cpp/sca/kernel/kernel-test.cpp
    tuscany/cpp/sca/kernel/xml.hpp
    tuscany/cpp/sca/modules/json/json-test.cpp
    tuscany/cpp/sca/modules/json/json.hpp

Modified: tuscany/cpp/sca/kernel/kernel-test.cpp
URL: 
http://svn.apache.org/viewvc/tuscany/cpp/sca/kernel/kernel-test.cpp?rev=821715&r1=821714&r2=821715&view=diff
==============================================================================
--- tuscany/cpp/sca/kernel/kernel-test.cpp (original)
+++ tuscany/cpp/sca/kernel/kernel-test.cpp Mon Oct  5 08:21:40 2009
@@ -31,6 +31,7 @@
 #include <sstream>
 #include "function.hpp"
 #include "list.hpp"
+#include "slist.hpp"
 #include "parallel.hpp"
 #include "value.hpp"
 #include "xml.hpp"
@@ -218,6 +219,15 @@
     return true;
 }
 
+bool testTokenize() {
+    assert(tokenize("/", "aaa/bbb/ccc/ddd") == makeList<std::string>("aaa", 
"bbb", "ccc", "ddd"));
+    assert(tokenize("/", "/bbb/ccc/ddd") == makeList<std::string>("", "bbb", 
"ccc", "ddd"));
+    assert(tokenize("/", "/bbb/ccc/") == makeList<std::string>("", "bbb", 
"ccc"));
+    assert(tokenize("/", "/bbb//ccc/") == makeList<std::string>("", "bbb", "", 
"ccc"));
+    assert(tokenize("/", "abc/def/") == makeList<std::string>("abc", "def"));
+    return true;
+}
+
 double testSeqMap(double x) {
     return x;
 }
@@ -285,15 +295,42 @@
 bool testCppPerf() {
     struct timeval start;
     struct timeval end;
-    gettimeofday(&start, NULL);
+    {
+        gettimeofday(&start, NULL);
+
+        list<double> s = seq(0.0, 999.0);
+        list<double> r = map((lambda<double(double)> )fib, s);
+        assert(1000 == length(r));
+
+        gettimeofday(&end, NULL);
+        //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 
1000 + start.tv_usec / 1000);
+        //std::cout << "Fib cpp function map perf test " << t << " ms" << 
std::endl;
+    }
+
+    {
+        struct nested {
+            static double fib(double n) {
+                struct nested {
+                    static double fib_aux(double n, double a, double b) {
+                        if(n == 0.0)
+                            return a;
+                        return fib_aux(n - 1.0, b, a + b);
+                    }
+                };
+                return nested::fib_aux(n, 0.0, 1.0);
+            }
+        };
+
+        gettimeofday(&start, NULL);
 
-    list<double> s = seq(0.0, 999.0);
-    list<double> r = map((lambda<double(double)> )fib, s);
-    assert(1000 == length(r));
-
-    gettimeofday(&end, NULL);
-    //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 
+ start.tv_usec / 1000);
-    //std::cout << "Fib cpp perf test " << t << " ms" << std::endl;
+        list<double> s = seq(0.0, 999.0);
+        list<double> r = map(lambda<double(double)>(nested::fib), s);
+        assert(1000 == length(r));
+
+        gettimeofday(&end, NULL);
+        //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 
1000 + start.tv_usec / 1000);
+        //std::cout << "Fib cpp nested function map perf test " << t << " ms" 
<< std::endl;
+    }
     return true;
 }
 
@@ -390,7 +427,7 @@
 
 bool testReadXML() {
     std::istringstream is(currencyXML);
-    const list<value> currency = readXML(is);
+    const list<value> currency = readXML(makeStreamList(is));
 
     const value composite = car(currency);
     assert(isElement(composite));
@@ -401,12 +438,22 @@
     return true;
 }
 
+std::ostringstream* xmlWriter(std::ostringstream* os, const std::string& s) {
+    (*os) << s;
+    return os;
+}
+
 bool testWriteXML() {
     std::istringstream is(currencyXML);
-    const list<value> currency = readXML(is);
+    const list<std::string> il = makeStreamList(is);
+
+    const list<value> currency = readXML(il);
     std::ostringstream os;
-    writeXML(currency, os);
+    lambda<std::ostringstream*(std::ostringstream*, std::string)> 
writer(xmlWriter);
+    writeXML(writer, &os, currency);
     assert(os.str() == currencyXML);
+
+    assert(writeXML(currency) == il);
     return true;
 }
 
@@ -429,6 +476,7 @@
     tuscany::testFilter();
     tuscany::testMember();
     tuscany::testReverse();
+    tuscany::testTokenize();
     tuscany::testSeq();
     tuscany::testValue();
     tuscany::testValueGC();

Added: tuscany/cpp/sca/kernel/slist.hpp
URL: 
http://svn.apache.org/viewvc/tuscany/cpp/sca/kernel/slist.hpp?rev=821715&view=auto
==============================================================================
--- tuscany/cpp/sca/kernel/slist.hpp (added)
+++ tuscany/cpp/sca/kernel/slist.hpp Mon Oct  5 08:21:40 2009
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_slist_hpp
+#define tuscany_slist_hpp
+
+/**
+ * Useful functions to work with lists of strings and character streams.
+ */
+
+#include <iostream>
+#include <string>
+#include "function.hpp"
+#include "list.hpp"
+
+namespace tuscany {
+
+/**
+ * Tokenize a string into a list of strings.
+ */
+const list<std::string> tokenize(const std::string& sep, const std::string& 
str) {
+    struct nested {
+        static const list<std::string> tokenize(const std::string& sep, const 
std::string& str, const unsigned int start = 0) {
+            if (start >= str.length())
+                return list<std::string>();
+            const unsigned int i = str.find_first_of(sep, start);
+            if (i == std::string::npos)
+                return makeList(str.substr(start));
+            return cons(str.substr(start, i - start), tokenize(sep, str, i + 
1));
+        }
+    };
+    return nested::tokenize(sep, str, 0);
+}
+
+/**
+ * Returns a lazy list view of an input stream.
+ */
+struct ilistRead{
+    std::istream &is;
+    ilistRead(std::istream& is) : is(is) {
+    }
+    const list<std::string> operator()() {
+        char buffer[1024];
+        is.read(buffer, 1024);
+        const int n = is.gcount();
+        if (n ==0)
+            return list<std::string>();
+        return cons(std::string(buffer, n), (*this)());
+    }
+};
+
+const list<std::string> makeStreamList(std::istream& is) {
+    return ilistRead(is)();
+}
+
+/**
+ * Fragment the first element of a list of strings to fit the given max length.
+ */
+const list<std::string> fragment(list<std::string> l, unsigned int max) {
+    const std::string s = car(l);
+    if (s.length() <= max)
+        return l;
+    return cons(s.substr(0, max), cons(s.substr(max), cdr(l)));
+}
+
+/**
+ * Write a list of strings to an output stream.
+ */
+std::ostream& write(const list<std::string>& l, std::ostream& os) {
+    if(isNil(l))
+        return os;
+    os << car(l);
+    return write(cdr(l), os);
+}
+
+}
+
+#endif /* tuscany_slist_hpp */

Modified: tuscany/cpp/sca/kernel/xml.hpp
URL: 
http://svn.apache.org/viewvc/tuscany/cpp/sca/kernel/xml.hpp?rev=821715&r1=821714&r2=821715&view=diff
==============================================================================
--- tuscany/cpp/sca/kernel/xml.hpp (original)
+++ tuscany/cpp/sca/kernel/xml.hpp Mon Oct  5 08:21:40 2009
@@ -30,8 +30,6 @@
 #include <libxml/xmlwriter.h>
 #include <libxml/xmlschemas.h>
 #include <libxml/globals.h>
-#include <iostream>
-#include <fstream>
 #include <string>
 #include "list.hpp"
 
@@ -158,7 +156,7 @@
 }
 
 /**
- * Read an XML document from a libxml2 XML reader.
+ * Read a list of values from a libxml2 XML reader.
  */
 const list<value> read(XMLReader& reader) {
     value nextToken = readToken(reader);
@@ -168,49 +166,35 @@
 }
 
 /**
- * Callback function called by libxml2 to read the XML input stream.
+ * Context passed to the read callback function.
  */
-int readCallback(void *context, char* buffer, int len) {
-    std::istream* is = static_cast<std::istream*>(context);
-    is->read(buffer, len);
-    const int n = is->gcount();
-    return n;
-}
-
-/**
- * Read an XML document from an input stream.
- */
-const list<value> readXML(std::istream& is) {
-    xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &is, NULL, NULL, 
XML_PARSE_NONET);
-    if (xml == NULL)
-        return list<value>();
-    XMLReader reader(xml);
-    return read(reader);
-}
-
-/**
- * Callback function called by libxml2 to read the XML file input stream.
- */
-int readFileCallback(void *context, char* buffer, int len) {
-    std::ifstream* is = static_cast<std::ifstream*>(context);
-    is->read(buffer, len);
-    return is->gcount();
-}
+class XMLReadContext {
+public:
+    XMLReadContext(const list<std::string>& ilist) : ilist(ilist) {
+    }
+    list<std::string> ilist;
+};
 
 /**
- * Callback function called by libxml2 to close the XML file input stream.
+ * Callback function called by libxml2 to read XML.
  */
-int readCloseFileCallback(void *context) {
-    std::ifstream* fis = static_cast<std::ifstream*>(context);
-    fis->close();
-    return 0;
+int readCallback(void *context, char* buffer, int len) {
+    XMLReadContext& rc = *static_cast<XMLReadContext*>(context);
+    if (isNil(rc.ilist))
+        return 0;
+    rc.ilist = fragment(rc.ilist, len);
+    std::string s = car(rc.ilist);
+    rc.ilist = cdr(rc.ilist);
+    s.copy(buffer, s.length());
+    return s.length();
 }
 
 /**
- * Read an XML document from a file input stream.
- */
-const list<value> readXML(std::ifstream& is) {
-    xmlTextReaderPtr xml = xmlReaderForIO(readFileCallback, 
readCloseFileCallback, &is, NULL, NULL, XML_PARSE_NONET);
+ * Read a list values from a list of strings representing an XML document.
+ */
+const list<value> readXML(const list<std::string>& ilist) {
+    XMLReadContext cx(ilist);
+    xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, 
XML_PARSE_NONET);
     if (xml == NULL)
         return list<value>();
     XMLReader reader(xml);
@@ -313,7 +297,7 @@
 }
 
 /**
- * Write an XML document to a libxml2 XML writer.
+ * Write a list of values to a libxml2 XML writer.
  */
 const bool write(const list<value>& l, const xmlTextWriterPtr xml) {
     if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0)
@@ -325,56 +309,47 @@
 }
 
 /**
- * Callback function called by libxml2 to write to the XML output stream.
+ * Context passed to the write callback function.
  */
-int writeCallback(void *context, const char* buffer, int len) {
-    std::ostream* os = static_cast<std::ostream*>(context);
-    os->write(buffer, len);
-    if (os->fail() || os->bad())
-        return -1;
-    return len;
-}
+template<typename R> class XMLWriteContext {
+public:
+    XMLWriteContext(const lambda<R(R, std::string)>& reduce, const R& accum) : 
reduce(reduce), accum(accum) {
+    }
+    const lambda<R(R, std::string)> reduce;
+    R accum;
+};
 
 /**
- * Write an XML document to an output stream.
+ * Callback function called by libxml2 to write XML out.
  */
-const bool writeXML(const list<value>& l, std::ostream& os) {
-    xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback, NULL, &os, 
NULL);
-    xmlTextWriterPtr xml = xmlNewTextWriter(out);
-    if (xml == NULL)
-        return false;
-    return write(l, xml);
+template<typename R> int writeCallback(void *context, const char* buffer, int 
len) {
+    XMLWriteContext<R>& cx = *static_cast<XMLWriteContext<R>*>(context);
+    cx.accum = cx.reduce(cx.accum, std::string(buffer, len));
+    return len;
 }
 
 /**
- * Callback function called by libxml2 to write to the XML file output stream.
+ * Write a list of values as an XML document.
  */
-int writeFileCallback(void *context, const char* buffer, int len) {
-    std::ofstream* os = static_cast<std::ofstream*>(context);
-    os->write(buffer, len);
-    if (os->fail() || os->bad())
-        return -1;
-    return len;
+template<typename R> const R writeXML(const lambda<R(R, std::string)>& reduce, 
const R& initial, const list<value>& l) {
+    XMLWriteContext<R> cx(reduce, initial);
+    xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback<R>, NULL, 
&cx, NULL);
+    xmlTextWriterPtr xml = xmlNewTextWriter(out);
+    if (xml != NULL)
+        write(l, xml);
+    return cx.accum;
 }
 
-/**
- * Callback function called by libxml2 to close the XML file output stream.
- */
-int writeCloseFileCallback(void *context) {
-    std::ofstream* fos = static_cast<std::ofstream*>(context);
-    fos->close();
-    return 0;
+const list<std::string> writeXMLList(const list<std::string>& listSoFar, const 
std::string& s) {
+    return cons(s, listSoFar);
 }
 
 /**
- * Write an XML document to a file output stream.
+ * Write a list of values as an XML document represented as a list of strings.
  */
-const bool writeXML(const list<value>& l, std::ofstream& os) {
-    xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeFileCallback, 
writeCloseFileCallback, &os, NULL);
-    xmlTextWriterPtr xml = xmlNewTextWriter(out);
-    if (xml == NULL)
-        return false;
-    return write(l, xml);
+const list<std::string> writeXML(const list<value>& l) {
+    lambda<list<std::string>(list<std::string>, std::string)> 
writer(writeXMLList);
+    return reverse(writeXML(writer, list<std::string>(), l));
 }
 
 }

Modified: tuscany/cpp/sca/modules/json/json-test.cpp
URL: 
http://svn.apache.org/viewvc/tuscany/cpp/sca/modules/json/json-test.cpp?rev=821715&r1=821714&r2=821715&view=diff
==============================================================================
--- tuscany/cpp/sca/modules/json/json-test.cpp (original)
+++ tuscany/cpp/sca/modules/json/json-test.cpp Mon Oct  5 08:21:40 2009
@@ -27,6 +27,7 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+#include "slist.hpp"
 #include "json.hpp"
 
 namespace tuscany {
@@ -41,6 +42,11 @@
     return true;
 }
 
+std::ostringstream* jsonWriter(std::ostringstream* os, const std::string& s) {
+    (*os) << s;
+    return os;
+}
+
 bool testJSON() {
     JSONContext cx;
 
@@ -49,16 +55,22 @@
     print(l, std::cout);
     std::cout << std::endl;
 
-    std::ostringstream sos;
-    writeJSON(cx, l, sos);
-    std::cout << sos.str() << std::endl;
-
-    std::istringstream is(sos.str());
-    list<value> r = readJSON(cx, is);
+    std::ostringstream os;
+    lambda<std::ostringstream*(std::ostringstream*, std::string)> 
writer(jsonWriter);
+    writeJSON(cx, writer, &os, l);
+    std::cout << os.str() << std::endl;
+
+    std::istringstream is(os.str());
+    list<std::string> il = makeStreamList(is);
+    list<value> r = readJSON(cx, il);
     print(r, std::cout);
     std::cout << std::endl;
     assert(r == l);
 
+    std::ostringstream wos;
+    write(writeJSON(cx, r), wos);
+    assert(wos.str() == os.str());
+
     return true;
 }
 

Modified: tuscany/cpp/sca/modules/json/json.hpp
URL: 
http://svn.apache.org/viewvc/tuscany/cpp/sca/modules/json/json.hpp?rev=821715&r1=821714&r2=821715&view=diff
==============================================================================
--- tuscany/cpp/sca/modules/json/json.hpp (original)
+++ tuscany/cpp/sca/modules/json/json.hpp Mon Oct  5 08:21:40 2009
@@ -19,8 +19,8 @@
 
 /* $Rev$ $Date$ */
 
-#ifndef tuscany_eval_driver_hpp
-#define tuscany_eval_driver_hpp
+#ifndef tuscany_json_hpp
+#define tuscany_json_hpp
 
 /**
  * JSON read/write functions.
@@ -29,8 +29,6 @@
 #include <assert.h>
 #define XP_UNIX
 #include <jsapi.h>
-#include <iostream>
-#include <sstream>
 #include <string>
 #include "list.hpp"
 #include "value.hpp"
@@ -191,41 +189,27 @@
 }
 
 /**
- * Reads characters from a JSON input stream.
+ * Consumes JSON strings and populates a JS object.
  */
-JSString* readCallback(const JSONContext& cx, std::istream& is) {
-    char buffer[1024];
-    if(is.eof())
-        return NULL;
-    is.read(buffer, 1024);
-    const int n = is.gcount();
-    if(n <= 0)
-        return NULL;
-    return JS_NewStringCopyN(cx, buffer, n);
-}
-
-/**
- * Consumes a JSON document and populates a JS object from it.
- */
-bool consumeJSON(const JSONContext& cx, JSONParser* parser, std::istream& is) {
-    JSString* jstr = readCallback(cx, is);
-    if(jstr == NULL)
+bool consumeJSON(const JSONContext& cx, JSONParser* parser, const 
list<std::string>& ilist) {
+    if (isNil(ilist))
         return true;
+    JSString* jstr = JS_NewStringCopyZ(cx, car(ilist).c_str());
     if(!JS_ConsumeJSONText(cx, parser, JS_GetStringChars(jstr), 
JS_GetStringLength(jstr)))
         return false;
-    return consumeJSON(cx, parser, is);
+    return consumeJSON(cx, parser, cdr(ilist));
 }
 
 /**
- * Read a JSON document from an input stream.
+ * Read JSON tokens from list of strings.
  */
-const list<value> readJSON(const JSONContext& cx, std::istream& is) {
+const list<value> readJSON(const JSONContext& cx, const list<std::string>& 
ilist) {
     jsval val;
     JSONParser* parser = JS_BeginJSONParse(cx, &val);
     if(parser == NULL)
         return list<value> ();
 
-    bool ok = consumeJSON(cx, parser, is);
+    bool ok = consumeJSON(cx, parser, ilist);
 
     if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL))
         return list<value> ();
@@ -308,42 +292,47 @@
 /**
  * Context passed to JSON write callback function.
  */
-class JSONWriteContext {
+template<typename R> class JSONWriteContext {
 public:
-    JSONWriteContext(const JSONContext& cx, std::ostream& os) :
-        os(os), cx(cx) {
+    JSONWriteContext(const JSONContext& cx, const lambda<R(R, std::string)>& 
reduce, const R& accum) : cx(cx), reduce(reduce), accum(accum) {
     }
-
-private:
-    std::ostream& os;
     const JSONContext& cx;
-
-    friend JSBool writeCallback(const jschar *buf, uint32 len, void *data);
+    const lambda<R(R, std::string)> reduce;
+    R accum;
 };
 
 /**
- * Called by JS_Stringify to write JSON document.
+ * Called by JS_Stringify to write JSON out.
  */
-JSBool writeCallback(const jschar *buf, uint32 len, void *data) {
-    JSONWriteContext& cx = *(static_cast<JSONWriteContext*> (data));
-    JSString* jstr = JS_NewUCStringCopyN(cx.cx, buf, len);
-    cx.os.write(JS_GetStringBytes(jstr), JS_GetStringLength(jstr));
-    if(cx.os.fail() || cx.os.bad())
-        return JS_FALSE;
+template<typename R> JSBool writeCallback(const jschar *buf, uint32 len, void 
*data) {
+    JSONWriteContext<R>& wcx = *(static_cast<JSONWriteContext<R>*> (data));
+    JSString* jstr = JS_NewUCStringCopyN(wcx.cx, buf, len);
+    wcx.accum = wcx.reduce(wcx.accum, std::string(JS_GetStringBytes(jstr), 
JS_GetStringLength(jstr)));
     return JS_TRUE;
 }
 
 /**
- * Write a JSON document to an output stream.
+ * Write a list of values as a JSON document.
  */
-const bool writeJSON(const JSONContext& cx, const list<value>& l, 
std::ostream& os) {
+template<typename R> const R writeJSON(const JSONContext& cx, const 
lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
     jsval val = valueToJSVal(cx, l);
-    JSONWriteContext wcx(cx, os);
-    if(!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback, &wcx))
-        return false;
-    return true;
+    JSONWriteContext<R> wcx(cx, reduce, initial);
+    JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx);
+    return wcx.accum;
+}
+
+const list<std::string> writeJSONList(const list<std::string>& listSoFar, 
const std::string& s) {
+    return cons(s, listSoFar);
+}
+
+/**
+ * Write a list of values as a JSON document represented as a list of strings.
+ */
+const list<std::string> writeJSON(const JSONContext& cx, const list<value>& l) 
{
+    lambda<list<std::string>(list<std::string>, std::string)> 
writer(writeJSONList);
+    return reverse(writeJSON(cx, writer, list<std::string>(), l));
 }
 
 }
 
-#endif
+#endif /* tuscany_json_hpp */


Reply via email to