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