blob: 8a55f8de8963a21672625dd018ac20d1d69ecc42 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
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. */
25typedef 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 */
78typedef 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 */
84typedef const char *C2StringLiteral;
85
86/**
87 * c2_status_t: status codes used.
88 */
89enum 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 */
126enum 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
189template<typename T, typename B>
190class C2_HIDE c2_cntr_t;
191
192/// \cond INTERNAL
193
194/// \defgroup utils_internal
195/// @{
196
197template<typename T>
198struct 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 */
235template<typename T, typename B=typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type>
236class 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;
244public:
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
384template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
385inline constexpr c2_cntr_t<T> operator+(const U &a, const c2_cntr_t<T> &b) {
386 return b + a;
387}
388
389template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
390inline 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
394template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
395inline constexpr c2_cntr_t<T> operator*(const U &a, const c2_cntr_t<T> &b) {
396 return b * a;
397}
398
399typedef c2_cntr_t<uint32_t> c2_cntr32_t; /** 32-bit counter type */
400typedef c2_cntr_t<uint64_t> c2_cntr64_t; /** 64-bit counter type */
401
402/// \cond INTERNAL
403
404/// \defgroup utils_internal
405/// @{
406
407template<typename... T> struct c2_types;
408
409/** specialization for a single type */
410template<typename T>
411struct 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 */
418template<typename T, typename U>
419struct 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 */
443template<typename T, typename U, typename... V>
444struct 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 */
456template<typename T, typename U>
457inline 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 */
473template<typename T, typename U, typename... V>
474constexpr 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 */
482template<typename T, typename U>
483inline 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 */
502template<typename T, typename U, typename... V>
503constexpr 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 */
515template<typename T, typename U, typename V>
516inline 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>
527template<typename T>
528struct 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};
533template<typename T>
534struct 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};
539template<typename T>
540struct 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};
545template<typename T>
546struct 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_