Advertisement
Guest User

Untitled

a guest
Feb 27th, 2019
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.94 KB | None | 0 0
  1. const std = @import("std");
  2. const testing = std.testing;
  3. const assert = std.debug.assert;
  4. const Allocator = std.mem.Allocator;
  5. const DirectAllocator = std.heap.DirectAllocator;
  6.  
  7. fn max(comptime T: type, a: T, b: T) T {
  8. return if (a > b) a else b;
  9. }
  10.  
  11. pub fn FlatMap(
  12. comptime K: type,
  13. comptime V: type,
  14. comptime hash: fn (K) u64,
  15. comptime key_equals: fn (K, K) bool,
  16. ) type {
  17. return struct {
  18. const Self = @This();
  19.  
  20. const KV = struct {
  21. value: V,
  22. key: K,
  23. distance: i8, // -1 == empty, -2 == deleted, otherwise represents probe distance
  24. };
  25.  
  26. slots: []KV,
  27. size: usize,
  28. maxLoadFactor: f32,
  29. longestProbe: i8,
  30. allocator: *Allocator,
  31.  
  32. const EMPTY: i8 = -1;
  33. const TOMBSTONE: i8 = -1;
  34.  
  35. pub fn init(allocator: *Allocator) !Self {
  36. var new_map = Self{
  37. .slots = undefined,
  38. .size = 0,
  39. .maxLoadFactor = 0.6,
  40. .longestProbe = 0,
  41. .allocator = allocator,
  42. };
  43.  
  44. new_map.slots = try allocator.alloc(KV, 2);
  45. return new_map;
  46. }
  47.  
  48. pub fn deinit(self: *Self) void {
  49. self.allocator.free(self.slots);
  50. }
  51.  
  52. pub inline fn capacity(self: *const Self) usize {
  53. return self.slots.len;
  54. }
  55.  
  56. pub inline fn loadFactor(self: *const Self) f32 {
  57. return @intToFloat(f32, self.size) / @intToFloat(f32, self.capacity());
  58. }
  59.  
  60. pub fn insert(self: *Self, key: K, value: V) !void {
  61. if (self.loadFactor() > self.maxLoadFactor) {
  62. try self.reserve(max(usize, 2, self.capacity() * 2));
  63. }
  64.  
  65. const N = self.capacity() - 1;
  66. var idx: usize = hash(key) & N;
  67.  
  68. var entry = KV{ .key = key, .value = value, .distance = 0 };
  69.  
  70. while (true) {
  71. var probed = &self.slots[idx];
  72.  
  73. if (probed.distance < 0) { // encountered EMPTY/TOMBSTONE
  74. probed.* = entry;
  75. self.size += 1;
  76. self.longestProbe = max(i8, entry.distance, self.longestProbe);
  77. return;
  78. } else if (key_equals(probed.key, entry.key)) {
  79. probed.value = entry.value;
  80. return;
  81. } else if (probed.distance < entry.distance) {
  82. self.longestProbe = max(i8, entry.distance, self.longestProbe);
  83. std.mem.swap(KV, probed, &entry);
  84. }
  85.  
  86. idx = (idx + 1) & N;
  87. entry.distance += 1;
  88. }
  89. }
  90.  
  91. pub fn lookup(self: *Self, lookup_key: K) ?*V {
  92. const N = self.capacity() - 1;
  93. var idx: usize = hash(lookup_key) & N;
  94. var distance: i8 = 0;
  95.  
  96. while (true) {
  97. var probed = &self.slots[idx];
  98.  
  99. if (key_equals(probed.key, lookup_key)) {
  100. return &probed.value;
  101. } else if (probed.distance == EMPTY) {
  102. return null;
  103. }
  104.  
  105. idx = (idx + 1) & N;
  106. distance += 1;
  107.  
  108. if (distance > self.longestProbe) {
  109. return null;
  110. }
  111. }
  112. }
  113.  
  114. pub fn contains(self: *Self, key: K) bool {
  115. return self.lookup(key) != null;
  116. }
  117.  
  118. pub fn remove(self: *Self, key_to_delete: K) bool {
  119. const N = self.capacity() - 1;
  120. var idx: usize = hash(key) & N;
  121. var distance: i8 = 0;
  122.  
  123. while (true) {
  124. var probed = &self.slots[idx];
  125.  
  126. if (key_equals(probed.key, key_to_delete)) {
  127. probed.distance = TOMBSTONE;
  128. self.size -= 1;
  129. return true;
  130. } else if (probed.distance == EMPTY) {
  131. return false;
  132. }
  133.  
  134. idx = (idx + 1) & N;
  135. distance += 1;
  136.  
  137. if (distance > self.longestProbe) {
  138. return false;
  139. }
  140. }
  141. }
  142.  
  143. pub fn reserve(self: *Self, newCapacity: usize) !void {
  144. assert(newCapacity > self.capacity());
  145. assert(newCapacity & (newCapacity - 1) == 0); // demand capacity is power of two
  146. var oldSlots = self.slots;
  147. self.slots = try self.allocator.alloc(KV, newCapacity);
  148.  
  149. for (self.slots) |*entry| {
  150. entry.distance = -1;
  151. }
  152.  
  153. self.size = 0;
  154. self.longestProbe = 0;
  155. for (oldSlots) |entry| {
  156. if (entry.distance >= 0) {
  157. _ = self.insert(entry.key, entry.value);
  158. }
  159. }
  160.  
  161. self.allocator.free(oldSlots);
  162. }
  163. };
  164. }
  165.  
  166. fn internal_hash(x: u32) u64 {
  167. var y: u64 = @intCast(u64, x);
  168.  
  169. y = (y + 0x7ed55d16) + (y << 12);
  170. y = (y ^ 0xc761c23c) ^ (y >> 19);
  171. y = (y + 0x165667b1) + (y << 5);
  172. y = (y + 0xd3a2646c) ^ (y << 9);
  173. y = (y + 0xfd7046c5) + (y << 3);
  174. y = (y ^ 0xb55a4f09) ^ (y >> 16);
  175.  
  176. return y;
  177. }
  178.  
  179. fn internal_equals(x: u32, y: u32) bool {
  180. return x == y;
  181. }
  182.  
  183. test "FlatMap" {
  184. var dalloc = DirectAllocator.init();
  185. defer dalloc.deinit();
  186.  
  187. var map = try FlatMap(u32, u32, internal_hash, internal_equals).init(&dalloc.allocator);
  188. defer map.deinit();
  189.  
  190. var i: u32 = 0;
  191. while (i < 10000) {
  192. try map.insert(i, i * 2);
  193. testing.expect(map.size == i + 1);
  194. testing.expect(map.contains(i));
  195. i += 1;
  196. }
  197.  
  198. i = 0;
  199. while (i < 300) {
  200. if (map.lookup(i)) |x| {
  201. testing.expect(x.* == i * 2);
  202. } else {
  203. testing.expect(false);
  204. }
  205. i += 1;
  206. }
  207. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement