blob: 8a55f8de8963a21672625dd018ac20d1d69ecc42 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef C2_H_
#define C2_H_
#include <errno.h>
#include <string>
/** nanoseconds with arbitrary origin. */
typedef int64_t c2_nsecs_t;
/** \mainpage Codec2
*
* Codec2 is a generic frame-based data processing API.
*
* The media subsystem accesses components via the \ref API.
*/
/** \ingroup API
*
* The Codec2 API defines the operation of data processing components and their interaction with
* the rest of the system.
*
* Coding Conventions
*
* Mitigating Binary Compatibility.
*
* While full binary compatibility is not a goal of the API (due to our use of STL), we try to
* mitigate binary breaks by adhering to the following conventions:
*
* - at most one vtable with placeholder virtual methods
* - all optional/placeholder virtual methods returning a c2_status_t, with C2_OMITTED not requiring
* any update to input/output arguments.
* - limiting symbol export of inline methods
* - use of pimpl (or shared-pimpl)
*
* Naming
*
* - all classes and types prefix with C2
* - classes for internal use prefix with _C2
* - enum values in global namespace prefix with C2_ all caps
* - enum values inside classes have no C2_ prefix as class already has it
* - supporting two kinds of enum naming: all-caps and kCamelCase
* \todo revisit kCamelCase for param-type
*
* Aspects
*
* Aspects define certain common behavior across a group of objects.
* - classes whose name matches _C2.*Aspect
* - only protected constructors
* - no desctructor and copiable
* - all methods are inline or static (this is opposite of the interface paradigm where all methods
* are virtual, which would not work due to the at most one vtable rule.)
* - only private variables (this prevents subclasses interfering with the aspects.)
*/
/// \defgroup types Common Types
/// @{
/**
* C2String: basic string implementation
*/
typedef std::string C2String;
/**
* C2StringLiteral: basic string literal implementation.
* \note these are never owned by any object, and can only refer to C string literals.
*/
typedef const char *C2StringLiteral;
/**
* c2_status_t: status codes used.
*/
enum c2_status_t : int32_t {
/*
* Use POSIX errno constants.
*/
C2_OK = 0, ///< operation completed successfully
// bad input
C2_BAD_VALUE = EINVAL, ///< argument has invalid value (user error)
C2_BAD_INDEX = ENXIO, ///< argument uses invalid index (user error)
C2_CANNOT_DO = ENOTSUP, ///< argument/index is valid but not possible
// bad sequencing of events
C2_DUPLICATE = EEXIST, ///< object already exists
C2_NOT_FOUND = ENOENT, ///< object not found
C2_BAD_STATE = EPERM, ///< operation is not permitted in the current state
C2_BLOCKING = EWOULDBLOCK, ///< operation would block but blocking is not permitted
C2_CANCELED = EINTR, ///< operation interrupted/canceled
// bad environment
C2_NO_MEMORY = ENOMEM, ///< not enough memory to complete operation
C2_REFUSED = EACCES, ///< missing permission to complete operation
C2_TIMED_OUT = ETIMEDOUT, ///< operation did not complete within timeout
// bad versioning
C2_OMITTED = ENOSYS, ///< operation is not implemented/supported (optional only)
// unknown fatal
C2_CORRUPTED = EFAULT, ///< some unexpected error prevented the operation
C2_NO_INIT = ENODEV, ///< status has not been initialized
};
/**
* Type that describes the desired blocking behavior for variable blocking calls. Blocking in this
* API is used in a somewhat modified meaning such that operations that merely update variables
* protected by mutexes are still considered "non-blocking" (always used in quotes).
*/
enum c2_blocking_t : int32_t {
/**
* The operation SHALL be "non-blocking". This means that it shall not perform any file
* operations, or call/wait on other processes. It may use a protected region as long as the
* mutex is never used to protect code that is otherwise "may block".
*/
C2_DONT_BLOCK = false,
/**
* The operation MAY be temporarily blocking.
*/
C2_MAY_BLOCK = true,
};
/// @}
/// \defgroup utils Utilities
/// @{
#define C2_DO_NOT_COPY(type) \
type& operator=(const type &) = delete; \
type(const type &) = delete; \
#define C2_DEFAULT_MOVE(type) \
type& operator=(type &&) = default; \
type(type &&) = default; \
#define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
#define C2_CONST __attribute__((const))
#define C2_HIDE __attribute__((visibility("hidden")))
#define C2_INLINE inline C2_HIDE
#define C2_INTERNAL __attribute__((internal_linkage))
#define C2_PACK __attribute__((aligned(4)))
#define C2_PURE __attribute__((pure))
#define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
inline bool operator!=(const type &other) const { return !(*this == other); } \
inline bool operator<=(const type &other) const { return (*this == other) || (*this < other); } \
inline bool operator>=(const type &other) const { return !(*this < other); } \
inline bool operator>(const type &other) const { return !(*this < other) && !(*this == other); }
#define DEFINE_FIELD_BASED_COMPARISON_OPERATORS(type, field) \
inline bool operator<(const type &other) const { return field < other.field; } \
inline bool operator==(const type &other) const { return field == other.field; } \
DEFINE_OTHER_COMPARISON_OPERATORS(type)
#define DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(type, field, mask) \
inline bool operator<(const type &other) const { \
return (field & mask) < (other.field & (mask)); \
} \
inline bool operator==(const type &other) const { \
return (field & mask) == (other.field & (mask)); \
} \
DEFINE_OTHER_COMPARISON_OPERATORS(type)
#define DEFINE_ENUM_OPERATORS(etype) \
inline constexpr etype operator|(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) | std::underlying_type<etype>::type(b)); } \
inline constexpr etype &operator|=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) | std::underlying_type<etype>::type(b)); return a; } \
inline constexpr etype operator&(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) & std::underlying_type<etype>::type(b)); } \
inline constexpr etype &operator&=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) & std::underlying_type<etype>::type(b)); return a; } \
inline constexpr etype operator^(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) ^ std::underlying_type<etype>::type(b)); } \
inline constexpr etype &operator^=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) ^ std::underlying_type<etype>::type(b)); return a; } \
inline constexpr etype operator~(etype a) { return (etype)(~std::underlying_type<etype>::type(a)); }
template<typename T, typename B>
class C2_HIDE c2_cntr_t;
/// \cond INTERNAL
/// \defgroup utils_internal
/// @{
template<typename T>
struct C2_HIDE _c2_cntr_compat_helper {
template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
C2_ALLOW_OVERFLOW
inline static constexpr T get(const U &value) {
return T(value);
}
template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type>
C2_ALLOW_OVERFLOW
inline static constexpr T get(const c2_cntr_t<U, void> &value) {
return T(value.mValue);
}
};
/// @}
/// \endcond
/**
* Integral counter type.
*
* This is basically an unsigned integral type that is NEVER checked for overflow/underflow - and
* comparison operators are redefined.
*
* \note Comparison of counter types is not fully transitive, e.g.
* it could be that a > b > c but a !> c.
* std::less<>, greater<>, less_equal<> and greater_equal<> specializations yield total ordering,
* but may not match semantic ordering of the values.
*
* Technically: counter types represent integer values: A * 2^N + value, where A can be arbitrary.
* This makes addition, subtraction, multiplication (as well as bitwise operations) well defined.
* However, division is in general not well defined, as the result may depend on A. This is also
* true for logical operators and boolean conversion.
*
* Even though well defined, bitwise operators are not implemented for counter types as they are not
* meaningful.
*/
template<typename T, typename B=typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type>
class C2_HIDE c2_cntr_t {
using compat = _c2_cntr_compat_helper<T>;
T mValue;
constexpr static T HALF_RANGE = T(~0) ^ (T(~0) >> 1);
template<typename U>
friend struct _c2_cntr_compat_helper;
public:
/**
* Default constructor. Initialized counter to 0.
*/
inline constexpr c2_cntr_t() : mValue(T(0)) {}
/**
* Construct from a compatible type.
*/
template<typename U>
inline constexpr c2_cntr_t(const U &value) : mValue(compat::get(value)) {}
/**
* Peek as underlying signed type.
*/
C2_ALLOW_OVERFLOW
inline constexpr typename std::make_signed<T>::type peek() const {
return static_cast<typename std::make_signed<T>::type>(mValue);
}
/**
* Peek as underlying unsigned type.
*/
inline constexpr T peeku() const {
return mValue;
}
/**
* Peek as long long - e.g. for printing.
*/
C2_ALLOW_OVERFLOW
inline constexpr long long peekll() const {
return (long long)mValue;
}
/**
* Peek as unsigned long long - e.g. for printing.
*/
C2_ALLOW_OVERFLOW
inline constexpr unsigned long long peekull() const {
return (unsigned long long)mValue;
}
/**
* Convert to a smaller counter type. This is always safe.
*/
template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type>
inline operator c2_cntr_t<U>() {
return c2_cntr_t<U>(mValue);
}
/**
* Arithmetic operators
*/
#define DEFINE_C2_CNTR_BINARY_OP(attrib, op, op_assign) \
template<typename U> \
attrib inline c2_cntr_t<T>& operator op_assign(const U &value) { \
mValue op_assign compat::get(value); \
return *this; \
} \
\
template<typename U, typename E=decltype(compat::get(U(0)))> \
attrib inline constexpr c2_cntr_t<T> operator op(const U &value) const { \
return c2_cntr_t<T>(mValue op compat::get(value)); \
} \
\
template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type> \
attrib inline constexpr c2_cntr_t<U> operator op(const c2_cntr_t<U> &value) const { \
return c2_cntr_t<U>(U(mValue) op value.peeku()); \
}
#define DEFINE_C2_CNTR_UNARY_OP(attrib, op) \
attrib inline constexpr c2_cntr_t<T> operator op() const { \
return c2_cntr_t<T>(op mValue); \
}
#define DEFINE_C2_CNTR_CREMENT_OP(attrib, op) \
attrib inline c2_cntr_t<T> &operator op() { \
op mValue; \
return *this; \
} \
attrib inline c2_cntr_t<T> operator op(int) { \
return c2_cntr_t<T, void>(mValue op); \
}
DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=)
DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=)
DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=)
DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -)
DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +)
DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++)
DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --)
template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
C2_ALLOW_OVERFLOW
inline constexpr c2_cntr_t<T> operator<<(const U &value) const {
return c2_cntr_t<T>(mValue << value);
}
template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
C2_ALLOW_OVERFLOW
inline c2_cntr_t<T> &operator<<=(const U &value) {
mValue <<= value;
return *this;
}
/**
* Comparison operators
*/
C2_ALLOW_OVERFLOW
inline constexpr bool operator<=(const c2_cntr_t<T> &other) const {
return T(other.mValue - mValue) < HALF_RANGE;
}
C2_ALLOW_OVERFLOW
inline constexpr bool operator>=(const c2_cntr_t<T> &other) const {
return T(mValue - other.mValue) < HALF_RANGE;
}
inline constexpr bool operator==(const c2_cntr_t<T> &other) const {
return mValue == other.mValue;
}
inline constexpr bool operator!=(const c2_cntr_t<T> &other) const {
return !(*this == other);
}
inline constexpr bool operator<(const c2_cntr_t<T> &other) const {
return *this <= other && *this != other;
}
inline constexpr bool operator>(const c2_cntr_t<T> &other) const {
return *this >= other && *this != other;
}
};
template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
inline constexpr c2_cntr_t<T> operator+(const U &a, const c2_cntr_t<T> &b) {
return b + a;
}
template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
inline constexpr c2_cntr_t<T> operator-(const U &a, const c2_cntr_t<T> &b) {
return c2_cntr_t<T>(a) - b;
}
template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
inline constexpr c2_cntr_t<T> operator*(const U &a, const c2_cntr_t<T> &b) {
return b * a;
}
typedef c2_cntr_t<uint32_t> c2_cntr32_t; /** 32-bit counter type */
typedef c2_cntr_t<uint64_t> c2_cntr64_t; /** 64-bit counter type */
/// \cond INTERNAL
/// \defgroup utils_internal
/// @{
template<typename... T> struct c2_types;
/** specialization for a single type */
template<typename T>
struct c2_types<T> {
typedef typename std::decay<T>::type wide_type;
typedef wide_type narrow_type;
typedef wide_type min_type; // type for min(T...)
};
/** specialization for two types */
template<typename T, typename U>
struct c2_types<T, U> {
static_assert(std::is_floating_point<T>::value == std::is_floating_point<U>::value,
"mixing floating point and non-floating point types is disallowed");
static_assert(std::is_signed<T>::value == std::is_signed<U>::value,
"mixing signed and unsigned types is disallowed");
typedef typename std::decay<
decltype(true ? std::declval<T>() : std::declval<U>())>::type wide_type;
typedef typename std::decay<
typename std::conditional<sizeof(T) < sizeof(U), T, U>::type>::type narrow_type;
typedef typename std::conditional<
std::is_signed<T>::value, wide_type, narrow_type>::type min_type;
};
/// @}
/// \endcond
/**
* Type support utility class. Only supports similar classes, such as:
* - all floating point
* - all unsigned/all signed
* - all pointer
*/
template<typename T, typename U, typename... V>
struct c2_types<T, U, V...> {
/** Common type that accommodates all template parameter types. */
typedef typename c2_types<typename c2_types<T, U>::wide_type, V...>::wide_type wide_type;
/** Narrowest type of the template parameter types. */
typedef typename c2_types<typename c2_types<T, U>::narrow_type, V...>::narrow_type narrow_type;
/** Type that accommodates the minimum value for any input for the template parameter types. */
typedef typename c2_types<typename c2_types<T, U>::min_type, V...>::min_type min_type;
};
/**
* \ingroup utils_internal
* specialization for two values */
template<typename T, typename U>
inline constexpr typename c2_types<T, U>::wide_type c2_max(const T a, const U b) {
typedef typename c2_types<T, U>::wide_type wide_type;
return ({ wide_type a_(a), b_(b); a_ > b_ ? a_ : b_; });
}
/**
* Finds the maximum value of a list of "similarly typed" values.
*
* This is an extension to std::max where the types do not have to be identical, and the smallest
* resulting type is used that accommodates the argument types.
*
* \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all
* unsigned.
*
* @return the largest of the input arguments.
*/
template<typename T, typename U, typename... V>
constexpr typename c2_types<T, U, V...>::wide_type c2_max(const T a, const U b, const V ... c) {
typedef typename c2_types<T, U, V...>::wide_type wide_type;
return ({ wide_type a_(a), b_(c2_max(b, c...)); a_ > b_ ? a_ : b_; });
}
/**
* \ingroup utils_internal
* specialization for two values */
template<typename T, typename U>
inline constexpr typename c2_types<T, U>::min_type c2_min(const T a, const U b) {
typedef typename c2_types<T, U>::wide_type wide_type;
return ({
wide_type a_(a), b_(b);
static_cast<typename c2_types<T, U>::min_type>(a_ < b_ ? a_ : b_);
});
}
/**
* Finds the minimum value of a list of "similarly typed" values.
*
* This is an extension to std::min where the types do not have to be identical, and the smallest
* resulting type is used that accommodates the argument types.
*
* \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all
* unsigned.
*
* @return the smallest of the input arguments.
*/
template<typename T, typename U, typename... V>
constexpr typename c2_types<T, U, V...>::min_type c2_min(const T a, const U b, const V ... c) {
typedef typename c2_types<U, V...>::min_type rest_type;
typedef typename c2_types<T, rest_type>::wide_type wide_type;
return ({
wide_type a_(a), b_(c2_min(b, c...));
static_cast<typename c2_types<T, rest_type>::min_type>(a_ < b_ ? a_ : b_);
});
}
/**
* \ingroup utils_internal
*/
template<typename T, typename U, typename V>
inline constexpr typename c2_types<T, V>::wide_type c2_clamp(const T a, const U b, const V c) {
typedef typename c2_types<T, U, V>::wide_type wide_type;
return ({
wide_type a_(a), b_(b), c_(c);
static_cast<typename c2_types<T, V>::wide_type>(b_ < a_ ? a_ : b_ > c_ ? c_ : b_);
});
}
/// @}
#include <functional>
template<typename T>
struct std::less<::c2_cntr_t<T>> {
constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
return lh.peeku() < rh.peeku();
}
};
template<typename T>
struct std::less_equal<::c2_cntr_t<T>> {
constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
return lh.peeku() <= rh.peeku();
}
};
template<typename T>
struct std::greater<::c2_cntr_t<T>> {
constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
return lh.peeku() > rh.peeku();
}
};
template<typename T>
struct std::greater_equal<::c2_cntr_t<T>> {
constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
return lh.peeku() >= rh.peeku();
}
};
#endif // C2_H_