diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 5c498a254..a862f3b4e 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -2,6 +2,7 @@ // Use of self source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. module std::collections::list(); +import std::io; import std::math; def ElementPredicate = fn bool(Type *type); diff --git a/lib/std/collections/ringbuffer.c3 b/lib/std/collections/ringbuffer.c3 new file mode 100644 index 000000000..e60c79179 --- /dev/null +++ b/lib/std/collections/ringbuffer.c3 @@ -0,0 +1,88 @@ +module collections::ringbuffer(); + +struct RingBuffer +{ + Type[SIZE] buf; + usz written; + usz head; +} + +fn void RingBuffer.init(&self) @inline +{ + *self = {}; +} + +fn void RingBuffer.putc(&self, Type c) +{ + if (self.written < SIZE) + { + self.buf[self.written] = c; + self.written++; + } + else + { + self.buf[self.head] = c; + self.head = (self.head + 1) % SIZE; + } +} + +fn Type RingBuffer.getc(&self, usz index) +{ + index %= SIZE; + usz avail = SIZE - self.head; + if (index < avail) + { + return self.buf[self.head + index]; + } + return self.buf[index - avail]; +} + +fn usz RingBuffer.get(&self, usz index, Type[] buffer) +{ + index %= SIZE; + if (self.written < SIZE) + { + if (index >= self.written) return 0; + usz end = self.written - index; + usz n = min(end, buffer.len); + buffer[:n] = self.buf[index:n]; + return n; + } + usz end = SIZE - self.head; + if (index >= end) + { + index -= end; + if (index >= self.head) return 0; + usz n = min(self.head - index, buffer.len); + buffer[:n] = self.buf[index:n]; + return n; + } + if (buffer.len <= SIZE - index) + { + usz n = buffer.len; + buffer[:n] = self.buf[self.head + index:n]; + return n; + } + usz n1 = SIZE - index; + buffer[:n1] = self.buf[self.head + index:n1]; + buffer = buffer[n1..]; + index -= n1; + usz n2 = min(self.head - index, buffer.len); + buffer[:n2] = self.buf[index:n2]; + return n1 + n2; +} + +fn void RingBuffer.push(&self, Type[] buffer) +{ + usz i; + while (self.written < SIZE && i < buffer.len) + { + self.buf[self.written] = buffer[i++]; + self.written++; + } + foreach (c : buffer[i..]) + { + self.buf[self.head] = c; + self.head = (self.head + 1) % SIZE; + } +} \ No newline at end of file diff --git a/lib/std/threads/os/thread_posix.c3 b/lib/std/threads/os/thread_posix.c3 index b312507b0..02d64c8ab 100644 --- a/lib/std/threads/os/thread_posix.c3 +++ b/lib/std/threads/os/thread_posix.c3 @@ -48,7 +48,7 @@ fn void! NativeMutex.lock(&self) /** * @require mtx.is_initialized() : "Mutex was not initialized" **/ -fn void! NativeMutex.lock_timeoutout(&mtx, ulong ms) +fn void! NativeMutex.lock_timeout(&mtx, ulong ms) { /* Try to acquire the lock and, if we fail, sleep for 5ms. */ Errno result; diff --git a/lib/std/threads/os/thread_win32.c3 b/lib/std/threads/os/thread_win32.c3 index 5b1a8b150..806274d05 100644 --- a/lib/std/threads/os/thread_win32.c3 +++ b/lib/std/threads/os/thread_win32.c3 @@ -88,9 +88,9 @@ fn void! NativeMutex.lock(&mtx) /** * @require mtx.timed "Only available for timed locks" **/ -fn void! NativeMutex.lock_timeout(&mtx, uint ms) +fn void! NativeMutex.lock_timeout(&mtx, usz ms) { - switch (win32::waitForSingleObject(mtx.handle, ms)) + switch (win32::waitForSingleObject(mtx.handle, (uint)ms)) { case win32::WAIT_OBJECT_0: break; diff --git a/lib/std/threads/thread.c3 b/lib/std/threads/thread.c3 index d98e266bf..f1d6c194b 100644 --- a/lib/std/threads/thread.c3 +++ b/lib/std/threads/thread.c3 @@ -33,7 +33,7 @@ fault ThreadFault macro void! Mutex.init(&mutex, MutexType type = MUTEX_PLAIN) => NativeMutex.init((NativeMutex*)mutex, type); macro void! Mutex.destroy(&mutex) => NativeMutex.destroy((NativeMutex*)mutex); macro void! Mutex.lock(&mutex) => NativeMutex.lock((NativeMutex*)mutex); -macro void! Mutex.lock_timeout(&mutex, ulong ms) => NativeMutex.lock((NativeMutex*)mutex, ms); +macro void! Mutex.lock_timeout(&mutex, ulong ms) => NativeMutex.lock_timeout((NativeMutex*)mutex, ms); macro bool Mutex.try_lock(&mutex) => NativeMutex.try_lock((NativeMutex*)mutex); macro void! Mutex.unlock(&mutex) => NativeMutex.unlock((NativeMutex*)mutex); @@ -56,7 +56,7 @@ macro void! Thread.detach(thread) => NativeThread.detach((NativeThread)thread); macro int! Thread.join(thread) => NativeThread.join((NativeThread)thread); macro bool Thread.equals(thread, Thread other) => NativeThread.equals((NativeThread)thread, (NativeThread)other); -macro void OnceFlag.call_once(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func); +macro void OnceFlag.call(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func); macro void yield() => os::native_thread_yield(); macro Thread current() => os::native_thread_current(); diff --git a/test/unit/stdlib/collections/ringbuffer.c3 b/test/unit/stdlib/collections/ringbuffer.c3 new file mode 100644 index 000000000..c14ba71ee --- /dev/null +++ b/test/unit/stdlib/collections/ringbuffer.c3 @@ -0,0 +1,26 @@ +module ringbuffer_test @test; +import collections::ringbuffer; +import std::io; + +def Buffer = RingBuffer(); + +fn void putc_getc() +{ + Buffer rb; + rb.init(); + rb.putc(1); + rb.putc(2); + rb.putc(3); + rb.putc(4); + + assert(rb.getc(0) == 1); + assert(rb.getc(1) == 2); + assert(rb.getc(2) == 3); + assert(rb.getc(3) == 4); + + rb.putc(5); + assert(rb.getc(0) == 2); + assert(rb.getc(1) == 3); + assert(rb.getc(2) == 4); + assert(rb.getc(3) == 5); +} \ No newline at end of file diff --git a/test/unit/stdlib/threads/simple_thread.c3 b/test/unit/stdlib/threads/simple_thread.c3 index 13d6249fe..2d541420b 100644 --- a/test/unit/stdlib/threads/simple_thread.c3 +++ b/test/unit/stdlib/threads/simple_thread.c3 @@ -1,6 +1,8 @@ import std::thread; import std::io; + int a; + fn void! testrun() @test { Thread t; @@ -8,6 +10,9 @@ fn void! testrun() @test t.create(fn int(void* arg) { a++; return 0; }, null)!; assert(t.join()! == 0); assert(a == 1); + + t.create(fn int(void* arg) { return 10; }, null)!; + assert(t.join()! == 10); } Mutex m; @@ -34,9 +39,54 @@ fn void! testrun_mutex() @test return 0; }, null)!; } - foreach (i, &t : ts) + foreach (&t : ts) { assert(t.join()! == 0); } assert(a == 100); + m.destroy()!; +} + +fn void! testrun_mutex_try() @test +{ + Mutex m; + m.init()!; + m.lock()!; + assert(m.try_lock() == false); + m.unlock()!; + assert(m.try_lock() == true); + m.unlock()!; +} + +fn void! testrun_mutex_timeout() @test +{ + Mutex m; + m.init()!; + m.lock()!; + if (catch m.lock_timeout(100)) + { + } + else + { + assert(false, "lock_timeout should fail"); + } + m.unlock()!; + m.lock_timeout(100)!; + m.unlock()!; +} + +int x_once = 100; + +fn void call_once() +{ + x_once += 100; +} + +fn void! testrun_once() @test +{ + OnceFlag once; + once.call(&call_once); + assert(x_once == 200); + once.call(&call_once); + assert(x_once == 200); } \ No newline at end of file