Range over a container r-value with disabled postblit
Nordlöw
per.nordlow at gmail.com
Sun Jan 14 01:38:17 UTC 2018
Given my combined hashmap and hashset container `HashMapOrSet`
defined at
https://github.com/nordlow/phobos-next/blob/master/src/hashmap_or_hashset.d
with deterministic memory management and disabled copy
constructions and a member byElement() defined as
@property auto byElement()() inout
{
dln("entering byElement");
alias This = ConstThis;
// TODO is the use of `&this` incorrect when `this`
is an r-value?
auto result =
ByElement!This((ElementRef!This(cast(This*)&this)));
result.initFirstNonEmptyBin();
dln("leaving byElement");
return result;
}
scope auto opSlice()() inout return
{
return byElement();
}
where
static private struct ByElement(HashMapOrSetType)
{
static if (is(ElementType == class))
{
/// Get reference to front element (key and
value).
@property scope auto front()() return @trusted
{
/* cast away const from `HashMapOrSetType`
for classes
* because class elements are currently
hashed and compared
* compared using their identity (pointer
value) `is`
*/
return
cast(ElementType)table.binElementsAt(binIx)[elementOffset];
}
}
else
{
/// Get reference to front element (key and
value).
@property scope auto front()()
{
return
table.binElementsAt(binIx)[elementOffset];
}
}
public ElementRef!HashMapOrSetType _elementRef;
alias _elementRef this;
}
iteration via opSlice works fine when `X` is fed as `this` to
`byElement` as an l-value as in
import digestx.fnv : FNV;
alias X = HashMapOrSet!(uint, void, null, FNV!(64, true));
const x = X.withElements([11].s);
foreach (e; x.byElement) {}
but when `X` is fed as an r-value `this` to `byElement` as in
import digestx.fnv : FNV;
alias X = HashMapOrSet!(uint, void, null, FNV!(64, true));
foreach (e; X.withElements([11].s).byElement) {}
I get a behaviour that seems to indicate that the instance of `X`
is freed after `byValue()` (opSlice) returns but before the
`ByValue`-range is consumed, resulting in incorrect (undefind)
behaviour.
Is it incorrect to use `&this` as follows
auto result =
ByElement!This((ElementRef!This(cast(This*)&this)));
in the `byElement`?
If so, is there a way around this problem except for making my
container be RC-allocated?
My current proposal for a solution is to make `byElement` a free
unary function
byElement(auto ref X x)
which statically checks via
static if (__traits(isRef, x))
whether the `X`-instance is passed as either an
- l-value, where my current solution works (ByLvalueElement), or
- r-value, in which the X-instance instead is moved into range
(ByRvalueElement).
byValue can be used via UFCS, but this solution removes the
possibility for using the opSlice-overload which I can live with.
Further, does all EMSI-container-style containers (with disabled
postblit) have the same issue with ranges over r-value instances
of its containers?
More information about the Digitalmars-d-learn
mailing list