Browse Source

* Implemented core features (checker, conditionals, constants, modifier, types)

* Implemented miscellaneous features (generic predicate, getter, setter)
* Implemented traits features (lambda traits)
master
bergmann 4 years ago
parent
commit
a78b13fdff
26 changed files with 1347 additions and 26 deletions
  1. +3
    -1
      include/cppmp.h
  2. +7
    -0
      include/cppmp/core.h
  3. +133
    -0
      include/cppmp/core/checker.h
  4. +51
    -0
      include/cppmp/core/checker.inl
  5. +142
    -0
      include/cppmp/core/conditionals.h
  6. +23
    -0
      include/cppmp/core/conditionals.inl
  7. +35
    -0
      include/cppmp/core/constants.h
  8. +45
    -0
      include/cppmp/core/modifier.h
  9. +39
    -0
      include/cppmp/core/modifier.inl
  10. +74
    -0
      include/cppmp/core/types.h
  11. +0
    -13
      include/cppmp/dummy.h
  12. +5
    -0
      include/cppmp/misc.h
  13. +26
    -0
      include/cppmp/misc/generic_predicate.h
  14. +41
    -0
      include/cppmp/misc/getter.h
  15. +179
    -0
      include/cppmp/misc/getter.inl
  16. +41
    -0
      include/cppmp/misc/setter.h
  17. +178
    -0
      include/cppmp/misc/setter.inl
  18. +3
    -0
      include/cppmp/traits.h
  19. +14
    -0
      include/cppmp/traits/lambda_traits.h
  20. +110
    -0
      include/cppmp/traits/lambda_traits.inl
  21. +1
    -1
      test/CMakeLists.txt
  22. +0
    -11
      test/cppmp/cppmp-tests.cpp
  23. +67
    -0
      test/cppmp/cppmp_getter_tests.cpp
  24. +72
    -0
      test/cppmp/cppmp_setter_tests.cpp
  25. +3
    -0
      test/cppmp/cppmp_tests.cpp
  26. +55
    -0
      test/cppmp/cppmp_traits_test.cpp

+ 3
- 1
include/cppmp.h View File

@@ -1,3 +1,5 @@
#pragma once

#include <cppmp/dummy.h>
#include "cppmp/core.h"
#include "cppmp/misc.h"
#include "cppmp/traits.h"

+ 7
- 0
include/cppmp/core.h View File

@@ -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"

+ 133
- 0
include/cppmp/core/checker.h View File

@@ -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"

+ 51
- 0
include/cppmp/core/checker.inl View File

@@ -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>>
{ };

}

+ 142
- 0
include/cppmp/core/conditionals.h View File

@@ -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"

+ 23
- 0
include/cppmp/core/conditionals.inl View File

@@ -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...>; };

}

}

+ 35
- 0
include/cppmp/core/constants.h View File

@@ -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;

}

+ 45
- 0
include/cppmp/core/modifier.h View File

@@ -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"

+ 39
- 0
include/cppmp/core/modifier.inl View File

@@ -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>
{ };

}

+ 74
- 0
include/cppmp/core/types.h View File

@@ -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>
{ };

}

+ 0
- 13
include/cppmp/dummy.h View File

@@ -1,13 +0,0 @@
#pragma once

#include <string>

namespace cppmp
{

struct Dummy
{
static std::string getHelloWorld();
};

}

+ 5
- 0
include/cppmp/misc.h View File

@@ -0,0 +1,5 @@
#pragma once

#include "misc/generic_predicate.h"
#include "misc/getter.h"
#include "misc/setter.h"

+ 26
- 0
include/cppmp/misc/generic_predicate.h View File

@@ -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)...); }
};

}

+ 41
- 0
include/cppmp/misc/getter.h View File

@@ -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"

+ 179
- 0
include/cppmp/misc/getter.inl View File

@@ -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>
{ };

}

+ 41
- 0
include/cppmp/misc/setter.h View File

@@ -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"

+ 178
- 0
include/cppmp/misc/setter.inl View File

@@ -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>
{ };

}

+ 3
- 0
include/cppmp/traits.h View File

@@ -0,0 +1,3 @@
#pragma once

#include "traits/lambda_traits.h"

+ 14
- 0
include/cppmp/traits/lambda_traits.h View File

@@ -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"

+ 110
- 0
include/cppmp/traits/lambda_traits.inl View File

@@ -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...>
{};

};

+ 1
- 1
test/CMakeLists.txt View File

@@ -22,7 +22,7 @@ Add_Executable ( cppmp-test
${CPPMP_TEST_SOURCE_FILES} )
Target_Link_Libraries ( cppmp-test
PUBLIC
cppmp-objects
cppmp
GTest::Main )

# pedantic


+ 0
- 11
test/cppmp/cppmp-tests.cpp View File

@@ -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!");
}

+ 67
- 0
test/cppmp/cppmp_getter_tests.cpp View File

@@ -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));
}

+ 72
- 0
test/cppmp/cppmp_setter_tests.cpp View File

@@ -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);
}

+ 3
- 0
test/cppmp/cppmp_tests.cpp View File

@@ -0,0 +1,3 @@
#include <gtest/gtest.h>

#include <cppmp.h>

+ 55
- 0
test/cppmp/cppmp_traits_test.cpp View File

@@ -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);

Loading…
Cancel
Save