Skip to content

Commit

Permalink
Simplify overload system to get meaningful errors and compile faster
Browse files Browse the repository at this point in the history
This is the 1st PR toward this goal. More to come.
  • Loading branch information
jfalcou authored Nov 18, 2023
1 parent 497aaf9 commit 9c9e7e3
Show file tree
Hide file tree
Showing 17 changed files with 878 additions and 348 deletions.
2 changes: 2 additions & 0 deletions doc/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ STRIP_FROM_INC_PATH = ../include
SEPARATE_MEMBER_PAGES = YES
TAB_SIZE = 2

ALIASES += "raberu=[RABERU](https://jfalcou.github.io/raberu/) \1"
ALIASES += "godbolt{1}=@include \1"
ALIASES += "groupheader{1}=<h2 class=\"groupheader\"> \1 </h2>"
ALIASES += "subgroupheader{1}=<h3 class=\"groupheader\"> \1 </h3>"
ALIASES += "nullable=[NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer)"
ALIASES += "callable=[Callable Object](https://en.cppreference.com/w/cpp/named_req/Callable)"
ALIASES += "container=[Container](https://en.cppreference.com/w/cpp/named_req/Container)"
Expand Down
1 change: 1 addition & 0 deletions doc/page02_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ These tutorials cover topics for improving your usage of SIMD instructions set w

**Advanced Topics**

- \subpage inter-with-native
- \subpage multiarch
2 changes: 1 addition & 1 deletion include/eve/as.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ namespace eve
using type = T;

constexpr as() noexcept {}
constexpr as(T const&) noexcept {}
explicit constexpr as(T const&) noexcept {}
};
}
2 changes: 1 addition & 1 deletion include/eve/as_element.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ namespace eve
struct as_element : as<element_type_t<T>>
{
constexpr as_element() noexcept {}
constexpr as_element(T const&) noexcept {}
explicit constexpr as_element(T const&) noexcept {}
};
}
29 changes: 29 additions & 0 deletions include/eve/concept/options.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//==================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once

#include <eve/detail/raberu.hpp>

namespace eve
{
template<typename T>
concept callable_options = rbr::concepts::settings<T>;

template<typename T>
concept callable_option = rbr::concepts::option<T>;

template<typename Option, auto Keyword>
concept exactly = rbr::concepts::exactly<Option,Keyword>;

template<typename Option, auto... Keyword>
concept any_options_from = callable_option<Option> && (exactly<Option,Keyword> || ...);

/// Checks if the type associated to a given Keyword in a Option pack is equal to Type
template<auto Keyword, typename Opts,typename Type>
concept match_option = std::same_as<Type, rbr::result::fetch_t<Keyword,Opts>>;
}
1 change: 0 additions & 1 deletion include/eve/module/algo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
//! **Required header:** @code{.cpp} #include <eve/module/algo.hpp> @endcode
//! @}
//==================================================================================================

#include <eve/module/algo/algo/all_of.hpp>
#include <eve/module/algo/algo/any_of.hpp>
#include <eve/module/algo/algo/array_utils.hpp>
Expand Down
9 changes: 0 additions & 9 deletions include/eve/traits/invoke/protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,6 @@ struct constant
using constant_tag = void;
};

//==================================================================================================
//! @concept callable
//! @brief **EVE** callable
//!
//! A type `T` satisfies eve::callable if and only if it is tagged as such either
//! manually or by inheriting from a T properties.
//!
//! @tparam T T type for the @callable to check
//==================================================================================================
template<typename T>
concept callable = requires(T) { typename T::callable_tag_type; };

Expand Down
12 changes: 12 additions & 0 deletions include/eve/traits/overload.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//======================================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//======================================================================================================================
#pragma once

#include <eve/traits/overload/protocol.hpp>
#include <eve/traits/overload/supports.hpp>
#include <eve/traits/overload/default_behaviors.hpp>
106 changes: 106 additions & 0 deletions include/eve/traits/overload/default_behaviors.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//======================================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//======================================================================================================================
#pragma once

#include <eve/concept/value.hpp>
#include <eve/detail/skeleton.hpp>
#include <eve/detail/function/conditional.hpp>

namespace eve
{
namespace detail
{
inline constexpr struct { EVE_FORCEINLINE auto operator()(auto, auto x) const { return x; } } return_2nd = {};
}

//====================================================================================================================

//====================================================================================================================
template< template<typename> class Func
, typename OptionsValues
, typename... Options
>
struct callable : decorated_with<OptionsValues, Options...>
{
using base = decorated_with<OptionsValues, Options...>;

template<typename T>
constexpr auto operator[](T t) const
requires( requires(base const& b) { b[t];} )
{
auto new_traits = base::operator[](t);
return Func<decltype(new_traits)>{new_traits};
}

template<typename T> void operator[](T t) const =delete;

template<typename... Args>
constexpr auto behavior(auto arch, Args&&... args) const
{
return Func<OptionsValues>::deferred_call(arch, EVE_FWD(args)...);
}

protected:
constexpr Func<OptionsValues> const& derived() const { return static_cast<Func<OptionsValues>>(*this); }
};

//====================================================================================================================
//! @addtogroup extensions
//! @{
//! @struct constant_callable
//! @brief CRTP base class giving an EVE's @callable the constant function semantic
//!
//! **Defined in Header**
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! Constants functions in EVE are built using a very common pattern. Inheriting from eve::constant simplifies the
//! implementation of such eve::callable by just requiring your eve::callable type to implement a static `value`
//! member function that provides the constant value using two parameters:
//! * an eve::options pack containing potential decorators passed to the constant.
//! * an eve::as instance to specify the output type.
//!
//! Constant functions in EVE also supports masking, which is directly implemented in eve::constant.
//!
//! @note The deferred overload named in the EVE_CALLABLE_OBJECT macro process is still available if an architecture
//! specific implementation of any given constant is required.
//!
//! @tparam Tag Type of current @callable being implemented
//!
//! @groupheader{Example}
//! @godbolt{doc/traits/callable_constant.cpp}
//! @}
//====================================================================================================================
template< template<typename> class Func
, typename OptionsValues
, typename... Options
>
struct constant_callable : callable<Func, OptionsValues, conditional_option, Options...>
{
template<typename O, typename T>
constexpr auto behavior(auto arch, O const& opts, as<T> const& target) const
{
using func_t = Func<OptionsValues>;
if constexpr( requires{ func_t::deferred_call(arch, opts, target); } )
{
return func_t::deferred_call(arch, opts, target);
}
else
{
// Compute the raw constant
auto const constant_value = Func<OptionsValues>::value(target,opts);

// Apply a mask if any and replace missing values with 0 if no alternative is provided
if constexpr(match_option<condition_key, O, ignore_none_>) return constant_value;
else return detail::mask_op(opts[condition_key], detail::return_2nd, 0, constant_value);
}
}
};
}
174 changes: 174 additions & 0 deletions include/eve/traits/overload/protocol.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
//======================================================================================================================
//! @file
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//======================================================================================================================
#pragma once

#include <eve/arch/tags.hpp>

//======================================================================================================================
//! @addtogroup simd
//! @{
//! @defgroup extensions Extensions points
//! @brief Macros, classes and functions designed to extend EVE externally.
//! @}
//======================================================================================================================

namespace eve
{
//====================================================================================================================
//! @addtogroup extensions
//! @{
//! @concept callable_object
//! @brief **EVE** callable object
//!
//! **Defined in Header**
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! A type `T` satisfies eve::callable_object if and only if it is tagged as such manually.
//!
//! @tparam T T type for the @callable to check
//! @}
//====================================================================================================================
template<typename T, typename...>
concept callable_object = requires(T const&) { typename T::callable_tag_type; };
}

//======================================================================================================================
//! @addtogroup extensions
//! @{
//! @def EVE_CALLABLE_OBJECT_FROM
//! @brief Generate the generic function interface for any EVE-compatible @callable
//!
//! **Defined in Header**
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! Use inside a @callable definition to generate the required EVE protocol of function's resolution based on type
//! and architecture informations.
//!
//! @param NS Namespace in which specialization of the @callable will be found. This namespace must have been
//! registered via EVE_CALLABLE_NAMESPACE.
//! @param TYPE Current @callable type
//! @param NAME Function identifier for overloads. Calls to `NS::NAME` are supposed to succeed.
//!
//! @see EVE_CALLABLE_OBJECT
//! @see EVE_CALLABLE_NAMESPACE
//!
//! @groupheader{Usage}
//!
//! @ref EVE_CALLABLE_OBJECT_FROM generates the expected code for defining a EVE @callable. EVE @callable are function
//! object which supports decorators and use an external function to specify its implementation.
//!
//! @ref EVE_CALLABLE_OBJECT_FROM relies on its enclosing type to provide at least one declaration of a member function
//! named `call` which represent the expected prototype of the function object, including potential constraints, and
//! its associated return type. @ref EVE_CALLABLE_OBJECT also relies on the existence of an appropriate number of
//! function overloads named `NAME` defined in the `NS` namespace. Those function contains the implementation
//! of the @callable overload for each pre-defined function.
//!
//! @groupheader{Example}
//!
//! @godbolt{doc/traits/callable_object_from.cpp}
//! @}
//======================================================================================================================
#define EVE_CALLABLE_OBJECT_FROM(NS,TYPE,NAME) \
template<typename... Args> \
static EVE_FORCEINLINE auto deferred_call(auto arch, Args&&...args) noexcept \
-> decltype(NAME(NS::adl_helper, arch, EVE_FWD(args)...)) \
{ \
return NAME( NS::adl_helper, arch, EVE_FWD(args)...); \
} \
using callable_tag_type = TYPE \
/**/

// THIS MACRO IS DUPLICATED TO ENSURE ERROR MESSAGE QUALITY
//======================================================================================================================
//! @addtogroup extensions
//! @{
//! @def EVE_CALLABLE_OBJECT
//! @brief Generate the generic function interface for an actual eve::callable
//!
//! **Defined in Header**
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! Use inside a @callable definition to generate the required EVE protocol of function's resolution based on type
//! and architecture informations using overload from the `eve::detail` namespace.
//!
//! @warning @ref EVE_CALLABLE_OBJECT is mostly used for EVE @callable definition. If you want to use EVE's overload
//! facility for your own library, use @ref EVE_CALLABLE_OBJECT_FROM.
//!
//! @param TYPE Current @callable type
//! @param NAME Function identifier for overloads. Calls to `eve::detail::NAME` are supposed to succeed.
//!
//! @groupheader{Usage}
//!
//! @ref EVE_CALLABLE_OBJECT generates the expected code for defining a EVE @callable. EVE @callable are function
//! object which supports decorators and use an external function to specify its implementation.
//!
//! @ref EVE_CALLABLE_OBJECT relies on its enclosing type to provide at least one declaration of a member function
//! named `call` which represent the expected prototype of the function object, including potential constraints, and
//! its associated return type. @ref EVE_CALLABLE_OBJECT also relies on the existence of an appropriate number of
//! function overloads named `NAME` defined in the eve::detail namespace. Those function contains the implementation
//! of the @callable overload for each pre-defined function.
//!
//! @groupheader{Example}
//!
//! @godbolt{doc/traits/callable_object.cpp}
//! @}
//======================================================================================================================
#define EVE_CALLABLE_OBJECT(TYPE,NAME) \
template<typename... Args> \
static EVE_FORCEINLINE auto deferred_call(auto arch, Args&&...args) noexcept \
-> decltype(NAME(eve::detail::adl_helper, arch, EVE_FWD(args)...)) \
{ \
return NAME(eve::detail::adl_helper, arch, EVE_FWD(args)...); \
} \
using callable_tag_type = TYPE \
/**/

//======================================================================================================================
//! @addtogroup extensions
//! @{
//! @def EVE_DISPATCH_CALL
//! @brief Generate the proper call to current EVE's @callable implementation
//! @}
//======================================================================================================================
#define EVE_DISPATCH_CALL(...) \
this->behavior(eve::current_api, this->options(), __VA_ARGS__) \
/**/

//======================================================================================================================
//! @addtogroup extensions
//! @{
//! @def EVE_CALLABLE_NAMESPACE
//! @brief Register a namespace as suitable for containing eve::callable overloads.
//! @}
//======================================================================================================================
#define EVE_CALLABLE_NAMESPACE() \
struct adl_helper_t {}; \
inline constexpr auto adl_helper = adl_helper_t {} \
/**/

//======================================================================================================================
//! @addtogroup extensions
//! @{
//! @def EVE_REQUIRES
//! @brief Flag a function to support delayed calls on given architecture
//! @}
//======================================================================================================================
#define EVE_REQUIRES(ARCH) adl_helper_t const &, ARCH const &

// Register eve::detail as the deferred namespace by default
namespace eve::detail { EVE_CALLABLE_NAMESPACE(); }
Loading

0 comments on commit 9c9e7e3

Please sign in to comment.