Skip to content

Commit b0896ae

Browse files
committed
containers.hashmap: Support non-copyable types
1 parent 1b94c07 commit b0896ae

File tree

1 file changed

+20
-10
lines changed

1 file changed

+20
-10
lines changed

src/containers/hashmap.d

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
module containers.hashmap;
99

10+
private import core.lifetime : move;
1011
private import containers.internal.hash;
1112
private import containers.internal.node : shouldAddGCRange;
1213
private import std.experimental.allocator.mallocator : Mallocator;
@@ -181,7 +182,7 @@ struct HashMap(K, V, Allocator = Mallocator, alias hashFunction = generateHash!K
181182
*/
182183
void opIndexAssign(V value, const K key)
183184
{
184-
insert(key, value);
185+
insert(key, move(mutable(value)));
185186
}
186187

187188
/**
@@ -257,7 +258,7 @@ struct HashMap(K, V, Allocator = Mallocator, alias hashFunction = generateHash!K
257258
auto app = appender!(K[])();
258259
foreach (ref const bucket; buckets)
259260
{
260-
foreach (item; bucket)
261+
foreach (ref item; bucket)
261262
app.put(cast(K) item.key);
262263
}
263264
return app.data;
@@ -364,6 +365,8 @@ private:
364365
enum bool useGC = supportGC && (shouldAddGCRange!K || shouldAddGCRange!V);
365366
alias Hash = typeof({ K k = void; return hashFunction(k); }());
366367

368+
static ref ContainerStorageType!T mutable(T)(ref T value) { return *cast(ContainerStorageType!T*)&value; }
369+
367370
enum IterType: ubyte
368371
{
369372
key, value, both
@@ -472,7 +475,7 @@ private:
472475

473476
Node* insert(const K key, V value)
474477
{
475-
return insert(key, value, hashFunction(key));
478+
return insert(key, move(mutable(value)), hashFunction(key));
476479
}
477480

478481
Node* insert(const K key, V value, const Hash hash, const bool modifyLength = true)
@@ -484,15 +487,15 @@ private:
484487
{
485488
if (item.hash == hash && item.key == key)
486489
{
487-
item.value = value;
490+
item.value = move(mutable(value));
488491
return &item;
489492
}
490493
}
491494
static if (storeHash)
492-
Node node = Node(hash, cast(ContainerStorageType!K) key, value);
495+
Node node = Node(hash, cast(ContainerStorageType!K) key, move(mutable(value)));
493496
else
494-
Node node = Node(cast(ContainerStorageType!K) key, value);
495-
Node* n = buckets[index].insertAnywhere(node);
497+
Node node = Node(cast(ContainerStorageType!K) key, move(mutable(value)));
498+
Node* n = buckets[index].insertAnywhere(move(node));
496499
if (modifyLength)
497500
_length++;
498501
if (shouldRehash())
@@ -533,7 +536,8 @@ private:
533536
buckets = cast(Bucket[]) allocator.allocate(newSize);
534537
static if (useGC)
535538
GC.addRange(buckets.ptr, buckets.length * Bucket.sizeof);
536-
assert (buckets);
539+
if (newLength)
540+
assert (buckets);
537541
assert (buckets.length == newLength);
538542
foreach (ref bucket; buckets)
539543
{
@@ -545,8 +549,8 @@ private:
545549

546550
foreach (ref bucket; oldBuckets)
547551
{
548-
foreach (node; bucket)
549-
insert(cast(K) node.key, node.value, node.hash, false);
552+
foreach (ref node; bucket)
553+
insert(cast(K) node.key, move(node.value), node.hash, false);
550554
typeid(typeof(bucket)).destroy(&bucket);
551555
}
552556
static if (useGC)
@@ -780,3 +784,9 @@ version(emsi_containers_unittest) unittest
780784
foreach (k, ref v; hm) { v++; }
781785
assert(hm["a"] == 2);
782786
}
787+
788+
version(emsi_containers_unittest) unittest
789+
{
790+
static struct S { @disable this(this); }
791+
alias HM = HashMap!(int, S);
792+
}

0 commit comments

Comments
 (0)