blob: fec56b9282796c68878241754bd3859638836b34 [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#pragma once
#include <type_traits>
// This header defines some utitily methods to manipulate scoped enums as flags
// C++11 scoped enums by default don't support flag operations (e.g. if (a & b))
// We need to define bitwise operations for them to be able to have strongly
// typed flags in our code.
//
// To enable the flag operators for your enum, most probably you just need to
// include this file. The only exception is if your enum is located in some
// namespace other than android, android::base or global. In that case you also
// need to add the following using to bring in the operators:
//
// using namespace ::android::base::EnumFlags;
namespace android {
namespace base {
namespace EnumFlags {
// A predicate which checks if template agument is a scoped enum
template<class E>
using is_scoped_enum = std::integral_constant<
bool,
std::is_enum<E>::value && !std::is_convertible<E, int>::value>;
template <class E>
using underlying_enum_type = typename std::underlying_type<E>::type;
template <class E, class Res = E>
using enable_if_scoped_enum =
typename std::enable_if<is_scoped_enum<E>::value, Res>::type;
template <class E>
enable_if_scoped_enum<E> operator|(E l, E r) {
return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
| static_cast<underlying_enum_type<E>>(r));
}
template <class E>
enable_if_scoped_enum<E> operator&(E l, E r) {
return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
& static_cast<underlying_enum_type<E>>(r));
}
template <class E>
enable_if_scoped_enum<E> operator~(E e) {
return static_cast<E>(~static_cast<underlying_enum_type<E>>(e));
}
template <class E>
enable_if_scoped_enum<E> operator|=(E& l, E r) {
return l = (l | r);
}
template <class E>
enable_if_scoped_enum<E> operator&=(E& l, E r) {
return l = (l & r);
}
template <class E>
enable_if_scoped_enum<E, bool> operator!(E e) {
return !static_cast<underlying_enum_type<E>>(e);
}
template <class E>
enable_if_scoped_enum<E, bool> operator!=(E e, int val) {
return static_cast<underlying_enum_type<E>>(e) !=
static_cast<underlying_enum_type<E>>(val);
}
template <class E>
enable_if_scoped_enum<E, bool> operator!=(int val, E e) {
return e != val;
}
template <class E>
enable_if_scoped_enum<E, bool> operator==(E e, int val) {
return static_cast<underlying_enum_type<E>>(e) ==
static_cast<underlying_enum_type<E>>(val);
}
template <class E>
enable_if_scoped_enum<E, bool> operator==(int val, E e) {
return e == val;
}
template <class E>
enable_if_scoped_enum<E, bool> nonzero(E e) {
return static_cast<underlying_enum_type<E>>(e) != 0;
}
} // namespace EnumFlags
// For the ADL to kick in let's make sure we bring all the operators into our
// main AndroidEmu namespaces...
using namespace ::android::base::EnumFlags;
} // namespace base
using namespace ::android::base::EnumFlags;
} // namespace android
// ... and into the global one, where most of the client functions are
using namespace ::android::base::EnumFlags;