draft a workaround for hashing functor objects
This commit is contained in:
parent
3256b7fe11
commit
6baadbaef0
3 changed files with 108 additions and 15 deletions
|
|
@ -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_*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue