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 }