1 module easyd.base;
2 
3 // (C) 2014-2018 by Matthias Rossmy
4 // This file is distributed under the "Fair Use License v2"
5 
6 import std.stdio;
7 import std.traits;
8 import std.typecons;
9 import std.math;
10 import std.conv;
11 import std.datetime;
12 import core.time;
13 import core.thread;
14 import core.memory;
15 
16 // aliases to allow writing types consistently in Pascal casing ////////
17 
18 alias byte Int8;
19 alias ubyte UInt8;
20 alias UInt8 Byte;
21 alias short Int16;
22 alias ushort UInt16;
23 alias int Int32;
24 alias uint UInt32;
25 alias long Int64;
26 alias ulong UInt64;
27 
28 alias Int32 Int;
29 alias ptrdiff_t NInt; //native int
30 alias size_t NUInt;
31 
32 alias float Float32;
33 alias double Float64;
34 alias real Real;
35 
36 alias Float32 Float;
37 
38 alias bool Bool;
39 alias string Str;
40 
41 ////////////////////////////////////////////////////////////////////////
42 
43 const int MEBI = 1024*1024;
44 
45 unittest
46 {
47 	static class StringArray
48 	{
49 		string[] data;
50 		void delegate(string)[] itemAdded;
51 		
52 		void add(string s)
53 		{
54 			data ~= s;
55 			itemAdded.trigger(s);
56 		}
57 	}
58 	
59 	static class MyComponent
60 	{
61 		StringArray sa;
62 		int callCount = 0;
63 		
64 		this()
65 		{
66 			sa.create; //equivalent to sa = new StringArray; but create avoids repeating the type (especially useful with templates)
67 			sa.itemAdded ~= &itemAddedHandler;
68 		}
69 
70 		void itemAddedHandler(string s)
71 		{
72 			callCount++;
73 		}
74 	}
75 	
76 	auto mc = new MyComponent;
77 	mc.sa.add("Test");
78 	assert(mc.callCount==1);
79 }
80 
81 // language extensions /////////////////////////////////////////////////
82 
83 void pinAddr(T)(T obj)
84 {
85 	GC.addRoot(cast(void*)obj);
86 	GC.setAttr(cast(void*)obj, GC.BlkAttr.NO_MOVE);
87 }
88 
89 void unpinAddr(T)(T obj)
90 {
91 	GC.clrAttr(cast(void*)obj, GC.BlkAttr.NO_MOVE);
92 	GC.removeRoot(cast(void*)obj);
93 }
94 
95 T create(T,P...)(ref T obj,P par)
96     if(is(T==class))
97 {
98     if(obj is null)
99     {
100         obj = new T(par);
101     }
102     return obj;
103 }
104 
105 T recreate(T,P...)(ref T obj,P par)
106 	if(is(T==class))
107 {
108 	obj = new T(par);
109 	return obj;
110 }
111 
112 bool Try(lazy void expression)
113 {
114     try
115     {
116         expression;
117         return true;
118     }
119     catch(Exception e)
120     {
121         return false;
122     }
123 }
124 
125 // type tools //////////////////////////////////////////////////////////
126 
127 bool isRefType(T)()
128 {
129 	T obj;
130 	return __traits(compiles, obj=null);
131 }
132 
133 //bool inherits(TCheck,TObj)(const TObj obj)
134 bool inherits(TCheck,TObj)(TObj obj) //work around for the mutable ObjectG.opCast of gtk-d, which should not be mutable of course
135 {
136 	return cast(const TCheck)(obj) !is null;
137 }
138 
139 bool hasDefaultConstructor(T)()
140 {
141 	return __traits(compiles, (new T));
142 }
143 
144 bool isClassOrStruct(T)()
145 {
146 	return __traits(hasMember, T, "tupleof");
147 }
148 
149 // array tools /////////////////////////////////////////////////////////
150 
151 T first(T)(T[] array)
152 {
153 	return array[0];
154 }
155 
156 T last(T)(T[] array)
157 {
158 	return array[array.length-1];
159 }
160 
161 T readFromPos(T)(Byte[] a, ulong pos)
162 	if(isBasicType!T)
163 {
164 	return *(cast(T*)(&(a[pos])));
165 }
166 
167 void writeToPos(T)(Byte[] a, ulong pos, T value)
168 	if(isBasicType!T)
169 {
170 	*(cast(Unqual!T*)(&(a[pos]))) = value;
171 }
172 
173 // trigger events //////////////////////////////////////////////////////
174 
175 void trigger(void delegate()[] listeners)
176 {
177 	foreach ( void delegate() func ; listeners )
178 	{
179 		func();
180 	}
181 }
182 
183 void trigger(T)(void delegate(T)[] listeners, T data)
184 {
185 	foreach ( void delegate(T) func ; listeners )
186 	{
187 		func(data);
188 	}
189 }
190 
191 void trigger(T,T2)(void delegate(T,T2)[] listeners, T data, T2 data2)
192 {
193 	foreach ( void delegate(T,T2) func ; listeners )
194 	{
195 		func(data,data2);
196 	}
197 }
198 
199 // misc ////////////////////////////////////////////////////////////////
200 
201 long ifloor(T)(T x)
202 {
203     return floor(x).to!long;
204 }
205 
206 ulong toHash(T)(T x)
207 {
208 	return typeid(x).getHash(&x);
209 }
210 
211 void followUp(T)(ref T follower, T master)
212 {
213 	static if(isFloatingPoint!T)
214 	{
215 		if(isNaN(master)) return;
216 	}
217 	if(master>follower) follower=master;
218 }
219 
220 void followDown(T)(ref T follower, T master)
221 {
222 	static if(isFloatingPoint!T)
223 	{
224 		if(isNaN(master)) return;
225 	}
226 	if(master<follower) follower=master;
227 }
228 
229 T weightedAvg(T)(T weight1, T x1, T x2)
230 {
231 	return weight1*x1 + (1-weight1)*x2;
232 }
233 
234 struct IdField {}
235 
236 string idField(T)()
237 {
238 	static if(isAggregateType!T && !isTuple!T)
239 	{
240 		foreach (member; __traits(allMembers, T))
241 		{
242 			static if(__traits(compiles, hasUDA!(__traits(getMember, T, member), IdField)))
243 			{
244 				if (hasUDA!(__traits(getMember, T, member),	IdField)) return member;
245 			}
246 		}
247 	}
248 	return "";
249 }
250 
251 bool setMember(TObj,TMem)(TObj obj, string member, TMem value)
252 {
253     bool result = false;
254     static if(is(TObj:Object))
255     {
256         foreach(t; BaseClassesTuple!TObj)
257         {
258             result = setMemberHelper(cast(t)(obj),member,value) || result;
259         }
260     }
261     return setMemberHelper(obj,member,value) || result;
262 }
263 
264 private bool setMemberHelper(TObj,TMem)(TObj obj, string member, ref TMem value)
265 {
266     bool result = false;
267     static if(__traits(hasMember, TObj, "tupleof"))
268     {
269         foreach (i,m; obj.tupleof)
270         {
271             if(__traits(identifier, obj.tupleof[i]) == member)
272             {
273                 static if(is(typeof(value):typeof(m)))
274                 {
275                     obj.tupleof[i] = value;
276                     result = true;
277                 }
278             }
279         }
280     }
281     return result;
282 }
283 
284 ulong getMsec()
285 {
286 	return TickDuration.currSystemTick.msecs;
287 }
288 
289 ulong msecSince(long refTime)
290 {
291 	return TickDuration.currSystemTick.msecs - refTime;
292 }
293 
294 void sleepMsec(uint duration)
295 {
296 	if(duration==0)
297 	{
298 		core.thread.Thread.yield;
299 	}else{
300 		core.thread.Thread.sleep( dur!("msecs")( duration ) );
301 	}
302 }
303 
304 DateTime now()
305 {
306 	return cast(DateTime)Clock.currTime;
307 }
308 
309 mixin template ImplementStruct(T)
310 {
311 	T ptr;
312 
313     this(TPar...)(TPar par)
314     {
315         ptr = new T(par);
316     }
317 
318     T reference()
319     {
320 		static if(hasDefaultConstructor!T)
321 		{
322 			return ptr.create;
323 		}
324 		else
325 		{
326 			return ptr;
327 		}
328     }
329     alias reference this;
330 
331     static if(__traits(hasMember, T, "dup"))
332     {
333         this(this)
334         {
335 			//writeln("Struct-Copy...");
336             if(ptr !is null) ptr = ptr.dup;
337 			//writeln("Struct-Copy ok");
338 		}
339     }
340     else
341     {
342         @disable this(this);
343 	}
344 
345 	/*static if(hasDefaultConstructor!T && !__traits(hasMember, T, "_do_not_serialize_"))
346 	{
347 		static if(is(T:ISpecialSerialize))
348 		{
349 			void serialize(ISerializer destination) 
350 			{
351 				if(ptr !is null) ptr.serialize(destination);
352 			}
353 			
354 			bool deserialize(IDeserializer source)
355 			{
356 				ptr.create;
357 				return ptr.deserialize(source);
358 			}
359 		}
360 		else
361 		{
362 			void serialize(ISerializer destination) 
363 			{
364 				if(ptr !is null) destination.serializeFields(ptr);
365 			}
366 			
367 			bool deserialize(IDeserializer source)
368 			{
369 				ptr.create;
370 				while(!source.isEndOfSection)
371 				{
372 					source.getItem;
373 					source.fillObjectMember(ptr,source.currentName);
374 				}
375 				return true;
376 			}
377 		}
378 	}*/
379 }