Commit c57ef80c authored by Xavier Thompson's avatar Xavier Thompson

Move optional to fundamental and adapt / arrange deque

parent da6a6cde
......@@ -4,13 +4,17 @@
#include <atomic>
#include <cstdint>
#include <memory>
#include <type_traits>
#include <utility>
#include <typon/fundamental/optional.hpp>
namespace typon
{
template <typename T>
requires std::is_trivially_copyable_v<T>
struct RingBuffer
{
using u8 = std::uint_least8_t;
......@@ -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>
struct Deque
{
using u8 = typename RingBuffer<T>::u8;
using u64 = typename RingBuffer<T>::u64;
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;
......@@ -157,49 +120,48 @@ namespace typon
_bottom.store(bottom + 1, relaxed);
}
Optional<T> pop() noexcept
Pop pop() noexcept
{
u64 bottom = _bottom.load(relaxed) - 1;
Array * array = _array.load(relaxed);
_bottom.store(bottom, relaxed);
std::atomic_thread_fence(seq_cst);
u64 top = _top.load(relaxed);
Optional<T> x {};
if (top <= bottom)
if (top > bottom)
{
x = array->get(bottom);
if (top == bottom)
{
if (!_top.compare_exchange_strong(top, top + 1, seq_cst, relaxed))
{
x = {};
}
_bottom.store(bottom + 1, relaxed);
_bottom.store(top, relaxed);
return { Empty };
}
T x = array->get(bottom);
if (top < bottom)
{
return { x };
}
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);
std::atomic_thread_fence(seq_cst);
u64 bottom = _bottom.load(acquire);
Optional<T> x {};
if (top < bottom)
{
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))
{
return {Optional<T>::abort};
return { Abort };
}
return { x };
}
return x;
return { Empty };
}
};
......
......@@ -51,7 +51,7 @@ namespace typon
{
std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> coroutine) noexcept
{
if (Optional continuation = Scheduler::pop())
if (auto continuation = Scheduler::pop())
{
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 @@
#include <vector>
#include <typon/fundamental/event_count.hpp>
#include <typon/fundamental/optional.hpp>
#include <typon/fundamental/random.hpp>
#include <typon/continuation.hpp>
......@@ -20,8 +21,8 @@ namespace typon
struct Scheduler
{
using uint = unsigned int;
using Task = Optional<continuation_handle>;
using Deque = Deque<continuation_handle>;
using Task = typename Deque::Pop;
static inline thread_local uint thread_id;
......@@ -151,7 +152,7 @@ namespace typon
}
auto key = _notifyer.prepare_wait();
task = _deque.back().steal();
if (task.state() != Task::empty)
if (!task.match(Deque::Empty))
{
_notifyer.cancel_wait();
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