From f04be0ef175b17070a3c19e803c9355cc5f4ce21 Mon Sep 17 00:00:00 2001 From: Adrian Conlon Date: Sun, 24 May 2026 17:48:56 +0100 Subject: [PATCH] Small wins --- inc/ClockedChip.h | 13 ++---- inc/Signal.h | 113 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 13 deletions(-) diff --git a/inc/ClockedChip.h b/inc/ClockedChip.h index 8cb8f81..7b8a620 100644 --- a/inc/ClockedChip.h +++ b/inc/ClockedChip.h @@ -14,14 +14,11 @@ namespace EightBit { [[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; } - void tick() noexcept { - ++m_cycles; - Ticked.fire(); - } - - void tick(int extra) noexcept { - for (int i = 0; i < extra; ++i) - tick(); + void tick(int extra = 1) noexcept { + m_cycles += extra; + if (Ticked.active()) + for (int i = 0; i < extra; ++i) + Ticked.fire(); } protected: diff --git a/inc/Signal.h b/inc/Signal.h index 68a3fbb..de612b5 100644 --- a/inc/Signal.h +++ b/inc/Signal.h @@ -13,15 +13,118 @@ namespace EightBit { delegates_t m_delegates; public: - void connect(const delegate_t functor) { + [[nodiscard]] constexpr auto count() const noexcept { return m_delegates.size(); } + [[nodiscard]] constexpr auto inactive() const noexcept { return count() == 0; } + [[nodiscard]] constexpr auto singular() const noexcept { return count() == 1; } + [[nodiscard]] constexpr auto active() const noexcept { return count() != 0; } + + constexpr void connect(const delegate_t functor) { m_delegates.push_back(functor); } void fire(T& e = EventArgs::empty()) const noexcept { - const auto firing = !m_delegates.empty(); - if (firing) - for (auto& delegate : m_delegates) - delegate(e); + for (auto& delegate : m_delegates) + delegate(e); } }; } + +// +// +//#pragma once +// +//#include +//#include +//#include +//#include "EventArgs.h" +// +//namespace EightBit { +// template class Signal final { +// private: +// using fn_t = void(*)(void*, T&); +// using dtor_t = void(*)(void*); +// +// struct Entry { +// void* ctx; +// fn_t fn; +// dtor_t dtor; // null for inline-stored (trivially-destructible) callables +// }; +// +// int m_count = 0; +// std::vector m_delegates; +// +// void destroy_entries() noexcept { +// for (auto& e : m_delegates) +// if (e.dtor) e.dtor(e.ctx); +// m_delegates.clear(); +// m_count = 0; +// } +// +// public: +// Signal() = default; +// +// // Copies are connection-less: a copied chip instance starts with no listeners +// Signal(const Signal&) noexcept {} +// Signal& operator=(const Signal&) noexcept { destroy_entries(); return *this; } +// +// ~Signal() { destroy_entries(); } +// +// template +// void connect(Callable&& callable) { +// using Decay = std::decay_t; +// +// // [this] lambdas on x64: sizeof == 8 == sizeof(void*), trivially copyable/destructible. +// // Pack the captured pointer directly into the void* slot — zero heap overhead, +// // and the dispatch function knows the concrete type so c(e) can be inlined. +// constexpr bool fits_inline = +// sizeof(Decay) <= sizeof(void*) && +// alignof(Decay) <= alignof(void*) && +// std::is_trivially_copyable_v && +// std::is_trivially_destructible_v; +// +// if constexpr (fits_inline) { +// void* storage = nullptr; +// std::memcpy(&storage, &callable, sizeof(Decay)); +// m_delegates.push_back({ +// storage, +// [](void* raw, T& e) noexcept { +// // Reconstruct the callable from the packed pointer bits. +// // Trivially-copyable, so memcpy into aligned storage is valid. +// alignas(Decay) char buf[sizeof(Decay)]; +// std::memcpy(buf, &raw, sizeof(Decay)); +// (*reinterpret_cast(buf))(e); +// }, +// nullptr +// }); +// } +// else { +// auto* heap = new Decay(std::forward(callable)); +// m_delegates.push_back({ +// static_cast(heap), +// [](void* raw, T& e) noexcept { +// (*static_cast(raw))(e); +// }, +// [](void* raw) noexcept { +// delete static_cast(raw); +// } +// }); +// } +// ++m_count; +// } +// +// [[nodiscard]] constexpr auto count() const noexcept { return m_count; } +// [[nodiscard]] constexpr auto inactive() const noexcept { return count() == 0; } +// [[nodiscard]] constexpr auto singular() const noexcept { return count() == 1; } +// [[nodiscard]] constexpr auto active() const noexcept { return count() != 0; } +// +// void fire(T& e = EventArgs::empty()) const noexcept { +// //if (inactive()) return; +// //if (singular()) { +// // m_delegates[0].fn(m_delegates[0].ctx, e); +// // return; +// //} +// for (const auto& entry : m_delegates) +// entry.fn(entry.ctx, e); +// } +// }; +//}