aboutsummaryrefslogtreecommitdiff
path: root/src/allocators.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/allocators.zig')
-rw-r--r--src/allocators.zig291
1 files changed, 46 insertions, 245 deletions
diff --git a/src/allocators.zig b/src/allocators.zig
index 4150a37c8..b29435a2d 100644
--- a/src/allocators.zig
+++ b/src/allocators.zig
@@ -144,14 +144,19 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type {
overflow_list: OverflowListType,
allocator: *Allocator,
+ mutex: Mutex = Mutex.init(),
pub var instance: Self = undefined;
+ pub var loaded = false;
pub fn init(allocator: *std.mem.Allocator) *Self {
- instance = Self{
- .allocator = allocator,
- .overflow_list = OverflowListType{},
- };
+ if (!loaded) {
+ instance = Self{
+ .allocator = allocator,
+ .overflow_list = OverflowListType{},
+ };
+ loaded = true;
+ }
return &instance;
}
@@ -175,6 +180,8 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type {
}
pub fn append(self: *Self, value: ValueType) !IndexType {
+ self.mutex.lock();
+ defer self.mutex.unlock();
var result = IndexType{ .index = std.math.maxInt(u31), .is_overflow = backing_buf_used > max_index };
if (result.is_overflow) {
result.index = @intCast(u31, self.overflow_list.items.len);
@@ -192,6 +199,9 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type {
}
pub const Pair = struct { index: IndexType, value: *ValueType };
pub fn appendGet(self: *Self, value: ValueType) !Pair {
+ self.mutex.lock();
+ defer self.mutex.unlock();
+
var result = IndexType{ .index = std.math.maxInt(u31), .is_overflow = backing_buf_used > max_index };
if (result.is_overflow) {
result.index = @intCast(u31, self.overflow_list.items.len);
@@ -209,6 +219,9 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type {
}
pub fn update(self: *Self, result: *IndexType, value: ValueType) !*ValueType {
+ self.mutex.lock();
+ defer self.mutex.unlock();
+
if (result.index.index == NotFound.index or result.index.index == Unassigned.index) {
result.index.is_overflow = backing_buf_used > max_index;
if (result.index.is_overflow) {
@@ -267,7 +280,7 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type {
};
}
-const Mutex = @import("./sync.zig").Mutex;
+const Mutex = @import("./lock.zig").Lock;
/// Append-only list.
/// Stores an initial count in .bss section of the object file
@@ -480,15 +493,21 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
index: IndexMap,
overflow_list: std.ArrayListUnmanaged(ValueType),
allocator: *Allocator,
+ mutex: Mutex = Mutex.init(),
pub var instance: Self = undefined;
+ var loaded: bool = false;
+
pub fn init(allocator: *std.mem.Allocator) *Self {
- instance = Self{
- .index = IndexMap{},
- .allocator = allocator,
- .overflow_list = std.ArrayListUnmanaged(ValueType){},
- };
+ if (!loaded) {
+ instance = Self{
+ .index = IndexMap{},
+ .allocator = allocator,
+ .overflow_list = std.ArrayListUnmanaged(ValueType){},
+ };
+ loaded = true;
+ }
return &instance;
}
@@ -500,6 +519,9 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
pub fn getOrPut(self: *Self, denormalized_key: []const u8) !Result {
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
const _key = Wyhash.hash(Seed, key);
+
+ self.mutex.lock();
+ defer self.mutex.unlock();
var index = try self.index.getOrPut(self.allocator, _key);
if (index.found_existing) {
@@ -522,14 +544,19 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
};
}
- pub fn get(self: *const Self, denormalized_key: []const u8) ?*ValueType {
+ pub fn get(self: *Self, denormalized_key: []const u8) ?*ValueType {
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
const _key = Wyhash.hash(Seed, key);
+ self.mutex.lock();
+ defer self.mutex.unlock();
const index = self.index.get(_key) orelse return null;
return self.atIndex(index);
}
pub fn markNotFound(self: *Self, result: Result) void {
+ self.mutex.lock();
+ defer self.mutex.unlock();
+
self.index.put(self.allocator, result.hash, NotFound) catch unreachable;
}
@@ -544,6 +571,9 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
}
pub fn put(self: *Self, result: *Result, value: ValueType) !*ValueType {
+ self.mutex.lock();
+ defer self.mutex.unlock();
+
if (result.index.index == NotFound.index or result.index.index == Unassigned.index) {
result.index.is_overflow = backing_buf_used > max_index;
if (result.index.is_overflow) {
@@ -576,6 +606,9 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
}
pub fn remove(self: *Self, denormalized_key: []const u8) void {
+ self.mutex.lock();
+ defer self.mutex.unlock();
+
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
const _key = Wyhash.hash(Seed, key);
@@ -671,6 +704,8 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
// 1. Storing the underyling string.
// 2. Making the key accessible at the index.
pub fn putKey(self: *Self, key: anytype, result: *Result) !void {
+ self.map.mutex.lock();
+ defer self.map.mutex.unlock();
var slice: []u8 = undefined;
// Is this actually a slice into the map? Don't free it.
@@ -715,240 +750,6 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
};
}
-pub fn TBSSMap(comptime ValueType: type, comptime count: anytype, store_keys: bool, estimated_key_length: usize) type {
- const max_index = count - 1;
- const BSSMapType = struct {
- pub threadlocal var backing_buf: [count]ValueType = undefined;
- pub threadlocal var backing_buf_used: u16 = 0;
- const Allocator = std.mem.Allocator;
- const Self = @This();
-
- index: IndexMap,
- overflow_list: std.ArrayListUnmanaged(ValueType),
- allocator: *Allocator,
-
- pub threadlocal var instance: Self = undefined;
-
- pub fn init(allocator: *std.mem.Allocator) *Self {
- instance = Self{
- .index = IndexMap{},
- .allocator = allocator,
- .overflow_list = std.ArrayListUnmanaged(ValueType){},
- };
-
- return &instance;
- }
-
- pub fn isOverflowing() bool {
- return backing_buf_used >= @as(u16, count);
- }
-
- pub fn getOrPut(self: *Self, key: []const u8) !Result {
- const _key = Wyhash.hash(Seed, key);
- var index = try self.index.getOrPut(self.allocator, _key);
-
- if (index.found_existing) {
- return Result{
- .hash = _key,
- .index = index.value_ptr.*,
- .status = switch (index.value_ptr.index) {
- NotFound.index => .not_found,
- Unassigned.index => .unknown,
- else => .exists,
- },
- };
- }
- index.value_ptr.* = Unassigned;
-
- return Result{
- .hash = _key,
- .index = Unassigned,
- .status = .unknown,
- };
- }
-
- pub fn get(self: *const Self, key: []const u8) ?*ValueType {
- const _key = Wyhash.hash(Seed, key);
- const index = self.index.get(_key) orelse return null;
- return self.atIndex(index);
- }
-
- pub fn markNotFound(self: *Self, result: Result) void {
- self.index.put(self.allocator, result.hash, NotFound) catch unreachable;
- }
-
- pub fn atIndex(self: *const Self, index: IndexType) ?*ValueType {
- if (index.index == NotFound.index or index.index == Unassigned.index) return null;
-
- if (index.is_overflow) {
- return &self.overflow_list.items[index.index];
- } else {
- return &backing_buf[index.index];
- }
- }
-
- pub fn put(self: *Self, result: *Result, value: ValueType) !*ValueType {
- if (result.index.index == NotFound.index or result.index.index == Unassigned.index) {
- result.index.is_overflow = backing_buf_used > max_index;
- if (result.index.is_overflow) {
- result.index.index = @intCast(u31, self.overflow_list.items.len);
- } else {
- result.index.index = backing_buf_used;
- backing_buf_used += 1;
- if (backing_buf_used >= max_index) {
- self.overflow_list = try @TypeOf(self.overflow_list).initCapacity(self.allocator, count);
- }
- }
- }
-
- try self.index.put(self.allocator, result.hash, result.index);
-
- if (result.index.is_overflow) {
- if (self.overflow_list.items.len == result.index.index) {
- const real_index = self.overflow_list.items.len;
- try self.overflow_list.append(self.allocator, value);
- } else {
- self.overflow_list.items[result.index.index] = value;
- }
-
- return &self.overflow_list.items[result.index.index];
- } else {
- backing_buf[result.index.index] = value;
-
- return &backing_buf[result.index.index];
- }
- }
-
- pub fn remove(self: *Self, key: []const u8) IndexType {
- const _key = Wyhash.hash(Seed, key);
- const index = self.index.get(_key) orelse return;
- defer _ = self.index.remove(_key);
-
- switch (index) {
- NotFound.index, Unassigned.index => {},
- 0...max_index => {
- // if (hasDeinit(ValueType)) {
- // backing_buf[index].deinit();
- // }
- backing_buf[index] = undefined;
- },
- else => {
- const i = index - count;
- if (hasDeinit(ValueType)) {
- self.overflow_list.items[i].deinit();
- }
- self.overflow_list.items[index - count] = undefined;
- },
- }
-
- return index;
- }
- };
- if (!store_keys) {
- return BSSMapType;
- }
-
- return struct {
- map: *BSSMapType,
- const Self = @This();
- pub threadlocal var instance: Self = undefined;
- threadlocal var key_list_buffer: [count * estimated_key_length]u8 = undefined;
- threadlocal var key_list_buffer_used: usize = 0;
- threadlocal var key_list_slices: [count][]u8 = undefined;
- threadlocal var key_list_overflow: std.ArrayListUnmanaged([]u8) = undefined;
-
- pub fn init(allocator: *std.mem.Allocator) *Self {
- instance = Self{
- .map = BSSMapType.init(allocator),
- };
-
- return &instance;
- }
-
- pub fn isOverflowing() bool {
- return instance.map.backing_buf_used >= count;
- }
- pub fn getOrPut(self: *Self, key: []const u8) !Result {
- return try self.map.getOrPut(key);
- }
- pub fn get(self: *Self, key: []const u8) ?*ValueType {
- return @call(.{ .modifier = .always_inline }, BSSMapType.get, .{ self.map, key });
- }
-
- pub fn atIndex(self: *Self, index: IndexType) ?*ValueType {
- return @call(.{ .modifier = .always_inline }, BSSMapType.atIndex, .{ self.map, index });
- }
-
- pub fn keyAtIndex(self: *Self, index: IndexType) ?[]const u8 {
- return switch (index.index) {
- Unassigned.index, NotFound.index => null,
- else => {
- if (!index.is_overflow) {
- return key_list_slices[index.index];
- } else {
- return key_list_overflow.items[index.index];
- }
- },
- };
- }
-
- pub fn put(self: *Self, key: anytype, comptime store_key: bool, result: *Result, value: ValueType) !*ValueType {
- var ptr = try self.map.put(result, value);
- if (store_key) {
- try self.putKey(key, result);
- }
-
- return ptr;
- }
-
- pub fn isKeyStaticallyAllocated(key: anytype) bool {
- return isSliceInBuffer(key, &key_list_buffer);
- }
-
- // There's two parts to this.
- // 1. Storing the underyling string.
- // 2. Making the key accessible at the index.
- pub fn putKey(self: *Self, key: anytype, result: *Result) !void {
- var slice: []u8 = undefined;
-
- // Is this actually a slice into the map? Don't free it.
- if (isKeyStaticallyAllocated(key)) {
- slice = constStrToU8(key);
- } else if (key_list_buffer_used + key.len < key_list_buffer.len) {
- const start = key_list_buffer_used;
- key_list_buffer_used += key.len;
- slice = key_list_buffer[start..key_list_buffer_used];
- std.mem.copy(u8, slice, key);
- } else {
- slice = try self.map.allocator.dupe(u8, key);
- }
-
- if (!result.index.is_overflow) {
- key_list_slices[result.index.index] = slice;
- } else {
- if (@intCast(u31, key_list_overflow.items.len) > result.index.index) {
- const existing_slice = key_list_overflow.items[result.index.index];
- if (!isKeyStaticallyAllocated(existing_slice)) {
- self.map.allocator.free(existing_slice);
- }
- key_list_overflow.items[result.index.index] = slice;
- } else {
- try key_list_overflow.append(self.map.allocator, slice);
- }
- }
- }
-
- pub fn markNotFound(self: *Self, result: Result) void {
- self.map.markNotFound(result);
- }
-
- // For now, don't free the keys.
- pub fn remove(self: *Self, key: string) IndexType {
- return self.map.remove(key);
- }
- };
-}
-
pub inline fn constStrToU8(s: []const u8) []u8 {
return @intToPtr([*]u8, @ptrToInt(s.ptr))[0..s.len];
}