voile.munion

管理された共用体を提供する
struct TypeEnum(Types...) if (Types.length > 0 && (NoDuplicates!Types.length == Types.length));
型列挙
Examples:
alias U = TypeEnum!(int, string);
U dat;
// assign
dat = 1;
dat = U("foo");
dat.initialize!int(1);

// cast
assert(cast(int)dat == 1);

// check
assert(!dat.empty);
assert(dat.check!int);
assert(!dat.check!string);
assert(dat.check!0);
assert(!dat.check!1);

// getter/setter
assert(dat.tag == 0);
assert(dat.get!int == 1);
set!int(dat, 5);
assert(dat.get!int == 5);
//	dat.set!1 = "foo";
//	assert(dat.get!1 == "foo");

// clear
dat.clear();
assert(dat.empty);

// match
dat = "foo";
assert(dat.match!(
	(int x)      => x,
	(string str) => str.length) == "foo".length);
@trusted this(T)(auto ref T val)
if(_inst.isAssignable!T);
コンストラクタ
void opAssign(T)(auto ref T val)
if(_inst.isAssignable!T);
代入
inout inout(T) opCast(T)()
if(_inst.isAssignable!T);
キャスト
const bool opEquals()(TypeEnum rhs);
等号演算子オーバーロード
const size_t toHash()();
ハッシュ
struct Tagged(U) if (is(U == union));
タグ付き共用体
Examples:
union U
{
	uint   x;
	uint   y;
	string str;
}

alias MU = Tagged!U;

MU dat;

dat.x = 10;
assert(dat.tag == 0);
assert(dat.x == 10);
assert(dat.get!0 == 10);
dat.str = "xxx";
assert(dat.get!2 == "xxx");
assert(dat.str == "xxx");
const bool opEquals()(Tagged rhs);
等号演算子オーバーロード
const size_t toHash()();
ハッシュ
ref auto opDispatch(string member)()
if(hasMember!(TaggedImpl!U.Instance, member));
void opDispatch(string member)(auto ref TaggedImpl!U.MemberType!member val)
if(hasMember!(TaggedImpl!U.Instance, member));
名前アクセス
Taggedの引数に共用体を与えた場合は名前でのアクセスを許可する。
See Also: Managed
Tagged!U tagged(U, size_t memberIndex, Args...)(auto ref Args args);
Tagged!U tagged(U, string memberName, Args...)(auto ref Args args);
Taggedの構築
Examples:
union U
{
	uint   x;
	uint   y;
}

auto dat = tagged!(U, 0)(10);
assert(dat.tag == 0);
assert(dat.x == 10);

dat = tagged!(U, "y")(20);
assert(dat.tag == 1);
assert(dat.y == 20);
struct Endata(E) if (is(E == enum));
データ付きのenum
Examples:
enum E
{
	@data!int     id,
	ignored,
	@data!string  str,
	@data!int     number,
	@data!string  get,
}
mixin EnumMemberAlieses!E;

alias EnumData = Endata!E;
EnumData dat;

// assign
dat.initialize!str("test");
dat.number = 10;

// check
assert(!dat.empty);
assert(dat.check!number);
assert(!dat.check!str);

// getter/setter
assert(dat.tag == number);
assert(.get!number(dat) == 10);
dat.set!id = 5;
assert(dat.tag == id);

// clear
dat.clear();
assert(dat.empty);

// ignored member
static assert(!__traits(compiles, dat.set!ignored(0)));
const bool opEquals()(Endata rhs);
等号演算子オーバーロード
const size_t toHash()();
ハッシュ
ref auto opDispatch(string member)()
if(hasMember!(EndataImpl!E.Instance, member));
void opDispatch(string member)(auto ref EndataImpl!E.MemberType!member val)
if(hasMember!(EndataImpl!E.Instance, member));
名前アクセス
Endata!(typeof(tag)) endata(alias tag, Args...)(auto ref Args payload);
Endataの構築
Examples:
enum E
{
	@data!int id,
	@data!int number,
}
mixin EnumMemberAlieses!E;

auto dat = endata!id(10);
assert(dat.tag == id);
assert(dat.id == 10);
template ManagedUnion(Types...) if (Types.length > 0)
引数によって実装を切り替えるManagedUnion
  • 引数が1つでunionならTaggedになる
  • 引数が1つでenumならEndataになる
  • それ以外ならTypeEnumになる
enum bool isTypeEnum(MU);
TypeEnumか判定する
enum bool isTagged(MU);
Taggedか判定する
enum bool isEndata(MU);
Endataか判定する
enum bool isManagedUnion(MU);
ManagedUnionか判定する
template TagType(MU) if (isManagedUnion!MU)
ManagedUnionのタグ型を得る
Examples:
static assert(is(TagType!(TypeEnum!(int, string)) == ubyte));
Examples:
enum E { @data!int x, @data!string str }
static assert(is(TagType!(Endata!E) == E));
template isAvailableTag(MU, alias tag) if (isManagedUnion!MU)
有効なタグか確認する
Examples:
alias MU = TypeEnum!(int, string);
static assert( isAvailableTag!(MU, 1));
static assert(!isAvailableTag!(MU, 2));
Examples:
enum E { @data!int x, @data!string str }
static assert(isAvailableTag!(Endata!E, E.x));
static assert(isAvailableTag!(Endata!E, E.str));
static assert(!isAvailableTag!(Endata!E, getNotFoundTag!(Endata!E)));
static assert(!isAvailableTag!(Endata!E, cast(E)3));
template getNotFoundTag(MU) if (isManagedUnion!MU)
無効なタグを取得する
Examples:
alias MU = TypeEnum!(int, string);
static assert(getNotFoundTag!MU != 0);
static assert(getNotFoundTag!MU != 1);
Examples:
enum E { @data!int x, @data!string str }
alias MU = Endata!E;
static assert(getNotFoundTag!MU != E.x);
static assert(getNotFoundTag!MU != E.str);
template hasType(MU, T) if (isTypeEnum!MU)
型を持っているか確認する
Examples:
alias MU = TypeEnum!(int, string);
static assert(hasType!(MU, int));
static assert(hasType!(MU, string));
static assert(!hasType!(MU, long));
template EnumMemberTypes(MU) if (isManagedUnion!MU)
持っている型を列挙する
Examples:
alias MU = TypeEnum!(int, string);
alias Types = EnumMemberTypes!MU;
static assert(is(Types[0] == int));
static assert(is(Types[1] == string));
template memberTags(MU) if (isManagedUnion!MU)
enum auto allTags(MU);
template EnumMemberTags(MU) if (isManagedUnion!MU)
タグを列挙する
Examples:
alias MU = TypeEnum!(int, string);
enum tags = memberTags!MU;
static assert(tags.length == 2);
static assert(tags[0] == 0);
static assert(tags[1] == 1);

alias MemberTags = EnumMemberTags!MU;
static assert(MemberTags.length == 2);
static assert(MemberTags[0] == 0);
static assert(MemberTags[1] == 1);
template TypeFromTag(MU, alias tag) if (isManagedUnion!MU)
タグから型を得る
Examples:
alias MU1 = TypeEnum!(int, string);
static assert(is(TypeFromTag!(MU1, 0) == int));
template isTypeAssignable(MU, T) if (isTypeEnum!MU)
型が代入可能か
TagType!MU tag(MU)(auto const ref MU dat)
if(isManagedUnion!MU);
タグを確認する
Examples:
alias MU = TypeEnum!(int, string);
MU tu;
assert(tag(tu) == getNotFoundTag!MU);
tu = 1;
assert(tag(tu) != getNotFoundTag!MU);
assert(tag(tu) == 0);
tu = "1";
assert(tag(tu) != getNotFoundTag!MU);
assert(tag(tu) == 1);
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

assert(tag(dat) == getNotFoundTag!ED);
dat.x = 1;
assert(tag(dat) != getNotFoundTag!ED);
assert(tag(dat) == x);
dat.str = "1";
assert(tag(dat) != getNotFoundTag!ED);
assert(tag(dat) == str);
void initialize(alias tag, MU, Args...)(auto ref MU dat, auto ref Args args)
if(isManagedUnion!MU && isAvailableTag!(MU, tag));
void initialize(T, MU, Args...)(auto ref MU dat, auto ref Args args)
if(isTypeEnum!MU && hasType!(MU, T));
void initialize(alias tag, MU)(auto ref MU dat)
if(isEndata!MU && !isAvailableTag!(MU, tag) && (ImplOf!MU.getIndex!tag == cast(ImplOf!MU.IndexType)ImplOf!MU.notfoundTag));
初期化する
Examples:
struct S { int x; }
alias MU = TypeEnum!(int, S);
MU dat;
initialize!0(dat, 1);
assert(get!0(dat) == 1);
initialize!1(dat, 100);
assert(get!1(dat) == S(100));
// for type
initialize!int(dat, 1000);
assert(get!0(dat) == 1000);
Examples:
import std.datetime: Date;
enum E { @data!int x, @data!Date date, test }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

initialize!x(dat, 1);
assert(get!x(dat) == 1);
initialize!date(dat, Date(2020, 8, 5));
assert(get!date(dat) == Date(2020, 8, 5));
initialize!test(dat);
assert(tag(dat) == test);
@property void set(alias tag, MU, T)(auto ref MU dat, auto ref T val)
if(isManagedUnion!MU && isAvailableTag!(MU, tag));
@property void set(T, MU)(ref MU dat, auto ref T val)
if(isTypeEnum!MU && hasType!(MU, T));
データをセットする
Examples:
struct S { int x; }
alias MU = TypeEnum!(int, S);
MU dat;
dat.set!0 = 1;
assert(get!0(dat) == 1);
set!1(dat, S(100));
assert(get!1(dat) == S(100));
// for type
dat.set!int = 10;
assert(dat.get!0 == 10);
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

dat.set!x = 1;
assert(dat.tag == x);
set!str(dat, "test");
assert(dat.tag == str);
ref auto get(alias tag, MU)(auto inout ref MU dat)
if(isManagedUnion!MU && isAvailableTag!(MU, tag));
ref auto get(T, MU)(auto inout ref MU dat)
if(isTypeEnum!MU && hasType!(MU, T));
データを取得する
Examples:
import core.exception: AssertError;
import std.exception;
alias MU = TypeEnum!(int, string);
MU tu;
(() @trusted => assertThrown!AssertError(get!0(tu) == 1) )();
set!1(tu, "test");
assert(get!1(tu) == "test");
// for type
assert(get!string(tu) == "test");
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

dat.set!x = 1;
assert(.get!x(dat) == 1);
dat.set!str = "test";
assert(dat.get!str == "test");
assert(dat.check!str);
bool check(alias tag, MU)(auto const ref MU dat)
if(isManagedUnion!MU && isAvailableTag!(MU, tag));
bool check(T, MU)(auto const ref MU dat)
if(isTypeEnum!MU && hasType!(MU, T));
データが入っていることを確認する
Examples:
alias MU = TypeEnum!(int, string);
MU tu;
assert(!tu.check!0);
assert(!tu.check!1);
tu.set!1 = "test";
assert(!tu.check!0);
assert(tu.check!1);
// for type
assert(tu.check!string);
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

dat.set!x = 1;
assert(dat.check!x);
dat.set!str = "test";
assert(dat.check!str);
void clear(MU)(auto ref MU dat)
if(isManagedUnion!MU);
データをクリアする
Examples:
alias MU = TypeEnum!(int, string);
MU tu;
assert(!tu.check!0);
assert(!tu.check!1);
tu.set!1 = "test";
assert(!tu.check!0);
assert(tu.check!1);
tu.clear();
assert(!tu.check!0);
assert(!tu.check!1);
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

dat.set!x = 1;
assert(check!x(dat));
dat.set!str = "test";
assert(check!str(dat));
bool empty(MU)(auto const ref MU dat)
if(isManagedUnion!MU);
データがクリアされているか確認する
Examples:
alias MU = TypeEnum!(int, string);
MU tu;
assert(tu.empty);
tu.set!1 = "test";
assert(!tu.empty);
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;
alias ED = Endata!E;
ED dat;

assert(dat.empty);
dat.set!x = 1;
assert(!dat.empty);
dat.set!str = "test";
assert(dat.check!str);
alias data = AttrData(T);
template hasData(alias value)
template getDatas(alias value) if (hasData!value)
union Data(alias e) if (hasData!e);
template EnumMemberAlieses(T) if (is(T == enum))
template match(Funcs...)
パターンマッチ
Examples:
import std.exception;
import std.conv: ConvException;
import voile.misc: nogcEnforce;
alias U = TypeEnum!(int, short, long);
U dat;

// マッチ関数を呼び出し
dat.set!0 = 1;
assert(dat.match!(
	(int x)  => x + 1, /* call */
	()       => 50,
	(long x) => x + 100) == 2);

// デフォルトを設定できる(empty || どれにもヒットしない)
dat.clear();
assert(dat.match!(
	(int x)  => x + 1,
	()       => 50, /* call */
	(long x) => x + 100) == 50);
// 例外をキャッチできる
dat = cast(long)5;
assert(dat.match!(
	(Exception e) => 100, /* call 2 */
	other         => 50,
	(long x)      => nogcEnforce(0)/* call 1 */) == 100);
Examples:
enum E { @data!int x, @data!string str }
mixin EnumMemberAlieses!E;

alias ED = Endata!E;
ED dat;

// マッチ関数を呼び出し 引数に Data!tag を指定することでマッチ対象指定
dat.x = 100;
assert(dat.match!(
	(Data!x x) => x + 11 /* call */,
	()          => 10) == 111);
// マッチ関数を呼び出し 引数に @tag を指定することでマッチ対象指定
dat.str = "test";
assert(dat.match!(
	(@str x) => (cast(string)x).length + 11,
	other    => 10) == 4 + 11);