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 }