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:
Fischlurch 2009-07-20 04:21:24 +02:00
parent e879e0c81b
commit 33757bbac3
4 changed files with 209 additions and 10 deletions

View file

@ -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>

View file

@ -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&,

View file

@ -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"

View 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