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 }