- pub const Iterator = struct {
- sv: SetView(K),
- idx: ?K,
- dir: enum { Forward, Backward },
-
- pub fn next(self: *Iterator) ?struct { key: K } {
- if (self.idx != null) {
- const k = self.idx.?;
- const item = self.sv.item_get(k) catch return null;
- self.idx = switch (self.dir) {
- .Forward => item.next,
- .Backward => item.prev,
- };
- return .{ .key = k };
- } else {
- return null;
- }
- }
- };
- pub fn iterator(self: Self) Iterator {
- return .{
- .sv = self,
- .idx = self.head.first,
- .dir = .Forward,
- };
- }
- pub fn reverse_iterator(self: Self) Iterator {
- return .{
- .sv = self,
- .idx = self.head.last,
- .dir = .Backward,
- };
- }
- };
-}
-pub fn List(comptime V: type) type {
- return struct {
- idx: ?Index = null,
-
- const Self = @This();
- pub const Index = u64;
- pub const Key = u64;
- pub const Val = V;
- pub const View = ListView(V);
-
- fn open_dbi(txn: lmdb.Txn) !lmdb.Dbi {
- return try txn.dbi("SetList");
- }
- pub fn init(txn: lmdb.Txn) !Self {
- const head = View.Head{};
- const dbi = try open_dbi(txn);
- const idx = try Prng.gen(dbi, Index);
- try dbi.put(idx, head);
- return .{ .idx = idx };
- }
- pub fn open(self: Self, txn: lmdb.Txn) !View {
- // create new head
- if (self.idx == null) {
- return error.NotInitialized;
- }
- // get head from dbi
- const dbi = try open_dbi(txn);
- const head = try dbi.get(self.idx.?, View.Head);
- return .{
- .dbi = dbi,
- .idx = self.idx.?,
- .head = head,
- };
- }
- };
-}
-
-pub fn ListView(comptime V: type) type {
- return struct {
- const Self = @This();
- const K = u64;
- const ItemIndex = struct { List(V).Index, K };
-
- pub const Head = struct {
- len: usize = 0,
- first: ?K = null,
- last: ?K = null,
- };
- pub const Item = struct {
- next: ?K = null,
- prev: ?K = null,
- data: V,
- };
-
- dbi: lmdb.Dbi,
- idx: List(V).Index,
- head: Head,
-
- fn item_idx(self: Self, k: K) ItemIndex {
- return .{ self.idx, k };
- }
- fn item_get(self: Self, k: K) !Item {
- return try self.dbi.get(self.item_idx(k), Item);
- }
- fn item_put(self: Self, k: K, item: Item) !void {
- try self.dbi.put(self.item_idx(k), item);
- }
- fn head_update(self: Self) !void {
- try self.dbi.put(self.idx, self.head);
- }
- fn gen(self: Self) !K {
- // TODO: limit loop
- while (true) {
- const k = try Prng.gen(self.dbi, K);
- if (!try self.dbi.has(self.item_idx(k))) {
- return k;
- }
- }
- }
- pub fn append(self: *Self, v: V) !K {