1 /++
2     Simple array utilities.
3 
4     Example:
5     ---
6     string[int] aa;
7 
8     immutable key = aa.uniqueKey;
9 
10     assert(key > 0);
11     assert(key in aa);
12     assert(aa[key] == string.init);
13 
14     Appender!(int]) sink;
15     sink.put(1);
16     sink.put(2);
17     sink.put(3);
18 
19     sink.zero(clear: false);
20     assert(sink.data == [ 0, 0, 0 ]);
21 
22     sink.zero(clear: false, 42);
23     assert(sink.data == [ 42, 42, 42 ]);
24 
25     sink.zero();  //(clear: true);
26     assert(!sink.data.length);
27     ---
28 
29     Copyright: [JR](https://github.com/zorael)
30     License: [Boost Software License 1.0](https://www.boost.org/users/license.html)
31 
32     Authors:
33         [JR](https://github.com/zorael)
34  +/
35 module lu.array;
36 
37 private:
38 
39 import std.array : Appender;
40 import std.traits : isIntegral;
41 
42 public:
43 
44 
45 // uniqueKey
46 /++
47     Returns a unique key for the passed associative array. Reserves the key by
48     assigning it a value.
49 
50     Note: This function will end up in an endless loop if a narrow range of indexes
51     is supplied and the associative array already contains values for all of them.
52 
53     Example:
54     ---
55     string[int] aa;
56     immutable key = aa.uniqueKey;
57     assert(key > 0);
58     assert(key in aa);
59     assert(aa[key] == string.init);
60     ---
61 
62     Params:
63         aa = Associative array to get a unique key for.
64         min = Optional minimum key value; defaults to `1`.
65         max = Optional maximum key value; defaults to `K.max`, where `K` is the
66             key type of the passed associative array.
67         value = Optional value to assign to the key; defaults to `V.init`, where
68             `V` is the value type of the passed associative array.
69 
70     Returns:
71         A unique key for the passed associative array. There will exist an array
72         entry for the key, with the value `value`.
73  +/
74 auto uniqueKey(AA : V[K], V, K)
75     (ref AA aa,
76     K min = 1,
77     K max = K.max,
78     V value = V.init)
79 if (isIntegral!K)
80 in ((max > min), "The upper index bound must be greater than the lower to get a unique key")
81 {
82     import std.random : uniform;
83 
84     auto id = uniform(min, max);  // mutable
85     while (id in aa) id = uniform(min, max);
86 
87     aa[id] = value;  // reserve it
88     return id;
89 }
90 
91 ///
92 unittest
93 {
94     import std.conv : to;
95 
96     {
97         string[int] aa;
98         immutable key = aa.uniqueKey;
99         assert(key in aa);
100     }
101     {
102         long[long] aa;
103         immutable key = aa.uniqueKey;
104         assert(key in aa);
105     }
106     {
107         shared bool[int] aa;
108         immutable key = aa.uniqueKey;
109         assert(key in aa);
110     }
111     {
112         int[int] aa;
113         immutable key = aa.uniqueKey(5, 6, 42);
114         assert(key == 5);
115         assert((aa[5] == 42), aa[5].to!string);
116     }
117 }
118 
119 
120 // zero
121 /++
122     Zeroes out the contents of an [std.array.Appender|Appender].
123 
124     Params:
125         sink = The [std.array.Appender|Appender] to zero out.
126         clear = (Optional) Whether to also call the `.clear()` method of the
127             [std.array.Appender|Appender] sink.
128         zeroValue = (Optional) The value to zero out the contents with.
129  +/
130 void zero(Sink : Appender!(T[]), T)
131     (ref Sink sink,
132     const bool clear = true,
133     T zeroValue = T.init)
134 {
135     foreach (ref thing; sink.data)
136     {
137         thing = zeroValue;
138     }
139 
140     if (clear) sink.clear();
141 }
142 
143 ///
144 unittest
145 {
146     {
147         Appender!(char[]) sink;
148         sink.put('a');
149         sink.put('b');
150         sink.put('c');
151         assert(sink.data == ['a', 'b', 'c']);
152 
153         sink.zero(clear: false);
154         assert(sink.data == [ 255, 255, 255 ]);
155 
156         sink.put('d');
157         assert(sink.data == [ 255, 255, 255, 'd' ]);
158 
159         sink.zero(clear: false, 'X');
160         assert(sink.data == [ 'X', 'X', 'X', 'X' ]);
161 
162         sink.zero(clear: true);
163         assert(!sink.data.length);
164     }
165     {
166         Appender!(string[]) sink;
167         sink.put("abc");
168         sink.put("def");
169         sink.put("ghi");
170         assert(sink.data == [ "abc", "def", "ghi" ]);
171 
172         sink.zero(clear: false, "(empty)");
173         assert(sink.data == [ "(empty)", "(empty)", "(empty)" ]);
174 
175         sink.zero(clear: false);
176         assert(sink.data == [ string.init, string.init, string.init ]);
177 
178         sink.zero(clear: true);
179         assert(!sink.data.length);
180     }
181 }