From c9bfccc35345ce58fb5774d4b0b6a9868b262c0a Mon Sep 17 00:00:00 2001 From: giorgio Date: Wed, 5 Sep 2012 08:31:30 +0000 Subject: git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1381061 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/branches/lightweight-sca/kernel/monad.hpp | 627 ++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 sca-cpp/branches/lightweight-sca/kernel/monad.hpp (limited to 'sca-cpp/branches/lightweight-sca/kernel/monad.hpp') diff --git a/sca-cpp/branches/lightweight-sca/kernel/monad.hpp b/sca-cpp/branches/lightweight-sca/kernel/monad.hpp new file mode 100644 index 0000000000..b67e92ad79 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/monad.hpp @@ -0,0 +1,627 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_monad_hpp +#define tuscany_monad_hpp + +/** + * Simple monad implementations. + */ + +#include +#include +#include "function.hpp" +#include "string.hpp" +#include "stream.hpp" +#include "sstream.hpp" +#include "fstream.hpp" + +namespace tuscany +{ + +/** + * Identity monad. Just wraps a value. + * To get the value in the monad, just cast it to the value type. + */ +template class id { +public: + id(const V& v) : v(v) { + } + + const id& operator=(const id& m) { + if(this == &m) + return *this; + v = m.v; + return *this; + } + + const bool operator!=(const id& m) const { + return !this->operator==(m); + } + + const bool operator==(const id& m) const { + if (&m == this) + return true; + return v == m.v; + } + +private: + const V v; + + template friend const X content(const id& m); +}; + +/** + * Write an identity monad to a stream. + */ +template ostream& operator<<(ostream& out, const id& m) { + out << content(m); + return out; +} + +/** + * Returns the content of an identity monad. + */ +template const V content(const id& m) { + return m.v; +} + +/** + * Return an identity monad from a value. + */ +template const id mkunit(const V& v) { + return id(v); +} + +template const lambda(const V)> unit() { + return mkunit; +} + +/** + * Bind a function to an identity monad. Pass the value in the monad to the function. + */ +template const id operator>>(const id& m, const lambda(const V)>& f) { + return f(content(m)); +} + +template const id operator>>(const id& m, const id (* const f)(const V)) { + return f(content(m)); +} + +/** + * Maybe monad. Used to represent an optional value, which may be there or not. + * To get the value in the monad, just cast it to the value type. + */ +template class maybe { +public: + maybe(const V& v) : hasv(true), v(v) { + } + + maybe() : hasv(false) { + } + + const maybe& operator=(const maybe& m) { + if(this == &m) + return *this; + hasv = m.hasv; + if (hasv) + v = m.v; + return *this; + } + + const bool operator!=(const maybe& m) const { + return !this->operator==(m); + } + + const bool operator==(const maybe& m) const { + if (this == &m) + return true; + if (!hasv) + return !m.hasv; + return m.hasv && v == m.v; + } + +private: + const bool hasv; + V v; + + template friend const bool hasContent(const maybe& m); + template friend const X content(const maybe& m); +}; + +/** + * Write a maybe monad to a stream. + */ +template ostream& operator<<(ostream& out, const maybe& m) { + if (!hasContent(m)) { + out << "nothing"; + return out; + } + out << content(m); + return out; +} + +/** + * Return a maybe monad with a value in it. + */ +template const maybe mkjust(const V& v) { + return maybe(v); +} + +template const lambda(const V)> just() { + return mkjust; +} + +/** + * Returns true if a maybe monad contains a content. + */ +template const bool hasContent(const maybe& m) { + return m.hasv; +} + +/** + * Returns the content of a maybe monad. + */ +template const V content(const maybe& m) { + return m.v; +} + +/** + * Bind a function to a maybe monad. Passes the value in the monad to the function + * if present, or does nothing if there's no value. + */ +template const maybe operator>>(const maybe& m, const lambda(const V)>& f) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +template const maybe operator>>(const maybe& m, const maybe (* const f)(const V)) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +/** + * Failable monad. Used to represent either a success value or a failure. + * To get the value in the monad, just cast it to the value type. + * To get the failure in the monad, cast it to the failure type. + */ +template class failable { +public: + failable() : hasv(false), c(-1) { + } + + failable(const V& v) : hasv(true), v(v), c(-1) { + } + + failable(const failable& m) : hasv(m.hasv), v(m.v), f(m.f), c(m.c) { + } + + const failable& operator=(const failable& m) { + if (&m == this) + return *this; + hasv = m.hasv; + v = m.v; + f = m.f; + c = m.c; + return *this; + } + + const bool operator!=(const failable& m) const { + return !this->operator==(m); + } + + const bool operator==(const failable& m) const { + if (this == &m) + return true; + if (!hasv) + return !m.hasv && f == m.f && c == m.c; + return m.hasv && v == m.v; + } + +private: + failable(const bool hasv, const F& f, const C& c) : hasv(hasv), f(f), c(c) { + } + + 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 R rcode(const failable& m); + template friend const failable mkfailure(const B& f, const R& c, const bool log); + template friend const failable mkfailure(const B& f, const int c, const bool log); + template friend const failable mkfailure(); + + bool hasv; + V v; + F f; + C c; +}; + +/** + * Write a failable monad to a stream. + */ +template ostream& operator<<(ostream& out, const failable& m) { + if (!hasContent(m)) { + out << reason(m) << " : " << rcode(m); + return out; + } + out << content(m); + return out; +} + +/** + * Returns a failable monad with a success value in it. + */ +template const failable mksuccess(const V& v) { + return failable(v); +} + +template const lambda(const V)> success() { + return mksuccess; +} + +/** + * Demangle a C++ function name. + */ +const string demangleFrame(const char* fun) { + int status; + char* name = abi::__cxa_demangle(fun, 0, 0, &status); + if (name == NULL) + return fun; + const string s = name; + free(name); + return s; +} + +/** + * Format a backtrace frame. + */ +const char* formatFrameFile(const char* file) { + const char* s = strrchr(file, '/'); + return s == NULL? file : s + 1; +} + +const string formatFrame(const char* symbol) { +#ifdef __clang__ + // Mac OS X CLang/LLVM stack frame format + // 0 kernel-test 0x000000010d440179 _ZN7tuscany9mkfailureINS_5valueENS_6stringEiEEKNS_8failableIT_T0_T1_EERKS5_RKS6_b + 265 + char nb[3]; + char file[256]; + char addr[32]; + char fun[256]; + char offset[16]; + if (sscanf(symbol, "%2s %255s %31s %255s %*[+] %15s", nb, file, addr, fun, offset) == 5) { + char buf[1024]; + if (debug_islogging()) + sprintf(buf, "%.255s %.31s %.511s + %.15s", formatFrameFile(file), addr, c_str(demangleFrame(fun)), offset); + else + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } +#else + // Linux GCC stack frame format + // ./kernel-test(_ZN7tuscany9mkfailureINS_5valueENS_6stringEiEEKNS_8failableIT_T0_T1_EERKS5_RKS6_b+0x23d) [0xb7197afd] + char file[256]; + char fun[256]; + char offset[16]; + char addr[32]; + if (sscanf(symbol, "%[^(]%*[(]%[^+]%*[+]%[^)]%*[)] %*[[]%[^]]%*[]]", file, fun, offset, addr) == 4) { + char buf[1024]; + if (debug_islogging()) + sprintf(buf, "%.255s %.31s %.511s + %.15s", formatFrameFile(file), addr, c_str(demangleFrame(fun)), offset); + else + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } + if (sscanf(symbol, "%[^(]%*[(]%*[^)]%*[)] %*[[]%[^]]%*[]]", file, addr) == 2) { + char buf[512]; + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } + if (sscanf(symbol, "%[^(]%*[(]%*[)] %*[[]%[^]]%*[]]", file, addr) == 2) { + char buf[512]; + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } +#endif + return symbol; +} + +/** + * Log backtrace frames. + */ +const bool logFrames(char** symbols, const int frames, const bool log) { + if (frames == 0) + return true; +#ifdef WANT_MAINTAINER_LOG + if (!log) + debug(formatFrame(*symbols), "failable::backtrace"); +#endif + if (log) + cfailure << "failable::backtrace: " << formatFrame(*symbols) << endl; + return logFrames(symbols + 1, frames - 1, log); +} + +/** + * Log a backtrace. + */ +const bool logBacktrace(void** callstack, const int frames, const bool log) { + char** symbols = backtrace_symbols(callstack, frames); + logFrames(symbols, frames, log); + free(symbols); + return true; +} + +/** + * Returns a failable monad with a failure in it. + */ +template const failable mkfailure(const F& f, const C& c, const bool log = true) { +#ifdef WANT_MAINTAINER_LOG + if (!log) { + // Log the failure + debug(f, "failable::mkfailure"); + + // Log the call stack + void* callstack[16]; + const int frames = backtrace(callstack, 16); + logBacktrace(callstack, frames, log); + } +#endif + if (log) { + ostringstream os; + os << f; + if (length(str(os)) != 0) { + // Log the failure + cfailure << "failable::mkfailure: " << f << " : " << c << endl; + + // Print the call stack + void* callstack[16]; + const int frames = backtrace(callstack, 16); + logBacktrace(callstack, frames, log); + } + } + return failable(false, f, c); +} + +template const failable mkfailure(const F& f, const int c = -1, const bool log = true) { + return mkfailure(f, c, log); +} + +template const failable mkfailure(const char* f, const int c = -1, const bool log = true) { + return mkfailure(string(f), c, log); +} + +template const failable mkfailure() { + return failable(false, string(), -1); +} + +template const lambda(const V)> failure() { + return mkfailure; +} + +/** + * Convert a failable of a given type to a failable of another type. + */ +template const failable mkfailure(const failable& f, const bool log = true) { + return mkfailure(reason(f), rcode(f), log); +} + +/** + * Returns true if the monad contains a content. + */ +template const bool hasContent(const failable& m) { + return m.hasv; +} + +/** + * Returns the content of a failable monad. + */ +template const V content(const failable& m) { + return m.v; +} + +/** + * Returns the reason for failure of a failable monad. + */ +template const F reason(const failable& m) { + return m.f; +} + +/** + * Returns the reason code for failure of a failable monad. + */ +template const C rcode(const failable& m) { + return m.c; +} + +/** + * Bind a function to a failable monad. Passes the success value in the monad to the function + * if present, or does nothing if there's no value and a failure instead. + */ +template +const failable operator>>(const failable& m, const lambda(const V)>& f) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +template +const failable operator>>(const failable& m, const failable (* const f)(const V)) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +/** + * State + content pair data type used by the state monad. + */ +template class scp { +public: + scp(const S& s, const V& v) : s(s), v(v) { + } + + operator const S() const { + return s; + } + + operator const V() const { + return v; + } + + const scp& operator=(const scp& p) { + if(this == &p) + return *this; + s = p.s; + v = p.v; + return *this; + } + + const bool operator!=(const scp& p) const { + return !this->operator==(p); + } + + const bool operator==(const scp& p) const { + if (this == &p) + return true; + return s == p.s && v == p.v; + } + +private: + const S s; + const V v; + + template friend const A scpstate(const scp& m); + template friend const B content(const scp& m); +}; + +/** + * Returns the state of a state-content pair. + */ +template const S scpstate(const scp& m) { + return m.s; +} + +/** + * Returns the content of a state-content pair. + */ +template const S content(const scp& m) { + return m.v; +} + +/** + * State monad. Used to represent the combination of a state and a content. + */ +template class state { +public: + state(const lambda(const S)>& f) : f(f) { + } + + const scp operator()(const S& s) const { + return f(s); + } + + const state& operator=(const state& m) { + if(this == &m) + return *this; + f = m.f; + return *this; + } + + const bool operator!=(const state& m) const { + return !this->operator==(m); + } + + const bool operator==(const state& m) const { + if (this == &m) + return true; + return f == m.f; + } + +private: + const lambda(const S)> f; +}; + +/** + * Write a state monad to a stream. + */ +template ostream& operator<<(ostream& out, const state& m) { + const S s = m; + const V v = m; + out << '(' << s << ' ' << v << ')'; + return out; +} + +/** + * Return a state monad carrying a result content. + */ +template struct returnState { + const V v; + returnState(const V& v) : v(v) { + } + const scp operator()(const S& s) const { + return scp(s, v); + } +}; + +template const state result(const V& v) { + return state(returnState(v)); +} + +/** + * Return a state monad with a transformer function. + * A transformer function takes a state and returns an scp pair carrying a content and a + * new (transformed) state. + */ +template const state transformer(const lambda(const S)>& f) { + return state(f); +} + +/** + * Bind a function to a state monad. The function takes a content and returns a state + * monad carrying a return content. + */ +template struct stateBind { + const state st; + const lambda(const A)>f; + + stateBind(const state& st, const lambda(const A)>& f) : st(st), f(f) { + } + + const scp operator()(const S& is) const { + const scp iscp = st(is); + const state m = f((A)iscp); + return m((S)iscp); + } +}; + +template +const state operator>>(const state& st, const lambda(const A)>& f) { + return state(stateBind(st, f)); +} + +template +const state operator>>(const state& st, const state (* const f)(const A)) { + return state(stateBind(st, f)); +} + +} +#endif /* tuscany_monad_hpp */ -- cgit v1.2.3