* Implemented miscellaneous features (generic predicate, getter, setter) * Implemented traits features (lambda traits)master
@@ -1,3 +1,5 @@ | |||
#pragma once | |||
#include <cppmp/dummy.h> | |||
#include "cppmp/core.h" | |||
#include "cppmp/misc.h" | |||
#include "cppmp/traits.h" |
@@ -0,0 +1,7 @@ | |||
#pragma once | |||
#include "core/checker.h" | |||
#include "core/conditionals.h" | |||
#include "core/constants.h" | |||
#include "core/modifier.h" | |||
#include "core/types.h" |
@@ -0,0 +1,133 @@ | |||
#pragma once | |||
#define cppmp_define_checker(name) \ | |||
template<typename... T> \ | |||
struct name \ | |||
: public integral_constant<decltype(std::name<T...>::value), std::name<T...>::value> \ | |||
{ }; \ | |||
\ | |||
template<typename... T> \ | |||
constexpr decltype(auto) name ## _v = name<T...>::value; | |||
#include "types.h" | |||
namespace cppmp | |||
{ | |||
/** | |||
* @brief Evaluates to true_t if the passed template parameters are valid, false_t otherwise. | |||
*/ | |||
template<typename...> | |||
struct is_valid; | |||
/** | |||
* @brief Is true if the passed template parameters are valid, false otherwise. | |||
*/ | |||
template<typename... T> | |||
constexpr decltype(auto) is_valid_v = is_valid<T...>::value; | |||
/** | |||
* @brief Evaluates to true_t if T is a specialization if T_template, false_t otherwise. | |||
*/ | |||
template<typename T, template <typename...> class T_template> | |||
struct is_specialization_of; | |||
/** | |||
* @brief Evaluates to true if T is a specialization if T_template, false otherwise. | |||
*/ | |||
template<typename T, template <typename...> class T_template> | |||
constexpr decltype(auto) is_specialization_of_v = is_specialization_of<T, T_template>::value; | |||
/** | |||
* @brief Evaluates to true_t if all passed parameters are true, false_t otherwise. | |||
*/ | |||
template<bool... B> | |||
struct is_true; | |||
/** | |||
* @brief Evaluates to true if all passed parameters are true, false otherwise. | |||
*/ | |||
template<bool... B> | |||
constexpr decltype(auto) is_true_v = is_true<B...>::value; | |||
cppmp_define_checker(is_void); | |||
cppmp_define_checker(is_null_pointer); | |||
cppmp_define_checker(is_integral); | |||
cppmp_define_checker(is_floating_point); | |||
cppmp_define_checker(is_array); | |||
cppmp_define_checker(is_enum); | |||
cppmp_define_checker(is_union); | |||
cppmp_define_checker(is_class); | |||
cppmp_define_checker(is_function); | |||
cppmp_define_checker(is_pointer); | |||
cppmp_define_checker(is_lvalue_reference); | |||
cppmp_define_checker(is_rvalue_reference); | |||
cppmp_define_checker(is_member_object_pointer); | |||
cppmp_define_checker(is_member_function_pointer); | |||
cppmp_define_checker(is_fundamental); | |||
cppmp_define_checker(is_arithmetic); | |||
cppmp_define_checker(is_scalar); | |||
cppmp_define_checker(is_object); | |||
cppmp_define_checker(is_compound); | |||
cppmp_define_checker(is_reference); | |||
cppmp_define_checker(is_member_pointer); | |||
cppmp_define_checker(is_const); | |||
cppmp_define_checker(is_volatile); | |||
cppmp_define_checker(is_trivial); | |||
cppmp_define_checker(is_trivially_copyable); | |||
cppmp_define_checker(is_standard_layout); | |||
cppmp_define_checker(is_pod); | |||
cppmp_define_checker(is_literal_type); | |||
cppmp_define_checker(has_unique_object_representations); | |||
cppmp_define_checker(is_empty); | |||
cppmp_define_checker(is_polymorphic); | |||
cppmp_define_checker(is_abstract); | |||
cppmp_define_checker(is_final); | |||
cppmp_define_checker(is_aggregate); | |||
cppmp_define_checker(is_signed); | |||
cppmp_define_checker(is_unsigned); | |||
cppmp_define_checker(is_constructible); | |||
cppmp_define_checker(is_trivially_constructible); | |||
cppmp_define_checker(is_nothrow_constructible); | |||
cppmp_define_checker(is_default_constructible); | |||
cppmp_define_checker(is_trivially_default_constructible); | |||
cppmp_define_checker(is_nothrow_default_constructible); | |||
cppmp_define_checker(is_copy_constructible); | |||
cppmp_define_checker(is_trivially_copy_constructible); | |||
cppmp_define_checker(is_nothrow_copy_constructible); | |||
cppmp_define_checker(is_move_constructible); | |||
cppmp_define_checker(is_trivially_move_constructible); | |||
cppmp_define_checker(is_nothrow_move_constructible); | |||
cppmp_define_checker(is_assignable); | |||
cppmp_define_checker(is_trivially_assignable); | |||
cppmp_define_checker(is_nothrow_assignable); | |||
cppmp_define_checker(is_copy_assignable); | |||
cppmp_define_checker(is_trivially_copy_assignable); | |||
cppmp_define_checker(is_nothrow_copy_assignable); | |||
cppmp_define_checker(is_move_assignable); | |||
cppmp_define_checker(is_trivially_move_assignable); | |||
cppmp_define_checker(is_nothrow_move_assignable); | |||
cppmp_define_checker(is_destructible); | |||
cppmp_define_checker(is_trivially_destructible); | |||
cppmp_define_checker(is_nothrow_destructible); | |||
cppmp_define_checker(has_virtual_destructor); | |||
cppmp_define_checker(is_swappable_with); | |||
cppmp_define_checker(is_swappable); | |||
cppmp_define_checker(is_nothrow_swappable_with); | |||
cppmp_define_checker(is_nothrow_swappable); | |||
cppmp_define_checker(alignment_of); | |||
cppmp_define_checker(rank); | |||
cppmp_define_checker(extent); | |||
cppmp_define_checker(is_same); | |||
cppmp_define_checker(is_base_of); | |||
cppmp_define_checker(is_convertible); | |||
cppmp_define_checker(is_invocable); | |||
cppmp_define_checker(is_invocable_r); | |||
cppmp_define_checker(is_nothrow_invocable); | |||
cppmp_define_checker(is_nothrow_invocable_r); | |||
} | |||
#undef cppmp_define_checker | |||
#include "checker.inl" |
@@ -0,0 +1,51 @@ | |||
#pragma once | |||
#include "checker.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* bool_pack */ | |||
template<bool...> | |||
struct bool_pack; | |||
/* is_specialization_of_impl */ | |||
template<typename T, template <typename...> class T_template> | |||
struct is_specialization_of_impl | |||
: public false_t | |||
{ }; | |||
template<template <typename...> class T_template, typename... Ts> | |||
struct is_specialization_of_impl<T_template<Ts...>, T_template> | |||
: public true_t | |||
{ }; | |||
} | |||
/* is_valid */ | |||
template<typename...> | |||
struct is_valid | |||
: public true_t | |||
{ }; | |||
/* is_specialization_of */ | |||
template<typename T, template <typename...> class T_template> | |||
struct is_specialization_of | |||
: public __impl::is_specialization_of_impl<T, T_template> | |||
{ }; | |||
/* is_true */ | |||
template<bool... B> | |||
struct is_true | |||
: public is_same<__impl::bool_pack<true, B...>, __impl::bool_pack<B..., true>> | |||
{ }; | |||
} |
@@ -0,0 +1,142 @@ | |||
#pragma once | |||
#include "types.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* eval_if_c_impl */ | |||
template<bool B, typename T, template<typename...> class E, typename... A> | |||
struct eval_if_impl; | |||
} | |||
/* enable_if */ | |||
/** | |||
* @brief Defines T as ::type if B is true, otherwise the resulting type is empty. | |||
*/ | |||
template<bool B, typename T = void> | |||
struct enable_if | |||
: public std::enable_if<B, T> | |||
{ }; | |||
/** | |||
* @brief Resulting type is T if B is true. If B is false the resulting type is invalid. | |||
*/ | |||
template<bool B, typename T = void> | |||
using enable_if_t = typename enable_if<B, T>::type; | |||
/* conditional/if */ | |||
/** | |||
* @brief Defines T as ::type if B is true, F otherwise. | |||
*/ | |||
template<bool B, typename T, typename F> | |||
struct conditional | |||
: public std::conditional<B, T, F> | |||
{ }; | |||
/** | |||
* @brief Evaluates to T if B is true, to F otherwise. | |||
*/ | |||
template<bool B, typename T, typename F> | |||
using conditional_t = typename conditional<B, T, F>::type; | |||
/** | |||
* @brief Same as conditional. | |||
*/ | |||
template<bool B, typename T, typename F> | |||
struct if_ | |||
: public conditional<B, T, F> | |||
{ }; | |||
/** | |||
* @brief Same as conditional_t. | |||
*/ | |||
template<bool B, typename T, typename F> | |||
using if_t = typename if_<B, T, F>::type; | |||
/* eval_if */ | |||
/** | |||
* @brief Defines T as ::type if B is true, evaluates E<A...> otherwise. | |||
*/ | |||
template<bool B, typename T, template<typename...> class E, typename... A> | |||
struct eval_if | |||
: public __impl::eval_if_impl<B, T, E, A...> | |||
{ }; | |||
/** | |||
* @brief Evaluates to T if B is true, to E<A...> otherwise. | |||
*/ | |||
template<bool B, typename T, template<typename...> class E, typename... A> | |||
using eval_if_t = typename eval_if<B, T, E, A...>::type; | |||
/* conjunction/and */ | |||
/** | |||
* @brief Evaluates to true_t if all passed arguments are also true_t. | |||
*/ | |||
template<typename... T> | |||
struct conjunction | |||
: public std::conjunction<T...> | |||
{ }; | |||
/** | |||
* @brief It to true if all passed arguments are also true_t. | |||
*/ | |||
template<typename... T> | |||
constexpr decltype(auto) conjunction_v = conjunction<T...>::value; | |||
/** | |||
* @brief Same as conjunction. | |||
*/ | |||
template<typename... T> | |||
struct and_ | |||
: public conjunction<T...> | |||
{ }; | |||
/** | |||
* @brief Same as conjunction_v. | |||
*/ | |||
template<typename... T> | |||
constexpr decltype(auto) and_v = conjunction<T...>::value; | |||
/* disjunction/or */ | |||
/** | |||
* @brief Evaluates to true_t if at least one passed arguments is true_t. | |||
*/ | |||
template<typename... T> | |||
struct disjunction | |||
: public std::disjunction<T...> | |||
{ }; | |||
/** | |||
* @brief Is true if at least one passed arguments is true_t. | |||
*/ | |||
template<typename... T> | |||
constexpr decltype(auto) disjunction_v = disjunction<T...>::value; | |||
/** | |||
* @brief Same as disjunction. | |||
*/ | |||
template<typename... T> | |||
struct or_ | |||
: public disjunction<T...> | |||
{ }; | |||
/** | |||
* @brief Same as disjunction_v. | |||
*/ | |||
template<typename... T> | |||
constexpr decltype(auto) or_v = disjunction<T...>::value; | |||
} | |||
#include "conditionals.inl" |
@@ -0,0 +1,23 @@ | |||
#pragma once | |||
#include "conditionals.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* eval_if_impl */ | |||
template<typename T, template<typename...> class E, typename... A> | |||
struct eval_if_impl<true, T, E, A...> | |||
{ using type = T; }; | |||
template<typename T, template<typename...> class E, typename... A> | |||
struct eval_if_impl<false, T, E, A...> | |||
{ using type = E<A...>; }; | |||
} | |||
} |
@@ -0,0 +1,35 @@ | |||
#pragma onec | |||
#include "types.h" | |||
namespace cppmp | |||
{ | |||
/** | |||
* @brief Boolean constant value. | |||
*/ | |||
template<bool B> | |||
constexpr bool_t<B> bool_c; | |||
/** | |||
* @brief True boolean constant value. | |||
*/ | |||
constexpr true_t true_c; | |||
/** | |||
* @brief False boolean constant value. | |||
*/ | |||
constexpr false_t false_c; | |||
/** | |||
* @brief Size constant value. | |||
*/ | |||
template<std::size_t I> | |||
constexpr size_t<I> size_c; | |||
/** | |||
* @brief Zero size constant value, | |||
*/ | |||
constexpr zero_t zero_c; | |||
} |
@@ -0,0 +1,45 @@ | |||
#pragma once | |||
#define cppmp_define_modifier(name) \ | |||
template<typename... T> \ | |||
struct name \ | |||
: public std::name<T...> \ | |||
{ }; \ | |||
\ | |||
template<typename... T> \ | |||
using name ## _t = typename name<T...>::type | |||
namespace cppmp | |||
{ | |||
template<class T> | |||
struct decay; | |||
template<typename T> | |||
using decay_t = typename decay<T>::type; | |||
cppmp_define_modifier(remove_cv); | |||
cppmp_define_modifier(remove_const); | |||
cppmp_define_modifier(remove_volatile); | |||
cppmp_define_modifier(add_cv); | |||
cppmp_define_modifier(add_const); | |||
cppmp_define_modifier(add_volatile); | |||
cppmp_define_modifier(remove_reference); | |||
cppmp_define_modifier(add_lvalue_reference); | |||
cppmp_define_modifier(add_rvalue_reference); | |||
cppmp_define_modifier(remove_pointer); | |||
cppmp_define_modifier(add_pointer); | |||
cppmp_define_modifier(make_signed); | |||
cppmp_define_modifier(make_unsigned); | |||
cppmp_define_modifier(remove_extent); | |||
cppmp_define_modifier(remove_all_extents); | |||
cppmp_define_modifier(common_type); | |||
cppmp_define_modifier(underlying_type); | |||
cppmp_define_modifier(result_of); | |||
cppmp_define_modifier(invoke_result); | |||
} | |||
#undef cppmp_define_modifier | |||
#include "modifier.inl" |
@@ -0,0 +1,39 @@ | |||
#pragma once | |||
#include "modifier.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* decay_impl */ | |||
template <typename T, typename U = remove_reference_t<T>> | |||
struct decay_impl | |||
{ using type = remove_cv_t<U>; }; | |||
template <typename T, typename U> | |||
struct decay_impl<T, U[]> | |||
{ using type = U*; }; | |||
template <typename T, typename U, std::size_t N> | |||
struct decay_impl<T, U[N]> | |||
{ using type = U*; }; | |||
template <typename T, typename R, typename ...A> | |||
struct decay_impl<T, R(A...)> | |||
{ using type = R(*)(A...); }; | |||
template <typename T, typename R, typename ...A> | |||
struct decay_impl<T, R(A..., ...)> | |||
{ using type = R(*)(A..., ...); }; | |||
} | |||
template<class T> | |||
struct decay | |||
: public __impl::decay_impl<T> | |||
{ }; | |||
} |
@@ -0,0 +1,74 @@ | |||
#pragma once | |||
#include <type_traits> | |||
namespace cppmp | |||
{ | |||
/** | |||
* @brief Evaluates to void. | |||
*/ | |||
template<typename...> | |||
using void_t = void; | |||
/** | |||
* @brief Simple type list. | |||
*/ | |||
template<typename...> | |||
struct list | |||
{ }; | |||
/** | |||
* @brief Inherit from all passed types. | |||
*/ | |||
template<typename... T> | |||
struct inherit | |||
: public T... | |||
{ }; | |||
/** | |||
* @brief Type to wrap constant values at compile time. | |||
*/ | |||
template<typename T, T t> | |||
struct integral_constant | |||
: public std::integral_constant<T, t> | |||
{ }; | |||
/** | |||
* @brief Boolean constant type. | |||
*/ | |||
template<bool B> | |||
struct bool_t | |||
: public integral_constant<bool, B> | |||
{ }; | |||
/** | |||
* @brief True boolean constant type. | |||
*/ | |||
struct true_t | |||
: public bool_t<true> | |||
{ }; | |||
/** | |||
* @brief False boolean constant type. | |||
*/ | |||
struct false_t | |||
: public bool_t<false> | |||
{ }; | |||
/** | |||
* @brief Size contant type. | |||
*/ | |||
template<size_t S> | |||
struct size_t | |||
: public integral_constant<std::size_t, S> | |||
{ }; | |||
/** | |||
* @brief Zero zize constant type. | |||
*/ | |||
struct zero_t | |||
: public size_t<0> | |||
{ }; | |||
} |
@@ -1,13 +0,0 @@ | |||
#pragma once | |||
#include <string> | |||
namespace cppmp | |||
{ | |||
struct Dummy | |||
{ | |||
static std::string getHelloWorld(); | |||
}; | |||
} |
@@ -0,0 +1,5 @@ | |||
#pragma once | |||
#include "misc/generic_predicate.h" | |||
#include "misc/getter.h" | |||
#include "misc/setter.h" |
@@ -0,0 +1,26 @@ | |||
#pragma once | |||
namespace cppmp | |||
{ | |||
/** | |||
* @brief Helper class to create generic predicates. | |||
* | |||
* @tparam T_builder Builder class to pass arguments to. | |||
*/ | |||
template<template<typename...> class T_builder> | |||
struct generic_predicate | |||
{ | |||
/** | |||
* @brief Invoke the builder to create the requested object. | |||
* | |||
* @param args Arguments to pass to the builder. | |||
* | |||
* @return Object created from the builder. | |||
*/ | |||
template<typename... T_args> | |||
constexpr decltype(auto) operator()(T_args&&... args) const | |||
{ return T_builder<list<T_args...>>::apply(std::forward<T_args>(args)...); } | |||
}; | |||
} |
@@ -0,0 +1,41 @@ | |||
#pragma once | |||
#include "generic_predicate.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* tag_getter */ | |||
struct tag_getter; | |||
/* getter_builder */ | |||
template<typename X, typename = void> | |||
struct getter_builder; | |||
} | |||
/** | |||
* @brief Evaluates to true_t if the passed type is an getter, to false_t otherwise. | |||
*/ | |||
template<typename T> | |||
struct is_getter; | |||
/** | |||
* @brief Is true if the passed type is an getter, false otherwise. | |||
*/ | |||
template<typename T> | |||
constexpr decltype(auto) is_getter_v = is_getter<T>::value; | |||
/** | |||
* @brief Predicate to create new getter objects. | |||
*/ | |||
constexpr decltype(auto) make_getter = generic_predicate<__impl::getter_builder> { }; | |||
} | |||
#include "getter.inl" |
@@ -0,0 +1,179 @@ | |||
#pragma once | |||
#include <cppmp/traits/lambda_traits.h> | |||
#include "getter.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* tag_getter */ | |||
struct tag_getter | |||
{ }; | |||
/* getter_builder - default */ | |||
template<typename X, typename> | |||
struct getter_builder | |||
{ | |||
template<typename... T_args> | |||
static constexpr decltype(auto) apply(T_args&&...) | |||
{ static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_getter(...)!"); } | |||
}; | |||
/* getter_builder - redirect existing getter */ | |||
template<typename T_getter> | |||
struct getter_builder< | |||
list<T_getter>, | |||
enable_if_t<is_getter_v<decay_t<T_getter>>>> | |||
{ | |||
static constexpr decltype(auto) apply(T_getter&& getter) | |||
{ return std::forward<T_getter>(getter); } | |||
}; | |||
/* getter_builder - member variable */ | |||
template<typename T_object, typename T_value> | |||
struct getter_builder< | |||
list<T_value T_object::*>, | |||
void> | |||
{ | |||
struct getter_member_var | |||
: public tag_getter | |||
{ | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = value_type object_type::*; | |||
member_type member; | |||
constexpr getter_member_var(member_type p_member) | |||
: member(p_member) | |||
{ } | |||
constexpr getter_member_var(getter_member_var&&) = default; | |||
constexpr getter_member_var(const getter_member_var&) = default; | |||
constexpr getter_member_var& operator = (getter_member_var&&) = default; | |||
constexpr getter_member_var& operator = (const getter_member_var&) = default; | |||
template<typename X_object> | |||
constexpr decltype(auto) operator()(X_object&& obj) const | |||
{ return std::forward<X_object>(obj).*member; } | |||
}; | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = value_type object_type::*; | |||
static constexpr decltype(auto) apply(member_type&& getter) | |||
{ return getter_member_var(std::forward<member_type>(getter)); } | |||
}; | |||
/* getter_builder - member function */ | |||
template<typename T_object, typename T_value, typename T_member> | |||
struct getter_builder_member_func | |||
{ | |||
struct getter_member_func | |||
: public tag_getter | |||
{ | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = T_member; | |||
member_type member; | |||
constexpr getter_member_func(member_type p_member) | |||
: member(p_member) | |||
{ } | |||
constexpr getter_member_func(getter_member_func&&) = default; | |||
constexpr getter_member_func(const getter_member_func&) = default; | |||
constexpr getter_member_func& operator = (getter_member_func&&) = default; | |||
constexpr getter_member_func& operator = (const getter_member_func&) = default; | |||
template<typename X_object> | |||
constexpr decltype(auto) operator()(X_object&& obj) const | |||
{ return (std::forward<X_object>(obj).*member)(); } | |||
}; | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = T_member; | |||
static constexpr decltype(auto) apply(member_type&& getter) | |||
{ return getter_member_func(std::forward<member_type>(getter)); } | |||
}; | |||
template<typename T_object, typename T_value> | |||
struct getter_builder< | |||
list<T_value (T_object::*)()>, | |||
void> | |||
: public getter_builder_member_func<T_object, T_value, T_value (T_object::*)()> | |||
{ }; | |||
template<typename T_object, typename T_value> | |||
struct getter_builder< | |||
list<T_value (T_object::*)() const>, | |||
void> | |||
: public getter_builder_member_func<T_object, T_value, T_value (T_object::*)() const> | |||
{ }; | |||
/* getter_builder - lambda/static */ | |||
template<typename T_lambda> | |||
struct getter_builder< | |||
list<T_lambda>, | |||
enable_if_t< | |||
is_valid_v<lambda_traits<decay_t<T_lambda>>> | |||
&& lambda_traits<decay_t<T_lambda>>::argument_count_v == 1 | |||
&& !is_void_v<typename lambda_traits<decay_t<T_lambda>>::return_type>>> | |||
{ | |||
struct getter_lambda | |||
: public tag_getter | |||
{ | |||
using lambda_type = T_lambda; | |||
using lambda_traits_type = lambda_traits<lambda_type>; | |||
using object_type = typename lambda_traits_type::template argument_t<0>; | |||
using value_type = typename lambda_traits_type::return_type; | |||
lambda_type lambda; | |||
constexpr getter_lambda(lambda_type&& p_lambda) | |||
: lambda(std::forward<lambda_type>(p_lambda)) | |||
{ } | |||
constexpr getter_lambda(getter_lambda&&) = default; | |||
constexpr getter_lambda(const getter_lambda&) = default; | |||
constexpr getter_lambda& operator = (getter_lambda&&) = default; | |||
constexpr getter_lambda& operator = (const getter_lambda&) = default; | |||
template<typename X_object> | |||
constexpr decltype(auto) operator()(X_object&& obj) const | |||
{ return lambda(std::forward<X_object>(obj)); } | |||
}; | |||
using lambda_type = T_lambda; | |||
static constexpr decltype(auto) apply(lambda_type&& lambda) | |||
{ return getter_lambda(std::forward<lambda_type>(lambda)); } | |||
}; | |||
} | |||
/* is_getter */ | |||
template<typename T> | |||
struct is_getter | |||
: public is_base_of<__impl::tag_getter, T> | |||
{ }; | |||
} |
@@ -0,0 +1,41 @@ | |||
#pragma once | |||
#include "generic_predicate.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* tag_setter */ | |||
struct tag_setter; | |||
/* setter_builder */ | |||
template<typename X, typename = void> | |||
struct setter_builder; | |||
} | |||
/** | |||
* @brief Evaluates to true_t if the passed type is an setter, to false_t otherwise. | |||
*/ | |||
template<typename T> | |||
struct is_setter; | |||
/** | |||
* @brief Is true if the passed type is an setter, false otherwise. | |||
*/ | |||
template<typename T> | |||
constexpr decltype(auto) is_setter_v = is_setter<T>::value; | |||
/** | |||
* @brief Predicate to create new setter objects. | |||
*/ | |||
constexpr decltype(auto) make_setter = generic_predicate<__impl::setter_builder> { }; | |||
} | |||
#include "setter.inl" |
@@ -0,0 +1,178 @@ | |||
#pragma once | |||
#include <cppmp/traits/lambda_traits.h> | |||
#include "setter.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* tag_setter */ | |||
struct tag_setter | |||
{ }; | |||
/* setter_builder - default */ | |||
template<typename X, typename> | |||
struct setter_builder | |||
{ | |||
template<typename... T_args> | |||
static constexpr decltype(auto) apply(T_args&&...) | |||
{ static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_setter(...)!"); } | |||
}; | |||
/* setter_builder - redirect existing setter */ | |||
template<typename T_setter> | |||
struct setter_builder< | |||
list<T_setter>, | |||
enable_if_t<is_setter_v<decay_t<T_setter>>>> | |||
{ | |||
static constexpr decltype(auto) apply(T_setter&& setter) | |||
{ return std::forward<T_setter>(setter); } | |||
}; | |||
/* setter_builder - member variable */ | |||
template<typename T_object, typename T_value> | |||
struct setter_builder< | |||
list<T_value T_object::*>, | |||
void> | |||
{ | |||
struct setter_member_var | |||
: public tag_setter | |||
{ | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = value_type object_type::*; | |||
member_type member; | |||
constexpr setter_member_var(member_type p_member) | |||
: member(p_member) | |||
{ } | |||
constexpr setter_member_var(setter_member_var&&) = default; | |||
constexpr setter_member_var(const setter_member_var&) = default; | |||
constexpr setter_member_var& operator = (setter_member_var&&) = default; | |||
constexpr setter_member_var& operator = (const setter_member_var&) = default; | |||
template<typename X_object, typename X_value> | |||
constexpr void operator()(X_object&& obj, X_value&& value) const | |||
{ std::forward<X_object>(obj).*member = value; } | |||
}; | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = value_type object_type::*; | |||
static constexpr decltype(auto) apply(member_type&& setter) | |||
{ return setter_member_var(std::forward<member_type>(setter)); } | |||
}; | |||
/* setter_builder - member function */ | |||
template<typename T_object, typename T_value, typename T_member> | |||
struct setter_builder_member_func | |||
{ | |||
struct setter_member_func | |||
: public tag_setter | |||
{ | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = T_member; | |||
member_type member; | |||
constexpr setter_member_func(member_type p_member) | |||
: member(p_member) | |||
{ } | |||
constexpr setter_member_func(setter_member_func&&) = default; | |||
constexpr setter_member_func(const setter_member_func&) = default; | |||
constexpr setter_member_func& operator = (setter_member_func&&) = default; | |||
constexpr setter_member_func& operator = (const setter_member_func&) = default; | |||
template<typename X_object, typename X_value> | |||
constexpr void operator()(X_object&& obj, X_value&& value) const | |||
{ (std::forward<X_object>(obj).*member)(value); } | |||
}; | |||
using object_type = T_object; | |||
using value_type = T_value; | |||
using member_type = T_member; | |||
static constexpr decltype(auto) apply(member_type&& setter) | |||
{ return setter_member_func(std::forward<member_type>(setter)); } | |||
}; | |||
template<typename T_object, typename T_value> | |||
struct setter_builder< | |||
list<void (T_object::*)(T_value)>, | |||
void> | |||
: public setter_builder_member_func<T_object, T_value, void (T_object::*)(T_value)> | |||
{ }; | |||
template<typename T_object, typename T_value> | |||
struct setter_builder< | |||
list<void (T_object::*)(T_value) const>, | |||
void> | |||
: public setter_builder_member_func<T_object, T_value, void (T_object::*)(T_value) const> | |||
{ }; | |||
/* setter_builder - lambda/static */ | |||
template<typename T_lambda> | |||
struct setter_builder< | |||
list<T_lambda>, | |||
enable_if_t< | |||
is_valid_v<lambda_traits<decay_t<T_lambda>>> | |||
&& lambda_traits<decay_t<T_lambda>>::argument_count_v == 2>> | |||
{ | |||
struct setter_lambda | |||
: public tag_setter | |||
{ | |||
using lambda_type = T_lambda; | |||
using lambda_traits_type = lambda_traits<lambda_type>; | |||
using object_type = typename lambda_traits_type::template argument_t<0>; | |||
using value_type = typename lambda_traits_type::return_type; | |||
lambda_type lambda; | |||
constexpr setter_lambda(lambda_type&& p_lambda) | |||
: lambda(std::forward<lambda_type>(p_lambda)) | |||
{ } | |||
constexpr setter_lambda(setter_lambda&&) = default; | |||
constexpr setter_lambda(const setter_lambda&) = default; | |||
constexpr setter_lambda& operator = (setter_lambda&&) = default; | |||
constexpr setter_lambda& operator = (const setter_lambda&) = default; | |||
template<typename X_object, typename X_value> | |||
constexpr void operator()(X_object&& obj, X_value&& value) const | |||
{ lambda(std::forward<X_object>(obj), std::forward<X_value>(value)); } | |||
}; | |||
using lambda_type = T_lambda; | |||
static constexpr decltype(auto) apply(lambda_type&& lambda) | |||
{ return setter_lambda(std::forward<lambda_type>(lambda)); } | |||
}; | |||
} | |||
/* is_setter */ | |||
template<typename T> | |||
struct is_setter | |||
: public is_base_of<__impl::tag_setter, T> | |||
{ }; | |||
} |
@@ -0,0 +1,3 @@ | |||
#pragma once | |||
#include "traits/lambda_traits.h" |
@@ -0,0 +1,14 @@ | |||
#pragma once | |||
namespace cppmp | |||
{ | |||
/** | |||
* @brief Contains type traits and other helpers for the passed lambda. | |||
*/ | |||
template<typename T_lambda, typename = void> | |||
struct lambda_traits; | |||
} | |||
#include "lambda_traits.inl" |
@@ -0,0 +1,110 @@ | |||
#pragma once | |||
#include "lambda_traits.h" | |||
namespace cppmp | |||
{ | |||
namespace __impl | |||
{ | |||
/* lambda_traits_impl */ | |||
template<bool B_is_mutable, typename T_object, typename T_return, typename... T_args> | |||
struct lambda_traits_impl | |||
{ | |||
using object_type = T_object; | |||
using return_type = T_return; | |||
using arguments_type = std::tuple<T_args...>; | |||
using is_mutable = bool_t<B_is_mutable>; | |||
using is_static = is_same<object_type, void>; | |||
using argument_count = size_t<sizeof...(T_args)>; | |||
static constexpr decltype(auto) is_mutable_v = is_mutable::value; | |||
static constexpr decltype(auto) is_static_v = is_static::value; | |||
static constexpr decltype(auto) argument_count_v = argument_count::value; | |||
template<std::size_t I> | |||
struct argument | |||
: public std::tuple_element<I, arguments_type> | |||
{ }; | |||
template<std::size_t I> | |||
using argument_t = typename argument<I>::type; | |||
}; | |||
} | |||
/* lambda_traits */ | |||
template<typename T_lambda> | |||
struct lambda_traits<T_lambda, enable_if_t<is_valid_v<decltype(&T_lambda::operator())>>> | |||
: public lambda_traits<decltype(&T_lambda::operator())> | |||
{ }; | |||
template<typename T_return, typename... T_args> | |||
struct lambda_traits<T_return (*)(T_args...), void> | |||
: public __impl::lambda_traits_impl<false, void, T_return, T_args...> | |||
{ }; | |||
template<typename T_object, typename T_return, typename... T_args> | |||
struct lambda_traits<T_return (T_object::*)(T_args...), void> | |||
: public __impl::lambda_traits_impl<true, T_object, T_return, T_args...> | |||
{ }; | |||
template<typename T_object, typename T_return, typename... T_args> | |||
struct lambda_traits<T_return (T_object::*)(T_args...) const, void> | |||
: public __impl::lambda_traits_impl<false, T_object, T_return, T_args...> | |||
{ }; | |||
} | |||
#pragma once | |||
#include <tuple> | |||
#include <type_traits> | |||
namespace stx | |||
{ | |||
namespace lambda_detail | |||
{ | |||
template<class Ret, class Cls, class IsMutable, class... Args> | |||
struct types | |||
{ | |||
using is_mutable = IsMutable; | |||
enum { arity = sizeof...(Args) }; | |||
using return_type = Ret; | |||
template<size_t i> | |||
struct arg | |||
{ | |||
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type; | |||
}; | |||
}; | |||
} | |||
template<class Ld> | |||
struct lambda_type | |||
: lambda_type<decltype(&Ld::operator())> | |||
{}; | |||
template<class Ret, class Cls, class... Args> | |||
struct lambda_type<Ret(Cls::*)(Args...)> | |||
: lambda_detail::types<Ret,Cls,std::true_type,Args...> | |||
{}; | |||
template<class Ret, class Cls, class... Args> | |||
struct lambda_type<Ret(Cls::*)(Args...) const> | |||
: lambda_detail::types<Ret,Cls,std::false_type,Args...> | |||
{}; | |||
}; |
@@ -22,7 +22,7 @@ Add_Executable ( cppmp-test | |||
${CPPMP_TEST_SOURCE_FILES} ) | |||
Target_Link_Libraries ( cppmp-test | |||
PUBLIC | |||
cppmp-objects | |||
cppmp | |||
GTest::Main ) | |||
# pedantic | |||
@@ -1,11 +0,0 @@ | |||
#include <gtest/gtest.h> | |||
#include <cppmp.h> | |||
using namespace ::testing; | |||
using namespace ::cppmp; | |||
TEST(cppmp, getHelloWorld) | |||
{ | |||
EXPECT_EQ(Dummy::getHelloWorld(), "Hello World!"); | |||
} |
@@ -0,0 +1,67 @@ | |||
#include <gtest/gtest.h> | |||
#include <cppmp.h> | |||
using namespace ::testing; | |||
using namespace ::cppmp; | |||
struct test_obj | |||
{ | |||
mutable int value; | |||
int get() | |||
{ return value; } | |||
int cget() const | |||
{ return value; } | |||
static int sget(test_obj& o) | |||
{ return o.value; } | |||
}; | |||
TEST(cppmp_getter_tests, member_var) | |||
{ | |||
test_obj o { 1 }; | |||
auto g = make_getter(&test_obj::value); | |||
EXPECT_EQ(1, g(o)); | |||
} | |||
TEST(cppmp_getter_tests, member_func) | |||
{ | |||
test_obj o { 1 }; | |||
auto g = make_getter(&test_obj::get); | |||
EXPECT_EQ(1, g(o)); | |||
} | |||
TEST(cppmp_getter_tests, const_member_func) | |||
{ | |||
test_obj o { 1 }; | |||
auto g = make_getter(&test_obj::cget); | |||
EXPECT_EQ(1, g(o)); | |||
} | |||
TEST(cppmp_getter_tests, static_func) | |||
{ | |||
test_obj o { 1 }; | |||
auto g = make_getter(&test_obj::sget); | |||
EXPECT_EQ(1, g(o)); | |||
} | |||
TEST(cppmp_getter_tests, lambda) | |||
{ | |||
test_obj o { 1 }; | |||
auto g = make_getter([](test_obj& o){ | |||
return o.value; | |||
}); | |||
EXPECT_EQ(1, g(o)); | |||
} |
@@ -0,0 +1,72 @@ | |||
#include <gtest/gtest.h> | |||
#include <cppmp.h> | |||
using namespace ::testing; | |||
using namespace ::cppmp; | |||
struct test_obj | |||
{ | |||
mutable int value; | |||
void set(int v) | |||
{ value = v; } | |||
void cset(int v) const | |||
{ value = v; } | |||
static void sset(test_obj& o, int v) | |||
{ o.value = v; } | |||
}; | |||
TEST(cppmp_setter_tests, member_var) | |||
{ | |||
test_obj o { 0 }; | |||
auto s = make_setter(&test_obj::value); | |||
s(o, 1); | |||
EXPECT_EQ(1, o.value); | |||
} | |||
TEST(cppmp_setter_tests, member_func) | |||
{ | |||
test_obj o { 1 }; | |||
auto s = make_setter(&test_obj::set); | |||
s(o, 1); | |||
EXPECT_EQ(1, o.value); | |||
} | |||
TEST(cppmp_setter_tests, const_member_func) | |||
{ | |||
test_obj o { 1 }; | |||
auto s = make_setter(&test_obj::cset); | |||
s(o, 1); | |||
EXPECT_EQ(1, o.value); | |||
} | |||
TEST(cppmp_setter_tests, static_func) | |||
{ | |||
test_obj o { 1 }; | |||
auto s = make_setter(&test_obj::sset); | |||
s(o, 1); | |||
EXPECT_EQ(1, o.value); | |||
} | |||
TEST(cppmp_setter_tests, lambda) | |||
{ | |||
test_obj o { 1 }; | |||
auto s = make_setter([](test_obj& o, int v){ | |||
o.value = v; | |||
}); | |||
s(o, 1); | |||
EXPECT_EQ(1, o.value); | |||
} |
@@ -0,0 +1,3 @@ | |||
#include <gtest/gtest.h> | |||
#include <cppmp.h> |
@@ -0,0 +1,55 @@ | |||
#include <gtest/gtest.h> | |||
#include <cppmp.h> | |||
using namespace ::testing; | |||
using namespace ::cppmp; | |||
struct test_obj | |||
{ | |||
int test(int); | |||
double ctest(float, std::string) const; | |||
static std::string sget(); | |||
}; | |||
constexpr decltype(auto) cpp_traits_lambda = [](std::string, int)->bool { return true; }; | |||
using type0 = ::cppmp::lambda_traits<decltype(&test_obj::test)>; | |||
using type1 = ::cppmp::lambda_traits<decltype(&test_obj::ctest)>; | |||
using type2 = ::cppmp::lambda_traits<decltype(&test_obj::sget)>; | |||
using type3 = ::cppmp::lambda_traits<std::string(*)(bool)>; | |||
using type4 = ::cppmp::lambda_traits<decltype(cpp_traits_lambda)>; | |||
static_assert(is_same_v<typename type0::object_type, test_obj>); | |||
static_assert(is_same_v<typename type0::return_type, int>); | |||
static_assert(is_same_v<typename type0::arguments_type, std::tuple<int>>); | |||
static_assert( type0::is_mutable_v == true); | |||
static_assert( type0::is_static_v == false); | |||
static_assert( type0::argument_count_v == 1); | |||
static_assert(is_same_v<typename type1::object_type, test_obj>); | |||
static_assert(is_same_v<typename type1::return_type, double>); | |||
static_assert(is_same_v<typename type1::arguments_type, std::tuple<float, std::string>>); | |||
static_assert( type1::is_mutable_v == false); | |||
static_assert( type1::is_static_v == false); | |||
static_assert( type1::argument_count_v == 2); | |||
static_assert(is_same_v<typename type2::object_type, void>); | |||
static_assert(is_same_v<typename type2::return_type, std::string>); | |||
static_assert(is_same_v<typename type2::arguments_type, std::tuple<>>); | |||
static_assert( type2::is_mutable_v == false); | |||
static_assert( type2::is_static_v == true); | |||
static_assert( type2::argument_count_v == 0); | |||
static_assert(is_same_v<typename type3::object_type, void>); | |||
static_assert(is_same_v<typename type3::return_type, std::string>); | |||
static_assert(is_same_v<typename type3::arguments_type, std::tuple<bool>>); | |||
static_assert( type3::is_mutable_v == false); | |||
static_assert( type3::is_static_v == true); | |||
static_assert( type3::argument_count_v == 1); | |||
static_assert(is_same_v<typename type4::return_type, bool>); | |||
static_assert(is_same_v<typename type4::arguments_type, std::tuple<std::string, int>>); | |||
static_assert( type4::is_mutable_v == false); | |||
static_assert( type4::is_static_v == false); | |||
static_assert( type4::argument_count_v == 2); |