BufferMetadata: likewise abandon use of function comparison for buffer handlers
The existing implementation created a Buffer-Type based on various traits, including the constructor and destructor functions for the buffer content. However, this necessitates calculating the hash_value of a std::function, which (see #294) is generally not possible to implement. So with this changeset we now store an additional identity hash value right into the TypeHandler, based on the target type placed into the buffer
This commit is contained in:
parent
d57770ca89
commit
94edb5de86
4 changed files with 185 additions and 138 deletions
|
|
@ -178,12 +178,12 @@ namespace std {
|
|||
* @note use with caution. Hash is calculated
|
||||
* relying on undocumented boost internals.
|
||||
*/
|
||||
template<typename SIG>
|
||||
inline lib::HashVal
|
||||
hash_value (function<SIG> const& fun)
|
||||
{
|
||||
return util::rawHashValue (fun);
|
||||
}
|
||||
// template<typename SIG>
|
||||
// inline lib::HashVal
|
||||
// hash_value (function<SIG> const& fun)
|
||||
// {
|
||||
// return util::rawHashValue (fun);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
** "clean up" after usage.
|
||||
**
|
||||
** Within the Lumiera Engine, the BufferProvider default implementation utilises instances
|
||||
** of TypeHandler to \em describe specific buffer types capable of managing an attached object,
|
||||
** of TypeHandler to _describe specific buffer types_ capable of managing an attached object,
|
||||
** or requiring some other kind of special treatment of the memory area used for the buffer.
|
||||
** This BufferDescriptor is embodied into the BufferMetadata::Key and used later on to invoke
|
||||
** the contained ctor / dtor functors, passing a concrete buffer (memory area).
|
||||
|
|
@ -84,6 +84,16 @@ namespace engine {
|
|||
X* embedded = static_cast<X*> (storageBuffer);
|
||||
embedded->~X();
|
||||
}
|
||||
|
||||
template<typename CTOR, typename DTOR>
|
||||
inline HashVal
|
||||
deriveCombinedTypeIdenity()
|
||||
{
|
||||
HashVal hash{0};
|
||||
boost::hash_combine (hash, typeid(CTOR).hash_code());
|
||||
boost::hash_combine (hash, typeid(DTOR).hash_code());
|
||||
return hash;
|
||||
}
|
||||
}//(End)placement-new helpers
|
||||
|
||||
|
||||
|
|
@ -97,8 +107,14 @@ namespace engine {
|
|||
* special treatment of a buffer space. When defined, the buffer
|
||||
* will be prepared on locking and cleanup will be invoked
|
||||
* automatically when releasing.
|
||||
* @warning comparison and hash values rely on internals of the
|
||||
* std::function implementation and might not be 100% accurate
|
||||
* @warning comparison and hash values are based merely on the type
|
||||
* of the Ctor and Dtor functions -- so all type handlers bound
|
||||
* to the same functor type count as equivalent. This might not
|
||||
* be what you'd expect, however, there is no sane way to test
|
||||
* for equivalence of functors anyway. In the typical usage,
|
||||
* a TypeHandler will be created by TypeHandler::create<TY>(),
|
||||
* and thus will be dedicated to a given type to be placed
|
||||
* into the storage buffer.
|
||||
*/
|
||||
struct TypeHandler
|
||||
{
|
||||
|
|
@ -106,11 +122,13 @@ namespace engine {
|
|||
|
||||
DoInBuffer createAttached;
|
||||
DoInBuffer destroyAttached;
|
||||
HashVal identity;
|
||||
|
||||
/** build an invalid NIL TypeHandler */
|
||||
TypeHandler()
|
||||
: createAttached()
|
||||
, destroyAttached()
|
||||
, identity{0}
|
||||
{ }
|
||||
|
||||
/** build a TypeHandler
|
||||
|
|
@ -124,6 +142,7 @@ namespace engine {
|
|||
TypeHandler(CTOR ctor, DTOR dtor)
|
||||
: createAttached (ctor)
|
||||
, destroyAttached (dtor)
|
||||
, identity{deriveCombinedTypeIdenity<CTOR,DTOR>()}
|
||||
{ }
|
||||
|
||||
/** builder function defining a TypeHandler
|
||||
|
|
@ -154,22 +173,14 @@ namespace engine {
|
|||
friend HashVal
|
||||
hash_value (TypeHandler const& handler)
|
||||
{
|
||||
HashVal hash(0);
|
||||
if (handler.isValid())
|
||||
{
|
||||
boost::hash_combine(hash, handler.createAttached);
|
||||
boost::hash_combine(hash, handler.destroyAttached);
|
||||
}
|
||||
return hash;
|
||||
return handler.identity;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator== (TypeHandler const& left, TypeHandler const& right)
|
||||
{
|
||||
return (not left.isValid() and not right.isValid())
|
||||
|| ( util::rawComparison(left.createAttached, right.createAttached)
|
||||
&& util::rawComparison(left.destroyAttached, right.destroyAttached)
|
||||
);
|
||||
|| (left.identity == right.identity);
|
||||
}
|
||||
friend bool
|
||||
operator!= (TypeHandler const& left, TypeHandler const& right)
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
verifyBruteForceComparison();
|
||||
verifyHashThroughBackdoor();
|
||||
// verifyBruteForceComparison();
|
||||
// verifyHashThroughBackdoor();
|
||||
}
|
||||
|
||||
typedef function<void(int)> Fvi;
|
||||
|
|
@ -78,129 +78,129 @@ namespace test {
|
|||
|
||||
|
||||
/** @test workaround for the missing functor comparison operator */
|
||||
void
|
||||
verifyBruteForceComparison()
|
||||
{
|
||||
Fvi f0;
|
||||
Fvi f1 (fun1);
|
||||
Fvi f2 (fun2);
|
||||
|
||||
CHECK (!rawComparison(f0, f1));
|
||||
CHECK (!rawComparison(f1, f2));
|
||||
CHECK (!rawComparison(f0, f2));
|
||||
|
||||
Fvi f22 (f2);
|
||||
CHECK ( rawComparison(f2, f22));
|
||||
|
||||
f1 = f2;
|
||||
CHECK ( rawComparison(f1, f2));
|
||||
|
||||
CHECK (!rawComparison(f0, Fvi())); // note: can't detect they are equivalent
|
||||
CHECK (!rawComparison(f0, Fiv()));
|
||||
|
||||
f1 = bind (fun2, _1);
|
||||
CHECK (!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);
|
||||
|
||||
CHECK (!rawComparison(f1, fm1));
|
||||
|
||||
CHECK (!rawComparison(fm1, fm2));
|
||||
CHECK (!rawComparison(fm1, fm3));
|
||||
CHECK (!rawComparison(fm1, fm4));
|
||||
CHECK (!rawComparison(fm1, fm5));
|
||||
CHECK (!rawComparison(fm1, fm6));
|
||||
CHECK (!rawComparison(fm2, fm3));
|
||||
CHECK (!rawComparison(fm2, fm4));
|
||||
CHECK (!rawComparison(fm2, fm5));
|
||||
CHECK (!rawComparison(fm2, fm6));
|
||||
CHECK (!rawComparison(fm3, fm4));
|
||||
CHECK (!rawComparison(fm3, fm5));
|
||||
CHECK (!rawComparison(fm3, fm6));
|
||||
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
|
||||
}
|
||||
// void
|
||||
// verifyBruteForceComparison()
|
||||
// {
|
||||
// Fvi f0;
|
||||
// Fvi f1 (fun1);
|
||||
// Fvi f2 (fun2);
|
||||
//
|
||||
// CHECK (!rawComparison(f0, f1));
|
||||
// CHECK (!rawComparison(f1, f2));
|
||||
// CHECK (!rawComparison(f0, f2));
|
||||
//
|
||||
// Fvi f22 (f2);
|
||||
// CHECK ( rawComparison(f2, f22));
|
||||
//
|
||||
// f1 = f2;
|
||||
// CHECK ( rawComparison(f1, f2));
|
||||
//
|
||||
// CHECK (!rawComparison(f0, Fvi())); // note: can't detect they are equivalent
|
||||
// CHECK (!rawComparison(f0, Fiv()));
|
||||
//
|
||||
// f1 = bind (fun2, _1);
|
||||
// CHECK (!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);
|
||||
//
|
||||
// CHECK (!rawComparison(f1, fm1));
|
||||
//
|
||||
// CHECK (!rawComparison(fm1, fm2));
|
||||
// CHECK (!rawComparison(fm1, fm3));
|
||||
// CHECK (!rawComparison(fm1, fm4));
|
||||
// CHECK (!rawComparison(fm1, fm5));
|
||||
// CHECK (!rawComparison(fm1, fm6));
|
||||
// CHECK (!rawComparison(fm2, fm3));
|
||||
// CHECK (!rawComparison(fm2, fm4));
|
||||
// CHECK (!rawComparison(fm2, fm5));
|
||||
// CHECK (!rawComparison(fm2, fm6));
|
||||
// CHECK (!rawComparison(fm3, fm4));
|
||||
// CHECK (!rawComparison(fm3, fm5));
|
||||
// CHECK (!rawComparison(fm3, fm6));
|
||||
// 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;
|
||||
h1 = calculateHash (f1);
|
||||
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
|
||||
}
|
||||
// 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;
|
||||
// h1 = calculateHash (f1);
|
||||
// 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
|
||||
// }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46127,6 +46127,42 @@
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1561305344531" ID="ID_1797228597" MODIFIED="1561308173677" TEXT="Funktion hash_value aufgeben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1561305360584" ID="ID_503655811" MODIFIED="1561308153571" TEXT="TypeHandler für BufferMetadata">
|
||||
<node CREATED="1561305394029" ID="ID_1225221352" MODIFIED="1561305409873" TEXT="definiert eine Art Buffer-Typ"/>
|
||||
<node CREATED="1561305410256" ID="ID_1164668948" MODIFIED="1561305416889" TEXT="basiert bisher auf dem konkreten Handler"/>
|
||||
<node CREATED="1561305428408" ID="ID_1356896886" MODIFIED="1561305452650" TEXT="kann man hier auch das Identitägs-Argument anwenden?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
d.h. wir brauchen keine Äquivalenz?
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1561305463577" ID="ID_1519337489" MODIFIED="1561305477381" TEXT="folglich wäre jeder TypeHandler ein Unikat"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1561308051917" ID="ID_914530129" MODIFIED="1561308171779" TEXT="pragmatische Lösung: Type-ID">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1561308061204" ID="ID_1554244425" MODIFIED="1561308168325" TEXT="verwende die typeid(TY) der Funktoren">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1561308078902" ID="ID_430150773" MODIFIED="1561308091311" TEXT="kann in's Auge gehn">
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
<node CREATED="1561308093797" ID="ID_553457078" MODIFIED="1561308135247" TEXT="wenn jemand eine std::function<void(void)> direkt speichert">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1561308115205" ID="ID_1743532708" MODIFIED="1561308132530" TEXT="Regel ist aber TypeHandler::create<TY>()">
|
||||
<icon BUILTIN="back"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1561296009625" ID="ID_617134183" MODIFIED="1561296050381" TEXT="alle Vergleichs-Operatoren auf Command-Funktor-Ebene zurückbauen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue