why the hell doesn't boost provide functor comparison operators..
(yes I know why: it can't be implemented 100% correctly)
This commit is contained in:
parent
e879e0c81b
commit
33757bbac3
4 changed files with 209 additions and 10 deletions
|
|
@ -26,7 +26,7 @@
|
|||
#include "lib/sync.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
#include "lib/functorutil.hpp"
|
||||
#include "lib/functor-util.hpp"
|
||||
#include "common/instancehandle.hpp"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
FUNCTORUTIL.hpp - collection of helpers for dealing with functors and signals
|
||||
FUNCTOR-UTIL.hpp - collection of helpers for dealing with functors and signals
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -21,10 +21,24 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef FUNCTORUTIL_H_
|
||||
#define FUNCTORUTIL_H_
|
||||
/** @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>
|
||||
|
||||
|
||||
|
||||
|
|
@ -83,23 +97,73 @@ namespace util { ////////////TODO: refactor it. But probably not directly into n
|
|||
}
|
||||
|
||||
|
||||
|
||||
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 functors internal data */
|
||||
* 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>
|
||||
bool
|
||||
rawComparison (function<SIG> const& f1,
|
||||
function<SIG> const& f2)
|
||||
{
|
||||
typedef char C8c[sizeof(f1)];
|
||||
typedef HijackedFunction const& Hij;
|
||||
|
||||
return reinterpret_cast<C8c const&> (f1)
|
||||
== reinterpret_cast<C8c const&> (f2);
|
||||
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>
|
||||
bool
|
||||
rawComparison (function<SIG1> const&,
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
#include "lib/bool-checkable.hpp"
|
||||
#include "lib/meta/function-closure.hpp"
|
||||
#include "proc/control/command-signature.hpp"
|
||||
#include "lib/functorutil.hpp"
|
||||
#include "lib/functor-util.hpp"
|
||||
#include "lib/format.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
|
|||
135
tests/lib/functor-util-test.cpp
Normal file
135
tests/lib/functor-util-test.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
FunctorUtil(Test) - verifying function object and signal utilities
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, 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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/functor-util.hpp"
|
||||
|
||||
//#include <boost/lexical_cast.hpp>
|
||||
#include <tr1/functional>
|
||||
#include <iostream>
|
||||
|
||||
//using boost::lexical_cast;
|
||||
//using util::isnil;
|
||||
//using std::string;
|
||||
using std::cout;
|
||||
using std::tr1::function;
|
||||
|
||||
|
||||
namespace util {
|
||||
namespace test {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void fun1 (int i) { cout << "fun1 (" << i << ")\n"; }
|
||||
void fun2 (int i) { cout << "fun2 (" << i << ")\n"; }
|
||||
|
||||
struct Dummy
|
||||
{
|
||||
void gummi (int i) { cout << "gummi (" << i << ")\n"; }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @test verify some aspects of the functor-util's behaviour.
|
||||
* Often, this is just a scrapbook for new ideas....
|
||||
*/
|
||||
class FunctorUtil_test : public Test
|
||||
{
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
verifyBruteForceComparison();
|
||||
}
|
||||
|
||||
|
||||
/** @test workaround for the missing functor comparison operator */
|
||||
void
|
||||
verifyBruteForceComparison()
|
||||
{
|
||||
typedef function<void(int)> Fvi;
|
||||
typedef function<int(void)> Fiv;
|
||||
|
||||
typedef function<void(void)> Fvv;
|
||||
|
||||
Fvi f0;
|
||||
Fvi f1 (fun1);
|
||||
Fvi f2 (fun2);
|
||||
|
||||
ASSERT (!rawComparison(f0, f1));
|
||||
ASSERT (!rawComparison(f1, f2));
|
||||
ASSERT (!rawComparison(f0, f2));
|
||||
|
||||
Fvi f22 (f2);
|
||||
ASSERT ( rawComparison(f2, f22));
|
||||
|
||||
f1 = f2;
|
||||
ASSERT ( rawComparison(f1, f2));
|
||||
|
||||
ASSERT (!rawComparison(f0, Fvi())); // note: can't detect they are equivalent
|
||||
ASSERT (!rawComparison(f0, Fiv()));
|
||||
|
||||
f1 = bind (fun2, _1);
|
||||
ASSERT (!rawComparison(f1, f2));
|
||||
|
||||
Dummy dum1, dum2;
|
||||
Fvi fm1 = bind (&Dummy::gummi, dum1, _1);
|
||||
Fvi fm2 = bind (&Dummy::gummi, dum2, _1);
|
||||
Fvv fm3 = bind (&Dummy::gummi, dum1, 23);
|
||||
Fvv fm4 = bind (&Dummy::gummi, dum1, 24);
|
||||
Fvv fm5 = bind (&Dummy::gummi, dum2, 24);
|
||||
Fvv fm6 = bind (&Dummy::gummi, dum2, 24);
|
||||
|
||||
ASSERT (!rawComparison(f1, fm1));
|
||||
|
||||
ASSERT (!rawComparison(fm1, fm2));
|
||||
ASSERT (!rawComparison(fm1, fm3));
|
||||
ASSERT (!rawComparison(fm1, fm4));
|
||||
ASSERT (!rawComparison(fm1, fm5));
|
||||
ASSERT (!rawComparison(fm1, fm6));
|
||||
ASSERT (!rawComparison(fm2, fm3));
|
||||
ASSERT (!rawComparison(fm2, fm4));
|
||||
ASSERT (!rawComparison(fm2, fm5));
|
||||
ASSERT (!rawComparison(fm2, fm6));
|
||||
ASSERT (!rawComparison(fm3, fm4));
|
||||
ASSERT (!rawComparison(fm3, fm5));
|
||||
ASSERT (!rawComparison(fm3, fm6));
|
||||
ASSERT (!rawComparison(fm4, fm5));
|
||||
ASSERT (!rawComparison(fm4, fm6));
|
||||
ASSERT (!rawComparison(fm5, fm6)); // again: can't detect they are equivalent
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (FunctorUtil_test, "unit common");
|
||||
|
||||
|
||||
|
||||
}} // namespace util::test
|
||||
Loading…
Reference in a new issue