mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 14:40:30 +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,
|
||||
Alex Rønne Petersen,
|
||||
Damian Ziemba
|
||||
Amaury SECHET
|
||||
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
|
||||
class)es.
|
||||
|
@ -211,6 +256,73 @@ template bitfields(T...)
|
|||
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
|
||||
unittest
|
||||
{
|
||||
|
@ -278,6 +390,59 @@ unittest
|
|||
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
|
||||
{
|
||||
// Bug #6686
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue