Home | History | Annotate | Download | only in include
      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 /** \file
     18  * Templates used to declare parameters.
     19  */
     20 #ifndef C2PARAM_DEF_H_
     21 #define C2PARAM_DEF_H_
     22 
     23 #include <type_traits>
     24 
     25 #include <C2Param.h>
     26 
     27 /// \addtogroup Parameters
     28 /// @{
     29 
     30 /* ======================== UTILITY TEMPLATES FOR PARAMETER DEFINITIONS ======================== */
     31 
     32 /// \addtogroup internal
     33 /// @{
     34 
     35 /// Helper class that checks if a type has equality and inequality operators.
     36 struct C2_HIDE _C2Comparable_impl
     37 {
     38     template<typename S, typename=decltype(S() == S())>
     39     static std::true_type TestEqual(int);
     40     template<typename>
     41     static std::false_type TestEqual(...);
     42 
     43     template<typename S, typename=decltype(S() != S())>
     44     static std::true_type TestNotEqual(int);
     45     template<typename>
     46     static std::false_type TestNotEqual(...);
     47 };
     48 
     49 /**
     50  * Helper template that returns if a type has equality and inequality operators.
     51  *
     52  * Use as _C2Comparable<typename S>::value.
     53  */
     54 template<typename S>
     55 struct C2_HIDE _C2Comparable
     56     : public std::integral_constant<bool, decltype(_C2Comparable_impl::TestEqual<S>(0))::value
     57                         || decltype(_C2Comparable_impl::TestNotEqual<S>(0))::value> {
     58 };
     59 
     60 ///  Helper class that checks if a type has a CORE_INDEX constant.
     61 struct C2_HIDE _C2CoreIndexHelper_impl
     62 {
     63     template<typename S, int=S::CORE_INDEX>
     64     static std::true_type TestCoreIndex(int);
     65     template<typename>
     66     static std::false_type TestCoreIndex(...);
     67 };
     68 
     69 /// Macro that defines and thus overrides a type's CORE_INDEX for a setting
     70 #define _C2_CORE_INDEX_OVERRIDE(coreIndex) \
     71 public: \
     72     enum : uint32_t { CORE_INDEX = coreIndex };
     73 
     74 
     75 /// Helper template that adds a CORE_INDEX to a type if it does not have one (for testing)
     76 template<typename S, int CoreIndex>
     77 struct C2_HIDE _C2AddCoreIndex : public S {
     78     _C2_CORE_INDEX_OVERRIDE(CoreIndex)
     79 };
     80 
     81 /**
     82  * \brief Helper class to check struct requirements for parameters.
     83  *
     84  * Features:
     85  *  - verify default constructor, no virtual methods, and no equality operators.
     86  *  - expose PARAM_TYPE, and non-flex FLEX_SIZE.
     87  */
     88 template<typename S, int CoreIndex, unsigned TypeFlags>
     89 struct C2_HIDE _C2StructCheck {
     90     static_assert(
     91             std::is_default_constructible<S>::value, "C2 structure must have default constructor");
     92     static_assert(!std::is_polymorphic<S>::value, "C2 structure must not have virtual methods");
     93     static_assert(!_C2Comparable<S>::value, "C2 structure must not have operator== or !=");
     94 
     95 public:
     96     enum : uint32_t {
     97         PARAM_TYPE = CoreIndex | TypeFlags
     98     };
     99 
    100 protected:
    101     enum : uint32_t {
    102         FLEX_SIZE = 0,
    103     };
    104 };
    105 
    106 /// Helper class that checks if a type has an integer FLEX_SIZE member.
    107 struct C2_HIDE _C2Flexible_impl {
    108     /// specialization for types that have a FLEX_SIZE member
    109     template<typename S, unsigned=S::FLEX_SIZE>
    110     static std::true_type TestFlexSize(int);
    111     template<typename>
    112     static std::false_type TestFlexSize(...);
    113 };
    114 
    115 /// Helper template that returns if a type has an integer FLEX_SIZE member.
    116 template<typename S>
    117 struct C2_HIDE _C2Flexible
    118     : public std::integral_constant<bool, decltype(_C2Flexible_impl::TestFlexSize<S>(0))::value> {
    119 };
    120 
    121 /// Macro to test if a type is flexible (has a FLEX_SIZE member).
    122 #define IF_FLEXIBLE(S) ENABLE_IF(_C2Flexible<S>::value)
    123 /// Shorthand for std::enable_if
    124 #define ENABLE_IF(cond) typename std::enable_if<cond>::type
    125 
    126 template<typename T, typename V=void>
    127 struct C2_HIDE _c2_enable_if_type {
    128     typedef V type;
    129 };
    130 
    131 /// Helper template that exposes the flexible subtype of a struct.
    132 template<typename S, typename E=void>
    133 struct C2_HIDE _C2FlexHelper {
    134     typedef void FlexType;
    135     enum : uint32_t { FLEX_SIZE = 0 };
    136 };
    137 
    138 /// Specialization for flexible types. This only works if _FlexMemberType is public.
    139 template<typename S>
    140 struct C2_HIDE _C2FlexHelper<S,
    141         typename _c2_enable_if_type<typename S::_FlexMemberType>::type> {
    142     typedef typename _C2FlexHelper<typename S::_FlexMemberType>::FlexType FlexType;
    143     enum : uint32_t { FLEX_SIZE = _C2FlexHelper<typename S::_FlexMemberType>::FLEX_SIZE };
    144 };
    145 
    146 /// Specialization for flex arrays.
    147 template<typename S>
    148 struct C2_HIDE _C2FlexHelper<S[],
    149         typename std::enable_if<std::is_void<typename _C2FlexHelper<S>::FlexType>::value>::type> {
    150     typedef S FlexType;
    151     enum : uint32_t { FLEX_SIZE = sizeof(S) };
    152 };
    153 
    154 /**
    155  * \brief Helper class to check flexible struct requirements and add common operations.
    156  *
    157  * Features:
    158  *  - expose CORE_INDEX and FieldList (this is normally inherited from the struct, but flexible
    159  *    structs cannot be base classes and thus inherited from)
    160  *  - disable copy assignment and construction (TODO: this is already done in the FLEX macro for the
    161  *    flexible struct, so may not be needed here)
    162  */
    163 template<typename S, int ParamIndex, unsigned TypeFlags>
    164 struct C2_HIDE _C2FlexStructCheck :
    165 // add flexible flag as _C2StructCheck defines PARAM_TYPE
    166         public _C2StructCheck<S, ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, TypeFlags> {
    167 public:
    168     enum : uint32_t {
    169         /// \hideinitializer
    170         CORE_INDEX = ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, ///< flexible struct core-index
    171     };
    172 
    173     inline static const std::vector<C2FieldDescriptor> FieldList() { return S::FieldList(); }
    174 
    175     // default constructor needed because of the disabled copy constructor
    176     inline _C2FlexStructCheck() = default;
    177 
    178 protected:
    179     // cannot copy flexible params
    180     _C2FlexStructCheck(const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
    181     _C2FlexStructCheck& operator= (const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
    182 
    183     // constants used for helper methods
    184     enum : uint32_t {
    185         /// \hideinitializer
    186         FLEX_SIZE = _C2FlexHelper<S>::FLEX_SIZE, ///< size of flexible type
    187         /// \hideinitializer
    188         MAX_SIZE = (uint32_t)std::min((size_t)UINT32_MAX, SIZE_MAX), // TODO: is this always u32 max?
    189         /// \hideinitializer
    190         BASE_SIZE = sizeof(S) + sizeof(C2Param), ///< size of the base param
    191     };
    192 
    193     /// returns the allocated size of this param with flexCount, or 0 if it would overflow.
    194     inline static size_t CalcSize(size_t flexCount, size_t size = BASE_SIZE) {
    195         if (flexCount <= (MAX_SIZE - size) / S::FLEX_SIZE) {
    196             return size + S::FLEX_SIZE * flexCount;
    197         }
    198         return 0;
    199     }
    200 
    201     /// dynamic new operator usable for params of type S
    202     inline void* operator new(size_t size, size_t flexCount) noexcept {
    203         // TODO: assert(size == BASE_SIZE);
    204         size = CalcSize(flexCount, size);
    205         if (size > 0) {
    206             return ::operator new(size);
    207         }
    208         return nullptr;
    209     }
    210 };
    211 
    212 /// Define From() cast operators for params.
    213 #define DEFINE_CAST_OPERATORS(_Type) \
    214     inline static _Type* From(C2Param *other) { \
    215         return (_Type*)C2Param::IfSuitable( \
    216                 other, sizeof(_Type), _Type::PARAM_TYPE, _Type::FLEX_SIZE, \
    217                 (_Type::PARAM_TYPE & T::Index::DIR_UNDEFINED) != T::Index::DIR_UNDEFINED); \
    218     } \
    219     inline static const _Type* From(const C2Param *other) { \
    220         return const_cast<const _Type*>(From(const_cast<C2Param *>(other))); \
    221     } \
    222     inline static _Type* From(std::nullptr_t) { return nullptr; } \
    223 
    224 /**
    225  * Define flexible allocators (AllocShared or AllocUnique) for flexible params.
    226  *  - P::AllocXyz(flexCount, args...): allocate for given flex-count. This maps to
    227  *          T(flexCount, args...)\
    228  *
    229  * Clang does not support args... followed by templated param as args... eats it. Hence,
    230  * provide specializations where the initializer replaces the flexCount.
    231  *
    232  * Specializations that deduce flexCount:
    233  *  - P::AllocXyz(T[], args...): allocate for size of (and with) init array.
    234  *  - P::AllocXyz(std::initializer_list<T>, args...): allocate for size of (and with) initializer
    235  *            list.
    236  *  - P::AllocXyz(std::vector<T>, args...): allocate for size of (and with) init vector.
    237  *  These specializations map to T(flexCount = size-of-init, args..., init)
    238  */
    239 #define DEFINE_FLEXIBLE_ALLOC(_Type, S, ptr, Ptr) \
    240     template<typename ...Args> \
    241     inline static std::ptr##_ptr<_Type> Alloc##Ptr(size_t flexCount, const Args(&... args)) { \
    242         return std::ptr##_ptr<_Type>(new(flexCount) _Type(flexCount, args...)); \
    243     } \
    244     template<typename ...Args, typename U=typename S::FlexType> \
    245     inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
    246             const std::initializer_list<U> &init, const Args(&... args)) { \
    247         return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
    248     } \
    249     template<typename ...Args, typename U=typename S::FlexType> \
    250     inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
    251             const std::vector<U> &init, const Args(&... args)) { \
    252         return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
    253     } \
    254     template<typename ...Args, typename U=typename S::FlexType, unsigned N> \
    255     inline static std::ptr##_ptr<_Type> Alloc##Ptr(const U(&init)[N], const Args(&... args)) { \
    256         return std::ptr##_ptr<_Type>(new(N) _Type(N, args..., init)); \
    257     } \
    258 
    259 /**
    260  * Define flexible methods AllocShared, AllocUnique and flexCount.
    261  */
    262 #define DEFINE_FLEXIBLE_METHODS(_Type, S) \
    263     DEFINE_FLEXIBLE_ALLOC(_Type, S, shared, Shared) \
    264     DEFINE_FLEXIBLE_ALLOC(_Type, S, unique, Unique) \
    265     inline size_t flexCount() const { \
    266         static_assert(sizeof(_Type) == _Type::BASE_SIZE, "incorrect BASE_SIZE"); \
    267         size_t sz = this->size(); \
    268         if (sz >= sizeof(_Type)) { \
    269             return (sz - sizeof(_Type)) / _Type::FLEX_SIZE; \
    270         } \
    271         return 0; \
    272     } \
    273 
    274 /// Mark flexible member variable and make structure flexible.
    275 #define FLEX(cls, m) \
    276     C2_DO_NOT_COPY(cls) \
    277 private: \
    278     C2PARAM_MAKE_FRIENDS \
    279     /** \if 0 */ \
    280     template<typename, typename> friend struct _C2FlexHelper; \
    281 public: \
    282     typedef decltype(m) _FlexMemberType; \
    283     /* default constructor with flexCount */ \
    284     inline cls(size_t) : cls() {} \
    285     /* constexpr static _FlexMemberType cls::* flexMember = &cls::m; */ \
    286     typedef typename _C2FlexHelper<_FlexMemberType>::FlexType FlexType; \
    287     static_assert(\
    288             !std::is_void<FlexType>::value, \
    289             "member is not flexible, or a flexible array of a flexible type"); \
    290     enum : uint32_t { FLEX_SIZE = _C2FlexHelper<_FlexMemberType>::FLEX_SIZE }; \
    291     /** \endif */ \
    292 
    293 /// @}
    294 
    295 /**
    296  * Global-parameter template.
    297  *
    298  * Base template to define a global setting/tuning or info based on a structure and
    299  * an optional ParamIndex. Global parameters are not tied to a port (input or output).
    300  *
    301  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
    302  * structure can be accessed directly, and constructors and potential public methods are also
    303  * wrapped.
    304  *
    305  * \tparam T param type C2Setting, C2Tuning or C2Info
    306  * \tparam S wrapped structure
    307  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
    308  * structures.
    309  */
    310 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
    311 struct C2_HIDE C2GlobalParam : public T, public S,
    312         public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
    313     _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    314 private:
    315     typedef C2GlobalParam<T, S, ParamIndex> _Type;
    316 
    317 public:
    318     /// Wrapper around base structure's constructor.
    319     template<typename ...Args>
    320     inline C2GlobalParam(const Args(&... args)) : T(sizeof(_Type), _Type::PARAM_TYPE), S(args...) { }
    321 
    322     DEFINE_CAST_OPERATORS(_Type)
    323 };
    324 
    325 /**
    326  * Global-parameter template for flexible structures.
    327  *
    328  * Base template to define a global setting/tuning or info based on a flexible structure and
    329  * an optional ParamIndex. Global parameters are not tied to a port (input or output).
    330  *
    331  * \tparam T param type C2Setting, C2Tuning or C2Info
    332  * \tparam S wrapped flexible structure
    333  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
    334  *         structures.
    335  *
    336  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
    337  * structures can be accessed via the m member variable; however, the constructors of the structure
    338  * are wrapped directly. (This is because flexible types cannot be subclassed.)
    339  */
    340 template<typename T, typename S, int ParamIndex>
    341 struct C2_HIDE C2GlobalParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
    342     : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
    343 private:
    344     typedef C2GlobalParam<T, S, ParamIndex> _Type;
    345 
    346     /// Wrapper around base structure's constructor.
    347     template<typename ...Args>
    348     inline C2GlobalParam(size_t flexCount, const Args(&... args))
    349         : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE), m(flexCount, args...) { }
    350 
    351 public:
    352     S m; ///< wrapped flexible structure
    353 
    354     DEFINE_FLEXIBLE_METHODS(_Type, S)
    355     DEFINE_CAST_OPERATORS(_Type)
    356 };
    357 
    358 /**
    359  * Port-parameter template.
    360  *
    361  * Base template to define a port setting/tuning or info based on a structure and
    362  * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
    363  * specific stream.
    364  *
    365  * \tparam T param type C2Setting, C2Tuning or C2Info
    366  * \tparam S wrapped structure
    367  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
    368  *         structures.
    369  *
    370  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
    371  * structure can be accessed directly, and constructors and potential public methods are also
    372  * wrapped.
    373  *
    374  * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
    375  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
    376  */
    377 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
    378 struct C2_HIDE C2PortParam : public T, public S,
    379         private _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_UNDEFINED> {
    380     _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    381 private:
    382     typedef C2PortParam<T, S, ParamIndex> _Type;
    383 
    384 public:
    385     /// Default constructor.
    386     inline C2PortParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
    387     template<typename ...Args>
    388     /// Wrapper around base structure's constructor while specifying port/direction.
    389     inline C2PortParam(bool _output, const Args(&... args))
    390         : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE), S(args...) { }
    391     /// Set port/direction.
    392     inline void setPort(bool output) { C2Param::setPort(output); }
    393 
    394     DEFINE_CAST_OPERATORS(_Type)
    395 
    396     /// Specialization for an input port parameter.
    397     struct input : public T, public S,
    398             public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
    399         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    400         /// Wrapper around base structure's constructor.
    401         template<typename ...Args>
    402         inline input(const Args(&... args)) : T(sizeof(_Type), input::PARAM_TYPE), S(args...) { }
    403 
    404         DEFINE_CAST_OPERATORS(input)
    405 
    406     };
    407 
    408     /// Specialization for an output port parameter.
    409     struct output : public T, public S,
    410             public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
    411         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    412         /// Wrapper around base structure's constructor.
    413         template<typename ...Args>
    414         inline output(const Args(&... args)) : T(sizeof(_Type), output::PARAM_TYPE), S(args...) { }
    415 
    416         DEFINE_CAST_OPERATORS(output)
    417     };
    418 };
    419 
    420 /**
    421  * Port-parameter template for flexible structures.
    422  *
    423  * Base template to define a port setting/tuning or info based on a flexible structure and
    424  * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
    425  * specific stream.
    426  *
    427  * \tparam T param type C2Setting, C2Tuning or C2Info
    428  * \tparam S wrapped flexible structure
    429  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
    430  *         structures.
    431  *
    432  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
    433  * structures can be accessed via the m member variable; however, the constructors of the structure
    434  * are wrapped directly. (This is because flexible types cannot be subclassed.)
    435  *
    436  * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
    437  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
    438  */
    439 template<typename T, typename S, int ParamIndex>
    440 struct C2_HIDE C2PortParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
    441     : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_UNDEFINED> {
    442 private:
    443     typedef C2PortParam<T, S, ParamIndex> _Type;
    444 
    445     /// Default constructor for basic allocation: new(flexCount) P.
    446     inline C2PortParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE) { }
    447     template<typename ...Args>
    448     /// Wrapper around base structure's constructor while also specifying port/direction.
    449     inline C2PortParam(size_t flexCount, bool _output, const Args(&... args))
    450         : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE),
    451           m(flexCount, args...) { }
    452 
    453 public:
    454     /// Set port/direction.
    455     inline void setPort(bool output) { C2Param::setPort(output); }
    456 
    457     S m; ///< wrapped flexible structure
    458 
    459     DEFINE_FLEXIBLE_METHODS(_Type, S)
    460     DEFINE_CAST_OPERATORS(_Type)
    461 
    462     /// Specialization for an input port parameter.
    463     struct input : public T,
    464             public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
    465     private:
    466         /// Wrapper around base structure's constructor while also specifying port/direction.
    467         template<typename ...Args>
    468         inline input(size_t flexCount, const Args(&... args))
    469             : T(_Type::CalcSize(flexCount), input::PARAM_TYPE), m(flexCount, args...) { }
    470 
    471     public:
    472         S m; ///< wrapped flexible structure
    473 
    474         DEFINE_FLEXIBLE_METHODS(input, S)
    475         DEFINE_CAST_OPERATORS(input)
    476     };
    477 
    478     /// Specialization for an output port parameter.
    479     struct output : public T,
    480             public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
    481     private:
    482         /// Wrapper around base structure's constructor while also specifying port/direction.
    483         template<typename ...Args>
    484         inline output(size_t flexCount, const Args(&... args))
    485             : T(_Type::CalcSize(flexCount), output::PARAM_TYPE), m(flexCount, args...) { }
    486 
    487     public:
    488         S m; ///< wrapped flexible structure
    489 
    490         DEFINE_FLEXIBLE_METHODS(output, S)
    491         DEFINE_CAST_OPERATORS(output)
    492     };
    493 };
    494 
    495 /**
    496  * Stream-parameter template.
    497  *
    498  * Base template to define a stream setting/tuning or info based on a structure and
    499  * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
    500  * output).
    501  *
    502  * \tparam T param type C2Setting, C2Tuning or C2Info
    503  * \tparam S wrapped structure
    504  * \tparam ParamIndex optional paramter index override. Must be specified for base/reused
    505  *         structures.
    506  *
    507  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
    508  * structure can be accessed directly, and constructors and potential public methods are also
    509  * wrapped.
    510  *
    511  * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
    512  * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
    513  * parameters with unspecified port expose a setPort method, and add an additional initial port
    514  * parameter to the constructor.
    515  */
    516 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
    517 struct C2_HIDE C2StreamParam : public T, public S,
    518         private _C2StructCheck<S, ParamIndex,
    519                 T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
    520     _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    521 private:
    522     typedef C2StreamParam<T, S, ParamIndex> _Type;
    523 
    524 public:
    525     /// Default constructor. Port/direction and stream-ID is undefined.
    526     inline C2StreamParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
    527     /// Wrapper around base structure's constructor while also specifying port/direction and
    528     /// stream-ID.
    529     template<typename ...Args>
    530     inline C2StreamParam(bool _output, unsigned stream, const Args(&... args))
    531         : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
    532           S(args...) { }
    533     /// Set port/direction.
    534     inline void setPort(bool output) { C2Param::setPort(output); }
    535     /// Set stream-id. \retval true if the stream-id was successfully set.
    536     inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
    537 
    538     DEFINE_CAST_OPERATORS(_Type)
    539 
    540     /// Specialization for an input stream parameter.
    541     struct input : public T, public S,
    542             public _C2StructCheck<S, ParamIndex,
    543                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
    544         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    545 
    546         /// Default constructor. Stream-ID is undefined.
    547         inline input() : T(sizeof(_Type), input::PARAM_TYPE) { }
    548         /// Wrapper around base structure's constructor while also specifying stream-ID.
    549         template<typename ...Args>
    550         inline input(unsigned stream, const Args(&... args))
    551             : T(sizeof(_Type), input::PARAM_TYPE, stream), S(args...) { }
    552         /// Set stream-id. \retval true if the stream-id was successfully set.
    553         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
    554 
    555         DEFINE_CAST_OPERATORS(input)
    556     };
    557 
    558     /// Specialization for an output stream parameter.
    559     struct output : public T, public S,
    560             public _C2StructCheck<S, ParamIndex,
    561                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
    562         _C2_CORE_INDEX_OVERRIDE(ParamIndex)
    563 
    564         /// Default constructor. Stream-ID is undefined.
    565         inline output() : T(sizeof(_Type), output::PARAM_TYPE) { }
    566         /// Wrapper around base structure's constructor while also specifying stream-ID.
    567         template<typename ...Args>
    568         inline output(unsigned stream, const Args(&... args))
    569             : T(sizeof(_Type), output::PARAM_TYPE, stream), S(args...) { }
    570         /// Set stream-id. \retval true if the stream-id was successfully set.
    571         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
    572 
    573         DEFINE_CAST_OPERATORS(output)
    574     };
    575 };
    576 
    577 /**
    578  * Stream-parameter template for flexible structures.
    579  *
    580  * Base template to define a stream setting/tuning or info based on a flexible structure and
    581  * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
    582  * output).
    583  *
    584  * \tparam T param type C2Setting, C2Tuning or C2Info
    585  * \tparam S wrapped flexible structure
    586  * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
    587  *         structures.
    588  *
    589  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
    590  * structures can be accessed via the m member variable; however, the constructors of the structure
    591  * are wrapped directly. (This is because flexible types cannot be subclassed.)
    592  *
    593  * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
    594  * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
    595  * parameters with unspecified port expose a setPort method, and add an additional initial port
    596  * parameter to the constructor.
    597  */
    598 template<typename T, typename S, int ParamIndex>
    599 struct C2_HIDE C2StreamParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
    600     : public T,
    601       public _C2FlexStructCheck<S, ParamIndex,
    602               T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
    603 private:
    604     typedef C2StreamParam<T, S, ParamIndex> _Type;
    605     /// Default constructor. Port/direction and stream-ID is undefined.
    606     inline C2StreamParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE, 0u) { }
    607     /// Wrapper around base structure's constructor while also specifying port/direction and
    608     /// stream-ID.
    609     template<typename ...Args>
    610     inline C2StreamParam(size_t flexCount, bool _output, unsigned stream, const Args(&... args))
    611         : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
    612           m(flexCount, args...) { }
    613 
    614 public:
    615     S m; ///< wrapped flexible structure
    616 
    617     /// Set port/direction.
    618     inline void setPort(bool output) { C2Param::setPort(output); }
    619     /// Set stream-id. \retval true if the stream-id was successfully set.
    620     inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
    621 
    622     DEFINE_FLEXIBLE_METHODS(_Type, S)
    623     DEFINE_CAST_OPERATORS(_Type)
    624 
    625     /// Specialization for an input stream parameter.
    626     struct input : public T,
    627             public _C2FlexStructCheck<S, ParamIndex,
    628                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
    629     private:
    630         /// Default constructor. Stream-ID is undefined.
    631         inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
    632         /// Wrapper around base structure's constructor while also specifying stream-ID.
    633         template<typename ...Args>
    634         inline input(size_t flexCount, unsigned stream, const Args(&... args))
    635             : T(_Type::CalcSize(flexCount), input::PARAM_TYPE, stream), m(flexCount, args...) { }
    636 
    637     public:
    638         S m; ///< wrapped flexible structure
    639 
    640         /// Set stream-id. \retval true if the stream-id was successfully set.
    641         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
    642 
    643         DEFINE_FLEXIBLE_METHODS(input, S)
    644         DEFINE_CAST_OPERATORS(input)
    645     };
    646 
    647     /// Specialization for an output stream parameter.
    648     struct output : public T,
    649             public _C2FlexStructCheck<S, ParamIndex,
    650                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
    651     private:
    652         /// Default constructor. Stream-ID is undefined.
    653         inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
    654         /// Wrapper around base structure's constructor while also specifying stream-ID.
    655         template<typename ...Args>
    656         inline output(size_t flexCount, unsigned stream, const Args(&... args))
    657             : T(_Type::CalcSize(flexCount), output::PARAM_TYPE, stream), m(flexCount, args...) { }
    658 
    659     public:
    660         S m; ///< wrapped flexible structure
    661 
    662         /// Set stream-id. \retval true if the stream-id was successfully set.
    663         inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
    664 
    665         DEFINE_FLEXIBLE_METHODS(output, S)
    666         DEFINE_CAST_OPERATORS(output)
    667     };
    668 };
    669 
    670 /* ======================== SIMPLE VALUE PARAMETERS ======================== */
    671 
    672 /**
    673  * \ingroup internal
    674  * A structure template encapsulating a single element with default constructors and no core-index.
    675  */
    676 template<typename T>
    677 struct C2SimpleValueStruct {
    678     T value; ///< simple value of the structure
    679     // Default constructor.
    680     inline C2SimpleValueStruct() = default;
    681     // Constructor with an initial value.
    682     inline C2SimpleValueStruct(T value) : value(value) {}
    683     DEFINE_BASE_C2STRUCT(SimpleValue)
    684 };
    685 
    686 // TODO: move this and next to some generic place
    687 /**
    688  * Interface to a block of (mapped) memory containing an array of some type (T).
    689  */
    690 template<typename T>
    691 struct C2MemoryBlock {
    692     /// \returns the number of elements in this block.
    693     virtual size_t size() const = 0;
    694     /// \returns a const pointer to the start of this block. Care must be taken to not read outside
    695     /// the block.
    696     virtual const T *data() const = 0; // TODO: should this be friend access only in some C2Memory module?
    697     /// \returns a pointer to the start of this block. Care must be taken to not read or write
    698     /// outside the block.
    699     inline T *data() { return const_cast<T*>(const_cast<const C2MemoryBlock*>(this)->data()); }
    700 
    701 protected:
    702     // TODO: for now it should never be deleted as C2MemoryBlock
    703     virtual ~C2MemoryBlock() = default;
    704 };
    705 
    706 /**
    707  * Interface to a block of memory containing a constant (constexpr) array of some type (T).
    708  */
    709 template<typename T>
    710 struct C2ConstMemoryBlock : public C2MemoryBlock<T> {
    711     virtual const T * data() const { return _mData; }
    712     virtual size_t size() const { return _mSize; }
    713 
    714     /// Constructor.
    715     template<unsigned N>
    716     inline constexpr C2ConstMemoryBlock(const T(&init)[N]) : _mData(init), _mSize(N) {}
    717 
    718 private:
    719     const T *_mData;
    720     const size_t _mSize;
    721 };
    722 
    723 /// \addtogroup internal
    724 /// @{
    725 
    726 /// Helper class to initialize flexible arrays with various initalizers.
    727 struct _C2ValueArrayHelper {
    728     // char[]-s are used as null terminated strings, so the last element is never inited.
    729 
    730     /// Initialize a flexible array using a constexpr memory block.
    731     template<typename T>
    732     static void init(T(&array)[], size_t arrayLen, const C2MemoryBlock<T> &block) {
    733         // reserve last element for terminal 0 for strings
    734         if (arrayLen && std::is_same<T, char>::value) {
    735             --arrayLen;
    736         }
    737         if (block.data()) {
    738             memcpy(array, block.data(), std::min(arrayLen, block.size()) * sizeof(T));
    739         }
    740     }
    741 
    742     /// Initialize a flexible array using an initializer list.
    743     template<typename T>
    744     static void init(T(&array)[], size_t arrayLen, const std::initializer_list<T> &init) {
    745         size_t ix = 0;
    746         // reserve last element for terminal 0 for strings
    747         if (arrayLen && std::is_same<T, char>::value) {
    748             --arrayLen;
    749         }
    750         for (const T &item : init) {
    751             if (ix == arrayLen) {
    752                 break;
    753             }
    754             array[ix++] = item;
    755         }
    756     }
    757 
    758     /// Initialize a flexible array using a vector.
    759     template<typename T>
    760     static void init(T(&array)[], size_t arrayLen, const std::vector<T> &init) {
    761         size_t ix = 0;
    762         // reserve last element for terminal 0 for strings
    763         if (arrayLen && std::is_same<T, char>::value) {
    764             --arrayLen;
    765         }
    766         for (const T &item : init) {
    767             if (ix == arrayLen) {
    768                 break;
    769             }
    770             array[ix++] = item;
    771         }
    772     }
    773 
    774     /// Initialize a flexible array using another flexible array.
    775     template<typename T, unsigned N>
    776     static void init(T(&array)[], size_t arrayLen, const T(&str)[N]) {
    777         // reserve last element for terminal 0 for strings
    778         if (arrayLen && std::is_same<T, char>::value) {
    779             --arrayLen;
    780         }
    781         if (arrayLen) {
    782             memcpy(array, str, std::min(arrayLen, (size_t)N) * sizeof(T));
    783         }
    784     }
    785 };
    786 
    787 /**
    788  * Specialization for a flexible blob and string arrays. A structure template encapsulating a single
    789  * flexible array member with default flexible constructors and no core-index. This type cannot be
    790  * constructed on its own as it's size is 0.
    791  *
    792  * \internal This is different from C2SimpleArrayStruct<T[]> simply because its member has the name
    793  * as value to reflect this is a single value.
    794  */
    795 template<typename T>
    796 struct C2SimpleValueStruct<T[]> {
    797     static_assert(std::is_same<T, char>::value || std::is_same<T, uint8_t>::value,
    798                   "C2SimpleValueStruct<T[]> is only for BLOB or STRING");
    799     T value[];
    800 
    801     inline C2SimpleValueStruct() = default;
    802     DEFINE_BASE_C2STRUCT(SimpleValue)
    803     FLEX(C2SimpleValueStruct, value)
    804 
    805 private:
    806     inline C2SimpleValueStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
    807         _C2ValueArrayHelper::init(value, flexCount, block);
    808     }
    809 
    810     inline C2SimpleValueStruct(size_t flexCount, const std::initializer_list<T> &init) {
    811         _C2ValueArrayHelper::init(value, flexCount, init);
    812     }
    813 
    814     inline C2SimpleValueStruct(size_t flexCount, const std::vector<T> &init) {
    815         _C2ValueArrayHelper::init(value, flexCount, init);
    816     }
    817 
    818     template<unsigned N>
    819     inline C2SimpleValueStruct(size_t flexCount, const T(&init)[N]) {
    820         _C2ValueArrayHelper::init(value, flexCount, init);
    821     }
    822 };
    823 
    824 /// @}
    825 
    826 /**
    827  * A structure template encapsulating a single flexible array element of a specific type (T) with
    828  * default constructors and no core-index. This type cannot be constructed on its own as it's size
    829  * is 0. Instead, it is meant to be used as a parameter, e.g.
    830  *
    831  *   typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2MyFancyStruct>,
    832  *           kParamIndexMyFancyArrayStreamParam> C2MyFancyArrayStreamInfo;
    833  */
    834 template<typename T>
    835 struct C2SimpleArrayStruct {
    836     static_assert(!std::is_same<T, char>::value && !std::is_same<T, uint8_t>::value,
    837                   "use C2SimpleValueStruct<T[]> is for BLOB or STRING");
    838 
    839     T values[]; ///< array member
    840     /// Default constructor
    841     inline C2SimpleArrayStruct() = default;
    842     DEFINE_BASE_FLEX_C2STRUCT(SimpleArray, values)
    843     //FLEX(C2SimpleArrayStruct, values)
    844 
    845 private:
    846     /// Construct from a C2MemoryBlock.
    847     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
    848     inline C2SimpleArrayStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
    849         _C2ValueArrayHelper::init(values, flexCount, block);
    850     }
    851 
    852     /// Construct from an initializer list.
    853     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
    854     inline C2SimpleArrayStruct(size_t flexCount, const std::initializer_list<T> &init) {
    855         _C2ValueArrayHelper::init(values, flexCount, init);
    856     }
    857 
    858     /// Construct from an vector.
    859     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
    860     inline C2SimpleArrayStruct(size_t flexCount, const std::vector<T> &init) {
    861         _C2ValueArrayHelper::init(values, flexCount, init);
    862     }
    863 
    864     /// Construct from another flexible array.
    865     /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
    866     template<unsigned N>
    867     inline C2SimpleArrayStruct(size_t flexCount, const T(&init)[N]) {
    868         _C2ValueArrayHelper::init(values, flexCount, init);
    869     }
    870 };
    871 
    872 /**
    873  * \addtogroup simplevalue Simple value and array structures.
    874  * @{
    875  *
    876  * Simple value structures.
    877  *
    878  * Structures containing a single simple value. These can be reused to easily define simple
    879  * parameters of various types:
    880  *
    881  *   typedef C2PortParam<C2Tuning, C2Int32Value, kParamIndexMyIntegerPortParam>
    882  *           C2MyIntegerPortParamTuning;
    883  *
    884  * They contain a single member (value or values) that is described as "value" or "values".
    885  *
    886  * These structures don't define a core index, and as such, they cannot be used in structure
    887  * declarations. Use type[] instead, such as int32_t field[].
    888  */
    889 /// A 32-bit signed integer parameter in value, described as "value"
    890 typedef C2SimpleValueStruct<int32_t> C2Int32Value;
    891 /// A 32-bit signed integer array parameter in values, described as "values"
    892 typedef C2SimpleArrayStruct<int32_t> C2Int32Array;
    893 /// A 32-bit unsigned integer parameter in value, described as "value"
    894 typedef C2SimpleValueStruct<uint32_t> C2Uint32Value;
    895 /// A 32-bit unsigned integer array parameter in values, described as "values"
    896 typedef C2SimpleArrayStruct<uint32_t> C2Uint32Array;
    897 /// A 64-bit signed integer parameter in value, described as "value"
    898 typedef C2SimpleValueStruct<int64_t> C2Int64Value;
    899 /// A 64-bit signed integer array parameter in values, described as "values"
    900 typedef C2SimpleArrayStruct<int64_t> C2Int64Array;
    901 /// A 64-bit unsigned integer parameter in value, described as "value"
    902 typedef C2SimpleValueStruct<uint64_t> C2Uint64Value;
    903 /// A 64-bit unsigned integer array parameter in values, described as "values"
    904 typedef C2SimpleArrayStruct<uint64_t> C2Uint64Array;
    905 /// A float parameter in value, described as "value"
    906 typedef C2SimpleValueStruct<float> C2FloatValue;
    907 /// A float array parameter in values, described as "values"
    908 typedef C2SimpleArrayStruct<float> C2FloatArray;
    909 /// A blob flexible parameter in value, described as "value"
    910 typedef C2SimpleValueStruct<uint8_t[]> C2BlobValue;
    911 /// A string flexible parameter in value, described as "value"
    912 typedef C2SimpleValueStruct<char[]> C2StringValue;
    913 
    914 template<typename T>
    915 const std::vector<C2FieldDescriptor> C2SimpleValueStruct<T>::FieldList() {
    916     return { DESCRIBE_C2FIELD(value, "value") };
    917 }
    918 template<typename T>
    919 const std::vector<C2FieldDescriptor> C2SimpleValueStruct<T[]>::FieldList() {
    920     return { DESCRIBE_C2FIELD(value, "value") };
    921 }
    922 template<typename T>
    923 const std::vector<C2FieldDescriptor> C2SimpleArrayStruct<T>::FieldList() {
    924     return { DESCRIBE_C2FIELD(values, "values") };
    925 }
    926 
    927 /// @}
    928 
    929 /// @}
    930 
    931 #endif  // C2PARAM_DEF_H_
    932