From 2dfbc312e6ccb88f838170d8e777d48aacde2ff5 Mon Sep 17 00:00:00 2001 From: johannst Date: Sun, 13 Nov 2022 14:13:35 +0000 Subject: deploy: 026d679006e5d470bacdc74bb3082072edf31e36 --- development/c++/meta4.cc | 104 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 development/c++/meta4.cc (limited to 'development/c++/meta4.cc') diff --git a/development/c++/meta4.cc b/development/c++/meta4.cc new file mode 100644 index 0000000..9c3be77 --- /dev/null +++ b/development/c++/meta4.cc @@ -0,0 +1,104 @@ +// Copyright (C) 2022 johannst + +#include +#include +#include +#include +#include + +template +struct registry { + using FUNC = R (*)(P...); + using SELF = registry; + using RET = R; + + static SELF& get() { + static SELF r; + return r; + } + + bool add(std::string nm, FUNC fn) { + const auto r = m_fns.insert({std::move(nm), std::move(fn)}); + return r.second; + } + + R invoke(const std::string& nm, P... p) const { return invoke_impl(nm, p...); } + + void dump() const { + for (const auto& it : m_fns) { + std::puts(it.first.c_str()); + } + } + + private: + std::map m_fns; + + template + std::enable_if_t> invoke_impl(const std::string& nm, P... p) const { + const auto it = m_fns.find(nm); + if (it == m_fns.end()) { + return; + } + std::invoke(it->second, p...); + } + + template + std::enable_if_t, RET> invoke_impl(const std::string& nm, + P... p) const { + const auto it = m_fns.find(nm); + if (it == m_fns.end()) { + static_assert(std::is_default_constructible_v, + "RET must be default constructible"); + return {}; + } + return std::invoke(it->second, p...); + } +}; + +#define TEST_REGISTER(REGISTRY, NAME) \ + static bool regfn_##REGISTRY##NAME() { \ + const bool r = REGISTRY::get().add(#NAME, NAME); \ + if (!r) { \ + std::puts("Failed to register test " #NAME ", same name already registered!"); \ + std::abort(); \ + } \ + return r; \ + } \ + static const bool reg_##REGISTRY##NAME = regfn_##REGISTRY##NAME(); + +#define TEST(REGISTRY, NAME, ...) \ + REGISTRY::RET NAME(__VA_ARGS__); \ + TEST_REGISTER(REGISTRY, NAME); \ + REGISTRY::RET NAME(__VA_ARGS__) + +// -- Usage 1 simple usage. + +using REG1 = registry; +TEST(REG1, test1) { + std::puts("REG1::test1"); +} +TEST(REG1, test2) { + std::puts("REG1::test2"); +} + +// -- Usage 2 with convenience macro wrapper. + +using REG2 = registry; +#define TEST2(NAME, ...) TEST(REG2, NAME, ##__VA_ARGS__) + +TEST2(test1, bool val) { + printf("REG2::test1 val %d\n", val); +} + +int main() { + const auto& R1 = REG1::get(); + R1.dump(); + R1.invoke("test1"); + R1.invoke("test2"); + + const auto& R2 = REG2::get(); + R2.dump(); + R2.invoke("test1", true); + + return 0; +} -- cgit v1.2.3