mirror of
https://github.com/matrix-construct/construct
synced 2024-12-28 16:34:13 +01:00
147 lines
3.8 KiB
C++
147 lines
3.8 KiB
C++
// Matrix Construct
|
|
//
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
// full license for this software is available in the LICENSE file.
|
|
|
|
#pragma once
|
|
#define HAVE_IRCD_UTIL_ENUM_H
|
|
|
|
namespace ircd::util {
|
|
|
|
// For conforming enums include a _NUM_ as the last element,
|
|
// then num_of<my_enum>() works
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::underlying_type<Enum>::type
|
|
num_of()
|
|
{
|
|
return static_cast<typename std::underlying_type<Enum>::type>(Enum::_NUM_);
|
|
}
|
|
|
|
// Iteration of a num_of() conforming enum
|
|
template<class Enum>
|
|
typename std::enable_if<std::is_enum<Enum>::value, void>::type
|
|
for_each(const std::function<void (const Enum &)> &func)
|
|
{
|
|
for(size_t i(0); i < num_of<Enum>(); ++i)
|
|
func(static_cast<Enum>(i));
|
|
}
|
|
|
|
/**
|
|
* flag-enum utilities
|
|
*
|
|
* This relaxes the strong typing of enums to allow bitflags with operations on the elements
|
|
* with intuitive behavior.
|
|
*
|
|
* If the project desires absolute guarantees on the strong enum typing then this can be tucked
|
|
* away in some namespace and imported into select scopes instead.
|
|
*/
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum>::type
|
|
operator~(const Enum &a)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return static_cast<Enum>(~static_cast<enum_t>(a));
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, bool>::type
|
|
operator!(const Enum &a)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return !static_cast<enum_t>(a);
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum>::type
|
|
operator|(const Enum &a, const Enum &b)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return static_cast<Enum>(static_cast<enum_t>(a) | static_cast<enum_t>(b));
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum>::type
|
|
operator&(const Enum &a, const Enum &b)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return static_cast<Enum>(static_cast<enum_t>(a) & static_cast<enum_t>(b));
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum>::type
|
|
operator^(const Enum &a, const Enum &b)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return static_cast<Enum>(static_cast<enum_t>(a) ^ static_cast<enum_t>(b));
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum &>::type
|
|
operator|=(Enum &a, const Enum &b)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return (a = (a | b));
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum &>::type
|
|
operator&=(Enum &a, const Enum &b)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return (a = (a & b));
|
|
}
|
|
|
|
template<class Enum>
|
|
constexpr
|
|
typename std::enable_if<std::is_enum<Enum>::value, Enum &>::type
|
|
operator^=(Enum &a, const Enum &b)
|
|
{
|
|
using enum_t = typename std::underlying_type<Enum>::type;
|
|
|
|
return (a = (a ^ b));
|
|
}
|
|
|
|
template<class Enum,
|
|
class it>
|
|
typename std::enable_if<std::is_enum<Enum>::value, typename std::underlying_type<Enum>::type>::type
|
|
combine_flags(const it &begin,
|
|
const it &end)
|
|
{
|
|
using type = typename std::underlying_type<Enum>::type;
|
|
|
|
return std::accumulate(begin, end, type(0), []
|
|
(auto ret, const auto &val)
|
|
{
|
|
return ret |= type(val);
|
|
});
|
|
}
|
|
|
|
template<class Enum>
|
|
typename std::enable_if<std::is_enum<Enum>::value, typename std::underlying_type<Enum>::type>::type
|
|
combine_flags(const std::initializer_list<Enum> &list)
|
|
{
|
|
return combine_flags<Enum>(begin(list), end(list));
|
|
}
|
|
|
|
} // namespace ircd::util
|