Created
November 12, 2024 02:52
-
-
Save jordanisaacs/4472c187f3a5903279c53e56b527d970 to your computer and use it in GitHub Desktop.
Invalid Pointer (with atomic support)
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"); | |
pub fn InvalidPtr(T: anytype, constant: bool) type { | |
const PtrType = blk: { | |
if (constant) { | |
break :blk ?*const T; | |
} else { | |
break :blk ?*T; | |
} | |
}; | |
const invalidVal: usize = @bitCast(@as(isize, -1)); | |
return packed struct(usize) { | |
const Self = @This(); | |
ptr: usize, | |
fn initInvalid() Self { | |
return .{ .ptr = invalidVal}; | |
} | |
fn init(ptr: PtrType) Self { | |
return .{ .ptr = @intFromPtr(ptr) }; | |
} | |
fn isInvalid(self: *const @This()) bool { | |
return self.ptr == invalidVal; | |
} | |
fn set(self: *@This(), ptr: PtrType) void { | |
self.ptr = @intFromPtr(ptr); | |
return; | |
} | |
fn setInvalid(self: *@This()) void { | |
self.ptr = null; | |
} | |
fn get(self: *const @This()) PtrType { | |
std.debug.assert(!self.isInvalid()); | |
return @ptrFromInt(self.ptr); | |
} | |
}; | |
} | |
test "Invalid Ptr const" { | |
const InvalidUsize = InvalidPtr(usize, true); | |
var invalidPtr = InvalidUsize.initInvalid(); | |
try std.testing.expect(invalidPtr.isInvalid()); | |
const val: usize = 1; | |
invalidPtr.set(&val); | |
try std.testing.expectEqual(&val, invalidPtr.get()); | |
try std.testing.expectEqual(val, invalidPtr.get().?.*); | |
invalidPtr.set(null); | |
try std.testing.expectEqual(null, invalidPtr.get()); | |
} | |
test "Invalid Ptr non-const" { | |
const InvalidUsize = InvalidPtr(usize, false); | |
var invalidPtr: InvalidUsize = InvalidUsize.initInvalid(); | |
try std.testing.expect(invalidPtr.isInvalid()); | |
var val: usize = 1; | |
invalidPtr.set(&val); | |
try std.testing.expectEqual(&val, invalidPtr.get().?); | |
try std.testing.expectEqual(val, invalidPtr.get().?.*); | |
const t = invalidPtr.get(); | |
t.?.* = 10; | |
try std.testing.expectEqual(&val, invalidPtr.get().?); | |
try std.testing.expectEqual(val, invalidPtr.get().?.*); | |
} | |
test "Invalid ptr atomic" { | |
const InvalidUsize = InvalidPtr(usize, false); | |
const AtomicInvalidUsize = std.atomic.Value(InvalidUsize); | |
var t = AtomicInvalidUsize.init(InvalidUsize.initInvalid()); | |
try std.testing.expect(t.load(.monotonic).isInvalid()); | |
try std.testing.expect(t.swap(InvalidUsize.init(null), .monotonic).isInvalid()); | |
try std.testing.expectEqual(null, t.load(.monotonic).get()); | |
var val: usize = 10; | |
try std.testing.expectEqual(null, t.swap(InvalidUsize.init(&val), .monotonic).get()); | |
try std.testing.expectEqual(10, t.load(.monotonic).get().?.*); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment