|
| 1 | +/* mbed Microcontroller Library |
| 2 | + * Copyright (c) 2017-2017 ARM Limited |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +#ifndef BLE_SAFE_ENUM_H_ |
| 18 | +#define BLE_SAFE_ENUM_H_ |
| 19 | + |
| 20 | +#include <stddef.h> |
| 21 | +#include <stdint.h> |
| 22 | + |
| 23 | +namespace ble { |
| 24 | + |
| 25 | +/** |
| 26 | + * Helper class used to define safe enumerations. |
| 27 | + * |
| 28 | + * C++ 98 enums expose different security holes: |
| 29 | + * - Scope The scope of the enum is the scope defining it. In other words, |
| 30 | + * enumerator defined at namespace scope are in the same scope that other |
| 31 | + * enumerator defined in that namespace even if they belong to a different |
| 32 | + * enumeration. |
| 33 | + * As a result it is really easy to collide names between two different |
| 34 | + * enumerators. At the end, the programmer has to protect its declaration |
| 35 | + * with long prefixing. |
| 36 | + * - Unsafe comparison: enumerators really just are named integer and can be |
| 37 | + * implicitly converted to integer. As a result it is possible to compare |
| 38 | + * value of different enum type. |
| 39 | + * - Layout: The layout type of enumerations is implementation defined. |
| 40 | + * |
| 41 | + * This template class expose a framework to overcome those issues: |
| 42 | + * |
| 43 | + * First enum has to be defined in a structure which inherit from this class. |
| 44 | + * The target type is the name of the structure containing the enumeration |
| 45 | + * while LayoutType is the inner type used to stored the enum. |
| 46 | + * |
| 47 | + * Comparison operator are provided so it is not possible to compare a SafeEnum |
| 48 | + * of a type to another SafeEnum of a different type. |
| 49 | + * |
| 50 | + * Implicit conversion to integer is not defined, users have to either use the |
| 51 | + * value function which return the integer value stored in an EnumType. Client |
| 52 | + * class can also define their own conversion operation. |
| 53 | + * |
| 54 | + * @tparam Target structure containing the enumeration definition. |
| 55 | + * @tparam LayoutType Inner type used to store enumeration value. |
| 56 | + * |
| 57 | + * @code |
| 58 | +
|
| 59 | + struct color_t : SafeEnum<color_t> { |
| 60 | + enum type { |
| 61 | + RED, |
| 62 | + GREEN, |
| 63 | + BLACK |
| 64 | + }; |
| 65 | +
|
| 66 | + color_t(type) : SafeEnum<color_t>(type) { } |
| 67 | + }; |
| 68 | +
|
| 69 | + // use an uint8_t to store the enumeration value |
| 70 | + struct shape_t : SafeEnum<shape_t, uint8_t> { |
| 71 | + enum type { |
| 72 | + RECTANGLE, |
| 73 | + CIRCLE, |
| 74 | + TRIANGLE |
| 75 | + }; |
| 76 | +
|
| 77 | + shape_t(type) : SafeEnum<shape_t>(type) { } |
| 78 | + }; |
| 79 | +
|
| 80 | + // shape enumerator is in the shape_t scope. |
| 81 | + shape_t shape = shape_t::RECTANGLE; |
| 82 | +
|
| 83 | + shape_t shape = color_t::RED; // Compilation error |
| 84 | +
|
| 85 | + if (shape == shape_t::CIRCLE) { |
| 86 | + } |
| 87 | +
|
| 88 | + // compilation error |
| 89 | + if (shape == color_t::RED) { |
| 90 | +
|
| 91 | + } |
| 92 | +
|
| 93 | + void sink(shape_t); (1) |
| 94 | + void sink(color_t); (2) |
| 95 | +
|
| 96 | + sink(shape); // use overload (1) |
| 97 | + sink(color); // use overload (2) |
| 98 | +
|
| 99 | + // explicit access to the value is mandatory when a SafeEnum value is used |
| 100 | + // as the condition in a switch statement |
| 101 | + switch(shape.value()) { |
| 102 | + case shape_t::RECTANGLE: |
| 103 | + break; |
| 104 | + } |
| 105 | +
|
| 106 | + * @endcode |
| 107 | + */ |
| 108 | +template<typename Target, typename LayoutType = unsigned int> |
| 109 | +struct SafeEnum { |
| 110 | + |
| 111 | + /** |
| 112 | + * Construction of an enumeration value. |
| 113 | + */ |
| 114 | + SafeEnum(LayoutType value) : _value(value) { } |
| 115 | + |
| 116 | + /** |
| 117 | + * Equal to operator for SafeEnum instances. |
| 118 | + * |
| 119 | + * @param lhs left hand side of the comparison |
| 120 | + * @param rhs right hand side of the comparison |
| 121 | + * |
| 122 | + * @return true if the inner value of lhs and rhs are equal and false |
| 123 | + * otherwise. |
| 124 | + */ |
| 125 | + friend bool operator==(SafeEnum lhs, SafeEnum rhs) { |
| 126 | + return lhs._value == rhs._value; |
| 127 | + } |
| 128 | + |
| 129 | + /** |
| 130 | + * Not equal to operator for SafeEnum instances. |
| 131 | + * |
| 132 | + * @param lhs left hand side of the comparison |
| 133 | + * @param rhs right hand side of the comparison |
| 134 | + * |
| 135 | + * @return true if the inner value of lhs and rhs are not equal and false |
| 136 | + * otherwise. |
| 137 | + */ |
| 138 | + friend bool operator!=(SafeEnum lhs, SafeEnum rhs) { |
| 139 | + return !(lhs == rhs); |
| 140 | + } |
| 141 | + |
| 142 | + /** |
| 143 | + * Explicit access to the inner value of the SafeEnum instance. |
| 144 | + */ |
| 145 | + LayoutType value() const { |
| 146 | + return _value; |
| 147 | + } |
| 148 | + |
| 149 | +private: |
| 150 | + LayoutType _value; |
| 151 | +}; |
| 152 | + |
| 153 | +} // namespace ble |
| 154 | + |
| 155 | +#endif /* BLE_SAFE_ENUM_H_ */ |
0 commit comments