pruneAA

Iterates an associative array and deletes invalid entries, either if the value is in a default .init state or as per the optionally passed predicate.

It is supposedly undefined behaviour to remove an associative array's fields when foreaching through it. So far we have been doing a simple mark-sweep garbage collection whenever we encounter this use-case in the code, so why not just make a generic solution instead and deduplicate code?

@safe
void
pruneAA
(
alias pred = null
AA
)
(
ref AA aa
)
if (
isAssociativeArray!AA &&
isMutable!AA
)

Parameters

pred

Optional predicate if special logic is needed to determine whether an entry is to be removed or not.

aa AA

The associative array to modify.

Examples

auto aa =
[
    "abc" : "def",
    "ghi" : string.init;
    "mno" : "123",
    "pqr" : string.init,
];

pruneAA(aa);

assert("ghi" !in aa);
assert("pqr" !in aa);

pruneAA!((entry) => entry.length > 0)(aa);

assert("abc" !in aa);
assert("mno" !in aa);
1 import std.conv : text;
2 
3 {
4     auto aa =
5     [
6         "abc" : "def",
7         "ghi" : "jkl",
8         "mno" : "123",
9         "pqr" : string.init,
10     ];
11 
12     pruneAA!((a) => a == "def")(aa);
13     assert("abc" !in aa);
14 
15     pruneAA!((a,b) => a == "pqr")(aa);
16     assert("pqr" !in aa);
17 
18     pruneAA!`a == "123"`(aa);
19     assert("mno" !in aa);
20 }
21 {
22     struct Record
23     {
24         string name;
25         int id;
26     }
27 
28     auto aa =
29     [
30         "rhubarb" : Record("rhubarb", 100),
31         "raspberry" : Record("raspberry", 80),
32         "blueberry" : Record("blueberry", 0),
33         "apples" : Record("green apples", 60),
34         "yakisoba"  : Record("yakisoba", 78),
35         "cabbage" : Record.init,
36     ];
37 
38     pruneAA(aa);
39     assert("cabbage" !in aa);
40 
41     pruneAA!((entry) => entry.id < 80)(aa);
42     assert("blueberry" !in aa);
43     assert("apples" !in aa);
44     assert("yakisoba" !in aa);
45     assert((aa.length == 2), aa.length.text);
46 }
47 {
48     import std.algorithm.searching : canFind;
49 
50     string[][string] aa =
51     [
52         "abc" : [ "a", "b", "c" ],
53         "def" : [ "d", "e", "f" ],
54         "ghi" : [ "g", "h", "i" ],
55         "jkl" : [ "j", "k", "l" ],
56     ];
57 
58     pruneAA(aa);
59     assert((aa.length == 4), aa.length.text);
60 
61     pruneAA!((entry) => entry.canFind("a"))(aa);
62     assert("abc" !in aa);
63 }