From 33757bbac33daeccd5ea0f0630478ce0723e44f1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 20 Jul 2009 04:21:24 +0200 Subject: [PATCH] why the hell doesn't boost provide functor comparison operators.. (yes I know why: it can't be implemented 100% correctly) --- src/common/guifacade.cpp | 2 +- src/lib/{functorutil.hpp => functor-util.hpp} | 80 +++++++++-- src/proc/control/memento-tie.hpp | 2 +- tests/lib/functor-util-test.cpp | 135 ++++++++++++++++++ 4 files changed, 209 insertions(+), 10 deletions(-) rename src/lib/{functorutil.hpp => functor-util.hpp} (52%) create mode 100644 tests/lib/functor-util-test.cpp diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 8d6f3fb98..670aa00b5 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -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 diff --git a/src/lib/functorutil.hpp b/src/lib/functor-util.hpp similarity index 52% rename from src/lib/functorutil.hpp rename to src/lib/functor-util.hpp index d8eb07132..473a17dc7 100644 --- a/src/lib/functorutil.hpp +++ b/src/lib/functor-util.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 @@ -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 +#include @@ -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 bool rawComparison (function const& f1, function const& f2) { - typedef char C8c[sizeof(f1)]; + typedef HijackedFunction const& Hij; - return reinterpret_cast (f1) - == reinterpret_cast (f2); + return reinterpret_cast (f1) + == reinterpret_cast (f2); } - + /** catch-all for the comparison: functors with + * different base type are always "different" */ template bool rawComparison (function const&, diff --git a/src/proc/control/memento-tie.hpp b/src/proc/control/memento-tie.hpp index 7ccac9322..3ad17c0fc 100644 --- a/src/proc/control/memento-tie.hpp +++ b/src/proc/control/memento-tie.hpp @@ -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" diff --git a/tests/lib/functor-util-test.cpp b/tests/lib/functor-util-test.cpp new file mode 100644 index 000000000..8072eecc3 --- /dev/null +++ b/tests/lib/functor-util-test.cpp @@ -0,0 +1,135 @@ +/* + FunctorUtil(Test) - verifying function object and signal utilities + + 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. + +* *****************************************************/ + + + +#include "lib/test/run.hpp" +//#include "lib/util.hpp" +#include "lib/functor-util.hpp" + +//#include +#include +#include + +//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 Fvi; + typedef function Fiv; + + typedef function 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