feat: add len and getAll to collections
This commit is contained in:
1 parent
ca9299e7cb
commit
9f0ee59bf0
1 file changed
+152
@@ -322,3 +322,155 @@ pub const Hash = struct {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(db: *Db, allocator: Allocator, name: []const u8) !usize {
|
||||||
|
const p = try prefix(allocator, name);
|
||||||
|
defer allocator.free(p);
|
||||||
|
var it = try db.scanPrefix(allocator, p);
|
||||||
|
defer it.deinit();
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next()) |_| count += 1;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns every field/value pair currently stored under `name`. Caller
|
||||||
|
/// owns the returned slice and each entry's `field`/`value` buffers.
|
||||||
|
pub fn getAll(db: *Db, allocator: Allocator, name: []const u8) ![]HashField {
|
||||||
|
const p = try prefix(allocator, name);
|
||||||
|
defer allocator.free(p);
|
||||||
|
|
||||||
|
var results = std.ArrayList(HashField).init(allocator);
|
||||||
|
errdefer {
|
||||||
|
for (results.items) |f| f.free(allocator);
|
||||||
|
results.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = try db.scanPrefix(allocator, p);
|
||||||
|
defer it.deinit();
|
||||||
|
while (try it.next()) |entry| {
|
||||||
|
const field = try allocator.dupe(u8, entry.key[p.len..]);
|
||||||
|
errdefer allocator.free(field);
|
||||||
|
const value = try allocator.dupe(u8, entry.value);
|
||||||
|
try results.append(.{ .field = field, .value = value });
|
||||||
|
}
|
||||||
|
return results.toOwnedSlice();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Set
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub const Set = struct {
|
||||||
|
fn prefix(allocator: Allocator, name: []const u8) ![]u8 {
|
||||||
|
var out = std.ArrayList(u8).init(allocator);
|
||||||
|
errdefer out.deinit();
|
||||||
|
try out.append(nsTag);
|
||||||
|
try appendSegment(&out, "S");
|
||||||
|
try appendSegment(&out, name);
|
||||||
|
return out.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memberKey(allocator: Allocator, name: []const u8, member: []const u8) ![]u8 {
|
||||||
|
var out = std.ArrayList(u8).init(allocator);
|
||||||
|
errdefer out.deinit();
|
||||||
|
try out.append(nsTag);
|
||||||
|
try appendSegment(&out, "S");
|
||||||
|
try appendSegment(&out, name);
|
||||||
|
try out.appendSlice(member);
|
||||||
|
return out.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the member was newly added (false if already present).
|
||||||
|
pub fn add(db: *Db, allocator: Allocator, name: []const u8, member: []const u8) !bool {
|
||||||
|
if (try isMember(db, allocator, name, member)) return false;
|
||||||
|
const k = try memberKey(allocator, name, member);
|
||||||
|
defer allocator.free(k);
|
||||||
|
try db.put(k, &.{});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the member was present and has been removed.
|
||||||
|
pub fn remove(db: *Db, allocator: Allocator, name: []const u8, member: []const u8) !bool {
|
||||||
|
if (!try isMember(db, allocator, name, member)) return false;
|
||||||
|
const k = try memberKey(allocator, name, member);
|
||||||
|
defer allocator.free(k);
|
||||||
|
try db.delete(k);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isMember(db: *Db, allocator: Allocator, name: []const u8, member: []const u8) !bool {
|
||||||
|
const k = try memberKey(allocator, name, member);
|
||||||
|
defer allocator.free(k);
|
||||||
|
const raw = try db.get(allocator, k) orelse return false;
|
||||||
|
allocator.free(raw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn card(db: *Db, allocator: Allocator, name: []const u8) !usize {
|
||||||
|
const members_ = try members(db, allocator, name);
|
||||||
|
defer {
|
||||||
|
for (members_) |m| allocator.free(m);
|
||||||
|
allocator.free(members_);
|
||||||
|
}
|
||||||
|
return members_.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns every member currently in the set. Caller owns the slice and
|
||||||
|
/// each element.
|
||||||
|
pub fn members(db: *Db, allocator: Allocator, name: []const u8) ![][]u8 {
|
||||||
|
const p = try prefix(allocator, name);
|
||||||
|
defer allocator.free(p);
|
||||||
|
|
||||||
|
var results = std.ArrayList([]u8).init(allocator);
|
||||||
|
errdefer {
|
||||||
|
for (results.items) |m| allocator.free(m);
|
||||||
|
results.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = try db.scanPrefix(allocator, p);
|
||||||
|
defer it.deinit();
|
||||||
|
while (try it.next()) |entry| {
|
||||||
|
try results.append(try allocator.dupe(u8, entry.key[p.len..]));
|
||||||
|
}
|
||||||
|
return results.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn containsSorted(haystack: [][]const u8, needle: []const u8) bool {
|
||||||
|
for (haystack) |h| {
|
||||||
|
if (std.mem.eql(u8, h, needle)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Members present in every one of `names`. Caller owns the result.
|
||||||
|
pub fn intersect(db: *Db, allocator: Allocator, names: []const []const u8) ![][]u8 {
|
||||||
|
var results = std.ArrayList([]u8).init(allocator);
|
||||||
|
errdefer {
|
||||||
|
for (results.items) |m| allocator.free(m);
|
||||||
|
results.deinit();
|
||||||
|
}
|
||||||
|
if (names.len == 0) return results.toOwnedSlice();
|
||||||
|
|
||||||
|
const first = try members(db, allocator, names[0]);
|
||||||
|
defer {
|
||||||
|
for (first) |m| allocator.free(m);
|
||||||
|
allocator.free(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
outer: for (first) |candidate| {
|
||||||
|
for (names[1..]) |other| {
|
||||||
|
if (!try isMember(db, allocator, other, candidate)) continue :outer;
|
||||||
|
}
|
||||||
|
try results.append(try allocator.dupe(u8, candidate));
|
||||||
|
}
|
||||||
|
return results.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Members present in any of `names`, deduplicated. Caller owns the result.
|
||||||
|
pub fn unionOf(db: *Db, allocator: Allocator, names: []const []const u8) ![][]u8 {
|
||||||
|
var results = std.ArrayList([]u8).init(allocator);
|
||||||
|
errdefer {
|
||||||
|
for (results.items) |m| allocator.free(m);
|
||||||
|
results.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user