Skip to content

Add enum class flag definition to platform #12772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions platform/mbed_enum_flags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright (c) 2020 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef MBED_SCOPED_ENUM_FLAGS_H
#define MBED_SCOPED_ENUM_FLAGS_H

#include <type_traits>

#define ENUM_FLAG_BITWISE_OPERATOR(T, OP) \
inline constexpr T operator OP(T lhs, T rhs) \
{ \
return T (static_cast<std::underlying_type_t<T>>(lhs) OP \
static_cast<std::underlying_type_t<T>>(rhs)); \
}


#define ENUM_FLAG_COMPOUND_ASSIGNMENT_OPERATOR(T, OP) \
inline constexpr T &operator OP(T &lhs, T rhs) \
{ \
return lhs = lhs OP rhs; \
}


/**
* @brief Applies bitwise operators to a enum class defined elsewhere.
*
* @param T The enum class typename
*
* This macro applies the bitwise negate, AND, OR, XOR operators and the
* corresponding assignment operators to an existing enum class. The macro
* uses underlying type traits to convert back and forth.
*
* Usage:
* @code
* external_enum.h:
*
* enum class SpokenLanguages : uint8_t {
* Sindarin = (1 << 0),
* Westron = (1 << 1),
* Rohirric = (1 << 2),
* BlackSpeech = (1 << 3)
* };
*
* my_code.cpp:
*
* #include "mbed_enum_flags.h"
* #include "external_enum.h"
*
* MBED_ENUM_FLAG_APPLY_OPERATORS(SpokenLanguages);
*
* SpokenLanguages gandalf = SpokenLanguages::Sindarin | SpokenLanguages::Westron |
* SpokenLanguages::Rohirric | SpokenLanguages::BlackSpeech;
* @endcode
*
*/
#define MBED_ENUM_FLAG_APPLY_OPERATORS(T) \
inline constexpr T operator ~(T lhs) \
{ \
return T(~static_cast<std::underlying_type_t<T>>(lhs)); \
} \
ENUM_FLAG_BITWISE_OPERATOR(T, |) \
ENUM_FLAG_BITWISE_OPERATOR(T, ^) \
ENUM_FLAG_BITWISE_OPERATOR(T, &) \
ENUM_FLAG_COMPOUND_ASSIGNMENT_OPERATOR(T, |=) \
ENUM_FLAG_COMPOUND_ASSIGNMENT_OPERATOR(T, ^=) \
ENUM_FLAG_COMPOUND_ASSIGNMENT_OPERATOR(T, &=) \
static_assert(true, "This assert true is to require a semicolon to terminate the macro.") \


/** @private
*
* @brief Bitwise definition macro with underlying type.
*
* Not part of public API. Do not use directly. Use MBED_SCOPED_ENUM_FLAGS instead.
*/
#define SCOPED_ENUM_FLAGS_TYPED(T, UNDERLYING_T) \
enum class T : UNDERLYING_T; \
MBED_ENUM_FLAG_APPLY_OPERATORS(T); \
enum class T : UNDERLYING_T

/** @private
*
* @brief Bitwise definition macro with default underlying type.
*
* Not part of public API. Do not use directly. Use MBED_SCOPED_ENUM_FLAGS instead.
*/
#define SCOPED_ENUM_FLAGS_UNTYPED(T) \
enum class T; \
MBED_ENUM_FLAG_APPLY_OPERATORS(T); \
enum class T

#define MBED_SCOPED_ENUM_FLAGS_CHOOSER(_1, _2, NAME, ...) NAME

/**
* @brief Creates an enum class with bitwise operator overloads.
*
* @param T The enum class typename
* @param UNDERLYING_T Optional: specify the underlying integral type. If
* omitted, the enum class underlying type will be the
* compiler default.
*
* This macro creates both the enum class type and defines NOT, AND, OR, and
* XOR operators. It also defines as three bitwise assignment operators, AND,
* OR, and XOR. It allows for the scoped nature of the enum class, but adds back
* the bitwise operators that were missing.
*
* This macro uses type traits to convert between the underlying type and back
* again for the bitwise operations.
*
* Usage:
* @code
* my_nice_enum_class_with_flags.h:
*
* MBED_SCOPED_ENUM_FLAGS(MyFlagName) {
* HasEars = (1 << 0),
* HasFur = (1 << 1),
* LaysEggs = (1 << 2),
* Meows = (1 << 3),
* Polydactyl = (1 << 30)
* };
*
* MBED_SCOPED_ENUM_FLAGS(SpokenLanguages, uint8_t) {
* Sindarin = (1 << 0),
* Westron = (1 << 1),
* Rohirric = (1 << 2),
* BlackSpeech = (1 << 3)
* };
*
* my_enum_class_flag_consumer.h:
*
* class EnumEater {
* public:
* EnumEater(MyFlagName flags) : _flags(flags) {}
*
* static MyFlagName DefaultFlags = MyFlagName::HasEars | MyFlagName::Meows;
*
* bool is_cat() const {
* return ((_flags & DefaultFlags) == DefaultFlags) &&
* ((_flags & MyFlagName::LaysEggs) == MyFlagName());
* }
* private:
* MyFlagName _flags;
* };
*
* bool is_Gandalf(SpokenLanguages flags) {
* return flags == (SpokenLanguages::Sindarin | SpokenLanguages::Westron |
* SpokenLanguages::SpeaksRohirric | SpokenLanguages::BlackSpeech);
* }
* @endcode
*
*/
#define MBED_SCOPED_ENUM_FLAGS(...) MBED_SCOPED_ENUM_FLAGS_CHOOSER(__VA_ARGS__, SCOPED_ENUM_FLAGS_TYPED, SCOPED_ENUM_FLAGS_UNTYPED)(__VA_ARGS__)

#endif //MBED_SCOPED_ENUM_FLAGS_H