1 module memutils.helpers;
2 public:
3 
4 template UnConst(T) {
5 	static if (is(T U == const(U))) {
6 		alias UnConst = U;
7 	} else static if (is(T V == immutable(V))) {
8 		alias UnConst = V;
9 	} else alias UnConst = T;
10 }
11 
12 /// TODO: Imitate Unique! for all objects (assume dtor) with release()
13 /// TODO: implement @override on underlying type T, and check for shadowed members.
14 mixin template Embed(alias OBJ, alias OWNED)
15 {
16 	import std.traits : hasMember;
17 	alias TR = typeof(OBJ);
18 	static if (is(typeof(*OBJ) == struct))
19 			alias T = typeof(*OBJ);
20 	else
21 		alias T = TR;
22 
23 	import std.traits : isSomeFunction;
24 	static if (!isSomeFunction!OBJ)
25 	@property ref const(T) fallthrough() const
26 	{
27 		static if (__traits(hasMember, typeof(this), "defaultInit")) {
28 			(cast(typeof(this)*)&this).defaultInit();
29 			checkInvariants();
30 		}
31 		static if (is(TR == T*)) return *OBJ;
32 		else return OBJ;
33 	}
34 
35 	@property ref T fallthrough()
36 	{
37 		static if (__traits(hasMember, typeof(this), "defaultInit")) {
38 			defaultInit();
39 			checkInvariants();
40 		}
41 		static if (is(TR == T*)) return *OBJ;
42 		else return OBJ;
43 	}
44 	
45 	@property ref const(T) opUnary(string op)() const if (op == "*")
46 	{
47 		return (cast(typeof(this)*)&this).fallthrough;
48 	}
49 	
50 	
51 	alias fallthrough this;
52 	
53 	static if (!isSomeFunction!OBJ)
54 	@property TR release() {
55 		static if (__traits(hasMember, typeof(this), "defaultInit")) {
56 			defaultInit();
57 			checkInvariants();
58 		}
59 		TR ret = OBJ;
60 		OBJ = null;
61 		return ret;
62 	}
63 
64 	auto opBinaryRight(string op, Key)(Key key)
65 	inout if (op == "in" && __traits(hasMember, typeof(OBJ), "opBinaryRight")) {
66 		defaultInit();
67 		return fallthrough().opBinaryRight!("in")(key);
68 	}
69 
70 	bool opEquals(U)(auto ref U other) const
71 	{
72 		defaultInit();
73 		return fallthrough().opEquals(other);
74 	}
75 	
76 	int opCmp(U)(auto ref U other) const
77 	{
78 		defaultInit();
79 		return fallthrough().opCmp(other);
80 	}
81 	
82 	int opApply(U...)(U args)
83 		if (__traits(hasMember, typeof(OBJ), "opApply"))
84 	{
85 		defaultInit();
86 		return fallthrough().opApply(args);
87 	}
88 	
89 	int opApply(U...)(U args) const
90 		if (__traits(hasMember, typeof(OBJ), "opApply"))
91 	{
92 		defaultInit();
93 		return fallthrough().opApply(args);
94 	}
95 	
96 	void opSliceAssign(U...)(U args)
97 		if (__traits(hasMember, typeof(OBJ), "opSliceAssign"))
98 	{
99 		defaultInit();
100 		fallthrough().opSliceAssign(args);
101 	}
102 
103 	
104 	auto opSlice(U...)(U args) const
105 		if (__traits(hasMember, typeof(OBJ), "opSlice"))
106 	{
107 		defaultInit();
108 		return (cast()fallthrough()).opSlice(args);
109 		
110 	}
111 
112 	static if (__traits(hasMember, typeof(OBJ), "opDollar"))
113 	size_t opDollar() const
114 	{
115 		return fallthrough().opDollar();
116 	}
117 	
118 	void opOpAssign(string op, U...)(auto ref U args)
119 		if (__traits(compiles, fallthrough().opOpAssign!op(args)))
120 	{
121 		defaultInit();
122 		fallthrough().opOpAssign!op(args);
123 	}
124 	
125 	auto opBinary(string op, U...)(auto ref U args)
126 		if (__traits(compiles, fallthrough().opBinary!op(args)))
127 	{
128 		defaultInit();
129 		return fallthrough().opBinary!op(args);
130 	}
131 	
132 	void opIndexAssign(U, V)(auto const ref U arg1, auto const ref V arg2)
133 		if (__traits(hasMember, typeof(fallthrough()), "opIndexAssign"))
134 	{		
135 		defaultInit();
136 		fallthrough().opIndexAssign(arg1, arg2);
137 	}
138 	
139 	auto ref opIndex(U...)(U args) inout
140 		if (__traits(hasMember, typeof(fallthrough()), "opIndex"))
141 	{
142 		return fallthrough().opIndex(args);
143 	}
144 	
145 	static if (__traits(compiles, fallthrough().opBinaryRight!("in")(ReturnType!(fallthrough().front).init)))
146 		bool opBinaryRight(string op, U)(auto ref U e) const if (op == "in") 
147 	{
148 		defaultInit();
149 		return fallthrough().opBinaryRight!("in")(e);
150 	}
151 }