1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.concurrency.Helpers; 13 14 import hunt.collection.Collection; 15 16 /** Shared implementation code for hunt.concurrency. */ 17 class Helpers { 18 private this() {} // non-instantiable 19 20 /** 21 * An implementation of Collection.toString() suitable for classes 22 * with locks. Instead of holding a lock for the entire duration of 23 * toString(), or acquiring a lock for each call to Iterator.next(), 24 * we hold the lock only during the call to toArray() (less 25 * disruptive to other threads accessing the collection) and follows 26 * the maxim "Never call foreign code while holding a lock". 27 */ 28 static string collectionToString(T)(Collection!T c) { 29 T[] a = c.toArray(); 30 size_t size = a.length; 31 if (size == 0) 32 return "[]"; 33 string[] arr = new string[size]; 34 size_t charLength = 0; 35 36 // Replace every array element with its string representation 37 for (size_t i = 0; i < size; i++) { 38 T e = a[i]; 39 // Extreme compatibility with AbstractCollection.toString() 40 string s = (typeid(e) == typeid(c)) ? "(this Collection)" : objectToString(e); 41 arr[i] = s; 42 charLength += s.length; 43 } 44 45 return toString(arr, size, charLength); 46 } 47 48 /** 49 * Like Arrays.toString(), but caller guarantees that size > 0, 50 * each element with index 0 <= i < size is a non-null string, 51 * and charLength is the sum of the lengths of the input Strings. 52 */ 53 static string toString(T)(T[] a, size_t size, size_t charLength) { 54 // assert a !is null; 55 // assert size > 0; 56 57 // Copy each string into a perfectly sized char[] 58 // Length of [ , , , ] == 2 * size 59 char[] chars = new char[charLength + 2 * size]; 60 chars[0] = '['; 61 int j = 1; 62 for (int i = 0; i < size; i++) { 63 if (i > 0) { 64 chars[j++] = ','; 65 chars[j++] = ' '; 66 } 67 string s = objectToString(a[i]); 68 size_t len = s.length; 69 chars[j .. j+len] = s[0..$]; 70 71 j += len; 72 } 73 chars[j] = ']'; 74 // assert j == chars.length - 1; 75 return cast(string)(chars); 76 } 77 78 /** Optimized form of: key ~ "=" ~ val */ 79 static string mapEntryToString(K, V)(K key, V val) { 80 string k, v; 81 size_t klen, vlen; 82 klen = (k = objectToString(key)).length; 83 vlen = (v = objectToString(val)).length; 84 char[] chars = new char[klen + vlen + 1]; 85 86 chars[0..klen] = k[0..klen]; 87 chars[klen] = '='; 88 chars[klen + 1..$] = v[0..klen]; 89 90 return cast(string)(chars); 91 } 92 93 private static string objectToString(T)(T x) { 94 // Extreme compatibility with StringBuilder.append(null) 95 import std.range.primitives; 96 static if(is(T == class)) { 97 string s; 98 return (x is null || (s = x.toString()).empty()) ? "null" : s; 99 } else static if(is(T == string)) { 100 return (x.empty()) ? "null" : x; 101 } else { 102 import std.conv; 103 return to!string(x); 104 } 105 } 106 }