/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* $Rev$ $Date$ */ #ifndef tuscany_value_hpp #define tuscany_value_hpp /** * Generic value type. */ #include #include #include #include "string.hpp" #include "sstream.hpp" #include "gc.hpp" #include "function.hpp" #include "list.hpp" #include "monad.hpp" namespace tuscany { #ifdef WANT_MAINTAINER_COUNTERS /** * Debug utilities. Counters used to track instances of values */ long int countValues = 0; long int countEValues = 0; long int countCValues = 0; long int countVValues = 0; bool resetValueCounters() { countValues = countEValues = countCValues = countVValues = 0; return true; } bool checkValueCounters() { return countValues == 0; } bool printValueCounters() { cout << "countValues " << countValues << endl; cout << "countEValues " << countEValues << endl; cout << "countCValues " << countCValues << endl; cout << "countVValues " << countVValues << endl; return true; } #else #define resetValueCounters() #define checkValueCounters() true #define printValueCounters() #endif #ifdef WANT_MAINTAINER_WATCH /** * Debug utilities. Macro used to write the contents of a value to * a string, easier to watch in a debugger than the value itself. */ #define debug_watchValue() do { \ this->watch = watchValue(*this); \ } while (0) #else #define debug_watchValue() #endif class value; class value { public: enum ValueType { Nil, Symbol, String, List, Number, Bool, Lambda, Ptr }; value() : type(value::Nil) { debug_inc(countValues); debug_inc(countEValues); debug_watchValue(); } value(const value& v) { debug_inc(countValues); debug_inc(countCValues); type = v.type; switch(type) { case value::List: lst() = v.lst(); case value::Lambda: func() = v.func(); case value::Symbol: str() = v.str(); case value::String: str() = v.str(); case value::Number: num() = v.num(); case value::Bool: boo() = v.boo(); case value::Ptr: ptr() = v.ptr(); default: break; } #ifdef WANT_MAINTAINER_WATCH watch = v.watch; #endif } virtual ~value() { debug_dec(countValues); } value(const lambda&)>& func) : type(value::Lambda), data(vdata(func)) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const string& str) : type(value::String), data(vdata(result(str))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const char* str) : type(value::Symbol), data(vdata(result(string(str)))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const list& lst) : type(value::List), data(vdata(result(lst))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const list >& l) : type(value::List), data(vdata(result(listOfValues(l)))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const double num) : type(value::Number), data(vdata(result(num))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const int num) : type(value::Number), data(vdata(result((double)num))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const bool boo) : type(value::Bool), data(vdata(result(boo))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const gc_ptr ptr) : type(value::Ptr), data(vdata(result(ptr))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const failable& m) : type(value::List), data(vdata(result(hasContent(m)? mklist(content(m)) : mklist(value(), reason(m))))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } value(const maybe& m) : type(value::List), data(vdata(result(hasContent(m)? mklist(content(m)) : list()))) { debug_inc(countValues); debug_inc(countVValues); debug_watchValue(); } const value& operator=(const value& v) { if(this == &v) return *this; type = v.type; switch(type) { case value::List: lst() = v.lst(); case value::Lambda: func() = v.func(); case value::Symbol: str() = v.str(); case value::String: str() = v.str(); case value::Number: num() = v.num(); case value::Bool: boo() = v.boo(); case value::Ptr: ptr() = v.ptr(); default: break; } #ifdef WANT_MAINTAINER_WATCH watch = v.watch; #endif return *this; } const bool operator!=(const value& v) const { return !this->operator==(v); } const bool operator==(const value& v) const { if(this == &v) return true; switch(type) { case value::Nil: return v.type == value::Nil; case value::List: return v.type == value::List && lst()() == v.lst()(); case value::Lambda: return v.type == value::Lambda && func() == v.func(); case value::Symbol: case value::String: return str()() == (string)v; case value::Number: return num()() == (double)v; case value::Bool: return boo()() == (bool)v; case value::Ptr: return v.type == value::Ptr && ptr()() == v.ptr()(); default: return false; } } const bool operator<(const value& v) const { if(this == &v) return false; switch(type) { case value::List: return v.type == value::List && lst()() < v.lst()(); case value::Symbol: case value::String: return str()() < (string)v; case value::Bool: return boo()() < (bool)v; case value::Number: return num()() < (double)v; default: return false; } } const bool operator>(const value& v) const { if(this == &v) return false; switch(type) { case value::List: return v.type == value::List && lst()() > v.lst()(); case value::Symbol: case value::String: return str()() > (string)v; case value::Bool: return boo()() > (bool)v; case value::Number: return num()() > (double)v; default: return false; } } const value operator()(const list& args) const { return func()(args); } operator const string() const { switch(type) { case value::Symbol: case value::String: return str()(); case value::Number: { ostringstream os; os << num()(); return tuscany::str(os); } case value::Bool: return boo()()? trueString : falseString; default: return emptyString; } } operator const double() const { switch(type) { case value::Symbol: case value::String: return atof(c_str(str()())); case value::Number: return (double)num()(); case value::Bool: return boo()()? 1.0 : 0.0; default: return 0.0; } } operator const int() const { switch(type) { case value::Symbol: case value::String: return atoi(c_str(str()())); case value::Number: return (int)num()(); case value::Bool: return boo()()? 1 : 0; default: return 0; } } operator const bool() const { switch(type) { case value::Symbol: case value::String: return str()() == string("true"); case value::Number: return (int)num()() != 0; case value::Bool: return boo()(); default: return 0; } } operator const gc_ptr() const { return ptr()(); } operator const list() const { return lst()(); } operator const list >() const { return listOfListOfValues(lst()()); } operator const lambda&)>() const { return func(); } private: template lambda& vdata() const { return *reinterpret_cast *> (const_cast *> (&data)); } template const lambda& vdata(const T& v) const { return *reinterpret_cast *> (&v); } lambda& num() const { return vdata (); } lambda& boo() const { return vdata (); } lambda()>& ptr() const { return vdata()> (); } lambda& str() const { return vdata (); } lambda()>& lst() const { return vdata()> (); } lambda&)>& func() const { return vdata&)> (); } const list listOfValues(const list >& l) const { if (isNil(l)) return list(); return cons(car(l), listOfValues(cdr(l))); } const list > listOfListOfValues(const list& l) const { if (isNil(l)) return list >(); return cons >(list(car(l)), listOfListOfValues(cdr(l))); } friend ostream& operator<<(ostream&, const value&); friend const value::ValueType type(const value& v); #ifdef WANT_MAINTAINER_WATCH friend const string watchValue(const value& v); string watch; #endif ValueType type; lambda data; }; #ifdef WANT_MAINTAINER_WATCH /** * Debug utility used to write the contents of a value to a string, easier * to watch than the value itself in a debugger. */ const string watchValue(const value& v) { if (v.type == value::List) return watchList(v); odebugstream os; os << v; return str(os); } #endif /** * Write an escape string to a buffer. */ const char* escapestr(const char* s, char* buf) { if (*s == '\0') { *buf = '\0'; return buf; } if (*s == '\\' || *s == '"') { *buf = '\\'; *(buf + 1) = *s; return escapestr(s + 1, buf + 2); } *buf = *s; return escapestr(s + 1, buf + 1); } /** * Write an escaped string value to a stream. */ ostream& escvwrite(const string& str, ostream& out) { char* buf = gc_cnew(length(str) * 2 + 1); escapestr(c_str(str), buf); out << buf; return out; } /** * Write a value to a stream. */ ostream& operator<<(ostream& out, const value& v) { switch(v.type) { case value::List: return out << v.lst()(); case value::Lambda: return out << "lambda::" << v.func(); case value::Symbol: return out << v.str()(); case value::String: out << '\"'; escvwrite(v.str()(), out); return out << '\"'; case value::Number: return out << v.num()(); case value::Bool: if(v.boo()()) return out << "true"; else return out << "false"; case value::Ptr: { const gc_ptr p = v.ptr()(); if (p == gc_ptr(NULL)) return out << "gc_ptr::null"; return out << "gc_ptr::" << p; } default: return out << "nil"; } } /** * Returns the type of a value. */ const value::ValueType type(const value& v) { return v.type; } /** * Returns true if a value is nil. */ const bool isNil(const value& v) { return type(v) == value::Nil; } /** * Returns true if a value is a lambda. */ const bool isLambda(const value& v) { return type(v) == value::Lambda; } /** * Returns true if a value is a string. */ const bool isString(const value& v) { return type(v) == value::String; } /** * Returns true if a value is a symbol. */ const bool isSymbol(const value& v) { return type(v) == value::Symbol; } /** * Returns true if a value is a list. */ const bool isList(const value& v) { return type(v) == value::List; } /** * Returns true if a value is a number. */ const bool isNumber(const value& v) { return type(v) == value::Number; } /** * Returns true if a value is a boolean. */ const bool isBool(const value& v) { return type(v) == value::Bool; } /** * Returns true if a value is a pointer. */ const bool isPtr(const value& v) { return type(v) == value::Ptr; } /** * Returns true if a value is a tagged list. */ const bool isTaggedList(const value& exp, value tag) { if(isList(exp) && !isNil((list)exp)) return car((list)exp) == tag; return false; } /** * Make a list of values from a list of other things. */ template const list mkvalues(const list& l) { if (isNil(l)) return list(); return cons(car(l), mkvalues(cdr(l))); } /** * Convert a list of values to a list of other things. */ template const list convertValues(const list& l) { if (isNil(l)) return list(); return cons(car(l), convertValues(cdr(l))); } /** * Convert a path string value to a list of values. */ const list pathTokens(const char* p) { if (p == NULL || p[0] == '\0') return list(); if (p[0] == '/') return tokenize("/", p + 1); return tokenize("/", p); } const list pathValues(const value& p) { return mkvalues(pathTokens(c_str(p))); } /** * Convert a path represented as a list of values to a string value. */ const value path(const list& p) { if (isNil(p)) return ""; return string("/") + car(p) + path(cdr(p)); } /** * Make a uuid value. */ const value mkuuid() { apr_uuid_t id; apr_uuid_get(&id); char buf[APR_UUID_FORMATTED_LENGTH]; apr_uuid_format(buf, &id); return value(string(buf, APR_UUID_FORMATTED_LENGTH)); } /** * Make a random alphanumeric value. */ const int intrand() { const apr_uint64_t now = apr_time_now(); srand((unsigned int)(((now >> 32) ^ now) & 0xffffffff)); return rand() & 0x0FFFF; } const value mkrand() { char buf[32]; const char* an = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (int i =0; i < 32; i++) buf[i] = an[intrand() % 62]; return value(string(buf, 32)); } } #endif /* tuscany_value_hpp */