draft a workaround for hashing functor objects

This commit is contained in:
Fischlurch 2011-10-14 03:54:22 +02:00
parent 3256b7fe11
commit 6baadbaef0
3 changed files with 108 additions and 15 deletions

View file

@ -38,11 +38,14 @@
#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
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<typename SIG>
inline size_t
hash_value (function<SIG> const& fun)
{
UNIMPLEMENTED ("hijack the function object and derive some hash value");
}
}}
#endif /*UTIL_HPP_*/

View file

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

View file

@ -27,12 +27,14 @@
#include "lib/functor-util.hpp"
#include <tr1/functional>
#include <boost/functional/hash.hpp>
#include <iostream>
//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<void(int)> Fvi;
typedef function<int(void)> Fiv;
typedef function<void(void)> Fvv;
/** @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);
@ -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<Fvi> 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<Fvv> 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
}
};