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