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)
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 
23 	static if (!__traits(hasMember, typeof(this), "defaultInit")) {
24 		void defaultInit() const {}
25 	}
26 	static if (!__traits(hasMember, typeof(this), "checkInvariants")) {
27 		void checkInvariants() const {}
28 	}
29 	@property ref const(T) opStar() const
30 	{
31 		(cast(typeof(this)*)&this).defaultInit();
32 		checkInvariants();
33 		static if (is(TR == T*)) return *OBJ;
34 		else return OBJ;
35 	}
36 	
37 	@property ref T opStar() {
38 		defaultInit();
39 		checkInvariants();
40 		static if (is(TR == T*)) return *OBJ;
41 		else return OBJ;
42 	}
43 	
44 	alias opStar this;
45 	
46 	auto opBinaryRight(string op, Key)(Key key)
47 	inout if (op == "in" && __traits(hasMember, typeof(OBJ), "opBinaryRight")) {
48 		defaultInit();
49 		return opStar().opBinaryRight!("in")(key);
50 	}
51 
52 	bool opEquals(U)(auto ref U other) const
53 	{
54 		defaultInit();
55 		return opStar().opEquals(other);
56 	}
57 	
58 	int opCmp(U)(auto ref U other) const
59 	{
60 		defaultInit();
61 		return opStar().opCmp(other);
62 	}
63 	
64 	int opApply(U...)(U args)
65 		if (__traits(hasMember, typeof(OBJ), "opApply"))
66 	{
67 		defaultInit();
68 		return opStar().opApply(args);
69 	}
70 	
71 	int opApply(U...)(U args) const
72 		if (__traits(hasMember, typeof(OBJ), "opApply"))
73 	{
74 		defaultInit();
75 		return opStar().opApply(args);
76 	}
77 	
78 	void opSliceAssign(U...)(U args)
79 		if (__traits(hasMember, typeof(OBJ), "opSliceAssign"))
80 	{
81 		defaultInit();
82 		opStar().opSliceAssign(args);
83 	}
84 
85 	
86 	auto opSlice(U...)(U args) const
87 		if (__traits(hasMember, typeof(OBJ), "opSlice"))
88 	{
89 		defaultInit();
90 		static if (is(U == void))
91 			return opStar().opSlice();
92 		else
93 			return opStar().opSlice(args);
94 		
95 	}
96 
97 	static if (__traits(hasMember, typeof(OBJ), "opDollar"))
98 	size_t opDollar() const
99 	{
100 		return opStar().opDollar();
101 	}
102 	
103 	void opOpAssign(string op, U...)(auto ref U args)
104 		if (__traits(compiles, opStar().opOpAssign!op(args)))
105 	{
106 		defaultInit();
107 		opStar().opOpAssign!op(args);
108 	}
109 	
110 	auto opBinary(string op, U...)(auto ref U args)
111 		if (__traits(compiles, opStar().opBinary!op(args)))
112 	{
113 		defaultInit();
114 		return opStar().opBinary!op(args);
115 	}
116 	
117 	void opIndexAssign(U, V)(auto const ref U arg1, auto const ref V arg2)
118 		if (__traits(hasMember, typeof(opStar()), "opIndexAssign"))
119 	{		
120 		defaultInit();
121 		opStar().opIndexAssign(arg1, arg2);
122 	}
123 	
124 	auto ref opIndex(U...)(U args) inout
125 		if (__traits(hasMember, typeof(opStar()), "opIndex"))
126 	{
127 		return opStar().opIndex(args);
128 	}
129 	
130 	static if (__traits(compiles, opStar().opBinaryRight!("in")(ReturnType!(opStar().front).init)))
131 		bool opBinaryRight(string op, U)(auto ref U e) const if (op == "in") 
132 	{
133 		defaultInit();
134 		return opStar().opBinaryRight!("in")(e);
135 	}
136 }