MutexedAA

An associative array and a Mutex. Wraps associative array operations in mutex locks.

Members

Functions

clear
void clear()

Clears the internal associative array.

get
auto get(K key, V value)

Retrieves the value for the key key, or returns the default value if there was none.

has
auto has(K key)

Returns whether or not the passed key is in the associative array.

isReady
auto isReady()

Returns whether or not this instance has been set up.

keys
auto keys()

Returns a new dynamic array of all the keys in the internal associative array.

length
auto length()

Returns the length of the internal associative array.

opEquals
auto opEquals(typeof(this) other)

Implements opEquals for this type, comparing the internal associative array with that of another MutexedAA.

opEquals
auto opEquals(AA other)

Implements opEquals for this type, comparing the internal associative array with a different one.

opIndex
auto opIndex(K key)

aa[key] array retrieve operation, wrapped in a mutex lock.

opIndexAssign
auto opIndexAssign(V value, K key)

aa[key] = value array assign operation, wrapped in a mutex lock.

opIndexOpAssign
void opIndexOpAssign(U value, K key)

Implements index assign operations by mixin strings.

opIndexUnary
auto opIndexUnary(K key)

Implements unary operations by mixin strings.

rehash
auto rehash()

Rehashes the internal associative array.

remove
auto remove(K key)

aa.remove(key) array operation, wrapped in a mutex lock.

require
auto require(K key, V value)

Returns the value for the key key, inserting value lazily if it is not present.

setup
void setup()

Sets up this instance. Does nothing if it has already been set up.

uniqueKey
auto uniqueKey(K min, K max, V value)

Reserves a unique key in the associative array.

update
void update(K key, V delegate() createDg, U delegate(K) updateDg)

Updates the value for the key key in the internal associative array, invoking the first of the passed delegate to insert a new value if it doesn't exist, or the second selegate to modify it in place if it does.

values
auto values()

Returns a new dynamic array of all the values in the internal associative array.

Variables

aa
AA aa;

The internal associative array.

mutex
Mutex mutex;

Mutex to lock the associative array with.

Parameters

AA

Associative array type.

V

Value type.

K

Key type.

Examples

MutexedAA!(string[int]) aa;
aa.setup();  // important!

aa[1] = "one";
aa[2] = "two";
aa[3] = "three";

auto hasOne = aa.has(1);
assert(hasOne);
assert(aa[1] == "one");

assert(aa[2] == "two");

auto three = aa.get(3);
assert(three == "three");

auto four = aa.get(4, "four");
assert(four == "four");

auto five = aa.require(5, "five");
assert(five == "five");
assert(aa[5] == "five");

auto keys = aa.keys;
assert(keys.canFind(1));
assert(keys.canFind(5));
assert(!keys.canFind(6));

auto values = aa.values;
assert(values.canFind("one"));
assert(values.canFind("four"));
assert(!values.canFind("six"));

aa.rehash();
1 {
2     MutexedAA!(string[int]) aa1;
3     assert(!aa1.isReady);
4     aa1.setup();
5     assert(aa1.isReady);
6     aa1.setup();  // extra setups ignored
7 
8     MutexedAA!(string[int]) aa2;
9     aa2.setup();
10 
11     aa1[42] = "hello";
12     aa2[42] = "world";
13     assert(aa1 != aa2);
14 
15     aa1[42] = "world";
16     assert(aa1 == aa2);
17 
18     aa2[99] = "goodbye";
19     assert(aa1 != aa2);
20 }
21 {
22     MutexedAA!(string[int]) aa;
23     aa.setup();
24 
25     assert(!aa.has(42));
26     aa.require(42, "hello");
27     assert((aa[42] == "hello"), aa[42]);
28 
29     bool set1;
30     assert(!aa.has(99));
31     string world1 = aa.require(99, { set1 = true; return "world"; }());
32     assert(set1);
33     assert((world1 == "world"), world1);
34     assert((aa[99] == "world"), aa[99]);
35 
36     bool set2;
37     string world2 = aa.require(99, { set2 = true; return "goodbye"; }());
38     assert(!set2);
39     assert((world2 != "goodbye"), world2);
40     assert((aa[99] != "goodbye"), aa[99]);
41 }
42 {
43     import std.concurrency : Tid, send, spawn;
44     import std.conv : to;
45     import core.time : MonoTime, seconds;
46 
47     static immutable timeout = 1.seconds;
48 
49     static void workerFn(MutexedAA!(string[int]) aa)
50     {
51         static void _assert(
52             lazy bool condition,
53             const string message = "unittest failure",
54             const string file = __FILE__,
55             const uint line = __LINE__)
56         {
57             if (!condition)
58             {
59                 import std.format : format;
60                 import std.stdio : writeln;
61 
62                 enum pattern = "core.exception.AssertError@%s(%d): %s";
63                 immutable assertMessage = pattern.format(file, line, message);
64                 writeln(assertMessage);
65                 assert(0, assertMessage);
66             }
67         }
68 
69         _assert(aa.isReady, "MutexedAA passed to worker was not set up properly");
70 
71         bool halt;
72 
73         while (!halt)
74         {
75             import std.concurrency : OwnerTerminated, receiveTimeout;
76             import std.variant : Variant;
77 
78             immutable receivedSomething = receiveTimeout(timeout,
79                 (bool _)
80                 {
81                     halt = true;
82                 },
83                 (int i)
84                 {
85                     _assert((aa.length == i-1), "Incorrect MutexedAA length before insert");
86                     aa[i] = i.to!string;
87                     _assert((aa.length == i), "Incorrect MutexedAA length after insert");
88                 },
89                 (OwnerTerminated _)
90                 {
91                     halt = true;
92                 },
93                 (Variant v)
94                 {
95                     import std.stdio : writeln;
96                     writeln("MutexedAA unit test worker received unknown message: ", v);
97                     halt = true;
98                 }
99             );
100 
101             if (!receivedSomething) return;
102         }
103     }
104 
105     MutexedAA!(string[int]) aa;
106     aa.setup();
107 
108     auto worker = spawn(&workerFn, aa);
109     immutable start = MonoTime.currTime;
110 
111     foreach (/*immutable*/ i; 1..10)  // start at 1 to enable length checks in worker
112     {
113         worker.send(i);
114         aa.setup();
115         auto present = aa.has(i);
116 
117         while (!present && (MonoTime.currTime - start) < timeout)
118         {
119             import core.thread : Thread;
120             import core.time : msecs;
121 
122             static immutable briefWait = 2.msecs;
123             Thread.sleep(briefWait);
124             present = aa.has(i);
125         }
126 
127         assert(present, "MutexedAA unit test worker timed out responding to " ~ i.to!string);
128         assert((aa[i] == i.to!string), aa[i]);
129     }
130 
131     worker.send(true);  // halt
132 }
133 {
134     import std.algorithm.searching : canFind;
135 
136     MutexedAA!(int[int]) aa;
137     aa.setup();
138 
139     aa[1] = 42;
140     aa[2] = 99;
141     assert(aa.length == 2);
142 
143     auto keys = aa.keys;
144     assert(keys.canFind(1));
145     assert(keys.canFind(2));
146     assert(!keys.canFind(3));
147 
148     auto values = aa.values;
149     assert(values.canFind(42));
150     assert(values.canFind(99));
151     assert(!values.canFind(0));
152 
153     assert(aa.get(1, 0) == 42);
154     assert(aa.get(2, 0) == 99);
155     assert(aa.get(0, 0) == 0);
156     assert(aa.get(3, 999) == 999);
157 }
158 {
159     MutexedAA!(int[int]) aa1;
160     aa1.setup();
161 
162     aa1[1] = 42;
163     aa1[2] = 99;
164 
165     int[int] aa2;
166 
167     aa2[1] = 42;
168     assert(aa1 != aa2);
169 
170     aa2[2] = 99;
171     assert(aa1 == aa2);
172 
173     ++aa2[2];
174     assert(aa2[2] == 100);
175 
176     aa2[1] += 1;
177     assert(aa2[1] == 43);
178 
179     aa2[1] -= 1;
180     assert(aa2[1] == 42);
181 
182     aa2[1] *= 2;
183     assert(aa2[1] == 84);
184 
185     int i = -aa2[1];
186     assert(i == -84);
187 }
188 {
189     MutexedAA!(char[][int]) aa;
190     aa.setup();
191 
192     aa[1] ~= 'a';
193     aa[1] ~= 'b';
194     aa[1] ~= 'c';
195     assert(aa[1] == "abc".dup);
196 
197     aa[1] ~= [ 'd', 'e', 'f' ];
198     assert(aa[1] == "abcdef".dup);
199 }
200 {
201     MutexedAA!(int[int]) aa;
202     aa.setup();
203 
204     immutable key = aa.uniqueKey;
205     assert(key > 0);
206 
207     assert(aa.has(key));
208     assert(aa[key] == int.init);
209     aa.remove(key);
210     assert(!aa.has(key));
211 
212     immutable key2 = aa.uniqueKey(1, 2, -1);
213     assert(key2 == 1);
214     assert(aa.has(key2));
215     assert(aa[key2] == -1);
216 }
217 static if (__VERSION__ >= 2088L)
218 {{
219     MutexedAA!(int[int]) aa;
220     aa.setup();
221 
222     assert(!aa.has(1));
223 
224     aa.update(1,
225         () => 42,
226         (int i) => i + 1);
227     assert(aa.has(1));
228     assert(aa[1] == 42);
229 
230     aa.update(1,
231         () => 42,
232         (int i) => i + 1);
233     assert(aa[1] == 43);
234 }}