Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# CMake - https://github.com/github/gitignore/blob/master/CMake.gitignore
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Expand Down
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ enable_testing()

add_library(mil INTERFACE)

target_compile_options(mil
INTERFACE

-Werror

-Wall
-Wextra
-Wpedantic

-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wenum-compare
-Wfloat-equal
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo
)

target_include_directories(mil
INTERFACE
$<INSTALL_INTERFACE:include>
Expand Down
143 changes: 134 additions & 9 deletions include/chain_invoke.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,70 @@ using namespace msl;
}
}

/**
* @brief TypeSelector will select what tuple of agrs will get from function
* tuple fow univsality and compatibility
* @tparam have_agrs have function args or no
* @tparam TRet return type of function
* @tparam stack_args tuple of args if function have_agrs
* @details Possible three variants which described below
// 1) if have agrs - then return type must be void and function params must
// be refs or pointers. Selected type is tuple (stack_args)
// 2) if have no agrs and return type is not ref or pointer then selected type is tuple<TRet>
// 3) if have no agrs and return type is ref or pointer then selected type is tuple<pointer<TRet>>
*/
template<bool have_agrs, typename TRet, typename stack_args>
struct TypeSelector final
{
private:
using stack_args_or_ret_value = std::conditional_t<have_agrs, stack_args, std::tuple<TRet>>;
inline static constexpr bool is_ref = std::is_reference_v<TRet>;
inline static constexpr bool is_pointer = std::is_pointer_v<TRet>;
using no_ref_but_pointer = std::tuple<std::add_pointer_t<std::remove_reference_t<TRet>>>;
using ret_pointer_or_ret_value = std::conditional_t<is_ref, no_ref_but_pointer, std::tuple<TRet>>;

public:
inline static constexpr bool have_agrs_value = have_agrs;
inline static constexpr bool is_ref_value = is_ref;
inline static constexpr bool is_pointer_value = is_pointer;
inline static constexpr bool is_copy_value = !have_agrs_value && !is_ref_value && !is_pointer_value;
using args_pointer_value = std::conditional_t<is_ref, ret_pointer_or_ret_value, stack_args_or_ret_value>;
using type = std::conditional_t<is_pointer, ret_pointer_or_ret_value, args_pointer_value>;

TypeSelector()
{
if constexpr(have_agrs_value)
{
static_assert(std::is_same_v<void, TRet>, "if have args then return value must be void");
}
if constexpr(! have_agrs_value)
{
static_assert(! std::is_same_v<void, TRet>, "if have no args then return value can't be void");
}
}
};

/**
* @brief The invoking step object, which also holds the tuple
*
* @tparam Fx Type of the method
*/
template<typename Fx>
struct OwningInvokingStep {
using tuple_t = typename function_info<Fx>::stack_args;
using qalified_t = typename function_info<Fx>::args;
using class_t = typename function_info<Fx>::cl;
struct OwningInvokingStep {
using function_info_t = function_info<Fx>;
using ret_t = typename function_info_t::ret;
inline static constexpr bool have_agrs = function_info_t::args_count > 0;
using type_selector_t = TypeSelector<have_agrs, ret_t, typename function_info_t::stack_args>;
using tuple_t = typename type_selector_t::type;
using qalified_t = typename function_info_t::args;
using class_t = typename function_info_t::cl;

static constexpr size_t TUPLE_SIZE { std::tuple_size_v<tuple_t> };
// not use dicrectly but in constructor have static assert
const function_info_t function_info_;

tuple_t tuple;
// only for call constructor type_selector_t and check static asserts
const type_selector_t ts;

/**
* @brief The streaming operator which simply deduces type of
Expand All @@ -88,8 +138,37 @@ using namespace msl;
*/
template<typename OpFx>
constexpr auto operator<<(OpFx const & aFx) && {
using invoking_t = typename function_info<OpFx>::cl;
return OwningInvokingStep<OpFx>{ aFx, std::get<invoking_t>(tuple) };
if constexpr (type_selector_t::have_agrs_value)
{
using invoking_t = typename function_info<OpFx>::cl;
return OwningInvokingStep<OpFx>{ aFx, std::get<invoking_t>(tuple) };
}
else
{
if constexpr(!type_selector_t::is_ref_value)
{
return OwningInvokingStep<OpFx>{ aFx, std::get<0>(tuple) };
}
else if constexpr(type_selector_t::is_ref_value)
{
// if write staright - static_assert(false, "still no realization when ret val is refernce or pointer");
// then assert work even if shouldn't
using bool_type_for_assert = typename std::conditional_t<type_selector_t::is_ref_value, std::false_type, std::true_type>;
static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer");
}
else if constexpr(type_selector_t::is_pointer_value)
{
// if write staright - static_assert(false, "still no realization when ret val is refernce or pointer");
// then assert work even if shouldn't
using bool_type_for_assert = typename std::conditional_t<type_selector_t::is_pointer_value, std::false_type, std::true_type>;
static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer");
}
else
{
// type_selector_t::have_agrs_value myst be false here
static_assert(type_selector_t::have_agrs_value, "unknown compile time branch");
}
}
}

/**
Expand All @@ -102,7 +181,31 @@ using namespace msl;
explicit constexpr OwningInvokingStep(Fx const & aFx, Obj & obj)
: tuple { }
{
this->invokeImpl(std::make_index_sequence<TUPLE_SIZE>{}, aFx, obj);
if constexpr (type_selector_t::have_agrs_value)
{
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
this->invokeImpl(std::make_index_sequence<function_info_t::args_count>{}, aFx, obj);
}
else if constexpr (type_selector_t::is_copy_value)
{
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
this->invokeImplWithret(aFx, obj);
}
else if constexpr (type_selector_t::is_ref_value)
{
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
this->invokeImplWithRefret(aFx, obj);
}
else if constexpr (type_selector_t::is_pointer_value)
{
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
this->invokeImplWithPtrret(aFx, obj);
}
else
{
// type_selector_t::have_agrs_value myst be false here
static_assert(type_selector_t::have_agrs_value, "unknown compile time branch");
}
}
private:
/**
Expand All @@ -113,8 +216,31 @@ using namespace msl;
*/
template<typename Obj, size_t ... Idx>
constexpr void invokeImpl(std::index_sequence<Idx...>, Fx const & aFx, Obj & obj) {
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
(obj.*aFx)(conditionalAddressOf<std::tuple_element_t<Idx, qalified_t>>(std::get<Idx>(tuple))...);
}

template<typename Obj>
constexpr void invokeImplWithret(Fx const & aFx, Obj & obj) {
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
std::get<0>(tuple) = (obj.*aFx)();
}

template<typename Obj>
constexpr void invokeImplWithRefret(Fx const & aFx, Obj & obj) {
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
decltype(auto) ret_val = (obj.*aFx)();
static_assert(std::is_reference_v<decltype(ret_val)>, "ret value must be reference");
std::get<0>(tuple) = &ret_val;
}

template<typename Obj>
constexpr void invokeImplWithPtrret(Fx const & aFx, Obj & obj) {
static_assert(std::is_same_v<class_t, Obj>, "must be one type");
decltype(auto) ret_val = (obj.*aFx)();
static_assert(std::is_pointer_v<decltype(ret_val)>, "ret value must be reference");
std::get<0>(tuple) = ret_val;
}
};

/**
Expand Down Expand Up @@ -146,7 +272,6 @@ using namespace msl;
*/
template<typename OpFx>
constexpr auto operator<<(OpFx const & aFx) && {
using invoking_t = typename function_info<OpFx>::cl;
return OwningInvokingStep<OpFx>{ aFx, obj };
}
};
Expand Down
Loading