From c39d4c6d143697ee8982df0833499a8de934dd9a Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sat, 26 Sep 2009 21:31:26 +0000 Subject: Refactored the value class. Cleaned up usage of namespaces to remove side effects from includes. Added a few util functions to help work with threads. Added synchronizations to make pointers thread safe. Adjusted store sample to refactoring. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@819220 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/sca/runtime/core/src/tuscany/function.hpp | 51 +++-- cpp/sca/runtime/core/src/tuscany/gc.hpp | 26 +-- cpp/sca/runtime/core/src/tuscany/list.hpp | 63 ++++-- cpp/sca/runtime/core/src/tuscany/parallel.hpp | 283 ++++++++++++++++++++++++++ cpp/sca/runtime/core/src/tuscany/value.hpp | 212 ++++++++++--------- 5 files changed, 481 insertions(+), 154 deletions(-) create mode 100644 cpp/sca/runtime/core/src/tuscany/parallel.hpp (limited to 'cpp/sca/runtime') diff --git a/cpp/sca/runtime/core/src/tuscany/function.hpp b/cpp/sca/runtime/core/src/tuscany/function.hpp index e0e8889dad..caba5211b9 100644 --- a/cpp/sca/runtime/core/src/tuscany/function.hpp +++ b/cpp/sca/runtime/core/src/tuscany/function.hpp @@ -23,14 +23,12 @@ #define tuscany_function_hpp /** - * Lambda function type, used to represent service operations. + * Lambda function type. */ #include #include "gc.hpp" -using std::ostream; - namespace tuscany { /** @@ -50,15 +48,13 @@ bool resetLambdaCounters() { } bool printLambdaCounters() { - using std::cout; - using 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; + std::cout << "countLambdas " << countLambdas << std::endl; + std::cout << "countELambdas " << countELambdas << std::endl; + std::cout << "countFLambdas " << countFLambdas << std::endl; + std::cout << "countCLambdas " << countCLambdas << std::endl; + std::cout << "countProxies " << countProxies << std::endl; + std::cout << "countFProxies " << countFProxies << std::endl; + std::cout << "countCProxies " << countCProxies << std::endl; return true; } @@ -81,11 +77,11 @@ public: } unsigned int acquire() { - return ++refCount; + return __sync_add_and_fetch(&refCount, 1); } unsigned int release() { - return --refCount; + return __sync_sub_and_fetch(&refCount, 1); } template class Proxy: public Callable { @@ -95,7 +91,7 @@ public: countFProxies ++; } - Proxy(const Proxy& p) : function(p.function) { + explicit Proxy(const Proxy& p) : function(p.function) { countProxies++; countCProxies ++; } @@ -166,14 +162,14 @@ public: return (*callable)(std::forward

(p)...); } - template friend ostream& operator<<(ostream&, const lambda&); + template friend std::ostream& operator<<(std::ostream&, const lambda&); private: typedef Callable CallableType; gc_counting_ptr callable; }; -template ostream& operator<<(ostream& out, const lambda& l) { +template std::ostream& operator<<(std::ostream& out, const lambda& l) { return out << "lambda::" << l.callable; } @@ -187,23 +183,22 @@ template lambda makeLambda(const R (* const /** * Curry a lambda function. */ -template class Curried { -private: - const T v; - const lambdaf; - +template class curried { public: - Curried(const lambda& f, const T& v): v(v), f(f) { + curried(const lambda& f, const T& v): v(v), f(f) { } const R operator()(P... p) const { return f(v, std::forward

(p)...); } +private: + const T v; + const lambdaf; }; template const lambda curry(const lambda& f, const T& t) { - return (lambda)Curried(f, t); + return (lambda)curried(f, t); } template const lambda curry(const lambda& f, const T& t, const U& u) { @@ -217,14 +212,16 @@ template const la /** * A lambda function that returns the given value. */ -template struct unitReturn { - const T v; - unitReturn(const T& v) : +template class unitReturn { +public: + explicit unitReturn(const T& v) : v(v) { } const T operator()() const { return v; } +private: + const T v; }; template const lambda unit(const T& v) { diff --git a/cpp/sca/runtime/core/src/tuscany/gc.hpp b/cpp/sca/runtime/core/src/tuscany/gc.hpp index 803ec31643..b0ed42a474 100644 --- a/cpp/sca/runtime/core/src/tuscany/gc.hpp +++ b/cpp/sca/runtime/core/src/tuscany/gc.hpp @@ -26,9 +26,7 @@ * Garbage collected pointer. */ -#include - -using std::ostream; +#include namespace tuscany { @@ -81,7 +79,7 @@ public: return countingRef->ptr; } - template friend ostream& operator<<(ostream&, const gc_ptr&); + template friend std::ostream& operator<<(std::ostream&, const gc_ptr&); private: struct CountingRef { @@ -95,12 +93,13 @@ private: void acquire(CountingRef* ref) throw() { if(ref) - ++ref->count; + __sync_add_and_fetch(&ref->count, 1); } void release() throw() { if(countingRef) { - if(--countingRef->count == 0) { + unsigned rc = __sync_sub_and_fetch(&countingRef->count, 1); + if(rc == 0) { delete countingRef->ptr; delete countingRef; } @@ -108,7 +107,7 @@ private: } }; -template ostream& operator<<(ostream& out, const gc_ptr& p) { +template std::ostream& operator<<(std::ostream& out, const gc_ptr& p) { return out << p.countingRef->ptr; } @@ -163,7 +162,7 @@ public: return countingRef->ptr; } - template friend ostream& operator<<(ostream&, const gc_aptr&); + template friend std::ostream& operator<<(std::ostream&, const gc_aptr&); private: struct CountingRef { @@ -177,12 +176,13 @@ private: void acquire(CountingRef* ref) throw() { if(ref) - ++ref->count; + __sync_add_and_fetch(&ref->count, 1); } void release() throw() { if(countingRef) { - if(--countingRef->count == 0) { + unsigned rc = __sync_sub_and_fetch(&countingRef->count, 1); + if(rc == 0) { delete[] countingRef->ptr; delete countingRef; } @@ -190,7 +190,7 @@ private: } }; -template ostream& operator<<(ostream& out, const gc_aptr& p) { +template std::ostream& operator<<(std::ostream& out, const gc_aptr& p) { return out << p.countingRef->ptr; } @@ -242,7 +242,7 @@ public: return ptr; } - template friend ostream& operator<<(ostream&, const gc_counting_ptr&); + template friend std::ostream& operator<<(std::ostream&, const gc_counting_ptr&); private: T* ptr; @@ -261,7 +261,7 @@ private: } }; -template ostream& operator<<(ostream& out, const gc_counting_ptr& p) { +template std::ostream& operator<<(std::ostream& out, const gc_counting_ptr& p) { return out << p.ptr; } diff --git a/cpp/sca/runtime/core/src/tuscany/list.hpp b/cpp/sca/runtime/core/src/tuscany/list.hpp index e180ad6134..ef493b19ca 100644 --- a/cpp/sca/runtime/core/src/tuscany/list.hpp +++ b/cpp/sca/runtime/core/src/tuscany/list.hpp @@ -29,8 +29,6 @@ #include #include "function.hpp" -using std::ostream; - namespace tuscany { long countlists = 0; @@ -44,12 +42,10 @@ bool resetlistCounters() { } bool printlistCounters() { - using std::cout; - using std::endl; - cout << "countlists " << countlists << endl; - cout << "countElists " << countElists << endl; - cout << "countIlists " << countIlists << endl; - cout << "countClists " << countClists << endl; + std::cout << "countlists " << countlists << std::endl; + std::cout << "countElists " << countElists << std::endl; + std::cout << "countIlists " << countIlists << std::endl; + std::cout << "countClists " << countClists << std::endl; return true; } @@ -57,12 +53,10 @@ bool printlistCounters() { * A car/cdr lisp-like pair, base structure to construct lists. */ -template struct list { - bool nil; - T car; - lambda ()> cdr; +template class list { +public: - list(const T car, const lambda ()> cdr) : + list(const T car, const lambda ()>& cdr) : nil(false), car(car), cdr(cdr) { countlists++; countIlists++; @@ -111,8 +105,11 @@ template struct list { return !this->operator==(p); } - template friend ostream& operator<<(ostream&, const list&); + template friend std::ostream& operator<<(std::ostream&, const list&); + bool nil; + T car; + lambda ()> cdr; }; /** @@ -125,7 +122,7 @@ template const bool isNil(const list& p) { /** * Write a list to an output stream. */ -template ostream& operator<<(ostream& out, const list& l) { +template std::ostream& operator<<(std::ostream& out, const list& l) { if(l == list ()) return out << "()"; return out << "(" << car(l) << ", " << cdr(l) << ")"; @@ -194,6 +191,13 @@ template const T cadr(const list& p) { return car(cdr(p)); } +/** + * Returns the car of the cdr of the cdr of a list. + */ +template const T caddr(const list& p) { + return car(cdr(cdr(p))); +} + /** * Returns the cdr of a cdr of a list. */ @@ -201,6 +205,13 @@ template const list cddr(const list& p) { return cdr(cdr(p)); } +/** + * Returns the cdr of a cdr of the cdr of a list. + */ +template const list cdddr(const list& p) { + return cdr(cdr(cdr(p))); +} + /** * Returns the length of a list. */ @@ -258,7 +269,7 @@ template const list map(const lambda& f, const */ template struct reduceAccumulate { const lambda f; - reduceAccumulate(const lambda& f) : + explicit reduceAccumulate(const lambda& f) : f(f) { } R operator()(const R& acc, const list& p) const { @@ -344,5 +355,25 @@ template const list assoc(const T& k, const list >& p) { return assoc(k, cdr(p)); } +/** + * Pretty print a list. + */ +template std::ostream& print(const list& l, std::ostream& os) { + os << "("; + if (!isNil(l)) { + list ml = l; + while(true) { + os << car(ml); + ml = cdr(ml); + if (isNil(ml)) + break; + os << ", "; + } + } + os << ")"; + return os; +} + } + #endif /* tuscany_list_hpp */ diff --git a/cpp/sca/runtime/core/src/tuscany/parallel.hpp b/cpp/sca/runtime/core/src/tuscany/parallel.hpp new file mode 100644 index 0000000000..c0d578e281 --- /dev/null +++ b/cpp/sca/runtime/core/src/tuscany/parallel.hpp @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_parallel_hpp +#define tuscany_parallel_hpp + +/** + * Simple parallel work execution functions. + */ + +#include +#include +#include "function.hpp" + +namespace tuscany { + +/** + * Returns the current thread id. + */ +unsigned int threadId() { + return syscall(__NR_gettid); +} + +/** + * Represents a value which will be know in the future. + */ +template class future { + +private: + template class futureValue { + public: + futureValue() : + refCount(0), hasValue(false) { + pthread_mutex_init(&valueMutex, NULL); + pthread_cond_init(&valueCond, NULL); + } + + ~futureValue() { + pthread_mutex_destroy(&valueMutex); + pthread_cond_destroy(&valueCond); + } + + unsigned int acquire() { + return __sync_add_and_fetch(&refCount, 1); + } + + unsigned int release() { + return __sync_sub_and_fetch(&refCount, 1); + } + + bool set(const T& v) { + pthread_mutex_lock(&valueMutex); + if(hasValue) { + pthread_mutex_unlock(&valueMutex); + return false; + } + hasValue = true; + value = v; + pthread_mutex_unlock(&valueMutex); + pthread_cond_broadcast(&valueCond); + return true; + } + + const T get() { + pthread_mutex_lock(&valueMutex); + while(!hasValue) { + pthread_cond_wait(&valueCond, &valueMutex); + } + const T& v = value; + pthread_mutex_unlock(&valueMutex); + return v; + } + + private: + unsigned refCount; + pthread_mutex_t valueMutex; + pthread_cond_t valueCond; + bool hasValue; + X value; + }; + + gc_counting_ptr > 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() { + //std::cout << "~future() threadId " << threadId() << "\n"; + } + + future(const future& f) : fvalue(f.fvalue) { + //std::cout << "future(const future& f) threadId " << threadId() << "\n"; + } + + const future& operator=(const future& f) { + //std::cout << "future::operator=(const future& f) threadId " << threadId() << "\n"; + if (&f == this) + return *this; + fvalue = f.fvalue; + return *this; + } + + const future& operator=(const T& v) const { + fvalue->set(v); + return *this; + } + + operator const T() const { + return fvalue->get(); + } + +}; + +/** + * A bounded thread safe queue. + */ +template class queue { +public: + explicit queue(int max) : max(max), size(0), tail(0), head(0), values(new T[max]) { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&full, NULL); + pthread_cond_init(&empty, NULL); + } + + ~queue() { + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&full); + pthread_cond_destroy(&empty); + } + +private: + const int max; + int size; + int tail; + int head; + pthread_mutex_t mutex; + pthread_cond_t full; + pthread_cond_t empty; + gc_aptr values; + + template friend const int enqueue(queue& q, const X& v); + template friend const X dequeue(queue& q); +}; + +/** + * Adds an element to the tail of the queue. + */ +template const int enqueue(queue&q, const T& v) { + pthread_mutex_lock(&q.mutex); + while(q.size == q.max) + pthread_cond_wait(&q.full, &q.mutex); + q.values[q.tail] = v; + q.tail = (q.tail + 1) % q.max; + q.size++; + pthread_mutex_unlock(&q.mutex); + pthread_cond_broadcast(&q.empty); + return q.size; +} + +/** + * Returns the element at the head of the queue. + */ +template const T dequeue(queue& q) { + pthread_mutex_lock(&q.mutex); + while(q.size == 0) + pthread_cond_wait(&q.empty, &q.mutex); + const T v = q.values[q.head]; + q.head = (q.head + 1) % q.max; + q.size--; + pthread_mutex_unlock(&q.mutex); + pthread_cond_broadcast(&q.full); + return v; +} + +/** + * The worker thread function. + */ +void *workerThreadFunc(void *arg) { + queue >* work = reinterpret_cast >*>(arg); + while(dequeue(*work)()) + ; + return NULL; +} + +/** + * Returns a list of worker threads. + */ +const list makeWorkerThreads(queue >& queue, const int count) { + if (count == 0) + return list(); + pthread_t thread; + pthread_create(&thread, NULL, workerThreadFunc, &queue); + return cons(thread, makeWorkerThreads(queue, count - 1)); +} + +/** + * A worker, implemented with a work queue and a pool of threads. + */ +class worker { +public: + explicit worker(int max) : work(queue >(max)), threads(makeWorkerThreads(work, max)) { + } + +private: + queue > work; + const list threads; + + template friend const future submit(worker& w, const lambda& func); + friend const bool shutdown(worker& w); +}; + +/** + * Function used to wrap work submitted to a worker. + */ +template bool submitFunc(const lambda& func, const future& fut) { + fut = func(); + return true; +} + +/** + * Submits work to a worker. + */ +template const future submit(worker& w, const lambda& func) { + const future fut; + const lambda f = curry(lambda, future)>(submitFunc), func, fut); + enqueue(w.work, f); + return fut; +} + +/** + * Enqueues shutdown requests. + */ +const bool shutdownEnqueue(const list& threads, queue >& work) { + if (threads == list()) + return true; + enqueue(work, unit(false)); + return shutdownEnqueue(cdr(threads), work); +} + +/** + * Waits for shut down threads to terminate. + */ +const bool shutdownJoin(const list& threads) { + if (threads == list()) + return true; + pthread_join(car(threads), NULL); + return shutdownJoin(cdr(threads)); +} + +/** + * Shutdown a worker. + */ +const bool shutdown(worker& w) { + shutdownEnqueue(w.threads, w.work); + shutdownJoin(w.threads); + return true; +} + +} +#endif /* tuscany_parallel_hpp */ diff --git a/cpp/sca/runtime/core/src/tuscany/value.hpp b/cpp/sca/runtime/core/src/tuscany/value.hpp index e92a9178ca..ca4bd06ca6 100644 --- a/cpp/sca/runtime/core/src/tuscany/value.hpp +++ b/cpp/sca/runtime/core/src/tuscany/value.hpp @@ -27,16 +27,11 @@ */ #include -#include +#include #include "gc.hpp" #include "function.hpp" #include "list.hpp" -using std::string; -using std::ostream; -using std::cout; -using std::endl; - namespace tuscany { @@ -51,72 +46,70 @@ bool resetValueCounters() { } bool printValueCounters() { - using std::cout; - using std::endl; - cout << "countValues " << countValues << endl; - cout << "countEValues " << countEValues << endl; - cout << "countCValues " << countCValues << endl; - cout << "countVValues " << countVValues << endl; + std::cout << "countValues " << countValues << std::endl; + std::cout << "countEValues " << countEValues << std::endl; + std::cout << "countCValues " << countCValues << std::endl; + std::cout << "countVValues " << countVValues << std::endl; return true; } -class Value; +class value; -class Value { +class value { public: enum ValueType { Undefined, Symbol, String, List, Number, Boolean, Character, Lambda }; - Value() : - type(Value::Undefined) { + value() : + type(value::Undefined) { countValues++; countEValues++; } - Value(const Value& v) { + value(const value& v) { countValues++; countCValues++; type = v.type; switch(type) { - case Value::List: + case value::List: lst() = v.lst(); - case Value::Lambda: + case value::Lambda: func() = v.func(); - case Value::Symbol: + case value::Symbol: str() = v.str(); - case Value::String: + case value::String: str() = v.str(); - case Value::Number: + case value::Number: num() = v.num(); - case Value::Boolean: + case value::Boolean: boo() = v.boo(); - case Value::Character: + case value::Character: chr() = v.chr(); default: break; } } - const Value& operator=(const Value& v) { + const value& operator=(const value& v) { if(this == &v) return *this; type = v.type; switch(type) { - case Value::List: + case value::List: lst() = v.lst(); - case Value::Lambda: + case value::Lambda: func() = v.func(); - case Value::Symbol: + case value::Symbol: str() = v.str(); - case Value::String: + case value::String: str() = v.str(); - case Value::Number: + case value::Number: num() = v.num(); - case Value::Boolean: + case value::Boolean: boo() = v.boo(); - case Value::Character: + case value::Character: chr() = v.chr(); default: break; @@ -124,122 +117,122 @@ public: return *this; } - virtual ~Value() { + virtual ~value() { countValues--; } - Value(const lambda&)>& func) : - type(Value::Lambda), data(vdata(func)) { + explicit value(const lambda&)>& func) : + type(value::Lambda), data(vdata(func)) { countValues++; countVValues++; } - Value(const string& str) : - type(Value::String), data(vdata(unit(str))) { + explicit value(const std::string& str) : + type(value::String), data(vdata(unit(str))) { countValues++; countVValues++; } - Value(const char* str) : - type(Value::Symbol), data(vdata(unit(string(str)))) { + explicit value(const char* str) : + type(value::Symbol), data(vdata(unit(std::string(str)))) { countValues++; countVValues++; } - Value(const list& lst) : - type(Value::List), data(vdata(unit(lst))) { + explicit value(const list& lst) : + type(value::List), data(vdata(unit(lst))) { countValues++; countVValues++; } - Value(const double num) : - type(Value::Number), data(vdata(unit(num))) { + explicit value(const double num) : + type(value::Number), data(vdata(unit(num))) { countValues++; countVValues++; } - Value(const int num) : - type(Value::Number), data(vdata(unit((double)num))) { + explicit value(const int num) : + type(value::Number), data(vdata(unit((double)num))) { countValues++; countVValues++; } - Value(const bool boo) : - type(Value::Boolean), data(vdata(unit(boo))) { + explicit value(const bool boo) : + type(value::Boolean), data(vdata(unit(boo))) { countValues++; countVValues++; } - Value(const char chr) : - type(Value::Character), data(vdata(unit(chr))) { + explicit value(const char chr) : + type(value::Character), data(vdata(unit(chr))) { countValues++; countVValues++; } - const bool operator!=(const Value& v) const { + const bool operator!=(const value& v) const { return !this->operator==(v); } - const bool operator==(const Value& v) const { + const bool operator==(const value& v) const { if(this == &v) return true; if(type != v.type) return false; switch(type) { - case Value::Undefined: + case value::Undefined: return true; - case Value::List: + case value::List: return lst()() == v.lst()(); - case Value::Lambda: + case value::Lambda: return func() == v.func(); - case Value::Symbol: + case value::Symbol: return str()() == v.str()(); - case Value::String: + case value::String: return str()() == v.str()(); - case Value::Number: + case value::Number: return num()() == v.num()(); - case Value::Boolean: + case value::Boolean: return boo()() == v.boo()(); - case Value::Character: + case value::Character: return chr()() == v.chr()(); default: return false; } } - const Value operator()(list& args) const { + const value operator()(list& args) const { return func()(args); } - operator string() const { + operator const std::string() const { return str()(); } - operator double() const { + operator const double() const { return num()(); } - operator int() const { + operator const int() const { return num()(); } - operator bool() const { + operator const bool() const { return boo()(); } - operator char() const { + operator const char() const { return chr()(); } - operator list() const { + operator const list() const { return lst()(); } - operator lambda&)>() const { + operator const lambda&)>() const { return func(); } - friend ostream& operator<<(ostream&, const Value&); + friend std::ostream& operator<<(std::ostream&, const value&); ValueType type; lambda data; @@ -265,77 +258,100 @@ private: return vdata (); } - lambda& str() const { - return vdata (); + lambda& str() const { + return vdata (); } - lambda()>& lst() const { - return vdata()> (); + lambda()>& lst() const { + return vdata()> (); } - lambda&)>& func() const { - return vdata&)> (); + lambda&)>& func() const { + return vdata&)> (); } }; -ostream& operator<<(ostream& out, const Value& v) { +std::ostream& operator<<(std::ostream& out, const value& v) { switch(v.type) { - case Value::List: + case value::List: return out << "List::" << v.lst()(); - case Value::Lambda: + case value::Lambda: return out << "Lambda::" << v.func(); - case Value::Symbol: + case value::Symbol: return out << "Symbol::" << v.str()(); - case Value::String: + case value::String: return out << "String::" << '\'' << v.str()() << '\''; - case Value::Number: + case value::Number: return out << "Number::" << v.num()(); - case Value::Boolean: + case value::Boolean: if(v.boo()()) return out << "Boolean::" << "true"; else return out << "Boolean::" << "false"; - case Value::Character: + case value::Character: return out << "Character::" << v.chr()(); default: return out << "Undefined"; } } -const bool isNull(const Value& value) { - return value.type == Value::Undefined; +const bool isNil(const value& value) { + return value.type == value::Undefined; } -const bool isString(const Value& value) { - return value.type == Value::String; +const bool isString(const value& value) { + return value.type == value::String; } -const bool isSymbol(const Value& value) { - return value.type == Value::Symbol; +const bool isSymbol(const value& value) { + return value.type == value::Symbol; } -const bool isList(const Value& value) { - return value.type == Value::List; +const bool isList(const value& value) { + return value.type == value::List; } -const bool isNumber(const Value& value) { - return value.type == Value::Number; +const bool isNumber(const value& value) { + return value.type == value::Number; } -const bool isBoolean(const Value& value) { - return value.type == Value::Boolean; +const bool isBoolean(const value& value) { + return value.type == value::Boolean; } -const bool isCharacter(const Value& value) { - return value.type == Value::Character; +const bool isCharacter(const value& value) { + return value.type == value::Character; } -const bool isTaggedList(const Value& exp, Value tag) { +const bool isTaggedList(const value& exp, value tag) { if(isList(exp)) - return car((list )exp) == tag; + return car((list )exp) == tag; return false; } +/** + * Pretty print a list of values. + */ +std::ostream& print(const list& l, std::ostream& os) { + os << "("; + if (!isNil(l)) { + list ml = l; + while(true) { + const value v = car(ml); + if (isList(v)) + print(list(v), os); + else + os << v; + ml = cdr(ml); + if (isNil(ml)) + break; + os << ", "; + } + } + os << ")"; + return os; +} + } #endif /* tuscany_value_hpp */ -- cgit v1.2.3