Commit c57ef80c authored by Xavier Thompson's avatar Xavier Thompson

Move optional to fundamental and adapt / arrange deque

parent da6a6cde
...@@ -4,13 +4,17 @@ ...@@ -4,13 +4,17 @@
#include <atomic> #include <atomic>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <type_traits>
#include <utility> #include <utility>
#include <typon/fundamental/optional.hpp>
namespace typon namespace typon
{ {
template <typename T> template <typename T>
requires std::is_trivially_copyable_v<T>
struct RingBuffer struct RingBuffer
{ {
using u8 = std::uint_least8_t; using u8 = std::uint_least8_t;
...@@ -75,57 +79,16 @@ namespace typon ...@@ -75,57 +79,16 @@ namespace typon
}; };
template <typename T>
struct Optional
{
enum State : unsigned char { empty = 0, abort = 1, engaged = 2};
State _state;
union
{
T _value;
};
Optional(State state = empty) noexcept : _state(state) {}
Optional(T value) noexcept : _state(engaged), _value(value) {}
~Optional()
{
if (_state == engaged)
{
std::destroy_at(std::addressof(_value));
}
}
operator bool() noexcept
{
return _state == engaged;
}
State state() noexcept
{
return _state;
}
T * operator->() noexcept
{
return std::addressof(_value);
}
T & operator*() noexcept
{
return _value;
}
};
template <typename T> template <typename T>
struct Deque struct Deque
{ {
using u8 = typename RingBuffer<T>::u8; using u8 = typename RingBuffer<T>::u8;
using u64 = typename RingBuffer<T>::u64; using u64 = typename RingBuffer<T>::u64;
using Array = RingBuffer<T>; using Array = RingBuffer<T>;
using Pop = fdt::optional<T, 2>;
static constexpr typename Pop::template state<0> Empty {};
static constexpr typename Pop::template state<1> Abort {};
using enum std::memory_order; using enum std::memory_order;
...@@ -157,49 +120,48 @@ namespace typon ...@@ -157,49 +120,48 @@ namespace typon
_bottom.store(bottom + 1, relaxed); _bottom.store(bottom + 1, relaxed);
} }
Optional<T> pop() noexcept Pop pop() noexcept
{ {
u64 bottom = _bottom.load(relaxed) - 1; u64 bottom = _bottom.load(relaxed) - 1;
Array * array = _array.load(relaxed); Array * array = _array.load(relaxed);
_bottom.store(bottom, relaxed); _bottom.store(bottom, relaxed);
std::atomic_thread_fence(seq_cst); std::atomic_thread_fence(seq_cst);
u64 top = _top.load(relaxed); u64 top = _top.load(relaxed);
Optional<T> x {}; if (top > bottom)
if (top <= bottom)
{ {
x = array->get(bottom); _bottom.store(top, relaxed);
if (top == bottom) return { Empty };
{ }
if (!_top.compare_exchange_strong(top, top + 1, seq_cst, relaxed)) T x = array->get(bottom);
{ if (top < bottom)
x = {}; {
} return { x };
_bottom.store(bottom + 1, relaxed);
}
} }
else if (!_top.compare_exchange_strong(top, top + 1, seq_cst, relaxed))
{ {
_bottom.store(bottom + 1, relaxed); _bottom.store(top + 1, relaxed);
return { Empty };
} }
return x; _bottom.store(top + 1, relaxed);
return { x };
} }
Optional<T> steal() noexcept Pop steal() noexcept
{ {
u64 top = _top.load(acquire); u64 top = _top.load(acquire);
std::atomic_thread_fence(seq_cst); std::atomic_thread_fence(seq_cst);
u64 bottom = _bottom.load(acquire); u64 bottom = _bottom.load(acquire);
Optional<T> x {};
if (top < bottom) if (top < bottom)
{ {
Array * array = _array.load(consume); Array * array = _array.load(consume);
x = array->get(top); T x = array->get(top);
if (!_top.compare_exchange_strong(top, top + 1, seq_cst, relaxed)) if (!_top.compare_exchange_strong(top, top + 1, seq_cst, relaxed))
{ {
return {Optional<T>::abort}; return { Abort };
} }
return { x };
} }
return x; return { Empty };
} }
}; };
......
...@@ -51,7 +51,7 @@ namespace typon ...@@ -51,7 +51,7 @@ namespace typon
{ {
std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> coroutine) noexcept std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> coroutine) noexcept
{ {
if (Optional continuation = Scheduler::pop()) if (auto continuation = Scheduler::pop())
{ {
return *continuation; return *continuation;
} }
......
#ifndef TYPON_FUNDAMENTAL_OPTIONAL_HPP_INCLUDED
#define TYPON_FUNDAMENTAL_OPTIONAL_HPP_INCLUDED
#include <type_traits>
namespace typon::fdt
{
template <typename T, unsigned char N>
requires std::is_trivially_copyable_v<T>
struct optional
{
static_assert(N > 0, "N must be greater than 0");
template <unsigned char I>
requires (I <= N)
using state = std::integral_constant<unsigned char, I>;
unsigned char _state;
union
{
T _value;
};
optional() noexcept : _state(0) {}
template <unsigned char I>
requires (I < N)
optional(state<I> state) noexcept : _state(state) {}
optional(T value) noexcept : _state(N), _value(value) {}
~optional()
{
if (_state == N)
{
std::destroy_at(std::addressof(_value));
}
}
operator bool() noexcept
{
return _state == N;
}
template <unsigned char I>
bool match(state<I> state) noexcept
{
return state() == _state;
}
T * operator->() noexcept
{
return std::addressof(_value);
}
T & operator*() noexcept
{
return _value;
}
};
}
#endif // TYPON_FUNDAMENTAL_OPTIONAL_HPP_INCLUDED
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include <typon/fundamental/event_count.hpp> #include <typon/fundamental/event_count.hpp>
#include <typon/fundamental/optional.hpp>
#include <typon/fundamental/random.hpp> #include <typon/fundamental/random.hpp>
#include <typon/continuation.hpp> #include <typon/continuation.hpp>
...@@ -20,8 +21,8 @@ namespace typon ...@@ -20,8 +21,8 @@ namespace typon
struct Scheduler struct Scheduler
{ {
using uint = unsigned int; using uint = unsigned int;
using Task = Optional<continuation_handle>;
using Deque = Deque<continuation_handle>; using Deque = Deque<continuation_handle>;
using Task = typename Deque::Pop;
static inline thread_local uint thread_id; static inline thread_local uint thread_id;
...@@ -151,7 +152,7 @@ namespace typon ...@@ -151,7 +152,7 @@ namespace typon
} }
auto key = _notifyer.prepare_wait(); auto key = _notifyer.prepare_wait();
task = _deque.back().steal(); task = _deque.back().steal();
if (task.state() != Task::empty) if (!task.match(Deque::Empty))
{ {
_notifyer.cancel_wait(); _notifyer.cancel_wait();
if (task) if (task)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment