mirror of
https://github.com/matrix-construct/construct
synced 2024-11-09 19:41:22 +01:00
157 lines
4.5 KiB
C
157 lines
4.5 KiB
C
|
// 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
|