Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 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 C2_H_ |
| 18 | #define C2_H_ |
| 19 | |
| 20 | #include <errno.h> |
| 21 | |
| 22 | #include <string> |
| 23 | |
| 24 | /** nanoseconds with arbitrary origin. */ |
| 25 | typedef int64_t c2_nsecs_t; |
| 26 | |
| 27 | /** \mainpage Codec2 |
| 28 | * |
| 29 | * Codec2 is a generic frame-based data processing API. |
| 30 | * |
| 31 | * The media subsystem accesses components via the \ref API. |
| 32 | */ |
| 33 | |
| 34 | /** \ingroup API |
| 35 | * |
| 36 | * The Codec2 API defines the operation of data processing components and their interaction with |
| 37 | * the rest of the system. |
| 38 | * |
| 39 | * Coding Conventions |
| 40 | * |
| 41 | * Mitigating Binary Compatibility. |
| 42 | * |
| 43 | * While full binary compatibility is not a goal of the API (due to our use of STL), we try to |
| 44 | * mitigate binary breaks by adhering to the following conventions: |
| 45 | * |
| 46 | * - at most one vtable with placeholder virtual methods |
| 47 | * - all optional/placeholder virtual methods returning a c2_status_t, with C2_OMITTED not requiring |
| 48 | * any update to input/output arguments. |
| 49 | * - limiting symbol export of inline methods |
| 50 | * - use of pimpl (or shared-pimpl) |
| 51 | * |
| 52 | * Naming |
| 53 | * |
| 54 | * - all classes and types prefix with C2 |
| 55 | * - classes for internal use prefix with _C2 |
| 56 | * - enum values in global namespace prefix with C2_ all caps |
| 57 | * - enum values inside classes have no C2_ prefix as class already has it |
| 58 | * - supporting two kinds of enum naming: all-caps and kCamelCase |
| 59 | * \todo revisit kCamelCase for param-type |
| 60 | * |
| 61 | * Aspects |
| 62 | * |
| 63 | * Aspects define certain common behavior across a group of objects. |
| 64 | * - classes whose name matches _C2.*Aspect |
| 65 | * - only protected constructors |
| 66 | * - no desctructor and copiable |
| 67 | * - all methods are inline or static (this is opposite of the interface paradigm where all methods |
| 68 | * are virtual, which would not work due to the at most one vtable rule.) |
| 69 | * - only private variables (this prevents subclasses interfering with the aspects.) |
| 70 | */ |
| 71 | |
| 72 | /// \defgroup types Common Types |
| 73 | /// @{ |
| 74 | |
| 75 | /** |
| 76 | * C2String: basic string implementation |
| 77 | */ |
| 78 | typedef std::string C2String; |
| 79 | |
| 80 | /** |
| 81 | * C2StringLiteral: basic string literal implementation. |
| 82 | * \note these are never owned by any object, and can only refer to C string literals. |
| 83 | */ |
| 84 | typedef const char *C2StringLiteral; |
| 85 | |
| 86 | /** |
| 87 | * c2_status_t: status codes used. |
| 88 | */ |
| 89 | enum c2_status_t : int32_t { |
| 90 | /* |
| 91 | * Use POSIX errno constants. |
| 92 | */ |
| 93 | C2_OK = 0, ///< operation completed successfully |
| 94 | |
| 95 | // bad input |
| 96 | C2_BAD_VALUE = EINVAL, ///< argument has invalid value (user error) |
| 97 | C2_BAD_INDEX = ENXIO, ///< argument uses invalid index (user error) |
| 98 | C2_CANNOT_DO = ENOTSUP, ///< argument/index is valid but not possible |
| 99 | |
| 100 | // bad sequencing of events |
| 101 | C2_DUPLICATE = EEXIST, ///< object already exists |
| 102 | C2_NOT_FOUND = ENOENT, ///< object not found |
| 103 | C2_BAD_STATE = EPERM, ///< operation is not permitted in the current state |
| 104 | C2_BLOCKING = EWOULDBLOCK, ///< operation would block but blocking is not permitted |
| 105 | C2_CANCELED = EINTR, ///< operation interrupted/canceled |
| 106 | |
| 107 | // bad environment |
| 108 | C2_NO_MEMORY = ENOMEM, ///< not enough memory to complete operation |
| 109 | C2_REFUSED = EACCES, ///< missing permission to complete operation |
| 110 | |
| 111 | C2_TIMED_OUT = ETIMEDOUT, ///< operation did not complete within timeout |
| 112 | |
| 113 | // bad versioning |
| 114 | C2_OMITTED = ENOSYS, ///< operation is not implemented/supported (optional only) |
| 115 | |
| 116 | // unknown fatal |
| 117 | C2_CORRUPTED = EFAULT, ///< some unexpected error prevented the operation |
| 118 | C2_NO_INIT = ENODEV, ///< status has not been initialized |
| 119 | }; |
| 120 | |
| 121 | /** |
| 122 | * Type that describes the desired blocking behavior for variable blocking calls. Blocking in this |
| 123 | * API is used in a somewhat modified meaning such that operations that merely update variables |
| 124 | * protected by mutexes are still considered "non-blocking" (always used in quotes). |
| 125 | */ |
| 126 | enum c2_blocking_t : int32_t { |
| 127 | /** |
| 128 | * The operation SHALL be "non-blocking". This means that it shall not perform any file |
| 129 | * operations, or call/wait on other processes. It may use a protected region as long as the |
| 130 | * mutex is never used to protect code that is otherwise "may block". |
| 131 | */ |
| 132 | C2_DONT_BLOCK = false, |
| 133 | /** |
| 134 | * The operation MAY be temporarily blocking. |
| 135 | */ |
| 136 | C2_MAY_BLOCK = true, |
| 137 | }; |
| 138 | |
| 139 | /// @} |
| 140 | |
| 141 | /// \defgroup utils Utilities |
| 142 | /// @{ |
| 143 | |
| 144 | #define C2_DO_NOT_COPY(type) \ |
| 145 | type& operator=(const type &) = delete; \ |
| 146 | type(const type &) = delete; \ |
| 147 | |
| 148 | #define C2_DEFAULT_MOVE(type) \ |
| 149 | type& operator=(type &&) = default; \ |
| 150 | type(type &&) = default; \ |
| 151 | |
| 152 | #define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer"))) |
| 153 | #define C2_CONST __attribute__((const)) |
| 154 | #define C2_HIDE __attribute__((visibility("hidden"))) |
| 155 | #define C2_INLINE inline C2_HIDE |
| 156 | #define C2_INTERNAL __attribute__((internal_linkage)) |
| 157 | #define C2_PACK __attribute__((aligned(4))) |
| 158 | #define C2_PURE __attribute__((pure)) |
| 159 | |
| 160 | #define DEFINE_OTHER_COMPARISON_OPERATORS(type) \ |
| 161 | inline bool operator!=(const type &other) const { return !(*this == other); } \ |
| 162 | inline bool operator<=(const type &other) const { return (*this == other) || (*this < other); } \ |
| 163 | inline bool operator>=(const type &other) const { return !(*this < other); } \ |
| 164 | inline bool operator>(const type &other) const { return !(*this < other) && !(*this == other); } |
| 165 | |
| 166 | #define DEFINE_FIELD_BASED_COMPARISON_OPERATORS(type, field) \ |
| 167 | inline bool operator<(const type &other) const { return field < other.field; } \ |
| 168 | inline bool operator==(const type &other) const { return field == other.field; } \ |
| 169 | DEFINE_OTHER_COMPARISON_OPERATORS(type) |
| 170 | |
| 171 | #define DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(type, field, mask) \ |
| 172 | inline bool operator<(const type &other) const { \ |
| 173 | return (field & mask) < (other.field & (mask)); \ |
| 174 | } \ |
| 175 | inline bool operator==(const type &other) const { \ |
| 176 | return (field & mask) == (other.field & (mask)); \ |
| 177 | } \ |
| 178 | DEFINE_OTHER_COMPARISON_OPERATORS(type) |
| 179 | |
| 180 | #define DEFINE_ENUM_OPERATORS(etype) \ |
| 181 | inline constexpr etype operator|(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) | std::underlying_type<etype>::type(b)); } \ |
| 182 | inline constexpr etype &operator|=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) | std::underlying_type<etype>::type(b)); return a; } \ |
| 183 | inline constexpr etype operator&(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) & std::underlying_type<etype>::type(b)); } \ |
| 184 | inline constexpr etype &operator&=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) & std::underlying_type<etype>::type(b)); return a; } \ |
| 185 | inline constexpr etype operator^(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) ^ std::underlying_type<etype>::type(b)); } \ |
| 186 | inline constexpr etype &operator^=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) ^ std::underlying_type<etype>::type(b)); return a; } \ |
| 187 | inline constexpr etype operator~(etype a) { return (etype)(~std::underlying_type<etype>::type(a)); } |
| 188 | |
| 189 | template<typename T, typename B> |
| 190 | class C2_HIDE c2_cntr_t; |
| 191 | |
| 192 | /// \cond INTERNAL |
| 193 | |
| 194 | /// \defgroup utils_internal |
| 195 | /// @{ |
| 196 | |
| 197 | template<typename T> |
| 198 | struct C2_HIDE _c2_cntr_compat_helper { |
| 199 | template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type> |
| 200 | C2_ALLOW_OVERFLOW |
| 201 | inline static constexpr T get(const U &value) { |
| 202 | return T(value); |
| 203 | } |
| 204 | |
| 205 | template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type> |
| 206 | C2_ALLOW_OVERFLOW |
| 207 | inline static constexpr T get(const c2_cntr_t<U, void> &value) { |
| 208 | return T(value.mValue); |
| 209 | } |
| 210 | }; |
| 211 | |
| 212 | /// @} |
| 213 | |
| 214 | /// \endcond |
| 215 | |
| 216 | /** |
| 217 | * Integral counter type. |
| 218 | * |
| 219 | * This is basically an unsigned integral type that is NEVER checked for overflow/underflow - and |
| 220 | * comparison operators are redefined. |
| 221 | * |
| 222 | * \note Comparison of counter types is not fully transitive, e.g. |
| 223 | * it could be that a > b > c but a !> c. |
| 224 | * std::less<>, greater<>, less_equal<> and greater_equal<> specializations yield total ordering, |
| 225 | * but may not match semantic ordering of the values. |
| 226 | * |
| 227 | * Technically: counter types represent integer values: A * 2^N + value, where A can be arbitrary. |
| 228 | * This makes addition, subtraction, multiplication (as well as bitwise operations) well defined. |
| 229 | * However, division is in general not well defined, as the result may depend on A. This is also |
| 230 | * true for logical operators and boolean conversion. |
| 231 | * |
| 232 | * Even though well defined, bitwise operators are not implemented for counter types as they are not |
| 233 | * meaningful. |
| 234 | */ |
| 235 | template<typename T, typename B=typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type> |
| 236 | class C2_HIDE c2_cntr_t { |
| 237 | using compat = _c2_cntr_compat_helper<T>; |
| 238 | |
| 239 | T mValue; |
| 240 | constexpr static T HALF_RANGE = T(~0) ^ (T(~0) >> 1); |
| 241 | |
| 242 | template<typename U> |
| 243 | friend struct _c2_cntr_compat_helper; |
| 244 | public: |
| 245 | |
| 246 | /** |
| 247 | * Default constructor. Initialized counter to 0. |
| 248 | */ |
| 249 | inline constexpr c2_cntr_t() : mValue(T(0)) {} |
| 250 | |
| 251 | /** |
| 252 | * Construct from a compatible type. |
| 253 | */ |
| 254 | template<typename U> |
| 255 | inline constexpr c2_cntr_t(const U &value) : mValue(compat::get(value)) {} |
| 256 | |
| 257 | /** |
| 258 | * Peek as underlying signed type. |
| 259 | */ |
| 260 | C2_ALLOW_OVERFLOW |
| 261 | inline constexpr typename std::make_signed<T>::type peek() const { |
| 262 | return static_cast<typename std::make_signed<T>::type>(mValue); |
| 263 | } |
| 264 | |
| 265 | /** |
| 266 | * Peek as underlying unsigned type. |
| 267 | */ |
| 268 | inline constexpr T peeku() const { |
| 269 | return mValue; |
| 270 | } |
| 271 | |
| 272 | /** |
| 273 | * Peek as long long - e.g. for printing. |
| 274 | */ |
| 275 | C2_ALLOW_OVERFLOW |
| 276 | inline constexpr long long peekll() const { |
| 277 | return (long long)mValue; |
| 278 | } |
| 279 | |
| 280 | /** |
| 281 | * Peek as unsigned long long - e.g. for printing. |
| 282 | */ |
| 283 | C2_ALLOW_OVERFLOW |
| 284 | inline constexpr unsigned long long peekull() const { |
| 285 | return (unsigned long long)mValue; |
| 286 | } |
| 287 | |
| 288 | /** |
| 289 | * Convert to a smaller counter type. This is always safe. |
| 290 | */ |
| 291 | template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type> |
| 292 | inline operator c2_cntr_t<U>() { |
| 293 | return c2_cntr_t<U>(mValue); |
| 294 | } |
| 295 | |
| 296 | /** |
| 297 | * Arithmetic operators |
| 298 | */ |
| 299 | |
| 300 | #define DEFINE_C2_CNTR_BINARY_OP(attrib, op, op_assign) \ |
| 301 | template<typename U> \ |
| 302 | attrib inline c2_cntr_t<T>& operator op_assign(const U &value) { \ |
| 303 | mValue op_assign compat::get(value); \ |
| 304 | return *this; \ |
| 305 | } \ |
| 306 | \ |
| 307 | template<typename U, typename E=decltype(compat::get(U(0)))> \ |
| 308 | attrib inline constexpr c2_cntr_t<T> operator op(const U &value) const { \ |
| 309 | return c2_cntr_t<T>(mValue op compat::get(value)); \ |
| 310 | } \ |
| 311 | \ |
| 312 | template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type> \ |
| 313 | attrib inline constexpr c2_cntr_t<U> operator op(const c2_cntr_t<U> &value) const { \ |
| 314 | return c2_cntr_t<U>(U(mValue) op value.peeku()); \ |
| 315 | } |
| 316 | |
| 317 | #define DEFINE_C2_CNTR_UNARY_OP(attrib, op) \ |
| 318 | attrib inline constexpr c2_cntr_t<T> operator op() const { \ |
| 319 | return c2_cntr_t<T>(op mValue); \ |
| 320 | } |
| 321 | |
| 322 | #define DEFINE_C2_CNTR_CREMENT_OP(attrib, op) \ |
| 323 | attrib inline c2_cntr_t<T> &operator op() { \ |
| 324 | op mValue; \ |
| 325 | return *this; \ |
| 326 | } \ |
| 327 | attrib inline c2_cntr_t<T> operator op(int) { \ |
| 328 | return c2_cntr_t<T, void>(mValue op); \ |
| 329 | } |
| 330 | |
| 331 | DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=) |
| 332 | DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=) |
| 333 | DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=) |
| 334 | |
| 335 | DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -) |
| 336 | DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +) |
| 337 | |
| 338 | DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++) |
| 339 | DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --) |
| 340 | |
| 341 | template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type> |
| 342 | C2_ALLOW_OVERFLOW |
| 343 | inline constexpr c2_cntr_t<T> operator<<(const U &value) const { |
| 344 | return c2_cntr_t<T>(mValue << value); |
| 345 | } |
| 346 | |
| 347 | template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type> |
| 348 | C2_ALLOW_OVERFLOW |
| 349 | inline c2_cntr_t<T> &operator<<=(const U &value) { |
| 350 | mValue <<= value; |
| 351 | return *this; |
| 352 | } |
| 353 | |
| 354 | /** |
| 355 | * Comparison operators |
| 356 | */ |
| 357 | C2_ALLOW_OVERFLOW |
| 358 | inline constexpr bool operator<=(const c2_cntr_t<T> &other) const { |
| 359 | return T(other.mValue - mValue) < HALF_RANGE; |
| 360 | } |
| 361 | |
| 362 | C2_ALLOW_OVERFLOW |
| 363 | inline constexpr bool operator>=(const c2_cntr_t<T> &other) const { |
| 364 | return T(mValue - other.mValue) < HALF_RANGE; |
| 365 | } |
| 366 | |
| 367 | inline constexpr bool operator==(const c2_cntr_t<T> &other) const { |
| 368 | return mValue == other.mValue; |
| 369 | } |
| 370 | |
| 371 | inline constexpr bool operator!=(const c2_cntr_t<T> &other) const { |
| 372 | return !(*this == other); |
| 373 | } |
| 374 | |
| 375 | inline constexpr bool operator<(const c2_cntr_t<T> &other) const { |
| 376 | return *this <= other && *this != other; |
| 377 | } |
| 378 | |
| 379 | inline constexpr bool operator>(const c2_cntr_t<T> &other) const { |
| 380 | return *this >= other && *this != other; |
| 381 | } |
| 382 | }; |
| 383 | |
| 384 | template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type> |
| 385 | inline constexpr c2_cntr_t<T> operator+(const U &a, const c2_cntr_t<T> &b) { |
| 386 | return b + a; |
| 387 | } |
| 388 | |
| 389 | template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type> |
| 390 | inline constexpr c2_cntr_t<T> operator-(const U &a, const c2_cntr_t<T> &b) { |
| 391 | return c2_cntr_t<T>(a) - b; |
| 392 | } |
| 393 | |
| 394 | template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type> |
| 395 | inline constexpr c2_cntr_t<T> operator*(const U &a, const c2_cntr_t<T> &b) { |
| 396 | return b * a; |
| 397 | } |
| 398 | |
| 399 | typedef c2_cntr_t<uint32_t> c2_cntr32_t; /** 32-bit counter type */ |
| 400 | typedef c2_cntr_t<uint64_t> c2_cntr64_t; /** 64-bit counter type */ |
| 401 | |
| 402 | /// \cond INTERNAL |
| 403 | |
| 404 | /// \defgroup utils_internal |
| 405 | /// @{ |
| 406 | |
| 407 | template<typename... T> struct c2_types; |
| 408 | |
| 409 | /** specialization for a single type */ |
| 410 | template<typename T> |
| 411 | struct c2_types<T> { |
| 412 | typedef typename std::decay<T>::type wide_type; |
| 413 | typedef wide_type narrow_type; |
| 414 | typedef wide_type min_type; // type for min(T...) |
| 415 | }; |
| 416 | |
| 417 | /** specialization for two types */ |
| 418 | template<typename T, typename U> |
| 419 | struct c2_types<T, U> { |
| 420 | static_assert(std::is_floating_point<T>::value == std::is_floating_point<U>::value, |
| 421 | "mixing floating point and non-floating point types is disallowed"); |
| 422 | static_assert(std::is_signed<T>::value == std::is_signed<U>::value, |
| 423 | "mixing signed and unsigned types is disallowed"); |
| 424 | |
| 425 | typedef typename std::decay< |
| 426 | decltype(true ? std::declval<T>() : std::declval<U>())>::type wide_type; |
| 427 | typedef typename std::decay< |
| 428 | typename std::conditional<sizeof(T) < sizeof(U), T, U>::type>::type narrow_type; |
| 429 | typedef typename std::conditional< |
| 430 | std::is_signed<T>::value, wide_type, narrow_type>::type min_type; |
| 431 | }; |
| 432 | |
| 433 | /// @} |
| 434 | |
| 435 | /// \endcond |
| 436 | |
| 437 | /** |
| 438 | * Type support utility class. Only supports similar classes, such as: |
| 439 | * - all floating point |
| 440 | * - all unsigned/all signed |
| 441 | * - all pointer |
| 442 | */ |
| 443 | template<typename T, typename U, typename... V> |
| 444 | struct c2_types<T, U, V...> { |
| 445 | /** Common type that accommodates all template parameter types. */ |
| 446 | typedef typename c2_types<typename c2_types<T, U>::wide_type, V...>::wide_type wide_type; |
| 447 | /** Narrowest type of the template parameter types. */ |
| 448 | typedef typename c2_types<typename c2_types<T, U>::narrow_type, V...>::narrow_type narrow_type; |
| 449 | /** Type that accommodates the minimum value for any input for the template parameter types. */ |
| 450 | typedef typename c2_types<typename c2_types<T, U>::min_type, V...>::min_type min_type; |
| 451 | }; |
| 452 | |
| 453 | /** |
| 454 | * \ingroup utils_internal |
| 455 | * specialization for two values */ |
| 456 | template<typename T, typename U> |
| 457 | inline constexpr typename c2_types<T, U>::wide_type c2_max(const T a, const U b) { |
| 458 | typedef typename c2_types<T, U>::wide_type wide_type; |
| 459 | return ({ wide_type a_(a), b_(b); a_ > b_ ? a_ : b_; }); |
| 460 | } |
| 461 | |
| 462 | /** |
| 463 | * Finds the maximum value of a list of "similarly typed" values. |
| 464 | * |
| 465 | * This is an extension to std::max where the types do not have to be identical, and the smallest |
| 466 | * resulting type is used that accommodates the argument types. |
| 467 | * |
| 468 | * \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all |
| 469 | * unsigned. |
| 470 | * |
| 471 | * @return the largest of the input arguments. |
| 472 | */ |
| 473 | template<typename T, typename U, typename... V> |
| 474 | constexpr typename c2_types<T, U, V...>::wide_type c2_max(const T a, const U b, const V ... c) { |
| 475 | typedef typename c2_types<T, U, V...>::wide_type wide_type; |
| 476 | return ({ wide_type a_(a), b_(c2_max(b, c...)); a_ > b_ ? a_ : b_; }); |
| 477 | } |
| 478 | |
| 479 | /** |
| 480 | * \ingroup utils_internal |
| 481 | * specialization for two values */ |
| 482 | template<typename T, typename U> |
| 483 | inline constexpr typename c2_types<T, U>::min_type c2_min(const T a, const U b) { |
| 484 | typedef typename c2_types<T, U>::wide_type wide_type; |
| 485 | return ({ |
| 486 | wide_type a_(a), b_(b); |
| 487 | static_cast<typename c2_types<T, U>::min_type>(a_ < b_ ? a_ : b_); |
| 488 | }); |
| 489 | } |
| 490 | |
| 491 | /** |
| 492 | * Finds the minimum value of a list of "similarly typed" values. |
| 493 | * |
| 494 | * This is an extension to std::min where the types do not have to be identical, and the smallest |
| 495 | * resulting type is used that accommodates the argument types. |
| 496 | * |
| 497 | * \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all |
| 498 | * unsigned. |
| 499 | * |
| 500 | * @return the smallest of the input arguments. |
| 501 | */ |
| 502 | template<typename T, typename U, typename... V> |
| 503 | constexpr typename c2_types<T, U, V...>::min_type c2_min(const T a, const U b, const V ... c) { |
| 504 | typedef typename c2_types<U, V...>::min_type rest_type; |
| 505 | typedef typename c2_types<T, rest_type>::wide_type wide_type; |
| 506 | return ({ |
| 507 | wide_type a_(a), b_(c2_min(b, c...)); |
| 508 | static_cast<typename c2_types<T, rest_type>::min_type>(a_ < b_ ? a_ : b_); |
| 509 | }); |
| 510 | } |
| 511 | |
| 512 | /** |
| 513 | * \ingroup utils_internal |
| 514 | */ |
| 515 | template<typename T, typename U, typename V> |
| 516 | inline constexpr typename c2_types<T, V>::wide_type c2_clamp(const T a, const U b, const V c) { |
| 517 | typedef typename c2_types<T, U, V>::wide_type wide_type; |
| 518 | return ({ |
| 519 | wide_type a_(a), b_(b), c_(c); |
| 520 | static_cast<typename c2_types<T, V>::wide_type>(b_ < a_ ? a_ : b_ > c_ ? c_ : b_); |
| 521 | }); |
| 522 | } |
| 523 | |
| 524 | /// @} |
| 525 | |
| 526 | #include <functional> |
| 527 | template<typename T> |
| 528 | struct std::less<::c2_cntr_t<T>> { |
| 529 | constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const { |
| 530 | return lh.peeku() < rh.peeku(); |
| 531 | } |
| 532 | }; |
| 533 | template<typename T> |
| 534 | struct std::less_equal<::c2_cntr_t<T>> { |
| 535 | constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const { |
| 536 | return lh.peeku() <= rh.peeku(); |
| 537 | } |
| 538 | }; |
| 539 | template<typename T> |
| 540 | struct std::greater<::c2_cntr_t<T>> { |
| 541 | constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const { |
| 542 | return lh.peeku() > rh.peeku(); |
| 543 | } |
| 544 | }; |
| 545 | template<typename T> |
| 546 | struct std::greater_equal<::c2_cntr_t<T>> { |
| 547 | constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const { |
| 548 | return lh.peeku() >= rh.peeku(); |
| 549 | } |
| 550 | }; |
| 551 | |
| 552 | #endif // C2_H_ |