From d220c9430a8d1e3e3849349141740b16738cc029 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Thu, 15 Jun 2017 21:55:23 -0600 Subject: [PATCH] Added bitfield support for std.typecons.Flag and other boolean variant types. --- changelog/std-bitmanip-flags.dd | 41 ++++++++++++++ std/bitmanip.d | 95 +++++++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 changelog/std-bitmanip-flags.dd diff --git a/changelog/std-bitmanip-flags.dd b/changelog/std-bitmanip-flags.dd new file mode 100644 index 00000000000..146f80a17ef --- /dev/null +++ b/changelog/std-bitmanip-flags.dd @@ -0,0 +1,41 @@ +Added support in the std.bitmanip.bitfields function for std.typecons.Flag and other user-defined types that inherit from bool. + +This change allows more types to be used in the $(REF bitfields,std,bitmanip) function, for example: +------ +import std.bitmanip, std.typecons; + +enum CustomFlag1 : bool +{ + first = false, second = true +} +alias CustomFlag2 = Flag!"CustomFlag2"; +template CustomFlag3(string name) +{ + enum CustomFlag3 : bool + { + false_ = false, + true_ = true, + } +} +struct Test +{ + mixin(bitfields!( + Flag!"a", "a", 1, + CustomFlag1, "b", 1, + CustomFlag2, "c", 1, + CustomFlag3!"something", "d", 1, + ubyte, "", 4)); +} +void main() +{ + Test t; + t.a = Yes.a; + t.b = CustomFlag1.second; + t.c = Yes.CustomFlag2; + t.d = CustomFlag3!"something".true_; + assert(t.a == Yes.a); + assert(t.b == CustomFlag1.second); + assert(t.c == Yes.CustomFlag2); + assert(t.c == CustomFlag3!"something".true_); +} +------ diff --git a/std/bitmanip.d b/std/bitmanip.d index c38a2a8cec4..662599ac82a 100644 --- a/std/bitmanip.d +++ b/std/bitmanip.d @@ -61,6 +61,7 @@ import std.traits; version(unittest) { import std.stdio; + import std.typecons : Flag, Yes, No; } @@ -72,6 +73,18 @@ private string myToString(ulong n) return cast(string) s ~ (n > uint.max ? "UL" : "U"); } +private template TypeName(T) +{ + static if (__traits(compiles, TemplateOf!T)) + { + enum TypeName = T.stringof ~ "!" ~ TemplateArgsOf!T.stringof[5..$]; + } + else + { + enum TypeName = T.stringof; + } +} + private template createAccessors( string store, T, string name, size_t len, size_t offset) { @@ -105,15 +118,15 @@ private template createAccessors( enum extendSign = 0; } - static if (is(T == bool)) + static if (is(T : bool)) { static assert(len == 1); enum result = // getter - "@property bool " ~ name ~ "() @safe pure nothrow @nogc const { return " - ~"("~store~" & "~myToString(maskAllElse)~") != 0;}\n" + "@property " ~ TypeName!T ~ " " ~ name ~ "() @safe pure nothrow @nogc const { return " + ~"cast(" ~ TypeName!T ~ ")(("~store~" & "~myToString(maskAllElse)~") != 0);}\n" // setter - ~"@property void " ~ name ~ "(bool v) @safe pure nothrow @nogc { " + ~"@property void " ~ name ~ "(" ~ TypeName!T ~ " v) @safe pure nothrow @nogc { " ~"if (v) "~store~" |= "~myToString(maskAllElse)~";" ~"else "~store~" &= ~cast(typeof("~store~"))"~myToString(maskAllElse)~";}\n"; } @@ -553,6 +566,80 @@ unittest test(); } +@safe unittest +{ + enum CustomFlag1 : bool + { + first = false, second = true + } + alias CustomFlag2 = Flag!"CustomFlag2"; + template CustomFlag3(string name) + { + enum CustomFlag3 : bool + { + false_ = false, + true_ = true, + } + } + struct Test + { + mixin(bitfields!( + Flag!"a", "a", 1, + CustomFlag1, "b", 1, + CustomFlag2, "c", 1, + CustomFlag3!"something", "d", 1, + ubyte, "", 4)); + } + Test t; + + Flag!"a" a; + CustomFlag1 b; + CustomFlag2 c; + CustomFlag3!"something" d; + + void check() + { + assert(a == t.a); + assert(b == t.b); + assert(c == t.c); + assert(d == t.d); + } + + check(); + + a = Yes.a; + t.a = a; + check(); + + b = CustomFlag1.second; + t.b = b; + check(); + + c = Yes.CustomFlag2; + t.c = c; + check(); + + d = CustomFlag3!"something".true_; + t.d = d; + check(); + + a = No.a; + t.a = a; + check(); + + b = CustomFlag1.first; + t.b = b; + check(); + + c = No.CustomFlag2; + t.c = c; + check(); + + d = CustomFlag3!"something".false_; + t.d = d; + check(); +} + @safe unittest { {