From e982b4ef38fd043c15e89bdd60763b10434a087e Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sun, 28 Feb 2010 19:40:06 +0000 Subject: Moving old inactive code to a branch as it's confusing code assist, searches and indexing in trunk. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@917273 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/branches/cpp-contrib/kernel/Makefile.am | 42 ++ sca-cpp/branches/cpp-contrib/kernel/config.hpp | 76 +++ .../branches/cpp-contrib/kernel/dynlib-test.cpp | 48 ++ sca-cpp/branches/cpp-contrib/kernel/dynlib.hpp | 91 ++++ sca-cpp/branches/cpp-contrib/kernel/element.hpp | 304 +++++++++++ sca-cpp/branches/cpp-contrib/kernel/fstream.hpp | 162 ++++++ sca-cpp/branches/cpp-contrib/kernel/function.hpp | 238 +++++++++ sca-cpp/branches/cpp-contrib/kernel/gc.hpp | 276 ++++++++++ .../branches/cpp-contrib/kernel/kernel-test.cpp | 594 +++++++++++++++++++++ sca-cpp/branches/cpp-contrib/kernel/list.hpp | 559 +++++++++++++++++++ sca-cpp/branches/cpp-contrib/kernel/mem-test.cpp | 162 ++++++ sca-cpp/branches/cpp-contrib/kernel/monad.hpp | 486 +++++++++++++++++ .../branches/cpp-contrib/kernel/parallel-test.cpp | 166 ++++++ sca-cpp/branches/cpp-contrib/kernel/parallel.hpp | 319 +++++++++++ sca-cpp/branches/cpp-contrib/kernel/perf.hpp | 68 +++ sca-cpp/branches/cpp-contrib/kernel/sstream.hpp | 240 +++++++++ sca-cpp/branches/cpp-contrib/kernel/stream.hpp | 200 +++++++ .../branches/cpp-contrib/kernel/string-test.cpp | 196 +++++++ sca-cpp/branches/cpp-contrib/kernel/string.hpp | 291 ++++++++++ sca-cpp/branches/cpp-contrib/kernel/tree.hpp | 125 +++++ sca-cpp/branches/cpp-contrib/kernel/value.hpp | 593 ++++++++++++++++++++ sca-cpp/branches/cpp-contrib/kernel/xml-test.cpp | 180 +++++++ sca-cpp/branches/cpp-contrib/kernel/xml.hpp | 369 +++++++++++++ sca-cpp/branches/cpp-contrib/kernel/xsd-test.cpp | 107 ++++ 24 files changed, 5892 insertions(+) create mode 100644 sca-cpp/branches/cpp-contrib/kernel/Makefile.am create mode 100644 sca-cpp/branches/cpp-contrib/kernel/config.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/dynlib-test.cpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/dynlib.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/element.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/fstream.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/function.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/gc.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/kernel-test.cpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/list.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/mem-test.cpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/monad.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/parallel-test.cpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/parallel.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/perf.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/sstream.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/stream.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/string-test.cpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/string.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/tree.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/value.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/xml-test.cpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/xml.hpp create mode 100644 sca-cpp/branches/cpp-contrib/kernel/xsd-test.cpp (limited to 'sca-cpp/branches/cpp-contrib/kernel') diff --git a/sca-cpp/branches/cpp-contrib/kernel/Makefile.am b/sca-cpp/branches/cpp-contrib/kernel/Makefile.am new file mode 100644 index 0000000000..cfacbb3662 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/Makefile.am @@ -0,0 +1,42 @@ +# 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. + +noinst_PROGRAMS = string-test kernel-test mem-test parallel-test xml-test xsd-test + +testdir=$(prefix)/test +test_LTLIBRARIES = libdynlib-test.la + +includedir = $(prefix)/include/kernel +include_HEADERS = *.hpp + +string_test_SOURCES = string-test.cpp + +libdynlib_test_la_SOURCES = dynlib-test.cpp + +kernel_test_SOURCES = kernel-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 + +TESTS = string-test kernel-test mem-test parallel-test xml-test diff --git a/sca-cpp/branches/cpp-contrib/kernel/config.hpp b/sca-cpp/branches/cpp-contrib/kernel/config.hpp new file mode 100644 index 0000000000..195612428e --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/config.hpp @@ -0,0 +1,76 @@ +/* + * 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 +{ + +#ifdef WANT_MAINTAINER_MODE + +/** + * Add string watch members to important classes to help watch them in a debugger. + */ +#define WANT_MAINTAINER_WATCH + +/** + * Increment / decrement a debug counter. + */ +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 + +/** + * Attribute used to mark unused parameters. + */ +#ifndef unused +#define unused __attribute__ ((unused)) +#endif + +} +#endif /* tuscany_config_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/dynlib-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/dynlib-test.cpp new file mode 100644 index 0000000000..419fa29db5 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/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 csquarel() { + return tuscany::lambda(tuscany::test::cppsquare); + } + +} diff --git a/sca-cpp/branches/cpp-contrib/kernel/dynlib.hpp b/sca-cpp/branches/cpp-contrib/kernel/dynlib.hpp new file mode 100644 index 0000000000..9f55dc4a49 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/dynlib.hpp @@ -0,0 +1,91 @@ +/* + * 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 + +#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(string("Could not load library: ") + name + ": " + dlerror()); + } + + lib(const lib& l) : name(l.name), h(l.h), owner(false) { + } + + ~lib() { + if (!owner) + return; + if (!hasContent(h) || content(h) == NULL) + return; + dlclose(content(h)); + } + +private: + template friend const failable > dynlambda(const string& name, const lib& l); + + const string name; + failable h; + bool owner; +}; + +/** + * Find a lambda function in a dynamic library. + */ +template const failable > dynlambda(const string& name, const lib& l) { + if (!hasContent(l.h)) + return mkfailure >(reason(l.h)); + const void* s = dlsym(content(l.h), c_str(name)); + if (s == NULL) + return mkfailure >(string("Could not load symbol: ") + name); + return lambda((S*)s); +} + +} +#endif /* tuscany_dlib_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/element.hpp b/sca-cpp/branches/cpp-contrib/kernel/element.hpp new file mode 100644 index 0000000000..c6aa2c44eb --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/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(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(v)) + return false; + return true; +} + +/** + * Returns the name of an attribute. + */ +const value attributeName(const list& l) { + return cadr(l); +} + +/** + * Returns the value of an attribute. + */ +const value attributeValue(const list& l) { + return caddr(l); +} + +/** + * Returns the name of an element. + */ +const value elementName(const list& l) { + return cadr(l); +} + +/** + * Returns true if an element has children. + */ +const bool elementHasChildren(const list& l) { + return !isNil(cddr(l)); +} + +/** + * Returns the children of an element. + */ +const list elementChildren(const list& l) { + return cddr(l); +} + +/** + * Returns true if an element has a value. + */ +const value elementHasValue(const list& l) { + const list r = reverse(l); + if (isSymbol(car(r))) + return false; + if(isList(car(r)) && !isNil((list)car(r)) && isSymbol(car(car(r)))) + return false; + return true; +} + +/** + * Returns the value of an element. + */ +const value elementValue(const list& l) { + return car(reverse(l)); +} + +/** + * Convert an element to a value. + */ +const bool elementToValueIsList(const value& v) { + if (!isList(v)) + return false; + const list l = v; + return (isNil(l) || !isSymbol(car(l))); +} + +const value elementToValue(const value& t) { + const list elementsToValues(const list& e); + + // Convert an attribute + if (isTaggedList(t, attribute)) + return mklist(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(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 l = v; + if (isNil(l)) + return false; + if (!isSymbol(car(l))) + return false; + return true; +} + +const list elementToValueGroupValues(const value& v, const list& l) { + if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l))) + return cons(v, l); + if (car(car(l)) != car(v)) + return cons(v, l); + if (!elementToValueIsList(cadr(car(l)))) { + const value g = mklist(car(v), mklist(cdr(v), cdr(car(l)))); + return elementToValueGroupValues(g, cdr(l)); + } + const value g = mklist(car(v), cons(cdr(v), (list)cadr(car(l)))); + return elementToValueGroupValues(g, cdr(l)); + +} + +const list elementsToValues(const list& 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 valuesToElements(const list& l); + + // Convert a name value pair + if (isList(t) && !isNil((list)t) && isSymbol(car(t))) { + const value n = car(t); + const value v = cadr(t); + + // Convert a single value to an attribute or an element + if (!isList(v)) { + if (substr(n, 0, 1) == atsign) + return mklist(attribute, substr(n, 1), v); + return mklist(element, n, v); + } + + // Convert a list value + if (isNil((list)v) || !isSymbol(car(v))) + return cons(element, cons(n, mklist(valuesToElements(v)))); + + // Convert a nested name value pair value + return cons(element, cons(n, valuesToElements(cdr(t)))); + } + + // Convert a value + if (!isList(t)) + return t; + return valuesToElements(t); +} + +/** + * Convert a list of values to a list of elements. + */ +const list valuesToElements(const list& l) { + if (isNil(l)) + return l; + return cons(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 select; + selectorLambda(const list& s) : select(s) { + } + const bool evalSelect(const list& s, const list 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 selector(const list 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)v) == name; + } +}; + +const value attributeValue(const value& name, const value& l) { + const list f = filter(filterAttribute(name), list(l)); + if (isNil(f)) + return value(); + return caddr(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)v) == name; + } +}; + +const value elementChildren(const value& name, const value& l) { + return filter(filterElement(name), list(l)); +} + +/** + * Return the child element with the given name. + */ +const value elementChild(const value& name, const value& l) { + const list f = elementChildren(name, l); + if (isNil(f)) + return value(); + return car(f); +} + +} +#endif /* tuscany_element_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/fstream.hpp b/sca-cpp/branches/cpp-contrib/kernel/fstream.hpp new file mode 100644 index 0000000000..f5a9dcd981 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/fstream.hpp @@ -0,0 +1,162 @@ +/* + * 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 +#include +#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) { + } + + ~ofstream() { + if (!owner) + return; + if (file == NULL) + return; + fclose(file); + } + + 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) { + } + + ~ifstream() { + if (!owner) + return; + if (file == NULL) + return; + fclose(file); + } + + const int read(void* buf, int 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); + +/** + * Debug log stream. + */ +#ifdef WANT_MAINTAINER_MODE + +template const bool debug(const V& v, const string& msg) { + cerr << msg << ": " << v << endl; + return true; +} + +const bool debug(const string& msg) { + cerr << msg << endl; + return true; +} + +#else + +#define debug(...) + +#endif + +} + +#endif /* tuscany_fstream_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/function.hpp b/sca-cpp/branches/cpp-contrib/kernel/function.hpp new file mode 100644 index 0000000000..db7318303a --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/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 +#include "fstream.hpp" +#include "gc.hpp" +#include "config.hpp" + +namespace tuscany { + +#ifdef WANT_MAINTAINER_MODE + +/** + * 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 class Callable { +public: + Callable() { + } + + virtual const int size() const = 0; + + virtual const R operator()(P... p) const = 0; + + virtual ~Callable() { + } + + template 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)...); + } + + virtual const int size() const { + return sizeof(function); + } + + private: + const F function; + }; +}; + +template class lambda; + +template class lambda { +public: + lambda() : callable(0) { + debug_inc(countLambdas); + debug_inc(countELambdas); + } + + template lambda(const F f) { + debug_inc(countLambdas); + debug_inc(countFLambdas); + + typedef typename CallableType::template Proxy ProxyType; + callable = gc_ptr(new (gc_new()) 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)...); + } + + template friend ostream& operator<<(ostream&, const lambda&); + template friend const bool isNil(const lambda& l); + +private: + typedef Callable CallableType; + gc_ptr callable; +}; + +template ostream& operator<<(ostream& out, const lambda& l) { + return out << "lambda::" << l.callable; +} + +/** + * Return true if a lambda is nil. + */ +template const bool isNil(const lambda& l) { + return ((void*)l.callable) == 0; +} + +/** + * Curry a lambda function. + */ +template class curried { +public: + curried(const lambda& f, const T& v): v(v), f(f) { + } + + const R operator()(P... p) const { + return f(v, std::forward

(p)...); + } + +private: + const T v; + const lambdaf; +}; + +template const lambda curry(const lambda& f, const T& t) { + return curried(f, t); +} + +template const lambda curry(const lambda& f, const T& t, const U& u) { + return curry(curry(f, t), u); +} + +template const lambda curry(const lambda& 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 class returnResult { +public: + returnResult(const T& v) : + v(v) { + } + const T operator()() const { + return v; + } +private: + const T v; +}; + +template const lambda result(const T& v) { + return returnResult (v); +} + +} +#endif /* tuscany_function_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/gc.hpp b/sca-cpp/branches/cpp-contrib/kernel/gc.hpp new file mode 100644 index 0000000000..ca01fdf95f --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/gc.hpp @@ -0,0 +1,276 @@ +/* + * 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 +#include +#include +#include +#include +#include "config.hpp" + +namespace tuscany +{ + +/** + * Pointer to a value. + */ +template 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!=(const gc_ptr& r) const throw() { + return !this->operator==(r); + } + + T& operator*() const throw() { + return *ptr; + } + + T* operator->() const throw() { + return ptr; + } + + operator T*() const throw() { + return ptr; + } + + T* ptr; +}; + +/** + * 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_scoped_pool; + + apr_pool_t* apr_pool; +}; + +/** + * Return APR pool used by a gc_pool. + */ +apr_pool_t* pool(const gc_pool& pool) { + return pool.apr_pool; +} + +/** + * Destroy a memory pool. + */ +const bool destroy(const gc_pool& p) { + apr_pool_destroy(pool(p)); + return true; +} + +/** + * Initialize APR. + */ +class gc_apr_context_t { +public: + gc_apr_context_t() { + apr_initialize(); + } +} gc_apr_context; + +/** + * Maintain a stack of memory pools. + */ +#ifdef WANT_THREADS +__thread +#endif +apr_pool_t* gc_pool_stack = NULL; + +/** + * Return the current memory pool. + */ +apr_pool_t* gc_current_pool() { + apr_pool_t* apr_pool = gc_pool_stack; + if (apr_pool != NULL) + return apr_pool; + + // Create a parent pool for the current thread + apr_pool_create(&apr_pool, NULL); + assert(apr_pool != NULL); + gc_pool_stack = apr_pool; + return apr_pool; +} + +/** + * 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; +} + +/** + * A memory pool scope, used to setup a scope in which a particular pool + * will be used for all allocations. + */ +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, NULL); + assert(apr_pool != NULL); + gc_push_pool(apr_pool); + } + + gc_scoped_pool(apr_pool_t* pool) : gc_pool(pool), 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); + } + +private: + gc_scoped_pool(const unused gc_scoped_pool& pool) : gc_pool(pool.apr_pool), prev(NULL), owner(false) { + } + + 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 apr_status_t gc_pool_cleanup(void* v) { + T* t = static_cast(v); + t->~T(); + return APR_SUCCESS; +} + +template T* gc_new(apr_pool_t* p) { + void* gc_new_ptr = apr_palloc(p, sizeof(T)); + assert(gc_new_ptr != NULL); + apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup, apr_pool_cleanup_null) ; + return static_cast(gc_new_ptr); +} + +template T* gc_new(const gc_pool& p) { + return gc_new(pool(p)); +} + +template T* gc_new() { + return gc_new(gc_current_pool()); +} + +template apr_status_t gc_pool_acleanup(void* v) { + int* m = static_cast(v); + int n = *m; + T* t = (T*)(m + 1); + for (int i = 0; i < n; i++, t++) + t->~T(); + return APR_SUCCESS; +} + +template T* gc_anew(apr_pool_t* p, int n) { + int* gc_anew_ptr = static_cast(apr_palloc(p, sizeof(int) + sizeof(T[n]))); + assert(gc_anew_ptr != NULL); + *gc_anew_ptr = n; + apr_pool_cleanup_register(p, gc_anew_ptr, gc_pool_acleanup, apr_pool_cleanup_null) ; + return (T*)(gc_anew_ptr + 1); +} + +template T* gc_anew(const gc_pool& p, int n) { + return gc_anew(pool(p), n); +} + +template T* gc_anew(int n) { + return gc_anew(gc_current_pool(), n); +} + +/** + * Allocate an array of chars. + */ +char* gc_cnew(apr_pool_t* p, int n) { + char* gc_cnew_ptr = static_cast(apr_palloc(p, n)); + assert(gc_cnew_ptr != NULL); + return gc_cnew_ptr; +} + +char* gc_cnew(int n) { + return gc_cnew(gc_current_pool(), n); +} + +} + +#endif /* tuscany_gc_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/kernel-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/kernel-test.cpp new file mode 100644 index 0000000000..44ffe06b7b --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/kernel-test.cpp @@ -0,0 +1,594 @@ +/* + * 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 +#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 f, int v) { + return f(v); +} + +bool testLambda() { + const lambda sq(square); + assert(sq(2) == 4); + assert(mapLambda(sq, 2) == 4); + assert(mapLambda(square, 2) == 4); + + const lambda incf(inc(10)); + assert(incf(1) == 11); + assert(mapLambda(incf, 1) == 11); + assert(mapLambda(inc(10), 1) == 11); + + lambda 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 (); + assert(str(os1) == "()"); + + ostringstream os2; + os2 << mklist(1, 2, 3); + assert(str(os2) == "(1 2 3)"); + return true; +} + +bool testEquals() { + assert(list() == list()); + assert(mklist(1, 2) == mklist(1, 2)); + assert(list() != 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())); + 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() + 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 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(square, list()))); + + const list m = map(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 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(isPositive, mklist(1, -1, 2, -2))) == 1); + assert(cadr(filter(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()))); + 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 > l = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); + assert(assoc("a", l) == mklist("a", "A")); + assert(isNil(assoc("z", l))); + + const list > u = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); + assert(assoc("a", u) == mklist("a", "A")); + + const list v = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); + assert(assoc("a", v) == mklist("a", "A")); + return true; +} + +bool testZip() { + const list k = mklist("x", "a", "y", "a"); + const list v = mklist("X", "A", "Y", "AA"); + const list > z = mklist(k, v); + const list > u = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); + assert(zip(k, v) == u); + assert(unzip(u) == z); + return true; +} + +bool testTokenize() { + assert(tokenize("/", "aaa/bbb/ccc/ddd") == mklist("aaa", "bbb", "ccc", "ddd")); + assert(tokenize("/", "/bbb/ccc/ddd") == mklist("", "bbb", "ccc", "ddd")); + assert(tokenize("/", "/bbb/ccc/") == mklist("", "bbb", "ccc")); + assert(tokenize("/", "/bbb//ccc/") == mklist("", "bbb", "", "ccc")); + assert(tokenize("/", "abc/def/") == mklist("abc", "def")); + return true; +} + +double testSeqMap(double x) { + return x; +} + +double testSeqReduce(unused double v, double accum) { + return accum + 1.0; +} + +bool testSeq() { + resetLambdaCounters(); + resetListCounters(); + + list s = seq(0.0, 1000.0); + assert(1001 == length(s)); + + assert(1001 == length(map(testSeqMap, s))); + + assert(801 == length(member(200.0, s))); + assert(201 == length(member(200.0, reverse(s)))); + + assert(1001 == (reduce(testSeqReduce, 0.0, s))); + return true; +} + +value valueSquare(list 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&)> vl(valueSquare); + assert(value(vl) == value(vl)); + assert(value(mklist(1, 2)) == value(mklist(1, 2))); + + const list v = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y")); + assert(cadr((list >)value(v)) == mklist("a", "A")); + + const value pv(gc_ptr(new (gc_new()) value(1))); + assert(*(gc_ptr)pv == value(1)); + + const list lpv = mklist(gc_ptr(new (gc_new()) value(1)), gc_ptr(new (gc_new()) value(2))); + assert(*(gc_ptr)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 t = mktree("a", list(), list()); + const list ct = constree("d", constree("f", constree("c", constree("e", constree("b", t))))); + const list mt = mktree(mklist("d", "f", "c", "e", "b", "a")); + assert(mt == ct); + const list l = flatten(mt); + assert(length(l) == 6); + assert(car(l) == "a"); + assert(car(reverse(l)) == "f"); + const list bt = mkbtree(l); + assert(car(bt) == "c"); + return true; +} + +const list lta(const string& x) { + return mklist(c_str(x), c_str(x + x)); +} + +bool testTreeAssoc() { + const list t = mktree(lta("a"), list(), list()); + const list at = constree(lta("d"), constree(lta("f"), constree(lta("c"), constree(lta("e"), constree(lta("b"), t))))); + const list l = flatten(at); + assert(length(l) == 6); + assert(car(l) == mklist("a", "aa")); + assert(car(reverse(l)) == mklist("f", "ff")); + const list bt = mkbtree(l); + assert(car(bt) == mklist("c", "cc")); + assert(assoctree("a", bt) == mklist("a", "aa")); + assert(assoctree("b", bt) == mklist("b", "bb")); + assert(assoctree("f", bt) == mklist("f", "ff")); + assert(isNil(assoctree("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 s = seq(0.0, 999.0); + list r = map(fib, s); + assert(1000 == length(r)); + return true; + } +}; + +struct nestedFibMapPerf { + const lambda fib; + nestedFibMapPerf(const lambda& fib) : fib(fib) { + } + const bool operator()() const { + list s = seq(0.0, 999.0); + list r = map(fib, s); + assert(1000 == length(r)); + return true; + } +}; + +bool testCppPerf() { + { + const lambda 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 nfml = nestedFibMapPerf(lambda(nested::fib)); + cout << "Nested Fibonacci map test " << (time(nfml, 1, 1) / 1000) << " ms" << endl; + } + return true; +} + +const id idF(const int v) { + return v * 2; +} + +const id idG(const int v) { + return v * 3; +} + +const id idH(const int v) { + return idF(v) >> idG; +} + +bool testIdMonad() { + const id m(2); + assert(m >> idF == idF(2)); + assert(m >> unit() == m); + assert(m >> idF >> idG == m >> idH); + return true; +} + +const maybe maybeF(const int v) { + return v * 2; +} + +const maybe maybeG(const int v) { + return v * 3; +} + +const maybe maybeH(const int v) { + return maybeF(v) >> maybeG; +} + +bool testMaybeMonad() { + const maybe m(2); + assert(m >> maybeF == maybeF(2)); + assert((m >> just()) == m); + assert(m >> maybeF >> maybeG == m >> maybeH); + + assert(maybe() >> maybeF >> maybeG == maybe()); + return true; +} + +const failable failableF(const int v) { + return v * 2; +} + +const failable failableG(const int v) { + return v * 3; +} + +const failable failableH(const int v) { + return failableF(v) >> failableG; +} + +bool testFailableMonad() { + const failable m(2); + assert(m >> failableF == failableF(2)); + assert((m >> success()) == m); + assert(m >> failableF >> failableG == m >> failableH); + + cout << "Failable monad test... " << endl; + failable ooops = mkfailure("test"); + assert(reason(ooops) == "test"); + assert(ooops >> failableF >> failableG == ooops); + return true; +} + +struct tickInc { + const double v; + tickInc(const double v) : v(v) { + } + const scp operator()(int s) const { + return scp(s + 1, v); + } +}; + +const state tick(const double v) { + return transformer(tickInc(v)); +} + +const state stateF(const double v) { + return result(v * 2.0) >> tick; +} + +const state stateG(const double v) { + return result(v + 5); +} + +const state stateH(const double v) { + return stateF(v) >> stateG; +} + +bool testStateMonad() { + const lambda(const double)> r(result); + + state m = result(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(".libs/libdynlib-test") + dynlibExt); + const failable > sq(dynlambda("csquare", dl)); + assert(hasContent(sq)); + lambda l(content(sq)); + assert(l(2) == 4); + + const failable()> > sql(dynlambda()>("csquarel", dl)); + assert(hasContent(sql)); + lambda()> ll(content(sql)); + assert(ll()(3) == 9); + return true; +} + +} + +int main() { + 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/cpp-contrib/kernel/list.hpp b/sca-cpp/branches/cpp-contrib/kernel/list.hpp new file mode 100644 index 0000000000..84eba6d82f --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/list.hpp @@ -0,0 +1,559 @@ +/* + * 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 +#include "string.hpp" +#include "fstream.hpp" +#include "function.hpp" + +namespace tuscany { + +#ifdef WANT_MAINTAINER_MODE + +/** + * Debug utilities. Counters used to track instances of lists, and + * macro used to write the contents of a list in a string, easier to + * watch in a debugger than the list itself. + */ +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 + +#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 class list { +public: + + list() { + debug_inc(countLists); + debug_inc(countELists); + debug_watchList(); + } + + list(const T car, const lambda()>& 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& operator=(const list& 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& 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& 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& 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& p) const { + return !this->operator==(p); + } + + operator const list >() const { + return (list >)T(*this); + } + +private: +#ifdef WANT_MAINTAINER_WATCH + template friend const string watchList(const list& p); + string watch; +#endif + + template friend const bool isNil(const list& p); + template friend const X car(const list& p); + template friend const list cdr(const list& p); + + T car; + lambda()> 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 const string watchList(const list& p) { + if(isNil(p)) + return "()"; + odebugstream os; + os << "(" << car(p) << " ...)"; + return str(os); +} + +#endif + +/** + * Returns true if the given list is nil. + */ +template const bool isNil(const list& p) { + return isNil(p.cdr); +} + +/** + * Write a list to an output stream. + */ +template ostream& writeHelper(ostream& out, const list& l) { + if (isNil(l)) + return out; + out << " " << car(l); + return writeHelper(out, cdr(l)); +} + +template ostream& operator<<(ostream& out, const list& l) { + if(isNil(l)) + return out << "()"; + out << "(" << car(l); + writeHelper(out, cdr(l)); + return out << ")"; +} + +/** + * Construct a (lazy) list from a value and a lambda function that returns the cdr. + */ +template const list cons(const T& car, const lambda()>& cdr) { + return list (car, cdr); +} + +/** + * Construct a list from a value and a cdr list. + */ +template const list cons(const T& car, const list& cdr) { + return list (car, result(cdr)); +} + +/** + * Cons variations for use with the reduce and reduceRight functions. + */ +template const list lcons(const list& cdr, const T& car) { + return cons(car, cdr); +} + +template const list rcons(const T& car, const list& cdr) { + return cons(car, cdr); +} + +/** + * Construct a list of one value. + */ +template const list mklist(const T& car) { + return list (car, result(list ())); +} + +/** + * Construct a list of two values. + */ +template const list mklist(const T& a, const T& b) { + return cons(a, mklist(b)); +} + +/** + * Construct a list of three values. + */ +template const list mklist(const T& a, const T& b, const T& c) { + return cons(a, cons(b, mklist(c))); +} + +/** + * Construct a list of four values. + */ +template const list 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 const list 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 const list 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 const T car(const list& p) { + // Abort if trying to access the car of a nil list + assert(!isNil(p.cdr)); + return p.car; +} + +/** + * Returns the cdr of a list. + */ +template const list cdr(const list& p) { + return p.cdr(); +} + +/** + * Returns the car of the cdr of a list. + */ +template const T cadr(const list& p) { + return car(cdr(p)); +} + +/** + * Returns the car of the cdr of the cdr of a list. + */ +template const T caddr(const list& p) { + return car(cdr(cdr(p))); +} + +/** + * Returns the car of the cdr of the cdr of the cdr of a list. + */ +template const T cadddr(const list& p) { + return car(cdr(cdr(cdr(p)))); +} + +/** + * Returns the cdr of a cdr of a list. + */ +template const list cddr(const list& p) { + return cdr(cdr(p)); +} + +/** + * Returns the cdr of a cdr of the cdr of a list. + */ +template const list cdddr(const list& p) { + return cdr(cdr(cdr(p))); +} + +/** + * Returns the length of a list. + */ +template struct lengthRef { + const int operator()(const int c, const list& p) { + if(isNil(p)) + return c; + return (*this)(c + 1, cdr(p)); + } +}; + +template const int length(const list& p) { + return lengthRef ()(0, p); +} + +/** + * Appends a list and a lambda function returning a list. + */ +template struct appendCdr { + const list a; + const lambda()> fb; + appendCdr(const list& a, const lambda()>& fb) : + a(a), fb(fb) { + } + const list operator()() const { + return append(a, fb); + } +}; + +template const list append(const list&a, const lambda()>& fb) { + if(isNil(a)) + return fb(); + + return cons(car(a), appendCdr (cdr(a), fb)); +} + +/** + * Appends two lists. + */ +template const list append(const list&a, const list& b) { + return append(a, result(b)); +} + +/** + * Append a value to a list. + */ +template const list operator+(const list& l, const T& v) { + return append(l, mklist(v)); +} + +template const list operator+(const list& l, const V& v) { + return append(l, mklist(v)); +} + +/** + * Map a lambda function on a list. + */ +template const list map(const lambda& f, const list& p) { + if(isNil(p)) + return list (); + return cons(f(car(p)), map(f, cdr(p))); +} + +/** + * Run a reduce lambda function on a list. + */ +template struct reduceAccumulate { + const lambda f; + reduceAccumulate(const lambda& f) : + f(f) { + } + R operator()(const R& acc, const list& p) const { + if(isNil(p)) + return acc; + return (*this)(f(acc, car(p)), cdr(p)); + } +}; + +template const R reduce(const lambda& f, const R& initial, const list& p) { + return reduceAccumulate (f)(initial, p); +} + +template struct reduceRightAccumulate { + const lambda f; + reduceRightAccumulate(const lambda& f) : + f(f) { + } + R operator()(const list& p, const R& acc) const { + if(isNil(p)) + return acc; + return (*this)(cdr(p), f(car(p), acc)); + } +}; + +template const R reduceRight(const lambda& f, const R& initial, const list& p) { + return reduceRightAccumulate (f)(p, initial); +} + +/** + * Run a filter lambda function on a list. + */ +template const list filter(const lambda& f, const list& p) { + if(isNil(p)) + return list (); + if(f(car(p))) { + const lambda(const lambda, const list)> ff(filter); + 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 const list member(const T& t, const list& p) { + if(isNil(p)) + return list (); + if(t == car(p)) + return p; + return member(t, cdr(p)); +} + +/** + * Reverse a list. + */ +template const list reverseIter(const list& acc, const list& p) { + if(isNil(p)) + return acc; + return reverseIter(cons(car(p), acc), cdr(p)); +} + +template const list reverse(const list& p) { + return reverseIter(list (), p); +} + +template const list seq(const T& start, const T& end); + +template struct seqGenerate { + const T start; + const T end; + seqGenerate(const T& start, const T&end) : + start(start), end(end) { + } + const list operator()() const { + return seq (start, end); + } +}; + +/** + * Returns a sequence of values between the given bounds. + */ +template const list seq(const T& start, const T& end) { + if(start == end) + return mklist(start); + if(start < end) + return cons(start, seqGenerate (start + 1, end)); + return cons(start, seqGenerate (start - 1, end)); +} + +/** + * Returns the i-th element of a list. + */ +template const T listRef(const list& l, const int 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 const list assoc(const T& k, const list >& p) { + if(isNil(p)) + return list (); + 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 const list > zip(const list& a, const list& b) { + if (isNil(a) || isNil(b)) + return list >(); + return cons >(mklist(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 const list unzipKeys(const list >& l) { + if (isNil(l)) + return list(); + return cons(car(car(l)), unzipKeys(cdr(l))); +} + +template const list unzipValues(const list >& l) { + if (isNil(l)) + return list(); + return cons(cadr(car(l)), unzipValues(cdr(l))); +} + +template const list > unzip(const list >& l) { + return mklist >(unzipKeys(l), unzipValues(l)); +} + +} + +#endif /* tuscany_list_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/mem-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/mem-test.cpp new file mode 100644 index 0000000000..b1164a5a36 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/mem-test.cpp @@ -0,0 +1,162 @@ +/* + * 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 +#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(); + 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 = 100000; + const lambda 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 = 100000; + const lambda 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::cout << "Testing..." << tuscany::endl; + + tuscany::testPoolAllocPerf(); + tuscany::testStdAllocPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/cpp-contrib/kernel/monad.hpp b/sca-cpp/branches/cpp-contrib/kernel/monad.hpp new file mode 100644 index 0000000000..8aa4bc1662 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/monad.hpp @@ -0,0 +1,486 @@ +/* + * 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 "function.hpp" +#include "string.hpp" +#include "stream.hpp" + +namespace tuscany +{ + +/** + * Identity monad. Just wraps a value. + * To get the value in the monad, just cast it to the value type. + */ +template class id { +public: + id(const V& v) : v(v) { + } + + const id& operator=(const id& m) { + if(this == &m) + return *this; + v = m.v; + return *this; + } + + const bool operator!=(const id& m) const { + return !this->operator==(m); + } + + const bool operator==(const id& m) const { + if (&m == this) + return true; + return v == m.v; + } + +private: + const V v; + + template friend const X content(const id& m); +}; + +/** + * Write an identity monad to a stream. + */ +template ostream& operator<<(ostream& out, const id& m) { + out << content(m); + return out; +} + +/** + * Returns the content of an identity monad. + */ +template const V content(const id& m) { + return m.v; +} + +/** + * Return an identity monad from a value. + */ +template const id mkunit(const V& v) { + return id(v); +} + +template const lambda(const V)> unit() { + return mkunit; +} + +/** + * Bind a function to an identity monad. Pass the value in the monad to the function. + */ +template const id operator>>(const id& m, const lambda(const V)>& f) { + return f(content(m)); +} + +template const id operator>>(const id& m, const id (* 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 class maybe { +public: + maybe(const V& v) : hasv(true), v(v) { + } + + maybe() : hasv(false) { + } + + const maybe& operator=(const maybe& m) { + if(this == &m) + return *this; + hasv = m.hasv; + if (hasv) + v = m.v; + return *this; + } + + const bool operator!=(const maybe& m) const { + return !this->operator==(m); + } + + const bool operator==(const maybe& 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 friend const bool hasContent(const maybe& m); + template friend const X content(const maybe& m); +}; + +/** + * Write a maybe monad to a stream. + */ +template ostream& operator<<(ostream& out, const maybe& m) { + if (!hasContent(m)) { + out << "nothing"; + return out; + } + out << content(m); + return out; +} + +/** + * Return a maybe monad with a value in it. + */ +template const maybe mkjust(const V& v) { + return maybe(v); +} + +template const lambda(const V)> just() { + return mkjust; +} + +/** + * Returns true if a maybe monad contains a content. + */ +template const bool hasContent(const maybe& m) { + return m.hasv; +} + +/** + * Returns the content of a maybe monad. + */ +template const V content(const maybe& 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 const maybe operator>>(const maybe& m, const lambda(const V)>& f) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +template const maybe operator>>(const maybe& m, const maybe (* 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 class failable { +public: + failable() : hasv(false) { + } + + failable(const V& v) : hasv(true), v(v) { + } + + failable(const failable& m) : hasv(m.hasv), v(m.v), f(m.f) { + } + + const failable& operator=(const failable& m) { + if (&m == this) + return *this; + hasv = m.hasv; + v = m.v; + f = m.f; + return *this; + } + + const bool operator!=(const failable& m) const { + return !this->operator==(m); + } + + const bool operator==(const failable& m) const { + if (this == &m) + return true; + if (!hasv) + return !m.hasv && f == m.f; + return m.hasv && v == m.v; + } + +private: + failable(const bool hasv, const F& f) : hasv(hasv), f(f) { + } + + template friend const bool hasContent(const failable& m); + template friend const A content(const failable& m); + template friend const B reason(const failable& m); + template friend const failable mkfailure(const B& f); + template friend const failable mkfailure(); + + bool hasv; + V v; + F f; +}; + +/** + * Write a failable monad to a stream. + */ +template ostream& operator<<(ostream& out, const failable& m) { + if (!hasContent(m)) { + out << reason(m); + return out; + } + out << content(m); + return out; +} + +/** + * Returns a failable monad with a success value in it. + */ +template const failable mksuccess(const V& v) { + return failable(v); +} + +template const lambda(const V)> success() { + return mksuccess; +} + +/** + * Returns a failable monad with a failure in it. + */ +template const failable mkfailure(const F& f) { + debug(f, "failable::mkfailure"); + return failable(false, f); +} + +template const failable mkfailure(const char* f) { + return mkfailure(string(f)); +} + +template const failable mkfailure() { + return failable(false, string()); +} + +template const lambda(const V)> failure() { + return mkfailure; +} + +/** + * Returns true if the monad contains a content. + */ +template const bool hasContent(const failable& m) { + return m.hasv; +} + +/** + * Returns the content of a failable monad. + */ +template const V content(const failable& m) { + return m.v; +} + +/** + * Returns the reason for failure of a failable monad. + */ +template const F reason(const failable& m) { + return m.f; +} + +/** + * 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 +const failable operator>>(const failable& m, const lambda(const V)>& f) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +template +const failable operator>>(const failable& m, const failable (* const f)(const V)) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +/** + * State + content pair data type used by the state monad. + */ +template 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& operator=(const scp& p) { + if(this == &p) + return *this; + s = p.s; + v = p.v; + return *this; + } + + const bool operator!=(const scp& p) const { + return !this->operator==(p); + } + + const bool operator==(const scp& p) const { + if (this == &p) + return true; + return s == p.s && v == p.v; + } + +private: + const S s; + const V v; + + template friend const A scpstate(const scp& m); + template friend const B content(const scp& m); +}; + +/** + * Returns the state of a state-content pair. + */ +template const S scpstate(const scp& m) { + return m.s; +} + +/** + * Returns the content of a state-content pair. + */ +template const S content(const scp& m) { + return m.v; +} + +/** + * State monad. Used to represent the combination of a state and a content. + */ +template class state { +public: + state(const lambda(const S)>& f) : f(f) { + } + + const scp operator()(const S& s) const { + return f(s); + } + + const state& operator=(const state& m) { + if(this == &m) + return *this; + f = m.f; + return *this; + } + + const bool operator!=(const state& m) const { + return !this->operator==(m); + } + + const bool operator==(const state& m) const { + if (this == &m) + return true; + return f == m.f; + } + +private: + const lambda(const S)> f; +}; + +/** + * Write a state monad to a stream. + */ +template ostream& operator<<(ostream& out, const state& m) { + const S s = m; + const V v = m; + out << '(' << s << ' ' << v << ')'; + return out; +} + +/** + * Return a state monad carrying a result content. + */ +template struct returnState { + const V v; + returnState(const V& v) : v(v) { + } + const scp operator()(const S& s) const { + return scp(s, v); + } +}; + +template const state result(const V& v) { + return state(returnState(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 const state transformer(const lambda(const S)>& f) { + return state(f); +} + +/** + * Bind a function to a state monad. The function takes a content and returns a state + * monad carrying a return content. + */ +template struct stateBind { + const state st; + const lambda(const A)>f; + + stateBind(const state& st, const lambda(const A)>& f) : st(st), f(f) { + } + + const scp operator()(const S& is) const { + const scp iscp = st(is); + const state m = f((A)iscp); + return m((S)iscp); + } +}; + +template +const state operator>>(const state& st, const lambda(const A)>& f) { + return state(stateBind(st, f)); +} + +template +const state operator>>(const state& st, const state (* const f)(const A)) { + return state(stateBind(st, f)); +} + +} +#endif /* tuscany_monad_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/parallel-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/parallel-test.cpp new file mode 100644 index 0000000000..2969dd0637 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/parallel-test.cpp @@ -0,0 +1,166 @@ +/* + * 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 +#include "stream.hpp" +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "perf.hpp" +#include "parallel.hpp" + +namespace tuscany { + +#ifdef WANT_THREADS + +int inci = 0; + +struct incPerf { + incPerf() { + } + const bool operator()() const { + inci = inci + 1; + return true; + } +}; + +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; + } +}; + +__thread int tlsi = 0; + +struct tlsPerf { + tlsPerf() { + } + const bool operator()() const { + tlsi = tlsi + 1; + return true; + } +}; + +bool testAtomicPerf() { + const int count = 100000; + { + const lambda l = incPerf(); + cout << "Non-atomic inc test " << time(l, 1000, count) << " ms" << endl; + assert(inci == count + 1000); + } + { + const lambda 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 l = mutexPerf(&mutex); + cout << "Locked inc test " << time(l, 1000, count) << " ms" << endl; + assert(muxi == count + 1000); + pthread_mutex_destroy(&mutex); + } + { + const lambda l = tlsPerf(); + cout << "Thread local inc test " << time(l, 1000, count) << " ms" << endl; + assert(tlsi == count + 1000); + } + return true; +} + +const int mtsquare(const int x) { + for(int i = 0; i < 10000000; i++) + ; + return x * x; +} + +bool checkResults(const list > r, int i) { + if (isNil(r)) + return true; + assert(car(r) == i * i); + checkResults(cdr(r), i + 1); + return true; +} + +const list > submitSquares(worker& w, const int max, const int i) { + if (i == max) + return list >(); + const lambda func = curry(lambda (mtsquare), i); + return cons(submit(w, func), submitSquares(w, max, i + 1)); +} + +bool testWorker() { + worker w(20); + { + const lambda func = curry(lambda (mtsquare), 2); + assert(submit(w, func) == 4); + } + { + const int max = 20; + const list > r(submitSquares(w, max, 0)); + checkResults(r, 0); + } + shutdown(w); + return true; +} + +#endif + +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + +#ifdef WANT_THREADS + tuscany::testAtomicPerf(); + 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/cpp-contrib/kernel/parallel.hpp b/sca-cpp/branches/cpp-contrib/kernel/parallel.hpp new file mode 100644 index 0000000000..09cf0df9a3 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/parallel.hpp @@ -0,0 +1,319 @@ +/* + * 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. + */ + +#ifdef WANT_THREADS +#include +#include +#include +#endif + +#include "function.hpp" +#include "list.hpp" + +namespace tuscany { + +#ifdef WANT_THREADS + +/** + * Returns the current thread id. + */ +unsigned int threadId() { + return syscall(__NR_gettid); +} + +/** + * Represents a value which will be know in the future. + */ +template class future { + +private: + template 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 > fvalue; + + template friend const X get(const future& f); + template friend bool set(const future& f, const X& v); + +public: + future() : fvalue(new (gc_new >()) futureValue()) { + } + + ~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 class wqueue { +public: + wqueue(int max) : max(max), size(0), tail(0), head(0), values(new (gc_anew(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 int max; + int size; + int tail; + int head; + pthread_mutex_t mutex; + pthread_cond_t full; + pthread_cond_t empty; + gc_ptr values; + + template friend const int enqueue(wqueue& q, const X& v); + template friend const X dequeue(wqueue& q); +}; + +/** + * Adds an element to the tail of the queue. + */ +template const int enqueue(wqueue&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 const T dequeue(wqueue& 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 >* work = reinterpret_cast >*>(arg); + while(dequeue(*work)()) + ; + return NULL; +} + +/** + * Returns a list of worker threads. + */ +const list workerThreads(wqueue >& wqueue, const int count) { + if (count == 0) + return list(); + 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(int max) : work(wqueue >(max)), threads(workerThreads(work, max)) { + } + + wqueue > work; + const list threads; + }; + +public: + worker(int max) : w(*(new (gc_new()) sharedWorker(max))) { + } + + worker(const worker& wk) : w(wk.w) { + } + +private: + sharedWorker& w; + + template friend const future submit(worker& w, const lambda& func); + friend const bool shutdown(worker& w); + friend const bool cancel(worker& w); +}; + +/** + * Function used to wrap work submitted to a worker. + */ +template bool submitFunc(const lambda& func, const future& fut) { + fut = func(); + return true; +} + +/** + * Submits work to a worker. + */ +template const future submit(worker& w, const lambda& func) { + const future fut; + const lambda f = curry(lambda, future)>(submitFunc), func, fut); + enqueue(w.w.work, f); + return fut; +} + +/** + * Enqueues shutdown requests. + */ +const bool shutdownEnqueue(const list& threads, wqueue >& 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& 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& 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; +} + +#endif + +} +#endif /* tuscany_parallel_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/perf.hpp b/sca-cpp/branches/cpp-contrib/kernel/perf.hpp new file mode 100644 index 0000000000..f5004d015b --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/perf.hpp @@ -0,0 +1,68 @@ +/* + * 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 +#include + +#include "function.hpp" + +namespace tuscany +{ + +/** + * Measure the time required to perform a function in msec. + */ +struct timeLambda { + const lambda f; + timeLambda(const lambda& f) : f(f) { + } + bool operator()(const long count) const { + if (count == 0) + return true; + f(); + (*this)(count - 1); + return true; + } +}; + +const double time(const lambda& f, const long warmup, const long count) { + const lambda 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; +} + +} +#endif /* tuscany_perf_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/sstream.hpp b/sca-cpp/branches/cpp-contrib/kernel/sstream.hpp new file mode 100644 index 0000000000..f5006606dd --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/sstream.hpp @@ -0,0 +1,240 @@ +/* + * 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 +#include +#include +#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); +} + +/** + * 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; + va_start (args, fmt); + string s; + s.len = vsnprintf(NULL, 0, fmt, args); + s.buf = gc_cnew(s.len + 1); + 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: + static const bool strHelper(const list 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 strHelper(cdr(l), b); + } + + const string str() { + if (isNil(buf)) + return string(); + string s; + s.len = len; + s.buf = gc_cnew(s.len + 1); + strHelper(buf, s.buf + len); + s.buf[s.len] = '\0'; + return s; + } + + friend const string str(ostringstream& os); + + int len; + list 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 int slen = length(s); + len = slen; + buf = c_str(s); + } + + ~istringstream() { + } + + istringstream(const istringstream& is) { + len = is.len; + cur = is.cur; + buf = is.buf; + } + + const int read(void* b, int size) { + const int 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: + int len; + int cur; + const char* buf; +}; + +/** + * Tokenize a string into a list of strings. + */ +const list tokenize(const char* sep, const string& str) { + struct nested { + static const list tokenize(const char* sep, const string& str, const int start = 0) { + if (start >= length(str)) + return list(); + const int 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, str, i + 1)); + } + }; + return nested::tokenize(sep, str, 0); +} + +/** + * Returns a lazy list view of an input stream. + */ +struct ilistRead{ + istream &is; + ilistRead(istream& is) : is(is) { + } + const list operator()() { + char buffer[1024]; + const int n = read(is, buffer, sizeof(buffer)); + if (n ==0) + return list(); + return cons(string(buffer, n), (*this)()); + } +}; + +const list streamList(istream& is) { + return ilistRead(is)(); +} + +/** + * Fragment the first element of a list of strings to fit the given max length. + */ +const list fragment(list l, int 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& 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/cpp-contrib/kernel/stream.hpp b/sca-cpp/branches/cpp-contrib/kernel/stream.hpp new file mode 100644 index 0000000000..32b754f315 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/stream.hpp @@ -0,0 +1,200 @@ +/* + * 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 +#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("%g", 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.vprintf("%s", "\n"); + return os.flush(); +} + +/* + * Input stream. + */ +class istream { +public: + virtual const int read(void* buf, int 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 int read(istream& is, void * buf, int 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 ostream& operator<<(ostream& out, const gc_ptr& p) { + return out << p.ptr; +} + +#ifdef WANT_MAINTAINER_MODE + +/** + * Debug stream implementation with no dependencies on anything else. + */ +class odebugstream : public ostream { +public: + odebugstream() { + } + + odebugstream& vprintf(const char* fmt, ...) { + va_list args; + va_start (args, fmt); + string s; + s.len = vsnprintf(NULL, 0, fmt, args); + s.buf = gc_cnew(s.len + 1); + 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/cpp-contrib/kernel/string-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/string-test.cpp new file mode 100644 index 0000000000..323756c7e4 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/string-test.cpp @@ -0,0 +1,196 @@ +/* + * 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 +#include +#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(); + string z = y; + assert(checkStringCopyCounters(0)); + resetStringCopyCounters(); + const list pl = list() + "abcd" + "efgh"; + printStringCopyCounters(); + resetStringCopyCounters(); + const list cl = cons("efgh", mklist("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(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[16384]; + +struct addStrings{ + const int size; + addStrings(const int size) : size(size) { + } + bool operator()() const { + const int sz = size / 4; + string x(charBuffer, sz); + string y(charBuffer, sz); + assert(length(add(x, y)) == sz * 2); + return true; + } +}; + +struct addStdStrings{ + const int size; + addStdStrings(const int size) : size(size) { + } + bool operator()() const { + const int 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 = 100000; + { + const lambda a16 = addStrings(16); + cout << "string test " << time(a16, 5, count) << " ms" << endl; + const lambda a32 =addStrings(32); + cout << "string test " << time(a32, 5, count) << " ms" << endl; + const lambda a256 =addStrings(256); + cout << "string test " << time(a256, 5, count) << " ms" << endl; + const lambda a1024 =addStrings(1024); + cout << "string test " << time(a1024, 5, count) << " ms" << endl; + const lambda a4096 =addStrings(4096); + cout << "string test " << time(a4096, 5, count) << " ms" << endl; + } + { + const lambda a16 =addStdStrings(16); + cout << "Std string test " << time(a16, 5, count) << " ms" << endl; + const lambda a32 =addStdStrings(32); + cout << "Std string test " << time(a32, 5, count) << " ms" << endl; + const lambda a256 =addStdStrings(256); + cout << "Std string test " << time(a256, 5, count) << " ms" << endl; + const lambda a1024 =addStdStrings(1024); + cout << "Std string test " << time(a1024, 5, count) << " ms" << endl; + const lambda a4096 =addStdStrings(4096); + cout << "Std string test " << time(a4096, 5, count) << " ms" << endl; + } + + return true; +} + +} + +int main() { + 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/cpp-contrib/kernel/string.hpp b/sca-cpp/branches/cpp-contrib/kernel/string.hpp new file mode 100644 index 0000000000..931417e430 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/string.hpp @@ -0,0 +1,291 @@ +/* + * 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 +#include +#include +#include +#include "gc.hpp" + +namespace tuscany { + +#ifdef WANT_MAINTAINER_MODE + +/** + * 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_MODE + 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 int n) { + len = n; + if (len == 0) { + buf = stringEmptyBuffer; + return; + } + buf = gc_cnew(len + 1); + string_memcpy(buf, s, len); + buf[len] = '\0'; + } + + string(const int 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 int 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 int 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_MODE + 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 int length(const string& s); + friend const char* c_str(const string& s); + friend const int find(const string& s1, const char* s2, const int start); + friend const string substr(const string& s, const int pos, const int n); + + int 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 int 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 int 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 int find(const string& s1, const char* s2, const int 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 int find(const string& s1, const char* s2) { + return find(s1, s2, 0); +} + +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 int find_first_of(const string& s1, const string& s2) { + return strcspn(c_str(s1), c_str(s2)); +} + +/** + * Find the last occurence of a character in a string. + */ +const int 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 int pos, const int 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 int 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/cpp-contrib/kernel/tree.hpp b/sca-cpp/branches/cpp-contrib/kernel/tree.hpp new file mode 100644 index 0000000000..436385aa1b --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/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 const list mktree(const T& e, const list& left, const list& right) { + return mklist(e, left, right); +} + +/** + * Find a leaf with the given key in a tree. + */ +template const list assoctree(const T& k, const list& tree) { + if (isNil(tree)) + return tree; + if (k == car(car(tree))) + return car(tree); + if (k < car(car(tree))) + return assoctree(k, cadr(tree)); + return assoctree(k, caddr(tree)); +} + +/** + * Construct a new tree from a leaf and a tree. + */ +template const list constree(const T& e, const list& tree) { + if (isNil(tree)) + return mktree(e, list(), list()); + if (e == car(tree)) + return tree; + if (e < car(tree)) + return mktree(car(tree), constree(e, cadr(tree)), caddr(tree)); + return mktree(car(tree), cadr(tree), constree(e, caddr(tree))); +} + +/** + * Make a tree from an unordered list of leaves. + */ +template const list mktree(const list& l) { + if (isNil(l)) + return l; + return constree(car(l), mktree(cdr(l))); +} + +/** + * Convert a tree to an ordered list of leaves. + */ +template const list flatten(const list& tree) { + if (isNil(tree)) + return tree; + return append(flatten(cadr(tree)), cons(car(tree), flatten(caddr(tree)))); +} + +/** + * Sort a list. + */ +template const list sort(const list& l) { + return flatten(mktree(l)); +} + +/** + * Make a balanced tree from an ordered list of leaves. + */ +template const list btreeHelper(const list& elements, const int n) { + if (n == 0) + return cons(list(), elements); + const int leftSize = (n - 1) / 2; { + const list leftResult = btreeHelper(elements, leftSize); { + const list leftTree = car(leftResult); + const list nonLeftElements = cdr(leftResult); + const int rightSize = n - (leftSize + 1); { + const T thisEntry = car(nonLeftElements); + const list rightResult = btreeHelper(cdr(nonLeftElements), rightSize); { + const list rightTree = car(rightResult); + const list remainingElements = cdr(rightResult); { + return cons(mktree(thisEntry, leftTree, rightTree), remainingElements); + } + } + } + } + } +} + +template const list mkbtree(const list& elements) { + return car(btreeHelper(elements, length(elements))); +} + +} + +#endif /* tuscany_tree_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/value.hpp b/sca-cpp/branches/cpp-contrib/kernel/value.hpp new file mode 100644 index 0000000000..87d80a3e2a --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/value.hpp @@ -0,0 +1,593 @@ +/* + * 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 +#include "string.hpp" +#include "sstream.hpp" +#include "gc.hpp" +#include "function.hpp" +#include "list.hpp" +#include "monad.hpp" + +namespace tuscany +{ + +#ifdef WANT_MAINTAINER_MODE + +/** + * Debug utilities. Counters used to track instances of values, and + * macro used to write the contents of a value in a string, easier to + * watch in a debugger than the value itself. + */ +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 + +#define debug_watchValue() do { \ + this->watch = watchValue(*this); \ + } while (0) + +#else + +#define debug_watchValue() + +#endif + +class value; + +class value { +public: + + enum ValueType { + Undefined, Symbol, String, List, Number, Bool, Lambda, Ptr + }; + + value() : type(value::Undefined) { + 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&)>& 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& lst) : type(value::List), data(vdata(result(lst))) { + debug_inc(countValues); + debug_inc(countVValues); + debug_watchValue(); + } + + value(const list >& 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 ptr) : type(value::Ptr), data(vdata(result(ptr))) { + debug_inc(countValues); + debug_inc(countVValues); + debug_watchValue(); + } + + value(const failable& m) : type(value::List), + data(vdata(result(hasContent(m)? mklist(content(m)) : mklist(value(), reason(m))))) { + debug_inc(countValues); + debug_inc(countVValues); + debug_watchValue(); + } + + value(const maybe& m) : type(value::List), + data(vdata(result(hasContent(m)? mklist(content(m)) : list()))) { + 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::Undefined: + return true; + 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& 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() const { + return ptr()(); + } + + operator const list() const { + return lst()(); + } + + operator const list >() const { + return listOfListOfValues(lst()()); + } + + operator const lambda&)>() const { + return func(); + } + +private: + template lambda& vdata() const { + return *reinterpret_cast *> (const_cast *> (&data)); + } + + template const lambda& vdata(const T& v) const { + return *reinterpret_cast *> (&v); + } + + lambda& num() const { + return vdata (); + } + + lambda& boo() const { + return vdata (); + } + + lambda()>& ptr() const { + return vdata()> (); + } + + lambda& str() const { + return vdata (); + } + + lambda()>& lst() const { + return vdata()> (); + } + + lambda&)>& func() const { + return vdata&)> (); + } + + const list listOfValues(const list >& l) const { + if (isNil(l)) + return list(); + return cons(car(l), listOfValues(cdr(l))); + } + + const list > listOfListOfValues(const list& l) const { + if (isNil(l)) + return list >(); + return cons >(list(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 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(v); + odebugstream os; + os << v; + return str(os); +} + +#endif + +/** + * 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: + return out << '\"' << v.str()() << '\"'; + 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 p = v.ptr()(); + if (p == gc_ptr(NULL)) + return out << "gc_ptr::null"; + return out << "gc_ptr::" << p; + } + default: + return out << "undefined"; + } +} + +/** + * 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::Undefined; +} + +/** + * 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)exp)) + return car((list)exp) == tag; + return false; +} + +/** + * Make a list of values from a list of other things. + */ +template const list mkvalues(const list& l) { + if (isNil(l)) + return list(); + return cons(car(l), mkvalues(cdr(l))); +} + +/** + * Convert a list of values to a list of other things. + */ +template const list convertValues(const list& l) { + if (isNil(l)) + return list(); + return cons(car(l), convertValues(cdr(l))); +} + +/** + * Convert a path string value to a list of values. + */ +const list pathTokens(const char* p) { + if (p == NULL || p[0] == '\0') + return list(); + if (p[0] == '/') + return tokenize("/", p + 1); + return tokenize("/", p); +} + +const list 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& p) { + if (isNil(p)) + return ""; + return string("/") + car(p) + path(cdr(p)); +} + +} +#endif /* tuscany_value_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/xml-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/xml-test.cpp new file mode 100644 index 0000000000..c83a65fd92 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/xml-test.cpp @@ -0,0 +1,180 @@ +/* + * 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 +#include "stream.hpp" +#include "string.hpp" +#include "list.hpp" +#include "value.hpp" +#include "element.hpp" +#include "xml.hpp" + +namespace tuscany { + +const string currencyXML = +"\n" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"US" +"" +"" +"\n"; + +const string customerXML = +"\n" +"" +"jdoe" +"

san franciscoca
" +"12341000" +"67892000" +"45673000" +"" +"\n"; + + +const bool isName(const value& token) { + return isTaggedList(token, attribute) && attributeName(token) == "name"; +} + +bool testReadXML() { + { + istringstream is(customerXML); + const list c = readXML(streamList(is)); + } + { + istringstream is(currencyXML); + const list c = readXML(streamList(is)); + + const value composite = car(c); + assert(isTaggedList(composite, element)); + assert(elementName(composite) == "composite"); + assert(attributeValue(car(filter(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 c = readXML(streamList(is)); + ostringstream os; + writeXML(xmlWriter, &os, c); + assert(str(os) == customerXML); + } + { + istringstream is(currencyXML); + const list c = readXML(streamList(is)); + ostringstream os; + writeXML(xmlWriter, &os, c); + assert(str(os) == currencyXML); + } + return true; +} + +bool testElements() { + { + const list ad = mklist(mklist("city", string("san francisco")), mklist("state", string("ca"))); + const list ac1 = mklist(mklist("id", string("1234")), mklist("balance", 1000)); + const list ac2 = mklist(mklist("id", string("6789")), mklist("balance", 2000)); + const list ac3 = mklist(mklist("id", string("4567")), mklist("balance", 3000)); + { + const list c = mklist(mklist("customer", mklist("name", string("jdoe")), cons("address", ad), mklist("account", mklist(ac1, ac2, ac3)))); + const list e = valuesToElements(c); + const list v = elementsToValues(e); + assert(v == c); + + ostringstream os; + writeXML(xmlWriter, &os, e); + assert(str(os) == customerXML); + } + { + const list c = mklist(mklist("customer", mklist("name", string("jdoe")), cons("address", ad), cons("account", ac1), cons("account", ac2), cons("account", ac3))); + const list e = valuesToElements(c); + const list v = elementsToValues(e); + + ostringstream os; + writeXML(xmlWriter, &os, e); + assert(str(os) == customerXML); + } + } + { + istringstream is(customerXML); + const list c = readXML(streamList(is)); + const list v = elementsToValues(c); + const list e = valuesToElements(v); + ostringstream os; + writeXML(xmlWriter, &os, e); + assert(str(os) == customerXML); + } + return true; +} + +bool testValues() { + { + const list l = mklist(list() + "ns1:echoString" + (list() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list() + "text" + string("Hello World!"))); + const list e = valuesToElements(l); + const failable > lx = writeXML(e); + ostringstream os; + write(content(lx), os); + istringstream is(str(os)); + const list x = readXML(streamList(is)); + const list v = elementsToValues(x); + assert(v == l); + } + return true; +} + +} + +int main() { + 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/cpp-contrib/kernel/xml.hpp b/sca-cpp/branches/cpp-contrib/kernel/xml.hpp new file mode 100644 index 0000000000..fa1701d83a --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/kernel/xml.hpp @@ -0,0 +1,369 @@ +/* + * 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 +#include +#include +#include +#include "string.hpp" +#include "list.hpp" +#include "stream.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" + +namespace tuscany { + +/** + * Initializes the libxml2 library. + */ +class XMLParser { +public: + XMLParser() { + xmlInitParser(); + } +} 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), tokenType(None), isEmptyElement(false), hasValue(false), hasAttributes(false) { + xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1); + xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1); + } + + ~XMLReader() { + 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: + const xmlTextReaderPtr xml; + 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(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 readList(const list& listSoFar, XMLReader& reader) { + const value token = readToken(reader); + if(isNil(token) || endElement == token) + return reverse(listSoFar); + if(startElement == token) + return readList(cons(readList(mklist(element), reader), listSoFar), reader); + return readList(cons(token, listSoFar), reader); +} + +/** + * Read a list of values from a libxml2 XML reader. + */ +const list read(XMLReader& reader) { + value nextToken = readToken(reader); + if (startElement == nextToken) + return mklist(readList(mklist(element), reader)); + return list(); +} + +/** + * Context passed to the read callback function. + */ +class XMLReadContext { +public: + XMLReadContext(const list& ilist) : ilist(ilist) { + } + list ilist; +}; + +/** + * Callback function called by libxml2 to read XML. + */ +int readCallback(void *context, char* buffer, int len) { + XMLReadContext& rc = *static_cast(context); + if (isNil(rc.ilist)) + return 0; + const list f(fragment(rc.ilist, len)); + const string s(car(f)); + rc.ilist = cdr(f); + memcpy(buffer, c_str(s), length(s)); + return length(s); +} + +/** + * Read a list of values from a list of strings representing an XML document. + */ +const list readXML(const list& ilist) { + XMLReadContext cx(ilist); + xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET); + if (xml == NULL) + return list(); + 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 expandElementValues(const value& n, const list& l) { + if (isNil(l)) + return l; + return cons(value(cons(element, cons(n, (list)car(l)))), expandElementValues(n, cdr(l))); +} + +const failable writeList(const list& 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("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 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("xmlTextWriterStartElement failed"); + + // Write its children + const failable w = writeList(elementChildren(token), xml); + if (!hasContent(w)) + return w; + + if (xmlTextWriterEndElement(xml) < 0) + return mkfailure("xmlTextWriterEndElement failed"); + } + } + else { + + // Write an element + if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0) + return mkfailure("xmlTextWriterStartElement failed"); + + // Write its children + const failable w = writeList(elementChildren(token), xml); + if (!hasContent(w)) + return w; + + if (xmlTextWriterEndElement(xml) < 0) + return mkfailure("xmlTextWriterEndElement failed"); + } + } else { + + // Write XML text + if (xmlTextWriterWriteString(xml, (const xmlChar*)c_str(string(token))) < 0) + return mkfailure("xmlTextWriterWriteString failed"); + } + + // Go on + return writeList(cdr(l), xml); +} + +/** + * Write a list of values to a libxml2 XML writer. + */ +const failable write(const list& l, const xmlTextWriterPtr xml, bool xmlTag) { + if (xmlTag) { + if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0) + return mkfailure(string("xmlTextWriterStartDocument failed")); + } + + const failable w = writeList(l, xml); + if (!hasContent(w)) + return w; + + if (xmlTag) { + if (xmlTextWriterEndDocument(xml) < 0) + return mkfailure("xmlTextWriterEndDocument failed"); + } + return true; +} + +/** + * Context passed to the write callback function. + */ +template class XMLWriteContext { +public: + XMLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { + } + const lambda reduce; + R accum; +}; + +/** + * Callback function called by libxml2 to write XML out. + */ +template int writeCallback(void *context, const char* buffer, int len) { + XMLWriteContext& cx = *static_cast*>(context); + cx.accum = cx.reduce(string(buffer, len), cx.accum); + return len; +} + +/** + * Convert a list of values to an XML document. + */ +template const failable writeXML(const lambda& reduce, const R& initial, const list& l, const bool xmlTag) { + XMLWriteContext cx(reduce, initial); + xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback, NULL, &cx, NULL); + if (out == NULL) + return mkfailure("xmlOutputBufferCreateIO failed"); + xmlTextWriterPtr xml = xmlNewTextWriter(out); + if (xml == NULL) + return mkfailure("xmlNewTextWriter failed"); + + const failable w = write(l, xml, xmlTag); + xmlFreeTextWriter(xml); + if (!hasContent(w)) { + return mkfailure(reason(w)); + } + return cx.accum; +} + +template const failable writeXML(const lambda& reduce, const R& initial, const list& l) { + return writeXML(reduce, initial, l, true); +} + +/** + * Convert a list of values to a list of strings representing an XML document. + */ +const failable > writeXML(const list& l, const bool xmlTag) { + const failable > ls = writeXML >(rcons, list(), l, xmlTag); + if (!hasContent(ls)) + return ls; + return reverse(list(content(ls))); +} + +const failable > writeXML(const list& l) { + return writeXML(l, true); +} + +} +#endif /* tuscany_xml_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/kernel/xsd-test.cpp b/sca-cpp/branches/cpp-contrib/kernel/xsd-test.cpp new file mode 100644 index 0000000000..0fc432c649 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/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 +#include + +namespace tuscany { + +bool printNode(xmlTextReaderPtr reader) { + const xmlChar* name = xmlTextReaderConstName(reader); + if(name == NULL) + name = (xmlChar *)""; + const xmlChar* value = xmlTextReaderConstValue(reader); + cout << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " " + << xmlTextReaderIsEmptyElement(reader) << " " << xmlTextReaderHasValue(reader); + if(value == NULL) + cout << endl; + else + cout << value << endl; + return true; +} + +int xmlRead(void *context, char* buffer, int len) { + return 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 schemas...\n"; + 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...\n"; + 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; +} -- cgit v1.2.3