www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to separarte lvalue parameter from rvalue?

reply realhet <real_het hotmail.com> writes:
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
parent reply realhet <real_het hotmail.com> writes:
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
parent Rachel Wilson <rachel vectle.com> writes:
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