digitalmars.D.learn - How to separarte lvalue parameter from rvalue?
- realhet (112/112) Sep 14 Hi! I try to make the easiest syntax for manipulating bits.
- realhet (13/14) Sep 14 Update: This way I it works, but I think I'm abusing it.
- Rachel Wilson (18/32) Oct 08 the trait youre looking for is __traits(isRef, data). with an
Hi! I try to make the easiest syntax for manipulating bits.
Examples:
```d
value.asBits[3..5] = 2;
writeln(value.asBits[3..5].as!uint);
```
For the entry point I chose from 2 implementations:
```d
auto asBits(D)(ref D data)
=> BitsRefSlice!D(&data, 0, D.sizeof*8);
auto asBits(D)(D data)
=> BitsValSlice!D(data, 0, D.sizeof*8);
```
But this is wrong. If I give it immutable data, it will chose
BitRefSlice. And BitRefSlice stores a pointer to data inside.
How can I detect it properly?
Here's the whole thing:
```d
struct BitsRefSlice(D)
{
private { D* pdata; size_t st, en; }
size_t opDollar(size_t pos)()
=> D.sizeof*8 - st;
auto opIndex()(size_t i)
=> BitsRefIndex!D(pdata, this.st+i).get;
auto opIndexAssign()(bool v, size_t i)
=> BitsRefIndex!D(pdata, this.st+i).set(v);
auto opSlice(size_t st, size_t en)
=> BitsRefSlice!D(pdata, this.st+st, this.st+en);
auto opSlice()
=> this[0..$];
auto as(T)()
=> BitsValSlice!D(*pdata, st, en).as!T;
auto as(T)(in T val)
{
const msk0 = ((1UL<<(en-st))-1),
msk = msk0<<st;
(*pdata) = (cast(D)((*pdata)&~msk | ((val&msk0)<<st)));
return val;
}
auto get() => BitsValSlice!D(*pdata, st, en).get;
auto access() => get;
auto access(T)(in T val) => as = val;
alias this = access;
} struct BitsValSlice(D)
{
private { D data; size_t st, en; }
size_t opDollar(size_t pos)()
=> D.sizeof*8 - st;
auto opIndex()(size_t i)
=> BitsValIndex!D(data, this.st+i).get;
auto opSlice(size_t st, size_t en)
=> BitsValSlice!D(data, this.st+st, this.st+en);
auto opSlice()
=> this[0..$];
auto as(T)()
{
auto res = (cast(T)((data>>st) & ((1UL<<(en-st))-1)));
static if(isIntegral!T && isSigned!T)
{
const sh = T.sizeof*8 - (en-st);
res = (cast(T)((cast(T)(res<<sh))>>sh)); /+sign extend+/
}
return res;
}
static if(D.sizeof<=4) { alias DefaultType = uint; }
else { alias DefaultType = ulong; }
auto get() => as!DefaultType;
alias this = get;
}
struct BitsRefIndex(D)
{
private { D* pdata; size_t idx; }
bool get() => BitsValIndex!D(*pdata, idx).get;
bool set(bool v)
{
*pdata = (cast(D)((*pdata)&~(1UL<<idx)|((cast(D)(v))<<idx)));
return v;
}
bool access() => get;
bool access(bool v) => set(v);
alias this = access;
} struct BitsValIndex(D)
{
private { D data; size_t idx; }
bool get() => !!((data>>idx)&1);
alias this = get;
}
auto asBits(D)(ref D data)
=> BitsRefSlice!D(&data, 0, D.sizeof*8);
auto asBits(D)(D data)
=> BitsValSlice!D(data, 0, D.sizeof*8);
bool test_bits()
{
ubyte b = 0x55; enforce(b.asBits[4..8]==5);
b.asBits[4..8] = -1; enforce(b.asBits[]==0xF5);
enforce(b.asBits[].as!int==-11);
enforce((0x696).asBits[4..$].as!ubyte==0x69);
return true;
}
```
Sep 14
On Monday, 14 September 2026 at 10:51:38 UTC, realhet wrote:Hi! I try to make the easiest syntax for manipulating bits.Update: This way I it works, but I think I'm abusing it. ```d auto asBits(D)(ref D data) { static if(__traits(compiles, data = data)) return BitsRefSlice!D(&data, 0, D.sizeof*8); else return BitsValSlice!D(data, 0, D.sizeof*8); } auto asBits(D)(D data) => BitsValSlice!D(data, 0, D.sizeof*8); ``` Somebody please tell me what's the best practice for this.
Sep 14
the trait youre looking for is __traits(isRef, data). with an
auto ref parameter you can do the whole thing in one function
instead of the compiles trick:
```d
auto asBits(D)(auto ref D data)
{
static if (__traits(isRef, data) && isMutable!D)
return BitsRefSlice!D(&data, 0, D.sizeof * 8);
else
return BitsValSlice!D(data, 0, D.sizeof * 8);
}
```
isRef tells you whether the argument actually bound by reference,
so immutable lvalues and rvalues fall through to the by-value
branch naturally. isMutable is from std.traits. one caveat: the
by-value branch has to copy the data before slicing, since an
rvalue is gone by the time the expression ends.
On Monday, 14 September 2026 at 11:02:49 UTC, realhet wrote:
On Monday, 14 September 2026 at 10:51:38 UTC, realhet wrote:
Hi! I try to make the easiest syntax for manipulating bits.
Update: This way I it works, but I think I'm abusing it.
```d
auto asBits(D)(ref D data)
{
static if(__traits(compiles, data = data)) return
BitsRefSlice!D(&data, 0, D.sizeof*8);
else return BitsValSlice!D(data, 0, D.sizeof*8);
}
auto asBits(D)(D data)
=> BitsValSlice!D(data, 0, D.sizeof*8);
```
Somebody please tell me what's the best practice for this.
Oct 08








Rachel Wilson <rachel vectle.com>