LUMIERA.clone/src/lib/functor-util.hpp

189 lines
5.5 KiB
C++

/*
FUNCTOR-UTIL.hpp - collection of helpers for dealing with functors and signals
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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 functor-util.hpp
** Collection of small helpers and utilities related to function objects.
**
** @todo combine with meta/function-closure.hpp and reorganise
**
** @see GuiSubsysDescriptor#start (guifacade.cpp)
** @see MementoTie
** @see functor-util-test.cpp
**
*/
#ifndef FUNCTOR_UTIL_H_
#define FUNCTOR_UTIL_H_
#include <tr1/functional>
#include <cstring>
namespace util { ////////////TODO: refactor it. But probably not directly into namespace lib. Needs some more consideration though
using std::tr1::function;
using std::tr1::bind;
using std::tr1::placeholders::_1;
/** "Combiner" which calls two functions one after another
* returning the result of the second invocation. */
template<typename SIG>
class CombineSequenced;
template<typename ARG, typename RET>
struct CombineSequenced<RET(ARG)>
{
typedef function<RET(ARG)> Func;
static RET
dispatch (Func first, Func second, ARG arg)
{
first (arg);
return second (arg);
}
};
template< typename SIG
, class COM = CombineSequenced<SIG>
>
class Dispatch
: public function<SIG>
{
typedef typename COM::Func Func;
public:
Dispatch (Func const& f1,
Func const& f2)
: Func (bind (&COM::dispatch, f1, f2, _1))
{ }
};
/** convenience shortcut to call two functors in sequence.
* @return a Dispatch functor object which incorporates the
* functors as copy and on invocation calls the first
* function and then returns the result of the second */
template<typename SIG>
Dispatch<SIG>
dispatchSequenced (function<SIG> const& f1,
function<SIG> const& f2)
{
return Dispatch<SIG> (f1, f2);
}
namespace { // hiding some nasty details...
/**
* This Class is used to surpass the access protection
* and break into the tr1::function implementation.
* Thus we can implement a raw comparison function,
* as a replacement for the missing functor comparison
* facility. (TR1 requires an operator==, but boost
* seemingly doesn't provide it, because it can't
* be done correctly/properly in all cases. See
* the section "FAQ" in the documentation of
* the boost/function library)
*
* The layout of this class is chosen to mimic that
* of the boost function implementation, without all
* the generic type decoration. For the comparison
* we use a conservative approach, by requiring
* the concrete invoker, the storage manager and
* the actual function and argument data pointers
* to be the same.
*/
class HijackedFunction
: std::tr1::_Function_base
{
typedef void (*DummyInvoker) (void);
DummyInvoker invoker_;
public:
friend bool
operator== (HijackedFunction const& f1,
HijackedFunction const& f2)
{
return (f1.invoker_ == f2.invoker_)
&& (f1._M_manager == f2._M_manager)
&& (f1._M_functor._M_unused._M_const_object ==
f2._M_functor._M_unused._M_const_object );
} // note: we don't cover any member pointer offset
};
}
/** temporary workaround: tr1/functional should define
* public comparison operators for functor objects, but
* in the implementation provided by boost 1.34 it doesn't.
* To get at least \em some comparison capability, we do a
* brute force comparison of the functor's internal data.
* @note use with caution. This implementation relies on
* internal details of boost/function; but it is
* rather conservative and might deem functors
* "different" erroneously, due to garbage in
* the internal functor data's storage */
template<typename SIG>
inline bool
rawComparison (function<SIG> const& f1,
function<SIG> const& f2)
{
typedef HijackedFunction const& Hij;
return reinterpret_cast<Hij> (f1)
== reinterpret_cast<Hij> (f2);
}
/** catch-all for the comparison: functors with
* different base type are always "different" */
template<typename SIG1, typename SIG2>
inline bool
rawComparison (function<SIG1> const&,
function<SIG2> const&)
{
return false;
}
/** variant with unchecked access */
inline bool
rawComparison (void* f1, void* f2)
{
typedef HijackedFunction * HijP;
return (!f1 && !f2)
|| *reinterpret_cast<HijP> (f1)
== *reinterpret_cast<HijP> (f2);
}
} // namespace util
#endif /*UTIL_HPP_*/