From a41d3104dc730d2cba15e1ef290b52e032d6e054 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Fri, 4 Oct 2024 21:13:49 +0200 Subject: variadic: mapping from generic types to common type --- variadic_to_common_type.cc | 132 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 variadic_to_common_type.cc diff --git a/variadic_to_common_type.cc b/variadic_to_common_type.cc new file mode 100644 index 0000000..d8609b5 --- /dev/null +++ b/variadic_to_common_type.cc @@ -0,0 +1,132 @@ +#if 0 +set -xe +trap 'rm -f a.out' EXIT +g++ -std=c++17 -Wall -Wextra -fsanitize=address -fsanitize=undefined variadic_to_common_type.cc && ./a.out | c++filt -t +clang++ -std=c++17 -Wall -Wextra -fsanitize=address -fsanitize=undefined variadic_to_common_type.cc && ./a.out | c++filt -t + +g++ -std=c++17 -Wall -Wextra variadic_to_common_type.cc && ./a.out | c++filt -t +which valgrind && valgrind ./a.out +exit 0 +#endif + +#include +#include + +#include +#include + +// Variadic template arguments to common type. +// +// This shows a method how to map variadic template arguments to a common type +// which can be used further down the processing pipeline. + +struct bytes { + const uint8_t* ptr; + size_t len; +}; + +// -- TO_BYTES CONVERTER ------------------------------------------------------- + +template +constexpr bytes to_bytes(const T& val) { + static_assert(std::is_arithmetic_v, ""); + return {.ptr = reinterpret_cast(&val), .len = sizeof(val)}; +} + +template +constexpr bytes to_bytes(const T (&vals)[N]) { + static_assert(std::is_arithmetic_v, ""); + static_assert(sizeof(vals) == sizeof(T) * N, ""); + return {.ptr = &vals, .len = sizeof(vals)}; +} + +template +constexpr bytes to_bytes(const std::array& vals) { + static_assert(std::is_arithmetic_v, ""); + return {.ptr = reinterpret_cast(vals.data()), + .len = sizeof(T) * N}; +} + +// -- SCALAR GENERATOR & ALIAS ------------------------------------------------- + +// Utility to generate scalar values of a specific type. + +template +struct scalar { + static_assert(std::is_arithmetic_v, ""); + + template + constexpr T operator()(F val) const { + static_assert(std::is_convertible_v, ""); + return static_cast(val); + } +}; + +inline constexpr scalar u64; +inline constexpr scalar f64; + +// -- ARRAY GENERATOR & ALIAS -------------------------------------------------- + +// Utility to generate array values of a specific type. + +template +struct array { + static_assert(std::is_arithmetic_v, ""); + + template + constexpr std::array operator()(F... val) const { + static_assert(is_convertible(), ""); + return {static_cast(val)...}; + } + + // Conversion checker helper. + + template + static constexpr bool is_convertible() { + return std::is_convertible_v; + } + + template + static constexpr bool is_convertible() { + return std::is_convertible_v && is_convertible(); + } +}; + +inline constexpr array u64v; +inline constexpr array f64v; + +// -- SERIALIZER --------------------------------------------------------------- + +// Example consumer of variadic arguments which are mapped to the common `bytes` +// type. + +#include + +#include +#include + +template +void serialize(Args&&... args) { + // auto vals = {to_bytes(args)...}; + std::initializer_list vals = {to_bytes(args)...}; + + for (auto b : vals) { + std::printf("bytes: .ptr=%p .len=%zu -> first by %u\n", b.ptr, b.len, + *b.ptr); + } + + auto vals_with_type = { + std::pair{to_bytes(args), typeid(args).name()}...}; + for (auto p : vals_with_type) { + auto b = p.first; + auto n = p.second; + // Pipe to `c++filt -t` to also interpret type mangling. + std::printf("bytes: .ptr=%p .len=%zu -> type=%s\n", b.ptr, b.len, n); + } +} + +// -- TEST ME ------------------------------------------------------------------ + +int main() { + serialize(u64(1), f64(2), u64v(10, 11, 12, 13), f64v(20.0, 21.0, 22.0)); +} -- cgit v1.2.3