1 /** 2 Copyright: Copyright (c) 2016-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.container.multihashset; 7 8 import voxelman.log; 9 import voxelman.container.hash.map; 10 11 /// Stores number of entries for each key 12 struct MultiHashSet(Key, Key emptyKey, Key deletedKey) 13 { 14 mixin MultiHashSetImpl!(Key, HashMap!(Key, size_t, emptyKey, deletedKey)); 15 } 16 17 /// ditto 18 struct MultiHashSet(Key) 19 { 20 mixin MultiHashSetImpl!(Key, HashMap!(Key, size_t)); 21 } 22 23 private mixin template MultiHashSetImpl(Key, HashMapT) { 24 HashMapT keys; 25 26 size_t get(Key key) { 27 return keys.get(key, 0); 28 } 29 30 alias opIndex = get; 31 32 // returns true if key was first time added after this call 33 bool add(Key key, size_t addedEntries = 1) { 34 size_t* numEntries = keys.getOrCreate(key, 0); 35 (*numEntries) += addedEntries; 36 return (*numEntries) == addedEntries; // new observer 37 } 38 39 // returns true if key was removed after this call 40 bool remove(Key key, size_t removedEntries = 1) { 41 size_t* numEntries = key in keys; 42 if (numEntries) { 43 size_t numToRemove = (*numEntries) >= removedEntries ? removedEntries : (*numEntries); 44 (*numEntries) -= numToRemove; 45 if ((*numEntries) == 0) { 46 keys.remove(key); 47 return true; 48 } 49 } 50 return false; 51 } 52 53 // iterate over all keys 54 int opApply(scope int delegate(in Key) del) { 55 foreach (Key key; keys.byKey()) 56 if (auto ret = del(key)) 57 return ret; 58 return 0; 59 } 60 61 int opApply(scope int delegate(in Key, size_t) del) { 62 foreach (key, numEntries; keys) 63 if (auto ret = del(key, numEntries)) 64 return ret; 65 return 0; 66 } 67 } 68 69 unittest { 70 import std.stdio; 71 MultiHashSet!int multiset; 72 73 enum iter = 64; 74 foreach (i; 0..iter) { 75 foreach (j; 0..iter) { 76 multiset.add(j); 77 assert(multiset[j] == i+1); 78 } 79 } 80 81 foreach (i; 0..iter) { 82 foreach (j; 0..iter) { 83 multiset.remove(j); 84 assert(multiset[j] == iter-i-1); 85 } 86 } 87 88 foreach (i; 0..iter) { 89 foreach (j; 0..iter) { 90 multiset.add(j); 91 assert(multiset[j] == i+1); 92 } 93 } 94 }