diff options
Diffstat (limited to 'sca-cpp/trunk/kernel')
-rw-r--r-- | sca-cpp/trunk/kernel/Makefile.am | 31 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/element.hpp | 300 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/function.hpp | 235 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/gc.hpp | 404 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/kernel-test.cpp | 737 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/list.hpp | 484 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/monad.hpp | 455 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/parallel.hpp | 283 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/slist.hpp | 96 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/value.hpp | 491 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/xml.hpp | 364 | ||||
-rw-r--r-- | sca-cpp/trunk/kernel/xsd-test.cpp | 107 |
12 files changed, 3987 insertions, 0 deletions
diff --git a/sca-cpp/trunk/kernel/Makefile.am b/sca-cpp/trunk/kernel/Makefile.am new file mode 100644 index 0000000000..0bbfa195c7 --- /dev/null +++ b/sca-cpp/trunk/kernel/Makefile.am @@ -0,0 +1,31 @@ +# 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 = kernel-test xsd-test + +nobase_include_HEADERS = *.hpp + +INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${APR_INCLUDE} + +kernel_test_SOURCES = kernel-test.cpp +kernel_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 + +xsd_test_SOURCES = xsd-test.cpp +xsd_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 + +TESTS = kernel-test + diff --git a/sca-cpp/trunk/kernel/element.hpp b/sca-cpp/trunk/kernel/element.hpp new file mode 100644 index 0000000000..2b5336ba5c --- /dev/null +++ b/sca-cpp/trunk/kernel/element.hpp @@ -0,0 +1,300 @@ +/* + * 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"); + +/** + * Returns true if a value is an element. + */ +bool isElement(const value& v) { + if (!isList(v) || isNil(v) || element != car<value>(v)) + return false; + return true; +} + +/** + * Returns true if a value is an attribute. + */ +bool isAttribute(const value& v) { + if (!isList(v) || isNil(v) || attribute != car<value>(v)) + return false; + return true; +} + +/** + * Returns the name of an attribute. + */ +const value attributeName(const list<value>& l) { + return cadr(l); +} + +/** + * Returns the value of an attribute. + */ +const value attributeValue(const list<value>& l) { + return caddr(l); +} + +/** + * Returns the name of an element. + */ +const value elementName(const list<value>& l) { + return cadr(l); +} + +/** + * Returns true if an element has children. + */ +const bool elementHasChildren(const list<value>& l) { + return !isNil(cddr(l)); +} + +/** + * Returns the children of an element. + */ +const list<value> elementChildren(const list<value>& l) { + return cddr(l); +} + +/** + * Returns true if an element has a value. + */ +const value elementHasValue(const list<value>& l) { + const list<value> r = reverse(l); + if (isSymbol(car(r))) + return false; + if(isList(car(r)) && isSymbol(car<value>(car(r)))) + return false; + return true; +} + +/** + * Returns the value of an element. + */ +const value elementValue(const list<value>& l) { + return car(reverse(l)); +} + +/** + * Convert an element to a value. + */ +const bool elementToValueIsList(const value& v) { + if (!isList(v)) + return false; + const list<value> l = v; + return (isNil(l) || !isSymbol(car(l))); +} + +const value elementToValue(const value& t) { + const list<value> elementsToValues(const list<value>& e); + + // Convert an attribute + if (isTaggedList(t, attribute)) + return mklist(attributeName(t), attributeValue(t)); + + // Convert an element + if (isTaggedList(t, element)) { + + // Convert an element's value + if (elementHasValue(t)) { + + // Convert a single value + if (!elementToValueIsList(elementValue(t))) + return mklist(elementName(t), elementValue(t)); + + // Convert a list value + return cons(elementName(t), mklist<value>(elementsToValues(elementValue(t)))); + } + + // Convert an element's children + return cons(elementName(t), elementsToValues(elementChildren(t))); + } + + // Convert a value + if (!isList(t)) + return t; + return elementsToValues(t); +} + +/** + * Convert a list of elements to a list of values. + */ +const bool elementToValueIsSymbol(const value& v) { + if (!isList(v)) + return false; + const list<value> l = v; + if (isNil(l)) + return false; + if (!isSymbol(car(l))) + return false; + return true; +} + +const list<value> elementToValueGroupValues(const value& v, const list<value>& l) { + if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l))) + return cons(v, l); + if (car<value>(car(l)) != car<value>(v)) + return cons(v, l); + if (!elementToValueIsList(cadr<value>(car(l)))) { + const value g = mklist<value>(car<value>(v), mklist<value>(cdr<value>(v), cdr<value>(car(l)))); + return elementToValueGroupValues(g, cdr(l)); + } + const value g = mklist<value>(car<value>(v), cons<value>(cdr<value>(v), (list<value>)cadr<value>(car(l)))); + return elementToValueGroupValues(g, cdr(l)); + +} + +const list<value> elementsToValues(const list<value>& e) { + if (isNil(e)) + return e; + return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e))); +} + +/** + * Convert a value to an element. + */ +const value valueToElement(const value& t) { + const list<value> valuesToElements(const list<value>& l); + + // Convert a name value pair + if (isList(t) && isSymbol(car<value>(t))) { + const value n = car<value>(t); + const value v = cadr<value>(t); + + // Convert a single value + if (!isList(v)) + return mklist(element, n, v); + + // Convert a list value + if (!isSymbol(car<value>(v))) + return cons(element, cons(n, mklist<value>(valuesToElements(v)))); + + // Convert a nested name value pair value + return cons(element, cons(n, valuesToElements(cdr<value>(t)))); + } + + // Convert a value + if (!isList(t)) + return t; + return valuesToElements(t); +} + +/** + * Convert a list of values to a list of elements. + */ +const list<value> valuesToElements(const list<value>& l) { + if (isNil(l)) + return l; + return cons<value>(valueToElement(car(l)), valuesToElements(cdr(l))); +} + +/** + * Returns a selector lambda function which can be used to filter + * elements against the given element pattern. + */ +struct selectorLambda { + const list<value> select; + selectorLambda(const list<value>& s) : select(s) { + } + const bool evalSelect(const list<value>& s, const list<value> v) const { + if (isNil(s)) + return true; + if (isNil(v)) + return false; + if (car(s) != car(v)) + return false; + return evalSelect(cdr(s), cdr(v)); + } + const bool operator()(const value& v) const { + if (!isList(v)) + return false; + return evalSelect(select, v); + } +}; + +const lambda<bool(value)> selector(const list<value> s) { + return selectorLambda(s); +} + +/** + * Returns the value of the attribute with the given name. + */ +struct filterAttribute { + const value name; + filterAttribute(const value& n) : name(n) { + } + const bool operator()(const value& v) const { + return isAttribute(v) && attributeName((list<value>)v) == name; + } +}; + +const value attributeValue(const value& name, const value& l) { + const list<value> f = filter<value>(filterAttribute(name), list<value>(l)); + if (isNil(f)) + return value(); + return caddr<value>(car(f)); +} + +/** + * Returns child elements with the given name. + */ +struct filterElement { + const value name; + filterElement(const value& n) : name(n) { + } + const bool operator()(const value& v) const { + return isElement(v) && elementName((list<value>)v) == name; + } +}; + +const value elementChildren(const value& name, const value& l) { + return filter<value>(filterElement(name), list<value>(l)); +} + +/** + * Return the child element with the given name. + */ +const value elementChild(const value& name, const value& l) { + const list<value> f = elementChildren(name, l); + if (isNil(f)) + return value(); + return car(f); +} + +} +#endif /* tuscany_element_hpp */ diff --git a/sca-cpp/trunk/kernel/function.hpp b/sca-cpp/trunk/kernel/function.hpp new file mode 100644 index 0000000000..c99ee5dbad --- /dev/null +++ b/sca-cpp/trunk/kernel/function.hpp @@ -0,0 +1,235 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_function_hpp +#define tuscany_function_hpp + +/** + * Lambda function type. + */ + +#include <iostream> +#include "gc.hpp" + +namespace tuscany { + +/** + * 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 printLambdaCounters() { + std::cout << "countLambdas " << countLambdas << std::endl; + std::cout << "countELambdas " << countELambdas << std::endl; + std::cout << "countFLambdas " << countFLambdas << std::endl; + std::cout << "countCLambdas " << countCLambdas << std::endl; + std::cout << "countProxies " << countProxies << std::endl; + std::cout << "countFProxies " << countFProxies << std::endl; + std::cout << "countCProxies " << countCProxies << std::endl; + return true; +} + +/** + * Lambda function type. + */ + +template<typename R, typename... P> class Callable { +public: + Callable() : refCount(0) { + } + + virtual const int size() const = 0; + + virtual const R operator()(P... p) const = 0; + + virtual ~Callable() { + } + + template<typename F> class Proxy: public Callable { + public: + Proxy(const F& f) : function(f) { + countProxies++; + countFProxies ++; + } + + Proxy(const Proxy& p) : function(p.function) { + countProxies++; + countCProxies ++; + } + + ~Proxy() { + countProxies--; + } + + virtual const R operator() (P... p) const { + return function(std::forward<P>(p)...); + } + + virtual const int size() const { + return sizeof(function); + } + + private: + const F function; + }; + +private: + friend class gc_counting_ptr<Callable>; + + unsigned int refCount; + + unsigned int acquire() { + return __sync_add_and_fetch(&refCount, 1); + } + + unsigned int release() { + return __sync_sub_and_fetch(&refCount, 1); + } +}; + +template<typename S> class lambda; + +template<typename R, typename... P> class lambda<R(P...)> { +public: + lambda() : callable(0) { + countLambdas++; + countELambdas++; + } + + template<typename F> lambda(const F f) : callable(0) { + typedef typename CallableType::template Proxy<F> ProxyType; + + countLambdas++; + countFLambdas++; + callable = gc_counting_ptr<CallableType>(new ProxyType(f)); + } + + lambda(const lambda& l) { + countLambdas++; + countCLambdas++; + callable = l.callable; + } + + const lambda& operator=(const lambda& l) { + if (this == &l) + return *this; + callable = l.callable; + return *this; + } + + ~lambda() { + countLambdas--; + } + + const bool operator==(const lambda& l) const { + if (this == &l) + return true; + return callable == l.callable; + } + + const bool operator!=(const lambda& l) const { + return !this->operator==(l); + } + + const R operator()(P... p) const { + return (*callable)(std::forward<P>(p)...); + } + + template<typename S> friend std::ostream& operator<<(std::ostream&, const lambda<S>&); + template<typename S> friend const bool isNil(const lambda<S>& l); + +private: + typedef Callable<R,P...> CallableType; + gc_counting_ptr<CallableType> callable; +}; + +template<typename S> std::ostream& operator<<(std::ostream& out, const lambda<S>& l) { + return out << "lambda::" << l.callable; +} + +/** + * Return true if a lambda is nil. + */ +template<typename S> const bool isNil(const lambda<S>& l) { + return ((void*)l.callable) == 0; +} + +/** + * Curry a lambda function. + */ +template<typename R, typename T, typename... P> class curried { +public: + curried(const lambda<R(T, P...)>& f, const T& v): v(v), f(f) { + } + + const R operator()(P... p) const { + return f(v, std::forward<P>(p)...); + } + +private: + const T v; + const lambda<R(T, P...)>f; +}; + +template<typename R, typename T, typename... P> const lambda<R(P...)> curry(const lambda<R(T, P...)>& f, const T& t) { + return curried<R, T, P...>(f, t); +} + +template<typename R, typename T, typename U, typename... P> const lambda<R(P...)> curry(const lambda<R(T, U, P...)>& f, const T& t, const U& u) { + return curry(curry(f, t), u); +} + +template<typename R, typename T, typename U, typename V, typename... P> const lambda<R(P...)> curry(const lambda<R(T, U, P...)>& f, const T& t, const U& u, const V& v) { + return curry(curry(curry(f, t), u), v); +} + +/** + * A lambda function that returns the given value. + */ +template<typename T> class returnResult { +public: + returnResult(const T& v) : + v(v) { + } + const T operator()() const { + return v; + } +private: + const T v; +}; + +template<typename T> const lambda<T()> result(const T& v) { + return returnResult<T> (v); +} + +} +#endif /* tuscany_function_hpp */ diff --git a/sca-cpp/trunk/kernel/gc.hpp b/sca-cpp/trunk/kernel/gc.hpp new file mode 100644 index 0000000000..7739e714c2 --- /dev/null +++ b/sca-cpp/trunk/kernel/gc.hpp @@ -0,0 +1,404 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_gc_hpp +#define tuscany_gc_hpp + +/** + * Garbage collected pointer. + */ + +#include <apr_general.h> +#include <apr_pools.h> +#include <iostream> + +namespace tuscany +{ + +template<typename T> class gc_ptr { +public: + gc_ptr(T* p = 0) throw() : countingRef(p == 0? 0 : new CountingRef(p)) { + } + + ~gc_ptr() throw() { + release(); + } + + gc_ptr(const gc_ptr& r) throw() : countingRef(r.countingRef) { + acquire(r.countingRef); + } + + gc_ptr& operator=(const gc_ptr& r) throw() { + if(this == &r) + return *this; + acquire(r.countingRef); + release(); + countingRef = r.countingRef; + return *this; + } + + const bool operator==(const gc_ptr& r) const throw() { + if (this == &r) + return true; + if (countingRef == NULL) + return r.countingRef == NULL; + if (r.countingRef == NULL) + return false; + return countingRef-> ptr == r.countingRef->ptr; + } + + const bool operator!=(const gc_ptr& r) const throw() { + return !this->operator ==(r); + } + + T& operator*() const throw() { + return *countingRef->ptr; + } + + T* operator->() const throw() { + return countingRef->ptr; + } + + operator T*() const throw() { + return countingRef->ptr; + } + + template<typename X> friend std::ostream& operator<<(std::ostream&, const gc_ptr<X>&); + +private: + struct CountingRef { + T* ptr; + unsigned count; + + CountingRef(T* p) throw() : + ptr(p), count(1) { + } + }* countingRef; + + void acquire(CountingRef* ref) throw() { + if(ref) + __sync_add_and_fetch(&ref->count, 1); + } + + void release() throw() { + if(countingRef) { + unsigned rc = __sync_sub_and_fetch(&countingRef->count, 1); + if(rc == 0) { + delete countingRef->ptr; + delete countingRef; + } + } + } +}; + +template<typename T> std::ostream& operator<<(std::ostream& out, const gc_ptr<T>& p) { + return out << p.countingRef->ptr; +} + +/** + * Garbage collected pointer to an array. + */ +template<typename T> class gc_aptr { +public: + gc_aptr(T* p = 0) throw() : countingRef(p == 0? 0 : new CountingRef(p)) { + } + + ~gc_aptr() throw() { + release(); + } + + gc_aptr(const gc_aptr& r) throw() : countingRef(r.countingRef) { + acquire(r.countingRef); + } + + gc_aptr& operator=(const gc_aptr& r) throw() { + if(this == &r) + return *this; + acquire(r.countingRef); + release(); + countingRef = r.countingRef; + return *this; + } + + const bool operator==(const gc_aptr& r) const throw() { + if (this == &r) + return true; + if (countingRef == NULL) + return r.countingRef == NULL; + if (r.countingRef == NULL) + return false; + return countingRef-> ptr == r.countingRef->ptr; + } + + const bool operator!=(const gc_aptr& r) const throw() { + return !this->operator ==(r); + } + + T& operator*() const throw() { + return *countingRef->ptr; + } + + T* operator->() const throw() { + return countingRef->ptr; + } + + operator T*() const throw() { + return countingRef->ptr; + } + + template<typename X> friend std::ostream& operator<<(std::ostream&, const gc_aptr<X>&); + +private: + struct CountingRef { + T* ptr; + unsigned count; + + CountingRef(T* p) throw() : + ptr(p), count(1) { + } + }* countingRef; + + void acquire(CountingRef* ref) throw() { + if(ref) + __sync_add_and_fetch(&ref->count, 1); + } + + void release() throw() { + if(countingRef) { + unsigned rc = __sync_sub_and_fetch(&countingRef->count, 1); + if(rc == 0) { + delete[] countingRef->ptr; + delete countingRef; + } + } + } +}; + +template<typename T> std::ostream& operator<<(std::ostream& out, const gc_aptr<T>& p) { + return out << p.countingRef->ptr; +} + +/** + * Garbage collected pointer to a reference counting object. + */ +template<typename T> class gc_counting_ptr { +public: + gc_counting_ptr(T* p = 0) throw() : ptr(p) { + acquire(p); + } + + ~gc_counting_ptr() throw() { + release(); + } + + gc_counting_ptr(const gc_counting_ptr& r) throw() : ptr(r.ptr) { + acquire(ptr); + } + + gc_counting_ptr& operator=(const gc_counting_ptr& r) throw() { + if(this == &r) + return *this; + acquire(r.ptr); + release(); + ptr = r.ptr; + return *this; + } + + const bool operator==(const gc_counting_ptr& r) const throw() { + if (this == &r) + return true; + return ptr == r.ptr; + } + + const bool operator!=(const gc_counting_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; + } + + template<typename X> friend std::ostream& operator<<(std::ostream&, const gc_counting_ptr<X>&); + +private: + T* ptr; + + void acquire(T* p) throw() { + if(p) + p->acquire(); + } + + void release() throw() { + if(ptr) { + if(ptr->release() == 0) { + delete ptr; + } + } + } +}; + +template<typename T> std::ostream& operator<<(std::ostream& out, const gc_counting_ptr<T>& p) { + return out << p.ptr; +} + +/** + * Apache Portable Runtime library context + */ +class APRContext { +public: + APRContext() { + apr_initialize(); + } + ~APRContext() { + apr_terminate(); + } +}; + +APRContext aprContext; + +/** + * Garbage collected memory pool, using an APR pool. + */ +class gc_pool { +public: + gc_pool() : aprPool(new APRPool) { + } + + operator apr_pool_t*() const { + return aprPool->p; + } + +private: + class APRPool { + friend class gc_pool; + friend class gc_counting_ptr<APRPool>; + + unsigned int refCount; + apr_pool_t* p; + + APRPool() : refCount(0) { + apr_pool_create(&p, NULL); + } + + ~APRPool() { + apr_pool_destroy(p); + } + + unsigned int acquire() { + return __sync_add_and_fetch(&refCount, 1); + } + + unsigned int release() { + return __sync_sub_and_fetch(&refCount, 1); + } + }; + + const gc_counting_ptr<APRPool> aprPool; +}; + +/** + * Garbage collected pointer to pooled memory. + */ +template<typename T> class gc_pool_ptr { +public: + gc_pool_ptr(T* ptr = 0) throw() : ptr(ptr) { + } + + ~gc_pool_ptr() throw() { + } + + gc_pool_ptr(const gc_pool_ptr& r) throw() : ptr(r.ptr) { + } + + gc_pool_ptr& operator=(const gc_pool_ptr& r) throw() { + if(this == &r) + return *this; + ptr = r.ptr; + return *this; + } + + const bool operator==(const gc_pool_ptr& r) const throw() { + if (this == &r) + return true; + return ptr == r.ptr; + } + + const bool operator!=(const gc_pool_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; + } + + template<typename X> friend std::ostream& operator<<(std::ostream&, const gc_pool_ptr<X>&); + +private: + T* ptr; +}; + +template<typename T> std::ostream& operator<<(std::ostream& out, const gc_pool_ptr<T>& p) { + return out << p.ptr; +} + +/** + * Cleanup function, called by the APR pool to cleanup registered resources. + * Calls the allocated object's destructor. + */ +template<typename T> apr_status_t gc_pool_cleanupCallback(void* v) { + T* t = static_cast<T*>(v); + t->~T(); + return APR_SUCCESS; +} + +/** + * Returns a pointer to an object allocated from a memory pool. + */ +template<typename T> gc_pool_ptr<T> gc_pool_new(const gc_pool& mp) { + + // Allocate memory from the pool + void* m = apr_palloc(mp, sizeof(T)); + + // Register a cleanup callback + apr_pool_cleanup_register(mp, m, gc_pool_cleanupCallback<T>, apr_pool_cleanup_null) ; + + // Run the requested type's constructor over the allocated memory + return new (m) T(); +} + +} +#endif /* tuscany_gc_hpp */ diff --git a/sca-cpp/trunk/kernel/kernel-test.cpp b/sca-cpp/trunk/kernel/kernel-test.cpp new file mode 100644 index 0000000000..9346e31b71 --- /dev/null +++ b/sca-cpp/trunk/kernel/kernel-test.cpp @@ -0,0 +1,737 @@ +/* + * 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 core utils. + */ + +#include <assert.h> +#include <sys/time.h> +#include <time.h> +#include <iostream> +#include <string> +#include <sstream> +#include "function.hpp" +#include "list.hpp" +#include "slist.hpp" +#include "parallel.hpp" +#include "value.hpp" +#include "element.hpp" +#include "xml.hpp" +#include "monad.hpp" + +namespace tuscany { + +struct inc { + int i; + inc(int i) : + i(i) { + } + const int operator()(const int x) const { + return x + i; + } +}; + +const int square(const int x) { + return x * x; +} + +int mapLambda(lambda<int(int)> f, int v) { + return f(v); +} + +bool testLambda() { + const lambda<int(int)> sq(square); + assert(sq(2) == 4); + assert(mapLambda(sq, 2) == 4); + assert(mapLambda(square, 2) == 4); + + const lambda<int(int)> incf(inc(10)); + assert(incf(1) == 11); + assert(mapLambda(incf, 1) == 11); + assert(mapLambda(inc(10), 1) == 11); + + lambda<int(int)> l; + l = incf; + assert(l(1) == 11); + l = square; + assert(l(2) == 4); + return true; +} + +bool testLambdaGC() { + resetLambdaCounters(); + testLambda(); + assert(countLambdas == 0); + 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; + } +}; + +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 testSet() { + list<int> l = mklist(1, 2, 3); + setCar(l, 4); + setCdr(l, mklist(5, 6)); + assert(car(l) == 4); + assert(cadr(l) == 5); + assert(caddr(l) == 6); + assert(isNil(cdddr(l))); + return true; +} + +bool testListGC() { + resetLambdaCounters(); + resetListCounters(); + countElements = 0; + testCons(); + testSet(); + assert(countLambdas == 0); + assert(countlists == 0); + assert(countElements == 0); + return true; +} + +bool testOut() { + std::ostringstream os1; + os1 << list<int> (); + assert(os1.str() == "()"); + + std::ostringstream os2; + os2 << mklist(1, 2, 3); + assert(os2.str() == "(1 2 3)"); + return true; +} + +bool testEquals() { + assert(list<int>() == list<int>()); + assert(mklist(1, 2) == mklist(1, 2)); + assert(list<int>() != mklist(1, 2)); + assert(mklist(1, 2, 3) == mklist(1, 2, 3)); + assert(mklist(1, 2) != mklist(1, 2, 3)); + return true; +} + +bool testLength() { + assert(0 == length(list<int>())); + assert(1 == length(mklist(1))); + assert(2 == length(cons(1, mklist(2)))); + return true; +} + +bool testAppend() { + assert(car(append(mklist(1), mklist(2))) == 1); + assert(car(cdr(append(mklist(1), mklist(2)))) == 2); + assert(car(cdr(cdr(append(mklist(1), mklist(2, 3))))) == 3); + assert(isNil(cdr(cdr(cdr(append(mklist(1), mklist(2, 3))))))); + + list<int> l; + l << 1 << 2 << 3; + assert(l == mklist(1, 2, 3)); + assert(list<int>() << 1 << 2 << 3 == mklist(1, 2, 3)); + return true; +} + +struct Complex { + int x; + int y; + Complex() { + } + Complex(int x, int y) : + x(x), y(y) { + } +}; + +bool testComplex() { + const list<Complex> p = mklist(Complex(1, 2), Complex(3, 4)); + assert(car(p).x == 1); + assert(car(cdr(p)).x == 3); + assert(isNil(cdr(cdr(p)))); + return true; +} + +bool testMap() { + assert(isNil(map<int, int>(square, list<int>()))); + + const list<int> m = map<int, int>(square, mklist(2, 3)); + assert(car(m) == 4); + assert(car(cdr(m)) == 9); + + return true; +} + +const int add(const int x, const int y) { + return x + y; +} + +bool testReduce() { + const lambda<int(int, int)> r(add); + assert(reduce(r, 0, mklist(1, 2, 3)) == 6); + return true; +} + +bool isPositive(int x) { + if(x >= 0) + return true; + else + return false; +} + +bool testFilter() { + assert(car(filter<int>(isPositive, mklist(1, -1, 2, -2))) == 1); + assert(cadr(filter<int>(isPositive, mklist(1, -1, 2, -2))) == 2); + return true; +} + +bool testMember() { + assert(isNil(member(4, mklist(1, 2, 3)))); + assert(car(member(1, mklist(1, 2, 3))) == 1); + assert(car(member(2, mklist(1, 2, 3))) == 2); + assert(car(member(3, mklist(1, 2, 3))) == 3); + return true; +} + +bool testReverse() { + assert(isNil(reverse(list<int>()))); + assert(car(reverse(mklist(1, 2, 3))) == 3); + assert(cadr(reverse(mklist(1, 2, 3))) == 2); + return true; +} + +bool testListRef() { + assert(listRef(mklist(1), 0) == 1); + assert(listRef(mklist(1, 2, 3), 0) == 1); + assert(listRef(mklist(1, 2, 3), 1) == 2); + assert(listRef(mklist(1, 2, 3), 2) == 3); + return true; +} + +bool testAssoc() { + const list<list<std::string> > l = mklist(mklist<std::string>("x", "X"), mklist<std::string>("a", "A"), mklist<std::string>("y", "Y"), mklist<std::string>("a", "AA")); + assert(assoc<std::string>("a", l) == mklist<std::string>("a", "A")); + assert(isNil(assoc<std::string>("z", l))); + + const list<list<value> > u = mklist(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"), mklist<value>("a", "AA")); + assert(assoc<value>("a", u) == mklist<value>("a", "A")); + + const list<value> v = mklist<value>(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"), mklist<value>("a", "AA")); + assert(assoc<value>("a", v) == mklist<value>("a", "A")); + return true; +} + +bool testZip() { + const list<std::string> k = mklist<std::string>("x", "a", "y", "a"); + const list<std::string> v = mklist<std::string>("X", "A", "Y", "AA"); + const list<list<std::string> > z = mklist(k, v); + const list<list<std::string> > u = mklist(mklist<std::string>("x", "X"), mklist<std::string>("a", "A"), mklist<std::string>("y", "Y"), mklist<std::string>("a", "AA")); + assert(zip(k, v) == u); + assert(unzip(u) == z); + return true; +} + +bool testTokenize() { + assert(tokenize("/", "aaa/bbb/ccc/ddd") == mklist<std::string>("aaa", "bbb", "ccc", "ddd")); + assert(tokenize("/", "/bbb/ccc/ddd") == mklist<std::string>("", "bbb", "ccc", "ddd")); + assert(tokenize("/", "/bbb/ccc/") == mklist<std::string>("", "bbb", "ccc")); + assert(tokenize("/", "/bbb//ccc/") == mklist<std::string>("", "bbb", "", "ccc")); + assert(tokenize("/", "abc/def/") == mklist<std::string>("abc", "def")); + return true; +} + +double testSeqMap(double x) { + return x; +} + +double testSeqReduce(double v, double accum) { + return accum + 1.0; +} + +bool testSeq() { + resetLambdaCounters(); + resetListCounters(); + + list<double> s = seq(0.0, 1000.0); + assert(1001 == length(s)); + //printLambdaCounters(); + //printListCounters(); + + assert(1001 == length(map<double, double>(testSeqMap, s))); + + assert(801 == length(member(200.0, s))); + assert(201 == length(member(200.0, reverse(s)))); + + assert(1001 == (reduce<double, double>(testSeqReduce, 0.0, s))); + //printLambdaCounters(); + //printListCounters(); + + return true; +} + +value valueSquare(list<value> x) { + return (int)car(x) * (int)car(x); +} + +bool testValue() { + assert(value(true) == value(true)); + assert(value(1) == value(1)); + assert(value("abcd") == value("abcd")); + lambda<value(list<value>&)> vl(valueSquare); + assert(value(vl) == value(vl)); + assert(value(mklist<value>(1, 2)) == value(mklist<value>(1, 2))); + + const list<value> v = mklist<value>(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y")); + assert(cadr((list<list<value> >)value(v)) == mklist<value>("a", "A")); + + const value pv(gc_ptr<value>(new value(1))); + assert(*(gc_ptr<value>)pv == value(1)); + + const list<value> lpv = mklist<value>(gc_ptr<value>(new value(1)), gc_ptr<value>(new value(2))); + assert(*(gc_ptr<value>)car(lpv) == value(1)); + *(gc_ptr<value>)cadr(lpv) = value(3); + assert(*(gc_ptr<value>)cadr(lpv) == value(3)); + return true; +} + +bool testValueGC() { + resetLambdaCounters(); + resetListCounters(); + resetValueCounters(); + testValue(); + assert(countValues == 0); + assert(countLambdas == 0); + assert(countlists == 0); + 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); +} + +bool testCppPerf() { + struct timeval start; + struct timeval end; + { + gettimeofday(&start, NULL); + + list<double> s = seq(0.0, 999.0); + list<double> r = map<double, double>(fib, s); + assert(1000 == length(r)); + + gettimeofday(&end, NULL); + //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + //std::cout << "Fib cpp function map perf test " << t << " ms" << std::endl; + } + + { + struct nested { + static double fib(double n) { + struct nested { + static double fib_aux(double n, double a, double b) { + if(n == 0.0) + return a; + return fib_aux(n - 1.0, b, a + b); + } + }; + return nested::fib_aux(n, 0.0, 1.0); + } + }; + + gettimeofday(&start, NULL); + + list<double> s = seq(0.0, 999.0); + list<double> r = map(lambda<double(double)>(nested::fib), s); + assert(1000 == length(r)); + + gettimeofday(&end, NULL); + //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + //std::cout << "Fib cpp nested function map perf test " << t << " ms" << std::endl; + } + return true; +} + +bool testAtomicPerf() { + struct timeval start; + struct timeval end; + { + gettimeofday(&start, NULL); + for(int i = 0; i < 10000000;) + i = i + 1; + gettimeofday(&end, NULL); + //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + //std::cout << "Loop test " << t << " ms" << std::endl; + } + { + gettimeofday(&start, NULL); + for(int i = 0; i < 10000000;) + __sync_add_and_fetch(&i, 1); + gettimeofday(&end, NULL); + //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + //std::cout << "Loop atomic test " << t << " ms" << std::endl; + } + { + pthread_mutex_t mutex; + pthread_mutex_init(&mutex, NULL); + gettimeofday(&start, NULL); + for(int i = 0; i < 10000000;) { + pthread_mutex_lock(&mutex); + i = i + 1; + pthread_mutex_unlock(&mutex); + } + gettimeofday(&end, NULL); + pthread_mutex_destroy(&mutex); + //long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); + //std::cout << "Loop mutex test " << t << " ms" << std::endl; + } + return true; +} + +const int mtsquare(const int x) { + //std::cout << "thread " << threadId() << " mtsquare(" << x << ")\n"; + for(int i = 0; i < 10000000; i++) + ; + return x * x; +} + +bool testWorker() { + worker w(10); + { + const lambda<int()> func = curry(lambda<int(int)> (mtsquare), 2); + assert(submit(w, func) == 4); + } + { + const int max = 10; + + list<future<int> > r; + for(int i = 0; i < max; i++) { + const lambda<int()> func = curry(lambda<int(int)> (mtsquare), i); + r = cons(submit(w, func), r); + } + for(int i = max - 1; i >= 0; i--) { + assert(car(r) == i * i); + r = cdr(r); + } + } + shutdown(w); + return true; +} + +const std::string currencyXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<composite xmlns=\"http://docs.oasis-open.org/ns/opencsa/sca/200903\" " +"xmlns:t=\"http://tuscany.apache.org/xmlns/sca/1.1\" " +"targetNamespace=\"http://services\" " +"name=\"currency\">" +"<component name=\"CurrencyConverterWebService\">" +"<implementation.java class=\"services.CurrencyConverterImpl\"/>" +"<service name=\"CurrencyConverter\">" +"<binding.ws/>" +"</service>" +"</component>" +"<component name=\"CurrencyConverterWebService2\">" +"<implementation.java class=\"services.CurrencyConverterImpl2\"/>" +"<service name=\"CurrencyConverter2\">" +"<binding.atom/>" +"</service>" +"<property name=\"currency\">US</property>" +"</component>" +"</composite>" +"\n"; + +const std::string customerXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<customer>" +"<name>jdoe</name>" +"<address><city>san francisco</city><state>ca</state></address>" +"<account><id>1234</id><balance>1000</balance></account>" +"<account><id>6789</id><balance>2000</balance></account>" +"<account><id>4567</id><balance>3000</balance></account>" +"</customer>" +"\n"; + + +const bool isName(const value& token) { + return isTaggedList(token, attribute) && attributeName(token) == "name"; +} + +bool testReadXML() { + { + std::istringstream is(customerXML); + const list<value> c = readXML(streamList(is)); + } + { + std::istringstream is(currencyXML); + const list<value> c = readXML(streamList(is)); + + const value composite = car(c); + assert(isTaggedList(composite, element)); + assert(elementName(composite) == "composite"); + assert(attributeValue(car(filter<value>(isName, elementChildren(composite)))) == std::string("currency")); + } + return true; +} + +std::ostringstream* xmlWriter(const std::string& s, std::ostringstream* os) { + (*os) << s; + return os; +} + +bool testWriteXML() { + { + std::istringstream is(customerXML); + const list<value> c = readXML(streamList(is)); + std::ostringstream os; + writeXML<std::ostringstream*>(xmlWriter, &os, c); + assert(os.str() == customerXML); + } + { + std::istringstream is(currencyXML); + const list<value> c = readXML(streamList(is)); + std::ostringstream os; + writeXML<std::ostringstream*>(xmlWriter, &os, c); + assert(os.str() == currencyXML); + } + return true; +} + +bool testElement() { + { + const list<value> ad = mklist<value>(mklist<value>("city", std::string("san francisco")), mklist<value>("state", std::string("ca"))); + const list<value> ac1 = mklist<value>(mklist<value>("id", std::string("1234")), mklist<value>("balance", 1000)); + const list<value> ac2 = mklist<value>(mklist<value>("id", std::string("6789")), mklist<value>("balance", 2000)); + const list<value> ac3 = mklist<value>(mklist<value>("id", std::string("4567")), mklist<value>("balance", 3000)); + { + const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", std::string("jdoe")), cons<value>("address", ad), mklist<value>("account", mklist<value>(ac1, ac2, ac3)))); + const list<value> e = valuesToElements(c); + const list<value> v = elementsToValues(e); + assert(v == c); + + std::ostringstream os; + writeXML<std::ostringstream*>(xmlWriter, &os, e); + assert(os.str() == customerXML); + } + { + const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", std::string("jdoe")), cons<value>("address", ad), cons<value>("account", ac1), cons<value>("account", ac2), cons<value>("account", ac3))); + const list<value> e = valuesToElements(c); + const list<value> v = elementsToValues(e); + + std::ostringstream os; + writeXML<std::ostringstream*>(xmlWriter, &os, e); + assert(os.str() == customerXML); + } + } + { + std::istringstream is(customerXML); + const list<value> c = readXML(streamList(is)); + const list<value> v = elementsToValues(c); + const list<value> e = valuesToElements(v); + std::ostringstream os; + writeXML<std::ostringstream*>(xmlWriter, &os, e); + assert(os.str() == customerXML); + } + return true; +} + +const id<int> idF(const int v) { + return v * 2; +} + +const id<int> idG(const int v) { + return v * 3; +} + +const id<int> idH(const int v) { + return idF(v) >> idG; +} + +bool testIdMonad() { + const id<int> m(2); + assert(m >> idF == idF(2)); + assert(m >> unit<int>() == m); + assert(m >> idF >> idG == m >> idH); + return true; +} + +const maybe<int> maybeF(const int v) { + return v * 2; +} + +const maybe<int> maybeG(const int v) { + return v * 3; +} + +const maybe<int> maybeH(const int v) { + return maybeF(v) >> maybeG; +} + +bool testMaybeMonad() { + const maybe<int> m(2); + assert(m >> maybeF == maybeF(2)); + assert((m >> just<int>()) == m); + assert(m >> maybeF >> maybeG == m >> maybeH); + + assert(maybe<int>() >> maybeF >> maybeG == maybe<int>()); + return true; +} + +const failable<int, std::string> failableF(const int v) { + return v * 2; +} + +const failable<int, std::string> failableG(const int v) { + return v * 3; +} + +const failable<int, std::string> failableH(const int v) { + return failableF(v) >> failableG; +} + +bool testFailableMonad() { + const failable<int, std::string> m(2); + assert(m >> failableF == failableF(2)); + assert((m >> success<int, std::string>()) == m); + assert(m >> failableF >> failableG == m >> failableH); + + failable<int, std::string> ooops = mkfailure<int, std::string>("ooops"); + assert(reason(ooops) == "ooops"); + assert(ooops >> failableF >> failableG == ooops); + return true; +} + +struct tickInc { + const double v; + tickInc(const double v) : v(v) { + } + const svp<int, double> operator()(int s) const { + return svp<int, double>(s + 1, v); + } +}; + +const state<int, double> tick(const double v) { + return transformer<int, double>(tickInc(v)); +} + +const state<int, double> stateF(const double v) { + return result<int, double>(v * 2.0) >> tick; +} + +const state<int, double> stateG(const double v) { + return result<int, double>(v + 5); +} + +const state<int, double> stateH(const double v) { + return stateF(v) >> stateG; +} + +bool testStateMonad() { + const lambda<state<int, double>(double)> r(result<int, double>); + + state<int, double> m = result<int, double>(2.0); + assert((m >> stateF)(0) == stateF(2.0)(0)); + assert(1 == (int)(m >> stateF)(0)); + assert((m >> r)(0) == m(0)); + assert((m >> stateF >> stateG)(0) == (m >> stateH)(0)); + + return true; +} + +} + +int main() { + std::cout << "Testing..." << std::endl; + + tuscany::testLambda(); + tuscany::testLambdaGC(); + tuscany::testCons(); + tuscany::testSet(); + 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::testElement(); + tuscany::testCppPerf(); + tuscany::testAtomicPerf(); + tuscany::testWorker(); + tuscany::testReadXML(); + tuscany::testWriteXML(); + tuscany::testIdMonad(); + tuscany::testMaybeMonad(); + tuscany::testFailableMonad(); + tuscany::testStateMonad(); + + std::cout << "OK" << std::endl; + + return 0; +} diff --git a/sca-cpp/trunk/kernel/list.hpp b/sca-cpp/trunk/kernel/list.hpp new file mode 100644 index 0000000000..c21efe173b --- /dev/null +++ b/sca-cpp/trunk/kernel/list.hpp @@ -0,0 +1,484 @@ +/* + * 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 <iostream> +#include "function.hpp" + +namespace tuscany { + +long countlists = 0; +long countIlists = 0; +long countClists = 0; +long countElists = 0; + +bool resetListCounters() { + countlists = countIlists = countClists = countElists = 0; + return true; +} + +bool printListCounters() { + std::cout << "countlists " << countlists << std::endl; + std::cout << "countElists " << countElists << std::endl; + std::cout << "countIlists " << countIlists << std::endl; + std::cout << "countClists " << countClists << std::endl; + return true; +} + +/** + * A car/cdr lisp-like pair, base structure to construct lists. + */ + +template<typename T> class list { +public: + + list() { + countlists++; + countElists++; + } + + list(const T car, const lambda<list<T> ()>& cdr) : + car(car), cdr(cdr) { + countlists++; + countIlists++; + } + + list(const list& p) : + car(p.car), cdr(p.cdr) { + countlists++; + countClists++; + } + + const list& operator=(const list<T>& p) { + if(this == &p) + return *this; + car = p.car; + cdr = p.cdr; + return *this; + } + + ~list() { + countlists--; + } + + const bool operator==(const list<T>& p) const { + if(this == &p) + return true; + if(isNil(cdr)) + return isNil(p.cdr); + if(isNil(p.cdr)) + return false; + if(!(car == p.car)) + return false; + if(cdr == p.cdr) + return true; + return cdr() == p.cdr(); + } + + const bool operator!=(const list<T>& p) const { + return !this->operator==(p); + } + + operator const list<list<T> >() const { + return (list<list<T> >)T(*this); + } + + list<T>& operator<<(const T& v) { + *this = append(*this, mklist(v)); + return *this; + } + + template<typename X> friend const bool isNil(const list<X>& p); + template<typename X> friend const X car(const list<X>& p); + template<typename X> friend const list<X> cdr(const list<X>& p); + template<typename X> friend const bool setCar(list<X>& p, const X& car); + template<typename X> friend const bool setCdr(list<X>& p, const list<X>& cdr); + template<typename X> friend const bool setCdr(list<X>& p, const lambda<list<X> ()>& cdr); + +private: + T car; + lambda<list<T> ()> cdr; +}; + +/** + * Returns true if the given list is nil. + */ +template<typename T> const bool isNil(const list<T>& p) { + return isNil(p.cdr); +} + +/** + * Write a list to an output stream. + */ +template<typename T> std::ostream& operator<<(std::ostream& out, const list<T>& l) { + if(isNil(l)) + return out << "()"; + out << "("; + list<T> ml = l; + while(true) { + out << car(ml); + ml = cdr(ml); + if (isNil(ml)) + break; + out << " "; + } + return out << ")"; +} + +/** + * Construct a (lazy) list from a value and a lambda function that returns the cdr. + */ +template<typename T> const list<T> cons(const T& car, const lambda<list<T> ()>& cdr) { + return list<T> (car, cdr); +} + +/** + * Construct a list from a value and a cdr list. + */ +template<typename T> const list<T> cons(const T& car, const list<T>& cdr) { + return list<T> (car, result(cdr)); +} + +/** + * Cons variations for use with the reduce and reduceRight functions. + */ +template<typename T> const list<T> lcons(const list<T>& cdr, const T& car) { + return cons<T>(car, cdr); +} + +template<typename T> const list<T> rcons(const T& car, const list<T>& cdr) { + return cons<T>(car, cdr); +} + +/** + * Construct a list of one value. + */ +template<typename T> const list<T> mklist(const T& car) { + return list<T> (car, result(list<T> ())); +} + +/** + * Construct a list of two values. + */ +template<typename T> const list<T> mklist(const T& a, const T& b) { + return cons(a, mklist(b)); +} + +/** + * Construct a list of three values. + */ +template<typename T> const list<T> mklist(const T& a, const T& b, const T& c) { + return cons(a, cons(b, mklist(c))); +} + +/** + * Construct a list of four values. + */ +template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d) { + return cons(a, cons(b, cons(c, mklist(d)))); +} + +/** + * Construct a list of five values. + */ +template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e) { + return cons(a, cons(b, cons(c, cons(d, mklist(e))))); +} + +/** + * Construct a list of six values. + */ +template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f) { + return cons(a, cons(b, cons(c, cons(d, cons(e, mklist(f)))))); +} + +/** + * Returns the car of a list. + */ +template<typename T> const T car(const list<T>& p) { + return p.car; +} + +/** + * Returns the cdr of a list. + */ +template<typename T> const list<T> cdr(const list<T>& p) { + return p.cdr(); +} + +/** + * Sets the car of a list. + */ +template<typename T> const bool setCar(list<T>& p, const T& car) { + p.car = car; + return true; +} + +/** + * Sets the cdr of a list. + */ +template<typename T> const bool setCdr(list<T>& p, const list<T>& c) { + p.cdr = result(c); + return true; +} + +/** + * Sets the cdr of a list to a lambda function. + */ +template<typename T> const bool setCdr(list<T>& p, const lambda<list<T> ()>& cdr) { + p.cdr = cdr; + return true; +} + + +/** + * Returns the car of the cdr of a list. + */ +template<typename T> const T cadr(const list<T>& p) { + return car(cdr(p)); +} + +/** + * Returns the car of the cdr of the cdr of a list. + */ +template<typename T> const T caddr(const list<T>& p) { + return car(cdr(cdr(p))); +} + +/** + * Returns the cdr of a cdr of a list. + */ +template<typename T> const list<T> cddr(const list<T>& p) { + return cdr(cdr(p)); +} + +/** + * Returns the cdr of a cdr of the cdr of a list. + */ +template<typename T> const list<T> cdddr(const list<T>& p) { + return cdr(cdr(cdr(p))); +} + +/** + * Returns the length of a list. + */ +template<typename T> struct lengthRef { + const int operator()(const int c, const list<T>& p) { + if(isNil(p)) + return c; + return (*this)(c + 1, cdr(p)); + } +}; + +template<typename T> const int length(const list<T>& p) { + return lengthRef<T> ()(0, p); +} + +/** + * Appends a list and a lambda function returning a list. + */ +template<typename T> struct appendCdr { + const list<T> a; + const lambda<list<T> ()> fb; + appendCdr(const list<T>& a, const lambda<list<T> ()>& fb) : + a(a), fb(fb) { + } + const list<T> operator()() const { + return append(a, fb); + } +}; + +template<typename T> const list<T> append(const list<T>&a, const lambda<list<T> ()>& fb) { + if(isNil(a)) + return fb(); + + return cons<T>(car(a), appendCdr<T> (cdr(a), fb)); +} + +/** + * Appends two lists. + */ +template<typename T> const list<T> append(const list<T>&a, const list<T>& b) { + return append(a, result(b)); +} + +/** + * Map a lambda function on a list. + */ +template<typename T, typename R> const list<R> map(const lambda<R(T)>& f, const list<T>& p) { + if(isNil(p)) + return list<R> (); + return cons(f(car(p)), map(f, cdr(p))); +} + +/** + * Run a reduce lambda function on a list. + */ +template<typename T, typename R> struct reduceAccumulate { + const lambda<R(R, T)> f; + reduceAccumulate(const lambda<R(R, T)>& f) : + f(f) { + } + R operator()(const R& acc, const list<T>& p) const { + if(isNil(p)) + return acc; + return (*this)(f(acc, car(p)), cdr(p)); + } +}; + +template<typename T, typename R> const R reduce(const lambda<R(R, T)>& f, const R& initial, const list<T>& p) { + return reduceAccumulate<T, R> (f)(initial, p); +} + +template<typename T, typename R> struct reduceRightAccumulate { + const lambda<R(T, R)> f; + reduceRightAccumulate(const lambda<R(T, R)>& f) : + f(f) { + } + R operator()(const list<T>& p, const R& acc) const { + if(isNil(p)) + return acc; + return (*this)(cdr(p), f(car(p), acc)); + } +}; + +template<typename T, typename R> const R reduceRight(const lambda<R(T, R)>& f, const R& initial, const list<T>& p) { + return reduceRightAccumulate<T, R> (f)(p, initial); +} + +/** + * Run a filter lambda function on a list. + */ +template<typename T> const list<T> filter(const lambda<bool(T)>& f, const list<T>& p) { + if(isNil(p)) + return list<T> (); + if(f(car(p))) { + const lambda<list<T> (lambda<bool(T)> , list<T> )> ff(filter<T> ); + return cons(car(p), curry(ff, f, cdr(p))); + } + return filter(f, cdr(p)); +} + +/** + * Returns a list pointing to a member of a list. + */ +template<typename T> const list<T> member(const T& t, const list<T>& p) { + if(isNil(p)) + return list<T> (); + if(t == car(p)) + return p; + return member(t, cdr(p)); +} + +/** + * Reverse a list. + */ +template<typename T> const list<T> reverseIter(const list<T>& acc, const list<T>& p) { + if(isNil(p)) + return acc; + return reverseIter(cons(car(p), acc), cdr(p)); +} + +template<typename T> const list<T> reverse(const list<T>& p) { + return reverseIter(list<T> (), p); +} + +template<typename T> const list<T> seq(const T& start, const T& end); + +template<typename T> struct seqGenerate { + const T start; + const T end; + seqGenerate(const T& start, const T&end) : + start(start), end(end) { + } + const list<T> operator()() const { + return seq<T> (start, end); + } +}; + +/** + * Returns a sequence of values between the given bounds. + */ +template<typename T> const list<T> seq(const T& start, const T& end) { + if(start == end) + return mklist(start); + if(start < end) + return cons<T>(start, seqGenerate<T> (start + 1, end)); + return cons<T>(start, seqGenerate<T> (start - 1, end)); +} + +/** + * Returns the i-th element of a list. + */ +template<typename T> const T listRef(const list<T>& l, const 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<typename T> const list<T> assoc(const T& k, const list<list<T> >& p) { + if(isNil(p)) + return list<T> (); + if(k == car(car(p))) + return car(p); + return assoc(k, cdr(p)); +} + +/** + * Returns a list of lists containing elements from two input lists. + */ +template<typename T> const list<list<T> > zip(const list<T>& a, const list<T>& b) { + if (isNil(a) || isNil(b)) + return list<list<T> >(); + return cons<list<T> >(mklist<T>(car(a), car(b)), zip(cdr(a), cdr(b))); +} + +/** + * Converts a list of key value pairs to a list containing the list of keys and the list of values. + */ +template<typename T> const list<T> unzipKeys(const list<list<T> >& l) { + if (isNil(l)) + return list<T>(); + return cons(car(car(l)), unzipKeys(cdr(l))); +} + +template<typename T> const list<T> unzipValues(const list<list<T> >& l) { + if (isNil(l)) + return list<T>(); + return cons(cadr(car(l)), unzipValues(cdr(l))); +} + +template<typename T> const list<list<T> > unzip(const list<list<T> >& l) { + return mklist<list<T> >(unzipKeys(l), unzipValues(l)); +} + +} + +#endif /* tuscany_list_hpp */ diff --git a/sca-cpp/trunk/kernel/monad.hpp b/sca-cpp/trunk/kernel/monad.hpp new file mode 100644 index 0000000000..98eb3799c0 --- /dev/null +++ b/sca-cpp/trunk/kernel/monad.hpp @@ -0,0 +1,455 @@ +/* + * 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 <string> +#include <iostream> +#include "function.hpp" + +namespace tuscany +{ + +/** + * Identity monad. Just wraps a value. + * To get the value in the monad, just cast it to the value type. + */ +template<typename V> class id { +public: + id(const V& v) : v(v) { + } + + operator const V() const { + return v; + } + + const id<V>& operator=(const id<V>& m) { + if(this == &m) + return *this; + v = m.v; + return *this; + } + + const bool operator!=(const id<V>& m) const { + return !this->operator==(m); + } + + const bool operator==(const id<V>& m) const { + if (&m == this) + return true; + return v == m.v; + } + +private: + const V v; +}; + +/** + * Write an identity monad to a stream. + */ +template<typename V> std::ostream& operator<<(std::ostream& out, const id<V>& m) { + out << (V)m; + return out; +} + +/** + * Return an identity monad from a value. + */ +template<typename V> const id<V> mkunit(const V& v) { + return id<V>(v); +} + +template<typename V> const lambda<id<V>(V)> unit() { + return mkunit<V>; +} + +/** + * Bind a function to an identity monad. Pass the value in the monad to the function. + */ +template<typename R, typename V> const id<R> operator>>(const id<V>& m, const lambda<id<R>(V)>& f) { + return f(m); +} + +template<typename R, typename V> const id<R> operator>>(const id<V>& m, const id<R> (* const f)(const V)) { + return f(m); +} + +/** + * Maybe monad. Used to represent an optional value, which may be there or not. + * To get the value in the monad, just cast it to the value type. + */ +template<typename V> class maybe { +public: + maybe(const V& v) : hasv(true), v(v) { + } + + maybe() : hasv(false) { + } + + operator const V() const { + return v; + } + + const maybe<V>& operator=(const maybe<V>& m) { + if(this == &m) + return *this; + hasv = m.hasv; + if (hasv) + v = m.v; + return *this; + } + + const bool operator!=(const maybe<V>& m) const { + return !this->operator==(m); + } + + const bool operator==(const maybe<V>& m) const { + if (this == &m) + return true; + if (!hasv) + return !m.hasv; + return m.hasv && v == m.v; + } + +private: + const bool hasv; + V v; + + template<typename A> friend const bool hasValue(const maybe<A>& m); +}; + +/** + * Write a maybe monad to a stream. + */ +template<typename V> std::ostream& operator<<(std::ostream& out, const maybe<V>& m) { + if (!hasValue(m)) { + out << "nothing"; + return out; + } + out << (V)m; + return out; +} + +/** + * Return a maybe monad with a value in it. + */ +template<typename V> const maybe<V> mkjust(const V& v) { + return maybe<V>(v); +} + +template<typename V> const lambda<maybe<V>(V)> just() { + return mkjust<V>; +} + +/** + * Returns true if the monad contains a value. + */ +template<typename V> const bool hasValue(const maybe<V>& m) { + return m.hasv; +} + +/** + * Bind a function to a maybe monad. Passes the value in the monad to the function + * if present, or does nothing if there's no value. + */ +template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const lambda<maybe<R>(V)>& f) { + if (!hasValue(m)) + return m; + return f(m); +} + +template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const maybe<R> (* const f)(const V)) { + if (!hasValue(m)) + return m; + return f(m); +} + +/** + * Failable monad. Used to represent either a success value or a failure. + * To get the value in the monad, just cast it to the value type. + * To get the failure in the monad, cast it to the failure type. + */ +template<typename V, typename F> class failable { +public: + failable() : hasv(false) { + } + + failable(const V& v) : hasv(true), v(v) { + } + + failable(const failable<V, F>& m) : hasv(m.hasv) { + if (hasv) + v = m.v; + else + f = m.f; + } + + operator const V() const { + return v; + } + + const failable<V, F>& operator=(const failable<V, F>& m) { + if(this == &m) + return *this; + hasv = m.hasv; + if (hasv) + v = m.v; + else + f = m.f; + return *this; + } + + const bool operator!=(const failable<V, F>& m) const { + return !this->operator==(m); + } + + const bool operator==(const failable<V, F>& m) const { + if (this == &m) + return true; + if (!hasv) + return !m.hasv && f == m.f; + return m.hasv && v == m.v; + } + +private: + bool hasv; + V v; + F f; + + failable(const bool hasv, const F& f) : hasv(hasv), f(f) { + } + + template<typename A, typename B> friend const bool hasValue(const failable<A, B>& m); + template<typename A, typename B> friend const B reason(const failable<A, B>& m); + template<typename A, typename B> friend const failable<A, B> mkfailure(const B& f); +}; + +/** + * Write a failable monad to a stream. + */ +template<typename V, typename F> std::ostream& operator<<(std::ostream& out, const failable<V, F>& m) { + if (!hasValue(m)) { + out << reason(m); + return out; + } + const V v = m; + out << v; + return out; +} + +/** + * Returns a failable monad with a success value in it. + */ +template<typename V, typename F> const failable<V, F> mksuccess(const V& v) { + return failable<V, F>(v); +} + +template<typename V, typename F> const lambda<failable<V, F>(V)> success() { + return mksuccess<V, F>; +} + +/** + * Returns a failable monad with a failure in it. + */ +template<typename V, typename F> const failable<V, F> mkfailure(const F& f) { + return failable<V, F>(false, f); +} + +template<typename V, typename F> const lambda<failable<V, F>(V)> failure() { + return mkfailure<V, F>; +} + +/** + * Returns true if the monad contains a value. + */ +template<typename V, typename F> const bool hasValue(const failable<V, F>& m) { + return m.hasv; +} + +/** + * Returns the reason for failure of a failable monad. + */ +template<typename V, typename F> const F reason(const failable<V, F>& 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<typename R, typename FR, typename V, typename FV> +const failable<R, FR> operator>>(const failable<V, FV>& m, const lambda<failable<R, FR>(V)>& f) { + if (!hasValue(m)) + return m; + return f(m); +} + +template<typename R, typename FR, typename V, typename FV> +const failable<R, FR> operator>>(const failable<V, FV>& m, const failable<R, FR> (* const f)(const V)) { + if (!hasValue(m)) + return m; + return f(m); +} + +/** + * State + value pair data type used by the state monad. + */ +template<typename S, typename V> class svp { +public: + svp(const S& s, const V& v) : s(s), v(v) { + } + + operator const S() const { + return s; + } + + operator const V() const { + return v; + } + + const svp<S, V>& operator=(const svp<S, V>& p) { + if(this == &p) + return *this; + s = p.s; + v = p.v; + return *this; + } + + const bool operator!=(const svp<S, V>& p) const { + return !this->operator==(p); + } + + const bool operator==(const svp<S, V>& p) const { + if (this == &p) + return true; + return s == p.s && v == p.v; + } + +private: + const S s; + const V v; +}; + +/** + * State monad. Used to represent the combination of a state and a value. + * To get the state in the monad, just cast it to the state type. + * To get the value in the monad, just cast it to the value type. + */ +template<typename S, typename V> class state { +public: + state(const lambda<svp<S, V>(S)>& f) : f(f) { + } + + const svp<S, V> operator()(const S& s) const { + return f(s); + } + + const state<S, V>& operator=(const state<S, V>& m) { + if(this == &m) + return *this; + f = m.f; + return *this; + } + + const bool operator!=(const state<S, V>& m) const { + return !this->operator==(m); + } + + const bool operator==(const state<S, V>& m) const { + if (this == &m) + return true; + return f == m.f; + } + +private: + const lambda<svp<S, V>(S)> f; +}; + +/** + * Write a state monad to a stream. + */ +template<typename S, typename V> std::ostream& operator<<(std::ostream& out, const state<S, V>& m) { + const S s = m; + const V v = m; + out << '(' << s << ' ' << v << ')'; + return out; +} + +/** + * Return a state monad carrying a result value. + */ +template<typename S, typename V> struct returnState { + const V v; + returnState(const V& v) : v(v) { + } + const svp<S, V> operator()(const S& s) const { + return svp<S, V>(s, v); + } +}; + +template<typename S, typename V> const state<S, V> result(const V& v) { + return state<S, V>(returnState<S, V>(v)); +} + +/** + * Return a state monad with a transformer function. + * A transformer function takes a state and returns an svp pair carrying a value and a + * new (transformed) state. + */ +template<typename S, typename V> const state<S, V> transformer(const lambda<svp<S, V>(S)>& f) { + return state<S, V>(f); +} + +/** + * Bind a function to a state monad. The function takes a value and returns a state + * monad carrying a return value. + */ +template<typename S, typename A, typename B> struct stateBind { + const state<S, A> st; + const lambda<state<S, B>(A)>f; + + stateBind(const state<S, A>& st, const lambda<state<S, B>(A)>& f) : st(st), f(f) { + } + + const svp<S, B> operator()(const S& is) const { + const svp<S, A> iscp = st(is); + const state<S, B> m = f((A)iscp); + return m((S)iscp); + } +}; + +template<typename S, typename A, typename B> +const state<S, B> operator>>(const state<S, A>& st, const lambda<state<S, B>(A)>& f) { + return state<S, B>(stateBind<S, A , B>(st, f)); +} + +template<typename S, typename A, typename B> +const state<S, B> operator>>(const state<S, A>& st, const state<S, B> (* const f)(const A)) { + return state<S, B>(stateBind<S, A , B>(st, f)); +} + +} +#endif /* tuscany_monad_hpp */ diff --git a/sca-cpp/trunk/kernel/parallel.hpp b/sca-cpp/trunk/kernel/parallel.hpp new file mode 100644 index 0000000000..c2a948bbeb --- /dev/null +++ b/sca-cpp/trunk/kernel/parallel.hpp @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_parallel_hpp +#define tuscany_parallel_hpp + +/** + * Simple parallel work execution functions. + */ + +#include <pthread.h> +#include <sys/syscall.h> +#include "function.hpp" + +namespace tuscany { + +/** + * Returns the current thread id. + */ +unsigned int threadId() { + return syscall(__NR_gettid); +} + +/** + * Represents a value which will be know in the future. + */ +template<typename T> class future { + +private: + template<typename X> class futureValue { + public: + futureValue() : + refCount(0), hasValue(false) { + pthread_mutex_init(&valueMutex, NULL); + pthread_cond_init(&valueCond, NULL); + } + + ~futureValue() { + pthread_mutex_destroy(&valueMutex); + pthread_cond_destroy(&valueCond); + } + + unsigned int acquire() { + return __sync_add_and_fetch(&refCount, 1); + } + + unsigned int release() { + return __sync_sub_and_fetch(&refCount, 1); + } + + 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: + unsigned refCount; + pthread_mutex_t valueMutex; + pthread_cond_t valueCond; + bool hasValue; + X value; + }; + + gc_counting_ptr<futureValue<T> > fvalue; + + template<typename X> friend const X get(const future<X>& f); + template<typename X> friend bool set(const future<X>& f, const X& v); + +public: + future() : fvalue(new futureValue<T>()) { + //std::cout << "future() threadId " << threadId() << "\n"; + } + + ~future() { + //std::cout << "~future() threadId " << threadId() << "\n"; + } + + future(const future& f) : fvalue(f.fvalue) { + //std::cout << "future(const future& f) threadId " << threadId() << "\n"; + } + + const future& operator=(const future& f) { + //std::cout << "future::operator=(const future& f) threadId " << threadId() << "\n"; + if (&f == this) + return *this; + fvalue = f.fvalue; + return *this; + } + + const future& operator=(const T& v) const { + fvalue->set(v); + return *this; + } + + operator const T() const { + return fvalue->get(); + } + +}; + +/** + * A bounded thread safe queue. + */ +template<typename T> class queue { +public: + queue(int max) : max(max), size(0), tail(0), head(0), values(new T[max]) { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&full, NULL); + pthread_cond_init(&empty, NULL); + } + + ~queue() { + 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_aptr<T> values; + + template<typename X> friend const int enqueue(queue<X>& q, const X& v); + template<typename X> friend const X dequeue(queue<X>& q); +}; + +/** + * Adds an element to the tail of the queue. + */ +template<typename T> const int enqueue(queue<T>&q, const T& v) { + pthread_mutex_lock(&q.mutex); + while(q.size == q.max) + pthread_cond_wait(&q.full, &q.mutex); + q.values[q.tail] = v; + q.tail = (q.tail + 1) % q.max; + q.size++; + pthread_mutex_unlock(&q.mutex); + pthread_cond_broadcast(&q.empty); + return q.size; +} + +/** + * Returns the element at the head of the queue. + */ +template<typename T> const T dequeue(queue<T>& q) { + pthread_mutex_lock(&q.mutex); + while(q.size == 0) + pthread_cond_wait(&q.empty, &q.mutex); + const T v = q.values[q.head]; + q.head = (q.head + 1) % q.max; + q.size--; + pthread_mutex_unlock(&q.mutex); + pthread_cond_broadcast(&q.full); + return v; +} + +/** + * The worker thread function. + */ +void *workerThreadFunc(void *arg) { + queue<lambda<bool()> >* work = reinterpret_cast<queue<lambda<bool()> >*>(arg); + while(dequeue(*work)()) + ; + return NULL; +} + +/** + * Returns a list of worker threads. + */ +const list<pthread_t> workerThreads(queue<lambda<bool()> >& queue, const int count) { + if (count == 0) + return list<pthread_t>(); + pthread_t thread; + pthread_create(&thread, NULL, workerThreadFunc, &queue); + return cons(thread, workerThreads(queue, count - 1)); +} + +/** + * A worker, implemented with a work queue and a pool of threads. + */ +class worker { +public: + worker(int max) : work(queue<lambda<bool()> >(max)), threads(workerThreads(work, max)) { + } + +private: + queue<lambda<bool()> > work; + const list<pthread_t> threads; + + template<typename X> friend const future<X> submit(worker& w, const lambda<X()>& func); + friend const bool shutdown(worker& w); +}; + +/** + * Function used to wrap work submitted to a worker. + */ +template<typename R> bool submitFunc(const lambda<R()>& func, const future<R>& fut) { + fut = func(); + return true; +} + +/** + * Submits work to a worker. + */ +template<typename R> const future<R> submit(worker& w, const lambda<R()>& func) { + const future<R> fut; + const lambda<bool()> f = curry(lambda<bool(lambda<R()>, future<R>)>(submitFunc<R>), func, fut); + enqueue(w.work, f); + return fut; +} + +/** + * Enqueues shutdown requests. + */ +const bool shutdownEnqueue(const list<pthread_t>& threads, queue<lambda<bool()> >& work) { + if (isNil(threads)) + return true; + enqueue(work, result(false)); + return shutdownEnqueue(cdr(threads), work); +} + +/** + * Waits for shut down threads to terminate. + */ +const bool shutdownJoin(const list<pthread_t>& threads) { + if (isNil(threads)) + return true; + pthread_join(car(threads), NULL); + return shutdownJoin(cdr(threads)); +} + +/** + * Shutdown a worker. + */ +const bool shutdown(worker& w) { + shutdownEnqueue(w.threads, w.work); + shutdownJoin(w.threads); + return true; +} + +} +#endif /* tuscany_parallel_hpp */ diff --git a/sca-cpp/trunk/kernel/slist.hpp b/sca-cpp/trunk/kernel/slist.hpp new file mode 100644 index 0000000000..705152cb29 --- /dev/null +++ b/sca-cpp/trunk/kernel/slist.hpp @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_slist_hpp +#define tuscany_slist_hpp + +/** + * Useful functions to work with lists of strings and character streams. + */ + +#include <iostream> +#include <string> +#include "function.hpp" +#include "list.hpp" + +namespace tuscany { + +/** + * Tokenize a string into a list of strings. + */ +const list<std::string> tokenize(const std::string& sep, const std::string& str) { + struct nested { + static const list<std::string> tokenize(const std::string& sep, const std::string& str, const unsigned int start = 0) { + if (start >= str.length()) + return list<std::string>(); + const unsigned int i = str.find_first_of(sep, start); + if (i == std::string::npos) + return mklist(str.substr(start)); + return cons(str.substr(start, i - start), tokenize(sep, str, i + 1)); + } + }; + return nested::tokenize(sep, str, 0); +} + +/** + * Returns a lazy list view of an input stream. + */ +struct ilistRead{ + std::istream &is; + ilistRead(std::istream& is) : is(is) { + } + const list<std::string> operator()() { + char buffer[1024]; + is.read(buffer, 1024); + const int n = is.gcount(); + if (n ==0) + return list<std::string>(); + return cons(std::string(buffer, n), (*this)()); + } +}; + +const list<std::string> streamList(std::istream& is) { + return ilistRead(is)(); +} + +/** + * Fragment the first element of a list of strings to fit the given max length. + */ +const list<std::string> fragment(list<std::string> l, unsigned int max) { + const std::string s = car(l); + if (s.length() <= max) + return l; + return cons(s.substr(0, max), cons(s.substr(max), cdr(l))); +} + +/** + * Write a list of strings to an output stream. + */ +std::ostream& write(const list<std::string>& l, std::ostream& os) { + if(isNil(l)) + return os; + os << car(l); + return write(cdr(l), os); +} + +} + +#endif /* tuscany_slist_hpp */ diff --git a/sca-cpp/trunk/kernel/value.hpp b/sca-cpp/trunk/kernel/value.hpp new file mode 100644 index 0000000000..d602b30623 --- /dev/null +++ b/sca-cpp/trunk/kernel/value.hpp @@ -0,0 +1,491 @@ +/* + * 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 <string> +#include <iostream> +#include <sstream> +#include "gc.hpp" +#include "function.hpp" +#include "list.hpp" + +namespace tuscany +{ + +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 printValueCounters() { + std::cout << "countValues " << countValues << std::endl; + std::cout << "countEValues " << countEValues << std::endl; + std::cout << "countCValues " << countCValues << std::endl; + std::cout << "countVValues " << countVValues << std::endl; + return true; +} + +class value; + +class value { +public: + + enum ValueType { + Undefined, Symbol, String, List, Number, Bool, Char, Lambda, Ptr, PoolPtr + }; + + value() : + type(value::Undefined) { + countValues++; + countEValues++; + } + + value(const value& v) { + countValues++; + 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::Char: + chr() = v.chr(); + case value::Ptr: + ptr() = v.ptr(); + case value::PoolPtr: + poolptr() = v.poolptr(); + default: + break; + } + } + + 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::Char: + chr() = v.chr(); + case value::Ptr: + ptr() = v.ptr(); + case value::PoolPtr: + poolptr() = v.poolptr(); + default: + break; + } + return *this; + } + + virtual ~value() { + countValues--; + } + + value(const lambda<value(list<value>&)>& func) : + type(value::Lambda), data(vdata(func)) { + countValues++; + countVValues++; + } + + value(const std::string& str) : + type(value::String), data(vdata(result(str))) { + countValues++; + countVValues++; + } + + value(const char* str) : + type(value::Symbol), data(vdata(result(std::string(str)))) { + countValues++; + countVValues++; + } + + value(const list<value>& lst) : + type(value::List), data(vdata(result(lst))) { + countValues++; + countVValues++; + } + + value(const list<list<value> >& l) : + type(value::List), data(vdata(result(listOfValues(l)))) { + countValues++; + countVValues++; + } + + value(const double num) : + type(value::Number), data(vdata(result(num))) { + countValues++; + countVValues++; + } + + value(const int num) : + type(value::Number), data(vdata(result((double)num))) { + countValues++; + countVValues++; + } + + value(const bool boo) : + type(value::Bool), data(vdata(result(boo))) { + countValues++; + countVValues++; + } + + value(const char chr) : + type(value::Char), data(vdata(result(chr))) { + countValues++; + countVValues++; + } + + value(const gc_ptr<value> ptr) : + type(value::Ptr), data(vdata(result(ptr))) { + countValues++; + countVValues++; + } + + value(const gc_pool_ptr<value> ptr) : + type(value::PoolPtr), data(vdata(result(ptr))) { + countValues++; + countVValues++; + } + + const bool operator!=(const value& v) const { + return !this->operator==(v); + } + + const bool operator==(const value& v) const { + if(this == &v) + return true; + if(type != v.type) + return false; + switch(type) { + case value::Undefined: + return true; + case value::List: + return lst()() == v.lst()(); + case value::Lambda: + return func() == v.func(); + case value::Symbol: + return str()() == v.str()(); + case value::String: + return str()() == v.str()(); + case value::Number: + return num()() == v.num()(); + case value::Bool: + return boo()() == v.boo()(); + case value::Char: + return chr()() == v.chr()(); + case value::Ptr: + return ptr()() == v.ptr()(); + case value::PoolPtr: + return poolptr()() == v.poolptr()(); + default: + return false; + } + } + + const value operator()(list<value>& args) const { + return func()(args); + } + + operator const std::string() const { + switch(type) { + case value::List: + case value::Lambda: + case value::Ptr: + case value::PoolPtr: + return ""; + case value::Symbol: + case value::String: + return str()(); + case value::Number: { + std::ostringstream sos; + sos << num()(); + return sos.str(); + } + case value::Bool: { + if(boo()()) + return "true"; + else + return "false"; + } + case value::Char: { + std::ostringstream sos; + sos << chr()(); + return sos.str(); + } + default: + return ""; + } + } + + operator const double() const { + return num()(); + } + + operator const int() const { + return num()(); + } + + operator const bool() const { + return boo()(); + } + + operator const char() const { + return chr()(); + } + + operator const gc_ptr<value>() const { + return ptr()(); + } + + operator const gc_pool_ptr<value>() const { + return poolptr()(); + } + + operator const list<value>() const { + return lst()(); + } + + operator const list<list<value> >() const { + return listOfListOfValues(lst()()); + } + + operator const lambda<value(list<value>&)>() const { + return func(); + } + + friend std::ostream& operator<<(std::ostream&, const value&); + + ValueType type; + lambda<char()> data; + +private: + template<typename T> lambda<T>& vdata() const { + return *reinterpret_cast<lambda<T> *> (const_cast<lambda<char()> *> (&data)); + } + + template<typename T> const lambda<char()>& vdata(const T& v) const { + return *reinterpret_cast<const lambda<char()> *> (&v); + } + + lambda<double()>& num() const { + return vdata<double()> (); + } + + lambda<bool()>& boo() const { + return vdata<bool()> (); + } + + lambda<char()>& chr() const { + return vdata<char()> (); + } + + lambda<gc_ptr<value>()>& ptr() const { + return vdata<gc_ptr<value>()> (); + } + + lambda<gc_pool_ptr<value>()>& poolptr() const { + return vdata<gc_pool_ptr<value>()> (); + } + + lambda<std::string()>& str() const { + return vdata<std::string()> (); + } + + lambda<list<value>()>& lst() const { + return vdata<list<value>()> (); + } + + lambda<value(list<value>&)>& func() const { + return vdata<value(list<value>&)> (); + } + + const list<value> listOfValues(const list<list<value> >& l) const { + if (isNil(l)) + return list<value>(); + return cons<value>(car(l), listOfValues(cdr(l))); + } + + const list<list<value> > listOfListOfValues(const list<value>& l) const { + if (isNil(l)) + return list<list<value> >(); + return cons<list<value> >(list<value>(car(l)), listOfListOfValues(cdr(l))); + } + +}; + +/** + * Write a value to a stream. + */ +std::ostream& operator<<(std::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::Char: + return out << v.chr()(); + case value::Ptr: { + const gc_ptr<value> p = v.ptr()(); + if (p == gc_ptr<value>(NULL)) + return out << "pointer::null"; + return out << "pointer::" << *p; + } + case value::PoolPtr: { + const gc_pool_ptr<value> p = v.poolptr()(); + if (p == gc_pool_ptr<value>(NULL)) + return out << "pointer::null"; + return out << "pointer::" << *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& value) { + return value.type == value::Undefined; +} + +/** + * Returns true if a value is a lambda. + */ +const bool isLambda(const value& value) { + return value.type == value::Lambda; +} + +/** + * Returns true if a value is a string. + */ +const bool isString(const value& value) { + return value.type == value::String; +} + +/** + * Returns true if a value is a symbol. + */ +const bool isSymbol(const value& value) { + return value.type == value::Symbol; +} + +/** + * Returns true if a value is a list. + */ +const bool isList(const value& value) { + return value.type == value::List; +} + +/** + * Returns true if a value is a number. + */ +const bool isNumber(const value& value) { + return value.type == value::Number; +} + +/** + * Returns true if a value is a boolean. + */ +const bool isBool(const value& value) { + return value.type == value::Bool; +} + +/** + * Returns true if a value is a character. + */ +const bool isChar(const value& value) { + return value.type == value::Char; +} + +/** + * Returns true if a value is a pointer. + */ +const bool isPtr(const value& value) { + return value.type == value::Ptr; +} + +/** + * Returns true if a value is a pooled pointer. + */ +const bool isPoolPtr(const value& value) { + return value.type == value::PoolPtr; +} + +/** + * Returns true if a value is a tagged list. + */ +const bool isTaggedList(const value& exp, value tag) { + if(isList(exp) && !isNil((list<value>)exp)) + return car((list<value>)exp) == tag; + return false; +} + +} +#endif /* tuscany_value_hpp */ diff --git a/sca-cpp/trunk/kernel/xml.hpp b/sca-cpp/trunk/kernel/xml.hpp new file mode 100644 index 0000000000..8d561557ca --- /dev/null +++ b/sca-cpp/trunk/kernel/xml.hpp @@ -0,0 +1,364 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_xml_hpp +#define tuscany_xml_hpp + +/** + * XML read/write functions. + */ + +#include <libxml/xmlreader.h> +#include <libxml/xmlwriter.h> +#include <libxml/xmlschemas.h> +#include <libxml/globals.h> +#include <string> +#include "list.hpp" +#include "slist.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" + +namespace tuscany { + +/** + * Initializes the libxml2 library. + */ +class XMLParser { +public: + XMLParser() { + xmlInitParser(); + } + + ~XMLParser() { + xmlCleanupParser(); + } +}; + +XMLParser xmlParser; + +/** + * Encapsulates a libxml2 xmlTextReader and its state. + */ +class XMLReader { +public: + enum TokenType { + None = 0, Element = 1, Attribute = 2, Text = 3, EndElement = 15, Identifier = 100, End = 101 + }; + + XMLReader(xmlTextReaderPtr xml) : xml(xml), 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 std::string(val); +} + +/** + * Read an XML attribute. + */ +const value readAttribute(XMLReader& reader) { + const char *name = (const char*)xmlTextReaderConstName(reader); + const char *val = (const char*)xmlTextReaderConstValue(reader); + return mklist<value>(attribute, name, std::string(val)); +} + +/** + * Read an XML token. + */ +const value readToken(XMLReader& reader) { + const int tokenType = reader.read(); + if (tokenType == XMLReader::None || tokenType == XMLReader::End) + return value(); + if (tokenType == XMLReader::Element) + return startElement; + if (tokenType == XMLReader::Identifier) + return readIdentifier(reader); + if (tokenType == XMLReader::Attribute) + return readAttribute(reader); + if (tokenType == XMLReader::Text) + return readText(reader); + if (tokenType == XMLReader::EndElement) + return endElement; + return readToken(reader); +} + +/** + * Read a list of values from XML tokens. + */ +const list<value> readList(const list<value>& listSoFar, XMLReader& reader) { + const value token = readToken(reader); + if(isNil(token) || endElement == token) + return reverse(listSoFar); + if(startElement == token) + return readList(cons<value>(readList(mklist(element), reader), listSoFar), reader); + return readList(cons(token, listSoFar), reader); +} + +/** + * Read a list of values from a libxml2 XML reader. + */ +const list<value> read(XMLReader& reader) { + value nextToken = readToken(reader); + if (startElement == nextToken) + return mklist<value>(readList(mklist(element), reader)); + return list<value>(); +} + +/** + * Context passed to the read callback function. + */ +class XMLReadContext { +public: + XMLReadContext(const list<std::string>& ilist) : ilist(ilist) { + } + list<std::string> ilist; +}; + +/** + * Callback function called by libxml2 to read XML. + */ +int readCallback(void *context, char* buffer, int len) { + XMLReadContext& rc = *static_cast<XMLReadContext*>(context); + if (isNil(rc.ilist)) + return 0; + rc.ilist = fragment(rc.ilist, len); + std::string s = car(rc.ilist); + rc.ilist = cdr(rc.ilist); + s.copy(buffer, s.length()); + return s.length(); +} + +/** + * Read a list values from a list of strings representing an XML document. + */ +const list<value> readXML(const list<std::string>& ilist) { + XMLReadContext cx(ilist); + xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET); + if (xml == NULL) + return list<value>(); + XMLReader reader(xml); + return read(reader); +} + +/** + * Default encoding used to write XML documents. + */ +const char* encoding = "UTF-8"; + + +/** + * Write a list of XML element or attribute tokens. + */ +const list<value> expandElementValues(const value& n, const list<value>& l) { + if (isNil(l)) + return l; + return cons<value>(value(cons<value>(element, cons<value>(n, (list<value>)car(l)))), expandElementValues(n, cdr(l))); +} + +const failable<bool, std::string> writeList(const list<value>& l, const xmlTextWriterPtr xml) { + if (isNil(l)) + return true; + + // Write an attribute + const value token(car(l)); + if (isTaggedList(token, attribute)) { + if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)std::string(attributeName(token)).c_str(), (const xmlChar*)std::string(attributeValue(token)).c_str()) < 0) + return mkfailure<bool, std::string>("xmlTextWriterWriteAttribute failed"); + + } else if (isTaggedList(token, element)) { + + // Write an element containing a value + if (elementHasValue(token)) { + const value v = elementValue(token); + if (isList(v)) { + + // Write an element per entry in a list of values + const list<value> e = expandElementValues(elementName(token), v); + writeList(e, xml); + + } else { + + // Write an element with a single value + if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0) + return mkfailure<bool, std::string>("xmlTextWriterStartElement failed"); + + // Write its children + const failable<bool, std::string> w = writeList(elementChildren(token), xml); + if (!hasValue(w)) + return w; + + if (xmlTextWriterEndElement(xml) < 0) + return mkfailure<bool, std::string>("xmlTextWriterEndElement failed"); + } + } + else { + + // Write an element + if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0) + return mkfailure<bool, std::string>("xmlTextWriterStartElement failed"); + + // Write its children + const failable<bool, std::string> w = writeList(elementChildren(token), xml); + if (!hasValue(w)) + return w; + + if (xmlTextWriterEndElement(xml) < 0) + return mkfailure<bool, std::string>("xmlTextWriterEndElement failed"); + } + } else { + + // Write XML text + if (xmlTextWriterWriteString(xml, (const xmlChar*)std::string(token).c_str()) < 0) + return mkfailure<bool, std::string>("xmlTextWriterWriteString failed"); + + } + + // Go on + return writeList(cdr(l), xml); +} + +/** + * Write a list of values to a libxml2 XML writer. + */ +const failable<bool, std::string> write(const list<value>& l, const xmlTextWriterPtr xml) { + if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0) + return mkfailure<bool, std::string>("xmlTextWriterStartDocument failed"); + + const failable<bool, std::string> w = writeList(l, xml); + if (!hasValue(w)) + return w; + + if (xmlTextWriterEndDocument(xml) < 0) + return mkfailure<bool, std::string>("xmlTextWriterEndDocument failed"); + return true; +} + +/** + * Context passed to the write callback function. + */ +template<typename R> class XMLWriteContext { +public: + XMLWriteContext(const lambda<R(std::string, R)>& reduce, const R& accum) : reduce(reduce), accum(accum) { + } + const lambda<R(std::string, R)> reduce; + R accum; +}; + +/** + * Callback function called by libxml2 to write XML out. + */ +template<typename R> int writeCallback(void *context, const char* buffer, int len) { + XMLWriteContext<R>& cx = *static_cast<XMLWriteContext<R>*>(context); + cx.accum = cx.reduce(std::string(buffer, len), cx.accum); + return len; +} + +/** + * Convert a list of values to an XML document. + */ +template<typename R> const failable<R, std::string> writeXML(const lambda<R(std::string, R)>& reduce, const R& initial, const list<value>& l) { + XMLWriteContext<R> cx(reduce, initial); + xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback<R>, NULL, &cx, NULL); + if (out == NULL) + return mkfailure<R, std::string>("xmlOutputBufferCreateIO failed"); + xmlTextWriterPtr xml = xmlNewTextWriter(out); + if (xml == NULL) + return mkfailure<R, std::string>("xmlNewTextWriter failed"); + + const failable<bool, std::string> w = write(l, xml); + xmlFreeTextWriter(xml); + if (!hasValue(w)) { + return mkfailure<R, std::string>(reason(w)); + } + return cx.accum; +} + +/** + * Convert a list of values to a list of strings representing an XML document. + */ +const failable<list<std::string>, std::string> writeXML(const list<value>& l) { + const failable<list<std::string>, std::string> ls = writeXML<list<std::string> >(rcons<std::string>, list<std::string>(), l); + if (!hasValue(ls)) + return ls; + return reverse(list<std::string>(ls)); +} + +} +#endif /* tuscany_xml_hpp */ diff --git a/sca-cpp/trunk/kernel/xsd-test.cpp b/sca-cpp/trunk/kernel/xsd-test.cpp new file mode 100644 index 0000000000..818c03ba68 --- /dev/null +++ b/sca-cpp/trunk/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 <iostream> +#include <string> +#include <libxml/xmlreader.h> +#include <libxml/xmlschemas.h> + +namespace tuscany { + +bool printNode(xmlTextReaderPtr reader) { + const xmlChar* name = xmlTextReaderConstName(reader); + if(name == NULL) + name = (xmlChar *)"<unknown>"; + const xmlChar* value = xmlTextReaderConstValue(reader); + std::cout << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " " + << xmlTextReaderIsEmptyElement(reader) << " " << xmlTextReaderHasValue(reader); + if(value == NULL) + std::cout << std::endl; + else + std::cout << value << std::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) { + std::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); + + std::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) + std::cout << "Could not validate document" << std::endl; + xmlFreeTextReader(reader); + if(rc != 0) + std::cout << "Could not parse document" << std::endl; + } else + std::cout << "Could not create parser" << std::endl; + } else + std::cout << "Could not open document" << std::endl; + + xmlSchemaFreeValidCtxt(validctx); + xmlSchemaFree(xsd); + xmlSchemaFreeParserCtxt(xsdctx); + + return true; +} + +} + +int main(int argc, char **argv) { + std::cout << "Testing..." << std::endl; + if(argc != 3) + return 1; + + tuscany::readFile(argv[1], argv[2]); + + xmlCleanupParser(); + + std::cout << "OK" << std::endl; + return 0; +} |