From 95fa76f5f3208d913320c13a05171ecdcd7134c2 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sat, 2 Jan 2010 10:27:26 +0000 Subject: Performance improvements when running both in multi-threaded and pre-forked HTTPD. Changed memory management to use Apache APR pools instead of ref counting pointers as it's much faster and easier to integrate with the Python and Ruby interpreters. Changed to use simple pool-based string and stream implementations instead of the STL ones, which cause a lots of mutex locks in a multi-threaded environment. Added build options to compile with threading and profiling. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@895165 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/kernel/Makefile.am | 14 +- sca-cpp/trunk/kernel/debug.hpp | 27 +-- sca-cpp/trunk/kernel/dynlib.hpp | 25 +- sca-cpp/trunk/kernel/element.hpp | 4 +- sca-cpp/trunk/kernel/fstream.hpp | 152 +++++++++++++ sca-cpp/trunk/kernel/function.hpp | 40 ++-- sca-cpp/trunk/kernel/gc.hpp | 405 ++++++++++----------------------- sca-cpp/trunk/kernel/kernel-test.cpp | 122 +++++----- sca-cpp/trunk/kernel/list.hpp | 110 ++++----- sca-cpp/trunk/kernel/mem-test.cpp | 162 +++++++++++++ sca-cpp/trunk/kernel/monad.hpp | 49 ++-- sca-cpp/trunk/kernel/parallel-test.cpp | 55 +++-- sca-cpp/trunk/kernel/parallel.hpp | 32 +-- sca-cpp/trunk/kernel/slist.hpp | 96 -------- sca-cpp/trunk/kernel/sstream.hpp | 234 +++++++++++++++++++ sca-cpp/trunk/kernel/stream.hpp | 148 ++++++++++++ sca-cpp/trunk/kernel/string-test.cpp | 196 ++++++++++++++++ sca-cpp/trunk/kernel/string.hpp | 288 +++++++++++++++++++++++ sca-cpp/trunk/kernel/tree.hpp | 4 +- sca-cpp/trunk/kernel/value.hpp | 184 ++++++++------- sca-cpp/trunk/kernel/xml-test.cpp | 69 +++--- sca-cpp/trunk/kernel/xml.hpp | 83 ++++--- sca-cpp/trunk/kernel/xsd-test.cpp | 26 +-- 23 files changed, 1707 insertions(+), 818 deletions(-) create mode 100644 sca-cpp/trunk/kernel/fstream.hpp create mode 100644 sca-cpp/trunk/kernel/mem-test.cpp delete mode 100644 sca-cpp/trunk/kernel/slist.hpp create mode 100644 sca-cpp/trunk/kernel/sstream.hpp create mode 100644 sca-cpp/trunk/kernel/stream.hpp create mode 100644 sca-cpp/trunk/kernel/string-test.cpp create mode 100644 sca-cpp/trunk/kernel/string.hpp (limited to 'sca-cpp/trunk/kernel') diff --git a/sca-cpp/trunk/kernel/Makefile.am b/sca-cpp/trunk/kernel/Makefile.am index 4dfc285e90..507454439a 100644 --- a/sca-cpp/trunk/kernel/Makefile.am +++ b/sca-cpp/trunk/kernel/Makefile.am @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -noinst_PROGRAMS = kernel-test parallel-test xml-test xsd-test +noinst_PROGRAMS = string-test kernel-test mem-test parallel-test xml-test xsd-test testdir=$(prefix)/test test_LTLIBRARIES = libdynlib-test.la @@ -25,12 +25,18 @@ include_HEADERS = *.hpp INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${APR_INCLUDE} -kernel_test_SOURCES = kernel-test.cpp -kernel_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 +string_test_SOURCES = string-test.cpp +string_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 libdynlib_test_la_SOURCES = dynlib-test.cpp libdynlib_test_la_LIBADD = -L${APR_LIB} -lapr-1 -laprutil-1 +kernel_test_SOURCES = kernel-test.cpp +kernel_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 + +mem_test_SOURCES = mem-test.cpp +mem_test_LDADD = -L${APR_LIB} -lapr-1 -laprutil-1 + parallel_test_SOURCES = parallel-test.cpp parallel_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 @@ -40,4 +46,4 @@ xml_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 xsd_test_SOURCES = xsd-test.cpp xsd_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -TESTS = kernel-test parallel-test xml-test +TESTS = string-test kernel-test mem-test parallel-test xml-test diff --git a/sca-cpp/trunk/kernel/debug.hpp b/sca-cpp/trunk/kernel/debug.hpp index c06fe55f4a..c51ee6c974 100644 --- a/sca-cpp/trunk/kernel/debug.hpp +++ b/sca-cpp/trunk/kernel/debug.hpp @@ -23,24 +23,15 @@ #define tuscany_debug_hpp /** - * Functions to help log and debug. + * Debug functions and macros. */ -#include -#include - namespace tuscany { #ifdef _DEBUG -/** - * Debug log. - */ -template const bool debug(const V& v, const std::string& msg) { - std::cerr << msg << ": " << v << std::endl; - return true; -} +//#define _DEBUG_WATCH /** * Increment / decrement a debug counter. @@ -55,20 +46,18 @@ bool debug_dec(long int& c) { return true; } -/** - * Attribute used to mark unused parameters. - */ -#define unused __attribute__ ((unused)) - #else -#define debug(v, msg) - #define debug_inc(c) #define debug_dec(c) -#define unused +#endif +/** + * Attribute used to mark unused parameters. + */ +#ifndef unused +#define unused __attribute__ ((unused)) #endif } diff --git a/sca-cpp/trunk/kernel/dynlib.hpp b/sca-cpp/trunk/kernel/dynlib.hpp index 10a5a030cb..a000653455 100644 --- a/sca-cpp/trunk/kernel/dynlib.hpp +++ b/sca-cpp/trunk/kernel/dynlib.hpp @@ -38,9 +38,9 @@ namespace tuscany { * OS specific dynamic library file extension. */ #ifdef IS_DARWIN -const std::string dynlibExt(".dylib"); +const string dynlibExt(".dylib"); #else -const std::string dynlibExt(".so"); +const string dynlibExt(".so"); #endif /** @@ -51,7 +51,7 @@ public: lib() : dl(NULL) { } - lib(const std::string& name) : dl(new DynLib(name)) { + lib(const string& name) : dl(new (gc_new()) DynLib(name)) { } ~lib() { @@ -60,41 +60,42 @@ public: private: class DynLib { public: - DynLib(const std::string& name) : name(name), h(dlopen(name.c_str(), RTLD_NOW)) { + DynLib(const string& name) : name(name), h(dlopen(c_str(name), RTLD_NOW)) { } + ~DynLib() { if (h == NULL) return; dlclose(h); } - const std::string name; + const string name; void* h; }; gc_ptr dl; - friend const failable dynlib(const std::string& name); - template friend const failable, std::string> dynlambda(const std::string& name, const lib& l); + friend const failable dynlib(const string& name); + template friend const failable > dynlambda(const string& name, const lib& l); }; /** * Load a dynamic library. */ -const failable dynlib(const std::string& name) { +const failable dynlib(const string& name) { const lib l(name); if (l.dl->h == NULL) - return mkfailure("Could not load library: " + name + ": " + dlerror()); + return mkfailure(string("Could not load library: ") + name + ": " + dlerror()); return l; } /** * Find a lambda function in a dynamic library. */ -template const failable, std::string> dynlambda(const std::string& name, const lib& l) { - const void* s = dlsym(l.dl->h, name.c_str()); +template const failable > dynlambda(const string& name, const lib& l) { + const void* s = dlsym(l.dl->h, c_str(name)); if (s == NULL) - return mkfailure, std::string>(std::string("Could not load symbol: " + name)); + return mkfailure >(string("Could not load symbol: ") + name); return lambda((S*)s); } diff --git a/sca-cpp/trunk/kernel/element.hpp b/sca-cpp/trunk/kernel/element.hpp index 612752d1df..4570110e96 100644 --- a/sca-cpp/trunk/kernel/element.hpp +++ b/sca-cpp/trunk/kernel/element.hpp @@ -98,7 +98,7 @@ const value elementHasValue(const list& l) { const list r = reverse(l); if (isSymbol(car(r))) return false; - if(isList(car(r)) && isSymbol(car(car(r)))) + if(isList(car(r)) && !isNil((list)car(r)) && isSymbol(car(car(r)))) return false; return true; } @@ -201,7 +201,7 @@ const value valueToElement(const value& t) { return mklist(element, n, v); // Convert a list value - if (!isSymbol(car(v))) + if (isNil((list)v) || !isSymbol(car(v))) return cons(element, cons(n, mklist(valuesToElements(v)))); // Convert a nested name value pair value diff --git a/sca-cpp/trunk/kernel/fstream.hpp b/sca-cpp/trunk/kernel/fstream.hpp new file mode 100644 index 0000000000..3d6b1edade --- /dev/null +++ b/sca-cpp/trunk/kernel/fstream.hpp @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_fstream_hpp +#define tuscany_fstream_hpp + +/** + * File based streams. + */ + +#include +#include +#include "string.hpp" +#include "stream.hpp" + +namespace tuscany { + +/* + * Output stream backed by a FILE. + */ +class ofstream : public ostream { +public: + ofstream(const string& path) : file(fopen(c_str(path), "wb")), owned(true) { + } + + ofstream(FILE* file) : file(file), owned(false) { + } + + ofstream(const ofstream& os) : file(os.file), owned(false) { + } + + ~ofstream() { + if (!owned) + return; + if (file == NULL) + return; + fclose(file); + } + + ofstream& vprintf(const char* fmt, ...) { + va_list args; + va_start (args, fmt); + vfprintf (file, fmt, args); + va_end (args); + return *this; + } + + ofstream& flush() { + fflush(file); + return *this; + } + +private: + FILE* file; + bool owned; +}; + +/* + * Input stream backed by a FILE. + */ +class ifstream : public istream { +public: + ifstream(const string& path) : file(fopen(c_str(path), "rb")), owned(true) { + } + + ifstream(FILE* file) : file(file), owned(false) { + } + + ifstream(const ifstream& is) : file(is.file), owned(false) { + } + + ~ifstream() { + if (!owned) + return; + if (file == NULL) + return; + fclose(file); + } + + const int read(void* buf, int size) { + return fread(buf, 1, size, file); + } + + const bool eof() { + return feof(file); + } + + const bool fail() { + return file == NULL; + } + + const int get() { + return fgetc(file); + } + + const int peek() { + int c = fgetc(file); + if (c == -1) + return c; + ungetc(c, file); + return c; + } + +private: + FILE* file; + bool owned; +}; + +/** + * Standard streams. + */ +ofstream cout(stdout); +ofstream cerr(stderr); +ifstream cin(stdin); + +/** + * Debug log stream. + */ +#ifdef _DEBUG + +template const bool debug(const V& v, const string& msg) { + cerr << msg << ": " << v << endl; + return true; +} + +#else + +#define debug(v, msg) + +#endif + +} + +#endif /* tuscany_fstream_hpp */ diff --git a/sca-cpp/trunk/kernel/function.hpp b/sca-cpp/trunk/kernel/function.hpp index 54784b5549..26f566fde6 100644 --- a/sca-cpp/trunk/kernel/function.hpp +++ b/sca-cpp/trunk/kernel/function.hpp @@ -26,7 +26,8 @@ * Lambda function type. */ -#include +#include +#include "fstream.hpp" #include "gc.hpp" #include "debug.hpp" @@ -55,13 +56,13 @@ bool checkLambdaCounters() { } 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; + cout << "countLambdas " << countLambdas << endl; + cout << "countELambdas " << countELambdas << endl; + cout << "countFLambdas " << countFLambdas << endl; + cout << "countCLambdas " << countCLambdas << endl; + cout << "countProxies " << countProxies << endl; + cout << "countFProxies " << countFProxies << endl; + cout << "countCProxies " << countCProxies << endl; return true; } @@ -79,7 +80,7 @@ bool printLambdaCounters() { template class Callable { public: - Callable() : refCount(0) { + Callable() { } virtual const int size() const = 0; @@ -116,19 +117,6 @@ public: private: const F function; }; - -private: - friend class gc_counting_ptr; - - unsigned int refCount; - - unsigned int acquire() { - return gc_add_and_fetch(refCount, (unsigned int)1); - } - - unsigned int release() { - return gc_sub_and_fetch(refCount, (unsigned int)1); - } }; template class lambda; @@ -145,7 +133,7 @@ public: debug_inc(countFLambdas); typedef typename CallableType::template Proxy ProxyType; - callable = gc_counting_ptr(new ProxyType(f)); + callable = gc_ptr(new (gc_new()) ProxyType(f)); } lambda(const lambda& l) { @@ -179,15 +167,15 @@ public: return (*callable)(std::forward

(p)...); } - template friend std::ostream& operator<<(std::ostream&, const lambda&); + template friend ostream& operator<<(ostream&, const lambda&); template friend const bool isNil(const lambda& l); private: typedef Callable CallableType; - gc_counting_ptr callable; + gc_ptr callable; }; -template std::ostream& operator<<(std::ostream& out, const lambda& l) { +template ostream& operator<<(ostream& out, const lambda& l) { return out << "lambda::" << l.callable; } diff --git a/sca-cpp/trunk/kernel/gc.hpp b/sca-cpp/trunk/kernel/gc.hpp index c9a1a35756..3d20245c69 100644 --- a/sca-cpp/trunk/kernel/gc.hpp +++ b/sca-cpp/trunk/kernel/gc.hpp @@ -23,399 +23,236 @@ #define tuscany_gc_hpp /** - * Garbage collected pointer. + * Garbage collected memory management, using APR memory pools. */ +#include #include #include -#include +#include +#include +#include "debug.hpp" namespace tuscany { /** - * Macros used to add or subtract values to reference counters. - * In a multithreaded environment, use the GCC __sync_add_and_fetch - * and __sync_sub_and_fetch built in functions. + * Pointer to a value. */ -#ifdef _REENTRANT - -#define gc_add_and_fetch(t, v) __sync_add_and_fetch(&(t), v) -#define gc_sub_and_fetch(t, v) __sync_sub_and_fetch(&(t), v) - -#else - -#define gc_add_and_fetch(t, v) ((t) = (t) + (v)) -#define gc_sub_and_fetch(t, v) ((t) = (t) - (v)) - -#endif - template class gc_ptr { public: - gc_ptr(T* p = 0) throw() : countingRef(p == 0? 0 : new CountingRef(p)) { + gc_ptr(T* ptr = NULL) throw() : ptr(ptr) { } ~gc_ptr() throw() { - release(); } - gc_ptr(const gc_ptr& r) throw() : countingRef(r.countingRef) { - acquire(r.countingRef); + gc_ptr(const gc_ptr& r) throw() : ptr(r.ptr) { } gc_ptr& operator=(const gc_ptr& r) throw() { if(this == &r) return *this; - acquire(r.countingRef); - release(); - countingRef = r.countingRef; + ptr = r.ptr; 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; + return ptr == r.ptr; } const bool operator!=(const gc_ptr& r) const throw() { - return !this->operator ==(r); + return !this->operator==(r); } T& operator*() const throw() { - return *countingRef->ptr; + return *ptr; } T* operator->() const throw() { - return countingRef->ptr; + return ptr; } operator T*() const throw() { - return countingRef->ptr; - } - - template friend std::ostream& operator<<(std::ostream&, const gc_ptr&); - -private: - struct CountingRef { - T* ptr; - unsigned count; - - CountingRef(T* p) throw() : - ptr(p), count(1) { - } - }* countingRef; - - void acquire(CountingRef* ref) throw() { - if(ref) - gc_add_and_fetch(ref->count, (unsigned int)1); + return ptr; } - void release() throw() { - if(countingRef) { - unsigned rc = gc_sub_and_fetch(countingRef->count, (unsigned int)1); - if(rc == 0) { - delete countingRef->ptr; - delete countingRef; - } - } - } + T* ptr; }; -template std::ostream& operator<<(std::ostream& out, const gc_ptr& p) { - return out << p.countingRef->ptr; -} - /** - * Garbage collected pointer to an array. + * Garbage collected APR memory pool. */ -template class gc_aptr { +class gc_pool { public: - gc_aptr(T* p = 0) throw() : countingRef(p == 0? 0 : new CountingRef(p)) { + gc_pool() : p(NULL) { } - ~gc_aptr() throw() { - release(); + gc_pool(apr_pool_t* p) : p(p) { } - gc_aptr(const gc_aptr& r) throw() : countingRef(r.countingRef) { - acquire(r.countingRef); + gc_pool(const gc_pool& pool) : p(pool.p) { } - gc_aptr& operator=(const gc_aptr& r) throw() { - if(this == &r) + gc_pool& operator=(const gc_pool& pool) { + if (this == &pool) return *this; - acquire(r.countingRef); - release(); - countingRef = r.countingRef; + p = pool.p; 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; + operator apr_pool_t*() const { + return p; } - template friend std::ostream& operator<<(std::ostream&, const gc_aptr&); - private: - struct CountingRef { - T* ptr; - unsigned count; - - CountingRef(T* p) throw() : - ptr(p), count(1) { - } - }* countingRef; - - void acquire(CountingRef* ref) throw() { - if(ref) - gc_add_and_fetch(ref->count, (unsigned int)1); - } + friend const bool destroy(gc_pool& pool); + friend class gc_global_pool_t; + friend class gc_scoped_pool; - void release() throw() { - if(countingRef) { - unsigned rc = gc_sub_and_fetch(countingRef->count, (unsigned int)1); - if(rc == 0) { - delete[] countingRef->ptr; - delete countingRef; - } - } - } + apr_pool_t* p; }; -template std::ostream& operator<<(std::ostream& out, const gc_aptr& p) { - return out << p.countingRef->ptr; -} - /** - * Garbage collected pointer to a reference counting object. + * Destroy a memory pool. */ -template 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 friend std::ostream& operator<<(std::ostream&, const gc_counting_ptr&); - -private: - T* ptr; - - void acquire(T* p) throw() { - if(p) - p->acquire(); - } - - void release() throw() { - if(ptr) { - if(ptr->release() == 0) { - delete ptr; - } - } - } -}; - -template std::ostream& operator<<(std::ostream& out, const gc_counting_ptr& p) { - return out << p.ptr; +const bool destroy(gc_pool& pool) { + apr_pool_destroy(pool.p); + return true; } /** - * Apache Portable Runtime library context + * Default global memory pool. */ -class APRContext { +class gc_apr_context_t { public: - APRContext() { + gc_apr_context_t() { apr_initialize(); } - ~APRContext() { - apr_terminate(); + ~gc_apr_context_t() { + //apr_terminate(); } }; -APRContext aprContext; +gc_apr_context_t gc_apr_context; -/** - * Garbage collected memory pool, using an APR pool. - */ -class gc_pool { +class gc_global_pool_t : public gc_pool { public: - gc_pool() : aprPool(new APRPool) { + gc_global_pool_t() { + apr_pool_create(&p, NULL); } - operator apr_pool_t*() const { - return aprPool->p; + ~gc_global_pool_t() { + //apr_pool_destroy(p); } +}; -private: - class APRPool { - friend class gc_pool; - friend class gc_counting_ptr; - - unsigned int refCount; - apr_pool_t* p; - - APRPool() : refCount(0) { - apr_pool_create(&p, NULL); - } - - ~APRPool() { - apr_pool_destroy(p); - } - - unsigned int acquire() { - return gc_add_and_fetch(refCount, (unsigned int)1); - } +gc_global_pool_t gc_global_pool; - unsigned int release() { - return gc_sub_and_fetch(refCount, (unsigned int)1); - } - }; +/** + * Maintain a stack of memory pools. + */ +#ifdef _REENTRANT +__thread +#endif +apr_pool_t* gc_pool_stack = NULL; - const gc_counting_ptr aprPool; -}; +/** + * Return the current memory pool. + */ +apr_pool_t* gc_current_pool() { + apr_pool_t* p = gc_pool_stack; + if (p != NULL) + return p; + apr_pool_t* g = gc_global_pool; + gc_pool_stack = g; + return g; +} /** - * Garbage collected pointer to pooled memory. + * A memory pool scope, used to setup a scope in which a particular pool + * will be used for all allocations. */ -template class gc_pool_ptr { +class gc_scoped_pool : public gc_pool { 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); + gc_scoped_pool() : gc_pool(NULL), prev(gc_current_pool()), owned(true) { + apr_pool_create(&p, NULL); + gc_pool_stack = p; } - T& operator*() const throw() { - return *ptr; + gc_scoped_pool(apr_pool_t* pool) : gc_pool(pool), prev(gc_current_pool()), owned(false) { + gc_pool_stack = p; } - T* operator->() const throw() { - return ptr; + ~gc_scoped_pool() { + if (owned) + apr_pool_destroy(p); + if (prev != NULL) + gc_pool_stack = prev; } - operator T*() const throw() { - return ptr; +private: + gc_scoped_pool(const unused gc_scoped_pool& pool) : gc_pool(pool.p), prev(NULL), owned(false) { } - template friend std::ostream& operator<<(std::ostream&, const gc_pool_ptr&); - -private: - T* ptr; + apr_pool_t* prev; + bool owned; }; -template std::ostream& operator<<(std::ostream& out, const gc_pool_ptr& p) { - return out << p.ptr; -} - /** - * Cleanup function, called by the APR pool to cleanup registered resources. - * Calls the allocated object's destructor. + * Allocates a pointer to an object allocated from a memory pool and + * register a cleanup callback for it. */ -template apr_status_t gc_pool_cleanupCallback(void* v) { +template apr_status_t gc_pool_cleanup(void* v) { T* t = static_cast(v); t->~T(); return APR_SUCCESS; } -/** - * Returns a pointer to an object allocated from a memory pool. - */ -template gc_pool_ptr gc_pool_new(const gc_pool& mp) { +template T* gc_new(apr_pool_t* p) { + void* m = apr_palloc(p, sizeof(T)); + apr_pool_cleanup_register(p, m, gc_pool_cleanup, apr_pool_cleanup_null) ; + return static_cast(m); +} + +template T* gc_new() { + return gc_new(gc_current_pool()); +} + +template apr_status_t gc_pool_acleanup(void* v) { + int* m = static_cast(v); + int n = *m; + T* t = static_cast(m + 1); + for (int i = 0; i < n; i++, t++) + t->~T(); + return APR_SUCCESS; +} - // Allocate memory from the pool - void* m = apr_palloc(mp, sizeof(T)); +template T* gc_anew(apr_pool_t* p, int n) { + int* m = static_cast(apr_palloc(p, sizeof(int) + sizeof(T[n]))); + *m = n; + apr_pool_cleanup_register(p, m, gc_pool_acleanup, apr_pool_cleanup_null) ; + return static_cast(m + 1); +} - // Register a cleanup callback - apr_pool_cleanup_register(mp, m, gc_pool_cleanupCallback, apr_pool_cleanup_null) ; +template T* gc_anew(int n) { + return gc_anew(gc_current_pool(), n); +} - // Run the requested type's constructor over the allocated memory - return new (m) T(); +/** + * Allocate an array of chars. + */ +char* gc_cnew(apr_pool_t* p, int n) { + return static_cast(apr_palloc(p, n)); +} + +char* gc_cnew(int n) { + return gc_cnew(gc_current_pool(), n); } } + #endif /* tuscany_gc_hpp */ diff --git a/sca-cpp/trunk/kernel/kernel-test.cpp b/sca-cpp/trunk/kernel/kernel-test.cpp index 8a5e4a704d..c4f76c13c9 100644 --- a/sca-cpp/trunk/kernel/kernel-test.cpp +++ b/sca-cpp/trunk/kernel/kernel-test.cpp @@ -24,12 +24,10 @@ */ #include -#include -#include -#include +#include "string.hpp" +#include "sstream.hpp" #include "function.hpp" #include "list.hpp" -#include "slist.hpp" #include "tree.hpp" #include "value.hpp" #include "monad.hpp" @@ -77,7 +75,10 @@ bool testLambda() { bool testLambdaGC() { resetLambdaCounters(); - testLambda(); + { + gc_scoped_pool gc; + testLambda(); + } assert(checkLambdaCounters()); return true; } @@ -87,18 +88,15 @@ int countElements = 0; struct Element { int i; - Element() : - i(0) { + Element() : i(0) { countElements++; } - Element(int i) : - i(i) { + Element(int i) : i(i) { countElements++; } - Element(const Element& o) : - i(o.i) { + Element(const Element& o) : i(o.i) { countElements++; } @@ -110,7 +108,7 @@ struct Element { return o.i == i; } }; -std::ostream& operator<<(std::ostream& out, const Element& v) { +ostream& operator<<(ostream& out, const Element& v) { out << v.i ; return out; } @@ -124,23 +122,14 @@ bool testCons() { return true; } -bool testSet() { - list 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(); + { + gc_scoped_pool gc; + testCons(); + } assert(checkLambdaCounters()); assert(checkListCounters()); assert(countElements == 0); @@ -148,13 +137,13 @@ bool testListGC() { } bool testOut() { - std::ostringstream os1; + ostringstream os1; os1 << list (); - assert(os1.str() == "()"); + assert(str(os1) == "()"); - std::ostringstream os2; + ostringstream os2; os2 << mklist(1, 2, 3); - assert(os2.str() == "(1 2 3)"); + assert(str(os2) == "(1 2 3)"); return true; } @@ -180,10 +169,7 @@ bool testAppend() { assert(car(cdr(cdr(append(mklist(1), mklist(2, 3))))) == 3); assert(isNil(cdr(cdr(cdr(append(mklist(1), mklist(2, 3))))))); - list l; - l << 1 << 2 << 3; - assert(l == mklist(1, 2, 3)); - assert(list() << 1 << 2 << 3 == mklist(1, 2, 3)); + assert(list() + 1 + 2 + 3 == mklist(1, 2, 3)); return true; } @@ -196,7 +182,7 @@ struct Complex { x(x), y(y) { } }; -std::ostream& operator<<(std::ostream& out, const Complex& v) { +ostream& operator<<(ostream& out, const Complex& v) { out << "[" << v.x << ":" << v.y << "]"; return out; } @@ -266,9 +252,9 @@ bool testListRef() { } bool testAssoc() { - const list > l = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); - assert(assoc("a", l) == mklist("a", "A")); - assert(isNil(assoc("z", l))); + const list > l = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); + assert(assoc("a", l) == mklist("a", "A")); + assert(isNil(assoc("z", l))); const list > u = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); assert(assoc("a", u) == mklist("a", "A")); @@ -279,21 +265,21 @@ bool testAssoc() { } bool testZip() { - const list k = mklist("x", "a", "y", "a"); - const list v = mklist("X", "A", "Y", "AA"); - const list > z = mklist(k, v); - const list > u = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); + const list k = mklist("x", "a", "y", "a"); + const list v = mklist("X", "A", "Y", "AA"); + const list > z = mklist(k, v); + const list > u = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y"), mklist("a", "AA")); assert(zip(k, v) == u); assert(unzip(u) == z); return true; } bool testTokenize() { - assert(tokenize("/", "aaa/bbb/ccc/ddd") == mklist("aaa", "bbb", "ccc", "ddd")); - assert(tokenize("/", "/bbb/ccc/ddd") == mklist("", "bbb", "ccc", "ddd")); - assert(tokenize("/", "/bbb/ccc/") == mklist("", "bbb", "ccc")); - assert(tokenize("/", "/bbb//ccc/") == mklist("", "bbb", "", "ccc")); - assert(tokenize("/", "abc/def/") == mklist("abc", "def")); + assert(tokenize("/", "aaa/bbb/ccc/ddd") == mklist("aaa", "bbb", "ccc", "ddd")); + assert(tokenize("/", "/bbb/ccc/ddd") == mklist("", "bbb", "ccc", "ddd")); + assert(tokenize("/", "/bbb/ccc/") == mklist("", "bbb", "ccc")); + assert(tokenize("/", "/bbb//ccc/") == mklist("", "bbb", "", "ccc")); + assert(tokenize("/", "abc/def/") == mklist("abc", "def")); return true; } @@ -336,13 +322,11 @@ bool testValue() { const list v = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y")); assert(cadr((list >)value(v)) == mklist("a", "A")); - const value pv(gc_ptr(new value(1))); + const value pv(gc_ptr(new (gc_new()) value(1))); assert(*(gc_ptr)pv == value(1)); - const list lpv = mklist(gc_ptr(new value(1)), gc_ptr(new value(2))); + const list lpv = mklist(gc_ptr(new (gc_new()) value(1)), gc_ptr(new (gc_new()) value(2))); assert(*(gc_ptr)car(lpv) == value(1)); - *(gc_ptr)cadr(lpv) = value(3); - assert(*(gc_ptr)cadr(lpv) == value(3)); return true; } @@ -350,7 +334,10 @@ bool testValueGC() { resetLambdaCounters(); resetListCounters(); resetValueCounters(); - testValue(); + { + gc_scoped_pool gc; + testValue(); + } assert(checkValueCounters()); assert(checkLambdaCounters()); assert(checkListCounters()); @@ -371,8 +358,8 @@ bool testTree() { return true; } -const list lta(const std::string& x) { - return mklist(x.c_str(), (x + x).c_str()); +const list lta(const string& x) { + return mklist(c_str(x), c_str(x + x)); } bool testTreeAssoc() { @@ -425,7 +412,7 @@ struct nestedFibMapPerf { bool testCppPerf() { { const lambda fml = fibMapPerf(); - std::cout << "Fibonacci map test " << (time(fml, 1, 1) / 1000) << " ms" << std::endl; + cout << "Fibonacci map test " << (time(fml, 1, 1) / 1000) << " ms" << endl; } { @@ -443,7 +430,7 @@ bool testCppPerf() { }; const lambda nfml = nestedFibMapPerf(lambda(nested::fib)); - std::cout << "Nested Fibonacci map test " << (time(nfml, 1, 1) / 1000) << " ms" << std::endl; + cout << "Nested Fibonacci map test " << (time(nfml, 1, 1) / 1000) << " ms" << endl; } return true; } @@ -490,26 +477,26 @@ bool testMaybeMonad() { return true; } -const failable failableF(const int v) { +const failable failableF(const int v) { return v * 2; } -const failable failableG(const int v) { +const failable failableG(const int v) { return v * 3; } -const failable failableH(const int v) { +const failable failableH(const int v) { return failableF(v) >> failableG; } bool testFailableMonad() { - const failable m(2); + const failable m(2); assert(m >> failableF == failableF(2)); - assert((m >> success()) == m); + assert((m >> success()) == m); assert(m >> failableF >> failableG == m >> failableH); - std::cout << "Failable monad test... "; - failable ooops = mkfailure("test"); + cout << "Failable monad test... " << endl; + failable ooops = mkfailure("test"); assert(reason(ooops) == "test"); assert(ooops >> failableF >> failableG == ooops); return true; @@ -553,14 +540,14 @@ bool testStateMonad() { } bool testDynLib() { - const failable dl(dynlib(".libs/libdynlib-test" + dynlibExt)); + const failable dl(dynlib(string(".libs/libdynlib-test") + dynlibExt)); assert(hasContent(dl)); - const failable, std::string> sq(dynlambda("csquare", content(dl))); + const failable> sq(dynlambda("csquare", content(dl))); assert(hasContent(sq)); lambda l(content(sq)); assert(l(2) == 4); - const failable()>, std::string> sql(dynlambda()>("csquarel", content(dl))); + const failable()>> sql(dynlambda()>("csquarel", content(dl))); assert(hasContent(sql)); lambda()> ll(content(sql)); assert(ll()(3) == 9); @@ -570,12 +557,11 @@ bool testDynLib() { } int main() { - std::cout << "Testing..." << std::endl; + tuscany::cout << "Testing..." << tuscany::endl; tuscany::testLambda(); tuscany::testLambdaGC(); tuscany::testCons(); - tuscany::testSet(); tuscany::testListGC(); tuscany::testOut(); tuscany::testEquals(); @@ -603,7 +589,7 @@ int main() { tuscany::testStateMonad(); tuscany::testDynLib(); - std::cout << "OK" << std::endl; + tuscany::cout << "OK" << tuscany::endl; return 0; } diff --git a/sca-cpp/trunk/kernel/list.hpp b/sca-cpp/trunk/kernel/list.hpp index 88163e63d2..653f49dfe5 100644 --- a/sca-cpp/trunk/kernel/list.hpp +++ b/sca-cpp/trunk/kernel/list.hpp @@ -26,9 +26,9 @@ * Simple list functions. */ -#include -#include -#include +#include +#include "string.hpp" +#include "fstream.hpp" #include "function.hpp" #include "debug.hpp" @@ -56,28 +56,33 @@ bool checkListCounters() { } 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; + cout << "countLists " << countLists << endl; + cout << "countELists " << countELists << endl; + cout << "countILists " << countILists << endl; + cout << "countCLists " << countCLists << endl; return true; } -#define debug_watchList() do { \ - this->watch = watchList(*this); \ - } while (0) - #else #define resetListCounters() #define checkListCounters() true #define printListCounters() +#endif + +#ifdef _DEBUG_WATCH + +#define debug_watchList() do { \ + this->watch = watchList(*this); \ + } while (0) + +#else + #define debug_watchList(); #endif - /** * A car/cdr lisp-like pair, base structure to construct lists. */ @@ -91,28 +96,26 @@ public: debug_watchList(); } - list(const T car, const lambda()>& cdr) : - car(car), cdr(cdr) { + list(const T car, const lambda()>& cdr) : car(car), cdr(cdr) { debug_inc(countLists); debug_inc(countILists); debug_watchList(); } - list(const list& p) : - car(p.car), cdr(p.cdr) { + list(const list& p) : car(p.car), cdr(p.cdr) { debug_inc(countLists); debug_inc(countCLists); -#ifdef _DEBUG +#ifdef _DEBUG_WATCH watch = p.watch; #endif } - const list& operator=(const list& p) { + const list& operator=(const list& p) { if(this == &p) return *this; car = p.car; cdr = p.cdr; -#ifdef _DEBUG +#ifdef _DEBUG_WATCH watch = p.watch; #endif return *this; @@ -172,41 +175,34 @@ public: return (list >)T(*this); } - list& operator<<(const T& v) { - *this = append(*this, mklist(v)); - return *this; - } +private: +#ifdef _DEBUG_WATCH + template friend const string watchList(const list& p); + string watch; +#endif template friend const bool isNil(const list& p); template friend const X car(const list& p); template friend const list cdr(const list& p); - template friend const bool setCar(list& p, const X& car); - template friend const bool setCdr(list& p, const list& cdr); - template friend const bool setCdr(list& p, const lambda()>& cdr); - -private: -#ifdef _DEBUG - template friend const std::string watchList(const list& p); - std::string watch; -#endif T car; lambda()> cdr; }; -#ifdef _DEBUG +#ifdef _DEBUG_WATCH /** * Debug utility used to write the contents of a list to a string, easier * to watch than the list itself in a debugger. */ -template const std::string watchList(const list& p) { +template const string watchList(const list& p) { if(isNil(p)) return "()"; - std::ostringstream os; + ostringstream os; os << "(" << car(p) << " ...)"; - return os.str(); + return str(os); } + #endif /** @@ -219,14 +215,14 @@ template const bool isNil(const list& p) { /** * Write a list to an output stream. */ -template std::ostream& writeHelper(std::ostream& out, const list& l) { +template ostream& writeHelper(ostream& out, const list& l) { if (isNil(l)) return out; out << " " << car(l); return writeHelper(out, cdr(l)); } -template std::ostream& operator<<(std::ostream& out, const list& l) { +template ostream& operator<<(ostream& out, const list& l) { if(isNil(l)) return out << "()"; out << "(" << car(l); @@ -305,6 +301,8 @@ template const list mklist(const T& a, const T& b, const T& c, co * Returns the car of a list. */ template const T car(const list& p) { + // Abort if trying to access the car of a nil list + assert(!isNil(p.cdr)); return p.car; } @@ -315,31 +313,6 @@ template const list cdr(const list& p) { return p.cdr(); } -/** - * Sets the car of a list. - */ -template const bool setCar(list& p, const T& car) { - p.car = car; - return true; -} - -/** - * Sets the cdr of a list. - */ -template const bool setCdr(list& p, const list& c) { - p.cdr = result(c); - return true; -} - -/** - * Sets the cdr of a list to a lambda function. - */ -template const bool setCdr(list& p, const lambda()>& cdr) { - p.cdr = cdr; - return true; -} - - /** * Returns the car of the cdr of a list. */ @@ -418,6 +391,17 @@ template const list append(const list&a, const list& b) { return append(a, result(b)); } +/** + * Append a value to a list. + */ +template const list operator+(const list& l, const T& v) { + return append(l, mklist(v)); +} + +template const list operator+(const list& l, const V& v) { + return append(l, mklist(v)); +} + /** * Map a lambda function on a list. */ diff --git a/sca-cpp/trunk/kernel/mem-test.cpp b/sca-cpp/trunk/kernel/mem-test.cpp new file mode 100644 index 0000000000..b1164a5a36 --- /dev/null +++ b/sca-cpp/trunk/kernel/mem-test.cpp @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Test memory allocation functions. + */ + +#include +#include "stream.hpp" +#include "string.hpp" +#include "gc.hpp" +#include "function.hpp" +#include "perf.hpp" + +namespace tuscany { + +int countElements = 0; +int maxElements = 0; + +class Element { +public: + Element() : i(0) { + countElements++; + if (countElements > maxElements) + maxElements = countElements; + } + + Element(int i) : i(i) { + countElements++; + if (countElements > maxElements) + maxElements = countElements; + } + + Element(const Element& o) : i(o.i) { + countElements++; + if (countElements > maxElements) + maxElements = countElements; + } + + ~Element() { + countElements--; + } + + const bool operator==(const Element& o) const { + return o.i == i; + } + +private: + friend ostream& operator<<(ostream& out, const Element& v); + + int i; + char c[20]; +}; + +ostream& operator<<(ostream& out, const Element& v) { + out << v.i ; + return out; +} + +bool poolAlloc(Element** p, const int count) { + if (count == 0) + return true; + p[count - 1] = new (gc_new()) Element(); + return poolAlloc(p, count - 1); +}; + +bool poolFree(Element** p, const int count) { + if (count == 0) + return true; + // Do nothing to free the element, but cycle through them just + // to get a fair comparison with the other memory alloc tests + return poolFree(p, count - 1); +}; + +struct poolAllocPerf { + const int n; + Element** p; + poolAllocPerf(const int n) : n(n), p(new Element*[n]) { + } + const bool operator()() const { + gc_scoped_pool gc; + poolAlloc(p, n); + return true; + } +}; + +bool testPoolAllocPerf() { + const int count = 100000; + const lambda pl = poolAllocPerf(count); + maxElements = 0; + cout << "Memory pool alloc test " << (time(pl, 1, 1) / count) << " ms" << endl; + assert(countElements == 0); + assert(maxElements == count); + return true; +} + +bool stdAlloc(Element** p, const int count) { + if (count == 0) + return true; + p[count - 1] = new Element(); + return stdAlloc(p, count - 1); +}; + +bool stdFree(Element** p, const int count) { + if (count == 0) + return true; + delete p[count -1]; + return stdFree(p, count - 1); +}; + +struct stdAllocPerf { + const int n; + Element** p; + stdAllocPerf(const int n) : n(n), p(new Element*[n]) { + } + const bool operator()() const { + stdAlloc(p, n); + stdFree(p, n); + return true; + } +}; + +bool testStdAllocPerf() { + const int count = 100000; + const lambda sl = stdAllocPerf(count); + maxElements = 0; + cout << "Memory standard alloc test " << (time(sl, 1, 1) / count) << " ms" << endl; + assert(countElements == 0); + assert(maxElements == count); + return true; +} + +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::testPoolAllocPerf(); + tuscany::testStdAllocPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/trunk/kernel/monad.hpp b/sca-cpp/trunk/kernel/monad.hpp index 5449aa38fd..d2057cf367 100644 --- a/sca-cpp/trunk/kernel/monad.hpp +++ b/sca-cpp/trunk/kernel/monad.hpp @@ -26,11 +26,10 @@ * Simple monad implementations. */ -#include -#include - #include "function.hpp" #include "debug.hpp" +#include "string.hpp" +#include "stream.hpp" namespace tuscany { @@ -70,7 +69,7 @@ private: /** * Write an identity monad to a stream. */ -template std::ostream& operator<<(std::ostream& out, const id& m) { +template ostream& operator<<(ostream& out, const id& m) { out << content(m); return out; } @@ -148,7 +147,7 @@ private: /** * Write a maybe monad to a stream. */ -template std::ostream& operator<<(std::ostream& out, const maybe& m) { +template ostream& operator<<(ostream& out, const maybe& m) { if (!hasContent(m)) { out << "nothing"; return out; @@ -203,7 +202,7 @@ template const maybe operator>>(const maybe& m, co * To get the value in the monad, just cast it to the value type. * To get the failure in the monad, cast it to the failure type. */ -template class failable { +template class failable { public: failable() : hasv(false) { } @@ -211,22 +210,7 @@ public: failable(const V& v) : hasv(true), v(v) { } - failable(const failable& m) : hasv(m.hasv) { - if (hasv) - v = m.v; - else - f = m.f; - } - - const failable& operator=(const failable& m) { - if(this == &m) - return *this; - hasv = m.hasv; - if (hasv) - v = m.v; - else - f = m.f; - return *this; + failable(const failable& m) : hasv(m.hasv), v(m.v), f(m.f) { } const bool operator!=(const failable& m) const { @@ -242,23 +226,28 @@ public: } private: - bool hasv; - V v; - F f; - failable(const bool hasv, const F& f) : hasv(hasv), f(f) { } + // Prevent mutation + const failable& operator=(const failable& m) { + return *this; + } + template friend const bool hasContent(const failable& m); template friend const A content(const failable& m); template friend const B reason(const failable& m); template friend const failable mkfailure(const B& f); + + bool hasv; + V v; + F f; }; /** * Write a failable monad to a stream. */ -template std::ostream& operator<<(std::ostream& out, const failable& m) { +template ostream& operator<<(ostream& out, const failable& m) { if (!hasContent(m)) { out << reason(m); return out; @@ -286,6 +275,10 @@ template const failable mkfailure(const F& f) { return failable(false, f); } +template const failable mkfailure(const char* f) { + return mkfailure(string(f)); +} + template const lambda(const V)> failure() { return mkfailure; } @@ -421,7 +414,7 @@ private: /** * Write a state monad to a stream. */ -template std::ostream& operator<<(std::ostream& out, const state& m) { +template ostream& operator<<(ostream& out, const state& m) { const S s = m; const V v = m; out << '(' << s << ' ' << v << ')'; diff --git a/sca-cpp/trunk/kernel/parallel-test.cpp b/sca-cpp/trunk/kernel/parallel-test.cpp index 8ae2eeed2c..b47501a58d 100644 --- a/sca-cpp/trunk/kernel/parallel-test.cpp +++ b/sca-cpp/trunk/kernel/parallel-test.cpp @@ -24,8 +24,8 @@ */ #include -#include -#include +#include "stream.hpp" +#include "string.hpp" #include "function.hpp" #include "list.hpp" #include "perf.hpp" @@ -33,6 +33,8 @@ namespace tuscany { +#ifdef _REENTRANT + int inci = 0; struct incPerf { @@ -84,25 +86,25 @@ bool testAtomicPerf() { const int count = 100000; { const lambda l = incPerf(); - std::cout << "Non-atomic inc test " << time(l, 1000, count) << " ms" << std::endl; + cout << "Non-atomic inc test " << time(l, 1000, count) << " ms" << endl; assert(inci == count + 1000); } { const lambda l = addAndFetchPerf(); - std::cout << "Atomic inc test " << time(l, 1000, count) << " ms" << std::endl; + cout << "Atomic inc test " << time(l, 1000, count) << " ms" << endl; assert(addi == count + 1000); } { pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); const lambda l = mutexPerf(&mutex); - std::cout << "Locked inc test " << time(l, 1000, count) << " ms" << std::endl; + cout << "Locked inc test " << time(l, 1000, count) << " ms" << endl; assert(muxi == count + 1000); pthread_mutex_destroy(&mutex); } { const lambda l = tlsPerf(); - std::cout << "Thread local inc test " << time(l, 1000, count) << " ms" << std::endl; + cout << "Thread local inc test " << time(l, 1000, count) << " ms" << endl; assert(tlsi == count + 1000); } return true; @@ -114,38 +116,51 @@ const int mtsquare(const int x) { return x * x; } +bool checkResults(const list > r, int i) { + if (isNil(r)) + return true; + assert(car(r) == i * i); + checkResults(cdr(r), i + 1); + return true; +} + +const list > submitSquares(worker& w, const int max, const int i) { + if (i == max) + return list >(); + const lambda func = curry(lambda (mtsquare), i); + return cons(submit(w, func), submitSquares(w, max, i + 1)); +} + bool testWorker() { - worker w(10); + worker w(20); { const lambda func = curry(lambda (mtsquare), 2); assert(submit(w, func) == 4); } { - const int max = 10; - - list > r; - for(int i = 0; i < max; i++) { - const lambda func = curry(lambda (mtsquare), i); - r = cons(submit(w, func), r); - } - for(int i = max - 1; i >= 0; i--) { - assert(car(r) == i * i); - r = cdr(r); - } + const int max = 20; + const list > r(submitSquares(w, max, 0)); + checkResults(r, 0); } shutdown(w); return true; } +#endif + } int main() { - std::cout << "Testing..." << std::endl; + tuscany::cout << "Testing..." << tuscany::endl; +#ifdef _REENTRANT tuscany::testAtomicPerf(); tuscany::testWorker(); +#else + tuscany::cout << "Skipped multi-thread tests" << tuscany::endl; +#endif - std::cout << "OK" << std::endl; + tuscany::cout << "OK" << tuscany::endl; return 0; } diff --git a/sca-cpp/trunk/kernel/parallel.hpp b/sca-cpp/trunk/kernel/parallel.hpp index a94764763a..33cb735b84 100644 --- a/sca-cpp/trunk/kernel/parallel.hpp +++ b/sca-cpp/trunk/kernel/parallel.hpp @@ -26,13 +26,18 @@ * Simple parallel work execution functions. */ +#ifdef _REENTRANT #include #include +#include +#endif #include "function.hpp" namespace tuscany { +#ifdef _REENTRANT + /** * Returns the current thread id. */ @@ -48,8 +53,7 @@ template class future { private: template class futureValue { public: - futureValue() : - refCount(0), hasValue(false) { + futureValue() : hasValue(false) { pthread_mutex_init(&valueMutex, NULL); pthread_cond_init(&valueCond, NULL); } @@ -59,14 +63,6 @@ private: pthread_cond_destroy(&valueCond); } - unsigned int acquire() { - return __sync_add_and_fetch(&refCount, (unsigned int)1); - } - - unsigned int release() { - return __sync_sub_and_fetch(&refCount, (unsigned int)1); - } - bool set(const T& v) { pthread_mutex_lock(&valueMutex); if(hasValue) { @@ -91,33 +87,28 @@ private: } private: - unsigned refCount; pthread_mutex_t valueMutex; pthread_cond_t valueCond; bool hasValue; X value; }; - gc_counting_ptr > fvalue; + gc_ptr > fvalue; template friend const X get(const future& f); template friend bool set(const future& f, const X& v); public: - future() : fvalue(new futureValue()) { - //std::cout << "future() threadId " << threadId() << "\n"; + future() : fvalue(new (gc_new >()) futureValue()) { } ~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; @@ -132,7 +123,6 @@ public: operator const T() const { return fvalue->get(); } - }; /** @@ -140,7 +130,7 @@ public: */ template class queue { public: - queue(int max) : max(max), size(0), tail(0), head(0), values(new T[max]) { + queue(int max) : max(max), size(0), tail(0), head(0), values(new (gc_anew(max)) T[max]) { pthread_mutex_init(&mutex, NULL); pthread_cond_init(&full, NULL); pthread_cond_init(&empty, NULL); @@ -160,7 +150,7 @@ private: pthread_mutex_t mutex; pthread_cond_t full; pthread_cond_t empty; - gc_aptr values; + gc_ptr values; template friend const int enqueue(queue& q, const X& v); template friend const X dequeue(queue& q); @@ -280,5 +270,7 @@ const bool shutdown(worker& w) { return true; } +#endif + } #endif /* tuscany_parallel_hpp */ diff --git a/sca-cpp/trunk/kernel/slist.hpp b/sca-cpp/trunk/kernel/slist.hpp deleted file mode 100644 index 705152cb29..0000000000 --- a/sca-cpp/trunk/kernel/slist.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 -#include -#include "function.hpp" -#include "list.hpp" - -namespace tuscany { - -/** - * Tokenize a string into a list of strings. - */ -const list tokenize(const std::string& sep, const std::string& str) { - struct nested { - static const list tokenize(const std::string& sep, const std::string& str, const unsigned int start = 0) { - if (start >= str.length()) - return list(); - 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 operator()() { - char buffer[1024]; - is.read(buffer, 1024); - const int n = is.gcount(); - if (n ==0) - return list(); - return cons(std::string(buffer, n), (*this)()); - } -}; - -const list streamList(std::istream& is) { - return ilistRead(is)(); -} - -/** - * Fragment the first element of a list of strings to fit the given max length. - */ -const list fragment(list l, 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& 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/sstream.hpp b/sca-cpp/trunk/kernel/sstream.hpp new file mode 100644 index 0000000000..5fcdb0c22b --- /dev/null +++ b/sca-cpp/trunk/kernel/sstream.hpp @@ -0,0 +1,234 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_sstream_hpp +#define tuscany_sstream_hpp + +/** + * Char buffer based streams. + */ + +#include +#include +#include +#include "string.hpp" +#include "stream.hpp" +#include "list.hpp" + +namespace tuscany { + +/** + * Instrumentable memcpy. + */ +void* stream_memcpy(void* t, const void* s, const size_t n) { + return memcpy(t, s, n); +} + +/** + * Output stream backed by a char buffer. + */ +class ostringstream : public ostream { +public: + ostringstream() : len(0) { + } + + ~ostringstream() { + } + + ostringstream(const ostringstream& os) { + len = os.len; + buf = os.buf; + } + + ostringstream& vprintf(const char* fmt, ...) { + va_list args; + va_start (args, fmt); + string s; + s.len = vsnprintf(NULL, 0, fmt, args); + s.buf = gc_cnew(s.len + 1); + vsnprintf(s.buf, s.len + 1, fmt, args); + buf = cons(s, buf); + len += s.len; + va_end (args); + return *this; + } + + ostringstream& flush() { + return *this; + } + +private: + static const bool strHelper(const list l, char* buf) { + if (isNil(l)) + return true; + const string c = car(l); + char* b = buf - length(c); + memcpy(b, c_str(c), length(c)); + return strHelper(cdr(l), b); + } + + const string str() { + if (isNil(buf)) + return string(); + string s; + s.len = len; + s.buf = gc_cnew(s.len + 1); + strHelper(buf, s.buf + len); + s.buf[s.len] = '\0'; + return s; + } + + friend const string str(ostringstream& os); + + int len; + list buf; +}; + +/** + * Return a string representation of a stream. + */ +const string str(ostringstream& os) { + return os.str(); +} + +/** + * Input stream backed by a char buffer + */ +class istringstream : public istream { +public: + istringstream(const string& s) { + cur = 0; + const int slen = length(s); + len = slen; + buf = c_str(s); + } + + ~istringstream() { + } + + istringstream(const istringstream& is) { + len = is.len; + cur = is.cur; + buf = is.buf; + } + + const int read(void* b, int size) { + const int n = len - cur; + if (n == 0) + return 0; + if (n > size) { + stream_memcpy(b, buf + cur, size); + cur = cur + size; + return size; + } + stream_memcpy(b, buf + cur, n); + cur = cur + n; + return n; + } + + const bool eof() { + return cur == len; + } + + const bool fail() { + return false; + } + + const int get() { + if (eof()) + return -1; + const int c = buf[cur]; + cur += 1; + return c; + } + + const int peek() { + if (eof()) + return -1; + return buf[cur]; + } + +private: + int len; + int cur; + const char* buf; +}; + +/** + * Tokenize a string into a list of strings. + */ +const list tokenize(const char* sep, const string& str) { + struct nested { + static const list tokenize(const char* sep, const string& str, const int start = 0) { + if (start >= length(str)) + return list(); + const int i = find(str, sep, start); + if (i == length(str)) + return mklist(string(substr(str, start))); + return cons(string(substr(str, start, i - start)), tokenize(sep, str, i + 1)); + } + }; + return nested::tokenize(sep, str, 0); +} + +/** + * Returns a lazy list view of an input stream. + */ +struct ilistRead{ + istream &is; + ilistRead(istream& is) : is(is) { + } + const list operator()() { + char buffer[1024]; + const int n = read(is, buffer, sizeof(buffer)); + if (n ==0) + return list(); + return cons(string(buffer, n), (*this)()); + } +}; + +const list streamList(istream& is) { + return ilistRead(is)(); +} + +/** + * Fragment the first element of a list of strings to fit the given max length. + */ +const list fragment(list l, int max) { + const string s = car(l); + if (length(s) <= max) + return l; + return cons(substr(s, 0, max), cons(substr(s, max), cdr(l))); +} + +/** + * Write a list of strings to an output stream. + */ +ostream& write(const list& l, ostream& os) { + if(isNil(l)) + return os; + os << car(l); + return write(cdr(l), os); +} + +} + +#endif /* tuscany_sstream_hpp */ diff --git a/sca-cpp/trunk/kernel/stream.hpp b/sca-cpp/trunk/kernel/stream.hpp new file mode 100644 index 0000000000..a3e532c4ce --- /dev/null +++ b/sca-cpp/trunk/kernel/stream.hpp @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_stream_hpp +#define tuscany_stream_hpp + +/** + * Basic stream type and functions. + */ + +#include +#include "debug.hpp" +#include "gc.hpp" +#include "string.hpp" + +namespace tuscany { + +/** + * Base output stream. + */ +class ostream { +public: + virtual ostream& vprintf(const char* fmt, ...) = 0; + virtual ostream& flush() = 0; +}; + +/** + * Flush a stream. + */ +ostream& flush(ostream& os) { + return os.flush(); +} + +/** + * Write simple values to a stream. + */ +ostream& operator<<(ostream& os, const char* v) { + return os.vprintf("%s", v); +} + +ostream& operator<<(ostream& os, const unsigned char* v) { + return os.vprintf("%s", v); +} + +ostream& operator<<(ostream& os, const char v) { + return os.vprintf("%c", v); +} + +ostream& operator<<(ostream& os, const int v) { + return os.vprintf("%d", v); +} + +ostream& operator<<(ostream& os, const long int v) { + return os.vprintf("%ld", v); +} + +ostream& operator<<(ostream& os, const double v) { + return os.vprintf("%g", v); +} + +ostream& operator<<(ostream& os, const void* v) { + return os.vprintf("%p", v); +} + +ostream& operator<<(ostream& os, const string& v) { + return os.vprintf("%s", c_str(v)); +} + +class stream_endl { +} endl; + +ostream& operator<<(ostream& os, unused const stream_endl e) { + os.vprintf("%s", "\n"); + return os.flush(); +} + +/* + * Input stream. + */ +class istream { +public: + virtual const int read(void* buf, int size) = 0; + virtual const bool eof() = 0; + virtual const bool fail() = 0; + virtual const int get() = 0; + virtual const int peek() = 0; +}; + +/** + * Read from an input stream. + */ +const int read(istream& is, void * buf, int size) { + return is.read(buf, size); +} + +/** + * Return true if the end of an input stream has been reached. + */ +const bool eof(istream& is) { + return is.eof(); +} + +/** + * Return true if an input stream can't be accessed. + */ +const bool fail(istream& is) { + return is.fail(); +} + +/** + * Read a character from a stream. + */ +const int get(istream& is) { + return is.get(); +} + +/** + * Peek a character from a stream. + */ +const int peek(istream& is) { + return is.peek(); +} + +template ostream& operator<<(ostream& out, const gc_ptr& p) { + return out << p.ptr; +} + +} + +#endif /* tuscany_stream_hpp */ diff --git a/sca-cpp/trunk/kernel/string-test.cpp b/sca-cpp/trunk/kernel/string-test.cpp new file mode 100644 index 0000000000..323756c7e4 --- /dev/null +++ b/sca-cpp/trunk/kernel/string-test.cpp @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Test string functions. + */ + +#include +#include +#include "sstream.hpp" +#include "string.hpp" +#include "list.hpp" +#include "perf.hpp" + +namespace tuscany { + +bool testCopies() { + resetStringCopyCounters(); + string x("abcd"); + assert(checkStringCopyCounters(1)); + resetStringCopyCounters(); + string y = string("abcd"); + assert(checkStringCopyCounters(1)); + resetStringCopyCounters(); + string z = y; + assert(checkStringCopyCounters(0)); + resetStringCopyCounters(); + const list pl = list() + "abcd" + "efgh"; + printStringCopyCounters(); + resetStringCopyCounters(); + const list cl = cons("efgh", mklist("abcd")); + printStringCopyCounters(); + return true; +} + +bool testString() { + const string s("abcd"); + assert(length(s) == 4); + assert(!strcmp(c_str(s), "abcd")); + + assert(s == "abcd"); + assert(s == string("abcd")); + assert(s != "zbcd"); + + assert(s < "zbcd"); + assert(s < "zbc"); + assert(s < "abzd"); + assert(s < "abcdz"); + + assert(s > "Abcd"); + assert(s > "Abc"); + assert(s > "abCd"); + assert(s > "Abcdz"); + + const string x = "abcd"; + assert(!strcmp(c_str(x), "abcd")); + + const string y = string("abcd"); + assert(!strcmp(c_str(y), "abcd")); + + assert(string("ab") + "cd" == "abcd"); + + assert(find("abcd", "cd") == 2); + assert(find("abcd", "xy") == length("abcd")); + assert(substr("abcdef", 4) == "ef"); + assert(substr("abcdef", 4, 2) == "ef"); + assert(substr("abcdef", 4, 3) == "ef"); + assert(substr("abcdef", 6, 3) == ""); + return true; +} + +bool testStream() { + ostringstream os; + os << "ab" << "cd"; + cout << str(os) << endl; + assert(str(os) == "abcd"); + + ostringstream cs; + cs << "\'"; + assert(str(cs) == "\'"); + cs << '\''; + assert(str(cs) == "\'\'"); + + istringstream is("abcd"); + char b[2]; + assert(read(is, b, 2) == 2); + assert(string("ab") == string(b, 2)); + assert(eof(is) == false); + assert(read(is, b, 2) == 2); + assert(string("cd") == string(b, 2)); + assert(eof(is) == true); + assert(read(is, b, 2) == 0); + return true; +} + +std::string stdAdd(std::string& x, std::string& y) { + return x + y; +} + +string add(string& x, string& y) { + return x + y; +} + +char charBuffer[16384]; + +struct addStrings{ + const int size; + addStrings(const int size) : size(size) { + } + bool operator()() const { + const int sz = size / 4; + string x(charBuffer, sz); + string y(charBuffer, sz); + assert(length(add(x, y)) == sz * 2); + return true; + } +}; + +struct addStdStrings{ + const int size; + addStdStrings(const int size) : size(size) { + } + bool operator()() const { + const int sz = size / 4; + std::string x(charBuffer, sz); + std::string y(charBuffer, sz); + assert(stdAdd(x, y).length() == (unsigned int)(sz * 2)); + return true; + } +}; + +bool testStringPerf() { + memset(charBuffer, 'A', 16384); + charBuffer[16384] = '\0'; + + const int count = 100000; + { + const lambda a16 = addStrings(16); + cout << "string test " << time(a16, 5, count) << " ms" << endl; + const lambda a32 =addStrings(32); + cout << "string test " << time(a32, 5, count) << " ms" << endl; + const lambda a256 =addStrings(256); + cout << "string test " << time(a256, 5, count) << " ms" << endl; + const lambda a1024 =addStrings(1024); + cout << "string test " << time(a1024, 5, count) << " ms" << endl; + const lambda a4096 =addStrings(4096); + cout << "string test " << time(a4096, 5, count) << " ms" << endl; + } + { + const lambda a16 =addStdStrings(16); + cout << "Std string test " << time(a16, 5, count) << " ms" << endl; + const lambda a32 =addStdStrings(32); + cout << "Std string test " << time(a32, 5, count) << " ms" << endl; + const lambda a256 =addStdStrings(256); + cout << "Std string test " << time(a256, 5, count) << " ms" << endl; + const lambda a1024 =addStdStrings(1024); + cout << "Std string test " << time(a1024, 5, count) << " ms" << endl; + const lambda a4096 =addStdStrings(4096); + cout << "Std string test " << time(a4096, 5, count) << " ms" << endl; + } + + return true; +} + +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::testCopies(); + tuscany::testString(); + tuscany::testStream(); + tuscany::testStringPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/trunk/kernel/string.hpp b/sca-cpp/trunk/kernel/string.hpp new file mode 100644 index 0000000000..f065bcc9a4 --- /dev/null +++ b/sca-cpp/trunk/kernel/string.hpp @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_string_hpp +#define tuscany_string_hpp + +/** + * Simple and fast string type backed by a char buffer + */ + +#include +#include +#include +#include +#include "gc.hpp" + +namespace tuscany { + +#ifdef _DEBUG + +/** + * Debug utilities. Counters used to track string copies. + */ +long countStringCopies = 0; + +bool resetStringCopyCounters() { + countStringCopies = 0; + return true; +} + +bool checkStringCopyCounters(long c) { + return countStringCopies == c; +} + +bool printStringCopyCounters() { + printf("countStringCopies %ld\n", countStringCopies); + return true; +} + +#else + +#define resetStringCopyCounters() +#define checkStringCopyCounters(c) true +#define printStringCopyCounters() + +#endif + +/** + * Instrumented memcpy. + */ +void* string_memcpy(void* t, const void* s, const size_t n) { +#ifdef _DEBUG + countStringCopies += 1; +#endif + return memcpy(t, s, n); +} + +char stringEmptyBuffer[1] = { '\0' }; + +/** + * String class. The maximum string size is specified as a template parameter. + */ +class string { +public: + string() : len(0) { + buf = stringEmptyBuffer; + } + + string(const char* s) { + len = strlen(s); + if (len == 0) { + buf = stringEmptyBuffer; + return; + } + buf = gc_cnew(len + 1); + string_memcpy(buf, s, len + 1); + } + + string(const char* s, const int n) { + len = n; + if (len == 0) { + buf = stringEmptyBuffer; + return; + } + buf = gc_cnew(len + 1); + string_memcpy(buf, s, len); + buf[len] = '\0'; + } + + string(const int n, const char c) { + len = n; + if (len == 0) { + buf = stringEmptyBuffer; + return; + } + buf = gc_cnew(len + 1); + memset(buf, c, n); + buf[len] = '\0'; + } + + string(const string& s) { + len = s.len; + buf = s.buf; + } + + const string& operator=(const string& s) { + if (&s == this) + return *this; + len = s.len; + buf = s.buf; + return *this; + } + + const bool operator==(const string& s) const { + if (len != s.len) + return false; + if (buf == s.buf) + return true; + return memcmp(buf, s.buf, len) == 0; + } + + const bool operator!=(const string& s) const { + return !(*this == s); + } + + const bool operator==(const char* s) const { + if (buf == s) + return true; + return strcmp(buf, s) == 0; + } + + const bool operator!=(const char* s) const { + return !(*this == s); + } + + const bool operator<(const string& s) const { + const int n = len < s.len? len : s.len; + const int c = memcmp(buf, s.buf, n); + if (c < 0) + return true; + if (c == 0) + return len < s.len; + return false; + } + + const bool operator>(const string& s) const { + const int n = len < s.len? len : s.len; + int c = memcmp(buf, s.buf, n); + if (c > 0) + return true; + if (c == 0) + return len > s.len; + return false; + } + +private: + friend class ostringstream; + friend const string operator+(const string& a, const string& b); + friend const string operator+(const string& a, const char* b); + friend const int length(const string& s); + friend const char* c_str(const string& s); + friend const int find(const string& s1, const char* s2, const int start); + friend const string substr(const string& s, const int pos, const int n); + + int len; + char* buf; +}; + +/** + * Adds two strings. + */ +const string operator+(const string& a, const string& b) { + string s; + s.len = a.len + b.len; + s.buf = gc_cnew(s.len + 1); + string_memcpy(s.buf, a.buf, a.len); + string_memcpy(s.buf + a.len, b.buf, b.len); + s.buf[s.len] = '\0'; + return s; +} + +const string operator+(const string& a, const char* b) { + string s; + const int blen = strlen(b); + s.len = a.len + blen; + s.buf = gc_cnew(s.len + 1); + string_memcpy(s.buf, a.buf, a.len); + string_memcpy(s.buf + a.len, b, blen); + s.buf[s.len] = '\0'; + return s; +} + +/** + * Returns the length of a string. + */ +const int length(const string& s) { + return s.len; +} + +/** + * Returns a string as a C zero terminated string. + */ +const char* c_str(const string& s) { + return s.buf; +} + +/** + * Find the first occurrence of string s2 in s1, starting at the given position. + */ +const int find(const string& s1, const char* s2, const int start) { + if (start >= s1.len) + return s1.len; + const char *f = strstr(s1.buf + start, s2); + if (f == NULL) + return s1.len; + return f - s1.buf; +} + +const int find(const string& s1, const char* s2) { + return find(s1, s2, 0); +} + +const bool contains(const string& s1, const char* s2) { + return find(s1, s2) != length(s1); +} + +/** + * Find the first occurence of any character from a string in a string. + */ +const int find_first_of(const string& s1, const string& s2) { + return strcspn(c_str(s1), c_str(s2)); +} + +/** + * Find the last occurence of a character in a string. + */ +const int find_last(const string& s, const char c) { + const char* cs = c_str(s); + const char* f = strrchr(cs, c); + if (f == NULL) + return length(s); + return f - cs; +} + +/** + * Return a substring of a string. + */ +const string substr(const string& s, const int pos, const int n) { + if (pos >= s.len) + return string(); + if (pos + n > s.len) + return string(s.buf + pos, s.len - pos); + return string(s.buf + pos, n); +} + +const string substr(const string& s, const int pos) { + return substr(s, pos, length(s)); +} + +/** + * Common string constants. + */ + +string trueString("true"); +string falseString("false"); +string emptyString(""); + +} + +#endif /* tuscany_string_hpp */ diff --git a/sca-cpp/trunk/kernel/tree.hpp b/sca-cpp/trunk/kernel/tree.hpp index f0c85ff403..436385aa1b 100644 --- a/sca-cpp/trunk/kernel/tree.hpp +++ b/sca-cpp/trunk/kernel/tree.hpp @@ -26,8 +26,8 @@ * Functions to work with trees. */ -#include -#include +#include "stream.hpp" +#include "string.hpp" #include "function.hpp" #include "list.hpp" #include "monad.hpp" diff --git a/sca-cpp/trunk/kernel/value.hpp b/sca-cpp/trunk/kernel/value.hpp index e767ead74b..d2c5f12e95 100644 --- a/sca-cpp/trunk/kernel/value.hpp +++ b/sca-cpp/trunk/kernel/value.hpp @@ -26,9 +26,9 @@ * Generic value type. */ -#include -#include -#include +#include +#include "string.hpp" +#include "sstream.hpp" #include "gc.hpp" #include "function.hpp" #include "list.hpp" @@ -60,23 +60,29 @@ bool checkValueCounters() { } 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; + cout << "countValues " << countValues << endl; + cout << "countEValues " << countEValues << endl; + cout << "countCValues " << countCValues << endl; + cout << "countVValues " << countVValues << endl; return true; } -#define debug_watchValue() do { \ - this->watch = watchValue(*this); \ - } while (0) - #else #define resetValueCounters() #define checkValueCounters() true #define printValueCounters() +#endif + +#ifdef _DEBUG_WATCH + +#define debug_watchValue() do { \ + this->watch = watchValue(*this); \ + } while (0) + +#else + #define debug_watchValue() #endif @@ -90,8 +96,7 @@ public: Undefined, Symbol, String, List, Number, Bool, Char, Lambda, Ptr, PoolPtr }; - value() : - type(value::Undefined) { + value() : type(value::Undefined) { debug_inc(countValues); debug_inc(countEValues); debug_watchValue(); @@ -123,43 +128,11 @@ public: default: break; } -#ifdef _DEBUG +#ifdef _DEBUG_WATCH watch = v.watch; #endif } - 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; - } -#ifdef _DEBUG - watch = v.watch; -#endif - return *this; - } - virtual ~value() { debug_dec(countValues); } @@ -170,13 +143,13 @@ public: debug_watchValue(); } - value(const std::string& str) : type(value::String), data(vdata(result(str))) { + value(const string& str) : type(value::String), data(vdata(result(str))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } - value(const char* str) : type(value::Symbol), data(vdata(result(std::string(str)))) { + value(const char* str) : type(value::Symbol), data(vdata(result(string(str)))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); @@ -218,19 +191,21 @@ public: debug_watchValue(); } +#ifdef _GC_REFCOUNT value(const gc_ptr ptr) : type(value::Ptr), data(vdata(result(ptr))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } +#endif - value(const gc_pool_ptr ptr) : type(value::PoolPtr), data(vdata(result(ptr))) { + value(const gc_ptr ptr) : type(value::PoolPtr), data(vdata(result(ptr))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } - value(const failable& m) : type(value::List), + value(const failable& m) : type(value::List), data(vdata(result(hasContent(m)? mklist(content(m)) : mklist(value(), reason(m))))) { debug_inc(countValues); debug_inc(countVValues); @@ -244,6 +219,38 @@ public: debug_watchValue(); } + const value& operator=(const value& v) { + if(this == &v) + return *this; + type = v.type; + switch(type) { + case value::List: + lst() = v.lst(); + case value::Lambda: + func() = v.func(); + case value::Symbol: + str() = v.str(); + case value::String: + str() = v.str(); + case value::Number: + num() = v.num(); + case value::Bool: + boo() = v.boo(); + case value::Char: + chr() = v.chr(); + case value::Ptr: + ptr() = v.ptr(); + case value::PoolPtr: + poolptr() = v.poolptr(); + default: + break; + } +#ifdef _DEBUG_WATCH + watch = v.watch; +#endif + return *this; + } + const bool operator!=(const value& v) const { return !this->operator==(v); } @@ -259,9 +266,8 @@ public: case value::Lambda: return v.type == value::Lambda && func() == v.func(); case value::Symbol: - return str()() == (std::string)v; case value::String: - return str()() == (std::string)v; + return str()() == (string)v; case value::Number: return num()() == (double)v; case value::Bool: @@ -285,8 +291,7 @@ public: return v.type == value::List && lst()() < v.lst()(); case value::Symbol: case value::String: - return str()() < (std::string)v; - return str()() < (std::string)v; + return str()() < (string)v; case value::Bool: return boo()() < (bool)v; case value::Number: @@ -306,8 +311,7 @@ public: return v.type == value::List && lst()() > v.lst()(); case value::Symbol: case value::String: - return str()() > (std::string)v; - return str()() > (std::string)v; + return str()() > (string)v; case value::Bool: return boo()() > (bool)v; case value::Number: @@ -323,25 +327,25 @@ public: return func()(args); } - operator const std::string() const { + operator const string() const { switch(type) { case value::Symbol: case value::String: return str()(); case value::Number: { - std::ostringstream sos; - sos << num()(); - return sos.str(); + ostringstream os; + os << num()(); + return tuscany::str(os); } case value::Bool: - return boo()()? "true" : "false"; + return boo()()? trueString : falseString; case value::Char: { - std::ostringstream sos; - sos << chr()(); - return sos.str(); + ostringstream os; + os << chr()(); + return tuscany::str(os); } default: - return ""; + return emptyString; } } @@ -349,7 +353,7 @@ public: switch(type) { case value::Symbol: case value::String: - return atof(str()().c_str()); + return atof(c_str(str()())); case value::Number: return (double)num()(); case value::Bool: @@ -365,7 +369,7 @@ public: switch(type) { case value::Symbol: case value::String: - return atoi(str()().c_str()); + return atoi(c_str(str()())); case value::Number: return (int)num()(); case value::Bool: @@ -381,7 +385,7 @@ public: switch(type) { case value::Symbol: case value::String: - return str()() == "true"; + return str()() == string("true"); case value::Number: return (int)num()() != 0; case value::Bool: @@ -409,11 +413,13 @@ public: } } +#ifdef _GC_REFCOUNT operator const gc_ptr() const { return ptr()(); } +#endif - operator const gc_pool_ptr() const { + operator const gc_ptr() const { return poolptr()(); } @@ -454,12 +460,12 @@ private: return vdata()> (); } - lambda()>& poolptr() const { - return vdata()> (); + lambda()>& poolptr() const { + return vdata()> (); } - lambda& str() const { - return vdata (); + lambda& str() const { + return vdata (); } lambda()>& lst() const { @@ -482,37 +488,38 @@ private: return cons >(list(car(l)), listOfListOfValues(cdr(l))); } - friend std::ostream& operator<<(std::ostream&, const value&); + friend ostream& operator<<(ostream&, const value&); friend const value::ValueType type(const value& v); -#ifdef _DEBUG - friend const std::string watchValue(const value& v); - std::string watch; +#ifdef _DEBUG_WATCH + friend const string watchValue(const value& v); + string watch; #endif ValueType type; lambda data; }; -#ifdef _DEBUG +#ifdef _DEBUG_WATCH /** * Debug utility used to write the contents of a value to a string, easier * to watch than the value itself in a debugger. */ -const std::string watchValue(const value& v) { +const string watchValue(const value& v) { if (v.type == value::List) return watchList(v); - std::ostringstream os; + ostringstream os; os << v; - return os.str(); + return str(os); } + #endif /** * Write a value to a stream. */ -std::ostream& operator<<(std::ostream& out, const value& v) { +ostream& operator<<(ostream& out, const value& v) { switch(v.type) { case value::List: return out << v.lst()(); @@ -538,8 +545,8 @@ std::ostream& operator<<(std::ostream& out, const value& v) { return out << "gc_ptr::" << p; } case value::PoolPtr: { - const gc_pool_ptr p = v.poolptr()(); - if (p == gc_pool_ptr(NULL)) + const gc_ptr p = v.poolptr()(); + if (p == gc_ptr(NULL)) return out << "pool_ptr::null"; return out << "pool_ptr::" << p; } @@ -634,5 +641,14 @@ const bool isTaggedList(const value& exp, value tag) { return false; } +/** + * Make a list of values from a list of other things. + */ +template const list mkvalues(const list& l) { + if (isNil(l)) + return list(); + return cons(car(l), mkvalues(cdr(l))); +} + } #endif /* tuscany_value_hpp */ diff --git a/sca-cpp/trunk/kernel/xml-test.cpp b/sca-cpp/trunk/kernel/xml-test.cpp index 88c476ffef..585a2e519d 100644 --- a/sca-cpp/trunk/kernel/xml-test.cpp +++ b/sca-cpp/trunk/kernel/xml-test.cpp @@ -24,9 +24,8 @@ */ #include -#include -#include -#include +#include "stream.hpp" +#include "string.hpp" #include "list.hpp" #include "value.hpp" #include "element.hpp" @@ -34,7 +33,7 @@ namespace tuscany { -const std::string currencyXML = +const string currencyXML = "\n" "\n" "" "jdoe" @@ -74,78 +73,78 @@ const bool isName(const value& token) { bool testReadXML() { { - std::istringstream is(customerXML); + istringstream is(customerXML); const list c = readXML(streamList(is)); } { - std::istringstream is(currencyXML); + istringstream is(currencyXML); const list c = readXML(streamList(is)); const value composite = car(c); assert(isTaggedList(composite, element)); assert(elementName(composite) == "composite"); - assert(attributeValue(car(filter(isName, elementChildren(composite)))) == std::string("currency")); + assert(attributeValue(car(filter(isName, elementChildren(composite)))) == string("currency")); } return true; } -std::ostringstream* xmlWriter(const std::string& s, std::ostringstream* os) { +ostream* xmlWriter(const string& s, ostream* os) { (*os) << s; return os; } bool testWriteXML() { { - std::istringstream is(customerXML); + istringstream is(customerXML); const list c = readXML(streamList(is)); - std::ostringstream os; - writeXML(xmlWriter, &os, c); - assert(os.str() == customerXML); + ostringstream os; + writeXML(xmlWriter, &os, c); + assert(str(os) == customerXML); } { - std::istringstream is(currencyXML); + istringstream is(currencyXML); const list c = readXML(streamList(is)); - std::ostringstream os; - writeXML(xmlWriter, &os, c); - assert(os.str() == currencyXML); + ostringstream os; + writeXML(xmlWriter, &os, c); + assert(str(os) == currencyXML); } return true; } bool testElement() { { - const list ad = mklist(mklist("city", std::string("san francisco")), mklist("state", std::string("ca"))); - const list ac1 = mklist(mklist("id", std::string("1234")), mklist("balance", 1000)); - const list ac2 = mklist(mklist("id", std::string("6789")), mklist("balance", 2000)); - const list ac3 = mklist(mklist("id", std::string("4567")), mklist("balance", 3000)); + const list ad = mklist(mklist("city", string("san francisco")), mklist("state", string("ca"))); + const list ac1 = mklist(mklist("id", string("1234")), mklist("balance", 1000)); + const list ac2 = mklist(mklist("id", string("6789")), mklist("balance", 2000)); + const list ac3 = mklist(mklist("id", string("4567")), mklist("balance", 3000)); { - const list c = mklist(mklist("customer", mklist("name", std::string("jdoe")), cons("address", ad), mklist("account", mklist(ac1, ac2, ac3)))); + const list c = mklist(mklist("customer", mklist("name", string("jdoe")), cons("address", ad), mklist("account", mklist(ac1, ac2, ac3)))); const list e = valuesToElements(c); const list v = elementsToValues(e); assert(v == c); - std::ostringstream os; - writeXML(xmlWriter, &os, e); - assert(os.str() == customerXML); + ostringstream os; + writeXML(xmlWriter, &os, e); + assert(str(os) == customerXML); } { - const list c = mklist(mklist("customer", mklist("name", std::string("jdoe")), cons("address", ad), cons("account", ac1), cons("account", ac2), cons("account", ac3))); + const list c = mklist(mklist("customer", mklist("name", string("jdoe")), cons("address", ad), cons("account", ac1), cons("account", ac2), cons("account", ac3))); const list e = valuesToElements(c); const list v = elementsToValues(e); - std::ostringstream os; - writeXML(xmlWriter, &os, e); - assert(os.str() == customerXML); + ostringstream os; + writeXML(xmlWriter, &os, e); + assert(str(os) == customerXML); } } { - std::istringstream is(customerXML); + istringstream is(customerXML); const list c = readXML(streamList(is)); const list v = elementsToValues(c); const list e = valuesToElements(v); - std::ostringstream os; - writeXML(xmlWriter, &os, e); - assert(os.str() == customerXML); + ostringstream os; + writeXML(xmlWriter, &os, e); + assert(str(os) == customerXML); } return true; } @@ -153,13 +152,13 @@ bool testElement() { } int main() { - std::cout << "Testing..." << std::endl; + tuscany::cout << "Testing..." << tuscany::endl; tuscany::testReadXML(); tuscany::testWriteXML(); tuscany::testElement(); - std::cout << "OK" << std::endl; + tuscany::cout << "OK" << tuscany::endl; return 0; } diff --git a/sca-cpp/trunk/kernel/xml.hpp b/sca-cpp/trunk/kernel/xml.hpp index eee6e290d8..84cfc30475 100644 --- a/sca-cpp/trunk/kernel/xml.hpp +++ b/sca-cpp/trunk/kernel/xml.hpp @@ -30,9 +30,9 @@ #include #include #include -#include +#include "string.hpp" #include "list.hpp" -#include "slist.hpp" +#include "stream.hpp" #include "value.hpp" #include "element.hpp" #include "monad.hpp" @@ -127,7 +127,7 @@ const value readIdentifier(XMLReader& reader) { */ const value readText(XMLReader& reader) { const char *val = (const char*)xmlTextReaderConstValue(reader); - return std::string(val); + return string(val); } /** @@ -136,7 +136,7 @@ const value readText(XMLReader& reader) { const value readAttribute(XMLReader& reader) { const char *name = (const char*)xmlTextReaderConstName(reader); const char *val = (const char*)xmlTextReaderConstValue(reader); - return mklist(attribute, name, std::string(val)); + return mklist(attribute, name, string(val)); } /** @@ -186,9 +186,9 @@ const list read(XMLReader& reader) { */ class XMLReadContext { public: - XMLReadContext(const list& ilist) : ilist(ilist) { + XMLReadContext(const list& ilist) : ilist(ilist) { } - list ilist; + list ilist; }; /** @@ -198,17 +198,17 @@ int readCallback(void *context, char* buffer, int len) { XMLReadContext& rc = *static_cast(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(); + const list f(fragment(rc.ilist, len)); + const string s(car(f)); + rc.ilist = cdr(f); + memcpy(buffer, c_str(s), length(s)); + return length(s); } /** - * Read a list values from a list of strings representing an XML document. + * Read a list of values from a list of strings representing an XML document. */ -const list readXML(const list& ilist) { +const list readXML(const list& ilist) { XMLReadContext cx(ilist); xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET); if (xml == NULL) @@ -232,15 +232,15 @@ const list expandElementValues(const value& n, const list& l) { return cons(value(cons(element, cons(n, (list)car(l)))), expandElementValues(n, cdr(l))); } -const failable writeList(const list& l, const xmlTextWriterPtr xml) { +const failable writeList(const list& l, const xmlTextWriterPtr xml) { if (isNil(l)) return true; // Write an attribute const value token(car(l)); if (isTaggedList(token, attribute)) { - if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)std::string(attributeName(token)).c_str(), (const xmlChar*)std::string(attributeValue(token)).c_str()) < 0) - return mkfailure("xmlTextWriterWriteAttribute failed"); + if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)c_str(string(attributeName(token))), (const xmlChar*)c_str(string(attributeValue(token)))) < 0) + return mkfailure("xmlTextWriterWriteAttribute failed"); } else if (isTaggedList(token, element)) { @@ -256,38 +256,37 @@ const failable writeList(const list& l, const xmlTextW } else { // Write an element with a single value - if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0) - return mkfailure("xmlTextWriterStartElement failed"); + if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0) + return mkfailure("xmlTextWriterStartElement failed"); // Write its children - const failable w = writeList(elementChildren(token), xml); + const failable w = writeList(elementChildren(token), xml); if (!hasContent(w)) return w; if (xmlTextWriterEndElement(xml) < 0) - return mkfailure("xmlTextWriterEndElement failed"); + return mkfailure("xmlTextWriterEndElement failed"); } } else { // Write an element - if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0) - return mkfailure("xmlTextWriterStartElement failed"); + if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0) + return mkfailure("xmlTextWriterStartElement failed"); // Write its children - const failable w = writeList(elementChildren(token), xml); + const failable w = writeList(elementChildren(token), xml); if (!hasContent(w)) return w; if (xmlTextWriterEndElement(xml) < 0) - return mkfailure("xmlTextWriterEndElement failed"); + return mkfailure("xmlTextWriterEndElement failed"); } } else { // Write XML text - if (xmlTextWriterWriteString(xml, (const xmlChar*)std::string(token).c_str()) < 0) - return mkfailure("xmlTextWriterWriteString failed"); - + if (xmlTextWriterWriteString(xml, (const xmlChar*)c_str(string(token))) < 0) + return mkfailure("xmlTextWriterWriteString failed"); } // Go on @@ -297,16 +296,16 @@ const failable writeList(const list& l, const xmlTextW /** * Write a list of values to a libxml2 XML writer. */ -const failable write(const list& l, const xmlTextWriterPtr xml) { +const failable write(const list& l, const xmlTextWriterPtr xml) { if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0) - return mkfailure("xmlTextWriterStartDocument failed"); + return mkfailure(string("xmlTextWriterStartDocument failed")); - const failable w = writeList(l, xml); + const failable w = writeList(l, xml); if (!hasContent(w)) return w; if (xmlTextWriterEndDocument(xml) < 0) - return mkfailure("xmlTextWriterEndDocument failed"); + return mkfailure("xmlTextWriterEndDocument failed"); return true; } @@ -315,9 +314,9 @@ const failable write(const list& l, const xmlTextWrite */ template class XMLWriteContext { public: - XMLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { + XMLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { } - const lambda reduce; + const lambda reduce; R accum; }; @@ -326,26 +325,26 @@ public: */ template int writeCallback(void *context, const char* buffer, int len) { XMLWriteContext& cx = *static_cast*>(context); - cx.accum = cx.reduce(std::string(buffer, len), cx.accum); + cx.accum = cx.reduce(string(buffer, len), cx.accum); return len; } /** * Convert a list of values to an XML document. */ -template const failable writeXML(const lambda& reduce, const R& initial, const list& l) { +template const failable writeXML(const lambda& reduce, const R& initial, const list& l) { XMLWriteContext cx(reduce, initial); xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback, NULL, &cx, NULL); if (out == NULL) - return mkfailure("xmlOutputBufferCreateIO failed"); + return mkfailure("xmlOutputBufferCreateIO failed"); xmlTextWriterPtr xml = xmlNewTextWriter(out); if (xml == NULL) - return mkfailure("xmlNewTextWriter failed"); + return mkfailure("xmlNewTextWriter failed"); - const failable w = write(l, xml); + const failable w = write(l, xml); xmlFreeTextWriter(xml); if (!hasContent(w)) { - return mkfailure(reason(w)); + return mkfailure(reason(w)); } return cx.accum; } @@ -353,11 +352,11 @@ template const failable writeXML(const lambda, std::string> writeXML(const list& l) { - const failable, std::string> ls = writeXML >(rcons, list(), l); +const failable > writeXML(const list& l) { + const failable > ls = writeXML >(rcons, list(), l); if (!hasContent(ls)) return ls; - return reverse(list(content(ls))); + return reverse(list(content(ls))); } } diff --git a/sca-cpp/trunk/kernel/xsd-test.cpp b/sca-cpp/trunk/kernel/xsd-test.cpp index 818c03ba68..0fc432c649 100644 --- a/sca-cpp/trunk/kernel/xsd-test.cpp +++ b/sca-cpp/trunk/kernel/xsd-test.cpp @@ -23,8 +23,8 @@ * Test validation of a composite file against an SCDL schema. */ -#include -#include +#include "string.hpp" +#include "fstream.hpp" #include #include @@ -35,12 +35,12 @@ bool printNode(xmlTextReaderPtr reader) { if(name == NULL) name = (xmlChar *)""; const xmlChar* value = xmlTextReaderConstValue(reader); - std::cout << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " " + cout << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " " << xmlTextReaderIsEmptyElement(reader) << " " << xmlTextReaderHasValue(reader); if(value == NULL) - std::cout << std::endl; + cout << endl; else - std::cout << value << std::endl; + cout << value << endl; return true; } @@ -54,13 +54,13 @@ int xmlClose(void *context) { } bool readFile(const char*xsdfilename, const char *filename) { - std::cout << "Loading schemas...\n"; + 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"; + cout << "Reading file...\n"; FILE* file = fopen(filename, "r"); if (file != NULL) { const xmlTextReaderPtr reader = xmlReaderForIO(xmlRead, xmlClose, file, filename, NULL, XML_PARSE_NONET); @@ -75,14 +75,14 @@ bool readFile(const char*xsdfilename, const char *filename) { printNode(reader); } if(xmlTextReaderIsValid(reader) != 1) - std::cout << "Could not validate document" << std::endl; + cout << "Could not validate document" << endl; xmlFreeTextReader(reader); if(rc != 0) - std::cout << "Could not parse document" << std::endl; + cout << "Could not parse document" << endl; } else - std::cout << "Could not create parser" << std::endl; + cout << "Could not create parser" << endl; } else - std::cout << "Could not open document" << std::endl; + cout << "Could not open document" << endl; xmlSchemaFreeValidCtxt(validctx); xmlSchemaFree(xsd); @@ -94,7 +94,7 @@ bool readFile(const char*xsdfilename, const char *filename) { } int main(int argc, char **argv) { - std::cout << "Testing..." << std::endl; + tuscany::cout << "Testing..." << tuscany::endl; if(argc != 3) return 1; @@ -102,6 +102,6 @@ int main(int argc, char **argv) { xmlCleanupParser(); - std::cout << "OK" << std::endl; + tuscany::cout << "OK" << tuscany::endl; return 0; } -- cgit v1.2.3