tuples!
parent
27c07594a8
commit
84921fffa7
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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) + "}";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue