Replace std::enable_if with requires

Introduce some concepts for enum and flags handling, goodbye and
thanks for all the fish std::enable_if.
This commit is contained in:
Maxime Coste 2020-11-11 21:43:27 +11:00
parent 04f11c2af3
commit fb4cef5b61
10 changed files with 61 additions and 72 deletions

View File

@ -30,8 +30,8 @@ public:
template<size_t N>
constexpr ArrayView(T(&array)[N]) : m_pointer(array), m_size(N) {}
template<typename Container,
typename = std::enable_if_t<sizeof(decltype(*std::declval<Container>().data())) == sizeof(T)>>
template<typename Container>
requires (sizeof(decltype(*std::declval<Container>().data())) == sizeof(T))
constexpr ArrayView(Container&& c)
: m_pointer(c.data()), m_size(c.size()) {}

View File

@ -70,9 +70,8 @@ template<> struct PerArgumentCommandCompleter<>
template<typename Completer, typename... Rest>
struct PerArgumentCommandCompleter<Completer, Rest...> : PerArgumentCommandCompleter<Rest...>
{
template<typename C, typename... R,
typename = std::enable_if_t<not std::is_base_of<PerArgumentCommandCompleter<>,
std::remove_reference_t<C>>::value>>
template<typename C, typename... R>
requires (not std::is_base_of_v<PerArgumentCommandCompleter<>, std::remove_reference_t<C>>)
PerArgumentCommandCompleter(C&& completer, R&&... rest)
: PerArgumentCommandCompleter<Rest...>(std::forward<R>(rest)...),
m_completer(std::forward<C>(completer)) {}

View File

@ -2,12 +2,16 @@
#define enum_hh_INCLUDED
#include "string.hh"
#include "meta.hh"
namespace Kakoune
{
template<typename T> struct EnumDesc { T value; StringView name; };
template<typename T>
concept DescribedEnum = requires { enum_desc(Meta::Type<T>{}); };
}
#endif // enum_hh_INCLUDED

View File

@ -11,22 +11,19 @@ namespace Kakoune
template<typename Flags>
constexpr bool with_bit_ops(Meta::Type<Flags>) { return false; }
template<typename Flags>
concept WithBitOps = with_bit_ops(Meta::Type<Flags>{});
template<typename Flags>
using UnderlyingType = std::underlying_type_t<Flags>;
template<typename Flags, typename T = void>
using EnableIfWithBitOps = std::enable_if_t<with_bit_ops(Meta::Type<Flags>{}), T>;
template<typename Flags, typename T = void>
using EnableIfWithoutBitOps = std::enable_if_t<not with_bit_ops(Meta::Type<Flags>{}), T>;
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr Flags operator|(Flags lhs, Flags rhs)
{
return (Flags)((UnderlyingType<Flags>) lhs | (UnderlyingType<Flags>) rhs);
}
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr Flags& operator|=(Flags& lhs, Flags rhs)
{
(UnderlyingType<Flags>&) lhs |= (UnderlyingType<Flags>) rhs;
@ -45,32 +42,32 @@ struct TestableFlags
constexpr bool operator!=(const TestableFlags<Flags>& other) const { return value != other.value; }
};
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr TestableFlags<Flags> operator&(Flags lhs, Flags rhs)
{
return { (Flags)((UnderlyingType<Flags>) lhs & (UnderlyingType<Flags>) rhs) };
}
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr Flags& operator&=(Flags& lhs, Flags rhs)
{
(UnderlyingType<Flags>&) lhs &= (UnderlyingType<Flags>) rhs;
return lhs;
}
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr Flags operator~(Flags lhs)
{
return (Flags)(~(UnderlyingType<Flags>)lhs);
}
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr Flags operator^(Flags lhs, Flags rhs)
{
return (Flags)((UnderlyingType<Flags>) lhs ^ (UnderlyingType<Flags>) rhs);
}
template<typename Flags, typename = EnableIfWithBitOps<Flags>>
template<WithBitOps Flags>
constexpr Flags& operator^=(Flags& lhs, Flags rhs)
{
(UnderlyingType<Flags>&) lhs ^= (UnderlyingType<Flags>) rhs;

View File

@ -11,16 +11,14 @@ namespace Kakoune
size_t hash_data(const char* data, size_t len);
template<typename Type>
std::enable_if_t<std::is_integral<Type>::value, size_t>
constexpr hash_value(const Type& val)
template<typename Type> requires std::is_integral_v<Type>
constexpr size_t hash_value(const Type& val)
{
return (size_t)val;
}
template<typename Type>
std::enable_if_t<std::is_enum<Type>::value, size_t>
constexpr hash_value(const Type& val)
template<typename Type> requires std::is_enum_v<Type>
constexpr size_t hash_value(const Type& val)
{
return hash_value((std::underlying_type_t<Type>)val);
}

View File

@ -182,12 +182,7 @@ struct HashMap
return m_items.back().value;
}
template<typename KeyType>
using EnableIfHashCompatible = std::enable_if_t<
IsHashCompatible<Key, std::decay_t<KeyType>>
>;
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr int find_index(const KeyType& key, size_t hash) const
{
for (auto slot = m_index.compute_slot(hash); slot < m_index.size(); ++slot)
@ -201,13 +196,13 @@ struct HashMap
return -1;
}
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr int find_index(const KeyType& key) const { return find_index(key, hash_value(key)); }
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr bool contains(const KeyType& key) const { return find_index(key) >= 0; }
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, std::remove_cvref_t<KeyType>>
constexpr Value& operator[](KeyType&& key)
{
const auto hash = hash_value(key);
@ -221,7 +216,7 @@ struct HashMap
return m_items.back().value;
}
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr void remove(const KeyType& key)
{
const auto hash = hash_value(key);
@ -234,7 +229,7 @@ struct HashMap
}
}
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr void unordered_remove(const KeyType& key)
{
const auto hash = hash_value(key);
@ -249,10 +244,10 @@ struct HashMap
}
}
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr void erase(const KeyType& key) { unordered_remove(key); }
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr void remove_all(const KeyType& key)
{
const auto hash = hash_value(key);
@ -275,14 +270,14 @@ struct HashMap
const Item& item(size_t index) const { return m_items[index]; }
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr iterator find(const KeyType& key)
{
auto index = find_index(key);
return index >= 0 ? begin() + index : end();
}
template<typename KeyType, typename = EnableIfHashCompatible<KeyType>>
template<typename KeyType> requires IsHashCompatible<Key, KeyType>
constexpr const_iterator find(const KeyType& key) const
{
return const_cast<HashMap*>(this)->find(key);

View File

@ -19,8 +19,8 @@ namespace Kakoune
{
template<typename T>
std::enable_if_t<std::is_same<decltype(option_to_string(std::declval<T>())), String>::value, String>
option_to_string(const T& value, Quoting)
String option_to_string(const T& value, Quoting)
requires std::is_same_v<decltype(option_to_string(std::declval<T>())), String>
{
return option_to_string(value);
}
@ -31,9 +31,8 @@ constexpr decltype(T::option_type_name) option_type_name(Meta::Type<T>)
return T::option_type_name;
}
template<typename Enum>
std::enable_if_t<std::is_enum<Enum>::value, String>
option_type_name(Meta::Type<Enum>)
template<typename Enum> requires std::is_enum_v<Enum>
String option_type_name(Meta::Type<Enum>)
{
return format("{}({})", with_bit_ops(Meta::Type<Enum>{}) ? "flags" : "enum",
join(enum_desc(Meta::Type<Enum>{}) |
@ -256,8 +255,8 @@ inline String option_to_string(const StronglyTypedNumber<RealType, ValueType>& o
}
template<typename Number>
std::enable_if_t<std::is_base_of<StronglyTypedNumber<Number, int>, Number>::value, Number>
option_from_string(Meta::Type<Number>, StringView str)
requires std::is_base_of_v<StronglyTypedNumber<Number, int>, Number>
Number option_from_string(Meta::Type<Number>, StringView str)
{
return Number{str_to_int(str)};
}
@ -290,8 +289,8 @@ inline void option_update(WorstMatch, const Context&)
}
template<typename Coord>
std::enable_if_t<std::is_base_of<LineAndColumn<Coord, decltype(Coord::line), decltype(Coord::column)>, Coord>::value, Coord>
option_from_string(Meta::Type<Coord>, StringView str)
requires std::is_base_of_v<LineAndColumn<Coord, decltype(Coord::line), decltype(Coord::column)>, Coord>
Coord option_from_string(Meta::Type<Coord>, StringView str)
{
struct error : runtime_error { error(size_t) : runtime_error{"expected <line>,<column>"} {} };
auto vals = str | split<StringView>(',')
@ -305,8 +304,8 @@ inline String option_to_string(const LineAndColumn<EffectiveType, LineType, Colu
return format("{},{}", opt.line, opt.column);
}
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, String> option_to_string(Flags flags)
template<DescribedEnum Flags> requires WithBitOps<Flags>
String option_to_string(Flags flags)
{
constexpr auto desc = enum_desc(Meta::Type<Flags>{});
String res;
@ -321,8 +320,8 @@ EnableIfWithBitOps<Flags, String> option_to_string(Flags flags)
return res;
}
template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
template<DescribedEnum Enum> requires (not WithBitOps<Enum>)
String option_to_string(Enum e)
{
constexpr auto desc = enum_desc(Meta::Type<Enum>{});
auto it = find_if(desc, [e](const EnumDesc<Enum>& d) { return d.value == e; });
@ -332,8 +331,8 @@ EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
return {};
}
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, Flags> option_from_string(Meta::Type<Flags>, StringView str)
template<DescribedEnum Flags> requires WithBitOps<Flags>
Flags option_from_string(Meta::Type<Flags>, StringView str)
{
constexpr auto desc = enum_desc(Meta::Type<Flags>{});
Flags flags{};
@ -347,8 +346,8 @@ EnableIfWithBitOps<Flags, Flags> option_from_string(Meta::Type<Flags>, StringVie
return flags;
}
template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
EnableIfWithoutBitOps<Enum, Enum> option_from_string(Meta::Type<Enum>, StringView str)
template<DescribedEnum Enum> requires (not WithBitOps<Enum>)
Enum option_from_string(Meta::Type<Enum>, StringView str)
{
constexpr auto desc = enum_desc(Meta::Type<Enum>{});
auto it = find_if(desc, [str](const EnumDesc<Enum>& d) { return d.name == str; });
@ -357,16 +356,16 @@ EnableIfWithoutBitOps<Enum, Enum> option_from_string(Meta::Type<Enum>, StringVie
return it->value;
}
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str)
template<DescribedEnum Flags> requires WithBitOps<Flags>
bool option_add(Flags& opt, StringView str)
{
const Flags old = opt;
opt |= option_from_string(Meta::Type<Flags>{}, str);
return opt != old;
}
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, bool> option_remove(Flags& opt, StringView str)
template<DescribedEnum Flags> requires WithBitOps<Flags>
bool option_remove(Flags& opt, StringView str)
{
const Flags old = opt;
opt &= ~option_from_string(Meta::Type<Flags>{}, str);

View File

@ -136,14 +136,12 @@ decltype(auto) to_string(const StronglyTypedNumber<RealType, ValueType>& val)
namespace detail
{
template<typename T> constexpr bool is_string = std::is_convertible<T, StringView>::value;
template<typename T, class = std::enable_if_t<not is_string<T>>>
decltype(auto) format_param(const T& val) { return to_string(val); }
template<typename T, class = std::enable_if_t<is_string<T>>>
template<typename T> requires std::is_convertible_v<T, StringView>
StringView format_param(const T& val) { return val; }
template<typename T> requires (not std::is_convertible_v<T, StringView>)
decltype(auto) format_param(const T& val) { return to_string(val); }
}
String format(StringView fmt, ArrayView<const StringView> params);

View File

@ -109,12 +109,12 @@ public:
bool operator>= (const iterator& other) const noexcept { return m_it >= other.m_it; }
template<typename T>
std::enable_if_t<std::is_same<T, BaseIt>::value or std::is_same<T, Sentinel>::value, bool>
operator==(const T& other) const noexcept { return m_it == other; }
requires std::is_same_v<T, BaseIt> or std::is_same_v<T, Sentinel>
bool operator==(const T& other) const noexcept { return m_it == other; }
template<typename T>
std::enable_if_t<std::is_same<T, BaseIt>::value or std::is_same<T, Sentinel>::value, bool>
operator!=(const T& other) const noexcept { return m_it != other; }
requires std::is_same_v<T, BaseIt> or std::is_same_v<T, Sentinel>
bool operator!=(const T& other) const noexcept { return m_it != other; }
bool operator< (const BaseIt& other) const noexcept { return m_it < other; }
bool operator<= (const BaseIt& other) const noexcept { return m_it <= other; }

View File

@ -16,8 +16,7 @@ struct Value
{
Value() = default;
template<typename T,
typename = std::enable_if_t<not std::is_same<Value, T>::value>>
template<typename T> requires (not std::is_same_v<Value, T>)
Value(T&& val)
: m_value{new Model<std::decay_t<T>>{std::forward<T>(val)}} {}