main
Brett 2025-04-23 15:04:37 -04:00
parent 27c07594a8
commit 84921fffa7
6 changed files with 306 additions and 48 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) include(cmake/color.cmake)
set(BLT_VERSION 5.4.8) set(BLT_VERSION 5.4.9)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

152
include/blt/meta/function.h Normal file
View File

@ -0,0 +1,152 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_META_FUNCTION_H
#define BLT_META_FUNCTION_H
#include <functional>
#include <tuple>
namespace blt::meta
{
struct std_function_tag
{};
struct function_ptr_tag
{};
struct lambda_tag
{};
struct member_function_ptr_tag
{};
template <typename Func>
struct function_like;
template <typename Return, typename... Args>
struct function_like<std::function<Return(Args...)>>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = std_function_tag;
};
template <typename Return, typename... Args>
struct function_like<Return (*)(Args...)>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = function_ptr_tag;
};
template <typename Return, typename... Args>
struct function_like<Return (*)(Args...) noexcept>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = function_ptr_tag;
};
template <typename Return, typename Class, typename... Args>
struct function_like<Return (Class::*)(Args...)>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = member_function_ptr_tag;
using class_type = Class;
};
template <typename Return, typename Class, typename... Args>
struct function_like<Return (Class::*)(Args...) const>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = member_function_ptr_tag;
using class_type = Class;
};
template <typename Return, typename Class, typename... Args>
struct function_like<Return (Class::*)(Args...) noexcept>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = member_function_ptr_tag;
using class_type = Class;
};
template <typename Return, typename Class, typename... Args>
struct function_like<Return (Class::*)(Args...) const noexcept>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using tag = member_function_ptr_tag;
using class_type = Class;
};
template <typename Func>
struct function_like
{
private:
template <typename>
struct lambda_traits
{};
template <typename Return, typename Class, typename... Args>
struct lambda_traits<Return (Class::*)(Args...) const>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using class_type = Class;
};
template <typename Return, typename Class, typename... Args>
struct lambda_traits<Return (Class::*)(Args...) noexcept>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using class_type = Class;
};
template <typename Return, typename Class, typename... Args>
struct lambda_traits<Return (Class::*)(Args...) const noexcept>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using class_type = Class;
};
template <typename Return, typename Class, typename... Args>
struct lambda_traits<Return (Class::*)(Args...)>
{
using return_type = Return;
using args_tuple = std::tuple<Args...>;
using class_type = Class;
};
using lambda_trait = lambda_traits<decltype(&Func::operator())>;
public:
using tag_type = lambda_tag;
using return_type = typename lambda_trait::return_type;
using args_tuple = typename lambda_trait::args_tuple;
using class_type = typename lambda_trait::class_type;
};
}
#endif //BLT_META_FUNCTION_H

View File

@ -0,0 +1,31 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_META_PASSTHROUGH_H
#define BLT_META_PASSTHROUGH_H
namespace blt::meta
{
template <typename T>
struct passthrough
{
using type = T;
};
}
#endif //BLT_META_PASSTHROUGH_H

View File

@ -0,0 +1,80 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_META_FILTER_VOID_H
#define BLT_META_FILTER_VOID_H
#include <tuple>
#include <type_traits>
namespace blt::meta
{
template <typename... Ts>
struct filter_void;
template <>
struct filter_void<>
{
using type = std::tuple<>;
};
template <typename T, typename... Ts>
struct filter_void<T, Ts...>
{
using type = std::conditional_t<std::is_void_v<T>, typename filter_void<Ts...>::type, decltype(std::tuple_cat(
std::declval<std::tuple<T>>(), std::declval<typename filter_void<Ts...>::type>()))>;
};
template <typename... Ts>
struct filter_void<std::tuple<Ts...>>
{
using type = typename filter_void<Ts...>::type;
};
template <typename... Ts>
using filter_void_t = typename filter_void<Ts...>::type;
template <template<typename...> typename Func, typename ArgsTuple, typename... Ts>
struct filter_func;
template <template<typename...> typename Func, typename ArgsTuple>
struct filter_func<Func, ArgsTuple>
{
using type = std::tuple<>;
};
template <template<typename...> typename Func, typename... Args, typename T, typename... Ts>
struct filter_func<Func, std::tuple<Args...>, T, Ts...>
{
using type = std::conditional_t<Func<T, Args...>::value, typename filter_func<Func, std::tuple<Args...>, Ts...>::type, decltype(
std::tuple_cat(std::declval<std::tuple<T>>(),
std::declval<typename filter_func<Func, std::tuple<Args...>, Ts...>::type>()))>;
};
template <template<typename...> typename Func, typename ArgsTuple, typename... Ts>
struct filter_func<Func, ArgsTuple, std::tuple<Ts...>>
{
using type = typename filter_func<Func, ArgsTuple, Ts...>::type;
};
template <template<typename...> typename Func, typename ArgsTuple, typename... Ts>
using filter_func_t = typename filter_func<Func, ArgsTuple, Ts...>::type;
}
#endif //BLT_META_FILTER_VOID_H

View File

@ -24,6 +24,8 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <variant> #include <variant>
#include <blt/meta/passthrough.h>
#include <blt/meta/tuple_filters.h>
#include <blt/std/types.h> #include <blt/std/types.h>
namespace blt namespace blt
@ -33,37 +35,13 @@ namespace blt
namespace detail namespace detail
{ {
template <typename... Ts>
struct filter_void;
template <>
struct filter_void<>
{
using type = std::tuple<>;
};
template <typename T, typename... Ts>
struct filter_void<T, Ts...>
{
using type = std::conditional_t<std::is_void_v<T>, typename filter_void<Ts...>::type, decltype(std::tuple_cat(
std::declval<std::tuple<T>>(), std::declval<typename filter_void<Ts...>::type>()))>;
};
template <typename... Ts>
using filter_void_t = typename filter_void<Ts...>::type;
template<typename T>
struct passthrough
{
using type = T;
};
template <typename Type, typename Func, typename... Args> template <typename Type, typename Func, typename... Args>
struct member_func_meta struct member_func_meta
{ {
using can_invoke = std::is_invocable<Func, Type, Args...>; using can_invoke = std::is_invocable<Func, Type, Args...>;
using return_type = typename std::conditional_t<can_invoke::value, std::invoke_result<Func, Type, Args...>, passthrough<void>>::type; using return_type = typename std::conditional_t<can_invoke::value, std::invoke_result<Func, Type, Args...>, meta::passthrough<void>>::type
;
}; };
template <typename Func, typename ArgsTuple, typename... Types> template <typename Func, typename ArgsTuple, typename... Types>
@ -73,7 +51,7 @@ namespace blt
struct member_call_return_type<Func, std::tuple<Args...>, Types...> struct member_call_return_type<Func, std::tuple<Args...>, Types...>
{ {
using result_types = std::tuple<member_func_meta<Types, Func, Args...>...>; using result_types = std::tuple<member_func_meta<Types, Func, Args...>...>;
using non_void_result_types = typename filter_void<typename member_func_meta<Types, Func, Args...>::return_type...>::type; using non_void_result_types = meta::filter_void_t<typename member_func_meta<Types, Func, Args...>::return_type...>;
static constexpr bool all_void = std::tuple_size_v<non_void_result_types> == 0; static constexpr bool all_void = std::tuple_size_v<non_void_result_types> == 0;
static constexpr bool some_void = std::tuple_size_v<non_void_result_types> != sizeof...(Types); static constexpr bool some_void = std::tuple_size_v<non_void_result_types> != sizeof...(Types);
@ -83,12 +61,35 @@ namespace blt
using return_type = std::conditional_t<all_void, void, std::conditional_t<some_void, std::optional<first_return>, first_return>>; using return_type = std::conditional_t<all_void, void, std::conditional_t<some_void, std::optional<first_return>, first_return>>;
}; };
template <typename Func, typename... Types>
struct visit_func_meta
{
using result_tuple = std::tuple<typename std::conditional_t<
std::is_invocable_v<Func, Types>, std::invoke_result<Func, Types>, meta::passthrough<void>>::type...>;
using non_void_results = meta::filter_void_t<result_tuple>;
using return_type = std::tuple_element_t<
0, std::conditional_t<std::tuple_size_v<non_void_results> == 0, std::tuple<void>, non_void_results>>;
};
template <typename FuncTuple, typename TypesTuple> template <typename FuncTuple, typename TypesTuple>
struct visit_return_type; struct visit_return_type;
template <typename... Funcs, typename... Types> template <typename... Funcs, typename... Types>
struct visit_return_type<std::tuple<Funcs...>, std::tuple<Types...>> struct visit_return_type<std::tuple<Funcs...>, std::tuple<Types...>>
{}; {
using return_tuple = std::tuple<typename visit_func_meta<Funcs, Types...>::return_type...>;
using non_void_returns = meta::filter_void_t<return_tuple>;
using first_return = std::tuple_element_t<
0, std::conditional_t<std::tuple_size_v<non_void_returns> == 0, std::tuple<void>, non_void_returns>>;
static constexpr bool all_void = std::tuple_size_v<non_void_returns> == 0;
static constexpr bool some_void = std::tuple_size_v<non_void_returns> != std::tuple_size_v<return_tuple>;
static constexpr bool all_same = meta::filter_func_t<std::is_same, std::tuple<first_return>, non_void_returns>::value;
};
} }
/* /*
@ -214,7 +215,7 @@ namespace blt
} }
template <typename MemberFunc, typename... Args> template <typename MemberFunc, typename... Args>
constexpr auto call_member(const MemberFunc func, Args&&... args) constexpr auto call_member(const MemberFunc func, Args&&... args) -> decltype(auto)
{ {
using meta = detail::member_call_return_type<MemberFunc, std::tuple<Args...>, Types...>; using meta = detail::member_call_return_type<MemberFunc, std::tuple<Args...>, Types...>;
return visit([&](auto&& value) -> typename meta::return_type { return visit([&](auto&& value) -> typename meta::return_type {
@ -356,12 +357,6 @@ namespace blt
} }
private: private:
template <typename Derived, typename Base, typename ReturnType, typename... Args>
static auto cast_member_ptr(ReturnType (Base::*base_func)(Args...))
{
return reinterpret_cast<ReturnType (Derived::*)(Args...)>(base_func);
}
value_type m_variant; value_type m_variant;
}; };

View File

@ -34,12 +34,12 @@ struct mutate_type : base_type
struct type1 final : base_type struct type1 final : base_type
{ {
[[nodiscard]] int simple() const override // NOLINT [[nodiscard]] int simple() const final // NOLINT
{ {
return 1; return 1;
} }
[[nodiscard]] std::string to_string() const override // NOLINT [[nodiscard]] std::string to_string() const final // NOLINT
{ {
return "Type1"; return "Type1";
} }
@ -48,12 +48,12 @@ struct type1 final : base_type
struct type2 final : base_type struct type2 final : base_type
{ {
[[nodiscard]] int simple() const override // NOLINT [[nodiscard]] int simple() const final // NOLINT
{ {
return 2; return 2;
} }
[[nodiscard]] std::string to_string() const override // NOLINT [[nodiscard]] std::string to_string() const final // NOLINT
{ {
return "Type2"; return "Type2";
} }
@ -62,12 +62,12 @@ struct type2 final : base_type
struct type3 final : base_type struct type3 final : base_type
{ {
[[nodiscard]] int simple() const override // NOLINT [[nodiscard]] int simple() const final // NOLINT
{ {
return 3; return 3;
} }
[[nodiscard]] std::string to_string() const override // NOLINT [[nodiscard]] std::string to_string() const final // NOLINT
{ {
return "Type3"; return "Type3";
} }
@ -79,17 +79,17 @@ struct storing_type1 final : mutate_type
{ {
} }
[[nodiscard]] int simple() const override // NOLINT [[nodiscard]] int simple() const final // NOLINT
{ {
return internal; return internal;
} }
void mutate(const int i) override void mutate(const int i) final
{ {
internal = i; internal = i;
} }
[[nodiscard]] std::string to_string() const override // NOLINT [[nodiscard]] std::string to_string() const final // NOLINT
{ {
return "Storing Type: {" + std::to_string(internal) + "}"; return "Storing Type: {" + std::to_string(internal) + "}";
} }
@ -103,17 +103,17 @@ struct storing_type2 final : mutate_type
{ {
} }
[[nodiscard]] int simple() const override // NOLINT [[nodiscard]] int simple() const final // NOLINT
{ {
return static_cast<int>(internal); return static_cast<int>(internal);
} }
void mutate(const int i) override void mutate(const int i) final
{ {
internal = static_cast<float>(i) * 2.2534f; internal = static_cast<float>(i) * 2.2534f;
} }
[[nodiscard]] std::string to_string() const override // NOLINT [[nodiscard]] std::string to_string() const final // NOLINT
{ {
return "Storing Type: {" + std::to_string(internal) + "}"; return "Storing Type: {" + std::to_string(internal) + "}";
} }