| author | |
| committer | |
| log | a3de27ef3bbc5212b2129ed75bab3503da09b9cf |
| tree | c0b7d12e3d81df6ff1683c8376442efafbcdf803 |
| parent | 55cac65f957fc374e4e369e26bd338f11b8b37ee |
| parent | 88e3a7d6dc7289103b8a644aaf6a63437ff6b6b5 |
| signature |
Improvements for std.atomic.{Int,Bool}4 files changed, 62 insertions(+), 3 deletions(-)
lib/std/atomic/bool.zig+12| ... | @@ -21,14 +21,26 @@ pub const Bool = extern struct { | ... | @@ -21,14 +21,26 @@ pub const Bool = extern struct { |
| 21 | // xchg is only valid rmw operation for a bool | 21 | // xchg is only valid rmw operation for a bool |
| 22 | /// Atomically modifies memory and then returns the previous value. | 22 | /// Atomically modifies memory and then returns the previous value. |
| 23 | pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool { | 23 | pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool { |
| 24 | switch (ordering) { | ||
| 25 | .Monotonic, .Acquire, .Release, .AcqRel, .SeqCst => {}, | ||
| 26 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a RMW operation"), | ||
| 27 | } | ||
| 24 | return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering); | 28 | return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering); |
| 25 | } | 29 | } |
| 26 | 30 | ||
| 27 | pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool { | 31 | pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool { |
| 32 | switch (ordering) { | ||
| 33 | .Unordered, .Monotonic, .Acquire, .SeqCst => {}, | ||
| 34 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"), | ||
| 35 | } | ||
| 28 | return @atomicLoad(bool, &self.unprotected_value, ordering); | 36 | return @atomicLoad(bool, &self.unprotected_value, ordering); |
| 29 | } | 37 | } |
| 30 | 38 | ||
| 31 | pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void { | 39 | pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void { |
| 40 | switch (ordering) { | ||
| 41 | .Unordered, .Monotonic, .Release, .SeqCst => {}, | ||
| 42 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a store operation"), | ||
| 43 | } | ||
| 32 | @atomicStore(bool, &self.unprotected_value, value, ordering); | 44 | @atomicStore(bool, &self.unprotected_value, value, ordering); |
| 33 | } | 45 | } |
| 34 | }; | 46 | }; |
lib/std/atomic/int.zig+15| ... | @@ -10,6 +10,9 @@ const testing = std.testing; | ... | @@ -10,6 +10,9 @@ const testing = std.testing; |
| 10 | 10 | ||
| 11 | /// Thread-safe, lock-free integer | 11 | /// Thread-safe, lock-free integer |
| 12 | pub fn Int(comptime T: type) type { | 12 | pub fn Int(comptime T: type) type { |
| 13 | if (!std.meta.trait.isIntegral(T)) | ||
| 14 | @compileError("Expected integral type, got '" ++ @typeName(T) ++ "'"); | ||
| 15 | |||
| 13 | return extern struct { | 16 | return extern struct { |
| 14 | unprotected_value: T, | 17 | unprotected_value: T, |
| 15 | 18 | ||
| ... | @@ -21,14 +24,26 @@ pub fn Int(comptime T: type) type { | ... | @@ -21,14 +24,26 @@ pub fn Int(comptime T: type) type { |
| 21 | 24 | ||
| 22 | /// Read, Modify, Write | 25 | /// Read, Modify, Write |
| 23 | pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T { | 26 | pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T { |
| 27 | switch (ordering) { | ||
| 28 | .Monotonic, .Acquire, .Release, .AcqRel, .SeqCst => {}, | ||
| 29 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a RMW operation"), | ||
| 30 | } | ||
| 24 | return @atomicRmw(T, &self.unprotected_value, op, operand, ordering); | 31 | return @atomicRmw(T, &self.unprotected_value, op, operand, ordering); |
| 25 | } | 32 | } |
| 26 | 33 | ||
| 27 | pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T { | 34 | pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T { |
| 35 | switch (ordering) { | ||
| 36 | .Unordered, .Monotonic, .Acquire, .SeqCst => {}, | ||
| 37 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"), | ||
| 38 | } | ||
| 28 | return @atomicLoad(T, &self.unprotected_value, ordering); | 39 | return @atomicLoad(T, &self.unprotected_value, ordering); |
| 29 | } | 40 | } |
| 30 | 41 | ||
| 31 | pub fn store(self: *Self, value: T, comptime ordering: builtin.AtomicOrder) void { | 42 | pub fn store(self: *Self, value: T, comptime ordering: builtin.AtomicOrder) void { |
| 43 | switch (ordering) { | ||
| 44 | .Unordered, .Monotonic, .Release, .SeqCst => {}, | ||
| 45 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a store operation"), | ||
| 46 | } | ||
| 32 | @atomicStore(T, &self.unprotected_value, value, ordering); | 47 | @atomicStore(T, &self.unprotected_value, value, ordering); |
| 33 | } | 48 | } |
| 34 | 49 |
lib/std/meta/trait.zig+32| ... | @@ -312,6 +312,38 @@ test "std.meta.trait.isNumber" { | ... | @@ -312,6 +312,38 @@ test "std.meta.trait.isNumber" { |
| 312 | testing.expect(!isNumber(NotANumber)); | 312 | testing.expect(!isNumber(NotANumber)); |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | pub fn isIntegral(comptime T: type) bool { | ||
| 316 | return switch (@typeInfo(T)) { | ||
| 317 | .Int, .ComptimeInt => true, | ||
| 318 | else => false, | ||
| 319 | }; | ||
| 320 | } | ||
| 321 | |||
| 322 | test "isIntegral" { | ||
| 323 | testing.expect(isIntegral(u32)); | ||
| 324 | testing.expect(!isIntegral(f32)); | ||
| 325 | testing.expect(isIntegral(@TypeOf(102))); | ||
| 326 | testing.expect(!isIntegral(@TypeOf(102.123))); | ||
| 327 | testing.expect(!isIntegral(*u8)); | ||
| 328 | testing.expect(!isIntegral([]u8)); | ||
| 329 | } | ||
| 330 | |||
| 331 | pub fn isFloat(comptime T: type) bool { | ||
| 332 | return switch (@typeInfo(T)) { | ||
| 333 | .Float, .ComptimeFloat => true, | ||
| 334 | else => false, | ||
| 335 | }; | ||
| 336 | } | ||
| 337 | |||
| 338 | test "isFloat" { | ||
| 339 | testing.expect(!isFloat(u32)); | ||
| 340 | testing.expect(isFloat(f32)); | ||
| 341 | testing.expect(!isFloat(@TypeOf(102))); | ||
| 342 | testing.expect(isFloat(@TypeOf(102.123))); | ||
| 343 | testing.expect(!isFloat(*f64)); | ||
| 344 | testing.expect(!isFloat([]f32)); | ||
| 345 | } | ||
| 346 | |||
| 315 | pub fn isConstPtr(comptime T: type) bool { | 347 | pub fn isConstPtr(comptime T: type) bool { |
| 316 | if (!comptime is(.Pointer)(T)) return false; | 348 | if (!comptime is(.Pointer)(T)) return false; |
| 317 | return @typeInfo(T).Pointer.is_const; | 349 | return @typeInfo(T).Pointer.is_const; |
lib/std/os.zig+3-3| ... | @@ -5214,7 +5214,7 @@ pub const CopyFileRangeError = error{ | ... | @@ -5214,7 +5214,7 @@ pub const CopyFileRangeError = error{ |
| 5214 | 5214 | ||
| 5215 | var has_copy_file_range_syscall = init: { | 5215 | var has_copy_file_range_syscall = init: { |
| 5216 | const kernel_has_syscall = std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true; | 5216 | const kernel_has_syscall = std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true; |
| 5217 | break :init std.atomic.Int(bool).init(kernel_has_syscall); | 5217 | break :init std.atomic.Bool.init(kernel_has_syscall); |
| 5218 | }; | 5218 | }; |
| 5219 | 5219 | ||
| 5220 | /// Transfer data between file descriptors at specified offsets. | 5220 | /// Transfer data between file descriptors at specified offsets. |
| ... | @@ -5246,7 +5246,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len | ... | @@ -5246,7 +5246,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len |
| 5246 | const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok; | 5246 | const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok; |
| 5247 | 5247 | ||
| 5248 | if (std.Target.current.os.tag == .linux and | 5248 | if (std.Target.current.os.tag == .linux and |
| 5249 | (use_c or has_copy_file_range_syscall.get())) | 5249 | (use_c or has_copy_file_range_syscall.load(.Monotonic))) |
| 5250 | { | 5250 | { |
| 5251 | const sys = if (use_c) std.c else linux; | 5251 | const sys = if (use_c) std.c else linux; |
| 5252 | 5252 | ||
| ... | @@ -5271,7 +5271,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len | ... | @@ -5271,7 +5271,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len |
| 5271 | EXDEV => {}, | 5271 | EXDEV => {}, |
| 5272 | // syscall added in Linux 4.5, use fallback | 5272 | // syscall added in Linux 4.5, use fallback |
| 5273 | ENOSYS => { | 5273 | ENOSYS => { |
| 5274 | has_copy_file_range_syscall.set(false); | 5274 | has_copy_file_range_syscall.store(true, .Monotonic); |
| 5275 | }, | 5275 | }, |
| 5276 | else => |err| return unexpectedErrno(err), | 5276 | else => |err| return unexpectedErrno(err), |
| 5277 | } | 5277 | } |