Skip to content

Instantly share code, notes, and snippets.

@jordanisaacs
Created November 12, 2024 02:52
Show Gist options
  • Save jordanisaacs/4472c187f3a5903279c53e56b527d970 to your computer and use it in GitHub Desktop.
Save jordanisaacs/4472c187f3a5903279c53e56b527d970 to your computer and use it in GitHub Desktop.
Invalid Pointer (with atomic support)
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