- More documentation

This commit is contained in:
2025-12-18 16:18:07 -05:00
parent 9e6f00eb60
commit 88e33bdcc8
50 changed files with 987 additions and 264 deletions

View File

@@ -68,21 +68,32 @@
#define __PRETTY_FUNCTION__ __FUNCSIG__
#endif
using assert_handler = void (*)(const char *, const char *, int , const char *);
#ifndef FENNEC_DOXYGEN
void _assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc, bool halt);
#endif
// flagged unlikely to optimize branch prediction
///
/// \brief base assert function, halts only in debug mode
/// \param expression the expression to validate
/// \param description the description of the assertion
#define assert(expression, description) \
if(not(expression)) [[unlikely]] { \
_assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, not FENNEC_RELEASE); \
}
///
/// \brief fail assert function, always halts
/// \param expression the expression to validate
/// \param description the description of the assertion
#define assertf(expression, description) \
if(not(expression)) [[unlikely]] { \
_assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, true); \
}
///
/// \brief debug assert function, only defined in debug mode
/// \param expression the expression to validate
/// \param description the description of the assertion
#if FENNEC_RELEASE
#define assertd(expression, description)
#else

View File

@@ -26,27 +26,58 @@ namespace fennec
// equality ============================================================================================================
///
/// \brief Struct to test equality of two values
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> struct equality;
///
/// \brief Implementations for two types that have a common equality operator \f$==\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct equality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x == y;
}
};
///
/// \brief Implementations for two types that have a common less operator \f$<\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires(not has_equals_v<T0, T1>
and has_less_v<T0, T1> and has_less_v<T1, T0>)
struct equality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return not(x < y) and not(y < x);
}
};
///
/// \brief Implementations for two types that have a common greater operator \f$>\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires(not(has_equals_v<T0, T1>)
and(not has_less_v<T0, T1> or not has_less_v<T1, T0>)
and(has_greater_v<T0, T1> and has_greater_v<T1, T0>))
struct equality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return not(x > y) and not(y > x);
}
@@ -55,24 +86,72 @@ struct equality<T0, T1> {
// inequality ==========================================================================================================
///
/// \brief Struct to test inequality of two values
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> struct inequality;
///
/// \brief Implementations for two types that have a common inequality operator \f$\neq\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_nequals_v<T0, T1>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x != y;
}
};
///
/// \brief Implementations for two types that have a common equality operator \f$==\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return not (x == y);
}
};
///
/// \brief Implementations for two types that have a common less operator \f$<\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return (x < y) or (y < x);
}
};
///
/// \brief Implementations for two types that have a common greater operator \f$>\f$
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return (x > y) or (y > x);
}
@@ -81,8 +160,17 @@ struct inequality<T0, T1> {
// less ================================================================================================================
///
/// \brief Struct to test if a value of type `T0` is less than a value of type `T1`
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_less_v<T0, T1>
struct less {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if less, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x < y;
}
@@ -91,30 +179,57 @@ struct less {
// less_equal ==========================================================================================================
///
/// \brief Struct to test if a value of type `T0` is less than or equal to a value of type `T1`
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1>
struct less_equals {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if less than or equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x <= y;
}
};
// less ================================================================================================================
// greater =============================================================================================================
///
/// \brief Struct to test if a value of type `T0` is greater than a value of type `T1`
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1>
struct greater {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if greater, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x < y;
return x > y;
}
};
// less_equal ==========================================================================================================
///
/// \brief Struct to test if a value of type `T0` is greater than or equal to a value of type `T1`
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1>
struct greater_equals {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if greater than or equal, \f$false\f$ otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x <= y;
return x >= y;
}
};

View File

@@ -89,7 +89,7 @@ template<bool B, typename TrueT, typename FalseT>
using conditional_t
= typename conditional<B, TrueT, FalseT>::type;
#ifndef FENNEC_DOXYGEN
// specialization of fennec::conditional for \f$true\f$ case
template<typename T, typename F>
struct conditional<true, T, F> : type_identity<T>{};
@@ -98,7 +98,7 @@ struct conditional<true, T, F> : type_identity<T>{};
// specialization of fennec::conditional for \f$false\f$ case
template<typename T, typename F>
struct conditional<false, T, F> : type_identity<F>{};
#endif
// fennec::detect ======================================================================================================
@@ -113,8 +113,8 @@ struct conditional<false, T, F> : type_identity<F>{};
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
struct detect
{
using type = DefaultT;
static constexpr bool is_detected = false;
using type = DefaultT; //!< the detected type
static constexpr bool is_detected = false; //!< whether it was detected
};
///
@@ -123,6 +123,7 @@ template<typename DefaultT, template<typename...> typename DetectT, typename...A
using detect_t = typename detect<DefaultT, DetectT, ArgsT...>::type;
#ifndef FENNEC_DOXYGEN
// true case
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
requires requires { typename DetectT<ArgsT...>; }
@@ -131,6 +132,7 @@ struct detect<DefaultT, DetectT, ArgsT...>
using type = DetectT<ArgsT...>;
static constexpr bool is_detected = true;
};
#endif
// fennec::enable_if ===================================================================================================
@@ -156,9 +158,11 @@ struct enable_if {};
template<bool B, typename T = void>
using enable_if_t = typename enable_if<B, T>::type;
#ifndef FENNEC_DOXYGEN
// true case
template<typename T>
struct enable_if<true, T> { using type = T; };
#endif
}

View File

@@ -28,8 +28,8 @@
///
///
#ifndef FENNEC_LANGCPP_DECLVAL_H
#define FENNEC_LANGCPP_DECLVAL_H
#ifndef FENNEC_LANG_DECLVAL_H
#define FENNEC_LANG_DECLVAL_H
#include <fennec/lang/detail/_declval.h>
@@ -38,6 +38,10 @@ namespace fennec
// fennec::declval =====================================================================================================
///
/// \brief Metaprogramming helper for testing values of type T
/// \tparam T the type
/// \returns a metavalue of type \f$T\f$
template<typename T> auto declval() noexcept -> decltype(detail::_declval<T>(0)) {
static_assert(detail::_declval_protector<T>{}, "declval must not be used");
return detail::_declval<T>(0);
@@ -45,4 +49,4 @@ template<typename T> auto declval() noexcept -> decltype(detail::_declval<T>(0))
}
#endif // FENNEC_LANGCPP_DECLVAL_H
#endif // FENNEC_LANG_DECLVAL_H

View File

@@ -40,39 +40,86 @@
namespace fennec
{
///
/// \brief a class capable of holding a function or non-capturing lambda
template<typename> class function;
///
/// \brief a class capable of holding a function or non-capturing lambda
/// \tparam ReturnT The return type of the function
/// \tparam ArgsT The argument types of the function
template<typename ReturnT, typename...ArgsT>
class function<ReturnT(ArgsT...)> {
public:
///
/// \brief default constructor
constexpr function() noexcept = default;
///
/// \brief destructor
constexpr ~function() = default;
constexpr function(const function&) noexcept = default;
constexpr function( function&&) noexcept = default;
///
/// \brief copy constructor
/// \param func the function to copy
constexpr function(const function& func) noexcept = default;
///
/// \brief move constructor
/// \param func the function to take ownership of
constexpr function(function&& func) noexcept = default;
///
/// \brief function constructor
/// \param func the function to capture
constexpr function(ReturnT (*func)(ArgsT...))
: call(func) {
}
///
/// \brief null constructor
constexpr function(nullptr_t) noexcept : function() {}
constexpr function& operator=(const function&) = default;
constexpr function& operator=(function&&) = default;
///
/// \brief copy assignment
/// \param func the function to copy
/// \returns a reference to self
constexpr function& operator=(const function& func) = default;
///
/// \brief move assignment
/// \param func the function to capture
/// \returns a reference to self
constexpr function& operator=(function&& func) = default;
///
/// \brief null assignment
/// \returns a reference to self
constexpr function& operator=(nullptr_t) {
call = nullptr;
return *this;
}
///
/// \brief function assignment
/// \param func the function to capture
/// \returns a reference to self
constexpr function& operator=(ReturnT (*func)(ArgsT...)) {
call = func;
return *this;
}
constexpr operator bool() const noexcept { return call != nullptr; }
///
/// \brief implicit bool check
/// \returns \f$true\f$ if a function is captured, \f$false\f$ otherwise
constexpr operator bool() const noexcept {
return call != nullptr;
}
///
/// \brief function call operator
/// \param args the arguments to call the function with
/// \returns the result of the function call
ReturnT operator()(ArgsT...args) const noexcept {
assertf(call != nullptr, "Attempted to call a null function object!");
return call(fennec::forward<ArgsT>(args)...);

View File

@@ -31,10 +31,13 @@ namespace fennec
/// \tparam Key The type to hash
template<typename Key> struct hash;
// Murmur3 Hash for 64-bit ints
/// \brief Murmur3 Hash for 64-bit ints
template<>
struct hash<uint64_t> {
using type_t = uint64_t;
using type_t = uint64_t; //!< the type of the hash
/// \brief hash operator
/// \param x the value to hash
/// \returns an integer hash for the value
constexpr size_t operator()(uint64_t x) const {
// Murmur3
x ^= x >> 33U;
@@ -46,16 +49,22 @@ struct hash<uint64_t> {
}
};
// Wrapper for casting ints
/// \brief Hashing for integer types
/// \tparam IntT the integer type
template<typename IntT>
requires is_integral_v<IntT>
struct hash<IntT> : hash<uint64_t> {
using type_t = IntT;
using type_t = IntT; //!< the type of the hash
};
// Wrapper for pointers
/// \brief Hashing for pointer types
/// \tparam PtrT The base type
template<typename PtrT>
struct hash<PtrT*> : hash<uintptr_t> {
using type_t = PtrT*; //!< the type of the hash
/// \brief hash operator
/// \param ptr the pointer to hash
/// \returns an integer hash for the value
constexpr size_t operator()(PtrT* ptr) const {
return hash<uintptr_t>::operator()((uintptr_t)(const void*)ptr);
}
@@ -64,6 +73,10 @@ struct hash<PtrT*> : hash<uintptr_t> {
// Float
template<>
struct hash<float> : hash<uint32_t> {
using type_t = float; //!< the type of the hash
/// \brief hash operator
/// \param x the value to hash
/// \returns an integer hash for the value
constexpr size_t operator()(float x) const {
return hash<uint32_t>::operator()(bit_cast<uint32_t>(x));
}
@@ -71,6 +84,10 @@ struct hash<float> : hash<uint32_t> {
template<>
struct hash<double> : hash<uint64_t> {
using type_t = double; //!< the type of the hash
/// \brief hash operator
/// \param x the value to hash
/// \returns an integer hash for the value
constexpr size_t operator()(double x) const {
return hash<uint64_t>::operator()(bit_cast<uint64_t>(x));
}

View File

@@ -28,40 +28,72 @@
///
///
#ifndef FENNEC_LANGCPP_RANGES_H
#define FENNEC_LANGCPP_RANGES_H
#ifndef FENNEC_LANG_RANGES_H
#define FENNEC_LANG_RANGES_H
#include <fennec/lang/types.h>
namespace fennec
{
///
/// \brief C++ Iterator Specification `begin()`
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the start of the container
template<typename ContainerT>
inline constexpr auto begin(ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
return c.begin();
}
///
/// \brief C++ Iterator Specification `begin()`
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the start of the container
template<typename ContainerT>
inline constexpr auto begin(const ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
return c.begin();
}
///
/// \brief C++ Iterator Specification `begin()`
/// \tparam T the element type
/// \tparam N the bounds of the array
/// \param arr a bounded array to iterate on
/// \returns an iterator at the start of the array
template<typename T, size_t N>
inline constexpr T* begin(T (&arr)[N]) noexcept {
return arr;
}
///
/// \brief C++ Iterator Specification `end()`
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the end of the container
template<typename ContainerT>
inline constexpr auto end(ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
return c.end();
}
///
/// \brief C++ Iterator Specification `end()`
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the end of the container
template<typename ContainerT>
inline constexpr auto end(const ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
return c.end();
}
///
/// \brief C++ Iterator Specification `end()`
/// \tparam T the element type
/// \tparam N the bounds of the array
/// \param arr a bounded array to iterate on
/// \returns an iterator at the end of the array
template<typename T, size_t N>
inline constexpr T* end(T (&arr)[N]) noexcept {
return arr + N;
@@ -69,4 +101,4 @@ inline constexpr T* end(T (&arr)[N]) noexcept {
}
#endif // FENNEC_LANGCPP_RANGES_H
#endif // FENNEC_LANG_RANGES_H

View File

@@ -19,12 +19,17 @@
#ifndef FENNEC_LANG_STARTUP_H
#define FENNEC_LANG_STARTUP_H
// Helper for running a function before main()
///
/// \brief Macro for running a function before main
/// \param f the name of the function
#define FENNEC_PRIVATE_STATIC_CONSTRUCTOR(f) \
inline static void f(void); \
struct f##_t_ { inline f##_t_(void) { f(); } }; inline static f##_t_ f##_; \
inline static void f(void)
///
/// \brief Macro for running a function before main in a class scope
/// \param f the name of the function
#define FENNEC_CLASS_STATIC_CONSTRUCTOR(f) \
struct f##_t_ { inline f##_t_(void) { f(); } }; inline static f##_t_ f##_; \
inline static void f(void)

View File

@@ -26,26 +26,38 @@ namespace fennec
// has_equals ==========================================================================================================
///
/// \brief Checks if a type has a defined equality operator
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0>
struct has_equals {
private:
// Use SFINAE to check for the operator
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() == declval<V>());
template<typename, typename> static auto test(...) -> false_type;
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
public:
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>; //!< The result of the check
};
template<typename T0, typename T1 = T0> constexpr bool has_equals_v = has_equals<T0, T1>::value;
// has_nequals =========================================================================================================
///
/// \brief Checks if a type has a defined inequality operator
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0>
struct has_nequals {
private:
// Use SFINAE to check for the operator
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() != declval<V>());
template<typename, typename> static auto test(...) -> false_type;
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
public:
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>; //!< The result of the check
};
template<typename T0, typename T1 = T0> constexpr bool has_nequals_v = has_nequals<T0, T1>::value;
@@ -53,13 +65,19 @@ template<typename T0, typename T1 = T0> constexpr bool has_nequals_v = has_nequa
// has_less ============================================================================================================
///
/// \brief Checks if a type has a defined less operator
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0>
struct has_less {
private:
// Use SFINAE to check for the operator
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() < declval<V>());
template<typename, typename> static auto test(...) -> false_type;
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
public:
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>; //!< The result of the check
};
template<typename T0, typename T1 = T0> constexpr bool has_less_v = has_less<T0, T1>::value;
@@ -67,13 +85,19 @@ template<typename T0, typename T1 = T0> constexpr bool has_less_v = has_less<T0,
// has_less_equals =====================================================================================================
///
/// \brief Checks if a type has a defined less equals operator
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0>
struct has_less_equals {
private:
// Use SFINAE to check for the operator
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() <= declval<V>());
template<typename, typename> static auto test(...) -> false_type;
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
public:
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>; //!< The result of the check
};
template<typename T0, typename T1 = T0> constexpr bool has_less_equals_v = has_less_equals<T0, T1>::value;
@@ -81,13 +105,19 @@ template<typename T0, typename T1 = T0> constexpr bool has_less_equals_v = has_l
// has_greater =========================================================================================================
///
/// \brief Checks if a type has a defined greater operator
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0>
struct has_greater {
private:
// Use SFINAE to check for the operator
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() > declval<V>());
template<typename, typename> static auto test(...) -> false_type;
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
public:
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>; //!< The result of the check
};
template<typename T0, typename T1 = T0> constexpr bool has_greater_v = has_greater<T0, T1>::value;
@@ -95,13 +125,19 @@ template<typename T0, typename T1 = T0> constexpr bool has_greater_v = has_great
// has_greater_equals ==================================================================================================
///
/// \brief Checks if a type has a defined greater equals operator
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0>
struct has_greater_equals {
private:
// Use SFINAE to check for the operator
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() >= declval<V>());
template<typename, typename> static auto test(...) -> false_type;
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
public:
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>; //!< The result of the check
};
template<typename T0, typename T1 = T0> constexpr bool has_greater_equals_v = has_greater_equals<T0, T1>::value;

View File

@@ -77,7 +77,8 @@ template<typename...TypesT> struct type_sequence {};
template<typename...TypesT> struct first_element : detail::_first_element<TypesT...> {};
///
/// \brief alias for first_element<TypesT>::type
/// \brief alias for `first_element<TypesT...>::type`
/// \tparam TypesT the Parameter Pack
template<typename...TypesT> using first_element_t = typename first_element<TypesT...>::type;
@@ -90,6 +91,10 @@ template<typename...TypesT> using first_element_t = typename first_element<Types
/// \tparam TypesT The type sequence
template<size_t n, typename...TypesT> struct nth_element : detail::_nth_element<n, 0, TypesT...> {};
///
/// \brief alias for nth_element<n, TypesT>::type
/// \tparam n The index in the type sequence
/// \tparam TypesT the Parameter Pack
template<size_t n, typename...TypesT> using nth_element_t = nth_element<n, TypesT...>::type;
@@ -100,6 +105,7 @@ template<size_t n, typename...TypesT> using nth_element_t = nth_element<n, Types
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first \f$ArgT\f$ of `ArgsT...` with \f$SubT\f$
template<typename ClassT, typename SubT> struct replace_first_element { };
#ifndef FENNEC_DOXYGEN
// Implementation
template<
template<typename, typename...> class ClassT // The Base Template
@@ -107,6 +113,7 @@ template<
, typename... RestT> // The Rest of the Parameter Pack
struct replace_first_element<ClassT<OriginT, RestT...>, SubT> // Specialization
{ using type = ClassT<SubT, RestT...>; }; // Definition
#endif
@@ -155,9 +162,13 @@ template<template<typename> typename SearchT, typename...TypesT> struct search_e
/// \tparam TypesT The type sequence to search
template<template<typename> typename SearchT, typename...TypesT> using search_element_t = search_element<SearchT, TypesT...>::type;
template<template<typename, typename...> typename, typename, typename...> struct search_element_args;
///
/// \brief Find the first element `T` in `TypesT...` that satisfies `SearchT<T, ArgsT...>`
/// \tparam SearchT A type that satisfies `template<typename>` and contains `static constexpr bool value;` to use for searching
/// \tparam TypesT The type sequence to search
/// \tparam ArgsT The arguments for the search
template<template<typename, typename...> typename SearchT, typename...TypesT, typename...ArgsT>
struct search_element_args<SearchT, type_sequence<ArgsT...>, TypesT...>
: detail::_search_element_args<SearchT, detail::_type_sequence<ArgsT...>, TypesT...> {
@@ -187,14 +198,16 @@ template<typename T, typename...Ts> constexpr bool contains_element_v = contains
///
/// \brief Checks if all types in a type sequence are unique
/// \tparam Ts The type sequence to check
template<typename...Ts> struct is_unique : false_type {};
template<typename...Ts> struct is_unique : false_type {};
#ifndef FENNEC_DOXYGEN
// Single type case
template<typename T> struct is_unique<T> : true_type {};
// Recursion case
template<typename T, typename...Ts> requires(not is_same_v<T, Ts> && ...)
struct is_unique<T, Ts...> : is_unique<Ts...> {};
#endif
///
/// \brief Shorthand for `is_unique<Ts...>::value`

View File

@@ -434,6 +434,9 @@
namespace fennec
{
///
/// \brief metaprogramming helper for determining if a function is consteval
/// \returns \f$true\f$ if under `consteval`, \f$false\f$ otherwise
constexpr inline bool is_constant_evaluated() noexcept {
if consteval {
return true;
@@ -1147,12 +1150,14 @@ template<typename T> struct is_scoped_enum
template<typename T> struct is_scoped_enum
: false_type {};
#ifndef FENNEC_DOXYGEN
// true case
template<typename T>
requires __is_enum(T) and requires(remove_cv_t<T> test) { test = test; } // fails if incomplete
struct is_scoped_enum<T>
: bool_constant<!requires(T test, void(*testf)(int)) { testf(test); }> {
};
#endif
#endif

View File

@@ -129,8 +129,14 @@ namespace fennec
// Decay Conversions ===================================================================================================
///
/// \brief decays a type into its most basic form
/// \tparam T the type to decay
template<typename T> struct decay : detail::_decay<T> {};
///
/// \brief shorthand for `typename decay<T>::type`
/// \tparam T the type to decay
template<typename T> using decay_t = typename decay<T>::type;
// Pointer Conversions =================================================================================================
@@ -170,6 +176,8 @@ template<typename T> struct strip_pointers : conditional_t<
type_identity<T>
> {};
///
/// \brief shorthand for `typename strip_pointers<T>::type`
template<typename T> using strip_pointers_t = strip_pointers<T>::type;

View File

@@ -76,10 +76,12 @@ template<typename T> constexpr T&& forward(remove_reference_t<T>& x) noexcept {
return static_cast<T&&>(x);
}
#ifndef FENNEC_DOXYGEN
// specialization for T&&
template<typename T> constexpr T&& forward(remove_reference_t<T>&& x) noexcept {
return static_cast<T&&>(x);
}
#endif
///