1 #!/usr/bin/env rdmd-dev-module 2 3 /** Generate Randomized Instances. 4 5 Copyright: Per Nordlöw 2014-. 6 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 7 Authors: $(WEB Per Nordlöw) 8 9 See also: http://forum.dlang.org/thread/byonwfghdqgcirdjyboh@forum.dlang.org 10 11 TODO Can these be tagged with @nogc? Currently std.random.uniform may allocate. 12 TODO Tags as nothrow when std.random gets there. 13 TODO How to handle possibly null reference (class, dynamic types) types? 14 Answer relates to how to randomize empty/null variable length structures 15 (arrays, strings, etc). 16 - Maybe some kind of length randomization? 17 */ 18 module random_ex; 19 20 import std.traits: isIntegral, isFloatingPoint, isNumeric, isIterable, isStaticArray, isArray, hasIndirections, isSomeString, isScalarType; 21 import std.range: isInputRange, ElementType, hasAssignableElements, isBoolean; 22 import std.random: uniform; 23 24 version(unittest) private enum testLength = 64; 25 26 /** Randomize Contents of $(D x). */ 27 auto ref randInPlace(E)(ref E x) @trusted 28 if (isBoolean!E) 29 { 30 return x = cast(bool)uniform(0, 2); 31 } 32 33 /** Randomize Contents of $(D x), optionally in range [$(D low), $(D high)]. */ 34 auto ref randInPlace(E)(ref E x, 35 E low = E.min, 36 E high = E.max) @trusted 37 if (isIntegral!E) 38 { 39 return x = uniform(low, high); // BUG: Never assigns the value E.max 40 } 41 42 /** Randomize Contents of $(D x), optional in range [$(D low), $(D high)]. */ 43 auto ref randInPlace(E)(ref E x, 44 E low = 0 /* E.min_normal */, 45 E high = 1 /* E.max */) @trusted 46 if (isFloatingPoint!E) 47 { 48 return x = uniform(low, high); 49 } 50 51 version(unittest) 52 { 53 import rational: Rational, rational; 54 } 55 56 /** Randomize Contents of $(D x). */ 57 auto ref randInPlace(Rational, E)(ref Rational!E x) @trusted 58 if (isIntegral!E) 59 { 60 return x = rational(uniform(E.min, E.max), 61 uniform(1, E.max)); 62 } 63 64 unittest 65 { 66 Rational!int x; 67 x.randInPlace; 68 } 69 70 /** Generate Random Contents of $(D x). 71 See also: http://forum.dlang.org/thread/emlgflxpgecxsqweauhc@forum.dlang.org 72 */ 73 auto ref randInPlace(ref dchar x) @trusted 74 { 75 auto ui = uniform(0, 76 0xD800 + 77 (0x110000 - 0xE000) - 2 // minus two for U+FFFE and U+FFFF 78 ); 79 if (ui < 0xD800) 80 { 81 return x = ui; 82 } 83 else 84 { 85 ui -= 0xD800; 86 ui += 0xE000; 87 88 // skip undefined 89 if (ui < 0xFFFE) 90 return x = ui; 91 else 92 ui += 2; 93 94 assert(ui < 0x110000); 95 return x = ui; 96 } 97 } 98 99 unittest 100 { 101 auto x = randomized!dchar; 102 dstring d = "alphaalphaalphaalphaalphaalphaalphaalphaalphaalpha"; 103 auto r = d.randomize; // TODO Use Phobos function to check if string is legally coded. 104 } 105 106 /** Randomize Contents of $(D x). */ 107 auto ref randInPlace(dstring x) @trusted 108 { 109 dstring y; 110 foreach (ix; 0 .. x.length) 111 y ~= randomized!dchar; // TODO How to do this in a better way? 112 x = y; 113 return y; 114 } 115 116 /** Randomize Contents of $(D x). 117 */ 118 auto ref randInPlace(R)(R x) 119 if (hasAssignableElements!R) 120 { 121 foreach (ref e; x) 122 { 123 e.randInPlace; 124 } 125 return x; 126 } 127 128 unittest 129 { 130 void testDynamic(T)() 131 { 132 auto x = new T[testLength]; 133 auto y = x.dup; 134 x.randInPlace; 135 y.randInPlace; 136 assert(y != x); 137 } 138 testDynamic!bool; 139 testDynamic!int; 140 testDynamic!float; 141 } 142 143 /** Randomize Contents of $(D x). 144 */ 145 auto ref randInPlace(T)(ref T x) @trusted 146 if (isStaticArray!T) 147 { 148 foreach (ref e; x) 149 { 150 e.randInPlace; 151 } 152 return x; 153 } 154 155 unittest 156 { 157 void testStatic(T)() 158 { 159 T[testLength] x; 160 auto y = x; 161 x.randInPlace; 162 y.randInPlace; 163 assert(y != x); 164 } 165 testStatic!bool; 166 testStatic!int; 167 testStatic!real; 168 enum E { a, b, c, d, e, f, g, h, 169 i, j, k, l, m, n, o, p } 170 testStatic!E; 171 } 172 173 /** Blockwise Randomize Contents of $(D x) of Array Type $(D A). 174 Randomizes in array blocks of type $(D B). 175 */ 176 auto ref randInPlaceBlockwise(B = size_t, A)(ref A x) @trusted 177 if (isArray!A && 178 isIntegral!(ElementType!A)) 179 { 180 alias E = ElementType!A; 181 static assert(E.sizeof < B.sizeof); 182 enum mult = B.sizeof / E.sizeof; // block multiplicity 183 184 immutable n = x.length; 185 186 // beginning unaligned bytes 187 auto p = cast(size_t)x.ptr; 188 immutable size_t mask = B.sizeof - 1; 189 immutable r = (p & mask) / E.sizeof; // element-offset from B-aligned address before x 190 size_t k = 0; // E-index to first B-block 191 if (r) 192 { 193 import std.algorithm: min; 194 k = min(n, mult - r); // at first aligned B-block 195 foreach (i, ref e; x[0 .. k]) 196 { 197 e.randInPlace; 198 } 199 } 200 201 // mid blocks of type B 202 auto bp = cast(B*)(x.ptr + k); // block pointer 203 immutable nB = (n - k) / mult; // number of B-blocks 204 foreach (ref b; 0 .. nB) // for each block index 205 { 206 bp[b].randInPlace; 207 } 208 209 // ending unaligned bytes 210 foreach (i, ref e; x[k + nB*mult .. $]) 211 { 212 e.randInPlace; 213 } 214 } 215 216 unittest 217 { 218 static void test(B = size_t, T)() 219 { 220 enum n = 1024; 221 222 // dynamic array 223 for (size_t i = 0; i < n; i++) 224 { 225 T[] da = new T[i]; 226 da.randInPlaceBlockwise!B; 227 size_t j = randomInstanceOf!(typeof(i))(0, n/2); 228 da.randInPlaceBlockwise!B; 229 } 230 231 // static array 232 T[n] sa; 233 auto sa2 = sa[1 .. $]; 234 sa2.randInPlaceBlockwise!B; 235 } 236 237 import std.meta : AliasSeq; 238 foreach (T; AliasSeq!(byte, short, int, ubyte, ushort, uint)) 239 { 240 test!(size_t, T); 241 } 242 } 243 244 /** Randomize Contents of members of $(D x). 245 */ 246 auto ref randInPlace(T)(ref T x) 247 if (is(T == struct)) 248 { 249 foreach (ref e; x.tupleof) 250 { 251 e.randInPlace; 252 } 253 return x; 254 } 255 256 unittest 257 { 258 struct T { ubyte a, b, c, d; } 259 T[testLength] x; 260 auto y = x; 261 x.randInPlace; 262 y.randInPlace; 263 assert(y != x); 264 } 265 266 /** Randomize Contents of members of $(D x). 267 */ 268 auto ref randInPlace(T)(T x) 269 if (is(T == class)) 270 { 271 foreach (ref e; x.tupleof) 272 { 273 e.randInPlace; 274 } 275 return x; 276 } 277 278 unittest 279 { 280 void testClass(E)() 281 { 282 class T { E a, b; } 283 auto x = new T; 284 auto y = new T; 285 x.randInPlace; 286 y.randInPlace; 287 assert(y != x); 288 } 289 testClass!bool; 290 testClass!int; 291 testClass!float; 292 } 293 294 /** Get New Randomized Instance of Type $(D T). 295 */ 296 T randomInstanceOf(T)() 297 { 298 /* TODO recursively only void-initialize parts of T that are POD, not 299 reference types */ 300 static if (hasIndirections!T) 301 T x; 302 else 303 /* don't init - randInPlace below fills in everything safely */ 304 T x = void; 305 return x.randInPlace; 306 } 307 308 /** Get New Randomized Instance of Type $(D T). 309 */ 310 T randomInstanceOf(T)(T low = T.min, 311 T high = T.max) 312 if (isNumeric!T) 313 { 314 /* TODO recursively only void-initialize parts of T that are POD, not 315 reference types */ 316 static if (hasIndirections!T) 317 T x; 318 else 319 /* don't init - randInPlace below fills in everything safely */ 320 T x = void; 321 return x.randInPlace(low, high); 322 } 323 324 alias randomize = randInPlace; 325 alias randomized = randomInstanceOf;