generated from dying-will-bullet/zig-project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
133 additions
and
4 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,78 @@ | ||
const std = @import("std"); | ||
const builtin = @import("builtin"); | ||
const testing = std.testing; | ||
|
||
export fn add(a: i32, b: i32) i32 { | ||
return a + b; | ||
pub fn OnceCell(comptime T: type) type { | ||
if (builtin.single_threaded) { | ||
return @import("./singlethread.zig").OnceCell(T); | ||
} else { | ||
return @import("./multithread.zig").OnceCell(T); | ||
} | ||
} | ||
|
||
test "basic add functionality" { | ||
try testing.expect(add(3, 7) == 10); | ||
pub fn Lazy(comptime T: type, comptime f: fn () T) type { | ||
_ = f; | ||
return struct { | ||
cell: OnceCell(T), | ||
}; | ||
} | ||
|
||
// -------------------------------------------------------------------------------- | ||
// Testing | ||
// -------------------------------------------------------------------------------- | ||
|
||
// var global_number: i32 = 0; | ||
// var global_once = once(incr); | ||
|
||
fn init1() i32 { | ||
return 1; | ||
} | ||
|
||
fn init2() i32 { | ||
return 2; | ||
} | ||
|
||
var c3: i32 = 0; | ||
|
||
fn init3() i32 { | ||
c3 += 1; | ||
return c3; | ||
} | ||
|
||
var cell1 = OnceCell(i32).init(); | ||
var cell2 = OnceCell(i32).init(); | ||
var cell3 = OnceCell(i32).init(); | ||
|
||
test "Once executes its function just once" { | ||
const r1 = cell1.getOrInit(init1); | ||
const r2 = cell1.getOrInit(init1); | ||
const r3 = cell1.getOrInit(init1); | ||
|
||
try testing.expect(r1 == 1); | ||
try testing.expectEqual(r1, r2); | ||
try testing.expectEqual(r2, r3); | ||
|
||
const a1 = cell2.getOrInit(init2); | ||
const a2 = cell2.getOrInit(init2); | ||
const a3 = cell2.getOrInit(init2); | ||
|
||
try testing.expect(a1 == 2); | ||
try testing.expectEqual(a1, a2); | ||
try testing.expectEqual(a2, a3); | ||
} | ||
|
||
test "test multithread " { | ||
var threads: [10]std.Thread = undefined; | ||
defer for (threads) |handle| handle.join(); | ||
|
||
for (&threads) |*handle| { | ||
handle.* = try std.Thread.spawn(.{}, struct { | ||
fn thread_fn(x: u8) void { | ||
_ = x; | ||
_ = cell3.getOrInit(init3); | ||
} | ||
}.thread_fn, .{0}); | ||
} | ||
|
||
try testing.expectEqual(@as(i32, 1), c3); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
const std = @import("std"); | ||
|
||
pub fn OnceCell(comptime T: type) type { | ||
return struct { | ||
cell: T = undefined, | ||
mutex: std.Thread.Mutex = std.Thread.Mutex{}, | ||
done: bool = false, | ||
|
||
const Self = @This(); | ||
|
||
pub fn init() Self { | ||
return Self{}; | ||
} | ||
|
||
pub fn get(self: Self) ?T { | ||
if (self.isInitialize()) { | ||
return self.cell; | ||
} | ||
return null; | ||
} | ||
|
||
// pub fn getPtr(self: Self) ?*T { | ||
// if (self.isInitialize()) { | ||
// return self.cell.ptr; | ||
// } | ||
// return null; | ||
// } | ||
|
||
pub fn getOrInit(self: *Self, comptime f: fn () T) T { | ||
// Fast path check | ||
if (self.get()) |value| { | ||
return value; | ||
} | ||
|
||
return self.initialize(f); | ||
} | ||
|
||
pub fn isInitialize(self: Self) bool { | ||
return @atomicLoad(bool, &self.done, .Acquire); | ||
} | ||
|
||
fn initialize(self: *Self, comptime f: fn () T) T { | ||
@setCold(true); | ||
|
||
self.mutex.lock(); | ||
defer self.mutex.unlock(); | ||
|
||
// The first thread to acquire the mutex gets to run the initializer | ||
|
||
if (!self.done) { | ||
self.cell = f(); | ||
defer @atomicStore(bool, &self.done, true, .Release); | ||
} | ||
return self.cell; | ||
} | ||
}; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pub fn OnceCell(comptime T: type) type { | ||
_ = T; | ||
return struct {}; | ||
} |