1 module containers_ex;
2 
3 version = benchmark;
4 
5 import std.range : isInputRange;
6 private import std.experimental.allocator.mallocator : Mallocator;
7 
8 /** Instantiator for $(D HashSet) in $(D containers-em).
9  */
10 auto hashSet(Allocator = Mallocator, R)(R r)
11     if (isInputRange!R)
12 {
13     import std.range : ElementType, hasLength;
14     alias E = ElementType!R; // TODO Unqual?
15 
16     import containers.hashset : HashSet;
17     static if (is(Allocator == Mallocator))
18     {
19         static if (hasLength!R)
20         {
21             const bucketCount = r.length; // TODO use
22             auto set = HashSet!(E, Allocator)();
23         }
24         else
25         {
26             auto set = HashSet!(E, Allocator)();
27         }
28     }
29     else
30     {
31         static if (hasLength!R)
32         {
33             const bucketCount = r.length; // TODO use
34             auto set = HashSet!(E, Allocator)(Allocator());
35         }
36         else
37         {
38             auto set = HashSet!(E, Allocator)(Allocator());
39         }
40     }
41 
42     foreach (const e; r)
43     {
44         set.insert(e);
45     }
46 
47     return set; // make it const to indicate fixed
48 }
49 
50 unittest
51 {
52     const x = [1, 2, 3, 2, 1];
53     auto hx = x.hashSet;
54     assert(1 in hx);
55     assert(2 in hx);
56     assert(3 in hx);
57     static assert(is(typeof(3 in hx) == const(int)*));
58 }
59 
60 version(none) unittest
61 {
62     import std.range : iota;
63     import std.algorithm : count;
64     enum n = 1024* 1024;
65 
66     alias T = int;
67 
68     void testHashSetMallocator()
69     {
70         auto hx = iota!T(0, n).hashSet;
71     }
72 
73     void testHashSetInSituRegion()
74     {
75         import std.experimental.allocator.building_blocks.region : Region, InSituRegion;
76         import std.experimental.allocator.mallocator : Mallocator;
77         import std.experimental.allocator.building_blocks.allocator_list : AllocatorList;
78 
79         import std.algorithm : max;
80         // Create a scalable list of regions. Each gets at least 1MB at a time by using malloc.
81         alias LocalAllocator = InSituRegion!(n, T.alignof);
82         auto hx = iota!T(0, n).hashSet!LocalAllocator; // TODO Use LocalAllocator
83     }
84 
85     void testAA()
86     {
87         bool[T] aa;
88         foreach (const e; iota!T(0, n)) { aa[e] = true; }
89     }
90 
91     import std.datetime : benchmark, Duration;
92     auto r = benchmark!(testHashSetMallocator,
93                         testHashSetInSituRegion,
94                         testAA)(10);
95     import std.stdio : writeln;
96 
97     import std.conv : to;
98     writeln("testHashSetMallocator: ", to!Duration(r[0]));
99     writeln("testHashSetInSituRegion:     ", to!Duration(r[1]));
100     writeln("testAA:                ", to!Duration(r[2]));
101 }