Advertisement
Guest User

Untitled

a guest
Jun 15th, 2019
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.45 KB | None | 0 0
  1. const std = @import("std");
  2. const mem = std.mem;
  3. const math = std.math;
  4.  
  5. const warn = std.debug.warn;
  6. const assert = std.debug.assert;
  7.  
  8. const ArrayList = std.ArrayList;
  9.  
  10. fn Bucket(comptime T: type, comptime items_per_bucket: i32) type {
  11. return struct {
  12. const Self = @This();
  13.  
  14. data: [items_per_bucket]T,
  15. occupied: [items_per_bucket]bool,
  16. index: i32,
  17. count: i32,
  18. };
  19. }
  20.  
  21. const BucketLocator = struct {
  22. bucket_index: i32,
  23. slot_index: usize,
  24. };
  25.  
  26. fn indexOf(comptime T: type, haystack: var, needle: T) ?usize {
  27. var itr = haystack.iterator();
  28. var i: usize = 0;
  29. while (itr.next()) |e| : (i += 1) {
  30. if (e == needle) return i;
  31. }
  32. return null;
  33. }
  34.  
  35. // TODO: Add shrink to free empty buckets.
  36. fn BucketArray(comptime T: type, comptime items_per_bucket: i32) type {
  37. return struct {
  38. const MyBucket = Bucket(T, items_per_bucket);
  39. const Self = @This();
  40.  
  41. allocator: *mem.Allocator,
  42. count: i64,
  43.  
  44. all_buckets: ArrayList(*MyBucket),
  45. unfull_buckets: ArrayList(*MyBucket),
  46.  
  47.  
  48. pub fn init(allocator: *mem.Allocator) Self {
  49. var a = Self {
  50. .all_buckets = ArrayList(*MyBucket).init(allocator),
  51. .unfull_buckets = ArrayList(*MyBucket).init(allocator),
  52. .count = 0,
  53. .allocator = allocator,
  54. };
  55. return a;
  56. }
  57.  
  58. pub fn deinit(self: *Self) void {
  59. var itr = self.all_buckets.iterator();
  60. while (itr.next()) |bucket| {
  61. self.allocator.destroy(bucket);
  62. }
  63. self.unfull_buckets.shrink(0);
  64. self.all_buckets.shrink(0);
  65. }
  66.  
  67. fn addBucket(self: *Self) error{OutOfMemory}!void {
  68. var b = try self.allocator.create(MyBucket);
  69. b.index = @intCast(i32, self.all_buckets.len);
  70. b.count = 0;
  71. assert(b.index == @intCast(i32, self.all_buckets.len)); // NOTE: Asserts if overflowed.
  72.  
  73. try self.all_buckets.append(b);
  74. try self.unfull_buckets.append(b);
  75. }
  76.  
  77. pub fn append(self: *Self, item: T) error{OutOfMemory}!BucketLocator {
  78. if (self.unfull_buckets.len == 0) try addBucket(self);
  79. assert(self.unfull_buckets.len != 0);
  80.  
  81. var bucket = self.unfull_buckets.at(0);
  82. var index: ?usize = null;
  83. for (bucket.occupied) |occupied, i| {
  84. if (occupied) { // TODO: FIXME: Why do we need to have this branch in order for this code to work at all?
  85. continue;
  86. } else {
  87. index = i;
  88. break;
  89. }
  90. // if (!occupied) {
  91. // index = i;
  92. // break;
  93. // }
  94. }
  95. assert(index != null); // TODO: Asserts.
  96.  
  97. bucket.occupied[index.?] = true;
  98. bucket.count += 1;
  99. assert(bucket.count <= items_per_bucket);
  100.  
  101. self.count += 1;
  102.  
  103. if (bucket.count == items_per_bucket) {
  104. var itr = self.unfull_buckets.iterator();
  105. var i: usize = 0;
  106. var removed = false;
  107. while (itr.next()) |value| : (i += 1) {
  108. if (value == bucket) {
  109. _ = self.unfull_buckets.swapRemove(i);
  110. removed = true;
  111. break;
  112. }
  113. }
  114. assert(removed);
  115. }
  116.  
  117. var loc = BucketLocator{
  118. .bucket_index = bucket.index,
  119. .slot_index = index.?,
  120. };
  121.  
  122. bucket.data[index.?] = item;
  123. return loc;
  124. }
  125.  
  126. pub fn remove(self: *Self, loc: BucketLocator) !T {
  127. var bucket = self.all_buckets.at(@intCast(usize, loc.bucket_index));
  128. assert(bucket.occupied[loc.slot_index] == true);
  129.  
  130. const wasFull = (bucket.count == items_per_bucket);
  131.  
  132. bucket.occupied[loc.slot_index] = false;
  133. bucket.count -= 1;
  134. self.count -= 1;
  135.  
  136. if (wasFull) {
  137. assert(indexOf(*MyBucket, self.unfull_buckets, bucket) == null);
  138. try self.unfull_buckets.append(bucket);
  139. }
  140.  
  141. return bucket.data[loc.slot_index];
  142. }
  143.  
  144. pub fn at(self: *Self, loc: BucketLocator) T {
  145. var bucket = self.all_buckets.at(@intCast(usize, loc.bucket_index));
  146. assert(bucket.occupied[loc.slot_index] == true);
  147. var result = bucket.data[@intCast(usize, loc.slot_index)];
  148. return result;
  149. }
  150.  
  151. pub fn iterator(self: *Self) BucketIterator {
  152. return BucketIterator{
  153. .array = self,
  154. .locator = BucketLocator{.bucket_index = 0, .slot_index = 0},
  155. .index = -1,
  156. };
  157. }
  158.  
  159. const BucketIterator = struct {
  160. array: *Self,
  161. index: i64,
  162. locator: BucketLocator,
  163.  
  164. fn next(self: *BucketIterator) ?T {
  165. if (self.index >= self.array.count) return null;
  166.  
  167. self.index += 1;
  168. var loc = self.locator;
  169.  
  170. if (self.index > 0) {
  171. while (true) {
  172. loc.slot_index += 1;
  173. if (loc.slot_index >= @intCast(usize, items_per_bucket)) {
  174. loc.slot_index = 0;
  175. loc.bucket_index += 1;
  176. }
  177.  
  178. if (@intCast(usize, loc.bucket_index) >= self.array.all_buckets.len) return null;
  179.  
  180. var bucket = self.array.all_buckets.at(@intCast(usize, loc.bucket_index));
  181. if (bucket.occupied[@intCast(usize, loc.slot_index)]) break;
  182. }
  183. self.locator = loc;
  184. }
  185.  
  186. return self.array.all_buckets.at(@intCast(usize, loc.bucket_index)).data[@intCast(usize, loc.slot_index)];
  187. }
  188. };
  189. };
  190. }
  191.  
  192. pub fn main() !void {
  193. var arena = std.heap.ArenaAllocator.init(&std.heap.DirectAllocator.init().allocator);
  194. defer arena.deinit();
  195.  
  196. var ba = BucketArray(i32, 4).init(&arena.allocator);
  197. defer ba.deinit();
  198. assert(ba.count == 0);
  199.  
  200. {
  201. var i: i32 = 1;
  202. while (i <= 1024) : (i *= 2) {
  203. _ = try ba.append(i);
  204. warn("add {}\n", i);
  205. }
  206. assert(ba.count == math.log2(i));
  207. }
  208. const countAfterAdding = ba.count;
  209.  
  210. {
  211. var itr = ba.iterator();
  212. var j: i32 = 0;
  213. warn("{{ ");
  214. while (itr.next()) |value| : (j += 1) {
  215. if (j > 0) warn(", ");
  216. warn("{}", value);
  217. assert(value == math.pow(i32, 2, j));
  218. }
  219. warn(" }}\n");
  220. }
  221.  
  222. {
  223. const removed = try ba.remove(BucketLocator{.bucket_index = 0, .slot_index = 2});
  224. assert(removed == 4);
  225. assert(ba.count == countAfterAdding-1);
  226. }
  227.  
  228. {
  229. var itr = ba.iterator();
  230. var i: i32 = 0;
  231. warn("{{ ");
  232. while (itr.next()) |value| : (i += 1) {
  233. if (i > 0) warn(", ");
  234. warn("{}", value);
  235.  
  236. assert(value != 4); // Since we removed it.
  237. }
  238. warn(" }}\n");
  239. }
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement