0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-10-31 19:08:59 +01:00
construct/include/ircd/util/enum.h
2018-02-05 21:24:34 -08:00

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