summaryrefslogtreecommitdiffstats
path: root/sca-cpp/branches/lightweight-sca/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/branches/lightweight-sca/kernel')
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/Makefile.am50
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/config.hpp121
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/dynlib-test.cpp48
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp100
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/element.hpp304
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/fstream.hpp404
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/function.hpp238
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/gc.hpp500
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp136
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/hash.hpp207
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp614
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/lambda-test.cpp103
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/list.hpp617
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp163
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/monad.hpp627
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp261
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/parallel.hpp466
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/perf.hpp78
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/sstream.hpp262
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/stream.hpp201
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/string-test.cpp199
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/string.hpp305
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/tree.hpp125
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/value.hpp656
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp235
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/xml.hpp412
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/xsd-test.cpp107
27 files changed, 7539 insertions, 0 deletions
diff --git a/sca-cpp/branches/lightweight-sca/kernel/Makefile.am b/sca-cpp/branches/lightweight-sca/kernel/Makefile.am
new file mode 100644
index 0000000000..e6a7fdb2b3
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/Makefile.am
@@ -0,0 +1,50 @@
+# 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.
+
+
+
+includedir = $(prefix)/include/kernel
+include_HEADERS = *.hpp
+
+string_test_SOURCES = string-test.cpp
+
+noinst_test_LTLIBRARIES = libdynlib-test.la
+noinst_testdir = `pwd`/tmp
+libdynlib_test_la_SOURCES = dynlib-test.cpp
+noinst_DATA = libdynlib-test${libsuffix}
+libdynlib-test${libsuffix}:
+ ln -s .libs/libdynlib-test${libsuffix}
+
+kernel_test_SOURCES = kernel-test.cpp
+
+lambda_test_SOURCES = lambda-test.cpp
+
+mem_test_SOURCES = mem-test.cpp
+
+parallel_test_SOURCES = parallel-test.cpp
+
+xml_test_SOURCES = xml-test.cpp
+xml_test_LDFLAGS = -lxml2
+
+xsd_test_SOURCES = xsd-test.cpp
+xsd_test_LDFLAGS = -lxml2
+
+hash_test_SOURCES = hash-test.cpp
+
+noinst_PROGRAMS = string-test kernel-test lambda-test hash-test mem-test parallel-test xml-test xsd-test
+TESTS = string-test kernel-test lambda-test hash-test mem-test parallel-test xml-test
+
diff --git a/sca-cpp/branches/lightweight-sca/kernel/config.hpp b/sca-cpp/branches/lightweight-sca/kernel/config.hpp
new file mode 100644
index 0000000000..944b9629e7
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/config.hpp
@@ -0,0 +1,121 @@
+/*
+ * 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_config_hpp
+#define tuscany_config_hpp
+
+#include "ap_config.h"
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "../config.h"
+
+/**
+ * Platform configuration and debug functions.
+ */
+namespace tuscany
+{
+
+/**
+ * Attribute used to mark unused parameters.
+ */
+#ifndef unused
+#define unused __attribute__ ((unused))
+#endif
+
+/**
+ * Compiler feature detection.
+ */
+#ifdef __clang__
+
+#if __has_feature(cxx_lambdas)
+#define HAS_CXX0X_LAMBDAS 1
+#endif
+
+#else
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)
+#define HAS_CXX0X_LAMBDAS 1
+#endif
+
+#endif
+
+/**
+ * Debug utilities.
+ */
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Strict compile warnings.
+ */
+#define WANT_MAINTAINER_WARNINGS
+
+/**
+ * Fast fail assertion.
+ */
+#define WANT_MAINTAINER_ASSERT
+
+/**
+ * Debug log.
+ */
+#define WANT_MAINTAINER_LOG
+
+/**
+ * Add string watch members to important classes to help watch them in a debugger.
+ */
+//#define WANT_MAINTAINER_WATCH
+
+/**
+ * Maintain counters of important objects to help test garbage collection.
+ */
+//#define WANT_MAINTAINER_COUNTERS
+
+#ifdef WANT_MAINTAINER_COUNTERS
+
+bool debug_inc(long int& c) {
+ c++;
+ return true;
+}
+
+bool debug_dec(long int& c) {
+ c--;
+ return true;
+}
+
+#else
+
+#define debug_inc(c)
+#define debug_dec(c)
+
+#endif
+
+#else
+
+#define debug_inc(c)
+#define debug_dec(c)
+
+#endif
+
+}
+#endif /* tuscany_config_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/dynlib-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/dynlib-test.cpp
new file mode 100644
index 0000000000..419fa29db5
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/dynlib-test.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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$ */
+
+/**
+ * Test library.
+ */
+
+#include "function.hpp"
+
+namespace tuscany {
+namespace test {
+
+ const int cppsquare(int x) {
+ return x * x;
+ }
+
+}
+}
+
+extern "C" {
+
+ const int csquare(const int x) {
+ return tuscany::test::cppsquare(x);
+ }
+
+ const tuscany::lambda<int(const int)> csquarel() {
+ return tuscany::lambda<int(const int)>(tuscany::test::cppsquare);
+ }
+
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp b/sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp
new file mode 100644
index 0000000000..69359b4dae
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp
@@ -0,0 +1,100 @@
+/*
+ * 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_dlib_hpp
+#define tuscany_dlib_hpp
+
+/**
+ * Simple dynamic library access functions.
+ */
+
+#include <dlfcn.h>
+
+#include "function.hpp"
+#include "gc.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+
+/**
+ * OS specific dynamic library file extension.
+ */
+#ifdef IS_DARWIN
+const string dynlibExt(".dylib");
+#else
+const string dynlibExt(".so");
+#endif
+
+/**
+ * Represents a reference to a dynamic library.
+ */
+class lib {
+public:
+ lib() : h(NULL), owner(false) {
+ }
+
+ lib(const string& name) : name(name), h(dlopen(c_str(name), RTLD_NOW)), owner(true) {
+ if (h == NULL)
+ h = mkfailure<void*>(string("Could not load library: ") + name + ": " + dlerror());
+ }
+
+ lib(const lib& l) : name(l.name), h(l.h), owner(false) {
+ }
+
+ const lib& operator=(const lib& l) {
+ if(this == &l)
+ return *this;
+ name = l.name;
+ h = l.h;
+ owner = false;
+ return *this;
+ }
+
+ ~lib() {
+ if (!owner)
+ return;
+ if (!hasContent(h) || content(h) == NULL)
+ return;
+ dlclose(content(h));
+ }
+
+private:
+ template<typename S> friend const failable<lambda<S> > dynlambda(const string& name, const lib& l);
+
+ string name;
+ failable<void*> h;
+ bool owner;
+};
+
+/**
+ * Find a lambda function in a dynamic library.
+ */
+template<typename S> const failable<lambda<S> > dynlambda(const string& name, const lib& l) {
+ if (!hasContent(l.h))
+ return mkfailure<lambda<S>>(l.h);
+ const void* s = dlsym(content(l.h), c_str(name));
+ if (s == NULL)
+ return mkfailure<lambda<S> >(string("Could not load symbol: ") + name);
+ return lambda<S>((S*)s);
+}
+
+}
+#endif /* tuscany_dlib_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/element.hpp b/sca-cpp/branches/lightweight-sca/kernel/element.hpp
new file mode 100644
index 0000000000..27b5af8691
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/element.hpp
@@ -0,0 +1,304 @@
+/*
+ * 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_element_hpp
+#define tuscany_element_hpp
+
+/**
+ * Functions to help represent data as lists of elements and attributes.
+ */
+
+#include "list.hpp"
+#include "value.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Tags used to tag lists of elements and attributes.
+ */
+const value attribute("attribute");
+const value element("element");
+const string atsign("@");
+
+/**
+ * Returns true if a value is an element.
+ */
+bool isElement(const value& v) {
+ if (!isList(v) || isNil(v) || element != car<value>(v))
+ return false;
+ return true;
+}
+
+/**
+ * Returns true if a value is an attribute.
+ */
+bool isAttribute(const value& v) {
+ if (!isList(v) || isNil(v) || attribute != car<value>(v))
+ return false;
+ return true;
+}
+
+/**
+ * Returns the name of an attribute.
+ */
+const value attributeName(const list<value>& l) {
+ return cadr(l);
+}
+
+/**
+ * Returns the value of an attribute.
+ */
+const value attributeValue(const list<value>& l) {
+ return caddr(l);
+}
+
+/**
+ * Returns the name of an element.
+ */
+const value elementName(const list<value>& l) {
+ return cadr(l);
+}
+
+/**
+ * Returns true if an element has children.
+ */
+const bool elementHasChildren(const list<value>& l) {
+ return !isNil(cddr(l));
+}
+
+/**
+ * Returns the children of an element.
+ */
+const list<value> elementChildren(const list<value>& l) {
+ return cddr(l);
+}
+
+/**
+ * Returns true if an element has a value.
+ */
+const bool elementHasValue(const list<value>& l) {
+ const list<value> r = reverse(l);
+ if (isSymbol(car(r)))
+ return false;
+ if(isList(car(r)) && !isNil((list<value>)car(r)) && isSymbol(car<value>(car(r))))
+ return false;
+ return true;
+}
+
+/**
+ * Returns the value of an element.
+ */
+const value elementValue(const list<value>& l) {
+ return car(reverse(l));
+}
+
+/**
+ * Convert an element to a value.
+ */
+const bool elementToValueIsList(const value& v) {
+ if (!isList(v))
+ return false;
+ const list<value> l = v;
+ return (isNil(l) || !isSymbol(car(l)));
+}
+
+const value elementToValue(const value& t) {
+ const list<value> elementsToValues(const list<value>& e);
+
+ // Convert an attribute
+ if (isTaggedList(t, attribute))
+ return mklist<value>(c_str(atsign + attributeName(t)), attributeValue(t));
+
+ // Convert an element
+ if (isTaggedList(t, element)) {
+
+ // Convert an element's value
+ if (elementHasValue(t)) {
+
+ // Convert a single value
+ if (!elementToValueIsList(elementValue(t)))
+ return mklist(elementName(t), elementValue(t));
+
+ // Convert a list value
+ return cons(elementName(t), mklist<value>(elementsToValues(elementValue(t))));
+ }
+
+ // Convert an element's children
+ return cons(elementName(t), elementsToValues(elementChildren(t)));
+ }
+
+ // Convert a value
+ if (!isList(t))
+ return t;
+ return elementsToValues(t);
+}
+
+/**
+ * Convert a list of elements to a list of values.
+ */
+const bool elementToValueIsSymbol(const value& v) {
+ if (!isList(v))
+ return false;
+ const list<value> l = v;
+ if (isNil(l))
+ return false;
+ if (!isSymbol(car(l)))
+ return false;
+ return true;
+}
+
+const list<value> elementToValueGroupValues(const value& v, const list<value>& l) {
+ if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l)))
+ return cons(v, l);
+ if (car<value>(car(l)) != car<value>(v))
+ return cons(v, l);
+ if (!elementToValueIsList(cadr<value>(car(l)))) {
+ const value g = mklist<value>(car<value>(v), mklist<value>(isList(cadr<value>(v))? (value)cdr<value>(v) : cadr<value>(v), isList(cadr<value>(car(l)))? (value)cdr<value>(car(l)) : cadr<value>(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+ }
+ const value g = mklist<value>(car<value>(v), cons<value>(isList(cadr<value>(v))? (value)cdr<value>(v) : cadr<value>(v), (list<value>)cadr<value>(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+
+}
+
+const list<value> elementsToValues(const list<value>& e) {
+ if (isNil(e))
+ return e;
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)));
+}
+
+/**
+ * Convert a value to an element.
+ */
+const value valueToElement(const value& t) {
+ const list<value> valuesToElements(const list<value>& l);
+
+ // Convert a name value pair
+ if (isList(t) && !isNil((list<value>)t) && isSymbol(car<value>(t))) {
+ const value n = car<value>(t);
+ const value v = isNil(cdr<value>(t))? value() : cadr<value>(t);
+
+ // Convert a single value to an attribute or an element
+ if (!isList(v)) {
+ if (substr(n, 0, 1) == atsign)
+ return mklist<value>(attribute, c_str(substr(n, 1)), v);
+ return mklist(element, n, v);
+ }
+
+ // Convert a list value
+ if (isNil((list<value>)v) || !isSymbol(car<value>(v)))
+ return cons(element, cons(n, mklist<value>(valuesToElements(v))));
+
+ // Convert a nested name value pair value
+ return cons(element, cons(n, valuesToElements(cdr<value>(t))));
+ }
+
+ // Convert a value
+ if (!isList(t))
+ return t;
+ return valuesToElements(t);
+}
+
+/**
+ * Convert a list of values to a list of elements.
+ */
+const list<value> valuesToElements(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(valueToElement(car(l)), valuesToElements(cdr(l)));
+}
+
+/**
+ * Returns a selector lambda function which can be used to filter
+ * elements against the given element pattern.
+ */
+struct selectorLambda {
+ const list<value> select;
+ selectorLambda(const list<value>& s) : select(s) {
+ }
+ const bool evalSelect(const list<value>& s, const list<value> v) const {
+ if (isNil(s))
+ return true;
+ if (isNil(v))
+ return false;
+ if (car(s) != car(v))
+ return false;
+ return evalSelect(cdr(s), cdr(v));
+ }
+ const bool operator()(const value& v) const {
+ if (!isList(v))
+ return false;
+ return evalSelect(select, v);
+ }
+};
+
+const lambda<bool(const value&)> selector(const list<value> s) {
+ return selectorLambda(s);
+}
+
+/**
+ * Returns the value of the attribute with the given name.
+ */
+struct filterAttribute {
+ const value name;
+ filterAttribute(const value& n) : name(n) {
+ }
+ const bool operator()(const value& v) const {
+ return isAttribute(v) && attributeName((list<value>)v) == name;
+ }
+};
+
+const value attributeValue(const value& name, const value& l) {
+ const list<value> f = filter<value>(filterAttribute(name), list<value>(l));
+ if (isNil(f))
+ return value();
+ return caddr<value>(car(f));
+}
+
+/**
+ * Returns child elements with the given name.
+ */
+struct filterElement {
+ const value name;
+ filterElement(const value& n) : name(n) {
+ }
+ const bool operator()(const value& v) const {
+ return isElement(v) && elementName((list<value>)v) == name;
+ }
+};
+
+const value elementChildren(const value& name, const value& l) {
+ return filter<value>(filterElement(name), list<value>(l));
+}
+
+/**
+ * Return the child element with the given name.
+ */
+const value elementChild(const value& name, const value& l) {
+ const list<value> f = elementChildren(name, l);
+ if (isNil(f))
+ return value();
+ return car(f);
+}
+
+}
+#endif /* tuscany_element_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/fstream.hpp b/sca-cpp/branches/lightweight-sca/kernel/fstream.hpp
new file mode 100644
index 0000000000..4f7f5152aa
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/fstream.hpp
@@ -0,0 +1,404 @@
+/*
+ * 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_fstream_hpp
+#define tuscany_fstream_hpp
+
+/**
+ * File based streams.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef WANT_HTTPD_LOG
+#include <apr_strings.h>
+#include <apr_fnmatch.h>
+#include <apr_lib.h>
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+#include <apr_base64.h>
+
+#include <httpd.h>
+// Hack to workaround compile error with CLang/LLVM
+#undef strtoul
+// Hack to workaround compile error with HTTPD 2.3.8
+#define new new_
+#include <http_config.h>
+#undef new
+#include <http_main.h>
+#include <http_log.h>
+
+#else
+
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#ifdef WANT_THREADS
+#include <pthread.h>
+#endif
+
+#endif
+
+#include "string.hpp"
+#include "stream.hpp"
+
+namespace tuscany {
+
+/*
+ * Output stream backed by a FILE.
+ */
+class ofstream : public ostream {
+public:
+ ofstream(const string& path) : file(fopen(c_str(path), "wb")), owner(true) {
+ }
+
+ ofstream(FILE* file) : file(file), owner(false) {
+ }
+
+ ofstream(const ofstream& os) : file(os.file), owner(false) {
+ }
+
+ const ofstream& operator=(const ofstream& os) {
+ if(this == &os)
+ return *this;
+ file = os.file;
+ owner = false;
+ return *this;
+ }
+
+ ~ofstream() {
+ if (!owner)
+ return;
+ if (file == NULL)
+ return;
+ fclose(file);
+ }
+
+ const bool fail() {
+ return file == NULL;
+ }
+
+ ofstream& vprintf(const char* fmt, ...) {
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (file, fmt, args);
+ va_end (args);
+ return *this;
+ }
+
+ ofstream& write(const string& s) {
+ fwrite(c_str(s), 1, length(s), file);
+ return *this;
+ }
+
+ ofstream& flush() {
+ fflush(file);
+ return *this;
+ }
+
+private:
+ FILE* file;
+ bool owner;
+};
+
+/*
+ * Input stream backed by a FILE.
+ */
+class ifstream : public istream {
+public:
+ ifstream(const string& path) : file(fopen(c_str(path), "rb")), owner(true) {
+ }
+
+ ifstream(FILE* file) : file(file), owner(false) {
+ }
+
+ ifstream(const ifstream& is) : file(is.file), owner(false) {
+ }
+
+ const ifstream& operator=(const ifstream& is) {
+ if(this == &is)
+ return *this;
+ file = is.file;
+ owner = false;
+ return *this;
+ }
+
+ ~ifstream() {
+ if (!owner)
+ return;
+ if (file == NULL)
+ return;
+ fclose(file);
+ }
+
+ const size_t read(void* buf, size_t size) {
+ return fread(buf, 1, size, file);
+ }
+
+ const bool eof() {
+ return feof(file);
+ }
+
+ const bool fail() {
+ return file == NULL;
+ }
+
+ const int get() {
+ return fgetc(file);
+ }
+
+ const int peek() {
+ int c = fgetc(file);
+ if (c == -1)
+ return c;
+ ungetc(c, file);
+ return c;
+ }
+
+private:
+ FILE* file;
+ bool owner;
+};
+
+/**
+ * Standard streams.
+ */
+ofstream cout(stdout);
+ofstream cerr(stderr);
+ifstream cin(stdin);
+
+/**
+ * Streams used for logging.
+ */
+
+#ifdef WANT_HTTPD_LOG
+
+/*
+ * HTTPD-based log stream.
+ */
+class loghstream : public ostream {
+public:
+ loghstream(const int level) : level(level), len(0) {
+ }
+
+ ~loghstream() {
+ }
+
+ ostream& vprintf(const char* fmt, ...) {
+ va_list args;
+ va_start (args, fmt);
+ const int l = vsnprintf(buf + len, (sizeof(buf) - 1) - len, fmt, args);
+ va_end (args);
+ len += l;
+ if (len > (int)(sizeof(buf) - 1))
+ len = sizeof(buf) - 1;
+ return *this;
+ }
+
+ ostream& write(const string& s) {
+ if (s != "\n")
+ return this->vprintf("%s", c_str(s));
+ buf[len] = '\0';
+ ap_log_error(NULL, 0, -1, level, 0, ap_server_conf, "%s", buf);
+ len = 0;
+ return *this;
+ }
+
+ ostream& flush() {
+ return *this;
+ }
+
+private:
+ const int level;
+ int len;
+ char buf[2049];
+};
+
+/**
+ * Info and failure log streams.
+ */
+loghstream cinfo(APLOG_INFO);
+loghstream cfailure(APLOG_ERR);
+
+#ifdef WANT_MAINTAINER_LOG
+
+/**
+ * Debug log stream.
+ */
+loghstream cdebug(APLOG_DEBUG);
+
+/**
+ * Return true if debug log is enabled.
+ */
+#define debug_islogging() (bool)(APLOG_MODULE_IS_LEVEL(ap_server_conf, APLOG_NO_MODULE, APLOG_DEBUG))
+
+#endif
+
+#else
+
+/**
+ * Format the current time.
+ */
+const string logTime() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ const time_t t = tv.tv_sec;
+ const tm* lt = localtime(&t);
+ char ft[32];
+ strftime(ft, 20, "%a %b %d %H:%M:%S", lt);
+ sprintf(ft + 19, ".%06lu ", (unsigned long)tv.tv_usec);
+ strftime(ft + 27, 5, "%Y", lt);
+ return ft;
+}
+
+/*
+ * File-based log stream.
+ */
+class logfstream : public ostream {
+public:
+ logfstream(FILE* file, const string& type) : file(file), type(type), head(false) {
+ }
+
+ logfstream(const logfstream& os) : file(os.file), type(os.type), head(os.head) {
+ }
+
+ ~logfstream() {
+ }
+
+ ostream& vprintf(const char* fmt, ...) {
+ whead();
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (file, fmt, args);
+ va_end (args);
+ return *this;
+ }
+
+ ostream& write(const string& s) {
+ whead();
+ fwrite(c_str(s), 1, length(s), file);
+ if (s == "\n")
+ head = false;
+ return *this;
+ }
+
+ ostream& flush() {
+ fflush(file);
+ return *this;
+ }
+
+private:
+ FILE* file;
+ const string type;
+ bool head;
+
+ const unsigned long tid() const {
+#ifdef WANT_THREADS
+ return (unsigned long)pthread_self();
+#else
+ return 0;
+#endif
+ }
+
+ ostream& whead() {
+ if (head)
+ return *this;
+ head = true;
+ *this << "[" << logTime() << "] [" << type << "] [pid " << (unsigned long)getpid() << ":tid " << tid() << "] ";
+ return *this;
+ }
+};
+
+/**
+ * Info and failure log streams.
+ */
+logfstream cinfo(stderr, "info");
+logfstream cfailure(stderr, "error");
+
+#ifdef WANT_MAINTAINER_LOG
+
+/**
+ * Debug log stream.
+ */
+logfstream cdebug(stderr, "debug");
+
+/**
+ * Return true if debug log is enabled.
+ */
+bool debug_isLoggingSet = false;
+bool debug_isLoggingEnv = false;
+
+const bool debug_isLogging() {
+ if (debug_isLoggingSet)
+ return debug_isLoggingEnv;
+ debug_isLoggingEnv = getenv("TUSCANY_DEBUG_LOG") != NULL;
+ return debug_isLoggingEnv;
+}
+
+#define debug_islogging() debug_isLogging()
+
+#endif
+
+#endif
+
+#ifdef WANT_MAINTAINER_LOG
+
+/**
+ * Log a debug message.
+ */
+const bool debugLog(const string& msg) {
+ gc_scoped_pool p;
+ cdebug << msg << endl;
+ return true;
+}
+
+/**
+ * Log a debug message and a value.
+ */
+template<typename V> const bool debugLog(const V& v, const string& msg) {
+ gc_scoped_pool p;
+ cdebug << msg << ": " << v << endl;
+ return true;
+}
+
+/**
+ * Log a debug message and two values.
+ */
+template<typename V, typename W> const bool debugLog(const V& v, const W& w, const string& msg) {
+ gc_scoped_pool p;
+ cdebug << msg << ": " << v << " : " << w << endl;
+ return true;
+}
+
+#define debug(...) do { if (debug_islogging()) tuscany::debugLog(__VA_ARGS__); } while(0)
+
+#else
+
+#define debug_islogging() false
+#define debug(...)
+
+#endif
+
+}
+
+#endif /* tuscany_fstream_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/function.hpp b/sca-cpp/branches/lightweight-sca/kernel/function.hpp
new file mode 100644
index 0000000000..60117dab98
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/function.hpp
@@ -0,0 +1,238 @@
+/*
+ * 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_function_hpp
+#define tuscany_function_hpp
+
+/**
+ * Lambda function type.
+ */
+
+#include <utility>
+#include "fstream.hpp"
+#include "gc.hpp"
+#include "config.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_MAINTAINER_COUNTERS
+
+/**
+ * Debug counters.
+ */
+long int countProxies;
+long int countFProxies = 0;
+long int countCProxies = 0;
+long int countLambdas = 0;
+long int countELambdas = 0;
+long int countCLambdas = 0;
+long int countFLambdas = 0;
+
+bool resetLambdaCounters() {
+ countLambdas = countELambdas = countCLambdas = countFLambdas = countProxies = countFProxies = countCProxies = 0;
+ return true;
+}
+
+bool checkLambdaCounters() {
+ return countLambdas == 0;
+}
+
+bool printLambdaCounters() {
+ cout << "countLambdas " << countLambdas << endl;
+ cout << "countELambdas " << countELambdas << endl;
+ cout << "countFLambdas " << countFLambdas << endl;
+ cout << "countCLambdas " << countCLambdas << endl;
+ cout << "countProxies " << countProxies << endl;
+ cout << "countFProxies " << countFProxies << endl;
+ cout << "countCProxies " << countCProxies << endl;
+ return true;
+}
+
+#else
+
+#define resetLambdaCounters()
+#define checkLambdaCounters() true
+#define printLambdaCounters()
+
+#endif
+
+/**
+ * Lambda function type.
+ */
+
+template<typename R, typename... P> class Callable {
+public:
+ Callable() {
+ }
+
+ virtual const size_t size() const = 0;
+
+ virtual const R operator()(P... p) const = 0;
+
+ virtual ~Callable() {
+ }
+
+ template<typename F> class Proxy: public Callable {
+ public:
+ Proxy(const F& f) : function(f) {
+ debug_inc(countProxies);
+ debug_inc(countFProxies);
+ }
+
+ Proxy(const Proxy& p) : function(p.function) {
+ debug_inc(countProxies);
+ debug_inc(countCProxies);
+ }
+
+ ~Proxy() {
+ debug_dec(countProxies);
+ }
+
+ virtual const R operator() (P... p) const {
+ return function(std::forward<P>(p)...);
+ }
+
+ virtual const size_t size() const {
+ return sizeof(function);
+ }
+
+ private:
+ const F function;
+ };
+};
+
+template<typename S> class lambda;
+
+template<typename R, typename... P> class lambda<R(P...)> {
+public:
+ lambda() : callable(0) {
+ debug_inc(countLambdas);
+ debug_inc(countELambdas);
+ }
+
+ template<typename F> lambda(const F f) {
+ debug_inc(countLambdas);
+ debug_inc(countFLambdas);
+
+ typedef typename CallableType::template Proxy<F> ProxyType;
+ callable = gc_ptr<CallableType>(new (gc_new<ProxyType>()) ProxyType(f));
+ }
+
+ lambda(const lambda& l) {
+ debug_inc(countLambdas);
+ debug_inc(countCLambdas);
+ callable = l.callable;
+ }
+
+ const lambda& operator=(const lambda& l) {
+ if (this == &l)
+ return *this;
+ callable = l.callable;
+ return *this;
+ }
+
+ ~lambda() {
+ debug_dec(countLambdas);
+ }
+
+ const bool operator==(const lambda& l) const {
+ if (this == &l)
+ return true;
+ return callable == l.callable;
+ }
+
+ const bool operator!=(const lambda& l) const {
+ return !this->operator==(l);
+ }
+
+ const R operator()(P... p) const {
+ return (*callable)(std::forward<P>(p)...);
+ }
+
+ template<typename S> friend ostream& operator<<(ostream&, const lambda<S>&);
+ template<typename S> friend const bool isNil(const lambda<S>& l);
+
+private:
+ typedef Callable<R,P...> CallableType;
+ gc_ptr<CallableType> callable;
+};
+
+template<typename S> ostream& operator<<(ostream& out, const lambda<S>& l) {
+ return out << "lambda::" << l.callable;
+}
+
+/**
+ * Return true if a lambda is nil.
+ */
+template<typename S> const bool isNil(const lambda<S>& l) {
+ return ((void*)l.callable) == 0;
+}
+
+/**
+ * Curry a lambda function.
+ */
+template<typename R, typename T, typename... P> class curried {
+public:
+ curried(const lambda<R(T, P...)>& f, const T& v): v(v), f(f) {
+ }
+
+ const R operator()(P... p) const {
+ return f(v, std::forward<P>(p)...);
+ }
+
+private:
+ const T v;
+ const lambda<R(T, P...)>f;
+};
+
+template<typename R, typename T, typename... P> const lambda<R(P...)> curry(const lambda<R(T, P...)>& f, const T& t) {
+ return curried<R, T, P...>(f, t);
+}
+
+template<typename R, typename T, typename U, typename... P> const lambda<R(P...)> curry(const lambda<R(T, U, P...)>& f, const T& t, const U& u) {
+ return curry(curry(f, t), u);
+}
+
+template<typename R, typename T, typename U, typename V, typename... P> const lambda<R(P...)> curry(const lambda<R(T, U, V, P...)>& f, const T& t, const U& u, const V& v) {
+ return curry(curry(curry(f, t), u), v);
+}
+
+/**
+ * A lambda function that returns the given value.
+ */
+template<typename T> class returnResult {
+public:
+ returnResult(const T& v) :
+ v(v) {
+ }
+ const T operator()() const {
+ return v;
+ }
+private:
+ const T v;
+};
+
+template<typename T> const lambda<T()> result(const T& v) {
+ return returnResult<T> (v);
+}
+
+}
+#endif /* tuscany_function_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/gc.hpp b/sca-cpp/branches/lightweight-sca/kernel/gc.hpp
new file mode 100644
index 0000000000..32ad8160cc
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/gc.hpp
@@ -0,0 +1,500 @@
+/*
+ * 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_gc_hpp
+#define tuscany_gc_hpp
+
+/**
+ * Garbage collected memory management, using APR memory pools.
+ */
+
+#include "config.hpp"
+#ifdef WANT_MALLOC_MMAP
+#include <sys/mman.h>
+#include <malloc.h>
+#endif
+#include <stdlib.h>
+#include <apr_general.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+#include <assert.h>
+#include <new>
+#ifdef WANT_THREADS
+#include <pthread.h>
+#endif
+
+namespace tuscany
+{
+
+#ifdef WANT_MAINTAINER_ASSERT
+
+/**
+ * Force a core dump on assertion violation.
+ */
+bool assertOrFail(const bool expr) {
+ if (!expr)
+ abort();
+ return true;
+}
+
+#else
+
+#define assertOrFail(expr)
+
+#endif
+
+/**
+ * Pointer to a value.
+ */
+template<typename T> class gc_ptr {
+public:
+ gc_ptr(T* ptr = NULL) throw() : ptr(ptr) {
+ }
+
+ ~gc_ptr() throw() {
+ }
+
+ gc_ptr(const gc_ptr& r) throw() : ptr(r.ptr) {
+ }
+
+ gc_ptr& operator=(const gc_ptr& r) throw() {
+ if(this == &r)
+ return *this;
+ ptr = r.ptr;
+ return *this;
+ }
+
+ const bool operator==(const gc_ptr& r) const throw() {
+ if (this == &r)
+ return true;
+ return ptr == r.ptr;
+ }
+
+ const bool operator==(T* p) const throw() {
+ return ptr == p;
+ }
+
+ const bool operator!=(const gc_ptr& r) const throw() {
+ return !this->operator==(r);
+ }
+
+ const bool operator!=(T* p) const throw() {
+ return !this->operator==(p);
+ }
+
+ T& operator*() const throw() {
+ return *ptr;
+ }
+
+ T* operator->() const throw() {
+ return ptr;
+ }
+
+ operator T*() const throw() {
+ return ptr;
+ }
+
+ T* ptr;
+};
+
+/**
+ * Initialize APR.
+ */
+class gc_apr_context_t {
+public:
+ gc_apr_context_t() {
+ apr_initialize();
+ }
+} gc_apr_context;
+
+/**
+ * Garbage collected APR memory pool.
+ */
+class gc_pool {
+public:
+ gc_pool() : apr_pool(NULL) {
+ }
+
+ gc_pool(apr_pool_t* p) : apr_pool(p) {
+ }
+
+ gc_pool(const gc_pool& pool) : apr_pool(pool.apr_pool) {
+ }
+
+ gc_pool& operator=(const gc_pool& pool) {
+ if (this == &pool)
+ return *this;
+ apr_pool = pool.apr_pool;
+ return *this;
+ }
+
+private:
+ friend apr_pool_t* pool(const gc_pool& pool);
+ friend class gc_global_pool_t;
+ friend class gc_child_pool;
+ friend class gc_local_pool;
+ friend class gc_scoped_pool;
+
+ apr_pool_t* apr_pool;
+};
+
+/**
+ * Return the APR pool used by a gc_pool.
+ */
+apr_pool_t* pool(const gc_pool& pool) {
+ return pool.apr_pool;
+}
+
+/**
+ * Maintain a stack of memory pools.
+ */
+#ifdef WANT_THREADS
+
+class gc_pool_stack_t {
+public:
+ gc_pool_stack_t() {
+ int rc = pthread_key_create(&key, NULL);
+ assertOrFail(rc == 0);
+ }
+
+ operator apr_pool_t*() const {
+ return static_cast<apr_pool_t*>(pthread_getspecific(key));
+ }
+
+ const gc_pool_stack_t& operator=(apr_pool_t* p) {
+ pthread_setspecific(key, p);
+ return *this;
+ }
+
+private:
+ pthread_key_t key;
+} gc_pool_stack;
+
+#else
+apr_pool_t* gc_pool_stack = NULL;
+#endif
+
+/**
+ * Push a pool onto the stack.
+ */
+apr_pool_t* gc_push_pool(apr_pool_t* pool) {
+ apr_pool_t* p = gc_pool_stack;
+ gc_pool_stack = pool;
+ return p;
+}
+
+/**
+ * Pop a pool from the stack.
+ */
+apr_pool_t* gc_pop_pool(apr_pool_t* pool) {
+ apr_pool_t* p = gc_pool_stack;
+ gc_pool_stack = pool;
+ return p;
+}
+
+/**
+ * Return the current memory pool.
+ */
+apr_pool_t* gc_current_pool() {
+ apr_pool_t* p = gc_pool_stack;
+ if (p != NULL)
+ return p;
+
+ // Create a parent pool for the current thread
+ apr_pool_create(&p, NULL);
+ assertOrFail(p != NULL);
+ gc_push_pool(p);
+ return p;
+}
+
+/**
+ * A child memory pool, which will be destroyed when its parent pool is destroyed.
+ */
+class gc_child_pool : public gc_pool {
+public:
+
+ gc_child_pool() : gc_pool(NULL), owner(true) {
+ apr_pool_create(&apr_pool, gc_current_pool());
+ assertOrFail(apr_pool != NULL);
+ }
+
+ gc_child_pool(const gc_child_pool& p) : gc_pool(p.apr_pool), owner(false) {
+ }
+
+ const gc_child_pool& operator=(const gc_child_pool& p) {
+ if(this == &p)
+ return *this;
+ apr_pool = p.apr_pool;
+ owner = false;
+ return *this;
+ }
+
+
+private:
+ bool owner;
+};
+
+/**
+ * A local pool scope, which will be destroyed when exiting the current scope.
+ */
+class gc_local_pool : public gc_pool {
+public:
+
+ gc_local_pool() : gc_pool(NULL), owner(true) {
+ apr_pool_create(&apr_pool, gc_current_pool());
+ assertOrFail(apr_pool != NULL);
+ }
+
+ ~gc_local_pool() {
+ if (owner)
+ apr_pool_destroy(apr_pool);
+ }
+
+ gc_local_pool(const gc_local_pool& p) : gc_pool(p.apr_pool), owner(false) {
+ }
+
+ const gc_local_pool& operator=(const gc_local_pool& p) {
+ if(this == &p)
+ return *this;
+ apr_pool = p.apr_pool;
+ owner = false;
+ return *this;
+ }
+
+private:
+ bool owner;
+};
+
+/**
+ * A memory pool scope, used to setup a scope in which a particular pool will be
+ * used for all allocations. Will be destroyed when existing the current scope.
+ */
+class gc_scoped_pool : public gc_pool {
+public:
+
+ gc_scoped_pool() : gc_pool(NULL), prev(gc_current_pool()), owner(true) {
+ apr_pool_create(&apr_pool, prev);
+ assertOrFail(apr_pool != NULL);
+ gc_push_pool(apr_pool);
+ }
+
+ gc_scoped_pool(apr_pool_t* p) : gc_pool(p), prev(gc_current_pool()), owner(false) {
+ gc_push_pool(apr_pool);
+ }
+
+ ~gc_scoped_pool() {
+ if (owner)
+ apr_pool_destroy(apr_pool);
+ gc_pop_pool(prev);
+ }
+
+ gc_scoped_pool(const gc_scoped_pool& p) : gc_pool(p.apr_pool), prev(p.prev), owner(false) {
+ }
+
+ const gc_scoped_pool& operator=(const gc_scoped_pool& p) {
+ if(this == &p)
+ return *this;
+ apr_pool = p.apr_pool;
+ prev = p.prev;
+ owner = false;
+ return *this;
+ }
+
+private:
+ apr_pool_t* prev;
+ bool owner;
+};
+
+/**
+ * Allocates a pointer to an object allocated from a memory pool and
+ * register a cleanup callback for it.
+ */
+template<typename T> apr_status_t gc_pool_cleanup(void* v) {
+ T* t = (T*)v;
+ t->~T();
+ return APR_SUCCESS;
+}
+
+template<typename T> T* gc_new(apr_pool_t* p) {
+ void* gc_new_ptr = apr_palloc(p, sizeof(T));
+ assertOrFail(gc_new_ptr != NULL);
+ apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup<T>, apr_pool_cleanup_null) ;
+ return (T*)(gc_new_ptr);
+}
+
+template<typename T> T* gc_new(const gc_pool& p) {
+ return gc_new<T>(pool(p));
+}
+
+template<typename T> T* gc_new() {
+ return gc_new<T>(gc_current_pool());
+}
+
+template<typename T> apr_status_t gc_pool_acleanup(void* v) {
+ size_t* m = static_cast<size_t*>(v);
+ size_t n = *m;
+ T* t = (T*)(m + 1);
+ for (size_t i = 0; i < n; i++, t++)
+ t->~T();
+ return APR_SUCCESS;
+}
+
+template<typename T> T* gc_anew(apr_pool_t* p, size_t n) {
+ size_t* gc_anew_ptr = static_cast<size_t*>(apr_palloc(p, sizeof(size_t) + sizeof(T) * n));
+ assertOrFail(gc_anew_ptr != NULL);
+ *gc_anew_ptr = n;
+ apr_pool_cleanup_register(p, gc_anew_ptr, gc_pool_acleanup<T>, apr_pool_cleanup_null) ;
+ return (T*)(gc_anew_ptr + 1);
+}
+
+template<typename T> T* gc_anew(const gc_pool& p, size_t n) {
+ return gc_anew<T>(pool(p), n);
+}
+
+template<typename T> T* gc_anew(size_t n) {
+ return gc_anew<T>(gc_current_pool(), n);
+}
+
+/**
+ * Allocate an array of chars.
+ */
+char* gc_cnew(apr_pool_t* p, size_t n) {
+ char* gc_cnew_ptr = static_cast<char*>(apr_palloc(p, n));
+ assertOrFail(gc_cnew_ptr != NULL);
+ return gc_cnew_ptr;
+}
+
+char* gc_cnew(size_t n) {
+ return gc_cnew(gc_current_pool(), n);
+}
+
+/**
+ * Pool based equivalent of the standard malloc function.
+ */
+void* gc_pool_malloc(size_t n) {
+ size_t* ptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
+ assertOrFail(ptr != NULL);
+ *ptr = n;
+ return ptr + 1;
+}
+
+/**
+ * Pool based equivalent of the standard realloc function.
+ */
+void* gc_pool_realloc(void* ptr, size_t n) {
+ size_t size = *(static_cast<size_t*>(ptr) - 1);
+ size_t* rptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
+ assertOrFail(rptr != NULL);
+ *rptr = n;
+ memcpy(rptr + 1, ptr, size < n? size : n);
+ return rptr + 1;
+}
+
+/**
+ * Pool based equivalent of the standard free function.
+ */
+void gc_pool_free(unused void* ptr) {
+ // Memory allocated from a pool is freed when the pool is freed
+}
+
+/**
+ * Pool based equivalent of the standard strdup function.
+ */
+char* gc_pool_strdup(const char* str) {
+ char* dptr = static_cast<char*>(gc_pool_malloc(strlen(str) + 1));
+ assertOrFail(dptr != NULL);
+ strcpy(dptr, str);
+ return dptr;
+}
+
+#ifdef WANT_MALLOC_MMAP
+
+/**
+ * Mmap based memory allocation functions.
+ */
+
+/**
+ * Mmap based equivalent of the standard malloc function.
+ */
+void* gc_mmap_malloc(size_t n, unused const void* caller) {
+ //printf("gc_mmap_malloc %d", n);
+ size_t* ptr = static_cast<size_t*>(mmap(NULL, sizeof(size_t) + n, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
+ assertOrFail(ptr != NULL);
+ *ptr = n;
+ //printf(" %p\n", ptr + 1);
+ return ptr + 1;
+}
+
+/**
+ * Mmap based equivalent of the standard realloc function.
+ */
+void* gc_mmap_realloc(void* ptr, size_t n, const void* caller) {
+ if (ptr == NULL)
+ return gc_mmap_malloc(n, caller);;
+ //printf("gc_mmap_realloc %p %d", ptr, n);
+ size_t size = *(static_cast<size_t*>(ptr) - 1);
+ size_t* rptr = static_cast<size_t*>(mremap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size, sizeof(size_t) + n, MREMAP_MAYMOVE, NULL));
+ assertOrFail(rptr != NULL);
+ *rptr = n;
+ //printf(" %p\n", rptr + 1);
+ return rptr + 1;
+}
+
+/**
+ * Mmap based equivalent of the standard free function.
+ */
+void gc_mmap_free(void* ptr, unused const void* caller) {
+ //printf("gc_mmap_free %p\n", ptr);
+ if (ptr == NULL)
+ return;
+ size_t size = *(static_cast<size_t*>(ptr) - 1);
+ munmap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size);
+}
+
+/**
+ * Mmap based equivalent of the standard memalign function.
+ */
+void* gc_mmap_memalign(unused size_t alignment, size_t n, unused const void* caller) {
+ //printf("gc_mmap_memalign %d %d\n", alignment, n);
+ return gc_mmap_malloc(n, caller);
+}
+
+/**
+ * Install the mmap based memory allocation functions.
+ */
+void gc_mmap_init_hook(void) {
+ __malloc_hook = gc_mmap_malloc;
+ __realloc_hook = gc_mmap_realloc;
+ __free_hook = gc_mmap_free;
+ __memalign_hook = gc_mmap_memalign;
+}
+
+#endif
+
+}
+
+#ifdef WANT_MALLOC_MMAP
+
+void (*__malloc_initialize_hook)(void) = tuscany::gc_mmap_init_hook;
+
+#endif
+
+#endif /* tuscany_gc_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp
new file mode 100644
index 0000000000..4e6a3654e5
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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$ */
+
+/**
+ * Test hash functions.
+ */
+
+#include <assert.h>
+#include "string.hpp"
+#include "hash.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+bool testCrc32hash() {
+ const string key("This is a test key");
+ unsigned int h = crc32hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+bool testTimes33hash() {
+ const string key("This is a test key");
+ unsigned int h = times33hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+bool testMurmurhash() {
+ const string key("This is a test key");
+ unsigned int h = murmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+bool testPortablemurmurhash() {
+ const string key("This is a test key");
+ unsigned int h = portablemurmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+struct crc32hashTest {
+ const string key;
+ crc32hashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = crc32hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+struct times33hashTest {
+ const string key;
+ times33hashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = times33hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+struct murmurhashTest {
+ const string key;
+ murmurhashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = murmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+struct portablemurmurhashTest {
+ const string key;
+ portablemurmurhashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = portablemurmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+bool testHashPerf() {
+ const string key("This is a test key");
+ const int count = 100000;
+
+ const lambda<bool()> crc32 = crc32hashTest(key);
+ cout << "crc32hash test " << time(crc32, 5, count) << " ms" << endl;
+ const lambda<bool()> times33 = times33hashTest(key);
+ cout << "times33hash test " << time(times33, 5, count) << " ms" << endl;
+ const lambda<bool()> murmur = murmurhashTest(key);
+ cout << "murmurhash test " << time(murmur, 5, count) << " ms" << endl;
+ const lambda<bool()> portablemurmur = portablemurmurhashTest(key);
+ cout << "portable murmurhash test " << time(portablemurmur, 5, count) << " ms" << endl;
+
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testCrc32hash();
+ tuscany::testTimes33hash();
+ tuscany::testMurmurhash();
+ tuscany::testPortablemurmurhash();
+ tuscany::testHashPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/hash.hpp b/sca-cpp/branches/lightweight-sca/kernel/hash.hpp
new file mode 100644
index 0000000000..993511e3c2
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/hash.hpp
@@ -0,0 +1,207 @@
+/*
+ * 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_hash_hpp
+#define tuscany_hash_hpp
+
+/**
+ * Fast hash functions.
+ */
+
+#include <apr_hash.h>
+#include <apr_memcache.h>
+
+namespace tuscany
+{
+
+/**
+ * Apache apr-util CRC32 hash function.
+ *
+ * See srclib/apr-util/memcache/apr_memcache.c from the Apache HTTPD
+ * source tree. Reproducing the comments from apr_memcache.c here:
+ *
+ * The crc32 functions and data were originally written by Spencer
+ * Garrett <srg@quick.com> and were gleaned from the PostgreSQL source
+ * tree at contrib/ltree/crc32.[ch] and from FreeBSD at
+ * src/usr.bin/cksum/crc32.c.
+ */
+const unsigned int crc32hash(const char* data, const size_t len) {
+ return (unsigned int)apr_memcache_hash_default(NULL, data, len);
+}
+
+/**
+ * Apache apr tables default hash function.
+ *
+ * See srclib/apr/tables/apr_hash.c from the Apache HTTPD source tree.
+ * Reproducing the comments from apr_hash.c here:
+ *
+ * This is the popular `times 33' hash algorithm which is used by
+ * perl and also appears in Berkeley DB. This is one of the best
+ * known hash functions for strings because it is both computed
+ * very fast and distributes very well.
+ *
+ * The originator may be Dan Bernstein but the code in Berkeley DB
+ * cites Chris Torek as the source. The best citation I have found
+ * is "Chris Torek, Hash function for text in C, Usenet message
+ * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich
+ * Salz's USENIX 1992 paper about INN which can be found at
+ * <http://citeseer.nj.nec.com/salz92internetnews.html>.
+ *
+ * The magic of number 33, i.e. why it works better than many other
+ * constants, prime or not, has never been adequately explained by
+ * anyone. So I try an explanation: if one experimentally tests all
+ * multipliers between 1 and 256 (as I did while writing a low-level
+ * data structure library some time ago) one detects that even
+ * numbers are not useable at all. The remaining 128 odd numbers
+ * (except for the number 1) work more or less all equally well.
+ * They all distribute in an acceptable way and this way fill a hash
+ * table with an average percent of approx. 86%.
+ *
+ * If one compares the chi^2 values of the variants (see
+ * Bob Jenkins ``Hashing Frequently Asked Questions'' at
+ * http://burtleburtle.net/bob/hash/hashfaq.html for a description
+ * of chi^2), the number 33 not even has the best value. But the
+ * number 33 and a few other equally good numbers like 17, 31, 63,
+ * 127 and 129 have nevertheless a great advantage to the remaining
+ * numbers in the large set of possible multipliers: their multiply
+ * operation can be replaced by a faster operation based on just one
+ * shift plus either a single addition or subtraction operation. And
+ * because a hash function has to both distribute good _and_ has to
+ * be very fast to compute, those few numbers should be preferred.
+ *
+ * -- Ralf S. Engelschall <rse@engelschall.com>
+ */
+const unsigned int times33hash(const char* data, const size_t len) {
+ apr_ssize_t l = len;
+ return apr_hashfunc_default(data, &l);
+}
+
+/**
+ * A very fast, non-cryptographic hash suitable for general hash-based
+ * lookup. See http://murmurhash.googlepages.com/ for more details.
+ *
+ * Original code by Austin Appleby, released to the public domain and under
+ * the MIT license.
+ *
+ * Compiles down to ~52 instructions on x86.
+ * Passes chi^2 tests for practically all keysets & bucket sizes.
+ * Excellent avalanche behavior. Maximum bias is under 0.5%.
+ * Passes Bob Jenkin's frog.c torture-test. No collisions possible for 4 byte
+ * keys, no small 1 to 7 bit differentials.
+ */
+const unsigned int murmurhash(const char* key, const size_t klen) {
+ unsigned int len = (unsigned int)klen;
+ const unsigned int seed = 0;
+
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char* data = (const unsigned char*)key;
+ while(len >= 4) {
+ unsigned int k = *(unsigned int*)(void*)data;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+/**
+ * An endian and alignment neutral, but half the speed, version of
+ * the murmur hash.
+ */
+const unsigned int portablemurmurhash(const char* key, const size_t klen) {
+ unsigned int len = (unsigned int)klen;
+ const unsigned int seed = 0;
+
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char* data = (const unsigned char *)key;
+ while(len >= 4) {
+ unsigned int k;
+ k = data[0];
+ k |= data[1] << 8;
+ k |= data[2] << 16;
+ k |= data[3] << 24;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+const unsigned int hashselect(const unsigned int hash, const unsigned int max) {
+ return hash % max;
+}
+
+}
+#endif /* tuscany_hash_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp
new file mode 100644
index 0000000000..4d2ca2ba81
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp
@@ -0,0 +1,614 @@
+/*
+ * 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$ */
+
+/**
+ * Test kernel functions.
+ */
+
+#include <assert.h>
+#include "string.hpp"
+#include "sstream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "dynlib.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+struct inc {
+ int i;
+ inc(int i) :
+ i(i) {
+ }
+ const int operator()(const int x) const {
+ return x + i;
+ }
+};
+
+const int square(const int x) {
+ return x * x;
+}
+
+int mapLambda(lambda<int(const int)> f, int v) {
+ return f(v);
+}
+
+bool testLambda() {
+ const lambda<int(const int)> sq(square);
+ assert(sq(2) == 4);
+ assert(mapLambda(sq, 2) == 4);
+ assert(mapLambda(square, 2) == 4);
+
+ const lambda<int(const int)> incf(inc(10));
+ assert(incf(1) == 11);
+ assert(mapLambda(incf, 1) == 11);
+ assert(mapLambda(inc(10), 1) == 11);
+
+ lambda<int(const int)> l;
+ l = incf;
+ assert(l(1) == 11);
+ l = square;
+ assert(l(2) == 4);
+ return true;
+}
+
+bool testLambdaGC() {
+ resetLambdaCounters();
+ {
+ gc_scoped_pool gc;
+ testLambda();
+ }
+ assert(checkLambdaCounters());
+ return true;
+}
+
+int countElements = 0;
+
+struct Element {
+ int i;
+
+ Element() : i(0) {
+ countElements++;
+ }
+
+ Element(int i) : i(i) {
+ countElements++;
+ }
+
+ Element(const Element& o) : i(o.i) {
+ countElements++;
+ }
+
+ ~Element() {
+ countElements--;
+ }
+
+ const bool operator==(const Element& o) const {
+ return o.i == i;
+ }
+};
+ostream& operator<<(ostream& out, const Element& v) {
+ out << v.i ;
+ return out;
+}
+
+bool testCons() {
+ assert(car(cons(2, mklist(3))) == 2);
+ assert(car(cdr(cons(2, mklist(3)))) == 3);
+ assert(isNil(cdr(cdr(cons(2, mklist(3))))));
+
+ assert(cons(Element(1), mklist(Element(2))) == mklist(Element(1), Element(2)));
+ return true;
+}
+
+bool testListGC() {
+ resetLambdaCounters();
+ resetListCounters();
+ countElements = 0;
+ {
+ gc_scoped_pool gc;
+ testCons();
+ }
+ assert(checkLambdaCounters());
+ assert(checkListCounters());
+ assert(countElements == 0);
+ return true;
+}
+
+bool testOut() {
+ ostringstream os1;
+ os1 << list<int> ();
+ assert(str(os1) == "()");
+
+ ostringstream os2;
+ os2 << mklist(1, 2, 3);
+ assert(str(os2) == "(1 2 3)");
+ return true;
+}
+
+bool testEquals() {
+ assert(list<int>() == list<int>());
+ assert(mklist(1, 2) == mklist(1, 2));
+ assert(list<int>() != mklist(1, 2));
+ assert(mklist(1, 2, 3) == mklist(1, 2, 3));
+ assert(mklist(1, 2) != mklist(1, 2, 3));
+ return true;
+}
+
+bool testLength() {
+ assert(0 == length(list<int>()));
+ assert(1 == length(mklist(1)));
+ assert(2 == length(cons(1, mklist(2))));
+ return true;
+}
+
+bool testAppend() {
+ assert(car(append(mklist(1), mklist(2))) == 1);
+ assert(car(cdr(append(mklist(1), mklist(2)))) == 2);
+ assert(car(cdr(cdr(append(mklist(1), mklist(2, 3))))) == 3);
+ assert(isNil(cdr(cdr(cdr(append(mklist(1), mklist(2, 3)))))));
+
+ assert(list<int>() + 1 + 2 + 3 == mklist(1, 2, 3));
+ return true;
+}
+
+struct Complex {
+ int x;
+ int y;
+ Complex() {
+ }
+ Complex(int x, int y) :
+ x(x), y(y) {
+ }
+};
+ostream& operator<<(ostream& out, const Complex& v) {
+ out << "[" << v.x << ":" << v.y << "]";
+ return out;
+}
+
+bool testComplex() {
+ const list<Complex> p = mklist(Complex(1, 2), Complex(3, 4));
+ assert(car(p).x == 1);
+ assert(car(cdr(p)).x == 3);
+ assert(isNil(cdr(cdr(p))));
+ return true;
+}
+
+bool testMap() {
+ assert(isNil(map<int, int>(square, list<int>())));
+
+ const list<int> m = map<int, int>(square, mklist(2, 3));
+ assert(car(m) == 4);
+ assert(car(cdr(m)) == 9);
+
+ return true;
+}
+
+const int add(const int x, const int y) {
+ return x + y;
+}
+
+bool testReduce() {
+ const lambda<int(const int, const int)> r(add);
+ assert(reduce(r, 0, mklist(1, 2, 3)) == 6);
+ return true;
+}
+
+bool isPositive(const int x) {
+ if(x >= 0)
+ return true;
+ else
+ return false;
+}
+
+bool testFilter() {
+ assert(car(filter<int>(isPositive, mklist(1, -1, 2, -2))) == 1);
+ assert(cadr(filter<int>(isPositive, mklist(1, -1, 2, -2))) == 2);
+ return true;
+}
+
+bool testMember() {
+ assert(isNil(member(4, mklist(1, 2, 3))));
+ assert(car(member(1, mklist(1, 2, 3))) == 1);
+ assert(car(member(2, mklist(1, 2, 3))) == 2);
+ assert(car(member(3, mklist(1, 2, 3))) == 3);
+ return true;
+}
+
+bool testReverse() {
+ assert(isNil(reverse(list<int>())));
+ assert(car(reverse(mklist(1, 2, 3))) == 3);
+ assert(cadr(reverse(mklist(1, 2, 3))) == 2);
+ return true;
+}
+
+bool testListRef() {
+ assert(listRef(mklist(1), 0) == 1);
+ assert(listRef(mklist(1, 2, 3), 0) == 1);
+ assert(listRef(mklist(1, 2, 3), 1) == 2);
+ assert(listRef(mklist(1, 2, 3), 2) == 3);
+ return true;
+}
+
+bool testAssoc() {
+ const list<list<string> > l = mklist(mklist<string>("x", "X"), mklist<string>("a", "A"), mklist<string>("y", "Y"), mklist<string>("a", "AA"));
+ assert(assoc<string>("a", l) == mklist<string>("a", "A"));
+ assert(isNil(assoc<string>("z", l)));
+
+ const list<list<value> > u = mklist(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"), mklist<value>("a", "AA"));
+ assert(assoc<value>("a", u) == mklist<value>("a", "A"));
+
+ const list<value> v = mklist<value>(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"), mklist<value>("a", "AA"));
+ assert(assoc<value>("a", v) == mklist<value>("a", "A"));
+ return true;
+}
+
+bool testZip() {
+ const list<string> k = mklist<string>("x", "a", "y", "a");
+ const list<string> v = mklist<string>("X", "A", "Y", "AA");
+ const list<list<string> > z = mklist(k, v);
+ const list<list<string> > u = mklist(mklist<string>("x", "X"), mklist<string>("a", "A"), mklist<string>("y", "Y"), mklist<string>("a", "AA"));
+ assert(zip(k, v) == u);
+ assert(unzip(u) == z);
+ return true;
+}
+
+bool testTokenize() {
+ assert(tokenize("/", "") == list<string>());
+ assert(tokenize("/", "aaa") == mklist<string>("aaa"));
+ assert(tokenize("/", "aaa/bbb/ccc/ddd") == mklist<string>("aaa", "bbb", "ccc", "ddd"));
+ assert(tokenize("/", "/bbb/ccc/ddd") == mklist<string>("", "bbb", "ccc", "ddd"));
+ assert(tokenize("/", "/bbb/ccc/") == mklist<string>("", "bbb", "ccc"));
+ assert(tokenize("/", "/bbb//ccc/") == mklist<string>("", "bbb", "", "ccc"));
+ assert(tokenize("/", "abc/def/") == mklist<string>("abc", "def"));
+
+ assert(join("/", list<string>()) == "");
+ assert(join("/", mklist<string>("aaa")) == "aaa");
+ assert(join("/", mklist<string>("aaa", "bbb", "ccc", "ddd")) == "aaa/bbb/ccc/ddd");
+ assert(join("/", mklist<string>("", "bbb", "ccc", "ddd")) == "/bbb/ccc/ddd");
+ assert(join("/", mklist<string>("bbb", "ccc", "")) == "bbb/ccc/");
+ assert(join("/", mklist<string>("bbb", "", "ccc")) == "bbb//ccc");
+ return true;
+}
+
+double testSeqMap(double x) {
+ return x;
+}
+
+double testSeqReduce(unused double v, double accum) {
+ return accum + 1.0;
+}
+
+bool testSeq() {
+ resetLambdaCounters();
+ resetListCounters();
+
+ list<double> s = seq(0.0, 1000.0);
+ assert(1001 == length(s));
+
+ assert(1001 == length(map<double, double>(testSeqMap, s)));
+
+ assert(801 == length(member(200.0, s)));
+ assert(201 == length(member(200.0, reverse(s))));
+
+ assert(1001 == (reduce<double, double>(testSeqReduce, 0.0, s)));
+ return true;
+}
+
+value valueSquare(list<value> x) {
+ return (int)car(x) * (int)car(x);
+}
+
+bool testValue() {
+ assert(value(true) == value(true));
+ assert(value(1) == value(1));
+ assert(value("abcd") == value("abcd"));
+ lambda<value(const list<value>&)> vl(valueSquare);
+ assert(value(vl) == value(vl));
+ assert(value(mklist<value>(1, 2)) == value(mklist<value>(1, 2)));
+
+ const list<value> v = mklist<value>(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"));
+ assert(cadr((list<list<value> >)value(v)) == mklist<value>("a", "A"));
+
+ const value pv(gc_ptr<value>(new (gc_new<value>()) value(1)));
+ assert(*(gc_ptr<value>)pv == value(1));
+
+ const list<value> lpv = mklist<value>(gc_ptr<value>(new (gc_new<value>()) value(1)), gc_ptr<value>(new (gc_new<value>()) value(2)));
+ assert(*(gc_ptr<value>)car(lpv) == value(1));
+ return true;
+}
+
+bool testValueGC() {
+ resetLambdaCounters();
+ resetListCounters();
+ resetValueCounters();
+ {
+ gc_scoped_pool gc;
+ testValue();
+ }
+ assert(checkValueCounters());
+ assert(checkLambdaCounters());
+ assert(checkListCounters());
+ return true;
+}
+
+bool testTree() {
+ const list<value> t = mktree<value>("a", list<value>(), list<value>());
+ const list<value> ct = constree<value>("d", constree<value>("f", constree<value>("c", constree<value>("e", constree<value>("b", t)))));
+ const list<value> mt = mktree(mklist<value>("d", "f", "c", "e", "b", "a"));
+ assert(mt == ct);
+ const list<value> l = flatten<value>(mt);
+ assert(length(l) == 6);
+ assert(car(l) == "a");
+ assert(car(reverse(l)) == "f");
+ const list<value> bt = mkbtree<value>(l);
+ assert(car(bt) == "c");
+ return true;
+}
+
+const list<value> lta(const string& x) {
+ return mklist<value>(c_str(x), c_str(x + x));
+}
+
+bool testTreeAssoc() {
+ const list<value> t = mktree<value>(lta("a"), list<value>(), list<value>());
+ const list<value> at = constree<value>(lta("d"), constree<value>(lta("f"), constree<value>(lta("c"), constree<value>(lta("e"), constree<value>(lta("b"), t)))));
+ const list<value> l = flatten<value>(at);
+ assert(length(l) == 6);
+ assert(car(l) == mklist<value>("a", "aa"));
+ assert(car(reverse(l)) == mklist<value>("f", "ff"));
+ const list<value> bt = mkbtree<value>(l);
+ assert(car(bt) == mklist<value>("c", "cc"));
+ assert(assoctree<value>("a", bt) == mklist<value>("a", "aa"));
+ assert(assoctree<value>("b", bt) == mklist<value>("b", "bb"));
+ assert(assoctree<value>("f", bt) == mklist<value>("f", "ff"));
+ assert(isNil(assoctree<value>("x", bt)));
+ return true;
+}
+
+double fib_aux(double n, double a, double b) {
+ if(n == 0.0)
+ return a;
+ return fib_aux(n - 1.0, b, a + b);
+}
+
+double fib(double n) {
+ return fib_aux(n, 0.0, 1.0);
+}
+
+struct fibMapPerf {
+ const bool operator()() const {
+ list<double> s = seq(0.0, 999.0);
+ list<double> r = map<double, double>(fib, s);
+ assert(1000 == length(r));
+ return true;
+ }
+};
+
+struct nestedFibMapPerf {
+ const lambda<double(const double)> fib;
+ nestedFibMapPerf(const lambda<double(const double)>& fib) : fib(fib) {
+ }
+ const bool operator()() const {
+ list<double> s = seq(0.0, 999.0);
+ list<double> r = map<double, double>(fib, s);
+ assert(1000 == length(r));
+ return true;
+ }
+};
+
+bool testCppPerf() {
+ {
+ const lambda<bool()> fml = fibMapPerf();
+ cout << "Fibonacci map test " << (time(fml, 1, 1) / 1000) << " ms" << 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);
+ }
+ };
+
+ const lambda<bool()> nfml = nestedFibMapPerf(lambda<double(const double)>(nested::fib));
+ cout << "Nested Fibonacci map test " << (time(nfml, 1, 1) / 1000) << " ms" << endl;
+ }
+ return true;
+}
+
+const id<int> idF(const int v) {
+ return v * 2;
+}
+
+const id<int> idG(const int v) {
+ return v * 3;
+}
+
+const id<int> idH(const int v) {
+ return idF(v) >> idG;
+}
+
+bool testIdMonad() {
+ const id<int> m(2);
+ assert(m >> idF == idF(2));
+ assert(m >> unit<int>() == m);
+ assert(m >> idF >> idG == m >> idH);
+ return true;
+}
+
+const maybe<int> maybeF(const int v) {
+ return v * 2;
+}
+
+const maybe<int> maybeG(const int v) {
+ return v * 3;
+}
+
+const maybe<int> maybeH(const int v) {
+ return maybeF(v) >> maybeG;
+}
+
+bool testMaybeMonad() {
+ const maybe<int> m(2);
+ assert(m >> maybeF == maybeF(2));
+ assert((m >> just<int>()) == m);
+ assert(m >> maybeF >> maybeG == m >> maybeH);
+
+ assert(maybe<int>() >> maybeF >> maybeG == maybe<int>());
+ return true;
+}
+
+const failable<int> failableF(const int v) {
+ return v * 2;
+}
+
+const failable<int> failableG(const int v) {
+ return v * 3;
+}
+
+const failable<int> failableH(const int v) {
+ return failableF(v) >> failableG;
+}
+
+bool testFailableMonad() {
+ const failable<int> m(2);
+ assert(m >> failableF == failableF(2));
+ assert((m >> success<int, string, int>()) == m);
+ assert(m >> failableF >> failableG == m >> failableH);
+
+ cout << "Failable monad test... " << endl;
+ const failable<int> ooops = mkfailure<int>("test", 500);
+ assert(reason(ooops) == "test");
+ assert(rcode(ooops) == 500);
+ assert(ooops >> failableF >> failableG == ooops);
+
+ const failable<value> vooops = mkfailure<value>(ooops);
+ assert(reason(vooops) == "test");
+ assert(rcode(vooops) == 500);
+
+ const value v = value(vooops);
+ assert(car<value>(v) == value());
+ assert(cadr<value>(v) == string("test"));
+ assert(caddr<value>(v) == value((double)500));
+ return true;
+}
+
+struct tickInc {
+ const double v;
+ tickInc(const double v) : v(v) {
+ }
+ const scp<int, double> operator()(int s) const {
+ return scp<int, double>(s + 1, v);
+ }
+};
+
+const state<int, double> tick(const double v) {
+ return transformer<int, double>(tickInc(v));
+}
+
+const state<int, double> stateF(const double v) {
+ return result<int, double>(v * 2.0) >> tick;
+}
+
+const state<int, double> stateG(const double v) {
+ return result<int, double>(v + 5);
+}
+
+const state<int, double> stateH(const double v) {
+ return stateF(v) >> stateG;
+}
+
+bool testStateMonad() {
+ const lambda<state<int, double>(const double)> r(result<int, double>);
+
+ state<int, double> m = result<int, double>(2.0);
+ assert((m >> stateF)(0) == stateF(2.0)(0));
+ assert(1 == (int)(m >> stateF)(0));
+ assert((m >> r)(0) == m(0));
+ assert((m >> stateF >> stateG)(0) == (m >> stateH)(0));
+
+ return true;
+}
+
+bool testDynLib() {
+ const lib dl(string("./libdynlib-test") + dynlibExt);
+ const failable<lambda<int(const int)> > sq(dynlambda<int(const int)>("csquare", dl));
+ assert(hasContent(sq));
+ lambda<int(const int)> l(content(sq));
+ assert(l(2) == 4);
+
+ const failable<lambda<lambda<int(const int)>()> > sql(dynlambda<lambda<int(const int)>()>("csquarel", dl));
+ assert(hasContent(sql));
+ lambda<lambda<int(const int)>()> ll(content(sql));
+ assert(ll()(3) == 9);
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testLambda();
+ tuscany::testLambdaGC();
+ tuscany::testCons();
+ tuscany::testListGC();
+ tuscany::testOut();
+ tuscany::testEquals();
+ tuscany::testLength();
+ tuscany::testAppend();
+ tuscany::testComplex();
+ tuscany::testMap();
+ tuscany::testReduce();
+ tuscany::testFilter();
+ tuscany::testMember();
+ tuscany::testReverse();
+ tuscany::testListRef();
+ tuscany::testAssoc();
+ tuscany::testZip();
+ tuscany::testTokenize();
+ tuscany::testSeq();
+ tuscany::testValue();
+ tuscany::testValueGC();
+ tuscany::testTree();
+ tuscany::testTreeAssoc();
+ tuscany::testCppPerf();
+ tuscany::testIdMonad();
+ tuscany::testMaybeMonad();
+ tuscany::testFailableMonad();
+ tuscany::testStateMonad();
+ tuscany::testDynLib();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/lambda-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/lambda-test.cpp
new file mode 100644
index 0000000000..05a16c2eb8
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/lambda-test.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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$ */
+
+/**
+ * Test C++0x lambda expressions.
+ */
+
+#include <assert.h>
+#include "function.hpp"
+#include "sstream.hpp"
+#include "fstream.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+#ifdef HAS_CXX0X_LAMBDAS
+
+const lambda<const int(const int)> inc(const int i) {
+ return [=](const int x)->const int {
+ return x + i;
+ };
+}
+
+const int square(const int x) {
+ return x * x;
+}
+
+int mapLambda(const lambda<const int(const int)> f, int v) {
+ return f(v);
+}
+
+bool testLambda() {
+ const lambda<const int(const int)> sq = square;
+ assert(sq(2) == 4);
+ assert(mapLambda(square, 2) == 4);
+ assert(mapLambda(sq, 2) == 4);
+ assert(mapLambda([](const int x)->const int { return x * x; }, 2) == 4);
+
+ const lambda<int(int)> incf = inc(10);
+ assert(incf(1) == 11);
+ assert(mapLambda(incf, 1) == 11);
+ assert(mapLambda(inc(10), 1) == 11);
+
+ lambda<const int(const int)> l;
+ l = incf;
+ assert(l(1) == 11);
+ l = square;
+ assert(l(2) == 4);
+ return true;
+}
+
+const double fib_aux(const double n, const double a, const double b) {
+ return n == 0.0? a : fib_aux(n - 1.0, b, a + b);
+}
+
+const bool fibMapPerf() {
+ list<double> s = seq(0.0, 4999.0);
+ list<double> r = map<double, double>([](const double n)->const double { return fib_aux(n, 0.0, 1.0); }, s);
+ assert(5000 == length(r));
+ return true;
+}
+
+bool testCppPerf() {
+ cout << "Fibonacci map test " << (time([]()->const bool { return fibMapPerf(); }, 1, 1) / 5000) << " ms" << endl;
+ return true;
+}
+
+#endif
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+#ifdef HAS_CXX0X_LAMBDAS
+ tuscany::testLambda();
+ tuscany::testCppPerf();
+#else
+ tuscany::cout << "Skipped C++0x lambda tests" << tuscany::endl;
+#endif
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/list.hpp b/sca-cpp/branches/lightweight-sca/kernel/list.hpp
new file mode 100644
index 0000000000..d3736de62c
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/list.hpp
@@ -0,0 +1,617 @@
+/*
+ * 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_list_hpp
+#define tuscany_list_hpp
+
+/**
+ * Simple list functions.
+ */
+
+#include <assert.h>
+#include "string.hpp"
+#include "fstream.hpp"
+#include "function.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_MAINTAINER_COUNTERS
+
+/**
+ * Debug utilities. Counters used to track instances of lists.
+ */
+long countLists = 0;
+long countILists = 0;
+long countCLists = 0;
+long countELists = 0;
+
+bool resetListCounters() {
+ countLists = countILists = countCLists = countELists = 0;
+ return true;
+}
+
+bool checkListCounters() {
+ return countLists == 0;
+}
+
+bool printListCounters() {
+ cout << "countLists " << countLists << endl;
+ cout << "countELists " << countELists << endl;
+ cout << "countILists " << countILists << endl;
+ cout << "countCLists " << countCLists << endl;
+ return true;
+}
+
+#else
+
+#define resetListCounters()
+#define checkListCounters() true
+#define printListCounters()
+
+#endif
+
+#ifdef WANT_MAINTAINER_WATCH
+
+/**
+ * Debug utilities. Macro used to write the contents of a list to
+ * a string, easier to watch in a debugger than the list itself.
+ */
+#define debug_watchList() do { \
+ this->watch = watchList(*this); \
+ } while (0)
+
+#else
+
+#define debug_watchList();
+
+#endif
+
+/**
+ * A car/cdr lisp-like pair, base structure to construct lists.
+ */
+
+template<typename T> class list {
+public:
+
+ list() {
+ debug_inc(countLists);
+ debug_inc(countELists);
+ debug_watchList();
+ }
+
+ list(const T car, const lambda<list<T>()>& cdr) : car(car), cdr(cdr) {
+ debug_inc(countLists);
+ debug_inc(countILists);
+ debug_watchList();
+ }
+
+ list(const list& p) : car(p.car), cdr(p.cdr) {
+ debug_inc(countLists);
+ debug_inc(countCLists);
+#ifdef WANT_MAINTAINER_WATCH
+ watch = p.watch;
+#endif
+ }
+
+ const list<T>& operator=(const list<T>& p) {
+ if(this == &p)
+ return *this;
+ car = p.car;
+ cdr = p.cdr;
+#ifdef WANT_MAINTAINER_WATCH
+ watch = p.watch;
+#endif
+ return *this;
+ }
+
+ ~list() {
+ debug_dec(countLists);
+ }
+
+ const bool operator==(const list<T>& p) const {
+ if(this == &p)
+ return true;
+ if(isNil(cdr))
+ return isNil(p.cdr);
+ if(isNil(p.cdr))
+ return false;
+ if(!(car == p.car))
+ return false;
+ if(cdr == p.cdr)
+ return true;
+ return cdr() == p.cdr();
+ }
+
+ const bool operator<(const list<T>& p) const {
+ if(this == &p)
+ return false;
+ if (isNil(cdr))
+ return !isNil(p.cdr);
+ if (isNil(p.cdr))
+ return false;
+ if (car < p.car)
+ return true;
+ if (car != p.car)
+ return false;
+ return cdr() < p.cdr();
+ }
+
+ const bool operator>(const list<T>& p) const {
+ if(this == &p)
+ return false;
+ if (isNil(cdr))
+ return false;
+ if (isNil(p.cdr))
+ return true;
+ if (car > p.car)
+ return true;
+ if (car != p.car)
+ return false;
+ return cdr() > p.cdr();
+ }
+
+ const bool operator!=(const list<T>& p) const {
+ return !this->operator==(p);
+ }
+
+ operator const list<list<T> >() const {
+ return (list<list<T> >)T(*this);
+ }
+
+private:
+#ifdef WANT_MAINTAINER_WATCH
+ template<typename X> friend const string watchList(const list<X>& p);
+ string watch;
+#endif
+
+ template<typename X> friend const bool isNil(const list<X>& p);
+ template<typename X> friend const X car(const list<X>& p);
+ template<typename X> friend const list<X> cdr(const list<X>& p);
+
+ T car;
+ lambda<list<T>()> cdr;
+};
+
+#ifdef WANT_MAINTAINER_WATCH
+
+/**
+ * Debug utility used to write the contents of a list to a string, easier
+ * to watch than the list itself in a debugger.
+ */
+template<typename T> const string watchList(const list<T>& p) {
+ if(isNil(p))
+ return "()";
+ odebugstream os;
+ os << "(" << car(p) << " ...)";
+ return str(os);
+}
+
+#endif
+
+/**
+ * Returns true if the given list is nil.
+ */
+template<typename T> const bool isNil(const list<T>& p) {
+ return isNil(p.cdr);
+}
+
+/**
+ * Write a list to an output stream.
+ */
+template<typename T> ostream& writeHelper(ostream& out, const list<T>& l) {
+ if (isNil(l))
+ return out;
+ out << " " << car(l);
+ return writeHelper(out, cdr(l));
+}
+
+template<typename T> ostream& operator<<(ostream& out, const list<T>& l) {
+ if(isNil(l))
+ return out << "()";
+ out << "(" << car(l);
+ writeHelper<T>(out, cdr(l));
+ return out << ")";
+}
+
+/**
+ * Construct a (lazy) list from a value and a lambda function that returns the cdr.
+ */
+template<typename T> const list<T> cons(const T& car, const lambda<list<T>()>& cdr) {
+ return list<T> (car, cdr);
+}
+
+/**
+ * Construct a list from a value and a cdr list.
+ */
+template<typename T> const list<T> cons(const T& car, const list<T>& cdr) {
+ return list<T> (car, result(cdr));
+}
+
+/**
+ * Cons variations for use with the reduce and reduceRight functions.
+ */
+template<typename T> const list<T> lcons(const list<T>& cdr, const T& car) {
+ return cons<T>(car, cdr);
+}
+
+template<typename T> const list<T> rcons(const T& car, const list<T>& cdr) {
+ return cons<T>(car, cdr);
+}
+
+/**
+ * Construct a list of one value.
+ */
+template<typename T> const list<T> mklist(const T& car) {
+ return list<T> (car, result(list<T> ()));
+}
+
+/**
+ * Construct a list of two values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b) {
+ return cons(a, mklist(b));
+}
+
+/**
+ * Construct a list of three values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c) {
+ return cons(a, cons(b, mklist(c)));
+}
+
+/**
+ * Construct a list of four values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d) {
+ return cons(a, cons(b, cons(c, mklist(d))));
+}
+
+/**
+ * Construct a list of five values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e) {
+ return cons(a, cons(b, cons(c, cons(d, mklist(e)))));
+}
+
+/**
+ * Construct a list of six values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f) {
+ return cons(a, cons(b, cons(c, cons(d, cons(e, mklist(f))))));
+}
+
+/**
+ * Returns the car of a list.
+ */
+template<typename T> const T car(const list<T>& p) {
+ // Abort if trying to access the car of a nil list
+ assertOrFail(!isNil(p.cdr));
+ return p.car;
+}
+
+/**
+ * Returns the cdr of a list.
+ */
+template<typename T> const list<T> cdr(const list<T>& p) {
+ return p.cdr();
+}
+
+/**
+ * Returns the car of the cdr (the 2nd element) of a list.
+ */
+template<typename T> const T cadr(const list<T>& p) {
+ return car(cdr(p));
+}
+
+/**
+ * Returns the 3rd element of a list.
+ */
+template<typename T> const T caddr(const list<T>& p) {
+ return car(cdr(cdr(p)));
+}
+
+/**
+ * Returns the 4th element of a list.
+ */
+template<typename T> const T cadddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(p))));
+}
+
+/**
+ * Returns the 5th element of a list.
+ */
+template<typename T> const T caddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(p)))));
+}
+
+/**
+ * Returns the 6th element of a list.
+ */
+template<typename T> const T cadddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(cdr(p))))));
+}
+
+/**
+ * Returns the 7th element of a list.
+ */
+template<typename T> const T caddddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(cdr(cdr(p)))))));
+}
+
+/**
+ * Returns the 8th element of a list.
+ */
+template<typename T> const T cadddddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(p))))))));
+}
+
+/**
+ * Returns a list of elements from the 3rd to the end of a list.
+ */
+template<typename T> const list<T> cddr(const list<T>& p) {
+ return cdr(cdr(p));
+}
+
+/**
+ * Returns a list of elements from the 4th to the end of a list.
+ */
+template<typename T> const list<T> cdddr(const list<T>& p) {
+ return cdr(cdr(cdr(p)));
+}
+
+/**
+ * Returns a list of elements from the 5th to the end of a list.
+ */
+template<typename T> const list<T> cddddr(const list<T>& p) {
+ return cdr(cdr(cdr(cdr(p))));
+}
+
+/**
+ * Returns a list of elements from the 6th to the end of a list.
+ */
+template<typename T> const list<T> cdddddr(const list<T>& p) {
+ return cdr(cdr(cdr(cdr(cdr(p)))));
+}
+
+/**
+ * Returns a list of elements from the 7th to the end of a list.
+ */
+template<typename T> const list<T> cddddddr(const list<T>& p) {
+ return cdr(cdr(cdr(cdr(cdr(cdr(p))))));
+}
+
+/**
+ * Returns a list of elements from the 8th to the end of a list.
+ */
+template<typename T> const list<T> cdddddddr(const list<T>& p) {
+ return cdr(cdr(cdr(cdr(cdr(cdr(cdr(p)))))));
+}
+
+/**
+ * Returns the length of a list.
+ */
+template<typename T> struct lengthRef {
+ const size_t operator()(const size_t c, const list<T>& p) {
+ if(isNil(p))
+ return c;
+ return (*this)(c + 1, cdr(p));
+ }
+};
+
+template<typename T> const size_t length(const list<T>& p) {
+ return lengthRef<T> ()(0, p);
+}
+
+/**
+ * Appends a list and a lambda function returning a list.
+ */
+template<typename T> struct appendCdr {
+ const list<T> a;
+ const lambda<list<T>()> fb;
+ appendCdr(const list<T>& a, const lambda<list<T>()>& fb) :
+ a(a), fb(fb) {
+ }
+ const list<T> operator()() const {
+ return append(a, fb);
+ }
+};
+
+template<typename T> const list<T> append(const list<T>&a, const lambda<list<T>()>& fb) {
+ if(isNil(a))
+ return fb();
+
+ return cons<T>(car(a), appendCdr<T> (cdr(a), fb));
+}
+
+/**
+ * Appends two lists.
+ */
+template<typename T> const list<T> append(const list<T>&a, const list<T>& b) {
+ return append(a, result(b));
+}
+
+/**
+ * Append a value to a list.
+ */
+template<typename T> const list<T> operator+(const list<T>& l, const T& v) {
+ return append(l, mklist(v));
+}
+
+template<typename T, typename V> const list<T> operator+(const list<T>& l, const V& v) {
+ return append(l, mklist<T>(v));
+}
+
+/**
+ * Map a lambda function on a list.
+ */
+template<typename T, typename R> const list<R> map(const lambda<R(const T)>& f, const list<T>& p) {
+ if(isNil(p))
+ return list<R> ();
+ return cons(f(car(p)), map(f, cdr(p)));
+}
+
+/**
+ * Run a reduce lambda function on a list.
+ */
+template<typename T, typename R> struct reduceAccumulate {
+ const lambda<R(const R&, const T&)> f;
+ reduceAccumulate(const lambda<R(const R, const T)>& f) :
+ f(f) {
+ }
+ R operator()(const R& acc, const list<T>& p) const {
+ if(isNil(p))
+ return acc;
+ return (*this)(f(acc, car(p)), cdr(p));
+ }
+};
+
+template<typename T, typename R> const R reduce(const lambda<R(const R, const T)>& f, const R& initial, const list<T>& p) {
+ return reduceAccumulate<T, R> (f)(initial, p);
+}
+
+template<typename T, typename R> struct reduceRightAccumulate {
+ const lambda<R(const T&, const R&)> f;
+ reduceRightAccumulate(const lambda<R(const T, const R)>& f) :
+ f(f) {
+ }
+ R operator()(const list<T>& p, const R& acc) const {
+ if(isNil(p))
+ return acc;
+ return (*this)(cdr(p), f(car(p), acc));
+ }
+};
+
+template<typename T, typename R> const R reduceRight(const lambda<R(const T, const R)>& f, const R& initial, const list<T>& p) {
+ return reduceRightAccumulate<T, R> (f)(p, initial);
+}
+
+/**
+ * Run a filter lambda function on a list.
+ */
+template<typename T> const list<T> filter(const lambda<bool(const T)>& f, const list<T>& p) {
+ if(isNil(p))
+ return list<T> ();
+ if(f(car(p))) {
+ const lambda<list<T>(const lambda<bool(const T)>, const list<T>)> ff(filter<T>);
+ return cons(car(p), curry(ff, f, cdr(p)));
+ }
+ return filter(f, cdr(p));
+}
+
+/**
+ * Returns a list pointing to a member of a list.
+ */
+template<typename T> const list<T> member(const T& t, const list<T>& p) {
+ if(isNil(p))
+ return list<T> ();
+ if(t == car(p))
+ return p;
+ return member(t, cdr(p));
+}
+
+/**
+ * Reverse a list.
+ */
+template<typename T> const list<T> reverseIter(const list<T>& acc, const list<T>& p) {
+ if(isNil(p))
+ return acc;
+ return reverseIter(cons(car(p), acc), cdr(p));
+}
+
+template<typename T> const list<T> reverse(const list<T>& p) {
+ return reverseIter(list<T> (), p);
+}
+
+template<typename T> const list<T> seq(const T& start, const T& end);
+
+template<typename T> struct seqGenerate {
+ const T start;
+ const T end;
+ seqGenerate(const T& start, const T&end) :
+ start(start), end(end) {
+ }
+ const list<T> operator()() const {
+ return seq<T> (start, end);
+ }
+};
+
+/**
+ * Returns a sequence of values between the given bounds.
+ */
+template<typename T> const list<T> seq(const T& start, const T& end) {
+ if(start == end)
+ return mklist(start);
+ if(start < end)
+ return cons<T>(start, seqGenerate<T> (start + 1, end));
+ return cons<T>(start, seqGenerate<T> (start - 1, end));
+}
+
+/**
+ * Returns the i-th element of a list.
+ */
+template<typename T> const T listRef(const list<T>& l, const size_t i) {
+ if (i == 0)
+ return car(l);
+ return listRef(cdr(l), i - 1);
+}
+
+/**
+ * Returns the first pair matching a key from a list of key value pairs.
+ */
+template<typename T> const list<T> assoc(const T& k, const list<list<T> >& p) {
+ if(isNil(p))
+ return list<T> ();
+ if(k == car(car(p)))
+ return car(p);
+ return assoc(k, cdr(p));
+}
+
+/**
+ * Returns a list of lists containing elements from two input lists.
+ */
+template<typename T> const list<list<T> > zip(const list<T>& a, const list<T>& b) {
+ if (isNil(a) || isNil(b))
+ return list<list<T> >();
+ return cons<list<T> >(mklist<T>(car(a), car(b)), zip(cdr(a), cdr(b)));
+}
+
+/**
+ * Converts a list of key value pairs to a list containing the list of keys and the list of values.
+ */
+template<typename T> const list<T> unzipKeys(const list<list<T> >& l) {
+ if (isNil(l))
+ return list<T>();
+ return cons(car(car(l)), unzipKeys(cdr(l)));
+}
+
+template<typename T> const list<T> unzipValues(const list<list<T> >& l) {
+ if (isNil(l))
+ return list<T>();
+ return cons(cadr(car(l)), unzipValues(cdr(l)));
+}
+
+template<typename T> const list<list<T> > unzip(const list<list<T> >& l) {
+ return mklist<list<T> >(unzipKeys(l), unzipValues(l));
+}
+
+}
+
+#endif /* tuscany_list_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp
new file mode 100644
index 0000000000..668dabe749
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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$ */
+
+/**
+ * Test memory allocation functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "gc.hpp"
+#include "function.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+int countElements = 0;
+int maxElements = 0;
+
+class Element {
+public:
+ Element() : i(0) {
+ countElements++;
+ if (countElements > maxElements)
+ maxElements = countElements;
+ }
+
+ Element(int i) : i(i) {
+ countElements++;
+ if (countElements > maxElements)
+ maxElements = countElements;
+ }
+
+ Element(const Element& o) : i(o.i) {
+ countElements++;
+ if (countElements > maxElements)
+ maxElements = countElements;
+ }
+
+ ~Element() {
+ countElements--;
+ }
+
+ const bool operator==(const Element& o) const {
+ return o.i == i;
+ }
+
+private:
+ friend ostream& operator<<(ostream& out, const Element& v);
+
+ int i;
+ char c[20];
+};
+
+ostream& operator<<(ostream& out, const Element& v) {
+ out << v.i ;
+ return out;
+}
+
+bool poolAlloc(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ p[count - 1] = new (gc_new<Element>()) Element();
+ return poolAlloc(p, count - 1);
+};
+
+bool poolFree(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ // Do nothing to free the element, but cycle through them just
+ // to get a fair comparison with the other memory alloc tests
+ return poolFree(p, count - 1);
+};
+
+struct poolAllocPerf {
+ const int n;
+ Element** p;
+ poolAllocPerf(const int n) : n(n), p(new Element*[n]) {
+ }
+ const bool operator()() const {
+ gc_scoped_pool gc;
+ poolAlloc(p, n);
+ return true;
+ }
+};
+
+bool testPoolAllocPerf() {
+ const int count = 10000;
+ const lambda<bool()> pl = poolAllocPerf(count);
+ maxElements = 0;
+ cout << "Memory pool alloc test " << (time(pl, 1, 1) / count) << " ms" << endl;
+ assert(countElements == 0);
+ assert(maxElements == count);
+ return true;
+}
+
+bool stdAlloc(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ p[count - 1] = new Element();
+ return stdAlloc(p, count - 1);
+};
+
+bool stdFree(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ delete p[count -1];
+ return stdFree(p, count - 1);
+};
+
+struct stdAllocPerf {
+ const int n;
+ Element** p;
+ stdAllocPerf(const int n) : n(n), p(new Element*[n]) {
+ }
+ const bool operator()() const {
+ stdAlloc(p, n);
+ stdFree(p, n);
+ return true;
+ }
+};
+
+bool testStdAllocPerf() {
+ const int count = 10000;
+ const lambda<bool()> sl = stdAllocPerf(count);
+ maxElements = 0;
+ cout << "Memory standard alloc test " << (time(sl, 1, 1) / count) << " ms" << endl;
+ assert(countElements == 0);
+ assert(maxElements == count);
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testPoolAllocPerf();
+ tuscany::testStdAllocPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/monad.hpp b/sca-cpp/branches/lightweight-sca/kernel/monad.hpp
new file mode 100644
index 0000000000..b67e92ad79
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/monad.hpp
@@ -0,0 +1,627 @@
+/*
+ * 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_monad_hpp
+#define tuscany_monad_hpp
+
+/**
+ * Simple monad implementations.
+ */
+
+#include <execinfo.h>
+#include <cxxabi.h>
+#include "function.hpp"
+#include "string.hpp"
+#include "stream.hpp"
+#include "sstream.hpp"
+#include "fstream.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Identity monad. Just wraps a value.
+ * To get the value in the monad, just cast it to the value type.
+ */
+template<typename V> class id {
+public:
+ id(const V& v) : v(v) {
+ }
+
+ const id<V>& operator=(const id<V>& m) {
+ if(this == &m)
+ return *this;
+ v = m.v;
+ return *this;
+ }
+
+ const bool operator!=(const id<V>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const id<V>& m) const {
+ if (&m == this)
+ return true;
+ return v == m.v;
+ }
+
+private:
+ const V v;
+
+ template<typename X> friend const X content(const id<X>& m);
+};
+
+/**
+ * Write an identity monad to a stream.
+ */
+template<typename V> ostream& operator<<(ostream& out, const id<V>& m) {
+ out << content(m);
+ return out;
+}
+
+/**
+ * Returns the content of an identity monad.
+ */
+template<typename V> const V content(const id<V>& m) {
+ return m.v;
+}
+
+/**
+ * Return an identity monad from a value.
+ */
+template<typename V> const id<V> mkunit(const V& v) {
+ return id<V>(v);
+}
+
+template<typename V> const lambda<id<V>(const V)> unit() {
+ return mkunit<V>;
+}
+
+/**
+ * Bind a function to an identity monad. Pass the value in the monad to the function.
+ */
+template<typename R, typename V> const id<R> operator>>(const id<V>& m, const lambda<id<R>(const V)>& f) {
+ return f(content(m));
+}
+
+template<typename R, typename V> const id<R> operator>>(const id<V>& m, const id<R> (* const f)(const V)) {
+ return f(content(m));
+}
+
+/**
+ * Maybe monad. Used to represent an optional value, which may be there or not.
+ * To get the value in the monad, just cast it to the value type.
+ */
+template<typename V> class maybe {
+public:
+ maybe(const V& v) : hasv(true), v(v) {
+ }
+
+ maybe() : hasv(false) {
+ }
+
+ const maybe<V>& operator=(const maybe<V>& m) {
+ if(this == &m)
+ return *this;
+ hasv = m.hasv;
+ if (hasv)
+ v = m.v;
+ return *this;
+ }
+
+ const bool operator!=(const maybe<V>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const maybe<V>& m) const {
+ if (this == &m)
+ return true;
+ if (!hasv)
+ return !m.hasv;
+ return m.hasv && v == m.v;
+ }
+
+private:
+ const bool hasv;
+ V v;
+
+ template<typename X> friend const bool hasContent(const maybe<X>& m);
+ template<typename X> friend const X content(const maybe<X>& m);
+};
+
+/**
+ * Write a maybe monad to a stream.
+ */
+template<typename V> ostream& operator<<(ostream& out, const maybe<V>& m) {
+ if (!hasContent(m)) {
+ out << "nothing";
+ return out;
+ }
+ out << content(m);
+ return out;
+}
+
+/**
+ * Return a maybe monad with a value in it.
+ */
+template<typename V> const maybe<V> mkjust(const V& v) {
+ return maybe<V>(v);
+}
+
+template<typename V> const lambda<maybe<V>(const V)> just() {
+ return mkjust<V>;
+}
+
+/**
+ * Returns true if a maybe monad contains a content.
+ */
+template<typename V> const bool hasContent(const maybe<V>& m) {
+ return m.hasv;
+}
+
+/**
+ * Returns the content of a maybe monad.
+ */
+template<typename V> const V content(const maybe<V>& m) {
+ return m.v;
+}
+
+/**
+ * Bind a function to a maybe monad. Passes the value in the monad to the function
+ * if present, or does nothing if there's no value.
+ */
+template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const lambda<maybe<R>(const V)>& f) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const maybe<R> (* const f)(const V)) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+/**
+ * Failable monad. Used to represent either a success value or a failure.
+ * To get the value in the monad, just cast it to the value type.
+ * To get the failure in the monad, cast it to the failure type.
+ */
+template<typename V, typename F = string, typename C = int> class failable {
+public:
+ failable() : hasv(false), c(-1) {
+ }
+
+ failable(const V& v) : hasv(true), v(v), c(-1) {
+ }
+
+ failable(const failable<V, F, C>& m) : hasv(m.hasv), v(m.v), f(m.f), c(m.c) {
+ }
+
+ const failable<V, F, C>& operator=(const failable<V, F, C>& m) {
+ if (&m == this)
+ return *this;
+ hasv = m.hasv;
+ v = m.v;
+ f = m.f;
+ c = m.c;
+ return *this;
+ }
+
+ const bool operator!=(const failable<V, F, C>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const failable<V, F, C>& m) const {
+ if (this == &m)
+ return true;
+ if (!hasv)
+ return !m.hasv && f == m.f && c == m.c;
+ return m.hasv && v == m.v;
+ }
+
+private:
+ failable(const bool hasv, const F& f, const C& c) : hasv(hasv), f(f), c(c) {
+ }
+
+ template<typename A, typename B, typename R> friend const bool hasContent(const failable<A, B, R>& m);
+ template<typename A, typename B, typename R> friend const A content(const failable<A, B, R>& m);
+ template<typename A, typename B, typename R> friend const B reason(const failable<A, B, R>& m);
+ template<typename A, typename B, typename R> friend const R rcode(const failable<A, B, R>& m);
+ template<typename A, typename B, typename R> friend const failable<A, B, R> mkfailure(const B& f, const R& c, const bool log);
+ template<typename A, typename B> friend const failable<A, B> mkfailure(const B& f, const int c, const bool log);
+ template<typename A> friend const failable<A> mkfailure();
+
+ bool hasv;
+ V v;
+ F f;
+ C c;
+};
+
+/**
+ * Write a failable monad to a stream.
+ */
+template<typename V, typename F, typename C> ostream& operator<<(ostream& out, const failable<V, F, C>& m) {
+ if (!hasContent(m)) {
+ out << reason(m) << " : " << rcode(m);
+ return out;
+ }
+ out << content(m);
+ return out;
+}
+
+/**
+ * Returns a failable monad with a success value in it.
+ */
+template<typename V, typename F, typename C> const failable<V, F, C> mksuccess(const V& v) {
+ return failable<V, F, C>(v);
+}
+
+template<typename V, typename F, typename C> const lambda<failable<V, F, C>(const V)> success() {
+ return mksuccess<V, F, C>;
+}
+
+/**
+ * Demangle a C++ function name.
+ */
+const string demangleFrame(const char* fun) {
+ int status;
+ char* name = abi::__cxa_demangle(fun, 0, 0, &status);
+ if (name == NULL)
+ return fun;
+ const string s = name;
+ free(name);
+ return s;
+}
+
+/**
+ * Format a backtrace frame.
+ */
+const char* formatFrameFile(const char* file) {
+ const char* s = strrchr(file, '/');
+ return s == NULL? file : s + 1;
+}
+
+const string formatFrame(const char* symbol) {
+#ifdef __clang__
+ // Mac OS X CLang/LLVM stack frame format
+ // 0 kernel-test 0x000000010d440179 _ZN7tuscany9mkfailureINS_5valueENS_6stringEiEEKNS_8failableIT_T0_T1_EERKS5_RKS6_b + 265
+ char nb[3];
+ char file[256];
+ char addr[32];
+ char fun[256];
+ char offset[16];
+ if (sscanf(symbol, "%2s %255s %31s %255s %*[+] %15s", nb, file, addr, fun, offset) == 5) {
+ char buf[1024];
+ if (debug_islogging())
+ sprintf(buf, "%.255s %.31s %.511s + %.15s", formatFrameFile(file), addr, c_str(demangleFrame(fun)), offset);
+ else
+ sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr);
+ return buf;
+ }
+#else
+ // Linux GCC stack frame format
+ // ./kernel-test(_ZN7tuscany9mkfailureINS_5valueENS_6stringEiEEKNS_8failableIT_T0_T1_EERKS5_RKS6_b+0x23d) [0xb7197afd]
+ char file[256];
+ char fun[256];
+ char offset[16];
+ char addr[32];
+ if (sscanf(symbol, "%[^(]%*[(]%[^+]%*[+]%[^)]%*[)] %*[[]%[^]]%*[]]", file, fun, offset, addr) == 4) {
+ char buf[1024];
+ if (debug_islogging())
+ sprintf(buf, "%.255s %.31s %.511s + %.15s", formatFrameFile(file), addr, c_str(demangleFrame(fun)), offset);
+ else
+ sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr);
+ return buf;
+ }
+ if (sscanf(symbol, "%[^(]%*[(]%*[^)]%*[)] %*[[]%[^]]%*[]]", file, addr) == 2) {
+ char buf[512];
+ sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr);
+ return buf;
+ }
+ if (sscanf(symbol, "%[^(]%*[(]%*[)] %*[[]%[^]]%*[]]", file, addr) == 2) {
+ char buf[512];
+ sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr);
+ return buf;
+ }
+#endif
+ return symbol;
+}
+
+/**
+ * Log backtrace frames.
+ */
+const bool logFrames(char** symbols, const int frames, const bool log) {
+ if (frames == 0)
+ return true;
+#ifdef WANT_MAINTAINER_LOG
+ if (!log)
+ debug(formatFrame(*symbols), "failable::backtrace");
+#endif
+ if (log)
+ cfailure << "failable::backtrace: " << formatFrame(*symbols) << endl;
+ return logFrames(symbols + 1, frames - 1, log);
+}
+
+/**
+ * Log a backtrace.
+ */
+const bool logBacktrace(void** callstack, const int frames, const bool log) {
+ char** symbols = backtrace_symbols(callstack, frames);
+ logFrames(symbols, frames, log);
+ free(symbols);
+ return true;
+}
+
+/**
+ * Returns a failable monad with a failure in it.
+ */
+template<typename V, typename F, typename C> const failable<V, F, C> mkfailure(const F& f, const C& c, const bool log = true) {
+#ifdef WANT_MAINTAINER_LOG
+ if (!log) {
+ // Log the failure
+ debug(f, "failable::mkfailure");
+
+ // Log the call stack
+ void* callstack[16];
+ const int frames = backtrace(callstack, 16);
+ logBacktrace(callstack, frames, log);
+ }
+#endif
+ if (log) {
+ ostringstream os;
+ os << f;
+ if (length(str(os)) != 0) {
+ // Log the failure
+ cfailure << "failable::mkfailure: " << f << " : " << c << endl;
+
+ // Print the call stack
+ void* callstack[16];
+ const int frames = backtrace(callstack, 16);
+ logBacktrace(callstack, frames, log);
+ }
+ }
+ return failable<V, F, C>(false, f, c);
+}
+
+template<typename V, typename F> const failable<V, F> mkfailure(const F& f, const int c = -1, const bool log = true) {
+ return mkfailure<V, F, int>(f, c, log);
+}
+
+template<typename V> const failable<V> mkfailure(const char* f, const int c = -1, const bool log = true) {
+ return mkfailure<V, string, int>(string(f), c, log);
+}
+
+template<typename V> const failable<V> mkfailure() {
+ return failable<V, string>(false, string(), -1);
+}
+
+template<typename V, typename F, typename C> const lambda<failable<V, F, C>(const V)> failure() {
+ return mkfailure<V, F, C>;
+}
+
+/**
+ * Convert a failable of a given type to a failable of another type.
+ */
+template<typename V, typename F, typename C, typename X> const failable<V, F, C> mkfailure(const failable<X, F, C>& f, const bool log = true) {
+ return mkfailure<V, F, C>(reason(f), rcode(f), log);
+}
+
+/**
+ * Returns true if the monad contains a content.
+ */
+template<typename V, typename F, typename C> const bool hasContent(const failable<V, F, C>& m) {
+ return m.hasv;
+}
+
+/**
+ * Returns the content of a failable monad.
+ */
+template<typename V, typename F, typename C> const V content(const failable<V, F, C>& m) {
+ return m.v;
+}
+
+/**
+ * Returns the reason for failure of a failable monad.
+ */
+template<typename V, typename F, typename C> const F reason(const failable<V, F, C>& m) {
+ return m.f;
+}
+
+/**
+ * Returns the reason code for failure of a failable monad.
+ */
+template<typename V, typename F, typename C> const C rcode(const failable<V, F, C>& m) {
+ return m.c;
+}
+
+/**
+ * Bind a function to a failable monad. Passes the success value in the monad to the function
+ * if present, or does nothing if there's no value and a failure instead.
+ */
+template<typename R, typename FR, typename XR, typename V, typename FV, typename XV>
+const failable<R, FR, XR> operator>>(const failable<V, FV, XV>& m, const lambda<failable<R, FR, XR>(const V)>& f) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+template<typename R, typename FR, typename XR, typename V, typename FV, typename XV>
+const failable<R, FR, XR> operator>>(const failable<V, FV, XV>& m, const failable<R, FR, XR> (* const f)(const V)) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+/**
+ * State + content pair data type used by the state monad.
+ */
+template<typename S, typename V> class scp {
+public:
+ scp(const S& s, const V& v) : s(s), v(v) {
+ }
+
+ operator const S() const {
+ return s;
+ }
+
+ operator const V() const {
+ return v;
+ }
+
+ const scp<S, V>& operator=(const scp<S, V>& p) {
+ if(this == &p)
+ return *this;
+ s = p.s;
+ v = p.v;
+ return *this;
+ }
+
+ const bool operator!=(const scp<S, V>& p) const {
+ return !this->operator==(p);
+ }
+
+ const bool operator==(const scp<S, V>& p) const {
+ if (this == &p)
+ return true;
+ return s == p.s && v == p.v;
+ }
+
+private:
+ const S s;
+ const V v;
+
+ template<typename A, typename B> friend const A scpstate(const scp<A, B>& m);
+ template<typename A, typename B> friend const B content(const scp<A, B>& m);
+};
+
+/**
+ * Returns the state of a state-content pair.
+ */
+template<typename S, typename V> const S scpstate(const scp<S, V>& m) {
+ return m.s;
+}
+
+/**
+ * Returns the content of a state-content pair.
+ */
+template<typename S, typename V> const S content(const scp<S, V>& m) {
+ return m.v;
+}
+
+/**
+ * State monad. Used to represent the combination of a state and a content.
+ */
+template<typename S, typename V> class state {
+public:
+ state(const lambda<scp<S, V>(const S)>& f) : f(f) {
+ }
+
+ const scp<S, V> operator()(const S& s) const {
+ return f(s);
+ }
+
+ const state<S, V>& operator=(const state<S, V>& m) {
+ if(this == &m)
+ return *this;
+ f = m.f;
+ return *this;
+ }
+
+ const bool operator!=(const state<S, V>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const state<S, V>& m) const {
+ if (this == &m)
+ return true;
+ return f == m.f;
+ }
+
+private:
+ const lambda<scp<S, V>(const S)> f;
+};
+
+/**
+ * Write a state monad to a stream.
+ */
+template<typename S, typename V> ostream& operator<<(ostream& out, const state<S, V>& m) {
+ const S s = m;
+ const V v = m;
+ out << '(' << s << ' ' << v << ')';
+ return out;
+}
+
+/**
+ * Return a state monad carrying a result content.
+ */
+template<typename S, typename V> struct returnState {
+ const V v;
+ returnState(const V& v) : v(v) {
+ }
+ const scp<S, V> operator()(const S& s) const {
+ return scp<S, V>(s, v);
+ }
+};
+
+template<typename S, typename V> const state<S, V> result(const V& v) {
+ return state<S, V>(returnState<S, V>(v));
+}
+
+/**
+ * Return a state monad with a transformer function.
+ * A transformer function takes a state and returns an scp pair carrying a content and a
+ * new (transformed) state.
+ */
+template<typename S, typename V> const state<S, V> transformer(const lambda<scp<S, V>(const S)>& f) {
+ return state<S, V>(f);
+}
+
+/**
+ * Bind a function to a state monad. The function takes a content and returns a state
+ * monad carrying a return content.
+ */
+template<typename S, typename A, typename B> struct stateBind {
+ const state<S, A> st;
+ const lambda<state<S, B>(const A)>f;
+
+ stateBind(const state<S, A>& st, const lambda<state<S, B>(const A)>& f) : st(st), f(f) {
+ }
+
+ const scp<S, B> operator()(const S& is) const {
+ const scp<S, A> iscp = st(is);
+ const state<S, B> m = f((A)iscp);
+ return m((S)iscp);
+ }
+};
+
+template<typename S, typename A, typename B>
+const state<S, B> operator>>(const state<S, A>& st, const lambda<state<S, B>(const A)>& f) {
+ return state<S, B>(stateBind<S, A , B>(st, f));
+}
+
+template<typename S, typename A, typename B>
+const state<S, B> operator>>(const state<S, A>& st, const state<S, B> (* const f)(const A)) {
+ return state<S, B>(stateBind<S, A , B>(st, f));
+}
+
+}
+#endif /* tuscany_monad_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp
new file mode 100644
index 0000000000..28e484d42b
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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$ */
+
+/**
+ * Test parallel functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "perf.hpp"
+#include "parallel.hpp"
+
+namespace tuscany {
+
+int inci = 0;
+
+struct incPerf {
+ incPerf() {
+ }
+ const bool operator()() const {
+ inci = inci + 1;
+ return true;
+ }
+};
+
+const gc_ptr<int> tlsic() {
+ gc_ptr<int> i = new (gc_new<int>()) int();
+ *i = 0;
+ return i;
+}
+const perthread_ptr<int> tlsi(tlsic);
+
+struct tlsPerf {
+ tlsPerf() {
+ }
+ const bool operator()() const {
+ *tlsi = *tlsi + 1;
+ return true;
+ }
+};
+
+#ifdef WANT_THREADS
+
+int addi = 0;
+
+struct addAndFetchPerf {
+ addAndFetchPerf() {
+ }
+ const bool operator()() const {
+ __sync_add_and_fetch(&addi, 1);
+ return true;
+ }
+};
+
+int muxi = 0;
+
+struct mutexPerf {
+ pthread_mutex_t* mutex;
+ mutexPerf(pthread_mutex_t* mutex) : mutex(mutex) {
+ }
+ const bool operator()() const {
+ pthread_mutex_lock(mutex);
+ muxi = muxi + 1;
+ pthread_mutex_unlock(mutex);
+ return true;
+ }
+};
+
+#endif
+
+bool testAtomicPerf() {
+ const int count = 100000;
+ {
+ const lambda<bool()> l = incPerf();
+ cout << "Non-atomic inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(inci == count + 1000);
+ }
+#ifdef WANT_THREADS
+ {
+ const lambda<bool()> l = addAndFetchPerf();
+ cout << "Atomic inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(addi == count + 1000);
+ }
+ {
+ pthread_mutex_t mutex;
+ pthread_mutex_init(&mutex, NULL);
+ const lambda<bool()> l = mutexPerf(&mutex);
+ cout << "Locked inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(muxi == count + 1000);
+ pthread_mutex_destroy(&mutex);
+ }
+#endif
+ {
+ const lambda<bool()> l = tlsPerf();
+ cout << "Thread local inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(*tlsi == count + 1000);
+ }
+ return true;
+}
+
+#ifdef WANT_THREADS
+
+const int mtsquare(const int x) {
+ for(int i = 0; i < 10000000; i++)
+ ;
+ return x * x;
+}
+
+const list<future<int> > submitSquares(worker& w, const int max, const int i) {
+ if (i == max)
+ return list<future<int> >();
+ const lambda<int()> func = curry(lambda<int(const int)> (mtsquare), i);
+ return cons(submit(w, func), submitSquares(w, max, i + 1));
+}
+
+bool checkSquareResults(const list<future<int> > r, int i) {
+ if (isNil(r))
+ return true;
+ assert(car(r) == i * i);
+ checkSquareResults(cdr(r), i + 1);
+ return true;
+}
+
+const gc_ptr<unsigned long> tlsvc() {
+ gc_ptr<unsigned long> i = new (gc_new<unsigned long>()) unsigned long();
+ *i = 0l;
+ return i;
+}
+const perthread_ptr<unsigned long> tlsv(tlsvc);
+
+const long int tlsset(gc_ptr<wqueue<bool>> wq, gc_ptr<wqueue<bool>> xq) {
+ const unsigned long v = *tlsv;
+ *tlsv = threadId();
+ enqueue(*xq, true);
+ dequeue(*wq);
+ return v;
+}
+
+const bool tlscheck(gc_ptr<wqueue<bool>> wq, gc_ptr<wqueue<bool>> xq) {
+ const bool r = *tlsv == threadId();
+ enqueue(*xq, true);
+ dequeue(*wq);
+ return r;
+}
+
+const bool waitForWorkers(wqueue<bool>& xq, const int n) {
+ if (n == 0)
+ return true;
+ dequeue(xq);
+ return waitForWorkers(xq, n - 1);
+}
+
+const bool unblockWorkers(wqueue<bool>& wq, const int n) {
+ if (n == 0)
+ return true;
+ enqueue(wq, true);
+ return unblockWorkers(wq, n - 1);
+}
+
+const list<future<long int> > submitTLSSets(worker& w, wqueue<bool>& wq, wqueue<bool>& xq, const int max, const int i) {
+ if (i == max)
+ return list<future<long int> >();
+ const lambda<long int()> func = curry(lambda<long int(gc_ptr<wqueue<bool>>, gc_ptr<wqueue<bool>>)>(tlsset), (gc_ptr<wqueue<bool>>)&wq, (gc_ptr<wqueue<bool>>)&xq);
+ return cons(submit(w, func), submitTLSSets(w, wq, xq, max, i + 1));
+}
+
+bool checkTLSSets(const list<future<long int> > s) {
+ if (isNil(s))
+ return true;
+ assert(car(s) == 0);
+ return checkTLSSets(cdr(s));
+}
+
+const list<future<bool> > submitTLSChecks(worker& w, wqueue<bool>& wq, wqueue<bool>& xq, const int max, const int i) {
+ if (i == max)
+ return list<future<bool> >();
+ const lambda<bool()> func = curry(lambda<bool(gc_ptr<wqueue<bool>>, gc_ptr<wqueue<bool>>)>(tlscheck), (gc_ptr<wqueue<bool>>)&wq, (gc_ptr<wqueue<bool>>)&xq);
+ return cons(submit(w, func), submitTLSChecks(w, wq, xq, max, i + 1));
+}
+
+bool checkTLSResults(const list<future<bool> > r) {
+ if (isNil(r))
+ return true;
+ assert(car(r) == true);
+ return checkTLSResults(cdr(r));
+}
+
+bool testWorker() {
+ const int max = 100;
+ worker w(max);
+ {
+ const lambda<int()> func = curry(lambda<int(const int)> (mtsquare), 2);
+ assert(submit(w, func) == 4);
+ }
+ {
+ const list<future<int> > r(submitSquares(w, max, 0));
+ checkSquareResults(r, 0);
+ }
+ {
+ wqueue<bool> wq(max);
+ unblockWorkers(wq, max);
+ waitForWorkers(wq, max);
+ unblockWorkers(wq, max);
+ waitForWorkers(wq, max);
+ }
+ {
+ wqueue<bool> wq(max);
+ wqueue<bool> xq(max);
+ const list<future<long int> > s(submitTLSSets(w, wq, xq, max, 0));
+ waitForWorkers(xq, max);
+ unblockWorkers(wq, max);
+ checkTLSSets(s);
+ const list<future<bool> > r(submitTLSChecks(w, wq, xq, max, 0));
+ waitForWorkers(xq, max);
+ unblockWorkers(wq, max);
+ checkTLSResults(r);
+ }
+ shutdown(w);
+ return true;
+}
+
+#endif
+
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testAtomicPerf();
+#ifdef WANT_THREADS
+ tuscany::testWorker();
+#else
+ tuscany::cout << "Skipped multi-thread tests" << tuscany::endl;
+#endif
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/parallel.hpp b/sca-cpp/branches/lightweight-sca/kernel/parallel.hpp
new file mode 100644
index 0000000000..3be4d3bc8e
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/parallel.hpp
@@ -0,0 +1,466 @@
+/*
+ * 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_parallel_hpp
+#define tuscany_parallel_hpp
+
+/**
+ * Simple parallel work execution functions.
+ */
+
+#include <unistd.h>
+#ifdef WANT_THREADS
+#include <pthread.h>
+#endif
+
+#include "function.hpp"
+#include "list.hpp"
+
+namespace tuscany {
+
+/**
+ * Returns the current process id.
+ */
+unsigned long processId() {
+ return (unsigned long)getpid();
+}
+
+#ifdef WANT_THREADS
+
+/**
+ * Returns the current thread id.
+ */
+unsigned long threadId() {
+ return (unsigned long)pthread_self();
+}
+
+/**
+ * Represents a value which will be know in the future.
+ */
+template<typename T> class future {
+
+private:
+ template<typename X> class futureValue {
+ public:
+ futureValue() : hasValue(false) {
+ pthread_mutex_init(&valueMutex, NULL);
+ pthread_cond_init(&valueCond, NULL);
+ }
+
+ futureValue(const futureValue& fv) : valueMutex(fv.valueMutex), valueCond(fv.valueCond), hasValue(fv.hasValue), value(fv.value) {
+ }
+
+ ~futureValue() {
+ //pthread_mutex_destroy(&valueMutex);
+ //pthread_cond_destroy(&valueCond);
+ }
+
+ bool set(const T& v) {
+ pthread_mutex_lock(&valueMutex);
+ if(hasValue) {
+ pthread_mutex_unlock(&valueMutex);
+ return false;
+ }
+ hasValue = true;
+ value = v;
+ pthread_mutex_unlock(&valueMutex);
+ pthread_cond_broadcast(&valueCond);
+ return true;
+ }
+
+ const T get() {
+ pthread_mutex_lock(&valueMutex);
+ while(!hasValue) {
+ pthread_cond_wait(&valueCond, &valueMutex);
+ }
+ const T& v = value;
+ pthread_mutex_unlock(&valueMutex);
+ return v;
+ }
+
+ private:
+ pthread_mutex_t valueMutex;
+ pthread_cond_t valueCond;
+ bool hasValue;
+ X value;
+ };
+
+ gc_ptr<futureValue<T> > fvalue;
+
+ template<typename X> friend const X get(const future<X>& f);
+ template<typename X> friend bool set(const future<X>& f, const X& v);
+
+public:
+ future() : fvalue(new (gc_new<futureValue<T> >()) futureValue<T>()) {
+ }
+
+ ~future() {
+ }
+
+ future(const future& f) : fvalue(f.fvalue) {
+ }
+
+ const future& operator=(const future& f) {
+ if (&f == this)
+ return *this;
+ fvalue = f.fvalue;
+ return *this;
+ }
+
+ const future& operator=(const T& v) const {
+ fvalue->set(v);
+ return *this;
+ }
+
+ operator const T() const {
+ return fvalue->get();
+ }
+};
+
+/**
+ * A bounded thread safe queue.
+ */
+template<typename T> class wqueue {
+public:
+ wqueue(size_t max) : max(max), size(0), tail(0), head(0), values(new (gc_anew<T>(max)) T[max]) {
+ pthread_mutex_init(&mutex, NULL);
+ pthread_cond_init(&full, NULL);
+ pthread_cond_init(&empty, NULL);
+ }
+
+ wqueue(const wqueue& wq) : max(wq.max), size(wq.size), tail(wq.tail), head(wq.head), mutex(wq.mutex), full(wq.full), empty(wq.empty), values(wq.values) {
+ }
+
+ ~wqueue() {
+ //pthread_mutex_destroy(&mutex);
+ //pthread_cond_destroy(&full);
+ //pthread_cond_destroy(&empty);
+ }
+
+private:
+ const size_t max;
+ size_t size;
+ size_t tail;
+ size_t head;
+ pthread_mutex_t mutex;
+ pthread_cond_t full;
+ pthread_cond_t empty;
+ gc_ptr<T> values;
+
+ template<typename X> friend const size_t enqueue(wqueue<X>& q, const X& v);
+ template<typename X> friend const X dequeue(wqueue<X>& q);
+};
+
+/**
+ * Adds an element to the tail of the queue.
+ */
+template<typename T> const size_t enqueue(wqueue<T>&q, const T& v) {
+ pthread_mutex_lock(&q.mutex);
+ while(q.size == q.max)
+ pthread_cond_wait(&q.full, &q.mutex);
+ q.values[q.tail] = v;
+ q.tail = (q.tail + 1) % q.max;
+ q.size++;
+ pthread_mutex_unlock(&q.mutex);
+ pthread_cond_broadcast(&q.empty);
+ return q.size;
+}
+
+/**
+ * Returns the element at the head of the queue.
+ */
+template<typename T> const T dequeue(wqueue<T>& q) {
+ pthread_mutex_lock(&q.mutex);
+ while(q.size == 0)
+ pthread_cond_wait(&q.empty, &q.mutex);
+ const T v = q.values[q.head];
+ q.head = (q.head + 1) % q.max;
+ q.size--;
+ pthread_mutex_unlock(&q.mutex);
+ pthread_cond_broadcast(&q.full);
+ return v;
+}
+
+/**
+ * The worker thread function.
+ */
+void *workerThreadFunc(void *arg) {
+ int ost;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ost);
+ int ot;
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &ot);
+
+ wqueue<lambda<bool()> >* work = reinterpret_cast<wqueue<lambda<bool()> >*>(arg);
+ while(dequeue(*work)())
+ ;
+ return NULL;
+}
+
+/**
+ * Returns a list of worker threads.
+ */
+const list<pthread_t> workerThreads(wqueue<lambda<bool()> >& wqueue, const size_t count) {
+ if (count == 0)
+ return list<pthread_t>();
+ pthread_t thread;
+ pthread_create(&thread, NULL, workerThreadFunc, &wqueue);
+ return cons(thread, workerThreads(wqueue, count - 1));
+}
+
+/**
+ * A worker, implemented with a work queue and a pool of threads.
+ */
+class worker {
+private:
+
+ // The worker holds a reference to a sharedWorker, to avoid non-thread-safe
+ // copies of the queue and thread pool when a worker is copied
+ class sharedWorker {
+ public:
+ sharedWorker(size_t max) : work(wqueue<lambda<bool()> >(max)), threads(workerThreads(work, max)) {
+ }
+
+ wqueue<lambda<bool()> > work;
+ const list<pthread_t> threads;
+ };
+
+public:
+ worker(size_t max) : w(*(new (gc_new<sharedWorker>()) sharedWorker(max))) {
+ }
+
+ worker(const worker& wk) : w(wk.w) {
+ }
+
+private:
+ sharedWorker& w;
+
+ template<typename X> friend const future<X> submit(worker& w, const lambda<X()>& func);
+ friend const bool shutdown(worker& w);
+ friend const bool cancel(worker& w);
+};
+
+/**
+ * Function used to wrap work submitted to a worker.
+ */
+template<typename R> bool submitFunc(const lambda<R()>& func, const future<R>& fut) {
+ fut = func();
+ return true;
+}
+
+/**
+ * Submits work to a worker.
+ */
+template<typename R> const future<R> submit(worker& w, const lambda<R()>& func) {
+ const future<R> fut;
+ const lambda<bool()> f = curry(lambda<bool(const lambda<R()>, future<R>)>(submitFunc<R>), func, fut);
+ enqueue(w.w.work, f);
+ return fut;
+}
+
+/**
+ * Enqueues shutdown requests.
+ */
+const bool shutdownEnqueue(const list<pthread_t>& threads, wqueue<lambda<bool()> >& work) {
+ if (isNil(threads))
+ return true;
+ enqueue(work, result(false));
+ return shutdownEnqueue(cdr(threads), work);
+}
+
+/**
+ * Waits for shut down threads to terminate.
+ */
+const bool shutdownJoin(const list<pthread_t>& threads) {
+ if (isNil(threads))
+ return true;
+ pthread_join(car(threads), NULL);
+ return shutdownJoin(cdr(threads));
+}
+
+/**
+ * Shutdown a worker.
+ */
+const bool shutdown(worker& w) {
+ shutdownEnqueue(w.w.threads, w.w.work);
+ shutdownJoin(w.w.threads);
+ return true;
+}
+
+/**
+ * Cancel a worker.
+ */
+const bool cancel(const list<pthread_t>& threads) {
+ if (isNil(threads))
+ return true;
+ pthread_cancel(car(threads));
+ return cancel(cdr(threads));
+}
+
+const bool cancel(worker& w) {
+ cancel(w.w.threads);
+ return true;
+}
+
+#else
+
+/**
+ * Returns the current thread id.
+ */
+unsigned long threadId() {
+ return 0;
+}
+
+#endif
+
+/**
+ * Represents a per-thread value.
+ */
+template<typename T> class perthread_ptr {
+public:
+ perthread_ptr() : key(createkey()), owner(true), cl(lambda<gc_ptr<T>()>()), managed(false) {
+ }
+
+ perthread_ptr(const lambda<gc_ptr<T>()>& cl) : key(createkey()), owner(true), cl(cl), managed(true) {
+ }
+
+ ~perthread_ptr() {
+ if (owner)
+ deletekey(key);
+ }
+
+ perthread_ptr(const perthread_ptr& c) : key(c.key), owner(false), cl(c.cl), managed(c.managed) {
+ }
+
+ perthread_ptr& operator=(const perthread_ptr& r) throw() {
+ if(this == &r)
+ return *this;
+ key = r.key;
+ owner = false;
+ cl = r.cl;
+ managed = r.managed;
+ return *this;
+ }
+
+ const perthread_ptr& operator=(const gc_ptr<T>& v) {
+ set(v);
+ return *this;
+ }
+
+ const perthread_ptr& operator=(T* v) {
+ set(v);
+ return *this;
+ }
+
+ const bool operator==(const gc_ptr<T>& r) const throw() {
+ return get() == r;
+ }
+
+ const bool operator==(T* p) const throw() {
+ return get() == p;
+ }
+
+ const bool operator!=(const gc_ptr<T>& r) const throw() {
+ return !this->operator==(r);
+ }
+
+ const bool operator!=(T* p) const throw() {
+ return !this->operator==(p);
+ }
+
+ T& operator*() const throw() {
+ return *get();
+ }
+
+ T* operator->() const throw() {
+ return get();
+ }
+
+ operator gc_ptr<T>() const {
+ return get();
+ }
+
+ operator T*() const {
+ return get();
+ }
+
+private:
+#ifdef WANT_THREADS
+ pthread_key_t createkey() {
+ pthread_key_t k;
+ pthread_key_create(&k, NULL);
+ return k;
+ }
+
+ bool deletekey(pthread_key_t k) {
+ pthread_key_delete(k);
+ return true;
+ }
+
+ bool set(const gc_ptr<T>& v) {
+ pthread_setspecific(key, (T*)v);
+ return true;
+ }
+
+ gc_ptr<T> get() const {
+ const gc_ptr<T> v = static_cast<T*>(pthread_getspecific(key));
+ if (v != NULL || !managed)
+ return v;
+ const gc_ptr<T> nv = cl();
+ pthread_setspecific(key, nv);
+ return nv;
+ }
+
+#else
+ gc_ptr<gc_ptr<T> > createkey() {
+ return new (gc_new<gc_ptr<T> >()) gc_ptr<T>();
+ }
+
+ bool deletekey(unused gc_ptr<gc_ptr<T> > k) {
+ return true;
+ }
+
+ bool set(const gc_ptr<T>& v) {
+ *key = v;
+ return true;
+ }
+
+ gc_ptr<T> get() const {
+ if (*key != NULL || !managed)
+ return *key;
+ *key = cl();
+ return *key;
+ }
+
+#endif
+
+#ifdef WANT_THREADS
+ pthread_key_t key;
+#else
+ gc_ptr<gc_ptr<T> >key;
+#endif
+
+ bool owner;
+ lambda<const gc_ptr<T>()> cl;
+ bool managed;
+};
+
+}
+#endif /* tuscany_parallel_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/perf.hpp b/sca-cpp/branches/lightweight-sca/kernel/perf.hpp
new file mode 100644
index 0000000000..04aad06664
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/perf.hpp
@@ -0,0 +1,78 @@
+/*
+ * 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_perf_hpp
+#define tuscany_perf_hpp
+
+/**
+ * Functions to help measure performance.
+ */
+
+#include <sys/time.h>
+#include <time.h>
+
+#include "function.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Measure the time required to perform a function in msec.
+ */
+struct timeLambda {
+ const lambda<bool()> f;
+ timeLambda(const lambda<bool()>& f) : f(f) {
+ }
+ bool operator()(const long count) const {
+ for (long i = 0; i < count; i++)
+ f();
+ return true;
+ }
+};
+
+const double time(const lambda<bool()>& f, const long warmup, const long count) {
+ const lambda<bool(long)> tl = timeLambda(f);
+ struct timeval start;
+ struct timeval end;
+
+ tl(warmup);
+ gettimeofday(&start, NULL);
+ tl(count);
+ gettimeofday(&end, NULL);
+
+ const long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
+ return (double)t / (double)count;
+}
+
+const unsigned long timems() {
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return (unsigned long)(t.tv_sec * 1000 + t.tv_usec / 1000);
+}
+
+const unsigned long timens() {
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return (unsigned long)(t.tv_sec * 1000000000 + t.tv_usec * 1000);
+}
+
+}
+#endif /* tuscany_perf_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/sstream.hpp b/sca-cpp/branches/lightweight-sca/kernel/sstream.hpp
new file mode 100644
index 0000000000..17fd28b48b
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/sstream.hpp
@@ -0,0 +1,262 @@
+/*
+ * 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_sstream_hpp
+#define tuscany_sstream_hpp
+
+/**
+ * Char buffer based streams.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <memory.h>
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+
+namespace tuscany {
+
+/**
+ * Instrumentable memcpy.
+ */
+void* stream_memcpy(void* t, const void* s, const size_t n) {
+ return memcpy(t, s, n);
+}
+
+/**
+ * Write a list of strings into a buffer.
+ */
+const bool writeList(const list<string>& l, char* buf) {
+ if (isNil(l))
+ return true;
+ const string c = car(l);
+ char* b = buf - length(c);
+ memcpy(b, c_str(c), length(c));
+ return writeList(cdr(l), b);
+}
+
+/**
+ * Output stream backed by a char buffer.
+ */
+class ostringstream : public ostream {
+public:
+ ostringstream() : len(0) {
+ }
+
+ ~ostringstream() {
+ }
+
+ ostringstream(const ostringstream& os) {
+ len = os.len;
+ buf = os.buf;
+ }
+
+ ostringstream& vprintf(const char* fmt, ...) {
+ va_list args;
+ string s;
+ va_start (args, fmt);
+ s.len = vsnprintf(NULL, 0, fmt, args);
+ s.buf = gc_cnew(s.len + 1);
+ va_start (args, fmt);
+ vsnprintf(s.buf, s.len + 1, fmt, args);
+ buf = cons(s, buf);
+ len += s.len;
+ va_end (args);
+ return *this;
+ }
+
+ ostringstream& write(const string& s) {
+ buf = cons(s, buf);
+ len += s.len;
+ return *this;
+ }
+
+ ostringstream& flush() {
+ return *this;
+ }
+
+private:
+ const string str() {
+ if (isNil(buf))
+ return string();
+ string s;
+ s.len = len;
+ s.buf = gc_cnew(s.len + 1);
+ writeList(buf, s.buf + len);
+ s.buf[s.len] = '\0';
+ return s;
+ }
+
+ friend const string str(ostringstream& os);
+
+ size_t len;
+ list<string> buf;
+};
+
+/**
+ * Return a string representation of a stream.
+ */
+const string str(ostringstream& os) {
+ return os.str();
+}
+
+/**
+ * Input stream backed by a char buffer
+ */
+class istringstream : public istream {
+public:
+ istringstream(const string& s) {
+ cur = 0;
+ const size_t slen = length(s);
+ len = slen;
+ buf = c_str(s);
+ }
+
+ ~istringstream() {
+ }
+
+ istringstream(const istringstream& is) {
+ len = is.len;
+ cur = is.cur;
+ buf = is.buf;
+ }
+
+ const size_t read(void* b, size_t size) {
+ const size_t n = len - cur;
+ if (n == 0)
+ return 0;
+ if (n > size) {
+ stream_memcpy(b, buf + cur, size);
+ cur = cur + size;
+ return size;
+ }
+ stream_memcpy(b, buf + cur, n);
+ cur = cur + n;
+ return n;
+ }
+
+ const bool eof() {
+ return cur == len;
+ }
+
+ const bool fail() {
+ return false;
+ }
+
+ const int get() {
+ if (eof())
+ return -1;
+ const int c = buf[cur];
+ cur += 1;
+ return c;
+ }
+
+ const int peek() {
+ if (eof())
+ return -1;
+ return buf[cur];
+ }
+
+private:
+ size_t len;
+ size_t cur;
+ const char* buf;
+};
+
+/**
+ * Tokenize a string into a list of strings.
+ */
+const list<string> tokenize(const char* sep, const string& str) {
+ struct nested {
+ static const list<string> tokenize(const char* sep, const size_t slen, const string& str, const size_t start) {
+ if (start >= length(str))
+ return list<string>();
+ const size_t i = find(str, sep, start);
+ if (i == length(str))
+ return mklist(string(substr(str, start)));
+ return cons(string(substr(str, start, i - start)), tokenize(sep, slen, str, i + slen));
+ }
+ };
+ return nested::tokenize(sep, strlen(sep), str, 0);
+}
+
+/**
+ * Join a list of strings into a single string.
+ */
+const string join(const char* sep, const list<string>& l) {
+ struct nested {
+ static ostringstream& join(const char* sep, const list<string>& l, ostringstream& os) {
+ if (isNil(l))
+ return os;
+ os << car(l);
+ if (!isNil(cdr(l)))
+ os << sep;
+ return join(sep, cdr(l), os);
+ }
+ };
+ ostringstream os;
+ return str(nested::join(sep, l, os));
+}
+
+/**
+ * Returns a lazy list view of an input stream.
+ */
+struct ilistRead{
+ istream &is;
+ ilistRead(istream& is) : is(is) {
+ }
+ const list<string> operator()() {
+ char buffer[1024];
+ const size_t n = read(is, buffer, sizeof(buffer));
+ if (n ==0)
+ return list<string>();
+ return cons(string(buffer, n), (*this)());
+ }
+};
+
+const list<string> streamList(istream& is) {
+ return ilistRead(is)();
+}
+
+/**
+ * Fragment the first element of a list of strings to fit the given max length.
+ */
+const list<string> fragment(list<string> l, size_t max) {
+ const string s = car(l);
+ if (length(s) <= max)
+ return l;
+ return cons(substr(s, 0, max), cons(substr(s, max), cdr(l)));
+}
+
+/**
+ * Write a list of strings to an output stream.
+ */
+ostream& write(const list<string>& l, ostream& os) {
+ if(isNil(l))
+ return os;
+ os << car(l);
+ return write(cdr(l), os);
+}
+
+}
+
+#endif /* tuscany_sstream_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/stream.hpp b/sca-cpp/branches/lightweight-sca/kernel/stream.hpp
new file mode 100644
index 0000000000..8ccfed948f
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/stream.hpp
@@ -0,0 +1,201 @@
+/*
+ * 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_stream_hpp
+#define tuscany_stream_hpp
+
+/**
+ * Basic stream type and functions.
+ */
+
+#include <stdarg.h>
+#include "config.hpp"
+#include "gc.hpp"
+#include "string.hpp"
+
+namespace tuscany {
+
+/**
+ * Base output stream.
+ */
+class ostream {
+public:
+ virtual ostream& vprintf(const char* fmt, ...) = 0;
+ virtual ostream& write(const string& s) = 0;
+ virtual ostream& flush() = 0;
+};
+
+/**
+ * Flush a stream.
+ */
+ostream& flush(ostream& os) {
+ return os.flush();
+}
+
+/**
+ * Write simple values to a stream.
+ */
+ostream& operator<<(ostream& os, const char* v) {
+ return os.vprintf("%s", v);
+}
+
+ostream& operator<<(ostream& os, const unsigned char* v) {
+ return os.vprintf("%s", v);
+}
+
+ostream& operator<<(ostream& os, const char v) {
+ return os.vprintf("%c", v);
+}
+
+ostream& operator<<(ostream& os, const int v) {
+ return os.vprintf("%d", v);
+}
+
+ostream& operator<<(ostream& os, const unsigned int v) {
+ return os.vprintf("%u", v);
+}
+
+ostream& operator<<(ostream& os, const long int v) {
+ return os.vprintf("%ld", v);
+}
+
+ostream& operator<<(ostream& os, const long unsigned int v) {
+ return os.vprintf("%lu", v);
+}
+
+ostream& operator<<(ostream& os, const double v) {
+ return os.vprintf("%.10g", v);
+}
+
+ostream& operator<<(ostream& os, const void* v) {
+ return os.vprintf("%p", v);
+}
+
+ostream& operator<<(ostream& os, const string& v) {
+ return os.write(v);
+}
+
+class stream_endl {
+} endl;
+
+ostream& operator<<(ostream& os, unused const stream_endl e) {
+ os.write("\n");
+ return os.flush();
+}
+
+/*
+ * Input stream.
+ */
+class istream {
+public:
+ virtual const size_t read(void* buf, size_t size) = 0;
+ virtual const bool eof() = 0;
+ virtual const bool fail() = 0;
+ virtual const int get() = 0;
+ virtual const int peek() = 0;
+};
+
+/**
+ * Read from an input stream.
+ */
+const size_t read(istream& is, void * buf, size_t size) {
+ return is.read(buf, size);
+}
+
+/**
+ * Return true if the end of an input stream has been reached.
+ */
+const bool eof(istream& is) {
+ return is.eof();
+}
+
+/**
+ * Return true if an input stream can't be accessed.
+ */
+const bool fail(istream& is) {
+ return is.fail();
+}
+
+/**
+ * Read a character from a stream.
+ */
+const int get(istream& is) {
+ return is.get();
+}
+
+/**
+ * Peek a character from a stream.
+ */
+const int peek(istream& is) {
+ return is.peek();
+}
+
+template<typename T> ostream& operator<<(ostream& out, const gc_ptr<T>& p) {
+ return out << p.ptr;
+}
+
+#ifdef WANT_MAINTAINER_LOG
+
+/**
+ * Debug stream implementation with no dependencies on anything else.
+ */
+class odebugstream : public ostream {
+public:
+ odebugstream() {
+ }
+
+ odebugstream& vprintf(const char* fmt, ...) {
+ va_list args;
+ string s;
+ va_start (args, fmt);
+ s.len = vsnprintf(NULL, 0, fmt, args);
+ s.buf = gc_cnew(s.len + 1);
+ va_start (args, fmt);
+ vsnprintf(s.buf, s.len + 1, fmt, args);
+ buf = buf + s;
+ va_end (args);
+ return *this;
+ }
+
+ odebugstream& write(const string& s) {
+ buf = buf + s;
+ return *this;
+ }
+
+ odebugstream& flush() {
+ return *this;
+ }
+
+private:
+ friend const string str(odebugstream& os);
+
+ string buf;
+};
+
+const string str(odebugstream& os) {
+ return os.buf;
+}
+
+#endif
+
+}
+
+#endif /* tuscany_stream_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/string-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/string-test.cpp
new file mode 100644
index 0000000000..b6f016b294
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/string-test.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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$ */
+
+/**
+ * Test string functions.
+ */
+
+#include <assert.h>
+#include <string>
+#include "sstream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+bool testCopies() {
+ resetStringCopyCounters();
+ string x("abcd");
+ assert(checkStringCopyCounters(1));
+ resetStringCopyCounters();
+ string y = string("abcd");
+ assert(checkStringCopyCounters(1));
+ resetStringCopyCounters();
+ unused string z = y;
+ assert(checkStringCopyCounters(0));
+ resetStringCopyCounters();
+ const list<string> pl = list<string>() + "abcd" + "efgh";
+ printStringCopyCounters();
+ resetStringCopyCounters();
+ const list<string> cl = cons<string>("efgh", mklist<string>("abcd"));
+ printStringCopyCounters();
+ return true;
+}
+
+bool testString() {
+ const string s("abcd");
+ assert(length(s) == 4);
+ assert(!strcmp(c_str(s), "abcd"));
+
+ assert(s == "abcd");
+ assert(s == string("abcd"));
+ assert(s != "zbcd");
+
+ assert(s < "zbcd");
+ assert(s < "zbc");
+ assert(s < "abzd");
+ assert(s < "abcdz");
+
+ assert(s > "Abcd");
+ assert(s > "Abc");
+ assert(s > "abCd");
+ assert(s > "Abcdz");
+
+ const string x = "abcd";
+ assert(!strcmp(c_str(x), "abcd"));
+
+ const string y = string("abcd");
+ assert(!strcmp(c_str(y), "abcd"));
+
+ assert(string("ab") + "cd" == "abcd");
+
+ assert(find("abcd", "cd") == 2);
+ assert(find("abcd", "xy") == length("abcd"));
+ assert(find_first_of("abcd", "cd") == 2);
+ assert(find_first_of("abcd", "xy") == length("abcd"));
+ assert(substr("abcdef", 4) == "ef");
+ assert(substr("abcdef", 4, 2) == "ef");
+ assert(substr("abcdef", 4, 3) == "ef");
+ assert(substr("abcdef", 6, 3) == "");
+ return true;
+}
+
+bool testStream() {
+ ostringstream os;
+ os << "ab" << "cd";
+ cout << str(os) << endl;
+ assert(str(os) == "abcd");
+
+ ostringstream cs;
+ cs << "\'";
+ assert(str(cs) == "\'");
+ cs << '\'';
+ assert(str(cs) == "\'\'");
+
+ istringstream is("abcd");
+ char b[2];
+ assert(read(is, b, 2) == 2);
+ assert(string("ab") == string(b, 2));
+ assert(eof(is) == false);
+ assert(read(is, b, 2) == 2);
+ assert(string("cd") == string(b, 2));
+ assert(eof(is) == true);
+ assert(read(is, b, 2) == 0);
+ return true;
+}
+
+std::string stdAdd(std::string& x, std::string& y) {
+ return x + y;
+}
+
+string add(string& x, string& y) {
+ return x + y;
+}
+
+char charBuffer[16385];
+
+struct addStrings{
+ const size_t size;
+ addStrings(const size_t size) : size(size) {
+ }
+ bool operator()() const {
+ const size_t sz = size / 4;
+ string x(charBuffer, sz);
+ string y(charBuffer, sz);
+ assert(length(add(x, y)) == sz * 2);
+ return true;
+ }
+};
+
+struct addStdStrings{
+ const size_t size;
+ addStdStrings(const size_t size) : size(size) {
+ }
+ bool operator()() const {
+ const size_t sz = size / 4;
+ std::string x(charBuffer, sz);
+ std::string y(charBuffer, sz);
+ assert(stdAdd(x, y).length() == (unsigned int)(sz * 2));
+ return true;
+ }
+};
+
+bool testStringPerf() {
+ memset(charBuffer, 'A', 16384);
+ charBuffer[16384] = '\0';
+
+ const int count = 10000;
+ {
+ const lambda<bool()> a16 = addStrings(16);
+ cout << "string test " << time(a16, 5, count) << " ms" << endl;
+ const lambda<bool()> a32 =addStrings(32);
+ cout << "string test " << time(a32, 5, count) << " ms" << endl;
+ const lambda<bool()> a256 =addStrings(256);
+ cout << "string test " << time(a256, 5, count) << " ms" << endl;
+ const lambda<bool()> a1024 =addStrings(1024);
+ cout << "string test " << time(a1024, 5, count) << " ms" << endl;
+ const lambda<bool()> a4096 =addStrings(4096);
+ cout << "string test " << time(a4096, 5, count) << " ms" << endl;
+ }
+ {
+ const lambda<bool()> a16 =addStdStrings(16);
+ cout << "Std string test " << time(a16, 5, count) << " ms" << endl;
+ const lambda<bool()> a32 =addStdStrings(32);
+ cout << "Std string test " << time(a32, 5, count) << " ms" << endl;
+ const lambda<bool()> a256 =addStdStrings(256);
+ cout << "Std string test " << time(a256, 5, count) << " ms" << endl;
+ const lambda<bool()> a1024 =addStdStrings(1024);
+ cout << "Std string test " << time(a1024, 5, count) << " ms" << endl;
+ const lambda<bool()> a4096 =addStdStrings(4096);
+ cout << "Std string test " << time(a4096, 5, count) << " ms" << endl;
+ }
+
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testCopies();
+ tuscany::testString();
+ tuscany::testStream();
+ tuscany::testStringPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/string.hpp b/sca-cpp/branches/lightweight-sca/kernel/string.hpp
new file mode 100644
index 0000000000..e726a61b84
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/string.hpp
@@ -0,0 +1,305 @@
+/*
+ * 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_string_hpp
+#define tuscany_string_hpp
+
+/**
+ * Simple and fast string type backed by a char buffer
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+#include "gc.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_MAINTAINER_COUNTERS
+
+/**
+ * Debug utilities. Counters used to track string copies.
+ */
+long countStringCopies = 0;
+
+bool resetStringCopyCounters() {
+ countStringCopies = 0;
+ return true;
+}
+
+bool checkStringCopyCounters(long c) {
+ return countStringCopies == c;
+}
+
+bool printStringCopyCounters() {
+ printf("countStringCopies %ld\n", countStringCopies);
+ return true;
+}
+
+#else
+
+#define resetStringCopyCounters()
+#define checkStringCopyCounters(c) true
+#define printStringCopyCounters()
+
+#endif
+
+/**
+ * Instrumented memcpy.
+ */
+void* string_memcpy(void* t, const void* s, const size_t n) {
+#ifdef WANT_MAINTAINER_COUNTERS
+ countStringCopies += 1;
+#endif
+ return memcpy(t, s, n);
+}
+
+char stringEmptyBuffer[1] = { '\0' };
+
+/**
+ * String class. The maximum string size is specified as a template parameter.
+ */
+class string {
+public:
+ string() : len(0) {
+ buf = stringEmptyBuffer;
+ }
+
+ string(const char* s) {
+ len = strlen(s);
+ if (len == 0) {
+ buf = stringEmptyBuffer;
+ return;
+ }
+ buf = gc_cnew(len + 1);
+ string_memcpy(buf, s, len + 1);
+ }
+
+ string(const char* s, const size_t n) {
+ len = n;
+ if (len == 0) {
+ buf = stringEmptyBuffer;
+ return;
+ }
+ buf = gc_cnew(len + 1);
+ string_memcpy(buf, s, len);
+ buf[len] = '\0';
+ }
+
+ string(const size_t n, const char c) {
+ len = n;
+ if (len == 0) {
+ buf = stringEmptyBuffer;
+ return;
+ }
+ buf = gc_cnew(len + 1);
+ memset(buf, c, n);
+ buf[len] = '\0';
+ }
+
+ string(const string& s) {
+ len = s.len;
+ buf = s.buf;
+ }
+
+ const string& operator=(const string& s) {
+ if (&s == this)
+ return *this;
+ len = s.len;
+ buf = s.buf;
+ return *this;
+ }
+
+ const bool operator==(const string& s) const {
+ if (len != s.len)
+ return false;
+ if (buf == s.buf)
+ return true;
+ return memcmp(buf, s.buf, len) == 0;
+ }
+
+ const bool operator!=(const string& s) const {
+ return !(*this == s);
+ }
+
+ const bool operator==(const char* s) const {
+ if (buf == s)
+ return true;
+ return strcmp(buf, s) == 0;
+ }
+
+ const bool operator!=(const char* s) const {
+ return !(*this == s);
+ }
+
+ const bool operator<(const string& s) const {
+ const size_t n = len < s.len? len : s.len;
+ const int c = memcmp(buf, s.buf, n);
+ if (c < 0)
+ return true;
+ if (c == 0)
+ return len < s.len;
+ return false;
+ }
+
+ const bool operator>(const string& s) const {
+ const size_t n = len < s.len? len : s.len;
+ int c = memcmp(buf, s.buf, n);
+ if (c > 0)
+ return true;
+ if (c == 0)
+ return len > s.len;
+ return false;
+ }
+
+private:
+#ifdef WANT_MAINTAINER_LOG
+ friend class odebugstream;
+#endif
+ friend class ostringstream;
+ friend const string operator+(const string& a, const string& b);
+ friend const string operator+(const string& a, const char* b);
+ friend const size_t length(const string& s);
+ friend const char* c_str(const string& s);
+ friend const size_t find(const string& s1, const char* s2, const size_t start);
+ friend const string substr(const string& s, const size_t pos, const size_t n);
+
+ size_t len;
+ char* buf;
+};
+
+/**
+ * Adds two strings.
+ */
+const string operator+(const string& a, const string& b) {
+ string s;
+ s.len = a.len + b.len;
+ s.buf = gc_cnew(s.len + 1);
+ string_memcpy(s.buf, a.buf, a.len);
+ string_memcpy(s.buf + a.len, b.buf, b.len);
+ s.buf[s.len] = '\0';
+ return s;
+}
+
+const string operator+(const string& a, const char* b) {
+ string s;
+ const size_t blen = strlen(b);
+ s.len = a.len + blen;
+ s.buf = gc_cnew(s.len + 1);
+ string_memcpy(s.buf, a.buf, a.len);
+ string_memcpy(s.buf + a.len, b, blen);
+ s.buf[s.len] = '\0';
+ return s;
+}
+
+/**
+ * Returns the length of a string.
+ */
+const size_t length(const string& s) {
+ return s.len;
+}
+
+/**
+ * Returns a string as a C zero terminated string.
+ */
+const char* c_str(const string& s) {
+ return s.buf;
+}
+
+/**
+ * Find the first occurrence of string s2 in s1, starting at the given position.
+ */
+const size_t find(const string& s1, const char* s2, const size_t start) {
+ if (start >= s1.len)
+ return s1.len;
+ const char *f = strstr(s1.buf + start, s2);
+ if (f == NULL)
+ return s1.len;
+ return f - s1.buf;
+}
+
+const size_t find(const string& s1, const char* s2) {
+ return find(s1, s2, 0);
+}
+
+/**
+ * Return true if string s1 contains s2.
+ */
+const bool contains(const string& s1, const char* s2) {
+ return find(s1, s2) != length(s1);
+}
+
+/**
+ * Find the first occurence of any character from a string in a string.
+ */
+const size_t find_first_of(const string& s1, const string& s2) {
+ return strcspn(c_str(s1), c_str(s2));
+}
+
+/**
+ * Find the first occurence of a character in a string.
+ */
+const size_t find(const string& s, const char c) {
+ const char* cs = c_str(s);
+ const char* f = strchr(cs, c);
+ if (f == NULL)
+ return length(s);
+ return f - cs;
+}
+
+/**
+ * Find the last occurence of a character in a string.
+ */
+const size_t find_last(const string& s, const char c) {
+ const char* cs = c_str(s);
+ const char* f = strrchr(cs, c);
+ if (f == NULL)
+ return length(s);
+ return f - cs;
+}
+
+/**
+ * Return a substring of a string.
+ */
+const string substr(const string& s, const size_t pos, const size_t n) {
+ if (pos >= s.len)
+ return string();
+ if (pos + n > s.len)
+ return string(s.buf + pos, s.len - pos);
+ return string(s.buf + pos, n);
+}
+
+const string substr(const string& s, const size_t pos) {
+ return substr(s, pos, length(s));
+}
+
+/**
+ * Common string constants.
+ */
+
+string trueString("true");
+string falseString("false");
+string emptyString("");
+
+}
+
+#endif /* tuscany_string_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/tree.hpp b/sca-cpp/branches/lightweight-sca/kernel/tree.hpp
new file mode 100644
index 0000000000..89a131c324
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/tree.hpp
@@ -0,0 +1,125 @@
+/*
+ * 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_tree_hpp
+#define tuscany_tree_hpp
+
+/**
+ * Functions to work with trees.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+
+namespace tuscany {
+
+/**
+ * Make a tree from a leaf and two branches.
+ */
+template<typename T> const list<T> mktree(const T& e, const list<T>& left, const list<T>& right) {
+ return mklist<T>(e, left, right);
+}
+
+/**
+ * Find a leaf with the given key in a tree.
+ */
+template<typename T> const list<T> assoctree(const T& k, const list<T>& tree) {
+ if (isNil(tree))
+ return tree;
+ if (k == car<T>(car(tree)))
+ return car(tree);
+ if (k < car<T>(car(tree)))
+ return assoctree<T>(k, cadr(tree));
+ return assoctree<T>(k, caddr(tree));
+}
+
+/**
+ * Construct a new tree from a leaf and a tree.
+ */
+template<typename T> const list<T> constree(const T& e, const list<T>& tree) {
+ if (isNil(tree))
+ return mktree(e, list<T>(), list<T>());
+ if (e == car(tree))
+ return tree;
+ if (e < car(tree))
+ return mktree<T>(car(tree), constree<T>(e, cadr(tree)), caddr(tree));
+ return mktree<T>(car(tree), cadr(tree), constree<T>(e, caddr(tree)));
+}
+
+/**
+ * Make a tree from an unordered list of leaves.
+ */
+template<typename T> const list<T> mktree(const list<T>& l) {
+ if (isNil(l))
+ return l;
+ return constree(car(l), mktree(cdr(l)));
+}
+
+/**
+ * Convert a tree to an ordered list of leaves.
+ */
+template<typename T> const list<T> flatten(const list<T>& tree) {
+ if (isNil(tree))
+ return tree;
+ return append<T>(flatten<T>(cadr(tree)), cons<T>(car(tree), flatten<T>(caddr(tree))));
+}
+
+/**
+ * Sort a list.
+ */
+template<typename T> const list<T> sort(const list<T>& l) {
+ return flatten(mktree(l));
+}
+
+/**
+ * Make a balanced tree from an ordered list of leaves.
+ */
+template<typename T> const list<T> btreeHelper(const list<T>& elements, const size_t n) {
+ if (n == 0)
+ return cons<T>(list<T>(), elements);
+ const size_t leftSize = (n - 1) / 2; {
+ const list<T> leftResult = btreeHelper<T>(elements, leftSize); {
+ const list<T> leftTree = car(leftResult);
+ const list<T> nonLeftElements = cdr(leftResult);
+ const size_t rightSize = n - (leftSize + 1); {
+ const T thisEntry = car(nonLeftElements);
+ const list<T> rightResult = btreeHelper<T>(cdr(nonLeftElements), rightSize); {
+ const list<T> rightTree = car(rightResult);
+ const list<T> remainingElements = cdr(rightResult); {
+ return cons<T>(mktree<T>(thisEntry, leftTree, rightTree), remainingElements);
+ }
+ }
+ }
+ }
+ }
+}
+
+template<typename T> const list<T> mkbtree(const list<T>& elements) {
+ return car(btreeHelper<T>(elements, length(elements)));
+}
+
+}
+
+#endif /* tuscany_tree_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/value.hpp b/sca-cpp/branches/lightweight-sca/kernel/value.hpp
new file mode 100644
index 0000000000..206fe8b32b
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/value.hpp
@@ -0,0 +1,656 @@
+/*
+ * 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_value_hpp
+#define tuscany_value_hpp
+
+/**
+ * Generic value type.
+ */
+
+#include <stdlib.h>
+#include <apr_uuid.h>
+#include <apr_time.h>
+
+#include "string.hpp"
+#include "sstream.hpp"
+#include "gc.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "monad.hpp"
+
+namespace tuscany
+{
+
+#ifdef WANT_MAINTAINER_COUNTERS
+
+/**
+ * Debug utilities. Counters used to track instances of values
+ */
+long int countValues = 0;
+long int countEValues = 0;
+long int countCValues = 0;
+long int countVValues = 0;
+
+bool resetValueCounters() {
+ countValues = countEValues = countCValues = countVValues = 0;
+ return true;
+}
+
+bool checkValueCounters() {
+ return countValues == 0;
+}
+
+bool printValueCounters() {
+ cout << "countValues " << countValues << endl;
+ cout << "countEValues " << countEValues << endl;
+ cout << "countCValues " << countCValues << endl;
+ cout << "countVValues " << countVValues << endl;
+ return true;
+}
+
+#else
+
+#define resetValueCounters()
+#define checkValueCounters() true
+#define printValueCounters()
+
+#endif
+
+#ifdef WANT_MAINTAINER_WATCH
+
+/**
+ * Debug utilities. Macro used to write the contents of a value to
+ * a string, easier to watch in a debugger than the value itself.
+ */
+
+#define debug_watchValue() do { \
+ this->watch = watchValue(*this); \
+ } while (0)
+
+#else
+
+#define debug_watchValue()
+
+#endif
+
+class value;
+
+class value {
+public:
+
+ enum ValueType {
+ Nil, Symbol, String, List, Number, Bool, Lambda, Ptr
+ };
+
+ value() : type(value::Nil) {
+ debug_inc(countValues);
+ debug_inc(countEValues);
+ debug_watchValue();
+ }
+
+ value(const value& v) {
+ debug_inc(countValues);
+ debug_inc(countCValues);
+ type = v.type;
+ switch(type) {
+ case value::List:
+ lst() = v.lst();
+ case value::Lambda:
+ func() = v.func();
+ case value::Symbol:
+ str() = v.str();
+ case value::String:
+ str() = v.str();
+ case value::Number:
+ num() = v.num();
+ case value::Bool:
+ boo() = v.boo();
+ case value::Ptr:
+ ptr() = v.ptr();
+ default:
+ break;
+ }
+#ifdef WANT_MAINTAINER_WATCH
+ watch = v.watch;
+#endif
+ }
+
+ virtual ~value() {
+ debug_dec(countValues);
+ }
+
+ value(const lambda<value(const list<value>&)>& func) : type(value::Lambda), data(vdata(func)) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const string& str) : type(value::String), data(vdata(result(str))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const char* str) : type(value::Symbol), data(vdata(result(string(str)))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const list<value>& lst) : type(value::List), data(vdata(result(lst))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const list<list<value> >& l) : type(value::List), data(vdata(result(listOfValues(l)))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const double num) : type(value::Number), data(vdata(result(num))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const int num) : type(value::Number), data(vdata(result((double)num))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const bool boo) : type(value::Bool), data(vdata(result(boo))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const gc_ptr<value> ptr) : type(value::Ptr), data(vdata(result(ptr))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const failable<value>& m) : type(value::List),
+ data(vdata(result(hasContent(m)? mklist<value>(content(m)) : rcode(m) == 1? mklist<value>(value(), reason(m)) : mklist<value>(value(), reason(m), rcode(m))))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const maybe<value>& m) : type(value::List),
+ data(vdata(result(hasContent(m)? mklist<value>(content(m)) : list<value>()))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ const value& operator=(const value& v) {
+ if(this == &v)
+ return *this;
+ type = v.type;
+ switch(type) {
+ case value::List:
+ lst() = v.lst();
+ case value::Lambda:
+ func() = v.func();
+ case value::Symbol:
+ str() = v.str();
+ case value::String:
+ str() = v.str();
+ case value::Number:
+ num() = v.num();
+ case value::Bool:
+ boo() = v.boo();
+ case value::Ptr:
+ ptr() = v.ptr();
+ default:
+ break;
+ }
+#ifdef WANT_MAINTAINER_WATCH
+ watch = v.watch;
+#endif
+ return *this;
+ }
+
+ const bool operator!=(const value& v) const {
+ return !this->operator==(v);
+ }
+
+ const bool operator==(const value& v) const {
+ if(this == &v)
+ return true;
+ switch(type) {
+ case value::Nil:
+ return v.type == value::Nil;
+ case value::List:
+ return v.type == value::List && lst()() == v.lst()();
+ case value::Lambda:
+ return v.type == value::Lambda && func() == v.func();
+ case value::Symbol:
+ case value::String:
+ return str()() == (string)v;
+ case value::Number:
+ return num()() == (double)v;
+ case value::Bool:
+ return boo()() == (bool)v;
+ case value::Ptr:
+ return v.type == value::Ptr && ptr()() == v.ptr()();
+ default:
+ return false;
+ }
+ }
+
+ const bool operator<(const value& v) const {
+ if(this == &v)
+ return false;
+ switch(type) {
+ case value::List:
+ return v.type == value::List && lst()() < v.lst()();
+ case value::Symbol:
+ case value::String:
+ return str()() < (string)v;
+ case value::Bool:
+ return boo()() < (bool)v;
+ case value::Number:
+ return num()() < (double)v;
+ default:
+ return false;
+ }
+ }
+
+ const bool operator>(const value& v) const {
+ if(this == &v)
+ return false;
+ switch(type) {
+ case value::List:
+ return v.type == value::List && lst()() > v.lst()();
+ case value::Symbol:
+ case value::String:
+ return str()() > (string)v;
+ case value::Bool:
+ return boo()() > (bool)v;
+ case value::Number:
+ return num()() > (double)v;
+ default:
+ return false;
+ }
+ }
+
+ const value operator()(const list<value>& args) const {
+ return func()(args);
+ }
+
+ operator const string() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return str()();
+ case value::Number: {
+ ostringstream os;
+ os << num()();
+ return tuscany::str(os);
+ }
+ case value::Bool:
+ return boo()()? trueString : falseString;
+ default:
+ return emptyString;
+ }
+ }
+
+ operator const double() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return atof(c_str(str()()));
+ case value::Number:
+ return (double)num()();
+ case value::Bool:
+ return boo()()? 1.0 : 0.0;
+ default:
+ return 0.0;
+ }
+ }
+
+ operator const int() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return atoi(c_str(str()()));
+ case value::Number:
+ return (int)num()();
+ case value::Bool:
+ return boo()()? 1 : 0;
+ default:
+ return 0;
+ }
+ }
+
+ operator const bool() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return str()() == string("true");
+ case value::Number:
+ return (int)num()() != 0;
+ case value::Bool:
+ return boo()();
+ default:
+ return 0;
+ }
+ }
+
+ operator const gc_ptr<value>() const {
+ return ptr()();
+ }
+
+ operator const list<value>() const {
+ return lst()();
+ }
+
+ operator const list<list<value> >() const {
+ return listOfListOfValues(lst()());
+ }
+
+ operator const lambda<value(const list<value>&)>() const {
+ return func();
+ }
+
+private:
+ template<typename T> lambda<T>& vdata() const {
+ return *reinterpret_cast<lambda<T> *> (const_cast<lambda<char()> *> (&data));
+ }
+
+ template<typename T> const lambda<char()>& vdata(const T& v) const {
+ return *reinterpret_cast<const lambda<char()> *> (&v);
+ }
+
+ lambda<double()>& num() const {
+ return vdata<double()> ();
+ }
+
+ lambda<bool()>& boo() const {
+ return vdata<bool()> ();
+ }
+
+ lambda<gc_ptr<value>()>& ptr() const {
+ return vdata<gc_ptr<value>()> ();
+ }
+
+ lambda<string()>& str() const {
+ return vdata<string()> ();
+ }
+
+ lambda<list<value>()>& lst() const {
+ return vdata<list<value>()> ();
+ }
+
+ lambda<value(const list<value>&)>& func() const {
+ return vdata<value(const list<value>&)> ();
+ }
+
+ const list<value> listOfValues(const list<list<value> >& l) const {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(car(l), listOfValues(cdr(l)));
+ }
+
+ const list<list<value> > listOfListOfValues(const list<value>& l) const {
+ if (isNil(l))
+ return list<list<value> >();
+ return cons<list<value> >(list<value>(car(l)), listOfListOfValues(cdr(l)));
+ }
+
+ friend ostream& operator<<(ostream&, const value&);
+ friend const value::ValueType type(const value& v);
+
+#ifdef WANT_MAINTAINER_WATCH
+ friend const string watchValue(const value& v);
+ string watch;
+#endif
+
+ ValueType type;
+ lambda<char()> data;
+};
+
+#ifdef WANT_MAINTAINER_WATCH
+
+/**
+ * Debug utility used to write the contents of a value to a string, easier
+ * to watch than the value itself in a debugger.
+ */
+const string watchValue(const value& v) {
+ if (v.type == value::List)
+ return watchList<value>(v);
+ odebugstream os;
+ os << v;
+ return str(os);
+}
+
+#endif
+
+/**
+ * Write an escape string to a buffer.
+ */
+const char* escapestr(const char* s, char* buf) {
+ if (*s == '\0') {
+ *buf = '\0';
+ return buf;
+ }
+ if (*s == '\\' || *s == '"') {
+ *buf = '\\';
+ *(buf + 1) = *s;
+ return escapestr(s + 1, buf + 2);
+ }
+ *buf = *s;
+ return escapestr(s + 1, buf + 1);
+}
+
+/**
+ * Write an escaped string value to a stream.
+ */
+ostream& escvwrite(const string& str, ostream& out) {
+ char* buf = gc_cnew(length(str) * 2 + 1);
+ escapestr(c_str(str), buf);
+ out << buf;
+ return out;
+}
+
+/**
+ * Write a value to a stream.
+ */
+ostream& operator<<(ostream& out, const value& v) {
+ switch(v.type) {
+ case value::List:
+ return out << v.lst()();
+ case value::Lambda:
+ return out << "lambda::" << v.func();
+ case value::Symbol:
+ return out << v.str()();
+ case value::String:
+ out << '\"';
+ escvwrite(v.str()(), out);
+ return out << '\"';
+ case value::Number:
+ return out << v.num()();
+ case value::Bool:
+ if(v.boo()())
+ return out << "true";
+ else
+ return out << "false";
+ case value::Ptr: {
+ const gc_ptr<value> p = v.ptr()();
+ if (p == gc_ptr<value>(NULL))
+ return out << "gc_ptr::null";
+ return out << "gc_ptr::" << p;
+ }
+ default:
+ return out << "nil";
+ }
+}
+
+/**
+ * Returns the type of a value.
+ */
+const value::ValueType type(const value& v) {
+ return v.type;
+}
+
+/**
+ * Returns true if a value is nil.
+ */
+const bool isNil(const value& v) {
+ return type(v) == value::Nil;
+}
+
+/**
+ * Returns true if a value is a lambda.
+ */
+const bool isLambda(const value& v) {
+ return type(v) == value::Lambda;
+}
+
+/**
+ * Returns true if a value is a string.
+ */
+const bool isString(const value& v) {
+ return type(v) == value::String;
+}
+
+/**
+ * Returns true if a value is a symbol.
+ */
+const bool isSymbol(const value& v) {
+ return type(v) == value::Symbol;
+}
+
+/**
+ * Returns true if a value is a list.
+ */
+const bool isList(const value& v) {
+ return type(v) == value::List;
+}
+
+/**
+ * Returns true if a value is a number.
+ */
+const bool isNumber(const value& v) {
+ return type(v) == value::Number;
+}
+
+/**
+ * Returns true if a value is a boolean.
+ */
+const bool isBool(const value& v) {
+ return type(v) == value::Bool;
+}
+
+/**
+ * Returns true if a value is a pointer.
+ */
+const bool isPtr(const value& v) {
+ return type(v) == value::Ptr;
+}
+
+/**
+ * Returns true if a value is a tagged list.
+ */
+const bool isTaggedList(const value& exp, value tag) {
+ if(isList(exp) && !isNil((list<value>)exp))
+ return car((list<value>)exp) == tag;
+ return false;
+}
+
+/**
+ * Make a list of values from a list of other things.
+ */
+template<typename T> const list<value> mkvalues(const list<T>& l) {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(car(l), mkvalues(cdr(l)));
+}
+
+/**
+ * Convert a list of values to a list of other things.
+ */
+template<typename T> const list<T> convertValues(const list<value>& l) {
+ if (isNil(l))
+ return list<T>();
+ return cons<T>(car(l), convertValues<T>(cdr(l)));
+}
+
+/**
+ * Convert a path string value to a list of values.
+ */
+const list<string> pathTokens(const char* p) {
+ if (p == NULL || p[0] == '\0')
+ return list<string>();
+ if (p[0] == '/')
+ return tokenize("/", p + 1);
+ return tokenize("/", p);
+}
+
+const list<value> pathValues(const value& p) {
+ return mkvalues(pathTokens(c_str(p)));
+}
+
+/**
+ * Convert a path represented as a list of values to a string value.
+ */
+const value path(const list<value>& p) {
+ if (isNil(p))
+ return "";
+ return string("/") + car(p) + path(cdr(p));
+}
+
+/**
+ * Make a uuid value.
+ */
+const value mkuuid() {
+ apr_uuid_t id;
+ apr_uuid_get(&id);
+ char buf[APR_UUID_FORMATTED_LENGTH];
+ apr_uuid_format(buf, &id);
+ return value(string(buf, APR_UUID_FORMATTED_LENGTH));
+}
+
+/**
+ * Make a random alphanumeric value.
+ */
+const int intrand() {
+ const apr_uint64_t now = apr_time_now();
+ srand((unsigned int)(((now >> 32) ^ now) & 0xffffffff));
+ return rand() & 0x0FFFF;
+}
+
+const value mkrand() {
+ char buf[32];
+ const char* an = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ for (int i =0; i < 32; i++)
+ buf[i] = an[intrand() % 62];
+ return value(string(buf, 32));
+}
+
+}
+#endif /* tuscany_value_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp
new file mode 100644
index 0000000000..0523cc74a6
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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$ */
+
+/**
+ * Test XML handling functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+
+const string currencyXML =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<composite xmlns=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" targetNamespace=\"http://services\" name=\"currency\">\n"
+" <component name=\"CurrencyConverterWebService\">\n"
+" <implementation.java class=\"services.CurrencyConverterImpl\"/>\n"
+" <service name=\"CurrencyConverter\">\n"
+" <binding.ws/>\n"
+" </service>\n"
+" </component>\n"
+" <component name=\"CurrencyConverterWebService2\">\n"
+" <implementation.java class=\"services.CurrencyConverterImpl2\"/>\n"
+" <service name=\"CurrencyConverter2\">\n"
+" <binding.atom/>\n"
+" </service>\n"
+" <property name=\"currency\">US</property>\n"
+" </component>\n"
+"</composite>\n";
+
+const string customerXML =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<customer>\n"
+" <name>jdoe</name>\n"
+" <address>\n"
+" <city>san francisco</city>\n"
+" <state>ca</state>\n"
+" </address>\n"
+" <account>\n"
+" <id>1234</id>\n"
+" <balance>1000</balance>\n"
+" </account>\n"
+" <account>\n"
+" <id>6789</id>\n"
+" <balance>2000</balance>\n"
+" </account>\n"
+" <account>\n"
+" <id>4567</id>\n"
+" <balance>3000</balance>\n"
+" </account>\n"
+"</customer>\n";
+
+const string abcXML =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<a>\n"
+" <m>abc</m>\n"
+" <m>def</m>\n"
+" <m>xyz</m>\n"
+" <m>tuv</m>\n"
+"</a>\n";
+
+const string xyzXML =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<a>\n"
+" <m>\n"
+" <id>123</id>\n"
+" <name>abc</name>\n"
+" </m>\n"
+" <m>\n"
+" <id>234</id>\n"
+" <name>def</name>\n"
+" </m>\n"
+" <m>\n"
+" <id>345</id>\n"
+" <name>xyz</name>\n"
+" </m>\n"
+" <m>\n"
+" <id>456</id>\n"
+" <name>tuv</name>\n"
+" </m>\n"
+"</a>\n";
+
+const bool isName(const value& token) {
+ return isTaggedList(token, attribute) && attributeName(token) == "name";
+}
+
+bool testReadXML() {
+ {
+ istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ }
+ {
+ istringstream is(currencyXML);
+ const list<value> c = readXML(streamList(is));
+
+ const value composite = car(c);
+ assert(isTaggedList(composite, element));
+ assert(elementName(composite) == "composite");
+ assert(attributeValue(car(filter<value>(isName, elementChildren(composite)))) == string("currency"));
+ }
+ return true;
+}
+
+ostream* xmlWriter(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+bool testWriteXML() {
+ {
+ istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, c);
+ assert(str(os) == customerXML);
+ }
+ {
+ istringstream is(currencyXML);
+ const list<value> c = readXML(streamList(is));
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, c);
+ assert(str(os) == currencyXML);
+ }
+ return true;
+}
+
+bool testElements() {
+ {
+ const list<value> ad = mklist<value>(mklist<value>("city", string("san francisco")), mklist<value>("state", string("ca")));
+ const list<value> ac1 = mklist<value>(mklist<value>("id", string("1234")), mklist<value>("balance", 1000));
+ const list<value> ac2 = mklist<value>(mklist<value>("id", string("6789")), mklist<value>("balance", 2000));
+ const list<value> ac3 = mklist<value>(mklist<value>("id", string("4567")), mklist<value>("balance", 3000));
+ {
+ const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", string("jdoe")), cons<value>("address", ad), mklist<value>("account", mklist<value>(ac1, ac2, ac3))));
+ const list<value> e = valuesToElements(c);
+ const list<value> v = elementsToValues(e);
+ assert(v == c);
+
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == customerXML);
+ }
+ {
+ const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", string("jdoe")), cons<value>("address", ad), cons<value>("account", ac1), cons<value>("account", ac2), cons<value>("account", ac3)));
+ const list<value> e = valuesToElements(c);
+ const list<value> v = elementsToValues(e);
+
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == customerXML);
+ }
+ }
+ {
+ istringstream is(abcXML);
+ const list<value> c = readXML(streamList(is));
+ const list<value> v = elementsToValues(c);
+ const list<value> e = valuesToElements(v);
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == abcXML);
+ }
+ {
+ istringstream is(xyzXML);
+ const list<value> c = readXML(streamList(is));
+ const list<value> v = elementsToValues(c);
+ const list<value> e = valuesToElements(v);
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == xyzXML);
+ }
+ {
+ istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ const list<value> v = elementsToValues(c);
+ const list<value> e = valuesToElements(v);
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == customerXML);
+ }
+ return true;
+}
+
+bool testValues() {
+ {
+ const list<value> l = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
+ const list<value> e = valuesToElements(l);
+ const failable<list<string> > lx = writeXML(e);
+ ostringstream os;
+ write(content(lx), os);
+ istringstream is(str(os));
+ const list<value> x = readXML(streamList(is));
+ const list<value> v = elementsToValues(x);
+ assert(v == l);
+ }
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::gc_scoped_pool p;
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testReadXML();
+ tuscany::testWriteXML();
+ tuscany::testElements();
+ tuscany::testValues();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/branches/lightweight-sca/kernel/xml.hpp b/sca-cpp/branches/lightweight-sca/kernel/xml.hpp
new file mode 100644
index 0000000000..d00a2905fb
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/xml.hpp
@@ -0,0 +1,412 @@
+/*
+ * 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_xml_hpp
+#define tuscany_xml_hpp
+
+/**
+ * XML read/write functions.
+ */
+
+#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/xmlschemas.h>
+#include <libxml/globals.h>
+#include "string.hpp"
+#include "list.hpp"
+#include "stream.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+
+/**
+ * APR-based memory management functions.
+ */
+
+
+/**
+ * Initializes the libxml2 library.
+ */
+class XMLParser {
+public:
+ XMLParser() {
+ debug("xml::XMLParser");
+ xmlMemSetup(gc_pool_free, gc_pool_malloc, gc_pool_realloc, gc_pool_strdup);
+ xmlInitParser();
+ }
+
+ ~XMLParser() {
+ }
+} xmlParser;
+
+/**
+ * Encapsulates a libxml2 xmlTextReader and its state.
+ */
+class XMLReader {
+public:
+ enum TokenType {
+ None = 0, Element = 1, Attribute = 2, Text = 3, EndElement = 15, Identifier = 100, End = 101
+ };
+
+ XMLReader(xmlTextReaderPtr xml) : xml(xml), owner(true), tokenType(None), isEmptyElement(false), hasValue(false), hasAttributes(false) {
+ debug("xml::XMLReader::xml");
+ xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1);
+ xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1);
+ }
+
+ XMLReader(const XMLReader& r) : xml(r.xml), owner(false), tokenType(r.tokenType), isEmptyElement(r.isEmptyElement), hasValue(r.hasValue), hasAttributes(r.hasAttributes) {
+ debug("xml::XMLReader::copy");
+ }
+
+ const XMLReader& operator=(const XMLReader& r) {
+ debug("xml::XMLReader::operator=");
+ if(this == &r)
+ return *this;
+ xml = r.xml;
+ owner = false;
+ tokenType = r.tokenType;
+ isEmptyElement = r.isEmptyElement;
+ hasValue = r.hasValue;
+ hasAttributes = r.hasAttributes;
+ return *this;
+ }
+
+ ~XMLReader() {
+ if (!owner)
+ return;
+ xmlTextReaderClose(xml);
+ xmlFreeTextReader(xml);
+ }
+
+ /**
+ * Read the next XML token and return its type.
+ */
+ int read() {
+ if (tokenType == End)
+ return tokenType;
+ if (tokenType == Element) {
+ isEmptyElement = xmlTextReaderIsEmptyElement(xml);
+ hasAttributes = xmlTextReaderHasAttributes(xml);
+ return tokenType = Identifier;
+ }
+ if (tokenType == Identifier && hasAttributes && xmlTextReaderMoveToFirstAttribute(xml) == 1)
+ return tokenType = Attribute;
+ if (tokenType == Attribute && xmlTextReaderMoveToNextAttribute(xml) == 1)
+ return tokenType = Attribute;
+ if (isEmptyElement && (tokenType == Identifier || tokenType == Attribute))
+ return tokenType = EndElement;
+ if (!xmlTextReaderRead(xml))
+ return tokenType = End;
+ return tokenType = xmlTextReaderNodeType(xml);
+ }
+
+ operator xmlTextReaderPtr() const {
+ return xml;
+ }
+
+private:
+ xmlTextReaderPtr xml;
+ bool owner;
+ int tokenType;
+ bool isEmptyElement;
+ bool hasValue;
+ bool hasAttributes;
+};
+
+/**
+ * Constants used to tag XML tokens.
+ */
+const value endElement("<");
+const value startElement(">");
+
+/**
+ * Read an XML identifier.
+ */
+const value readIdentifier(XMLReader& reader) {
+ const char* name = (const char*)xmlTextReaderConstName(reader);
+ return name;
+}
+
+/**
+ * Read XML text.
+ */
+const value readText(XMLReader& reader) {
+ const char *val = (const char*)xmlTextReaderConstValue(reader);
+ return string(val);
+}
+
+/**
+ * Read an XML attribute.
+ */
+const value readAttribute(XMLReader& reader) {
+ const char *name = (const char*)xmlTextReaderConstName(reader);
+ const char *val = (const char*)xmlTextReaderConstValue(reader);
+ return mklist<value>(attribute, name, string(val));
+}
+
+/**
+ * Read an XML token.
+ */
+const value readToken(XMLReader& reader) {
+ const int tokenType = reader.read();
+ if (tokenType == XMLReader::None || tokenType == XMLReader::End)
+ return value();
+ if (tokenType == XMLReader::Element)
+ return startElement;
+ if (tokenType == XMLReader::Identifier)
+ return readIdentifier(reader);
+ if (tokenType == XMLReader::Attribute)
+ return readAttribute(reader);
+ if (tokenType == XMLReader::Text)
+ return readText(reader);
+ if (tokenType == XMLReader::EndElement)
+ return endElement;
+ return readToken(reader);
+}
+
+/**
+ * Read a list of values from XML tokens.
+ */
+const list<value> readList(const list<value>& listSoFar, XMLReader& reader) {
+ const value token = readToken(reader);
+ if(isNil(token) || endElement == token)
+ return reverse(listSoFar);
+ if(startElement == token)
+ return readList(cons<value>(readList(mklist(element), reader), listSoFar), reader);
+ return readList(cons(token, listSoFar), reader);
+}
+
+/**
+ * Read a list of values from a libxml2 XML reader.
+ */
+const list<value> read(XMLReader& reader) {
+ value nextToken = readToken(reader);
+ if (startElement == nextToken)
+ return mklist<value>(readList(mklist(element), reader));
+ return list<value>();
+}
+
+/**
+ * Context passed to the read callback function.
+ */
+class XMLReadContext {
+public:
+ XMLReadContext(const list<string>& ilist) : ilist(ilist) {
+ }
+ list<string> ilist;
+};
+
+/**
+ * Callback function called by libxml2 to read XML.
+ */
+int readCallback(void *context, char* buffer, int len) {
+ XMLReadContext& rc = *static_cast<XMLReadContext*>(context);
+ if (isNil(rc.ilist))
+ return 0;
+ const list<string> f(fragment(rc.ilist, len));
+ const string s(car(f));
+ rc.ilist = cdr(f);
+ memcpy(buffer, c_str(s), length(s));
+ return (int)length(s);
+}
+
+/**
+ * Return true if a list of strings contains an XML document.
+ */
+const bool isXML(const list<string>& ls) {
+ if (isNil(ls))
+ return false;
+ return substr(car(ls), 0, 5) == "<?xml";
+}
+
+/**
+ * Read a list of values from a list of strings representing an XML document.
+ */
+const list<value> readXML(const list<string>& ilist) {
+ debug(ilist, "xml::readXML");
+ XMLReadContext cx(ilist);
+ xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET | XML_PARSE_NODICT);
+ if (xml == NULL)
+ return list<value>();
+ XMLReader reader(xml);
+ return read(reader);
+}
+
+/**
+ * Default encoding used to write XML documents.
+ */
+const char* encoding = "UTF-8";
+
+
+/**
+ * Write a list of XML element or attribute tokens.
+ */
+const list<value> expandElementValues(const value& n, const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(value(cons<value>(element, cons<value>(n, isList(car(l))? (list<value>)car(l) : mklist(car(l))))), expandElementValues(n, cdr(l)));
+}
+
+const failable<bool> writeList(const list<value>& l, const xmlTextWriterPtr xml) {
+ if (isNil(l))
+ return true;
+
+ // Write an attribute
+ const value token(car(l));
+ if (isTaggedList(token, attribute)) {
+ if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)c_str(string(attributeName(token))), (const xmlChar*)c_str(string(attributeValue(token)))) < 0)
+ return mkfailure<bool>("xmlTextWriterWriteAttribute failed");
+
+ } else if (isTaggedList(token, element)) {
+
+ // Write an element containing a value
+ if (elementHasValue(token)) {
+ const value v = elementValue(token);
+ if (isList(v)) {
+
+ // Write an element per entry in a list of values
+ const list<value> e = expandElementValues(elementName(token), v);
+ writeList(e, xml);
+
+ } else {
+
+ // Write an element with a single value
+ if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0)
+ return mkfailure<bool>("xmlTextWriterStartElement failed");
+
+ // Write its children
+ const failable<bool> w = writeList(elementChildren(token), xml);
+ if (!hasContent(w))
+ return w;
+
+ if (xmlTextWriterEndElement(xml) < 0)
+ return mkfailure<bool>("xmlTextWriterEndElement failed");
+ }
+ }
+ else {
+
+ // Write an element
+ if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0)
+ return mkfailure<bool>("xmlTextWriterStartElement failed");
+
+ // Write its children
+ const failable<bool> w = writeList(elementChildren(token), xml);
+ if (!hasContent(w))
+ return w;
+
+ if (xmlTextWriterEndElement(xml) < 0)
+ return mkfailure<bool>("xmlTextWriterEndElement failed");
+ }
+ } else {
+
+ // Write XML text
+ if (xmlTextWriterWriteString(xml, (const xmlChar*)c_str(string(token))) < 0)
+ return mkfailure<bool>("xmlTextWriterWriteString failed");
+ }
+
+ // Go on
+ return writeList(cdr(l), xml);
+}
+
+/**
+ * Write a list of values to a libxml2 XML writer.
+ */
+const failable<bool> write(const list<value>& l, const xmlTextWriterPtr xml, bool xmlTag) {
+ if (xmlTag) {
+ if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0)
+ return mkfailure<bool>("xmlTextWriterStartDocument failed");
+ }
+
+ const failable<bool> w = writeList(l, xml);
+ if (!hasContent(w))
+ return w;
+
+ if (xmlTag) {
+ if (xmlTextWriterEndDocument(xml) < 0)
+ return mkfailure<bool>("xmlTextWriterEndDocument failed");
+ }
+ return true;
+}
+
+/**
+ * Context passed to the write callback function.
+ */
+template<typename R> class XMLWriteContext {
+public:
+ XMLWriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
+ }
+ const lambda<R(const string&, const R)> reduce;
+ R accum;
+};
+
+/**
+ * Callback function called by libxml2 to write XML out.
+ */
+template<typename R> int writeCallback(void *context, const char* buffer, int len) {
+ XMLWriteContext<R>& cx = *static_cast<XMLWriteContext<R>*>(context);
+ cx.accum = cx.reduce(string(buffer, len), cx.accum);
+ return len;
+}
+
+/**
+ * Convert a list of values to an XML document.
+ */
+template<typename R> const failable<R> writeXML(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const bool xmlTag) {
+ XMLWriteContext<R> cx(reduce, initial);
+ xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback<R>, NULL, &cx, NULL);
+ if (out == NULL)
+ return mkfailure<R>("xmlOutputBufferCreateIO failed");
+ xmlTextWriterPtr xml = xmlNewTextWriter(out);
+ if (xml == NULL)
+ return mkfailure<R>("xmlNewTextWriter failed");
+ xmlTextWriterSetIndent(xml, 1);
+
+ const failable<bool> w = write(l, xml, xmlTag);
+ xmlFreeTextWriter(xml);
+ if (!hasContent(w)) {
+ return mkfailure<R>(w);
+ }
+ return cx.accum;
+}
+
+template<typename R> const failable<R> writeXML(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML(reduce, initial, l, true);
+}
+
+/**
+ * Convert a list of values to a list of strings representing an XML document.
+ */
+const failable<list<string> > writeXML(const list<value>& l, const bool xmlTag) {
+ debug(l, "xml::writeXML");
+ const failable<list<string> > ls = writeXML<list<string> >(rcons<string>, list<string>(), l, xmlTag);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+const failable<list<string> > writeXML(const list<value>& l) {
+ return writeXML(l, true);
+}
+
+}
+#endif /* tuscany_xml_hpp */
diff --git a/sca-cpp/branches/lightweight-sca/kernel/xsd-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/xsd-test.cpp
new file mode 100644
index 0000000000..fbd2ee6dca
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/xsd-test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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$ */
+
+/**
+ * Test validation of a composite file against an SCDL schema.
+ */
+
+#include "string.hpp"
+#include "fstream.hpp"
+#include <libxml/xmlreader.h>
+#include <libxml/xmlschemas.h>
+
+namespace tuscany {
+
+bool printNode(xmlTextReaderPtr reader) {
+ const xmlChar* name = xmlTextReaderConstName(reader);
+ if(name == NULL)
+ name = (xmlChar *)"<unknown>";
+ const xmlChar* value = xmlTextReaderConstValue(reader);
+ cerr << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " "
+ << xmlTextReaderIsEmptyElement(reader) << " " << xmlTextReaderHasValue(reader);
+ if(value == NULL)
+ cerr << endl;
+ else
+ cerr << value << endl;
+ return true;
+}
+
+int xmlRead(void *context, char* buffer, int len) {
+ return (int)fread(buffer, 1, len, (FILE*)context);
+}
+
+int xmlClose(void *context) {
+ fclose((FILE*)context);
+ return 0;
+}
+
+bool readFile(const char*xsdfilename, const char *filename) {
+ cout << "Loading schema " << xsdfilename << endl;
+ const xmlDocPtr xsddoc = xmlReadFile(xsdfilename, NULL, XML_PARSE_NONET);
+ const xmlSchemaParserCtxtPtr xsdctx = xmlSchemaNewDocParserCtxt(xsddoc);
+ const xmlSchemaPtr xsd = xmlSchemaParse(xsdctx);
+ const xmlSchemaValidCtxtPtr validctx = xmlSchemaNewValidCtxt(xsd);
+
+ cout << "Reading file " << filename << endl;
+ FILE* file = fopen(filename, "r");
+ if (file != NULL) {
+ const xmlTextReaderPtr reader = xmlReaderForIO(xmlRead, xmlClose, file, filename, NULL, XML_PARSE_NONET);
+ xmlTextReaderSetParserProp(reader, XML_PARSER_DEFAULTATTRS, 1);
+ xmlTextReaderSetParserProp(reader, XML_PARSER_SUBST_ENTITIES, 1);
+
+ if(reader != NULL) {
+ xmlTextReaderSchemaValidateCtxt(reader, validctx, 0);
+
+ int rc;
+ while((rc = xmlTextReaderRead(reader)) == 1) {
+ printNode(reader);
+ }
+ if(xmlTextReaderIsValid(reader) != 1)
+ cout << "Could not validate document" << endl;
+ xmlFreeTextReader(reader);
+ if(rc != 0)
+ cout << "Could not parse document" << endl;
+ } else
+ cout << "Could not create parser" << endl;
+ } else
+ cout << "Could not open document" << endl;
+
+ xmlSchemaFreeValidCtxt(validctx);
+ xmlSchemaFree(xsd);
+ xmlSchemaFreeParserCtxt(xsdctx);
+
+ return true;
+}
+
+}
+
+int main(int argc, char **argv) {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ if(argc != 3)
+ return 1;
+
+ tuscany::readFile(argv[1], argv[2]);
+
+ xmlCleanupParser();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}