0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-09 19:41:22 +01:00
construct/include/ircd/util/enum.h

157 lines
4.5 KiB
C
Raw Normal View History

// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk
//
// 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.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#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