`Item`s in `StringHashMap` or `ArrayList`

I am making a password manager, and I have vault Items stored in a hashmap, should I add the name to the Item or keep the name in the StringHashMap?

This highly depends on your usage needs - e.g. the size of the dataset, which operations need to be fastest, how big the names are, etc.

Can you describe the problem space more?

I am working on a password manager, and the main data structure is a Vault and this is in the core library, which I want to be used for multiple different apps.

Here are the sides:

  • The CLI uses a key to access data from the StringHashMap
  • If in the future I make a web UI, I think an ArrayList would be more appropiate, because the Item would be rendered as a list, and the search wouldn’t be exact keys

Here is the repo if you want to look at the code, it is very work in progress: https://codeberg.org/Vexo413/zpass.

Maybe you can try this:

pub const std = @import("std");

pub const Item = struct {
    key: []u8,
    payload: u64,
};

pub const KeyContext = struct {
    pub fn hash(self: @This(), item: Item) u64 {
        _ = self;
        return std.hash_map.hashString(item.key);
    }
    pub fn eql(self: @This(), a: Item, b: Item) bool {
        _ = self;
        return std.hash_map.eqlString(a.key, b.key);
    }
};

pub const PseudoKeyContext = struct {
    pub fn hash(self: @This(), s: []const u8) u64 {
        _ = self;
        return std.hash_map.hashString(s);
    }
    pub fn eql(self: @This(), a: []const u8, b: Item) bool {
        _ = self;
        return std.hash_map.eqlString(a, b.key);
    }
};

pub const Map = std.HashMapUnmanaged(Item, void, KeyContext, std.hash_map.default_max_load_percentage);

test Map {
    const allocator = std.testing.allocator;
    var map: Map = .empty;
    defer {
        // free all keys before map deinit.
        var rm_it = map.keyIterator();
        while (rm_it.next()) |owned_item| {
            allocator.free(owned_item.key);
        }
        defer map.deinit(allocator);
    }
    const get_ctx: PseudoKeyContext = .{};
    // Insert an item
    const put: Item = .{ .key = try allocator.dupe(u8, "1"), .payload = 1 };
    try map.putContext(allocator, put, {}, .{});
    // find an item
    const get: ?Item = map.getKeyAdapted("1", get_ctx);
    try std.testing.expectEqual(put, get);
}

Have you heard about ArrayHashMap ? Does it help?

No, I haven’t heard of it, should it be used when the list is bigger than 9 items, in the docs it says there is little overhead when there are a small amount of items. My whatever I decide will probably often use a lot more than 9 items. Zig Documentation