1 module dkh.container.radixheap; 2 3 import dkh.container.stackpayload; 4 5 import std.functional : unaryFun; 6 import std.traits : isSigned, isUnsigned; 7 8 /** 9 Radix Heap 10 */ 11 template RadixHeap(T, alias pred = "a") { 12 alias _pred = unaryFun!pred; // pred(value) = key 13 alias K = typeof(_pred(T())); // key type 14 /// 15 static if (isUnsigned!K) { 16 // unsigned 17 18 struct RadixHeap { 19 static struct Payload { 20 StackPayload!T[K.sizeof*8+1] v; 21 size_t len; 22 K last; 23 24 // bsr(x) + 1 25 private static int bsr1(K x) { 26 import core.bitop : bsr; 27 return (x == 0) ? 0 : bsr(x)+1; 28 } 29 private void assign(T item) { 30 K key = _pred(item); 31 assert(last <= key); 32 v[bsr1(key^last)] ~= item; 33 } 34 private void pull() { 35 import std.range, std.algorithm; 36 if (v[0].length) return; 37 auto i = iota(K.sizeof*8+1).find!(a => v[a].length).front; 38 // reassign v[i] 39 last = v[i].data[].map!_pred.reduce!min; 40 v[i].data.each!(a => assign(a)); 41 v[i].clear(); 42 } 43 44 void insert(T item) { 45 len++; 46 assign(item); 47 } 48 T front() { 49 pull(); 50 return v[0].back; 51 } 52 void removeFront() { 53 pull(); 54 len--; 55 v[0].removeBack(); 56 } 57 } 58 Payload* p; 59 60 @property bool empty() const { return (!p || p.len == 0); } /// 61 @property size_t length() const { return (!p ? 0 : p.len); } /// 62 alias opDollar = length; /// ditto 63 64 /// Warning: return minimum 65 T front() { 66 assert(!empty, "RadixHeap.front: heap is empty"); 67 return p.front; 68 } 69 void insert(T item) { 70 if (!p) p = new Payload(); 71 p.insert(item); 72 } /// 73 void removeFront() { 74 assert(!empty, "RadixHeap.removeFront: heap is empty"); 75 p.removeFront(); 76 } /// 77 } 78 } else static if (isSigned!K) { 79 // signed 80 import std.traits : Unsigned; 81 static Unsigned!K pred2(in T item) { 82 return _pred(item) ^ (K(1) << (K.sizeof*8 - 1)); 83 } 84 alias RadixHeap = RadixHeap!(T, pred2); 85 } else { 86 static assert(false); 87 } 88 } 89 90 /// 91 unittest { 92 RadixHeap!int q; 93 q.insert(2); 94 q.insert(1); 95 assert(q.front == 1); 96 q.removeFront(); 97 assert(q.front == 2); 98 } 99 100 unittest { 101 import std.algorithm; 102 import std.random; 103 void test(T)() { 104 RadixHeap!T q; 105 T[] a = new T[100]; 106 a.each!((ref x) => x = uniform!"[]"(T.min, T.max)); 107 foreach (i; 0..100) { 108 q.insert(a[i]); 109 } 110 a.sort!"a<b"; 111 foreach (i; 0..100) { 112 assert(q.front() == a[i]); 113 q.removeFront(); 114 } 115 } 116 test!ubyte(); 117 test!ushort(); 118 test!uint(); 119 test!ulong(); 120 121 test!byte(); 122 test!short(); 123 test!int(); 124 test!long(); 125 } 126 127 unittest { 128 RadixHeap!int r; 129 r.insert(100); 130 auto r2 = r; 131 r2.insert(10); 132 assert(r.length == 2); 133 r.removeFront(); 134 assert(r2.length == 1); 135 }