General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

306 lines
6.8 KiB

#pragma once
#include <type_traits>
#include <typeinfo>
#include <cstddef>
#include <limits>
#include "gp/algorithm/min_max.hpp"
namespace gp{
/**
* @brief Picks either of the types depending on the condition
*
* @tparam cond the condition
* @tparam T the type picked when the condition is true
* @tparam U the type picked when the condition is false
*/
template<bool cond, typename T, typename U>
struct either
{
};
template<typename T, typename U>
struct either<true,T,U>
{
typedef T type;
};
template<typename T, typename U>
struct either<false,T,U>
{
typedef U type;
};
/**
* @brief Checks if the provided booleans are all true at compile time
*/
template<bool first, bool ...list>
struct constexpr_all_of
{
static constexpr bool value = first && constexpr_all_of<list...>::value;
};
template<bool first>
struct constexpr_all_of<first>
{
static constexpr bool value = first;
};
/**
* @brief Checks if at least one of the provided booleans is true at compile time
*/
template<bool first, bool ...list>
struct constexpr_any_of
{
static constexpr bool value = first || constexpr_any_of<list...>::value;
};
template<bool first>
struct constexpr_any_of<first>
{
static constexpr bool value = first;
};
/**
* @brief Checks if the provided type has a compile time defined size
*
* @tparam T the tested type
* @return true if it has a defined size
* @return false if its size may change due to inheritance or other factors
*/
template<typename T>
constexpr bool is_fixed_size()
{
return std::is_final<T>::value
|| std::is_fundamental<T>::value;
}
/**
* @brief Checks if the provided typelist is all of fixed size
*/
template<typename T, typename ...rest>
struct all_of_fixed_size
{
static constexpr bool value = is_fixed_size<T>() && all_of_fixed_size<rest...>::value;
};
template<typename T>
struct all_of_fixed_size<T>
{
static constexpr bool value = is_fixed_size<T>();
};
/**
* @brief Checks if the provided list contains the provided class
*
* @tparam Univ the class to look for
*/
template<typename Univ, typename T, typename ...rest>
struct list_contains_class
{
static constexpr bool value = (
std::is_same<T, Univ>::value
) || list_contains_class<Univ, rest...>::value;
};
template<typename Univ, typename T>
struct list_contains_class<Univ, T>
{
static constexpr bool value = std::is_same<T, Univ>::value;
};
/**
* @brief gives the index of Univ from the end of the argument list
*
* @tparam Univ The type to look for
*/
template<typename Univ, typename T, typename ...rest>
struct r_index_of
{
static constexpr std::size_t value = std::is_same<T, Univ>::value ? sizeof...(rest) : r_index_of<Univ, rest...>::value;
};
template<typename Univ, typename T>
struct r_index_of<Univ, T>
{
static constexpr std::size_t value = std::is_same<T, Univ>::value ? 0 : std::numeric_limits<std::size_t>::max();
};
/**
* @brief gives the type of the idx value from the end of the argument list
*
* @tparam idx The index to return the type of
*/
template<size_t idx, typename T, typename ...rest>
struct r_index_at
{
using type =
typename either<
idx==sizeof...(rest),
T,
typename r_index_at<idx,rest...>::type
>::type;
};
/**
* @brief extracts the first type of the list
*/
template<typename U, typename ...rest>
struct first_of {
using type = U;
};
/**
* @brief gives the size of the largest element in the provided list
*
* @return constexpr std::size_t equal to the largest size of all
*/
template<typename T, typename U, typename ...rest>
constexpr std::size_t max_size()
{
if constexpr (sizeof...(rest) == 0)
{
return gp::max(sizeof(T),sizeof(U));
}
else
{
return max_size<
typename either<
( sizeof(T) > sizeof(U) ),
T,
U
>::type,
rest...>();
}
}
/**
* @brief remove reference state from the provided type
*/
template<typename T>
struct remove_reference
{
using type = T;
};
template<typename T>
struct remove_reference<T&>
{
using type = T;
};
template<typename T>
struct remove_reference<T&&>
{
using type = T;
};
/**
* @brief Has a value of true if the provided type has a size() function member
*/
template<typename T>
struct has_size_interface
{
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U, size_t (U::*f)() const> struct SFINAE{};
template<class C> static yes test(SFINAE<C,&C::size>*);
template<class C> static no test(...);
public:
static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
};
/**
* @brief Has a value of true if the provided type has a begin() function member
*/
template<typename T>
struct has_begin_interface
{
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U, auto (U::*f)() const> struct SFINAE{};
template<class C> static yes test(SFINAE<C,&C::begin>*);
template<class C> static no test(...);
public:
static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
};
/**
* @brief Has a value of true if the provided type has a end() function member
*/
template<typename T>
struct has_end_interface
{
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U, auto (U::*f)() const> struct SFINAE{};
template<class C> static yes test(SFINAE<C,&C::end>*);
template<class C> static no test(...);
public:
static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
};
// TODO: Replace those with concepts
template<typename T>
using has_range_interface = constexpr_all_of<has_begin_interface<T>::value,has_end_interface<T>::value>;
template<typename T>
using has_measurable_range_interface = constexpr_all_of<has_range_interface<T>::value,has_size_interface<T>::value>;
template<typename T>
struct has_allocate_interface
{
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U, void* (U::*f)(size_t)> struct SFINAE{};
template<class C> static yes test(SFINAE<C,&C::allocate>*);
template<class C> static no test(...);
public:
static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
};
template<typename T>
struct has_deallocate_interface
{
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U, bool (U::*f)(void*)> struct SFINAE{};
template<class C> static yes test(SFINAE<C,&C::deallocate>*);
template<class C> static no test(...);
public:
static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
};
template<typename T>
using has_allocator_interface = constexpr_all_of<has_allocate_interface<T>::value,has_deallocate_interface<T>::value>;
}