1 /* 2 * Copyright (c) 2016, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 */ 9 10 #ifndef FATAL_INCLUDE_fatal_type_qualifier_h 11 #define FATAL_INCLUDE_fatal_type_qualifier_h 12 13 #include <type_traits> 14 15 namespace fatal { 16 17 /** 18 * Member function const/volatile qualifiers category. 19 * 20 * `none`: neither const nor volatile 21 * `c`: const but not volatile 22 * `v`: volatile but not const 23 * `cv`: both const and volatile (guaranteed 24 * to be the bitwise or of `c` and `v`) 25 * 26 * @author: Marcelo Juchem <marcelo@fb.com> 27 */ 28 enum class cv_qualifier: 29 unsigned char 30 { 31 none = 0, 32 c = 1, 33 v = 2, 34 cv = c | v 35 }; 36 37 /** 38 * Bitwise and (&) operator for `cv_qualifier` to make it easy to 39 * check for the presence of either the const or volatile qualifier: 40 * 41 * Example: 42 * 43 * void check_constness(cv_qualifier q) { 44 * if (q & cv_qualifier::c) { 45 * cout << "it is const, dunno about volatile"; 46 * } 47 * } 48 * 49 * @author: Marcelo Juchem <marcelo@fb.com> 50 */ 51 static constexpr bool operator &(cv_qualifier lhs, cv_qualifier rhs) { 52 using type = std::underlying_type<cv_qualifier>::type; 53 return static_cast<bool>(static_cast<type>(lhs) & static_cast<type>(rhs)); 54 } 55 56 enum class ref_qualifier: 57 unsigned char 58 { 59 none = 0, 60 lvalue = 1, 61 rvalue = 2 62 }; 63 64 /** 65 * Applies `std::add_const` to a type iff some other type is const. 66 * 67 * Example: 68 * 69 * struct foo {}; 70 * 71 * // yields `foo` 72 * using result1 = add_const_from<foo, int>::type; 73 * using result1 = add_const_from_t<foo, int>; 74 * 75 * // yields `foo const` 76 * using result2 = add_const_from<foo, int const>::type; 77 * using result2 = add_const_from_t<foo, int const>; 78 * 79 * // yields `foo const` 80 * using result3 = add_const_from<foo const, int const>::type; 81 * using result3 = add_const_from_t<foo const, int const>; 82 * 83 * @author: Marcelo Juchem <marcelo@fb.com> 84 */ 85 template <typename T, typename> 86 struct add_const_from { 87 using type = T; 88 }; 89 90 template <typename T, typename TFrom> 91 struct add_const_from<T, TFrom const> { 92 using type = typename std::add_const<T>::type; 93 }; 94 95 template <typename T, typename TFrom> 96 using add_const_from_t = typename add_const_from<T, TFrom>::type; 97 98 /** 99 * Applies `std::add_volatile` to a type iff some other type is volatile. 100 * 101 * Example: 102 * 103 * struct foo {}; 104 * 105 * // yields `foo` 106 * using result1 = add_volatile_from<foo, int>::type; 107 * using result1 = add_volatile_from_t<foo, int>; 108 * 109 * // yields `foo const` 110 * using result2 = add_volatile_from<foo, int volatile>::type; 111 * using result2 = add_volatile_from_t<foo, int volatile>; 112 * 113 * // yields `foo const` 114 * using result3 = add_volatile_from<foo volatile, int volatile>::type; 115 * using result3 = add_volatile_from_t<foo volatile, int volatile>; 116 * 117 * @author: Marcelo Juchem <marcelo@fb.com> 118 */ 119 template <typename T, typename> 120 struct add_volatile_from { 121 using type = T; 122 }; 123 124 template <typename T, typename TFrom> 125 struct add_volatile_from<T, TFrom volatile> { 126 using type = typename std::add_volatile<T>::type; 127 }; 128 129 template <typename T, typename TFrom> 130 using add_volatile_from_t = typename add_volatile_from<T, TFrom>::type; 131 132 /** 133 * Applies `std::add_const` to a type iff some other type is const. 134 * Applies `std::add_volatile` to a type iff some other type is volatile. 135 * Applies `std::add_cv` toa type iff some other type is const volatile. 136 * 137 * Example: 138 * 139 * struct foo {}; 140 * 141 * // yields `foo` 142 * using result1 = add_cv_from<foo, int>::type; 143 * using result1 = add_cv_from_t<foo, int>; 144 * 145 * // yields `foo const` 146 * using result2 = add_cv_from<foo, int const>::type; 147 * using result2 = add_cv_from_t<foo, int const>; 148 * 149 * // yields `foo const` 150 * using result3 = add_cv_from<foo const, int const>::type; 151 * using result3 = add_cv_from_t<foo const, int const>; 152 * 153 * // yields `foo volatile` 154 * using result4 = add_cv_from<foo, int volatile>::type; 155 * using result4 = add_cv_from_t<foo, int volatile>; 156 * 157 * // yields `foo volatile` 158 * using result5 = add_cv_from<foo volatile, int volatile>::type; 159 * using result5 = add_cv_from_t<foo volatile, int volatile>; 160 * 161 * // yields `foo const volatile` 162 * using result6 = add_cv_from<foo, int const volatile>::type; 163 * using result6 = add_cv_from_t<foo, int const volatile>; 164 * 165 * // yields `foo const volatile` 166 * using result7 = add_cv_from<foo const volatile, int const volatile>::type; 167 * using result7 = add_cv_from_t<foo const volatile, int const volatile>; 168 * 169 * @author: Marcelo Juchem <marcelo@fb.com> 170 */ 171 template <typename T, typename> 172 struct add_cv_from { 173 using type = T; 174 }; 175 176 template <typename T, typename TFrom> 177 struct add_cv_from<T, TFrom const> { 178 using type = typename std::add_const<T>::type; 179 }; 180 181 template <typename T, typename TFrom> 182 struct add_cv_from<T, TFrom volatile> { 183 using type = typename std::add_volatile<T>::type; 184 }; 185 186 template <typename T, typename TFrom> 187 struct add_cv_from<T, TFrom const volatile> { 188 using type = typename std::add_cv<T>::type; 189 }; 190 191 template <typename T, typename TFrom> 192 using add_cv_from_t = typename add_cv_from<T, TFrom>::type; 193 194 /** 195 * Given types `T` and `U`: 196 * - if `U` is not a reference, yield `T` 197 * - if `U` is an l-value reference, yield `std::add_lvalue_reference<T>::type` 198 * - if `U` is an r-value reference, yield `std::add_rvalue_reference<T>::type` 199 * 200 * Example: 201 * 202 * struct foo {}; 203 * 204 * // yields `foo` 205 * using result1 = add_reference_from<foo, int>::type; 206 * using result1 = add_reference_from_t<foo, int>; 207 * 208 * // yields `foo &&` 209 * using result2 = add_reference_from<foo &&, int>::type; 210 * using result2 = add_reference_from_t<foo &&, int>; 211 * 212 * // yields `foo &` 213 * using result3 = add_reference_from<foo, int &>::type; 214 * using result3 = add_reference_from_t<foo, int &>; 215 * 216 * // yields `foo &` 217 * using result4 = add_reference_from<foo &&, int &>::type; 218 * using result4 = add_reference_from_t<foo &&, int &>; 219 * 220 * // yields `foo &&` 221 * using result5 = add_reference_from<foo, int &&>::type; 222 * using result5 = add_reference_from_t<foo, int &&>; 223 * 224 * // yields `foo &` 225 * using result6 = add_reference_from<foo &, int &&>::type; 226 * using result6 = add_reference_from_t<foo &, int &&>; 227 * 228 * @author: Marcelo Juchem <marcelo@fb.com> 229 */ 230 template <typename T, typename> 231 struct add_reference_from { 232 using type = T; 233 }; 234 235 template <typename T, typename TFrom> 236 struct add_reference_from<T, TFrom &> { 237 using type = typename std::add_lvalue_reference<T>::type; 238 }; 239 240 template <typename T, typename TFrom> 241 struct add_reference_from<T, TFrom &&> { 242 using type = typename std::add_rvalue_reference<T>::type; 243 }; 244 245 template <typename T, typename TFrom> 246 using add_reference_from_t = typename add_reference_from<T, TFrom>::type; 247 248 /** 249 * Combine the effects of `add_cv_from` and `add_reference_from`. 250 * 251 * Example: 252 * 253 * struct foo {}; 254 * 255 * // yields `foo` 256 * using result_1 = add_cv_reference_from<foo, int>::type; 257 * using result_1 = add_cv_reference_from_t<foo, int>; 258 * 259 * // yields `foo const &` 260 * using result_2 = add_cv_reference_from<foo, int const &>::type; 261 * using result_2 = add_cv_reference_from_t<foo, int const &>; 262 * 263 * // yields `foo volatile &&` 264 * using result_3 = add_cv_reference_from<foo, int volatile &&>::type; 265 * using result_3 = add_cv_reference_from_t<foo, int volatile &&>; 266 * 267 * @author: Marcelo Juchem <marcelo@fb.com> 268 */ 269 template <typename T, typename> 270 struct add_cv_reference_from { 271 using type = T; 272 }; 273 274 template <typename T, typename TFrom> 275 struct add_cv_reference_from<T, TFrom const> { 276 using type = typename std::add_const<T>::type; 277 }; 278 279 template <typename T, typename TFrom> 280 struct add_cv_reference_from<T &, TFrom const> { 281 using type = typename std::add_lvalue_reference< 282 typename std::add_const<T>::type 283 >::type; 284 }; 285 286 template <typename T, typename TFrom> 287 struct add_cv_reference_from<T &&, TFrom const> { 288 using type = typename std::add_rvalue_reference< 289 typename std::add_const<T>::type 290 >::type; 291 }; 292 293 template <typename T, typename TFrom> 294 struct add_cv_reference_from<T, TFrom volatile> { 295 using type = typename std::add_volatile<T>::type; 296 }; 297 298 template <typename T, typename TFrom> 299 struct add_cv_reference_from<T &, TFrom volatile> { 300 using type = typename std::add_lvalue_reference< 301 typename std::add_volatile<T>::type 302 >::type; 303 }; 304 305 template <typename T, typename TFrom> 306 struct add_cv_reference_from<T &&, TFrom volatile> { 307 using type = typename std::add_rvalue_reference< 308 typename std::add_volatile<T>::type 309 >::type; 310 }; 311 312 template <typename T, typename TFrom> 313 struct add_cv_reference_from<T, TFrom &> { 314 using type = typename std::add_lvalue_reference< 315 typename add_cv_reference_from<T, TFrom>::type 316 >::type; 317 }; 318 319 template <typename T, typename TFrom> 320 struct add_cv_reference_from<T, TFrom &&> { 321 using type = typename std::add_rvalue_reference< 322 typename add_cv_reference_from<T, TFrom>::type 323 >::type; 324 }; 325 326 template <typename T, typename TFrom> 327 using add_cv_reference_from_t = typename add_cv_reference_from<T, TFrom>::type; 328 329 } // namespace fatal { 330 331 #endif // FATAL_INCLUDE_fatal_type_qualifier_h 332