Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/asciidoctor-ghpages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

- name: Install Mermaid
run: |
npm install -g @mermaid-js/mermaid-cli@11.4.2
npm install -g @mermaid-js/mermaid-cli@11.12.0
npx puppeteer browsers install chrome-headless-shell

- name: Install asciidoctor
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ build/
/venv
/.vscode
/.idea
/.cache
.cache/
/.DS_Store
.clang-format
.clang-tidy
Expand Down
2 changes: 0 additions & 2 deletions docs/for_each_n_args.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/for_each_n_ar
provides a method for calling a function (or other callable) with batches of
arguments from a parameter pack.

IMPORTANT: `for_each_n_args` is not yet available on freestanding implementations.

Examples:
[source,cpp]
----
Expand Down
2 changes: 0 additions & 2 deletions docs/function_traits.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/function_trai
contains type traits for introspecting function signatures. It works with
functions, lambda expressions, and classes with `operator()`.

IMPORTANT: Function traits are not yet available on freestanding implementations.

Examples:
[source,cpp]
----
Expand Down
3 changes: 1 addition & 2 deletions include/stdx/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,7 @@ template <std::size_t N> using smallest_uint_t = decltype(smallest_uint<N>());

namespace bit_detail {
template <std::size_t... Offsets>
constexpr auto shifts =
[]() -> std::array<std::size_t, sizeof...(Offsets) + 1> {
constexpr auto shifts = []()->std::array<std::size_t, sizeof...(Offsets) + 1> {
constexpr auto offsets = std::array{std::size_t{}, Offsets...};
auto s = std::array<std::size_t, sizeof...(Offsets) + 1>{};
for (auto i = std::size_t{}; i < sizeof...(Offsets); ++i) {
Expand Down
130 changes: 113 additions & 17 deletions include/stdx/function_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,136 @@
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/utility.hpp>

#include <functional>
#include <type_traits>
#include <utility>

namespace stdx {
inline namespace v1 {
namespace detail {
template <typename...> struct function_traits;
template <auto> struct any_type {
// NOLINTNEXTLINE(google-explicit-constructor)
template <typename T> operator T();
};

template <typename R, typename... Args>
struct function_traits<std::function<R(Args...)>> {
template <typename F> struct function_traits;

template <typename R, typename... Args> struct function_traits<R(Args...)> {
using return_type = R;

template <template <typename...> typename List> using args = List<Args...>;
template <template <typename...> typename List>
using decayed_args = List<std::decay_t<Args>...>;
using arity = std::integral_constant<std::size_t, sizeof...(Args)>;
using obj_t = void;

template <auto N> using nth_arg = nth_t<N, Args...>;
template <auto N> using decayed_nth_arg = std::decay_t<nth_arg<N>>;

template <std::size_t... Is>
constexpr static auto invoke(std::index_sequence<Is...>)
-> std::invoke_result_t<R(Args...), any_type<Is>...>;
};

template <typename R, typename... Args>
struct function_traits<R (*)(Args...)> : function_traits<R(Args...)> {};

template <typename R, typename... Args>
struct function_traits<R (*const)(Args...)> : function_traits<R(Args...)> {};

template <typename R, typename... Args>
struct function_traits<R (*volatile)(Args...)> : function_traits<R(Args...)> {};

template <typename R, typename... Args>
struct function_traits<R (*const volatile)(Args...)>
: function_traits<R(Args...)> {};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...)> : function_traits<R(Args...)> {
using obj_t = C;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) &> : function_traits<R(Args...)> {
using obj_t = C &;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) const &>
: function_traits<R(Args...)> {
using obj_t = C const &;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) volatile &>
: function_traits<R(Args...)> {
using obj_t = C volatile &;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) const volatile &>
: function_traits<R(Args...)> {
using obj_t = C const volatile &;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) &&> : function_traits<R(Args...)> {
using obj_t = C &&;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) const &&>
: function_traits<R(Args...)> {
using obj_t = C const &&;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) volatile &&>
: function_traits<R(Args...)> {
using obj_t = C volatile &&;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) const volatile &&>
: function_traits<R(Args...)> {
using obj_t = C const volatile &&;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) const> : function_traits<R(Args...)> {
using obj_t = C const;
};

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) volatile>
: function_traits<R(Args...)> {
using obj_t = C volatile;
};
} // namespace detail

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...) const volatile>
: function_traits<R(Args...)> {
using obj_t = C const volatile;
};

template <typename F, typename = void> struct detect_call_operator {
template <std::size_t... Is>
constexpr static auto invoke(std::index_sequence<Is...>) ->
typename boost::mp11::mp_cond<
boost::mp11::mp_valid<std::invoke_result_t, F &&, any_type<Is>...>,
boost::mp11::mp_defer<std::invoke_result_t, F &&, any_type<Is>...>,
boost::mp11::mp_valid<std::invoke_result_t, F &, any_type<Is>...>,
boost::mp11::mp_defer<std::invoke_result_t, F &,
any_type<Is>...>>::type;
};
template <typename F>
using function_traits =
detail::function_traits<decltype(std::function{std::declval<F>()})>;
struct detect_call_operator<
F, std::void_t<decltype(&remove_cvref_t<F>::operator())>>
: function_traits<decltype(&remove_cvref_t<F>::operator())> {};

template <typename F> struct function_traits : detect_call_operator<F> {};
} // namespace detail

template <typename F> using function_traits = detail::function_traits<F>;

template <typename F> using return_t = typename function_traits<F>::return_type;
template <typename F, template <typename...> typename List>
Expand All @@ -39,6 +143,7 @@ template <typename F, template <typename...> typename List>
using decayed_args_t = typename function_traits<F>::template decayed_args<List>;
template <typename F>
using nongeneric_arity_t = typename function_traits<F>::arity;
template <typename F> using obj_arg_t = typename function_traits<F>::obj_t;

template <typename F, auto N>
using nth_arg_t = typename function_traits<F>::template nth_arg<N>;
Expand All @@ -47,18 +152,9 @@ using decayed_nth_arg_t =
typename function_traits<F>::template decayed_nth_arg<N>;

namespace detail {
template <auto> struct any_type {
// NOLINTNEXTLINE(google-explicit-constructor)
template <typename T> operator T();
};

template <typename F, std::size_t... Is>
constexpr auto try_invoke_impl(std::index_sequence<Is...>)
-> std::invoke_result_t<F, any_type<Is>...>;

template <typename F, typename N>
using try_invoke =
decltype(try_invoke_impl<F>(std::make_index_sequence<N::value>{}));
decltype(function_traits<F>::invoke(std::make_index_sequence<N::value>{}));

template <typename F, typename N>
using has_arg_count = boost::mp11::mp_valid<try_invoke, F, N>;
Expand Down
2 changes: 1 addition & 1 deletion include/stdx/tuple_algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ constexpr auto contains_type(
template <tuplelike T, template <typename> typename Proj = std::type_identity_t>
[[nodiscard]] constexpr auto sorted_indices() {
return []<std::size_t... Is>(std::index_sequence<Is...>)
-> std::array<std::size_t, sizeof...(Is)> {
->std::array<std::size_t, sizeof...(Is)> {
using P = std::pair<std::string_view, std::size_t>;
auto a = std::array<P, sizeof...(Is)>{
P{stdx::type_as_string<Proj<tuple_element_t<Is, T>>>(), Is}...};
Expand Down
Loading