diff --git a/src/lib/functor-util.hpp b/src/lib/functor-util.hpp index d47b86a9c..b8f4780c3 100644 --- a/src/lib/functor-util.hpp +++ b/src/lib/functor-util.hpp @@ -38,11 +38,14 @@ #define FUNCTOR_UTIL_H_ #include -#include -namespace util { ////////////TODO: refactor it. But probably not directly into namespace lib. Needs some more consideration though +namespace lib { + typedef size_t HashVal; +} + +namespace util { ////////////TODO: refactor namespace. But probably not directly into namespace lib. Needs some more consideration though using std::tr1::function; using std::tr1::bind; @@ -101,7 +104,7 @@ 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 + * This Class is used to bypass 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 @@ -186,4 +189,16 @@ namespace util { ////////////TODO: refactor it. But probably not directly into n } // namespace util +namespace std { +namespace tr1 { + + template + inline size_t + hash_value (function const& fun) + { + UNIMPLEMENTED ("hijack the function object and derive some hash value"); + } + +}} + #endif /*UTIL_HPP_*/ diff --git a/tests/components/proc/control/command-equality-test.cpp b/tests/components/proc/control/command-equality-test.cpp index 715a3b83f..c580f1eda 100644 --- a/tests/components/proc/control/command-equality-test.cpp +++ b/tests/components/proc/control/command-equality-test.cpp @@ -98,10 +98,11 @@ namespace test { * To conduct this test, we set up two sets of functions, and then build both complete * command objects and command implementation facilities based on them. * - * @note The hidden problem with those comparisons is the equivalence of function objects, - * which is required by TR1, but refused to implement by lib boost. We use a low level - * hack, based on internals of the boost function implementation, but this solution - * fails to detect equivalent functions under some circumstances (e.g. when there is + * @note The hidden problem with those comparisons is the equivalence of function objects. + * While required by TR1, unfortunately lib boost refuses to implement functor equality. + * Which forces us to resort to a low level hack, based on internals of the boost function + * implementation. This workaround reliably pinpoints differing functions, but sometimes + * fails to detect equivalent functions under specific circumstances (e.g. when there is * binding involved, and / or the binders have been cloned). Bottom line: \c == is * reliable, \c != might be wrong. * @@ -112,6 +113,7 @@ namespace test { * @see control::MementoTie * @see control::CommandImpl * @see command-basic-test.hpp + * @see functor-util.hpp functor equality workaround */ class CommandEquality_test : public Test { diff --git a/tests/lib/functor-util-test.cpp b/tests/lib/functor-util-test.cpp index 0692158fe..c031ddc60 100644 --- a/tests/lib/functor-util-test.cpp +++ b/tests/lib/functor-util-test.cpp @@ -27,12 +27,14 @@ #include "lib/functor-util.hpp" #include +#include #include //using util::isnil; -//using std::string; +using lib::HashVal; using std::cout; using std::tr1::function; +using boost::hash; // note: only boost::hash allows for easy defining of custom hash functions namespace util { @@ -56,7 +58,7 @@ namespace test { /********************************************************************* * @test verify some aspects of the functor-util's behaviour. - * Often, this is just a scrapbook for new ideas.... + * At times, this is just a scrapbook for new ideas.... */ class FunctorUtil_test : public Test { @@ -64,18 +66,19 @@ namespace test { run (Arg) { verifyBruteForceComparison(); + verifyHashThroughBackdoor(); } + typedef function Fvi; + typedef function Fiv; + + typedef function Fvv; + /** @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); @@ -118,10 +121,83 @@ namespace test { CHECK (!rawComparison(fm3, fm4)); CHECK (!rawComparison(fm3, fm5)); CHECK (!rawComparison(fm3, fm6)); - CHECK (!rawComparison(fm4, fm5)); + CHECK (!rawComparison(fm4, fm5)); // note: same argument but different functor instance CHECK (!rawComparison(fm4, fm6)); CHECK (!rawComparison(fm5, fm6)); // again: can't detect they are equivalent } + + + /** @test workaround for missing standard hash + * calculation for functor objects. + * Workaround relying on boost + * implementation internals */ + void + verifyHashThroughBackdoor() + { + Fvi f0; + Fvi f1 (fun1); + Fvi f2 (fun2); + Fvi f22 (f2); + + hash calculateHash; + CHECK (calculateHash (f0)); + CHECK (calculateHash (f1)); + CHECK (calculateHash (f2)); + CHECK (calculateHash (f22)); + + HashVal h0 = calculateHash (f0); + HashVal h1 = calculateHash (f1); + HashVal h2 = calculateHash (f2); + HashVal h22 = calculateHash (f22); + + CHECK (h0 != h1); + CHECK (h0 != h2); + CHECK (h1 != h2); + + CHECK (h2 == h22); + + f1 = f2; + CHECK (h1 == h2); + CHECK (h1 != h0); + + CHECK (h0 != calculateHash (Fvi())); // note: equivalence not detected + + // checking functors based on member function(s) + 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); + + HashVal hm1 = calculateHash (fm1); + HashVal hm2 = calculateHash (fm2); + + hash calculateHashVV; + HashVal hm3 = calculateHashVV (fm3); + HashVal hm4 = calculateHashVV (fm4); + HashVal hm5 = calculateHashVV (fm5); + HashVal hm6 = calculateHashVV (fm6); + + CHECK (h1 != hm1); + + CHECK (hm1 != hm2); + CHECK (hm1 != hm3); + CHECK (hm1 != hm4); + CHECK (hm1 != hm5); + CHECK (hm1 != hm6); + CHECK (hm2 != hm3); + CHECK (hm2 != hm4); + CHECK (hm2 != hm5); + CHECK (hm2 != hm6); + CHECK (hm3 != hm4); + CHECK (hm3 != hm5); + CHECK (hm3 != hm6); + CHECK (hm4 != hm5); + CHECK (hm4 != hm6); + CHECK (hm5 != hm6); // again: unable to detect the equivalence + } };