Last active
November 4, 2025 19:48
-
-
Save denisdefreyne/9f954ca824925dd8f0fefdfad48d12ab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const std = @import("std"); | |
| const Self = @This(); | |
| ref_count: u8 = 1, | |
| allocator: std.mem.Allocator, | |
| content: union(enum) { | |
| owned: struct { | |
| data: []const u8, | |
| }, | |
| owned_z: struct { | |
| data: [:0]const u8, | |
| }, | |
| constant_slice: []const u8, | |
| reference_slice: struct { | |
| data: []const u8, | |
| referenced: *Self, | |
| }, | |
| }, | |
| pub fn newFromOwned(allocator: std.mem.Allocator, data: []const u8) error{OutOfMemory}!*Self { | |
| const self = try allocator.create(Self); | |
| self.* = .{ | |
| .allocator = allocator, | |
| .content = .{ .owned = .{ | |
| .data = data, | |
| } }, | |
| }; | |
| return self; | |
| } | |
| pub fn newFromOwnedZ(allocator: std.mem.Allocator, data: [:0]const u8) error{OutOfMemory}!*Self { | |
| const self = try allocator.create(Self); | |
| self.* = .{ | |
| .allocator = allocator, | |
| .content = .{ .owned_z = .{ | |
| .data = data, | |
| } }, | |
| }; | |
| return self; | |
| } | |
| pub fn newFromConstantSlice(allocator: std.mem.Allocator, data: []const u8) error{OutOfMemory}!*Self { | |
| const self = try allocator.create(Self); | |
| self.* = .{ | |
| .allocator = allocator, | |
| .content = .{ .constant_slice = data }, | |
| }; | |
| return self; | |
| } | |
| pub fn newFromReferenceSlice(allocator: std.mem.Allocator, data: []const u8, referenced: *Self) error{OutOfMemory}!*Self { | |
| const self = try allocator.create(Self); | |
| referenced.retain(); | |
| self.* = .{ | |
| .allocator = allocator, | |
| .content = .{ .reference_slice = .{ | |
| .data = data, | |
| .referenced = referenced, | |
| } }, | |
| }; | |
| return self; | |
| } | |
| test "alloc + init + retain + release - owned" { | |
| const wrapped = try std.testing.allocator.dupe(u8, "hi"); | |
| const s = try Self.newFromOwned(std.testing.allocator, wrapped); | |
| defer s.release(); | |
| try std.testing.expectEqualStrings("hi", s.getSlice()); | |
| } | |
| test "alloc + init + retain + release - owned with sentinel" { | |
| const wrapped = try std.testing.allocator.dupeZ(u8, "hi"); | |
| const s = try Self.newFromOwnedZ(std.testing.allocator, wrapped); | |
| defer s.release(); | |
| try std.testing.expectEqualStrings("hi", s.getSlice()); | |
| } | |
| test "alloc + init + retain + release - constant slice" { | |
| const s = try Self.newFromConstantSlice(std.testing.allocator, "hi"); | |
| defer s.release(); | |
| try std.testing.expectEqualStrings("hi", s.getSlice()); | |
| } | |
| test "alloc + init + retain + release - reference slice" { | |
| const wrapped = try std.testing.allocator.dupe(u8, "helloworld"); | |
| const s1 = try Self.newFromOwned(std.testing.allocator, wrapped); | |
| defer s1.release(); | |
| const s2 = try Self.newFromReferenceSlice(std.testing.allocator, s1.getSlice()[4..7], s1); | |
| defer s2.release(); | |
| try std.testing.expectEqualStrings("owo", s2.getSlice()); | |
| } | |
| pub fn getSlice(self: *const Self) []const u8 { | |
| return switch (self.content) { | |
| .owned => |s| s.data, | |
| .owned_z => |s| s.data, | |
| .constant_slice => |s| s, | |
| .reference_slice => |s| s.data, | |
| }; | |
| } | |
| pub fn retain(self: *Self) void { | |
| self.ref_count += 1; | |
| } | |
| pub fn release(self: *Self) void { | |
| self.ref_count -= 1; | |
| if (self.ref_count == 0) { | |
| self.destroy(self.allocator); | |
| } | |
| } | |
| fn destroy(self: *Self, allocator: std.mem.Allocator) void { | |
| // dealloc content | |
| switch (self.content) { | |
| .owned => |s| { | |
| self.allocator.free(s.data); | |
| }, | |
| .owned_z => |s| { | |
| self.allocator.free(s.data); | |
| }, | |
| .constant_slice => { | |
| // do nothing | |
| }, | |
| .reference_slice => |s| { | |
| s.referenced.release(); | |
| }, | |
| } | |
| // dealloc self | |
| allocator.destroy(self); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment