mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
add tests for Mutex (#925)
* std/lib: add tests for Mutex Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/collections: add missing import Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * std/collections: add RingBuffer Signed-off-by: Pierre Curto <pierre.curto@gmail.com> --------- Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
@@ -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(<Type>);
|
||||
import std::io;
|
||||
import std::math;
|
||||
|
||||
def ElementPredicate = fn bool(Type *type);
|
||||
|
||||
88
lib/std/collections/ringbuffer.c3
Normal file
88
lib/std/collections/ringbuffer.c3
Normal file
@@ -0,0 +1,88 @@
|
||||
module collections::ringbuffer(<Type, SIZE>);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
26
test/unit/stdlib/collections/ringbuffer.c3
Normal file
26
test/unit/stdlib/collections/ringbuffer.c3
Normal file
@@ -0,0 +1,26 @@
|
||||
module ringbuffer_test @test;
|
||||
import collections::ringbuffer;
|
||||
import std::io;
|
||||
|
||||
def Buffer = RingBuffer(<char, 4>);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user