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 get_c2_cntr_compat_helper201 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 get_c2_cntr_compat_helper207 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 */ c2_cntr_t()249 inline constexpr c2_cntr_t() : mValue(T(0)) {} 250 251 /** 252 * Construct from a compatible type. 253 */ 254 template<typename U> c2_cntr_t(const U & value)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 peek()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 */ peeku()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 peekll()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 peekull()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 constexpr 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_ 553