mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +03:00
Add the capability to create tagged pointer and classes in bitmanip
This commit is contained in:
parent
ea52f8eeff
commit
182548e4da
1 changed files with 165 additions and 0 deletions
165
std/bitmanip.d
165
std/bitmanip.d
|
@ -14,6 +14,7 @@ Authors: $(WEB digitalmars.com, Walter Bright),
|
||||||
Jonathan M Davis,
|
Jonathan M Davis,
|
||||||
Alex Rønne Petersen,
|
Alex Rønne Petersen,
|
||||||
Damian Ziemba
|
Damian Ziemba
|
||||||
|
Amaury SECHET
|
||||||
Source: $(PHOBOSSRC std/_bitmanip.d)
|
Source: $(PHOBOSSRC std/_bitmanip.d)
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
|
@ -159,6 +160,50 @@ private template createFields(string store, size_t offset, Ts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ulong getBitsForAlign(ulong a)
|
||||||
|
{
|
||||||
|
ulong bits = 0;
|
||||||
|
while ((a & 0x01) == 0)
|
||||||
|
{
|
||||||
|
bits++;
|
||||||
|
a >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(a == 1, "alignment is not a power of 2");
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private template createReferenceAccessor(string store, T, ulong bits, string name)
|
||||||
|
{
|
||||||
|
enum mask = (1UL << bits) - 1;
|
||||||
|
// getter
|
||||||
|
enum result = "@property "~T.stringof~" "~name~"() @trusted pure nothrow @nogc const { auto result = "
|
||||||
|
~ "("~store~" & "~myToString(~mask)~");"
|
||||||
|
~ " return cast("~T.stringof~") cast(void*) result;}\n"
|
||||||
|
// setter
|
||||||
|
~"@property void "~name~"("~T.stringof~" v) @trusted pure nothrow @nogc { "
|
||||||
|
~"assert(((cast(typeof("~store~")) cast(void*) v) & "~myToString(mask)~`) == 0, "Value not properly aligned for '`~name~`'"); `
|
||||||
|
~store~" = cast(typeof("~store~"))"
|
||||||
|
~" (("~store~" & (cast(typeof("~store~")) "~myToString(mask)~"))"
|
||||||
|
~" | ((cast(typeof("~store~")) cast(void*) v) & (cast(typeof("~store~")) "~myToString(~mask)~")));}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private template sizeOfBitField(T...)
|
||||||
|
{
|
||||||
|
static if(T.length < 2)
|
||||||
|
enum sizeOfBitField = 0;
|
||||||
|
else
|
||||||
|
enum sizeOfBitField = T[2] + sizeOfBitField!(T[3 .. $]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private template createTaggedReference(string store, T, ulong a, string name, Ts...)
|
||||||
|
{
|
||||||
|
static assert(sizeOfBitField!Ts <= getBitsForAlign(a), "Fields must fit in the bits know to be zero because of alignment.");
|
||||||
|
enum result
|
||||||
|
= createReferenceAccessor!(store, T, sizeOfBitField!Ts, name).result
|
||||||
|
~ createFields!(store, 0, Ts, size_t, "", T.sizeof * 8 - sizeOfBitField!Ts).result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Allows creating bit fields inside $(D_PARAM struct)s and $(D_PARAM
|
Allows creating bit fields inside $(D_PARAM struct)s and $(D_PARAM
|
||||||
class)es.
|
class)es.
|
||||||
|
@ -211,6 +256,73 @@ template bitfields(T...)
|
||||||
enum { bitfields = createFields!(createStoreName!(T), 0, T).result }
|
enum { bitfields = createFields!(createStoreName!(T), 0, T).result }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This string mixin generator allows one to create tagged pointers inside $(D_PARAM struct)s and $(D_PARAM class)es.
|
||||||
|
|
||||||
|
A tagged pointer uses the bits known to be zero in a normal pointer or class reference to store extra information.
|
||||||
|
For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero.
|
||||||
|
One can store a 2-bit integer there.
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
----
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
mixin(taggedPointer!(
|
||||||
|
uint*, "x",
|
||||||
|
bool, "b1", 1,
|
||||||
|
bool, "b2", 1));
|
||||||
|
}
|
||||||
|
A obj;
|
||||||
|
obj.x = new int;
|
||||||
|
obj.b1 = true;
|
||||||
|
obj.b2 = false;
|
||||||
|
----
|
||||||
|
|
||||||
|
The example above creates a tagged pointer in the struct A. The pointer is of type
|
||||||
|
$(D uint*) as specified by the first argument, and is named x, as specified by the second
|
||||||
|
argument.
|
||||||
|
|
||||||
|
Following arguments works the same way as $(D bitfield)'s. The bitfield must fit into the
|
||||||
|
bits known to be zero because of the pointer alignement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template taggedPointer(T : T*, string name, Ts...) {
|
||||||
|
enum taggedPointer = createTaggedReference!(createStoreName!(T, name, 0, Ts), T*, T.alignof, name, Ts).result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This string mixin generator allows one to create tagged class reference inside $(D_PARAM struct)s and $(D_PARAM class)es.
|
||||||
|
|
||||||
|
A tagged class reference uses the bits known to be zero in a normal class reference to store extra information.
|
||||||
|
For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero.
|
||||||
|
One can store a 2-bit integer there.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
----
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
mixin(taggedClassRef!(
|
||||||
|
Object, "o",
|
||||||
|
uint, "i", 2));
|
||||||
|
}
|
||||||
|
A obj;
|
||||||
|
obj.o = new Object();
|
||||||
|
obj.i = 3;
|
||||||
|
----
|
||||||
|
|
||||||
|
The example above creates a tagged reference to an Object in the struct A. This expects the same parameters
|
||||||
|
as $(D taggedPointer), except the first argument which must be a class type instead of a pointer type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template taggedClassRef(T, string name, Ts...) if(is(T == class)) {
|
||||||
|
enum taggedClassRef = createTaggedReference!(createStoreName!(T, name, 0, Ts), T, 8, name, Ts).result;
|
||||||
|
}
|
||||||
|
|
||||||
@safe pure nothrow @nogc
|
@safe pure nothrow @nogc
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
|
@ -278,6 +390,59 @@ unittest
|
||||||
t4b.a = -5; assert(t4b.a == -5L);
|
t4b.a = -5; assert(t4b.a == -5L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
struct Test5
|
||||||
|
{
|
||||||
|
mixin(taggedPointer!(
|
||||||
|
int*, "a",
|
||||||
|
uint, "b", 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
Test5 t5;
|
||||||
|
t5.a = null;
|
||||||
|
t5.b = 3;
|
||||||
|
assert(t5.a is null);
|
||||||
|
assert(t5.b == 3);
|
||||||
|
|
||||||
|
int myint = 42;
|
||||||
|
t5.a = &myint;
|
||||||
|
assert(t5.a is &myint);
|
||||||
|
assert(t5.b == 3);
|
||||||
|
|
||||||
|
struct Test6
|
||||||
|
{
|
||||||
|
mixin(taggedClassRef!(
|
||||||
|
Object, "o",
|
||||||
|
bool, "b", 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Test6 t6;
|
||||||
|
t6.o = null;
|
||||||
|
t6.b = false;
|
||||||
|
assert(t6.o is null);
|
||||||
|
assert(t6.b == false);
|
||||||
|
|
||||||
|
auto o = new Object();
|
||||||
|
t6.o = o;
|
||||||
|
t6.b = true;
|
||||||
|
assert(t6.o is o);
|
||||||
|
assert(t6.b == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
static assert(!__traits(compiles,
|
||||||
|
taggedPointer!(
|
||||||
|
int*, "a",
|
||||||
|
uint, "b", 3)));
|
||||||
|
|
||||||
|
static assert(!__traits(compiles,
|
||||||
|
taggedClassRef!(
|
||||||
|
Object, "a",
|
||||||
|
uint, "b", 4)));
|
||||||
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
// Bug #6686
|
// Bug #6686
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue