/* WRAPPER.hpp - some smart wrapping and reference managing helper templates Copyright (C) Lumiera.org 2009, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file wrapper.hpp ** Library implementation: smart-pointer variations, wrappers and managing holders. ** This is (intended to become) a loose collection of the various small helper templates ** for wrapping, containing, placing or handling a somewhat \em problematic other object. ** Mostly these are implemented to suit a specific need and then factored out later on. ** - AssignableRefWrapper is not used anymore as of 12/09 ** - ItemWrapper is a similar concept, but more like a smart-ptr. Moreover, ** it can be instantiated with a value type, a pointer or a reference type, ** yielding the same behaviour in all cases (useful for building templates) ** - FunctionResult is the combination of ItemWrapper with a functor object ** to cache the function result value. ** ** @see lib::TransformIter ** */ #ifndef LIB_WRAPPER_H #define LIB_WRAPPER_H #include "lib/error.hpp" #include "lib/bool-checkable.hpp" #include "lib/meta/function.hpp" #include "lib/meta/function-closure.hpp" #include "lib/util.hpp" #include #include #include namespace lib { namespace wrapper { using util::unConst; using util::isSameObject; using lib::meta::FunctionSignature; using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE; using boost::remove_const; using std::function; /** * Extension to std::reference_wrapper: * Allows additionally to re-bind to another reference, * almost like a pointer. Helpful for building templates. * @warning potentially dangerous */ template class AssignableRefWrapper : public std::reference_wrapper { typedef std::reference_wrapper RefWrapper; public: explicit AssignableRefWrapper(TY& ref) : RefWrapper(ref) { } AssignableRefWrapper& operator= (RefWrapper const& o) { RefWrapper::operator= (o); return *this; } AssignableRefWrapper& operator= (TY& newRef) { (*this) = RefWrapper(newRef); return *this; } }; /** * Reference wrapper implemented as constant function, * returning the (fixed) reference on invocation */ template class ReturnRef { T& ref_; public: ReturnRef(T& target) : ref_(target) { } T& operator() () const { return ref_;} }; template ReturnRef refFunction (T& target) { return ReturnRef (target); } /** * Universal value/ref wrapper behaving like a pointer. * A copyable, assignable value object, not managing ownership. * It can be default constructed and \c bool evaluated to detect * an empty holder. The value is retrieved pointer-like, by * explicit dereferentiation. (Contrast this to std::ref, * where the original reference is retrieved by conversion) * * The purpose of this template is to be able to remember * pretty much any kind of value or pointer or reference, * and to subsume this handling within a single template. * An example would be to remember the value yielded * by a function, without any further assumptions * regarding this function. */ template class ItemWrapper : public BoolCheckable > { typedef typename remove_const::type TY_unconst; mutable char content_[sizeof(TY)]; bool created_; void build (TY const& ref) { new(&content_) TY(ref); created_ = true; } void discard () { if (created_) access().~TY(); created_ = false; } TY& access () const { return reinterpret_cast (content_); } TY_unconst& access_unconst() const ///< used to assign new buffer contents { return const_cast (access()); } public: ItemWrapper() : created_(false) { } explicit ItemWrapper(TY const& o) { build (o); } ~ItemWrapper() { discard(); } /* == copy and assignment == */ ItemWrapper (ItemWrapper const& ref) : created_(false) { if (ref.isValid()) build (*ref); } ItemWrapper& operator= (ItemWrapper const& ref) { if (!ref.isValid()) discard(); else this->operator= (*ref); return *this; } template ItemWrapper& operator= (X const& something) ///< accept anything assignable to TY { if (!isSameObject (something, access() )) { if (created_) access_unconst() = something; else build (something); } return *this; } /* == value access == */ TY& operator* () const { if (!created_) throw lumiera::error::State ("accessing uninitialised value/ref wrapper" , LUMIERA_ERROR_BOTTOM_VALUE); return access(); } bool isValid () const { return created_; } void reset () { discard(); } }; /** * Specialisation of the ItemWrapper to deal with references, * as if they were pointer values. Allows the reference value * to be default constructed to \c NULL and to be re-assigned. */ template class ItemWrapper : public BoolCheckable > { TY * content_; public: ItemWrapper() : content_() { } explicit ItemWrapper(TY& o) : content_( &o ) { } /* using default copy and assignment */ /** allowing to re-bind the reference */ ItemWrapper& operator= (TY& otherRef) { content_ = &otherRef; return *this; } /* == value access == */ TY& operator* () const { if (!content_) throw lumiera::error::State ("accessing uninitialised reference wrapper" , LUMIERA_ERROR_BOTTOM_VALUE); return *content_; } bool isValid () const { return bool(content_); } void reset () { content_ = 0; } }; /** allow equality comparison if the wrapped types are comparable */ template inline bool operator== (ItemWrapper const& w1, ItemWrapper const& w2) { return (!w1 && !w2) || ( w1 && w2 && (*w1)==(*w2)); } template inline bool operator!= (ItemWrapper const& w1, ItemWrapper const& w2) { return not (w1 == w2); } /** * Extension of ItemWrapper: a function remembering * the result of the last invocation. Initially, the "value" * is bottom (undefined, NIL), until the function is invoked * for the first time. After that, the result of the last * invocation can be accessed by \c operator*() * * @note non-copyable. (removing this limitation would * require a much more expensive implementation, * by implementing operator() ourselves) */ template class FunctionResult : public function , boost::noncopyable { typedef typename FunctionSignature >::Ret Res; typedef ItemWrapper ResWrapper; ResWrapper lastResult_; Res captureResult (Res res) { lastResult_ = res; return res; } public: /** default ctor yields an object * locked to \em invalid state */ FunctionResult () { } /** Create result-remembering functor * by binding the given function. Explanation: * - *this is a \em function * - initially it is defined as invalid * - then we build the function composition of * the target function, and a function storing * the result value into the ResWrapper member * - define ourselves by assigning the resulting * composite function */ template FunctionResult (FUN targetFunction) { using std::bind; using std::placeholders::_1; using lib::meta::func::chained; // note: binding "this" mandates noncopyable function doCaptureResult = bind (&FunctionResult::captureResult, this, _1 ); function chainedWithResCapture = chained (targetFunction, doCaptureResult); function::operator= (chainedWithResCapture); // define the function (baseclass) } Res& operator*() const { return *lastResult_; } bool isValid () const { return lastResult_.isValid(); } operator bool() const { return isValid(); } // can't use lib::BoolCheckable, because tr1::function implements safe-bool too }; }} // namespace lib::wrap #endif