2
0

index.zig 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. const std = @import("std");
  2. const storage = @import("storage.zig");
  3. var tree_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
  4. const tree_allocator = tree_arena.allocator();
  5. const temp_allocator = std.heap.c_allocator;
  6. const RadixNode = struct {
  7. edge: []const u8,
  8. children: std.StringHashMap(*RadixNode),
  9. is_terminal: bool,
  10. fn init(edge: []const u8) *RadixNode {
  11. const node = tree_allocator.create(RadixNode) catch unreachable;
  12. node.* = .{
  13. .edge = tree_allocator.dupe(u8, edge) catch unreachable,
  14. .children = std.StringHashMap(*RadixNode).init(tree_allocator),
  15. .is_terminal = false,
  16. };
  17. return node;
  18. }
  19. fn deinit(self: *RadixNode) void {
  20. var it = self.children.iterator();
  21. while (it.next()) |entry| {
  22. entry.value_ptr.*.deinit();
  23. }
  24. self.children.deinit();
  25. tree_allocator.free(self.edge);
  26. tree_allocator.destroy(self);
  27. }
  28. };
  29. var root: *RadixNode = undefined;
  30. var root_initialized = false;
  31. fn ensureRoot() void {
  32. if (!root_initialized) {
  33. root = RadixNode.init("");
  34. root_initialized = true;
  35. }
  36. }
  37. fn commonPrefixLen(a: []const u8, b: []const u8) usize {
  38. var i: usize = 0;
  39. while (i < a.len and i < b.len and a[i] == b[i]) {
  40. i += 1;
  41. }
  42. return i;
  43. }
  44. pub fn insert(key: []const u8) void {
  45. ensureRoot();
  46. if (key.len == 0) return;
  47. var node = root;
  48. var remaining = key;
  49. while (remaining.len > 0) {
  50. var found = false;
  51. var it = node.children.iterator();
  52. while (it.next()) |entry| {
  53. const child = entry.value_ptr.*;
  54. const prefix_len = commonPrefixLen(child.edge, remaining);
  55. if (prefix_len > 0) {
  56. found = true;
  57. if (prefix_len == child.edge.len) {
  58. if (prefix_len == remaining.len) {
  59. child.is_terminal = true;
  60. return;
  61. }
  62. remaining = remaining[prefix_len..];
  63. node = child;
  64. break;
  65. } else {
  66. const old_edge = child.edge;
  67. const common = old_edge[0..prefix_len];
  68. const child_suffix = old_edge[prefix_len..];
  69. const key_suffix = remaining[prefix_len..];
  70. const intermediate = RadixNode.init(common);
  71. tree_allocator.free(child.edge);
  72. child.edge = tree_allocator.dupe(u8, child_suffix) catch unreachable;
  73. intermediate.children.put(child_suffix, child) catch unreachable;
  74. _ = node.children.remove(old_edge);
  75. node.children.put(common, intermediate) catch unreachable;
  76. if (key_suffix.len == 0) {
  77. intermediate.is_terminal = true;
  78. return;
  79. } else {
  80. const new_child = RadixNode.init(key_suffix);
  81. new_child.is_terminal = true;
  82. intermediate.children.put(key_suffix, new_child) catch unreachable;
  83. return;
  84. }
  85. }
  86. }
  87. }
  88. if (!found) {
  89. const new_child = RadixNode.init(remaining);
  90. new_child.is_terminal = true;
  91. node.children.put(remaining, new_child) catch unreachable;
  92. return;
  93. }
  94. }
  95. node.is_terminal = true;
  96. }
  97. pub fn delete(key: []const u8) void {
  98. ensureRoot();
  99. if (key.len == 0) return;
  100. const node = findNode(root, key);
  101. if (node) |n| {
  102. n.is_terminal = false;
  103. }
  104. }
  105. fn findNode(node: *RadixNode, key: []const u8) ?*RadixNode {
  106. if (key.len == 0) return node;
  107. var current = node;
  108. var remaining = key;
  109. while (remaining.len > 0) {
  110. var found = false;
  111. var it = current.children.iterator();
  112. while (it.next()) |entry| {
  113. const child = entry.value_ptr.*;
  114. const prefix_len = commonPrefixLen(child.edge, remaining);
  115. if (prefix_len > 0) {
  116. if (prefix_len < child.edge.len) {
  117. return null;
  118. }
  119. if (prefix_len == remaining.len) {
  120. return child;
  121. }
  122. remaining = remaining[prefix_len..];
  123. current = child;
  124. found = true;
  125. break;
  126. }
  127. }
  128. if (!found) return null;
  129. }
  130. return current;
  131. }
  132. pub fn searchByPrefix(prefix: []const u8) ?*RadixNode {
  133. ensureRoot();
  134. if (prefix.len == 0) return root;
  135. return findNode(root, prefix);
  136. }
  137. fn countKeys(node: *RadixNode) usize {
  138. var count: usize = 0;
  139. if (node.is_terminal) {
  140. count += 1;
  141. }
  142. var it = node.children.iterator();
  143. while (it.next()) |entry| {
  144. count += countKeys(entry.value_ptr.*);
  145. }
  146. return count;
  147. }
  148. const MAX_KEYS_RETURN = 10000;
  149. const MAX_KEY_LENGTH = 1024;
  150. fn collectKeysWithBuffer(node: *RadixNode, prefix_buffer: []u8, prefix_len: usize, keys: *std.ArrayListUnmanaged([]const u8), max_keys: usize) void {
  151. if (keys.items.len >= max_keys) return;
  152. if (node.is_terminal) {
  153. const key = temp_allocator.dupe(u8, prefix_buffer[0..prefix_len]) catch return;
  154. keys.append(temp_allocator, key) catch return;
  155. }
  156. var it = node.children.iterator();
  157. while (it.next()) |entry| {
  158. if (keys.items.len >= max_keys) break;
  159. const child = entry.value_ptr.*;
  160. const edge_len = child.edge.len;
  161. if (prefix_len + edge_len > MAX_KEY_LENGTH) continue;
  162. @memcpy(prefix_buffer[prefix_len .. prefix_len + edge_len], child.edge);
  163. collectKeysWithBuffer(child, prefix_buffer, prefix_len + edge_len, keys, max_keys);
  164. }
  165. }
  166. fn collectKeys(node: *RadixNode, prefix: []const u8, keys: *std.ArrayListUnmanaged([]const u8), max_keys: usize) void {
  167. var prefix_buffer: [MAX_KEY_LENGTH]u8 = undefined;
  168. if (prefix.len > MAX_KEY_LENGTH) return;
  169. @memcpy(prefix_buffer[0..prefix.len], prefix);
  170. collectKeysWithBuffer(node, &prefix_buffer, prefix.len, keys, max_keys);
  171. }
  172. pub fn getKeysFromNode(node: *RadixNode, prefix: []const u8) [][]const u8 {
  173. var keys_list = std.ArrayListUnmanaged([]const u8){};
  174. collectKeys(node, prefix, &keys_list, MAX_KEYS_RETURN);
  175. return keys_list.toOwnedSlice(temp_allocator) catch &[_][]const u8{};
  176. }
  177. pub fn getKeysByPrefix(prefix: []const u8) []const u8 {
  178. ensureRoot();
  179. const node = searchByPrefix(prefix) orelse return "";
  180. const keys = getKeysFromNode(node, prefix);
  181. if (keys.len == 0) return "";
  182. return std.mem.join(temp_allocator, "\r", keys) catch "";
  183. }
  184. pub fn getValuesByPrefix(prefix: []const u8) []const u8 {
  185. ensureRoot();
  186. const node = searchByPrefix(prefix) orelse return "";
  187. const keys = getKeysFromNode(node, prefix);
  188. if (keys.len == 0) return "";
  189. const values = temp_allocator.alloc([]const u8, keys.len) catch return "";
  190. for (keys, 0..) |key, i| {
  191. const value = storage.read(key) orelse "";
  192. values[i] = value;
  193. }
  194. return std.mem.join(temp_allocator, "\r", values) catch "";
  195. }
  196. pub fn getAllKeys() []const u8 {
  197. ensureRoot();
  198. const keys = getKeysFromNode(root, &[_]u8{});
  199. if (keys.len == 0) return "";
  200. return std.mem.join(temp_allocator, "\r", keys) catch "";
  201. }