mirror of https://github.com/ARMmbed/mbed-os.git
156 lines
4.4 KiB
C
156 lines
4.4 KiB
C
|
/* mbed Microcontroller Library
|
||
|
* Copyright (c) 2017-2017 ARM Limited
|
||
|
*
|
||
|
* 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 BLE_SAFE_ENUM_H_
|
||
|
#define BLE_SAFE_ENUM_H_
|
||
|
|
||
|
#include <stddef.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
namespace ble {
|
||
|
|
||
|
/**
|
||
|
* Helper class used to define safe enumerations.
|
||
|
*
|
||
|
* C++ 98 enums expose different security holes:
|
||
|
* - Scope The scope of the enum is the scope defining it. In other words,
|
||
|
* enumerator defined at namespace scope are in the same scope that other
|
||
|
* enumerator defined in that namespace even if they belong to a different
|
||
|
* enumeration.
|
||
|
* As a result it is really easy to collide names between two different
|
||
|
* enumerators. At the end, the programmer has to protect its declaration
|
||
|
* with long prefixing.
|
||
|
* - Unsafe comparison: enumerators really just are named integer and can be
|
||
|
* implicitly converted to integer. As a result it is possible to compare
|
||
|
* value of different enum type.
|
||
|
* - Layout: The layout type of enumerations is implementation defined.
|
||
|
*
|
||
|
* This template class expose a framework to overcome those issues:
|
||
|
*
|
||
|
* First enum has to be defined in a structure which inherit from this class.
|
||
|
* The target type is the name of the structure containing the enumeration
|
||
|
* while LayoutType is the inner type used to stored the enum.
|
||
|
*
|
||
|
* Comparison operator are provided so it is not possible to compare a SafeEnum
|
||
|
* of a type to another SafeEnum of a different type.
|
||
|
*
|
||
|
* Implicit conversion to integer is not defined, users have to either use the
|
||
|
* value function which return the integer value stored in an EnumType. Client
|
||
|
* class can also define their own conversion operation.
|
||
|
*
|
||
|
* @tparam Target structure containing the enumeration definition.
|
||
|
* @tparam LayoutType Inner type used to store enumeration value.
|
||
|
*
|
||
|
* @code
|
||
|
|
||
|
struct color_t : SafeEnum<color_t> {
|
||
|
enum type {
|
||
|
RED,
|
||
|
GREEN,
|
||
|
BLACK
|
||
|
};
|
||
|
|
||
|
color_t(type) : SafeEnum<color_t>(type) { }
|
||
|
};
|
||
|
|
||
|
// use an uint8_t to store the enumeration value
|
||
|
struct shape_t : SafeEnum<shape_t, uint8_t> {
|
||
|
enum type {
|
||
|
RECTANGLE,
|
||
|
CIRCLE,
|
||
|
TRIANGLE
|
||
|
};
|
||
|
|
||
|
shape_t(type) : SafeEnum<shape_t>(type) { }
|
||
|
};
|
||
|
|
||
|
// shape enumerator is in the shape_t scope.
|
||
|
shape_t shape = shape_t::RECTANGLE;
|
||
|
|
||
|
shape_t shape = color_t::RED; // Compilation error
|
||
|
|
||
|
if (shape == shape_t::CIRCLE) {
|
||
|
}
|
||
|
|
||
|
// compilation error
|
||
|
if (shape == color_t::RED) {
|
||
|
|
||
|
}
|
||
|
|
||
|
void sink(shape_t); (1)
|
||
|
void sink(color_t); (2)
|
||
|
|
||
|
sink(shape); // use overload (1)
|
||
|
sink(color); // use overload (2)
|
||
|
|
||
|
// explicit access to the value is mandatory when a SafeEnum value is used
|
||
|
// as the condition in a switch statement
|
||
|
switch(shape.value()) {
|
||
|
case shape_t::RECTANGLE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
* @endcode
|
||
|
*/
|
||
|
template<typename Target, typename LayoutType = unsigned int>
|
||
|
struct SafeEnum {
|
||
|
|
||
|
/**
|
||
|
* Construction of an enumeration value.
|
||
|
*/
|
||
|
SafeEnum(LayoutType value) : _value(value) { }
|
||
|
|
||
|
/**
|
||
|
* Equal to operator for SafeEnum instances.
|
||
|
*
|
||
|
* @param lhs left hand side of the comparison
|
||
|
* @param rhs right hand side of the comparison
|
||
|
*
|
||
|
* @return true if the inner value of lhs and rhs are equal and false
|
||
|
* otherwise.
|
||
|
*/
|
||
|
friend bool operator==(SafeEnum lhs, SafeEnum rhs) {
|
||
|
return lhs._value == rhs._value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Not equal to operator for SafeEnum instances.
|
||
|
*
|
||
|
* @param lhs left hand side of the comparison
|
||
|
* @param rhs right hand side of the comparison
|
||
|
*
|
||
|
* @return true if the inner value of lhs and rhs are not equal and false
|
||
|
* otherwise.
|
||
|
*/
|
||
|
friend bool operator!=(SafeEnum lhs, SafeEnum rhs) {
|
||
|
return !(lhs == rhs);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Explicit access to the inner value of the SafeEnum instance.
|
||
|
*/
|
||
|
LayoutType value() const {
|
||
|
return _value;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
LayoutType _value;
|
||
|
};
|
||
|
|
||
|
} // namespace ble
|
||
|
|
||
|
#endif /* BLE_SAFE_ENUM_H_ */
|