From f10b7eb25ad135d1b64b68a39dd1f2399a210299 Mon Sep 17 00:00:00 2001 From: audiobird Date: Mon, 14 Apr 2025 12:53:17 -0700 Subject: [PATCH 1/9] Remove duplicate code --- util/callable.hh | 105 +++++++++++------------------------------------ 1 file changed, 24 insertions(+), 81 deletions(-) diff --git a/util/callable.hh b/util/callable.hh index 91b4431..9c61a13 100644 --- a/util/callable.hh +++ b/util/callable.hh @@ -13,105 +13,40 @@ // (which shouldn't happen, since the point of this is to avoid the heap, // but it could...) -template -class CallbackSized { -private: - // static constexpr unsigned BUFFER_SIZE = 2 * sizeof(void *); - -public: - CallbackSized() = default; - - template - CallbackSized(Callable callable) { - static_assert(sizeof(Callable) <= BUFFER_SIZE); - static_assert(std::is_invocable_v); - - new (&m_data[0]) Callable(callable); - m_callback = invoke; - m_destroy = destroy; - } - - ~CallbackSized() { - if (m_destroy) - m_destroy(&m_data[0]); - } - - void call() { - // if (m_callback) - m_callback(&m_data[0]); - return; - } - - void operator()() { - call(); - } - - operator bool() { - return m_callback; - } - -private: - template - static void invoke(void *object) { - Callable &callable = *reinterpret_cast(object); - callable(); - } - - template - static void destroy(void *object) { - Callable &callable = *reinterpret_cast(object); - callable.~Callable(); - } - -private: - using CallbackM = void (*)(void *); - CallbackM m_callback{}; - - using Deleter = void (*)(void *); - Deleter m_destroy{}; - - alignas(uint64_t) uint8_t m_data[BUFFER_SIZE]; -}; - -using Callback = CallbackSized<2 * sizeof(void *)>; - // Function is a callback that takes parameters and returns something -template -struct Function {}; - -template -class Function { -private: - static constexpr uint8_t BUFFER_SIZE = 2 * sizeof(void *); +template +struct FunctionSized {}; +template +class FunctionSized { public: - Function() = default; + FunctionSized() = default; template - Function(Callable callable) { - static_assert(sizeof(Callable) <= BUFFER_SIZE); - static_assert(std::is_invocable_v); - + requires(sizeof(Callable) <= buffer_size && std::is_invocable_v) + FunctionSized(Callable callable) + : m_callback{invoke} + , m_destroy{destroy} { new (&m_data[0]) Callable(callable); - m_callback = invoke; - m_destroy = destroy; } - ~Function() { + ~FunctionSized() { if (m_destroy) m_destroy(&m_data[0]); } Ret call(Args... args) { - if (m_callback) - return m_callback(&m_data[0], std::forward(args)...); - return Ret(); + return m_callback(&m_data[0], std::forward(args)...); } Ret operator()(Args... args) { return call(std::forward(args)...); } + operator bool() const { + return m_callback; + } + private: template static Ret invoke(void *object, Args... args) { @@ -132,5 +67,13 @@ private: using Deleter = void (*)(void *); Deleter m_destroy{}; - alignas(uint64_t) uint8_t m_data[BUFFER_SIZE]; + alignas(uint64_t) uint8_t m_data[buffer_size]; }; + +template +using Function = FunctionSized; + +template +using CallbackSized = FunctionSized; + +using Callback = CallbackSized<2 * sizeof(void *)>; From 66605f40877fb11542e60ddbf734673e533aa039 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 09:43:50 -0700 Subject: [PATCH 2/9] Add tests for CallbackSized and Callback --- tests/callable_tests.cc | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/callable_tests.cc b/tests/callable_tests.cc index a726b0b..98ec900 100644 --- a/tests/callable_tests.cc +++ b/tests/callable_tests.cc @@ -48,3 +48,58 @@ TEST_CASE("Callable Function lots of params") { CHECK(func(10, 10.f, 'a', {}, {2, 'a', 1.2f, 1.4}) == 137); CHECK(capture == 20); } + +TEST_CASE("FunctionSized") { + // This fails to compile (which is what we want) + // auto capture{0}; + // auto capture2{0}; + // auto capture3{0}; + // auto func = Function{[&](int a, int b) { + // capture += 10; + // capture2 += 10; + // capture3 += 10; + // return a + b + capture; + // }}; + + auto capture{0}; + auto capture2{0}; + auto capture3{0}; + auto func = FunctionSized{[&](int a, int b) { + capture += 10; + capture2 += 10; + capture3 += 10; + return a + b + capture; + }}; +} + +TEST_CASE("Callable") { + auto capture{0}; + + auto func = Callback{[&capture] { + capture += 10; + return capture; + }}; + + func(); + CHECK(capture == 10); + func(); + CHECK(capture == 20); +} + +TEST_CASE("CallableSized") { + auto capture{0}; + auto capture2{0}; + auto capture3{0}; + + auto func = CallbackSized{[&] { + capture += 10; + capture2 += 10; + capture3 += 10; + return capture; + }}; + + func(); + CHECK(capture3 == 10); + func(); + CHECK(capture3 == 20); +} From b3177c0c56a92bbcbbad5805a3a276f74cebe44a Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 09:50:01 -0700 Subject: [PATCH 3/9] Fix Callback when return type is void --- util/callable.hh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/util/callable.hh b/util/callable.hh index 9c61a13..7648757 100644 --- a/util/callable.hh +++ b/util/callable.hh @@ -51,7 +51,10 @@ private: template static Ret invoke(void *object, Args... args) { Callable &callable = *reinterpret_cast(object); - return callable(std::forward(args)...); + if constexpr (std::is_same_v) + callable(std::forward(args)...); + else + return callable(std::forward(args)...); } template From e609a07374a011366f2ebff6c426ea19aa42a324 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 09:53:38 -0700 Subject: [PATCH 4/9] CI: add more gcc and clang versions --- .github/workflows/c-cpp.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 8ab8512..fdbeba8 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -11,19 +11,11 @@ jobs: build: strategy: matrix: - os: [ubuntu-22.04] - cxx: [g++-12, g++-11, clang++-15, clang++-14] + os: [ubuntu-22.04, ubuntu-24.04] + cxx: [g++-14, g++-13, g++-12, g++-11, clang++-19, clang++-18, clang++-17, clang++-16, clang++-15 ] include: - os: macos-latest cxx: clang++ - - os: ubuntu-24.04 - cxx: g++-13 - - os: ubuntu-24.04 - cxx: clang++-16 - - os: ubuntu-24.04 - cxx: clang++-17 - - os: ubuntu-24.04 - cxx: clang++-18 runs-on: ${{ matrix.os }} From f754eac02547ad08d1bee63d91c1e3c3f6c45eaf Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 09:57:06 -0700 Subject: [PATCH 5/9] CI: exclude some compilers --- .github/workflows/c-cpp.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index fdbeba8..5485208 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -16,6 +16,11 @@ jobs: include: - os: macos-latest cxx: clang++ + exclude: + - os: ubuntu-22.04 + cxx: [clang++-17, clang++-18, clang++-19] + - os: ubuntu-24.04 + cxx: [clang++-15, g++-11] runs-on: ${{ matrix.os }} From 0df8af422241e29f9f56d46d409645f1872bdff7 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 09:59:39 -0700 Subject: [PATCH 6/9] CI: --- .github/workflows/c-cpp.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 5485208..fc97b16 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -18,9 +18,17 @@ jobs: cxx: clang++ exclude: - os: ubuntu-22.04 - cxx: [clang++-17, clang++-18, clang++-19] + cxx: clang++-16 + - os: ubuntu-22.04 + cxx: clang++-17 + - os: ubuntu-22.04 + cxx: clang++-18 + - os: ubuntu-22.04 + cxx: clang++-19 + - os: ubuntu-24.04 + cxx: clang++-15 - os: ubuntu-24.04 - cxx: [clang++-15, g++-11] + cxx: g++-11 runs-on: ${{ matrix.os }} From 57945b8a43e47755278eddbe6a5a16f2c41b3b19 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 10:00:46 -0700 Subject: [PATCH 7/9] CI: --- .github/workflows/c-cpp.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index fc97b16..21a75c3 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -25,6 +25,11 @@ jobs: cxx: clang++-18 - os: ubuntu-22.04 cxx: clang++-19 + - os: ubuntu-22.04 + cxx: g++-13 + - os: ubuntu-22.04 + cxx: g++-14 + - os: ubuntu-24.04 cxx: clang++-15 - os: ubuntu-24.04 From 6c91528047df5721cc6121ff4ae5ac71596028c7 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 10:01:43 -0700 Subject: [PATCH 8/9] CI --- .github/workflows/c-cpp.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 21a75c3..d3b428b 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, ubuntu-24.04] - cxx: [g++-14, g++-13, g++-12, g++-11, clang++-19, clang++-18, clang++-17, clang++-16, clang++-15 ] + cxx: [g++-14, g++-13, g++-12, g++-11, clang++-18, clang++-17, clang++-16, clang++-15 ] include: - os: macos-latest cxx: clang++ @@ -23,8 +23,6 @@ jobs: cxx: clang++-17 - os: ubuntu-22.04 cxx: clang++-18 - - os: ubuntu-22.04 - cxx: clang++-19 - os: ubuntu-22.04 cxx: g++-13 - os: ubuntu-22.04 From 4498524a310969f6b921bc16bda9c97f2b0f3e39 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Tue, 15 Apr 2025 10:09:26 -0700 Subject: [PATCH 9/9] Add more tests for Callable --- tests/callable_tests.cc | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/callable_tests.cc b/tests/callable_tests.cc index 98ec900..860e7b7 100644 --- a/tests/callable_tests.cc +++ b/tests/callable_tests.cc @@ -103,3 +103,36 @@ TEST_CASE("CallableSized") { func(); CHECK(capture3 == 20); } + +TEST_CASE("~Callable") { + auto capture{0}; + + Callback *func = new Callback{[&capture] { + capture += 10; + return capture; + }}; + + (*func)(); + CHECK(capture == 10); + (*func)(); + CHECK(capture == 20); + + delete func; + + Callback *empty = new Callback(); + delete empty; +} + +TEST_CASE("operator bool") { + auto capture{0}; + + Callback func; + CHECK_FALSE((bool)func); + + func = Callback{[&capture] { + capture += 10; + return capture; + }}; + + CHECK((bool)func); +}