Library: rework detection of ''same object''

We use the memory address to detect reference to ''the same language object.''
While primarily a testing tool, this predicate is also used in the
core application at places, especially to prevent self-assignment
and to handle custom allocations.

It turns out that actually we need two flavours for convenient usage
 - `isSameObject` uses strict comparison of address and accepts only references
 - `isSameAdr` can also accept pointers and even void*, but will dereference pointers
This leads to some further improvements of helper utilities related to memory addresses...
This commit is contained in:
Fischlurch 2024-11-14 22:10:43 +01:00
parent 766da84a62
commit 7ed8486774
26 changed files with 731 additions and 359 deletions

View file

@ -1,58 +1,18 @@
/* try.cpp - for trying out some language features....
/* try.cpp - to try out and experiment with new features....
* scons will create the binary bin/try
*
*/
// 8/07 - how to control NOBUG??
// execute with NOBUG_LOG='ttt:TRACE' bin/try
// 1/08 - working out a static initialisation problem for Visitor (Tag creation)
// 1/08 - check 64bit longs
// 4/08 - comparison operators on shared_ptr<Asset>
// 4/08 - conversions on the value_type used for boost::any
// 5/08 - how to guard a downcasting access, so it is compiled in only if the involved types are convertible
// 7/08 - combining partial specialisation and subclasses
// 10/8 - abusing the STL containers to hold noncopyable values
// 6/09 - investigating how to build a mixin template providing an operator bool()
// 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type"
// 1/10 - can we determine at compile time the presence of a certain function (for duck-typing)?
// 4/10 - pretty printing STL containers with python enabled GDB?
// 1/11 - exploring numeric limits
// 1/11 - integer floor and wrap operation(s)
// 1/11 - how to fetch the path of the own executable -- at least under Linux?
// 10/11 - simple demo using a pointer and a struct
// 11/11 - using the boost random number generator(s)
// 12/11 - how to detect if string conversion is possible?
// 1/12 - is partial application of member functions possible?
// 5/14 - c++11 transition: detect empty function object
// 7/14 - c++11 transition: std hash function vs. boost hash
// 9/14 - variadic templates and perfect forwarding
// 11/14 - pointer to member functions and name mangling
// 8/15 - Segfault when loading into GDB (on Debian/Jessie 64bit
// 8/15 - generalising the Variant::Visitor
// 1/16 - generic to-string conversion for ostream
// 1/16 - build tuple from runtime-typed variant container
// 3/17 - generic function signature traits, including support for Lambdas
// 9/17 - manipulate variadic templates to treat varargs in several chunks
// 11/17 - metaprogramming to detect the presence of extension points
// 11/17 - detect generic lambda
// 12/17 - investigate SFINAE failure. Reason was indirect use while in template instantiation
// 03/18 - Dependency Injection / Singleton initialisation / double checked locking
// 04/18 - investigate construction of static template members
// 08/18 - Segfault when compiling some regular expressions for EventLog search
// 10/18 - investigate insidious reinterpret cast
// 12/18 - investigate the trinomial random number algorithm from the C standard lib
// 04/19 - forwarding tuple element(s) to function invocation
// 06/19 - use a statefull counting filter in a treeExplorer pipeline
// 03/20 - investigate type deduction bug with PtrDerefIter
// 01/21 - look for ways to detect the presence of an (possibly inherited) getID() function
// 08/22 - techniques to supply additional feature selectors to a constructor call
// 10/23 - search for ways to detect signatures of member functions and functors uniformly
// 11/23 - prototype for a builder-DSL to configure a functor to draw and map random values
// 11/24 - how to define a bare object location comparison predicate
// 11/23 - prototype for grouping from iterator
/** @file try.cpp
* Investigate how best to integrate a grouping device into the iterator pipeline framework.
* Attempt to generalise the util::isSameObject, to support a mix of pointers and references.
* This is a long standing requirement, yet I made several failed attempts in the past,
* due to difficulties detecting a pointer after perfect-forwarding the argument. However,
* it is not even necessary to perfect-forward, if all we want is to extract the raw address.
*
* To my defence, I should add that I never took the time to conduct a proper experiment
* in a stand-alone setup; investigating directly in "lib/util.hpp" is a waste of time.
*/
typedef unsigned int uint;
@ -61,186 +21,113 @@ typedef unsigned int uint;
#include "lib/format-cout.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/test/diagnostic-output.hpp"
#include "lib/format-util.hpp"
#include "lib/util.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/test/test-coll.hpp"
#include <utility>
#include <array>
#include <string>
using std::forward;
using lib::rani;
using std::move;
using std::string;
namespace lib {
namespace iter_explorer {
template<class SRC, class RES, uint grp>
class Groupy
: public SRC
{
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
protected:
using Group = std::array<RES, grp>;
using Iter = typename Group::iterator;
union Buffer
{
char storage[sizeof(Group)];
Group group;
Iter begin() { return group.begin();}
Iter end() { return group.end(); }
};
Buffer buff_;
uint pos_{0};
public:
using value_type = Group;
using reference = Group&;
using pointer = Group*;
Groupy() =default;
// inherited default copy operations
Groupy (SRC&& dataSrc)
: SRC{move (dataSrc)}
{
pullGroup(); // initially pull to establish the invariant
}
/**
* Iterate over the Elements in the current group.
* @return a Lumiera Forward Iterator with value type RES
*/
auto
getGroupedElms()
{
ENSURE (buff_.begin()+pos_ <= buff_.end());
// Array iterators are actually pointers
return RangeIter{buff_.begin(), buff_.begin()+pos_};
}
/**
* Retrieve the tail elements produced by the source,
* which did not suffice to fill a full group.
* @remark getRest() is NIL during regular iteration, but
* possibly yields elements when checkPoint() = false;
*/
auto
getRestElms()
{
return checkPoint()? RangeIter<Iter>()
: getGroupedElms();
}
/** refresh state when other layers manipulate the source sequence.
* @note possibly pulls to re-establish the invariant */
void
expandChildren()
{
SRC::expandChildren();
pullGroup();
}
public: /* === Iteration control API for IterableDecorator === */
bool
checkPoint() const
{
return pos_ == grp;
}
reference
yield() const
{
return unConst(buff_).group;
}
void
iterNext()
{
pullGroup();
}
protected:
SRC&
srcIter() const
{
return unConst(*this);
}
/** @note establishes the invariant:
* source has been consumed to fill a group */
void
pullGroup ()
{
for (pos_=0
; pos_<grp and srcIter()
; ++pos_,++srcIter()
)
buff_.group[pos_] = *srcIter();
}
};
template<uint grp, class IT>
auto
groupy (IT&& src)
{
using Value = typename meta::ValueTypeBinding<IT>::value_type;
using ResCore = Groupy<IT, Value, grp>;
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
return IterExplorer<ResIter> (ResCore {move(src)});
}
}//iter_explorer
}//lib
using lib::test::getTestSeq_int;
using lib::test::VecI;
/** Diagnostic helper: join all the elements from a _copy_ of the iterator */
template<class II>
inline string
materialise (II&& ii)
{
return util::join (std::forward<II> (ii), "-");
}
template<uint num, uint grp>
void
test()
template<class X>
inline const void*
getAd (X& x)
{
VecI vec1 = getTestSeq_int<VecI> (num);
cout <<"---"<<grp<<" of "<<num<<"---\n"
<< materialise(vec1) <<endl;
auto it = lib::explore(vec1);
auto groupie = lib::explore(lib::iter_explorer::groupy<grp> (move(it)))
.transform([](auto it){ return "["+util::join(*it)+"]"; });
for ( ;groupie; ++groupie)
cout << *groupie<<"-";
CHECK (not groupie);
CHECK (groupie.getGroupedElms());
CHECK (groupie.getRestElms());
for (auto r = groupie.getRestElms() ;r; ++r)
cout << *r<<"+";
cout << endl;
return static_cast<const void*> (std::addressof(x));
}
template<class X>
inline const void*
getAd (X* x)
{
return static_cast<const void*> (x);
}
template<class A, class B>
inline bool
isSameOb (A const& a, B const& b)
{
return getAd(a)
== getAd(b);
}
struct Boo
{
string moo;
short goo;
Boo(short uh)
: moo{util::toString(uh-1)}
, goo(uh+1)
{ }
operator string() const
{
return moo+util::toString(goo);
}
};
struct SuBoo : Boo
{
long poo = rani(goo);
using Boo::Boo;
};
inline Boo*
asBoo (void* mem)
{// type tag to mark memory address as Buffer
return static_cast<Boo*> (mem);
}
int
main (int, char**)
{
test<10,3>();
test<13,5>();
test<55,23>();
test<23,55>();
Boo boo(23);
Boo booo(23);
Boo* boop = &boo;
Boo const* const beep = boop;
cout << boo << endl;
SHOW_EXPR(util::showAdr(getAd(boo )))
SHOW_EXPR(util::showAdr(getAd(&boo)))
SHOW_EXPR(util::showAdr(getAd(boop)))
SHOW_EXPR(util::showAdr(getAd(beep)))
SHOW_EXPR(isSameOb(boop, beep))
SHOW_EXPR(isSameOb(&boop, &beep))
SHOW_EXPR(isSameOb(boo, beep))
SHOW_EXPR(isSameOb(*beep, booo))
SHOW_EXPR(isSameOb(boo, boo.moo))
SHOW_EXPR(isSameOb(boo, &boo.moo))
SHOW_EXPR(isSameOb(boo.moo, booo))
SHOW_EXPR(isSameOb(booo, asBoo(&booo.moo)))
SHOW_EXPR(isSameOb(booo, asBoo(&booo.goo)))
const void* voo = boop;
SHOW_EXPR(isSameOb(voo, boo))
SHOW_EXPR(isSameOb(voo, boop))
SHOW_EXPR(isSameOb(voo, asBoo(&boo.moo)))
SHOW_EXPR(isSameOb(voo, asBoo(&booo.moo)))
SHOW_EXPR(isSameOb(voo, asBoo(&boo.goo)))
Boo&& roo = move(boo);
SHOW_EXPR(isSameOb(roo, boo))
SHOW_EXPR(isSameOb(voo, roo))
SHOW_EXPR(isSameOb(voo, Boo{roo}))
SuBoo* suBoo = static_cast<SuBoo*>(&boo);
SHOW_EXPR(isSameOb(boo, suBoo))
SHOW_EXPR(isSameOb(boo, suBoo->moo))
SHOW_EXPR(isSameOb(voo, suBoo->moo))
SHOW_EXPR(isSameOb(voo, suBoo->poo))
SuBoo sudo{*suBoo};
SHOW_EXPR(isSameOb(sudo, suBoo))
suBoo = &sudo;
SHOW_EXPR(isSameOb(sudo.poo, suBoo->poo))
cout << "\n.gulp.\n";
return 0;

View file

@ -271,10 +271,10 @@ namespace advice {
Provision&
operator= (Provision const& o)
{
if (!isSameObject(*this, o))
if (not isSameObject (*this, o))
{
AdviceLink::operator= (o);
setSolution ( NULL );
setSolution (nullptr);
}
return *this;
}

View file

@ -70,8 +70,6 @@
namespace lib {
using util::isSameObject;
/**
* Registry for tracking object instances.
* Custom implementation of the RefArray interface,

View file

@ -93,7 +93,7 @@ namespace std {
operator<< (basic_ostream<_CharT, _Traits>& os, X const* ptr)
{
if (ptr)
return util::showAddr(os, ptr) << "" << util::StringConv<X>::invoke (*ptr);
return util::showAdr(os, ptr) << "" << util::StringConv<X>::invoke (*ptr);
else
return os << "⟂ «" << lib::meta::typeStr<X>() << "»";
}

View file

@ -384,7 +384,7 @@ namespace util {
/** @note show only the trailing X bytes of any address */
ostream&
showAddr (ostream& stream, void const* addr)
showAdr (ostream& stream, void const* addr)
{
IosSavepoint save{stream};
size_t suffix_modulus = size_t(1) << DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 8;
@ -399,10 +399,10 @@ namespace util {
string
showAddr (void const* addr) noexcept
showAdr (void const* addr) noexcept
try {
ostringstream buffer;
showAddr (buffer, addr);
showAdr (buffer, addr);
return buffer.str();
}
catch(...)

View file

@ -83,16 +83,16 @@ namespace meta {
namespace util {
std::string showDouble (double) noexcept;
std::string showFloat (float) noexcept;
std::string showSize (size_t) noexcept;
std::string showAddr (void const* addr) noexcept;
std::string showDouble (double) noexcept;
std::string showFloat (float) noexcept;
std::string showSize (size_t) noexcept;
std::string showAdr (void const* addr) noexcept;
/** preconfigured format for pretty-printing of addresses */
std::ostream& showAddr (std::ostream&, void const* addr);
std::ostream& showAdr (std::ostream&, void const* addr);
/** renders the size_t in hex, optionally only trailing bytes */
std::string showHash (size_t hash, uint showBytes=8) noexcept;
std::string showHash (size_t hash, uint showBytes=8) noexcept;
inline std::string
showHashLSB (size_t hash) noexcept

View file

@ -466,14 +466,14 @@ namespace util {
/** pretty-print an address as hex-suffix */
std::string showAddr (void const* addr) noexcept;
std::string showAdr (void const* addr) noexcept;
template<typename X>
inline lib::meta::disable_if<std::is_pointer<X>,
std::string >
showAddr (X& elm) noexcept
showAdr (X& elm) noexcept
{
return showAddr(&elm);
return showAdr(&elm);
}
@ -482,7 +482,7 @@ namespace util {
inline std::string
showPtr (X* ptr =nullptr)
{
return ptr? showAddr(ptr) + "" + StringConv<X>::invoke(*ptr)
return ptr? showAdr(ptr) + "" + StringConv<X>::invoke(*ptr)
: BOTTOM_INDICATOR + " «" + typeStr(ptr) + "»";
}
@ -492,7 +492,7 @@ namespace util {
{
using TargetType = typename SP::element_type;
return smPtr? label+"("+showAddr(smPtr.get()) + ") ↗" + StringConv<TargetType>::invoke(*smPtr)
return smPtr? label+"("+showAdr(smPtr.get()) + ") ↗" + StringConv<TargetType>::invoke(*smPtr)
: BOTTOM_INDICATOR + " «" + typeStr(smPtr) + "»";
}

View file

@ -86,9 +86,8 @@
#include <boost/lexical_cast.hpp>
#include <cstddef>
#include <utility>
#include <type_traits>
#include <utility>
namespace lib {
@ -98,6 +97,7 @@ namespace lib {
using LERR_(WRONG_TYPE);
using util::isSameObject;
using util::isSameAdr;
using util::unConst;
@ -430,7 +430,7 @@ namespace lib {
operator= (SUB const& newContent)
{
if (empty()
or not isSameObject (*buff().getBase(), newContent)
or not isSameAdr (buff().getBase(), &newContent) // caution: BaseP may be void* and SUB might be a pointer
)
{
killBuffer();

View file

@ -295,7 +295,7 @@ namespace test{
return " :---#"
+ util::toString (1 + sizeof...(xs))
+ " -- Type: " + showType<XX&&>()
+ " \tAdr" + util::showAddr (x)
+ " \tAdr" + util::showAdr (x)
+ "\n"
+ showVariadicTypes (std::forward<XS>(xs)...);
}

View file

@ -54,7 +54,7 @@ using std::make_shared;
using std::make_pair;
using util::contains;
using util::joinDash;
using util::showAddr;
using util::showAdr;
namespace lib {
@ -221,7 +221,7 @@ namespace test{
Location loc = newAlloc.buff.front();
ASSERT (not contains (allocs_, loc));
newAlloc.entryID = ++entryNr_;
logAlloc (poolID_, "allocate", bytes, newAlloc.entryID, showAddr(loc));
logAlloc (poolID_, "allocate", bytes, newAlloc.entryID, showAdr(loc));
checksum_ += newAlloc.entryID * bytes;
return allocs_.emplace (loc, move(newAlloc))
.first->second;
@ -236,14 +236,14 @@ namespace test{
ASSERT (entry.buff);
ASSERT (entry.buff.front() == loc);
if (entry.buff.size() != bytes) // *deliberately* tolerating wrong data, but log incident to support diagnostics
logAlarm ("SizeMismatch", bytes, "", entry.buff.size(), entry.entryID, showAddr(loc));
logAlarm ("SizeMismatch", bytes, "", entry.buff.size(), entry.entryID, showAdr(loc));
logAlloc (poolID_, "deallocate", bytes, entry.entryID, bytes, showAddr(loc));
logAlloc (poolID_, "deallocate", bytes, entry.entryID, bytes, showAdr(loc));
checksum_ -= entry.entryID * bytes; // Note: using the given size (if wrong ⟿ checksum mismatch)
allocs_.erase(loc);
}
else // deliberately no exception here (for better diagnostics)
logAlarm ("FreeUnknown", bytes, showAddr(loc));
logAlarm ("FreeUnknown", bytes, showAdr(loc));
}

View file

@ -335,7 +335,7 @@ namespace time {
SmpteTC&
SmpteTC::operator= (SmpteTC const& o)
{
if (!isSameObject (*this, o))
if (not isSameObject (*this, o))
{
TCode::operator= (o);
effectiveFramerate_ = o.effectiveFramerate_;

View file

@ -25,12 +25,11 @@
** Tiny helper functions and shortcuts to be used _everywhere_
** Consider this header to be effectively included in almost every translation unit.
** @remark The motivation of using these helpers is conciseness and uniformity of expression.
** There are several extensions and not-so-frequently used supplements packaged into
** separate headers.
** Further extensions and not-so-frequently used supplements are packaged into separate headers.
** @warning be sure to understand the ramifications of including _anything_ here...
** @see util-coll.hpp
** @see util-foreach.hpp
** @see util-quant.hpp
** @see util-foreach.hpp
*/
@ -188,6 +187,8 @@ namespace util {
/* ======== string and containment ========= */
/** check if string starts with a given prefix */
inline bool
startsWith (string const& str, string const& prefix)
@ -354,8 +355,12 @@ namespace util {
}
/** shortcut to save some typing when having to define
* const and non-const variants of member functions
* @remark the »social contract« when using this function is
* that the programmer has to ensure effective const correctness!
*/
template<class OBJ>
inline OBJ*
@ -372,8 +377,53 @@ namespace util {
}
/* ======== address and identity ========= */
/** extract address but strip any type info */
template<class X>
inline const void*
getAdr (X& x)
{
return static_cast<const void*> (std::addressof(x));
}
template<class X>
inline const void*
getAdr (X* x)
{
return static_cast<const void*> (x);
}
/** generate an unique numeric ID based on the referred entity */
template<class X>
inline size_t
addrID (X const& x)
{
return size_t(getAdr (x));
}
/** the addressable memory »slot« — platform dependent. */
template<typename X>
inline size_t
slotNr (X const& x)
{
return addrID(x) / sizeof(size_t);
}
/** compare plain object address identity, disregarding type.
* @note the pointee is compared when passing pointer(s)
*/
template<class A, class B>
inline bool
isSameAdr (A const& a, B const& b)
{
return getAdr(a) == getAdr(b);
}
/** compare plain object identity,
* bypassing any custom comparison operators.
* based directly on the referee's memory identities.
*/
template<class A, class B>
inline bool
@ -383,38 +433,10 @@ namespace util {
== static_cast<const void*> (std::addressof(b));
}
/** extract address but strip any type info */
template<class X>
inline const void*
getAddr (X& x)
{
return static_cast<const void*> (std::addressof(x));
}
template<class X>
inline const void*
getAddr (X* x)
{
return static_cast<const void*> (x);
}
/** the addressable memory »slot« — platform dependent */
template<typename X>
inline size_t
slotNr (X const& x)
{
return reinterpret_cast<size_t> (std::addressof(x)) / sizeof(size_t);
}
template<typename X>
inline size_t
slotNr (X const* x)
{
return reinterpret_cast<size_t> (x) / sizeof(size_t);;
}
/** determine heuristically if two objects
* are located close to each other in memory.
* @remark can be used to find out about heap vs. stack allocation
* @remark can be used to find out about heap versus stack allocation
* @warning relies on platform and implementation-defined observable behaviour
*/
template<typename A, typename B>
inline bool
@ -483,6 +505,7 @@ namespace util {
/* === some common macro definitions === */
/** suppress "warning: unused variable" on vars, which are

View file

@ -31,7 +31,7 @@
#include "steam/engine/buffer-metadata.hpp"
#include "lib/util.hpp"
using util::isSameObject;
using util::isSameAdr;
namespace steam {
namespace engine {
@ -243,7 +243,7 @@ namespace engine {
bool
BufferProvider::was_created_by_this_provider (BuffDescr const& descr) const
{
return isSameObject (*this, *descr.provider_);
return isSameAdr (this, descr.provider_);
}

View file

@ -278,7 +278,7 @@ namespace engine {
{
diagn::Block* block4buffer = locateBlock (typeID, specifics);
REQUIRE (block4buffer, "releasing a buffer not allocated through this provider");
REQUIRE (util::isSameObject(storage, block4buffer->accessMemory()));
REQUIRE (util::isSameAdr (storage, block4buffer->accessMemory()));
block4buffer->markReleased();
}

View file

@ -66,11 +66,11 @@ namespace gear {
{
return string{"Act("}
+ showVerb()
+ util::showAddr(this)
+ util::showAdr(this)
+ ": "
+ showData()
+ "; ⤵ "
+ (next? next->showVerb()+util::showAddr(*next)
+ (next? next->showVerb()+util::showAdr(*next)
: util::BOTTOM_INDICATOR)
+ ")";
}
@ -106,7 +106,7 @@ namespace gear {
+ ", quality="
+ util::toString(data_.timing.quality);
case NOTIFY:
return util::showAddr(data_.notification.target)
return util::showAdr(data_.notification.target)
+ ", timing:"
+ util::toString(Time{data_.notification.timing});
case GATE:

View file

@ -656,12 +656,17 @@ return: 0
END
TEST "integer rounding utility" UtilFloordiv_test <<END
TEST "collection utils" UtilCollection_test <<END
return: 0
END
TEST "integer scale wrapping utility" UtilFloorwrap_test <<END
TEST "util: integer rounding" UtilFloordiv_test <<END
return: 0
END
TEST "util: integer scale wrapping" UtilFloorwrap_test <<END
out-lit: --------int--------12/4
out-lit: 12 / 4 = 3 % = 0 floor= 3.0 wrap = ( 3, 0)
out-lit: 11 / 4 = 2 % = 3 floor= 2.0 wrap = ( 2, 3)
@ -770,7 +775,7 @@ return: 0
END
TEST "collection utils" UtilCollection_test <<END
TEST "util: address identity" UtilIdentity_test <<END
return: 0
END

View file

@ -32,12 +32,8 @@
#include "lib/error.hpp"
#include "lib/util.hpp"
#include <cstdlib>
using LERR_(ASSERTION);
using util::isSameObject;
using util::typeStr;
using std::rand;
namespace lib {
@ -62,7 +58,7 @@ namespace test{
class DigxelConfigurations_test : public Test
{
virtual void
run (Arg)
run (Arg)
{
verifyConfiguration<Digxel<int> > (123);
verifyConfiguration<Digxel<double>> (123.4567);

View file

@ -306,7 +306,7 @@ namespace test{
TestDigxel d2(d1);
CHECK (d2 == someValue);
CHECK (!isSameObject (d1, d2));
CHECK (not isSameObject (d1, d2));
d1 = randomFrac();
CHECK (d1 != d2);

View file

@ -43,7 +43,7 @@
using ::Test;
using lib::explore;
using lib::test::showSizeof;
using util::getAddr;
using util::getAdr;
using util::isnil;
using std::numeric_limits;
@ -306,7 +306,7 @@ namespace test {
// trigger overflow and allocation of second extent
char& c2 = clu.create<char> ('U');
CHECK (blk != currBlock()); // allocation moved to a new extent
CHECK (getAddr(c2) == currBlock() + 2*sizeof(void*)); // c2 resides immediately after the two administrative »slots«
CHECK (getAdr(c2) == currBlock() + 2*sizeof(void*)); // c2 resides immediately after the two administrative »slots«
CHECK (clu.storage_.rest == EXTSIZ - posOffset());
CHECK (clu.numBytes() == EXTSIZ - 2*sizeof(void*) + 1); // accounted allocation for the full first block + one byte
CHECK (clu.numExtents() == 2); // we have two extents now

View file

@ -44,9 +44,7 @@ using ::test::Test;
using std::array;
using lib::explore;
using util::isSameObject;
using util::isLimited;
using util::getAddr;
using util::isnil;
using util::join;
@ -486,7 +484,7 @@ namespace test{
void
check_ElementStorage()
{
auto loc = [](auto& something){ return size_t(getAddr (something)); };
auto loc = [](auto& something){ return util::addrID (something); };
auto calcSpread = [&](auto& several){ return loc(several[1]) - loc(several[0]); };
{ // Scenario-1 : tightly packed values
@ -532,6 +530,7 @@ namespace test{
CHECK (5 == elms.size());
auto moved = move(elms);
CHECK (5 == moved.size());
CHECK (loc(elms) != loc(moved));
CHECK (isnil (elms));
CHECK (loc(moved[0]) == p0);

View file

@ -57,7 +57,7 @@ namespace test {
using util::_Fmt;
using util::isnil;
using util::getAddr;
using util::getAdr;
using util::isSameObject;
using std::string;
using std::move;
@ -509,14 +509,14 @@ namespace test {
CHECK (s->start == -100);
CHECK (s->after == 2);
CHECK (s->id == id1);
CHECK (adr1 == getAddr(*s));
CHECK (adr1 == getAdr(*s));
CHECK (s != p);
++s;
CHECK (s == p);
CHECK (s->start == 2);
CHECK (s->after == 3);
CHECK (s->id == id2);
CHECK (adr2 != getAddr(*s)); // this is the first part of the split segment (new allocation)
CHECK (adr2 != getAdr(*s)); // this is the first part of the split segment (new allocation)
++s;
CHECK (s != p);
CHECK (s == n);
@ -525,7 +525,7 @@ namespace test {
CHECK (s->id != id1);
CHECK (s->id != id2);
CHECK (s->id != id3);
CHECK (adr2 != getAddr(*s));
CHECK (adr2 != getAdr(*s));
++s;
CHECK (s != n);
CHECK (s != a);
@ -534,7 +534,7 @@ namespace test {
CHECK (s->id != id1);
CHECK (s->id == id2);
CHECK (s->id != id3);
CHECK (adr2 != getAddr(*s)); // this is the second part of the split segment (new allocation)
CHECK (adr2 != getAdr(*s)); // this is the second part of the split segment (new allocation)
++s;
CHECK (s == a);
CHECK (s->start == 6);
@ -542,7 +542,7 @@ namespace test {
CHECK (s->id != id1);
CHECK (s->id != id2);
CHECK (s->id == id3);
CHECK (adr3 == getAddr(*s));
CHECK (adr3 == getAdr(*s));
++s;
CHECK (s == segs.end());
}

View file

@ -0,0 +1,229 @@
/*
UtilIdentity(Test) - helpers for identity and memory location
Copyright (C) Lumiera.org
2024, Hermann Vosseler <Ichthyostega@web.de>
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.
* *****************************************************/
/** @file util-identity-test.cpp
** unit test \ref UtilIdentity_test
*/
#include "lib/test/run.hpp"
#include "lib/format-obj.hpp"
#include "lib/util.hpp"
#include <utility>
#include <string>
using std::move;
using std::string;
namespace util {
namespace test {
/*****************************************************************//**
* @test verify identity based on memory address location,
* which can be relevant for custom allocation schemes
* and to prevent self-assignment.
* - access to a given entitie's address is used as foundation,
* with the _special twist_ that a pointer is »unpacked«
* - based on this address, an ID-number can be generated
* - moreover, two flavours of identity check are provided
* + util::isSameObject compares at the level of the
* _language object_ it takes its arguments _solely_
* by reference and does not »unpack« a pointer.
* The term [object] is used here as in the C++ standard
* + util::isSameAdr accepts any mix of references and
* pointers, disregarding any type information, thereby
* _»unpacking«_ the address information contained in a
* pointer is (i.e. the address of the pointee is used)
* [object]: https://en.cppreference.com/w/cpp/language/type
*/
class UtilIdentity_test : public Test
{
void
run (Arg)
{
verify_getAdr();
verify_addrID();
verify_isSameAdr();
verify_isSameObject();
}
/** @test determine the address of an referred entity,
* possibly _unpacking_ a pointer (using its content)
*/
void
verify_getAdr()
{
CHECK (getAdr (this) == this);
CHECK (getAdr (*this) == this);
CStr aloof[2] = {"reality", "check"};
CHECK (getAdr (aloof) == &aloof);
CHECK (getAdr (&aloof[0]) == &aloof);
CHECK (getAdr (&aloof[1]) == aloof+1);
CHECK (getAdr ( aloof[0]) == aloof[0]);
CHECK (getAdr ( aloof[1]) == aloof[1]);
}
/** @test generate a numeric ID based on the memory address. */
void
verify_addrID()
{
uint ui[2] = {2,3};
CHECK (addrID (ui[1]) == addrID (ui[0]) + sizeof(uint));
uint* up{ui+1};
CHECK (addrID (ui[1]) == addrID (up));
}
/** dummy entity to compare */
struct Boo
{
short moo;
string woo;
Boo()
: moo(rani(1000))
, woo{toString(moo-1)}
{ }
};
struct SuBoo : Boo
{
using Boo::Boo;
size_t poo{addrID (this)};
};
static Boo* asBoo (void* mem) { return static_cast<Boo*> (mem); }
/** @test determine identity of referred arguments based on their
* memory location; pointers are unpacked, referring to the pointee.
*/
void
verify_isSameAdr()
{
Boo boo;
Boo booo;
Boo* boop = &boo;
Boo const* const beep = boop;
CHECK (boo.moo != booo.moo);
CHECK (boo.moo == boop->moo);
CHECK ( isSameAdr (boop, beep));
CHECK (not isSameAdr (&boop,&beep));
CHECK ( isSameAdr (boo, beep));
CHECK ( isSameAdr (*beep, boo ));
CHECK (not isSameAdr (*beep, booo));
CHECK ( isSameAdr (boo, boo.moo));
CHECK ( isSameAdr (boo, &boo.moo));
CHECK (not isSameAdr (boo.moo, booo));
CHECK ( isSameAdr (booo, asBoo(&booo.moo)));
CHECK (not isSameAdr (booo, asBoo(&booo.woo)));
// handles also void*
const void* voo = boop;
CHECK ( isSameAdr (voo, boo));
CHECK ( isSameAdr (voo, boop));
CHECK (not isSameAdr (voo, booo));
CHECK ( isSameAdr (voo, asBoo(&boo.moo)));
CHECK (not isSameAdr (voo, asBoo(&booo.moo)));
CHECK (not isSameAdr (voo, asBoo(&boo.woo)));
// RValue taken by ref
Boo&& roo = move(boo);
CHECK ( isSameAdr (roo, boo));
CHECK ( isSameAdr (voo, roo));
CHECK (not isSameAdr (voo, Boo{roo}));
// type information disregarded
SuBoo* suBoo = static_cast<SuBoo*>(&boo);
CHECK ( isSameAdr (boo, suBoo));
CHECK ( isSameAdr (boo, suBoo->moo));
CHECK ( isSameAdr (voo, suBoo->moo));
CHECK (not isSameAdr (voo, suBoo->poo));
SuBoo sudo{*suBoo};
CHECK (not isSameAdr (sudo, boo));
CHECK (not isSameAdr (sudo, suBoo));
suBoo = &sudo;
CHECK ( isSameAdr (sudo.poo, suBoo->poo));
}
/** @test determine strictly the identity of referred entities as given. */
void
verify_isSameObject()
{
Boo boo;
Boo booo;
Boo* boop = &boo;
Boo* woop = boop;
Boo& foop = *woop;
CHECK ( isSameObject (boo, boo ));
CHECK ( isSameObject (booo, booo));
CHECK (not isSameObject (boo, booo));
CHECK (not isSameObject (booo, boo ));
// pointers count as »objects« and are not dereferenced
CHECK (not isSameObject (boop, woop));
CHECK (not isSameObject (boop, booo));
CHECK (not isSameObject (boop, boo ));
CHECK (not isSameObject (booo, woop));
CHECK (not isSameObject (boo , woop));
CHECK ( isSameObject (boo , foop));
CHECK ( isSameObject (foop, boo ));
CHECK (not isSameObject (foop, boop));
CHECK (not isSameObject (foop, woop));
CHECK (not isSameObject (foop, &boo ));
CHECK ( isSameObject (foop, *boop));
CHECK ( isSameObject (*boop, foop));
// RValue taken by ref
Boo&& roo = move(boo);
CHECK ( isSameObject (roo, boo));
CHECK (not isSameObject (boo, Boo{roo}));
// type information disregarded
SuBoo* suBoo = static_cast<SuBoo*>(&boo);
CHECK ( isSameObject (boo, *suBoo));
CHECK ( isSameObject (boo, suBoo->moo));
CHECK (not isSameObject (boo, suBoo->woo));
// void* is treated as a distinct object
void* voo = boop;
CHECK (not isSameObject (voo , boop));
CHECK (not isSameObject (voo , boo));
CHECK (not isSameObject (voo , &boo)); // ...not getting anywhere...
CHECK (not isSameObject (voo , asBoo(&boo)));
CHECK (not isSameObject (boo , asBoo(&boo)));
}
};
LAUNCHER (UtilIdentity_test, "unit common");
}} // namespace util::test

View file

@ -41,9 +41,8 @@ using std::tuple_size_v;
namespace util {
namespace test {
typedef std::vector<uint> VecI;
typedef lib::RangeIter<VecI::iterator> RangeI;
using VecI = std::vector<uint>;
using RangeI = lib::RangeIter<VecI::iterator>;
namespace{ // Test data and operations

View file

@ -555,7 +555,7 @@ namespace test {
buildActivationTap (Activity const& subject, string id ="")
{
return mockActs_.emplace_back (subject
,isnil(id)? "tap-"+subject.showVerb()+util::showAddr(subject)
,isnil(id)? "tap-"+subject.showVerb()+util::showAdr(subject)
: id
,eventLog_
,invocationSeq_);
@ -566,14 +566,14 @@ namespace test {
insertActivationTap (Activity*& wiring, string id ="")
{
wiring = wiring? & buildActivationTap (*wiring, id)
: & buildActivationProbe (isnil(id)? "tail-"+util::showAddr(&wiring) : id);
: & buildActivationProbe (isnil(id)? "tail-"+util::showAdr(&wiring) : id);
return *wiring;
}
Activity&
buildGateWatcher (Activity& gate, string id ="")
{
insertActivationTap (gate.next, "after-" + (isnil(id)? gate.showVerb()+util::showAddr(gate) : id));
insertActivationTap (gate.next, "after-" + (isnil(id)? gate.showVerb()+util::showAdr(gate) : id));
return buildActivationTap (gate, id);
}
@ -581,7 +581,7 @@ namespace test {
watchGate (Activity*& wiring, string id ="")
{
wiring = wiring? & buildGateWatcher (*wiring, id)
: & buildActivationProbe (isnil(id)? "tail-"+util::showAddr(&wiring) : id);
: & buildActivationProbe (isnil(id)? "tail-"+util::showAdr(&wiring) : id);
return *wiring;
}

View file

@ -1623,7 +1623,7 @@ namespace test {
{
return _Fmt{"ChainCalc(w:%d)◀%s"}
% maxFan
% util::showAddr(startNode_);
% util::showAdr(startNode_);
}
};

View file

@ -16189,9 +16189,7 @@
</node>
<node CREATED="1523232888115" ID="ID_800807629" MODIFIED="1523232908023">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
aber genau das ist hier jeweils nur <i>in einem Fall</i>&#160;gegeben
@ -17093,9 +17091,7 @@
</node>
<node CREATED="1504193354056" FOLDED="true" ID="ID_385011645" MODIFIED="1518487921077">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>Abstraktion</b>&#160;zur Steuerung schaffen
@ -17569,9 +17565,7 @@
<node CREATED="1541088360999" ID="ID_1860524548" MODIFIED="1557498707223" TEXT="horizontale Ausdehnung steuerbar">
<node CREATED="1541088395516" ID="ID_122658669" MODIFIED="1576282358102" TEXT="nat&#xfc;rlich">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
d.h. das Widget unternimmt selber nichts, und &#252;berl&#228;&#223;t GTK die Gr&#246;&#223;enbestimmung
@ -18101,9 +18095,7 @@
<node CREATED="1654448154480" ID="ID_1428501909" MODIFIED="1654448287941" TEXT="LABEL">
<node CREATED="1654448495868" ID="ID_278262506" MODIFIED="1662037668001" TEXT="oder MARKER?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Terminologie nicht klar...
@ -19118,9 +19110,7 @@
</node>
<node CREATED="1664767140485" ID="ID_428399436" MODIFIED="1664767217656" TEXT="vor allem die wieder-einblenden-Sequenz ist gef&#xe4;hrlich">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...denn sie wird f&#252;r jeden Fokuswechsel und f&#252;r jeden erfolglosen Versuch erneut durchlaufen, und zwar in den meisten F&#228;llen (Label) bis zum 3.Schritt, nur um dann zu merken, da&#223; eben doch nichts mehr rauszuholen ist.
@ -20180,9 +20170,7 @@
<node CREATED="1666285046869" ID="ID_925433658" MODIFIED="1666285057773" TEXT="setzt dann Zeiten und Namen"/>
<node CREATED="1666285058499" ID="ID_1175866676" MODIFIED="1666285084060">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
und danach feuert der <i>StructuralChange</i>-Listener
@ -22387,9 +22375,7 @@
</node>
<node COLOR="#338800" CREATED="1575845743838" ID="ID_1827383151" MODIFIED="1582503290754" TEXT="testContainsSequence()-predicate does not work properly in the initial base check">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
again the problem with the reversed order due to forward_list
@ -46584,9 +46570,7 @@
</node>
<node CREATED="1448078798369" ID="ID_819750758" MODIFIED="1576282358014" TEXT="komplett-Reset">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
mark &quot;reset&quot;
@ -46811,9 +46795,7 @@
<node CREATED="1455236382183" ID="ID_983670310" MODIFIED="1518487921086" TEXT="Einstiegspunkt: revealYourself"/>
<node CREATED="1455236393861" ID="ID_1638665625" MODIFIED="1518487921086">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
support ist <i>optional</i>
@ -47175,9 +47157,7 @@
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
das mag &#252;berraschen --
@ -47476,9 +47456,7 @@
<node CREATED="1455913759727" HGAP="43" ID="ID_1318158783" MODIFIED="1512926191911" TEXT="Modell">
<node CREATED="1455913778429" ID="ID_884750408" MODIFIED="1575133325713" TEXT="sub-Collections">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
eindeutig &#252;berlegen
@ -56354,6 +56332,29 @@
</node>
</node>
</node>
<node CREATED="1731602067582" ID="ID_1120424143" MODIFIED="1731602071322" TEXT="Ausdrucksmittel">
<node CREATED="1731602123520" ID="ID_614194653" MODIFIED="1731602280844" TEXT="Speicher-Identit&#xe4;t">
<linktarget COLOR="#59586c" DESTINATION="ID_614194653" ENDARROW="Default" ENDINCLINATION="-1423;212;" ID="Arrow_ID_1656634027" SOURCE="ID_180344920" STARTARROW="None" STARTINCLINATION="-701;37;"/>
<node CREATED="1731600837017" ID="ID_1200940596" MODIFIED="1731600906446" TEXT="isSameObject">
<font NAME="Monospaced" SIZE="12"/>
<node CREATED="1731600933000" ID="ID_562384209" MODIFIED="1731600960815" TEXT="nimmt die Argumente stets als Referenz"/>
<node CREATED="1731600962593" ID="ID_1995003068" MODIFIED="1731600989770" TEXT="vergleicht die Speicher-Idenit&#xe4;t der referierten Objekte"/>
<node CREATED="1731600990479" ID="ID_1074322955" MODIFIED="1731601028461" TEXT="Pointer sind &quot;objects&quot; im Sinne von C++ &#x27f9; es werden nicht die Pointees verglichen"/>
<node CREATED="1731601031372" ID="ID_1290492988" MODIFIED="1731601052890" TEXT="das hei&#xdf;t, dies ist die bestehende Funktion, und sie bleibt so, wie sie ist"/>
</node>
<node CREATED="1731600845818" ID="ID_570811457" MODIFIED="1731600923731" TEXT="isSameAddr">
<font NAME="Monospaced" SIZE="12"/>
<node CREATED="1731601069781" ID="ID_1090427138" MODIFIED="1731601080522" TEXT="nimmt einen beliebigen Mix von Pointern oder Referenzen"/>
<node CREATED="1731601081698" ID="ID_925316830" MODIFIED="1731601099164" TEXT="Pointer werden selber als Referenz gedeutet und einmal dereferenziert"/>
<node CREATED="1731601100055" ID="ID_957797383" MODIFIED="1731601116708" TEXT="die dadurch bezeichneten &quot;objects&quot; werden verglichen"/>
<node CREATED="1731601117550" ID="ID_83648196" MODIFIED="1731601164748" TEXT="das hei&#xdf;t, dies ist die neue flexible Implementierung (f&#xfc;r spezielle F&#xe4;lle)"/>
<node CREATED="1731601170863" ID="ID_88090345" MODIFIED="1731601192896" TEXT="im Besonderen k&#xf6;nnen wir damit void* vergleichen (was bisher unm&#xf6;glich war)"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1731602329563" HGAP="12" ID="ID_35905059" MODIFIED="1731624715759" TEXT="util-identity-test.cpp" VSHIFT="12">
<icon BUILTIN="forward"/>
</node>
</node>
</node>
</node>
<node CREATED="1573230375839" ID="ID_270568302" MODIFIED="1573230382276" TEXT="policies">
<node CREATED="1573230393523" ID="ID_1929317164" MODIFIED="1573230398694" TEXT="wie viel const-correctness?">
@ -57524,9 +57525,7 @@
</html></richcontent>
<node CREATED="1731516823812" ID="ID_1419872560" MODIFIED="1731516925668" TEXT="bedingt durch Reorganisation #includes">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...hatte vor einiger Zeit aufger&#228;umt und einen eigenen #include &quot;lib/integral.hpp&quot; geschaffen. Dadurch ist downstream der #include f&#252;r time-value.hpp rausgefallen, und damit fehlte die String-conversion f&#252;r Rationals
@ -57537,9 +57536,7 @@
</node>
<node CREATED="1731516926921" ID="ID_1885341686" MODIFIED="1731516970756" TEXT="die eigentliche Ursache ist das ungel&#xf6;ste Problem mit FSecs">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...dazu nochmal &#252;ber die ganze Problematik nachgedacht und entsprechende Kommentare in #1258 und #1261 hinterlassen
@ -57589,11 +57586,21 @@
<font size="1">END </font>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1731624499756" ID="ID_293265001" MODIFIED="1731624683932" TEXT="WorkForce_test">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
<font face="Monospaced" size="2">CHECK: work-force-test.cpp:425: thread_1: verify_scalePool: (2*fullCnt == uniqueCnt) </font>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1731467207226" ID="ID_977237610" MODIFIED="1731467207226" TEXT="TrackingHeapBlockProvider_test">
<node CREATED="1731467220749" ID="ID_1574698883" MODIFIED="1731467357686" TEXT="ASSERTION">
<node COLOR="#435e98" CREATED="1731467207226" ID="ID_977237610" MODIFIED="1731624884569" TEXT="TrackingHeapBlockProvider_test">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731467220749" ID="ID_1574698883" MODIFIED="1731624803495" TEXT="ASSERTION">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -57601,16 +57608,245 @@
0000000516: PRECONDITION: tracking-heap-block-provider.cpp:281: thread_1: detachBuffer: (util::isSameObject(storage, block4buffer-&gt;accessMemory()))
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<linktarget COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_986253090" SOURCE="ID_844778131" STARTARROW="None" STARTINCLINATION="30;3;"/>
<linktarget COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_1250752825" SOURCE="ID_74232375" STARTARROW="None" STARTINCLINATION="34;4;"/>
<node CREATED="1731518054338" ID="ID_1029594237" MODIFIED="1731519199214" TEXT="neu eingef&#xfc;hrt im Juli 2024 &#x2014; wegen LocalTag">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Damals im Juli habe ich versucht, die Info zum Ausgabe-Buffer durch das allgemeine Buffer-Handling-Framework durchzuf&#228;deln; daf&#252;r habe ich das <font color="#0b0d8d" face="Monospaced">LocalTag</font>&#160;(vorher <font color="#0b0d8d" face="Monospaced">LocalKey</font>&#160;genannt) eingesetzt; in der weiteren Entwicklung habe ich jedoch dann diesen architektonisch unpassenden Ansatz verworfen und die Identifikation des Ausgabe-Buffers direkt in den Aufruf von oben hereingegeben.
</p>
<p>
In diesem Zusammenhang habe ich das BufferProvider-Framework nochmal genauer angeschaut, einige potentielle Gefahren abgedichtet und &#8212; TADAA &#8212; <b>zus&#228;tzliche Assertions</b>&#160;eingebaut, die jetzt ansprechen. Gut gebr&#252;llt, L&#246;we
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1731518770635" ID="ID_1551802265" MODIFIED="1731519196383">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
ich hab damals auf <i>theoretischem Weg</i>&#160;die Gefahr duplikater Eintr&#228;ge entdeckt...
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Und zwar durch den Umstand, da&#223; die Eintr&#228;ge im Buffer-Provider durch Key-Records markiert sind, welche untereinander hierarchisch zusammenh&#228;ngen k&#246;nnen. Denn zun&#228;chst stellt ein solcher Eintrag einen Buffer-Typ dar, von dem dann viele einzelne konkrete Buffer registiert und verwarbeitet werden. Das Problem entsteht nun aber, weil auch ein zus&#228;tzliches LocalTag mit in den Key einflie&#223;t zur zus&#228;tzlichen Differenzierung. Das ist zun&#228;chst sinnvoll, um einen Typ zus&#228;tzlich zu qualifizieren. Gef&#228;hrlich ist aber, da&#223; zu einem bestehenden Buffer mit Adresse noch ein Local-Tag hinzugef&#252;gt werden k&#246;nnte, oder da&#223; man versucht, die gleiche Adresse einmal mit und einmal ohne LocalTag anzusprechen. Denn dadurch w&#252;rden zwei Metadatens&#228;tze erzeugt, die dann jeweils auch einen eigenst&#228;ndigen Lifecycle durchlaufen, obwohl sie zur gleichen Buffer-Adresse geh&#246;ren.
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1731519381164" ID="ID_768637407" MODIFIED="1731519497995" TEXT="mir war aufgefallen, da&#xdf; f&#xfc;r release() eines Buffers die Adress-Info auf zwei Wegen vorliegt">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...und aber eine dieser Infos einfach ignoriert wird, n&#228;mlich die konkrete Info, die der im BuffHandle vom Client eingebettet ist. Daher habe ich f&#252;r die einzige Implementierung, den TrackingHeapBlockProvider beide Infos in einer Assertion verglichen. Und genau dieser Check scheitert jetzt (noch nicht klar warum)
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1731519941439" ID="ID_357574011" MODIFIED="1731519948226" TEXT="Untersuchung...">
<icon BUILTIN="forward"/>
<node CREATED="1731519949320" ID="ID_240715659" MODIFIED="1731519987357" TEXT="Call-Path: simpleExample() &#x27f6; provider.releaseBuffer(testBuff)"/>
<node CREATED="1731520006047" ID="ID_577977745" MODIFIED="1731520016425" TEXT="Debugger">
<node CREATED="1731529842821" ID="ID_304693119" MODIFIED="1731529854030" TEXT="nebenbei bemerkt: TypeHandler verwendet eine identity">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1731529855307" ID="ID_1862852828" MODIFIED="1731529863928" TEXT="wozu wird die verwendet?">
<icon BUILTIN="help"/>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1731529995641" ID="ID_570070738" MODIFIED="1731530005496" TEXT="Aua: f&#xfc;r hash_value">
<icon BUILTIN="broken-line"/>
</node>
<node CREATED="1731530923708" ID="ID_1704286619" MODIFIED="1731530935278" TEXT="Problem best&#xe4;tigt: flie&#xdf;t in die Key-Identity ein"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1731529864690" ID="ID_1980255586" MODIFIED="1731529881765" TEXT="die baut nur auf dem Typ der Funktoren auf">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1731529882792" ID="ID_206400237" MODIFIED="1731529889643" TEXT="das ist rein-logisch zu wenig"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731529890448" ID="ID_1813009572" MODIFIED="1731529914846" TEXT="wir br&#xe4;uchten einen Hash des konkreten Funktors">
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1731467215176" ID="ID_844778131" MODIFIED="1731467314156" TEXT="BufferProviderProtocol_test">
</node>
<node CREATED="1731530752729" ID="ID_1739111078" MODIFIED="1731530782462" TEXT="au&#xdf;erdem: TypeHandler wird x-fach als Argument kopiert">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
und zwar f&#252;r die Key-Erstellung; die nimmt wohl das Argument by-value
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731532150744" FOLDED="true" ID="ID_1436652987" MODIFIED="1731624876192" TEXT="eigentlicher Fehler ist &#xbb;trivial&#xab;">
<icon BUILTIN="idea"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1731532165222" ID="ID_1833321928" MODIFIED="1731624871572" TEXT="util::isSameObject() funktioniert nicht mit Pointern">
<icon BUILTIN="broken-line"/>
</node>
<node CREATED="1731532197465" ID="ID_1421822856" MODIFIED="1731532204220" TEXT="das Problem hatte ich schon mehrfach....">
<node CREATED="1731532205120" ID="ID_1252046258" MODIFIED="1731532213103" TEXT="da wird dann der Overload f&#xfc;r Referenzen genommen"/>
<node CREATED="1731532213703" ID="ID_502132953" MODIFIED="1731532231897" TEXT="und dann bekommt man die Adresse des Pointers, nicht das Pointee"/>
</node>
<node CREATED="1731557607155" ID="ID_369696513" MODIFIED="1731557634957" TEXT="ist hier besonders l&#xe4;stig, weil eine Seite als void* reinkommt"/>
<node COLOR="#338800" CREATED="1731557638735" ID="ID_84382244" MODIFIED="1731624765483" TEXT="kann man diese Funktion vielleicht doch generischer implementieren?">
<icon BUILTIN="help"/>
<node CREATED="1731557658612" ID="ID_883821710" MODIFIED="1731557746261" TEXT="Untersuchung in separater translation-unit (try.cpp)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
bisher hab ich immer den &#187;Fehler&#171; gemacht, solche trickreichen Experimente im Blindflug in util.hpp machen zu wollen. Das ging dann schief, und nach drei vergeblichen Versuchen hab ich das Thema aufgegeben, schlie&#223;lich dauert jeder Build 5 Minuten.....
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1731557747600" ID="ID_853752206" MODIFIED="1731607866837" TEXT="was ist eigentlich das Problem...??">
<node CREATED="1731557774684" ID="ID_1079471653" MODIFIED="1731557781559" TEXT="man kann auf getAddr() aufbauen"/>
<node CREATED="1731557782127" ID="ID_923836116" MODIFIED="1731557807312">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
es braucht hier <b>kein</b>&#160;perfect-forwarding
</p>
</body>
</html></richcontent>
<font NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1731557814482" ID="ID_1814674606" MODIFIED="1731557862676" TEXT="und Overload-Resolution trennt const* problemlos von const&amp;"/>
<node CREATED="1731557865776" ID="ID_1157127706" MODIFIED="1731557879306" TEXT="gleich noch x-fach verschiedene Aufruf-Varianten erprobt"/>
<node CREATED="1731557880370" ID="ID_1944561028" MODIFIED="1731607927621" TEXT="gibt es dann nicht doch irgend welche ekelhaften Grenzf&#xe4;lle...?">
<arrowlink COLOR="#fef1a9" DESTINATION="ID_571510979" ENDARROW="Default" ENDINCLINATION="1;-21;" ID="Arrow_ID_441150383" STARTARROW="None" STARTINCLINATION="-165;7;"/>
</node>
</node>
<node COLOR="#338800" CREATED="1731557904987" ID="ID_1391232069" MODIFIED="1731607858554" TEXT="also mal versuchsweise tats&#xe4;chlich umgestellt">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#e9e37f" COLOR="#d70657" CREATED="1731557924088" ID="ID_571510979" MODIFIED="1731607954840" TEXT="ein paar Tests scheitern">
<linktarget COLOR="#fef1a9" DESTINATION="ID_571510979" ENDARROW="Default" ENDINCLINATION="1;-21;" ID="Arrow_ID_441150383" SOURCE="ID_1944561028" STARTARROW="None" STARTINCLINATION="-165;7;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1731557952732" ID="ID_777170043" MODIFIED="1731557953581" TEXT="ReplaceableItem_test">
<node CREATED="1731558129469" ID="ID_1886714615" MODIFIED="1731558148849" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
<font face="Monospaced">CHECK ( isSameObject (*ptrWrap.get(), x)); </font>
</p>
<p>
<font face="Monospaced">CHECK (!isSameObject ( ptrWrap.get(), x));</font>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1731558151929" ID="ID_610281553" MODIFIED="1731558167499" TEXT="tja ... das geht jetzt nicht mehr mit der &#xbb;verbesserten&#xab; Funktion"/>
</node>
<node CREATED="1731557965170" ID="ID_878035767" MODIFIED="1731557966708" TEXT="Symbol_test">
<node CREATED="1731558015153" ID="ID_1322838504" MODIFIED="1731558560689" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
<font face="Monospaced">CHECK (not isSameObject (y1.c(), y2.c()));&#160; </font>
</p>
<p>
<font face="Monospaced">CHECK (&#160;&#160;&#160;&#160;isSameObject (*y1.c(), *y2.c()));</font>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1731558175623" ID="ID_1288225438" MODIFIED="1731558197241" TEXT="gleiches Problem hier: jetzt werden die Pointees verglichen, und die sind tats&#xe4;chlich gleich"/>
</node>
<node CREATED="1731557941189" ID="ID_1041472032" MODIFIED="1731559882555" TEXT="ItemWrapper_test">
<node CREATED="1731557968137" ID="ID_1008712171" MODIFIED="1731557978948" TEXT="hier entgleist die self-Assignment-Sperre"/>
<node CREATED="1731559053809" ID="ID_459077352" MODIFIED="1731559074210" TEXT="und zwar in dem Fall, wo val &#x2254; nullptr in dem ItemWrapper gespeichert wurde"/>
<node COLOR="#435e98" CREATED="1731559450932" ID="ID_1145602858" MODIFIED="1731608768749" TEXT="opaque-holder.hpp, Zeile 433 ist m&#xf6;glicherweise vom gleichen Problem betroffen">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1731608782409" ID="ID_1577437011" MODIFIED="1731609018193" TEXT="es gibt sogar zwei Probleme hier">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
ein einer einzigen &#8222;harmlosen&#8220; Zeile...
</p>
<ul>
<li>
wenn man die Policy f&#252;r &#187;unrelated objects&#171; verwendet, w&#228;re BaseP &#8801; void* und es g&#228;be einen Compile-Fehler. <i>Zeigt da&#223; die Tests oberfl&#228;chlich sind</i>
</li>
<li>
wenn der Payload-Typ SUB ein Pointer ist (auch das w&#228;re theoretisch m&#246;glich im Falle der &#187;unrelated objects&#171;) dann w&#252;rde der Object-Vergleich funktionieren (aber am void* scheitern), wohingegen der Address-Vergleich den Payload-Pointer auspacken, und somit zu einem falschen Urteil kommen w&#252;rde
</li>
</ul>
</body>
</html></richcontent>
<icon BUILTIN="ksmiletris"/>
</node>
<node CREATED="1731608770140" ID="ID_1073282986" MODIFIED="1731608781543" TEXT="durch die differenzierte L&#xf6;sung nun explizit behoben"/>
<node COLOR="#435e98" CREATED="1731609027812" ID="ID_209219846" MODIFIED="1731609059104" TEXT="der Trick ist: f&#xfc;r den Adress-Vergleich explizit von der Payload die Adresse ziehen">
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1731559869128" ID="ID_1223047727" MODIFIED="1731559877774" TEXT="replacable-item.hpp, Zeile 111 ebenso"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1731559083735" ID="ID_1945208616" MODIFIED="1731607982318" TEXT="also: das Problem ist, man braucht die andere (striktere) Vergleichs-Semantik manchmal auch">
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1731560045628" ID="ID_975714348" MODIFIED="1731560051599" TEXT="und zwar in kniffeligen Situationen"/>
<node CREATED="1731560052027" ID="ID_5087696" MODIFIED="1731560070981" TEXT="wie self-Assign-Sperre, aber konvertierbar zur Payload und Payload ist ein Pointer"/>
<node CREATED="1731560071617" ID="ID_583408006" MODIFIED="1731560124827" TEXT="in solchen F&#xe4;llen f&#xfc;hrt die &#xbb;magische&#xab; Dereferenzierung zu einem Fehlurteil"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731560153334" ID="ID_225688426" MODIFIED="1731607988680" TEXT="Aufgabe ist also: eine L&#xf6;sung f&#xfc;r diese Sonderf&#xe4;lle finden">
<icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1731560176655" ID="ID_614617889" MODIFIED="1731607991375" TEXT="und zwar eine L&#xf6;sung, die nicht &#xfc;berraschend ist">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1731600307680" ID="ID_434676407" MODIFIED="1731600338394">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
wir brauchen zwei Semantiken &#10233; also <b>zwei</b>&#160;Utilities
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1731600354596" ID="ID_1754449803" MODIFIED="1731600563068" TEXT="tats&#xe4;chlich ist der flexible Vergleich als Sonderfall zu betrachen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
in den allemeisen F&#228;llen entspricht das, was gepr&#252;ft wird, tats&#228;chlich dem Begriff &quot;object&quot; aus dem C++ - Standard, also <i>keine Referenz, keine Funktion und nicht void.</i>
</p>
</body>
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1731600820255" ID="ID_180344920" MODIFIED="1731602293404" TEXT="Beschlu&#xdf;: Festlegung der Namen und der Semantik">
<arrowlink COLOR="#59586c" DESTINATION="ID_614194653" ENDARROW="Default" ENDINCLINATION="-1423;212;" ID="Arrow_ID_1656634027" STARTARROW="None" STARTINCLINATION="-701;37;"/>
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#b2d2c5" COLOR="#435e98" CREATED="1731624825649" ID="ID_1060913528" MODIFIED="1731624852008" TEXT="Code-Basis verbessert">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1731467215176" ID="ID_844778131" MODIFIED="1731624889948" TEXT="BufferProviderProtocol_test">
<arrowlink COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_986253090" STARTARROW="None" STARTINCLINATION="30;3;"/>
</node>
<node CREATED="1731467215176" ID="ID_74232375" MODIFIED="1731467357686" TEXT="OutputSlotProtocol_test">
<node COLOR="#435e98" CREATED="1731467215176" ID="ID_74232375" MODIFIED="1731624889948" TEXT="OutputSlotProtocol_test">
<arrowlink COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_1250752825" STARTARROW="None" STARTINCLINATION="34;4;"/>
</node>
</node>