aboutsummaryrefslogtreecommitdiff
path: root/src/hive_array.zig
blob: fd6835396667245e1dd5ac78a6a8957a122d14cd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const testing = std.testing;

/// An array that efficiently tracks which elements are in use.
/// The pointers are intended to be stable
/// Sorta related to https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0447r15.html
pub fn HiveArray(comptime T: type, comptime capacity: u16) type {
    return struct {
        const Self = @This();
        buffer: [capacity]T = undefined,
        available: std.bit_set.IntegerBitSet(capacity) = std.bit_set.IntegerBitSet(capacity).initFull(),
        pub const size = capacity;

        pub fn init() Self {
            return .{};
        }

        pub fn get(self: *Self) ?*T {
            const index = self.available.findFirstSet() orelse return null;
            self.available.unset(index);
            return &self.buffer[index];
        }

        pub fn at(self: *Self, index: u16) *T {
            assert(index < capacity);
            return &self.buffer[index];
        }

        pub fn claim(self: *Self, index: u16) void {
            assert(index < capacity);
            assert(self.available.isSet(index));
            self.available.unset(index);
        }

        pub fn indexOf(self: *const Self, value: *const T) ?u32 {
            const start = &self.buffer;
            const end = @as([*]const T, @ptrCast(start)) + capacity;
            if (!(@intFromPtr(value) >= @intFromPtr(start) and @intFromPtr(value) < @intFromPtr(end)))
                return null;

            // aligned to the size of T
            const index = (@intFromPtr(value) - @intFromPtr(start)) / @sizeOf(T);
            assert(index < capacity);
            assert(&self.buffer[index] == value);
            return @as(u32, @intCast(index));
        }

        pub fn in(self: *const Self, value: *const T) bool {
            const start = &self.buffer;
            const end = @as([*]const T, @ptrCast(start)) + capacity;
            return (@intFromPtr(value) >= @intFromPtr(start) and @intFromPtr(value) < @intFromPtr(end));
        }

        pub fn put(self: *Self, value: *T) bool {
            const index = self.indexOf(value) orelse return false;

            assert(!self.available.isSet(index));
            assert(&self.buffer[index] == value);

            value.* = undefined;

            self.available.set(index);
            return true;
        }

        pub const Fallback = struct {
            hive: HiveArray(T, capacity),
            allocator: std.mem.Allocator,

            pub const This = @This();

            pub fn init(allocator: std.mem.Allocator) This {
                return .{
                    .allocator = allocator,
                    .hive = HiveArray(T, capacity).init(),
                };
            }

            pub fn get(self: *This) *T {
                if (self.hive.get()) |value| {
                    return value;
                }

                return self.allocator.create(T) catch unreachable;
            }

            pub fn tryGet(self: *This) !*T {
                if (self.hive.get()) |value| {
                    return value;
                }

                return try self.allocator.create(T);
            }

            pub fn put(self: *This, value: *T) void {
                if (self.hive.put(value)) return;

                self.allocator.destroy(value);
            }
        };
    };
}

test "HiveArray" {
    const size = 64;

    // Choose an integer with a weird alignment
    const Int = u127;

    var a = HiveArray(Int, size).init();

    {
        var b = a.get().?;
        try testing.expect(a.get().? != b);
        try testing.expectEqual(a.indexOf(b), 0);
        try testing.expect(a.put(b));
        try testing.expect(a.get().? == b);
        var c = a.get().?;
        c.* = 123;
        var d: Int = 12345;
        try testing.expect(a.put(&d) == false);
        try testing.expect(a.in(&d) == false);
    }

    a.available = @TypeOf(a.available).initFull();
    {
        var i: u63 = 0;
        while (i < size) {
            var b = a.get().?;
            try testing.expectEqual(a.indexOf(b), i);
            try testing.expect(a.put(b));
            try testing.expect(a.get().? == b);
            i = i + 1;
        }
        i = 0;
        while (i < size) : (i += 1) {
            try testing.expect(a.get() == null);
        }
    }
}
d>-14/+10 2022-07-05Fix bug in ffiGravatar Jarred Sumner 2-4/+4 2022-07-05[bun-framework-next] BumpGravatar Jarred Sumner 4-5/+5 2022-07-05Clean up some benchmarksGravatar Jarred Sumner 5-3/+102 2022-07-04[bench] react hello worldGravatar Jarred Sumner 4-8/+220 2022-07-04Update DockerfileGravatar Jarred Sumner 1-1/+1 2022-07-04[internal] Don't need to run jsc-bindings-headers in CIGravatar Jarred Sumner 2-12/+1 2022-07-04once moreGravatar Jarred Sumner 1-1/+4 2022-07-04[internal] Fix build script on old nodeGravatar Jarred Sumner 1-0/+7 2022-07-04Handle global require("string")Gravatar Jarred Sumner 4-19/+30 2022-07-04Fix case in dynamic require()Gravatar Jarred Sumner 2-5/+24 2022-07-04[internal] Fix duplicate symbol issueGravatar Jarred Sumner 1-3/+0 2022-07-04Fix npm peer dep issueGravatar Jarred Sumner 2-2/+3 2022-07-04[bench] Add a react ssr hello worldGravatar Jarred Sumner 2-0/+37 2022-07-04Update bun.lockbGravatar Jarred Sumner 1-0/+0 2022-07-04Update README.mdGravatar Jarred Sumner 1-15/+6 2022-07-04[resolver] Add a test for self-referencing package.json exportsGravatar Jarred Sumner 1-0/+44 2022-07-04Bump docker build of webkitGravatar Jarred Sumner 1-1/+1 2022-07-04[itnernal] Cleanup some of the streams codeGravatar Jarred Sumner 7-792/+846 2022-07-04[internal] Add a note explaining what to do if this failsGravatar Jarred Sumner 1-0/+4 2022-07-04[jsc] Handle promise ownership (might revert this)Gravatar Jarred Sumner 1-3/+8 2022-07-04[jsc] Run JSC's deferredWorkTimer sometimesGravatar Jarred Sumner 1-1/+1 2022-07-04[jsc] Attempt to make detecting ArrayBuffer/Uint8Array fasterGravatar Jarred Sumner 1-13/+128 2022-07-04[server] Clean up some of the logic for freeing ReadableStreamGravatar Jarred Sumner 1-3/+30 2022-07-04Update __global.zigGravatar Jarred Sumner 1-4/+4 2022-07-04[jsc] Make JSC own the memory for source code stringsGravatar Jarred Sumner 2-19/+40