cpptick - reorganie files

This commit is contained in:
erki 2023-10-24 20:31:03 +03:00
parent 72961f2750
commit 80a4f39f7b
5 changed files with 273 additions and 231 deletions

View File

@ -0,0 +1,117 @@
//
// Created by erki on 24/10/23.
//
#pragma once
#include <type_traits>
#include <array>
#include <cstring>
namespace cpptick
{
template<typename T>
concept TrivialClass = std::is_trivial_v<T> && std::is_trivially_destructible_v<T>;
template<typename T>
concept CopyableClass = !TrivialClass<T> && std::copy_constructible<T>;
template<typename T>
concept SlotArgument = TrivialClass<T> || CopyableClass<T>;
struct ArgStorage
{
std::array<char, sizeof(int) * 12> buffer;
std::array<char*, 12> pointer_buffer;
std::array<char*, 12>::iterator pointer_buffer_head;
std::size_t space_remaining;
ArgStorage() = default;
ArgStorage(const ArgStorage&) = default;
ArgStorage(ArgStorage&&) = default;
void reset()
{
space_remaining = buffer.size();
pointer_buffer_head = pointer_buffer.begin();
*pointer_buffer_head = buffer.data();
}
template<TrivialClass T>
void pushArg(T&& arg)
{
if (pointer_buffer_head == pointer_buffer.end() || space_remaining == 0)
std::exit(1);
void* memory_location = *pointer_buffer_head;
if (std::align(alignof(T), sizeof(T), memory_location, space_remaining) == nullptr)
std::exit(2);
std::memcpy(memory_location, &arg, sizeof(T));
pointer_buffer_head++;
if (pointer_buffer_head != pointer_buffer.end())
{
*pointer_buffer_head = (char*)memory_location + sizeof(T);
space_remaining -= sizeof(T);
}
}
template<CopyableClass T>
void pushArg(T&& arg)
{
if (pointer_buffer_head == pointer_buffer.end() || space_remaining == 0)
std::exit(1);
void* memory_location = *pointer_buffer_head;
if (std::align(alignof(T), sizeof(T), memory_location, space_remaining) == nullptr)
std::exit(2);
new (memory_location) T{arg};
pointer_buffer_head++;
if (pointer_buffer_head != pointer_buffer.end())
{
*pointer_buffer_head = (char*)memory_location + sizeof(T);
space_remaining -= sizeof(T);
}
}
template<TrivialClass T>
void cleanUp(const std::size_t)
{ }
template<CopyableClass T>
void cleanUp(const std::size_t index)
{
T* item = reinterpret_cast<T*>(pointer_buffer[index]);
item->~T();
}
template<typename... Args, size_t... Is>
void cleanUp(std::index_sequence<Is...>)
{
(cleanUp<Args>(Is), ...);
}
template<typename... Args>
void cleanUp()
{
cleanUp<Args...>(std::make_index_sequence<sizeof...(Args)>{});
}
template<SlotArgument T>
T& at(const std::size_t idx)
{
return *((T*)pointer_buffer[idx]);
}
template<SlotArgument T>
const T& at(const std::size_t idx) const
{
return *((T*)pointer_buffer[idx]);
}
};
}

View File

@ -1,235 +1,9 @@
// //
// Created by erki on 12/09/23. // Created by erki on 24/10/23.
// //
#pragma once #pragma once
#include <type_traits> #include "cpptick/argstore.hpp"
#include <memory> #include "cpptick/scheduler.hpp"
#include <array> #include "cpptick/slot.hpp"
#include <cstring>
#include <utility_function.hpp>
#include <utility_ringbuffer.hpp>
namespace cpptick
{
template<typename T>
concept TrivialClass = std::is_trivial_v<T> && std::is_trivially_destructible_v<T>;
template<typename T>
concept CopyableClass = !TrivialClass<T> && std::copy_constructible<T>;
template<typename T>
concept SlotArgument = TrivialClass<T> || CopyableClass<T>;
struct ArgStorage
{
std::array<char, sizeof(int) * 12> buffer;
std::array<char*, 12> pointer_buffer;
std::array<char*, 12>::iterator pointer_buffer_head;
std::size_t space_remaining;
ArgStorage() = default;
ArgStorage(const ArgStorage&) = default;
ArgStorage(ArgStorage&&) = default;
void reset()
{
space_remaining = buffer.size();
pointer_buffer_head = pointer_buffer.begin();
*pointer_buffer_head = buffer.data();
}
template<TrivialClass T>
void pushArg(T&& arg)
{
if (pointer_buffer_head == pointer_buffer.end() || space_remaining == 0)
std::exit(1);
void* memory_location = *pointer_buffer_head;
if (std::align(alignof(T), sizeof(T), memory_location, space_remaining) == nullptr)
std::exit(2);
std::memcpy(memory_location, &arg, sizeof(T));
pointer_buffer_head++;
if (pointer_buffer_head != pointer_buffer.end())
{
*pointer_buffer_head = (char*)memory_location + sizeof(T);
space_remaining -= sizeof(T);
}
}
template<CopyableClass T>
void pushArg(T&& arg)
{
if (pointer_buffer_head == pointer_buffer.end() || space_remaining == 0)
std::exit(1);
void* memory_location = *pointer_buffer_head;
if (std::align(alignof(T), sizeof(T), memory_location, space_remaining) == nullptr)
std::exit(2);
new (memory_location) T{arg};
pointer_buffer_head++;
if (pointer_buffer_head != pointer_buffer.end())
{
*pointer_buffer_head = (char*)memory_location + sizeof(T);
space_remaining -= sizeof(T);
}
}
template<TrivialClass T>
void cleanUp(const std::size_t)
{ }
template<CopyableClass T>
void cleanUp(const std::size_t index)
{
T* item = reinterpret_cast<T*>(pointer_buffer[index]);
item->~T();
}
template<typename... Args, size_t... Is>
void cleanUp(std::index_sequence<Is...>)
{
(cleanUp<Args>(Is), ...);
}
template<typename... Args>
void cleanUp()
{
cleanUp<Args...>(std::make_index_sequence<sizeof...(Args)>{});
}
template<SlotArgument T>
T& at(const std::size_t idx)
{
return *((T*)pointer_buffer[idx]);
}
template<SlotArgument T>
const T& at(const std::size_t idx) const
{
return *((T*)pointer_buffer[idx]);
}
};
struct Scheduler
{
using StoredCall = std::pair<Utility::IFunction<void (ArgStorage&)>*, ArgStorage>;
Utility::Ringbuffer<StoredCall, 12> stored_calls;
void tick()
{
if (!stored_calls.empty())
{
auto* f = stored_calls.begin()->first;
auto& args = stored_calls.begin()->second;
(*f)(args);
stored_calls.pop_front();
}
}
ArgStorage& storeCall(Utility::IFunction<void (ArgStorage&)>* call)
{
// @todo: handle overflow...
// still constructs double.
stored_calls.emplace_back(call, ArgStorage{});
auto& storage = stored_calls.back().second;
storage.reset();
return storage;
}
};
template<typename>
struct Slot;
template<typename R, SlotArgument... Args>
struct Slot<R(Args...)>
{
std::array<Utility::IFunction<R (Args...)>*, 12> signals;
Scheduler* scheduler;
Utility::FunctionOwned<Slot<R(Args...)>, void (ArgStorage&)> invoke_ptr;
Slot() = delete;
explicit Slot(Scheduler* sched)
: scheduler(sched)
, invoke_ptr(*this, &Slot<R(Args...)>::callUp)
{
signals.fill(nullptr);
}
Slot(const Slot&) = delete;
Slot(Slot&&) = delete;
Slot& operator=(const Slot&) = delete;
Slot& operator=(Slot&&) = delete;
void connect(Utility::IFunction<R (Args...)>* signal)
{
for (auto*& callable : signals)
{
if (callable == nullptr)
{
callable = signal;
break;
}
}
}
Utility::IFunction<R (Args...)>* connect(R (*func)(Args...))
{
auto* f = new Utility::Function<R (Args...)>(func);
connect(f);
return f;
}
template<typename Source>
Utility::IFunction<R (Args...)>* connect(Source& src, R (Source::* func)(Args...))
{
auto* f = new Utility::FunctionOwned<Source, R (Args...)>(src, func);
connect(f);
return f;
}
template<size_t... Is>
void callUpFunction(Utility::IFunction<R (Args...)>* func, ArgStorage& args, std::index_sequence<Is...>)
{
(*func)(std::forward<Args>(args.at<Args>(Is))...);
}
void callUpFunction(Utility::IFunction<R (Args...)>* func, ArgStorage& args)
{
callUpFunction(func, args, std::make_index_sequence<sizeof...(Args)>{});
}
void callUp(ArgStorage& args)
{
for (auto* f : signals)
{
if (f)
callUpFunction(f, args);
else
break;
}
args.cleanUp<Args...>();
}
void invoke(Args... args)
{
ArgStorage& storage = scheduler->storeCall(&invoke_ptr);
(storage.pushArg(std::forward<Args>(args)), ...);
}
};
}

View File

@ -0,0 +1,45 @@
//
// Created by erki on 24/10/23.
//
#pragma once
#include <tuple>
#include <utility_function.hpp>
#include <utility_ringbuffer.hpp>
#include "cpptick/argstore.hpp"
namespace cpptick
{
struct Scheduler
{
using StoredCall = std::pair<Utility::IFunction<void (ArgStorage&)>*, ArgStorage>;
Utility::Ringbuffer<StoredCall, 12> stored_calls;
void tick()
{
if (!stored_calls.empty())
{
auto* f = stored_calls.begin()->first;
auto& args = stored_calls.begin()->second;
(*f)(args);
stored_calls.pop_front();
}
}
ArgStorage& storeCall(Utility::IFunction<void (ArgStorage&)>* call)
{
// @todo: handle overflow...
// still constructs double.
stored_calls.emplace_back(call, ArgStorage{});
auto& storage = stored_calls.back().second;
storage.reset();
return storage;
}
};
}

View File

@ -0,0 +1,106 @@
//
// Created by erki on 12/09/23.
//
#pragma once
#include <memory>
#include <array>
#include <cstring>
#include <utility_function.hpp>
#include <utility_ringbuffer.hpp>
#include "cpptick/argstore.hpp"
#include "cpptick/scheduler.hpp"
namespace cpptick
{
template<typename>
struct Slot;
template<typename R, SlotArgument... Args>
struct Slot<R(Args...)>
{
std::array<Utility::IFunction<R (Args...)>*, 12> signals;
Scheduler* scheduler;
Utility::FunctionOwned<Slot<R(Args...)>, void (ArgStorage&)> invoke_ptr;
Slot() = delete;
explicit Slot(Scheduler* sched)
: scheduler(sched)
, invoke_ptr(*this, &Slot<R(Args...)>::callUp)
{
signals.fill(nullptr);
}
Slot(const Slot&) = delete;
Slot(Slot&&) = delete;
Slot& operator=(const Slot&) = delete;
Slot& operator=(Slot&&) = delete;
void connect(Utility::IFunction<R (Args...)>* signal)
{
for (auto*& callable : signals)
{
if (callable == nullptr)
{
callable = signal;
break;
}
}
}
Utility::IFunction<R (Args...)>* connect(R (*func)(Args...))
{
auto* f = new Utility::Function<R (Args...)>(func);
connect(f);
return f;
}
template<typename Source>
Utility::IFunction<R (Args...)>* connect(Source& src, R (Source::* func)(Args...))
{
auto* f = new Utility::FunctionOwned<Source, R (Args...)>(src, func);
connect(f);
return f;
}
template<size_t... Is>
void callUpFunction(Utility::IFunction<R (Args...)>* func, ArgStorage& args, std::index_sequence<Is...>)
{
(*func)(std::forward<Args>(args.at<Args>(Is))...);
}
void callUpFunction(Utility::IFunction<R (Args...)>* func, ArgStorage& args)
{
callUpFunction(func, args, std::make_index_sequence<sizeof...(Args)>{});
}
void callUp(ArgStorage& args)
{
for (auto* f : signals)
{
if (f)
callUpFunction(f, args);
else
break;
}
args.cleanUp<Args...>();
}
void invoke(Args... args)
{
ArgStorage& storage = scheduler->storeCall(&invoke_ptr);
(storage.pushArg(std::forward<Args>(args)), ...);
}
};
}

View File

@ -4,7 +4,7 @@
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
#include <cpptick/cpptick.hpp> #include "cpptick/cpptick.hpp"
namespace namespace
{ {