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 #ifndef C2PARAM_H_
     18 #define C2PARAM_H_
     19 
     20 #include <C2.h>
     21 
     22 #include <stdbool.h>
     23 #include <stdint.h>
     24 
     25 #include <algorithm>
     26 #include <string>
     27 #include <type_traits>
     28 #include <utility>
     29 #include <vector>
     30 
     31 /// \addtogroup Parameters
     32 /// @{
     33 
     34 /// \defgroup internal Internal helpers.
     35 
     36 /*!
     37  * \file
     38  * PARAMETERS: SETTINGs, TUNINGs, and INFOs
     39  * ===
     40  *
     41  * These represent miscellaneous control and metadata information and are likely copied into
     42  * kernel space. Therefore, these are C-like structures designed to carry just a small amount of
     43  * information. We are using C++ to be able to add constructors, as well as non-virtual and class
     44  * methods.
     45  *
     46  * ==Specification details:
     47  *
     48  * Restrictions:
     49  *   - must be POD struct, e.g. no vtable (no virtual destructor)
     50  *   - must have the same size in 64-bit and 32-bit mode (no size_t)
     51  *   - as such, no pointer members
     52  *   - some common member field names are reserved as they are defined as methods for all
     53  *     parameters:
     54  *     they are: size, type, kind, index and stream
     55  *
     56  * Behavior:
     57  * - Params can be global (not related to input or output), related to input or output,
     58  *   or related to an input/output stream.
     59  * - All params are queried/set using a unique param index, which incorporates a potential stream
     60  *   index and/or port.
     61  * - Querying (supported) params MUST never fail.
     62  * - All params MUST have default values.
     63  * - If some fields have "unsupported" or "invalid" values during setting, this SHOULD be
     64  *   communicated to the app.
     65  *   a) Ideally, this should be avoided.  When setting parameters, in general, component should do
     66  *     "best effort" to apply all settings. It should change "invalid/unsupported" values to the
     67  *     nearest supported values.
     68  *   - This is communicated to the client by changing the source values in tune()/
     69  *     configure().
     70  *   b) If falling back to a supported value is absolutely impossible, the component SHALL return
     71  *     an error for the specific setting, but should continue to apply other settings.
     72  *     TODO: this currently may result in unintended results.
     73  *
     74  * **NOTE:** unlike OMX, params are not versioned. Instead, a new struct with new param index
     75  * SHALL be added as new versions are required.
     76  *
     77  * The proper subtype (Setting, Info or Param) is incorporated into the class type. Define structs
     78  * to define multiple subtyped versions of related parameters.
     79  *
     80  * ==Implementation details:
     81  *
     82  * - Use macros to define parameters
     83  * - All parameters must have a default constructor
     84  *   - This is only used for instantiating the class in source (e.g. will not be used
     85  *     when building a parameter by the framework from key/value pairs.)
     86  */
     87 
     88 /// \ingroup internal
     89 
     90 /**
     91  * Parameter base class.
     92  */
     93 struct C2Param {
     94     // param index encompasses the following:
     95     //
     96     // - kind (setting, tuning, info, struct)
     97     // - scope
     98     //   - direction (global, input, output)
     99     //   - stream flag
    100     //   - stream ID (usually 0)
    101     // - and the parameter's type (core index)
    102     //   - flexible parameter flag
    103     //   - vendor extension flag
    104     //   - type index (this includes the vendor extension flag)
    105     //
    106     // layout:
    107     //
    108     //        kind : <------- scope -------> : <----- core index ----->
    109     //      +------+-----+---+------+--------+----|------+--------------+
    110     //      | kind | dir | - |stream|streamID|flex|vendor|  type index  |
    111     //      +------+-----+---+------+--------+----+------+--------------+
    112     //  bit: 31..30 29.28       25   24 .. 17  16    15   14    ..     0
    113     //
    114 public:
    115     /**
    116      * C2Param kinds, usable as bitmaps.
    117      */
    118     enum kind_t : uint32_t {
    119         NONE    = 0,
    120         STRUCT  = (1 << 0),
    121         INFO    = (1 << 1),
    122         SETTING = (1 << 2),
    123         TUNING  = (1 << 3) | SETTING, // tunings are settings
    124     };
    125 
    126     /**
    127      * The parameter type index specifies the underlying parameter type of a parameter as
    128      * an integer value.
    129      *
    130      * Parameter types are divided into two groups: platform types and vendor types.
    131      *
    132      * Platform types are defined by the platform and are common for all implementations.
    133      *
    134      * Vendor types are defined by each vendors, so they may differ between implementations.
    135      * It is recommended that vendor types be the same for all implementations by a specific
    136      * vendor.
    137      */
    138     typedef uint32_t type_index_t;
    139     enum : uint32_t {
    140             TYPE_INDEX_VENDOR_START = 0x00008000, ///< vendor indices SHALL start after this
    141     };
    142 
    143     /**
    144      * Core index is the underlying parameter type for a parameter. It is used to describe the
    145      * layout of the parameter structure regardless of the component or parameter kind/scope.
    146      *
    147      * It is used to identify and distinguish global parameters, and also parameters on a given
    148      * port or stream. They must be unique for the set of global parameters, as well as for the
    149      * set of parameters on each port or each stream, but the same core index can be used for
    150      * parameters on different streams or ports, as well as for global parameters and port/stream
    151      * parameters.
    152      *
    153      * Multiple parameter types can share the same layout.
    154      *
    155      * \note The layout for all parameters with the same core index across all components must
    156      * be identical.
    157      */
    158     struct CoreIndex {
    159     //public:
    160         enum : uint32_t {
    161             IS_FLEX_FLAG    = 0x00010000,
    162             IS_REQUEST_FLAG = 0x00020000,
    163         };
    164 
    165     protected:
    166         enum : uint32_t {
    167             KIND_MASK      = 0xC0000000,
    168             KIND_STRUCT    = 0x00000000,
    169             KIND_TUNING    = 0x40000000,
    170             KIND_SETTING   = 0x80000000,
    171             KIND_INFO      = 0xC0000000,
    172 
    173             DIR_MASK       = 0x30000000,
    174             DIR_GLOBAL     = 0x20000000,
    175             DIR_UNDEFINED  = DIR_MASK, // MUST have all bits set
    176             DIR_INPUT      = 0x00000000,
    177             DIR_OUTPUT     = 0x10000000,
    178 
    179             IS_STREAM_FLAG  = 0x02000000,
    180             STREAM_ID_MASK  = 0x01F00000,
    181             STREAM_ID_SHIFT = 20,
    182             MAX_STREAM_ID   = STREAM_ID_MASK >> STREAM_ID_SHIFT,
    183             STREAM_MASK     = IS_STREAM_FLAG | STREAM_ID_MASK,
    184 
    185             IS_VENDOR_FLAG  = 0x00008000,
    186             TYPE_INDEX_MASK = 0x0000FFFF,
    187             CORE_MASK       = TYPE_INDEX_MASK | IS_FLEX_FLAG,
    188         };
    189 
    190     public:
    191         /// constructor/conversion from uint32_t
    192         inline CoreIndex(uint32_t index) : mIndex(index) { }
    193 
    194         // no conversion from uint64_t
    195         inline CoreIndex(uint64_t index) = delete;
    196 
    197         /// returns true iff this is a vendor extension parameter
    198         inline bool isVendor() const { return mIndex & IS_VENDOR_FLAG; }
    199 
    200         /// returns true iff this is a flexible parameter (with variable size)
    201         inline bool isFlexible() const { return mIndex & IS_FLEX_FLAG; }
    202 
    203         /// returns the core index
    204         /// This is the combination of the parameter type index and the flexible flag.
    205         inline uint32_t coreIndex() const { return mIndex & CORE_MASK; }
    206 
    207         /// returns the parameter type index
    208         inline type_index_t typeIndex() const { return mIndex & TYPE_INDEX_MASK; }
    209 
    210         DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(CoreIndex, mIndex, CORE_MASK)
    211 
    212     protected:
    213         uint32_t mIndex;
    214     };
    215 
    216     /**
    217      * Type encompasses the parameter's kind (tuning, setting, info), its scope (whether the
    218      * parameter is global, input or output, and whether it is for a stream) and the its base
    219      * index (which also determines its layout).
    220      */
    221     struct Type : public CoreIndex {
    222     //public:
    223         /// returns true iff this is a global parameter (not for input nor output)
    224         inline bool isGlobal() const { return (mIndex & DIR_MASK) == DIR_GLOBAL; }
    225         /// returns true iff this is an input or input stream parameter
    226         inline bool forInput() const { return (mIndex & DIR_MASK) == DIR_INPUT; }
    227         /// returns true iff this is an output or output stream parameter
    228         inline bool forOutput() const { return (mIndex & DIR_MASK) == DIR_OUTPUT; }
    229 
    230         /// returns true iff this is a stream parameter
    231         inline bool forStream() const { return mIndex & IS_STREAM_FLAG; }
    232         /// returns true iff this is a port (input or output) parameter
    233         inline bool forPort() const   { return !forStream() && !isGlobal(); }
    234 
    235         /// returns the parameter type: the parameter index without the stream ID
    236         inline uint32_t type() const { return mIndex & (~STREAM_ID_MASK); }
    237 
    238         /// return the kind (struct, info, setting or tuning) of this param
    239         inline kind_t kind() const {
    240             switch (mIndex & KIND_MASK) {
    241                 case KIND_STRUCT: return STRUCT;
    242                 case KIND_INFO: return INFO;
    243                 case KIND_SETTING: return SETTING;
    244                 case KIND_TUNING: return TUNING;
    245                 default: return NONE; // should not happen
    246             }
    247         }
    248 
    249         /// constructor/conversion from uint32_t
    250         inline Type(uint32_t index) : CoreIndex(index) { }
    251 
    252         // no conversion from uint64_t
    253         inline Type(uint64_t index) = delete;
    254 
    255         DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(Type, mIndex, ~STREAM_ID_MASK)
    256 
    257     private:
    258         friend struct C2Param;   // for setPort()
    259         friend struct C2Tuning;  // for KIND_TUNING
    260         friend struct C2Setting; // for KIND_SETTING
    261         friend struct C2Info;    // for KIND_INFO
    262         // for DIR_GLOBAL
    263         template<typename T, typename S, int I, class F> friend struct C2GlobalParam;
    264         template<typename T, typename S, int I, class F> friend struct C2PortParam;   // for kDir*
    265         template<typename T, typename S, int I, class F> friend struct C2StreamParam; // for kDir*
    266         friend struct _C2ParamInspector; // for testing
    267 
    268         /**
    269          * Sets the port/stream direction.
    270          * @return true on success, false if could not set direction (e.g. it is global param).
    271          */
    272         inline bool setPort(bool output) {
    273             if (isGlobal()) {
    274                 return false;
    275             } else {
    276                 mIndex = (mIndex & ~DIR_MASK) | (output ? DIR_OUTPUT : DIR_INPUT);
    277                 return true;
    278             }
    279         }
    280     };
    281 
    282     /**
    283      * index encompasses all remaining information: basically the stream ID.
    284      */
    285     struct Index : public Type {
    286         /// returns the index as uint32_t
    287         inline operator uint32_t() const { return mIndex; }
    288 
    289         /// constructor/conversion from uint32_t
    290         inline Index(uint32_t index) : Type(index) { }
    291 
    292         /// copy constructor
    293         inline Index(const Index &index) = default;
    294 
    295         // no conversion from uint64_t
    296         inline Index(uint64_t index) = delete;
    297 
    298         /// returns the stream ID or ~0 if not a stream
    299         inline unsigned stream() const {
    300             return forStream() ? rawStream() : ~0U;
    301         }
    302 
    303         /// Returns an index with stream field set to given stream.
    304         inline Index withStream(unsigned stream) const {
    305             Index ix = mIndex;
    306             (void)ix.setStream(stream);
    307             return ix;
    308         }
    309 
    310         /// sets the port (direction). Returns true iff successful.
    311         inline Index withPort(bool output) const {
    312             Index ix = mIndex;
    313             (void)ix.setPort(output);
    314             return ix;
    315         }
    316 
    317         DEFINE_FIELD_BASED_COMPARISON_OPERATORS(Index, mIndex)
    318 
    319     private:
    320         friend struct C2Param;           // for setStream, MakeStreamId, isValid
    321         friend struct _C2ParamInspector; // for testing
    322 
    323         /**
    324          * @return true if the type is valid, e.g. direction is not undefined AND
    325          * stream is 0 if not a stream param.
    326          */
    327         inline bool isValid() const {
    328             // there is no Type::isValid (even though some of this check could be
    329             // performed on types) as this is only used on index...
    330             return (forStream() ? rawStream() < MAX_STREAM_ID : rawStream() == 0)
    331                     && (mIndex & DIR_MASK) != DIR_UNDEFINED;
    332         }
    333 
    334         /// returns the raw stream ID field
    335         inline unsigned rawStream() const {
    336             return (mIndex & STREAM_ID_MASK) >> STREAM_ID_SHIFT;
    337         }
    338 
    339         /// returns the streamId bitfield for a given |stream|. If stream is invalid,
    340         /// returns an invalid bitfield.
    341         inline static uint32_t MakeStreamId(unsigned stream) {
    342             // saturate stream ID (max value is invalid)
    343             if (stream > MAX_STREAM_ID) {
    344                 stream = MAX_STREAM_ID;
    345             }
    346             return (stream << STREAM_ID_SHIFT) & STREAM_ID_MASK;
    347         }
    348 
    349         inline bool convertToStream(bool output, unsigned stream) {
    350             mIndex = (mIndex & ~DIR_MASK) | IS_STREAM_FLAG;
    351             (void)setPort(output);
    352             return setStream(stream);
    353         }
    354 
    355         inline void convertToPort(bool output) {
    356             mIndex = (mIndex & ~(DIR_MASK | IS_STREAM_FLAG));
    357             (void)setPort(output);
    358         }
    359 
    360         inline void convertToGlobal() {
    361             mIndex = (mIndex & ~(DIR_MASK | IS_STREAM_FLAG)) | DIR_GLOBAL;
    362         }
    363 
    364         inline void convertToRequest() {
    365             mIndex = mIndex | IS_REQUEST_FLAG;
    366         }
    367 
    368         /**
    369          * Sets the stream index.
    370          * \return true on success, false if could not set index (e.g. not a stream param).
    371          */
    372         inline bool setStream(unsigned stream) {
    373             if (forStream()) {
    374                 mIndex = (mIndex & ~STREAM_ID_MASK) | MakeStreamId(stream);
    375                 return this->stream() < MAX_STREAM_ID;
    376             }
    377             return false;
    378         }
    379     };
    380 
    381 public:
    382     // public getters for Index methods
    383 
    384     /// returns true iff this is a vendor extension parameter
    385     inline bool isVendor() const { return _mIndex.isVendor(); }
    386     /// returns true iff this is a flexible parameter
    387     inline bool isFlexible() const { return _mIndex.isFlexible(); }
    388     /// returns true iff this is a global parameter (not for input nor output)
    389     inline bool isGlobal() const { return _mIndex.isGlobal(); }
    390     /// returns true iff this is an input or input stream parameter
    391     inline bool forInput() const { return _mIndex.forInput(); }
    392     /// returns true iff this is an output or output stream parameter
    393     inline bool forOutput() const { return _mIndex.forOutput(); }
    394 
    395     /// returns true iff this is a stream parameter
    396     inline bool forStream() const { return _mIndex.forStream(); }
    397     /// returns true iff this is a port (input or output) parameter
    398     inline bool forPort() const   { return _mIndex.forPort(); }
    399 
    400     /// returns the stream ID or ~0 if not a stream
    401     inline unsigned stream() const { return _mIndex.stream(); }
    402 
    403     /// returns the parameter type: the parameter index without the stream ID
    404     inline Type type() const { return _mIndex.type(); }
    405 
    406     /// returns the index of this parameter
    407     /// \todo: should we restrict this to C2ParamField?
    408     inline uint32_t index() const { return (uint32_t)_mIndex; }
    409 
    410     /// returns the core index of this parameter
    411     inline CoreIndex coreIndex() const { return _mIndex.coreIndex(); }
    412 
    413     /// returns the kind of this parameter
    414     inline kind_t kind() const { return _mIndex.kind(); }
    415 
    416     /// returns the size of the parameter or 0 if the parameter is invalid
    417     inline size_t size() const { return _mSize; }
    418 
    419     /// returns true iff the parameter is valid
    420     inline operator bool() const { return _mIndex.isValid() && _mSize > 0; }
    421 
    422     /// returns true iff the parameter is invalid
    423     inline bool operator!() const { return !operator bool(); }
    424 
    425     // equality is done by memcmp (use equals() to prevent any overread)
    426     inline bool operator==(const C2Param &o) const {
    427         return equals(o) && memcmp(this, &o, _mSize) == 0;
    428     }
    429     inline bool operator!=(const C2Param &o) const { return !operator==(o); }
    430 
    431     /// safe(r) type cast from pointer and size
    432     inline static C2Param* From(void *addr, size_t len) {
    433         // _mSize must fit into size, but really C2Param must also to be a valid param
    434         if (len < sizeof(C2Param)) {
    435             return nullptr;
    436         }
    437         // _mSize must match length
    438         C2Param *param = (C2Param*)addr;
    439         if (param->_mSize != len) {
    440             return nullptr;
    441         }
    442         return param;
    443     }
    444 
    445     /// Returns managed clone of |orig| at heap.
    446     inline static std::unique_ptr<C2Param> Copy(const C2Param &orig) {
    447         if (orig.size() == 0) {
    448             return nullptr;
    449         }
    450         void *mem = ::operator new (orig.size());
    451         C2Param *param = new (mem) C2Param(orig.size(), orig._mIndex);
    452         param->updateFrom(orig);
    453         return std::unique_ptr<C2Param>(param);
    454     }
    455 
    456     /// Returns managed clone of |orig| as a stream parameter at heap.
    457     inline static std::unique_ptr<C2Param> CopyAsStream(
    458             const C2Param &orig, bool output, unsigned stream) {
    459         std::unique_ptr<C2Param> copy = Copy(orig);
    460         if (copy) {
    461             copy->_mIndex.convertToStream(output, stream);
    462         }
    463         return copy;
    464     }
    465 
    466     /// Returns managed clone of |orig| as a port parameter at heap.
    467     inline static std::unique_ptr<C2Param> CopyAsPort(const C2Param &orig, bool output) {
    468         std::unique_ptr<C2Param> copy = Copy(orig);
    469         if (copy) {
    470             copy->_mIndex.convertToPort(output);
    471         }
    472         return copy;
    473     }
    474 
    475     /// Returns managed clone of |orig| as a global parameter at heap.
    476     inline static std::unique_ptr<C2Param> CopyAsGlobal(const C2Param &orig) {
    477         std::unique_ptr<C2Param> copy = Copy(orig);
    478         if (copy) {
    479             copy->_mIndex.convertToGlobal();
    480         }
    481         return copy;
    482     }
    483 
    484     /// Returns managed clone of |orig| as a stream parameter at heap.
    485     inline static std::unique_ptr<C2Param> CopyAsRequest(const C2Param &orig) {
    486         std::unique_ptr<C2Param> copy = Copy(orig);
    487         if (copy) {
    488             copy->_mIndex.convertToRequest();
    489         }
    490         return copy;
    491     }
    492 
    493 #if 0
    494     template<typename P, class=decltype(C2Param(P()))>
    495     P *As() { return P::From(this); }
    496     template<typename P>
    497     const P *As() const { return const_cast<const P*>(P::From(const_cast<C2Param*>(this))); }
    498 #endif
    499 
    500 protected:
    501     /// sets the stream field. Returns true iff successful.
    502     inline bool setStream(unsigned stream) {
    503         return _mIndex.setStream(stream);
    504     }
    505 
    506     /// sets the port (direction). Returns true iff successful.
    507     inline bool setPort(bool output) {
    508         return _mIndex.setPort(output);
    509     }
    510 
    511 public:
    512     /// invalidate this parameter. There is no recovery from this call; e.g. parameter
    513     /// cannot be 'corrected' to be valid.
    514     inline void invalidate() { _mSize = 0; }
    515 
    516     // if other is the same kind of (valid) param as this, copy it into this and return true.
    517     // otherwise, do not copy anything, and return false.
    518     inline bool updateFrom(const C2Param &other) {
    519         if (other._mSize <= _mSize && other._mIndex == _mIndex && _mSize > 0) {
    520             memcpy(this, &other, other._mSize);
    521             return true;
    522         }
    523         return false;
    524     }
    525 
    526 protected:
    527     // returns |o| if it is a null ptr, or if can suitably be a param of given |type| (e.g. has
    528     // same type (ignoring stream ID), and size). Otherwise, returns null. If |checkDir| is false,
    529     // allow undefined or different direction (e.g. as constructed from C2PortParam() vs.
    530     // C2PortParam::input), but still require equivalent type (stream, port or global); otherwise,
    531     // return null.
    532     inline static const C2Param* IfSuitable(
    533             const C2Param* o, size_t size, Type type, size_t flexSize = 0, bool checkDir = true) {
    534         if (o == nullptr || o->_mSize < size || (flexSize && ((o->_mSize - size) % flexSize))) {
    535             return nullptr;
    536         } else if (checkDir) {
    537             return o->_mIndex.type() == type.mIndex ? o : nullptr;
    538         } else if (o->_mIndex.isGlobal()) {
    539             return nullptr;
    540         } else {
    541             return ((o->_mIndex.type() ^ type.mIndex) & ~Type::DIR_MASK) ? nullptr : o;
    542         }
    543     }
    544 
    545     /// base constructor
    546     inline C2Param(uint32_t paramSize, Index paramIndex)
    547         : _mSize(paramSize),
    548           _mIndex(paramIndex) {
    549         if (paramSize > sizeof(C2Param)) {
    550             memset(this + 1, 0, paramSize - sizeof(C2Param));
    551         }
    552     }
    553 
    554     /// base constructor with stream set
    555     inline C2Param(uint32_t paramSize, Index paramIndex, unsigned stream)
    556         : _mSize(paramSize),
    557           _mIndex(paramIndex | Index::MakeStreamId(stream)) {
    558         if (paramSize > sizeof(C2Param)) {
    559             memset(this + 1, 0, paramSize - sizeof(C2Param));
    560         }
    561         if (!forStream()) {
    562             invalidate();
    563         }
    564     }
    565 
    566 private:
    567     friend struct _C2ParamInspector; // for testing
    568 
    569     /// returns true iff |o| has the same size and index as this. This performs the
    570     /// basic check for equality.
    571     inline bool equals(const C2Param &o) const {
    572         return _mSize == o._mSize && _mIndex == o._mIndex;
    573     }
    574 
    575     uint32_t _mSize;
    576     Index _mIndex;
    577 };
    578 
    579 /// \ingroup internal
    580 /// allow C2Params access to private methods, e.g. constructors
    581 #define C2PARAM_MAKE_FRIENDS \
    582     template<typename U, typename S, int I, class F> friend struct C2GlobalParam; \
    583     template<typename U, typename S, int I, class F> friend struct C2PortParam; \
    584     template<typename U, typename S, int I, class F> friend struct C2StreamParam; \
    585 
    586 /**
    587  * Setting base structure for component method signatures. Wrap constructors.
    588  */
    589 struct C2Setting : public C2Param {
    590 protected:
    591     template<typename ...Args>
    592     inline C2Setting(const Args(&... args)) : C2Param(args...) { }
    593 public: // TODO
    594     enum : uint32_t { PARAM_KIND = Type::KIND_SETTING };
    595 };
    596 
    597 /**
    598  * Tuning base structure for component method signatures. Wrap constructors.
    599  */
    600 struct C2Tuning : public C2Setting {
    601 protected:
    602     template<typename ...Args>
    603     inline C2Tuning(const Args(&... args)) : C2Setting(args...) { }
    604 public: // TODO
    605     enum : uint32_t { PARAM_KIND = Type::KIND_TUNING };
    606 };
    607 
    608 /**
    609  * Info base structure for component method signatures. Wrap constructors.
    610  */
    611 struct C2Info : public C2Param {
    612 protected:
    613     template<typename ...Args>
    614     inline C2Info(const Args(&... args)) : C2Param(args...) { }
    615 public: // TODO
    616     enum : uint32_t { PARAM_KIND = Type::KIND_INFO };
    617 };
    618 
    619 /**
    620  * Structure uniquely specifying a field in an arbitrary structure.
    621  *
    622  * \note This structure is used differently in C2FieldDescriptor to
    623  * identify array fields, such that _mSize is the size of each element. This is
    624  * because the field descriptor contains the array-length, and we want to keep
    625  * a relevant element size for variable length arrays.
    626  */
    627 struct _C2FieldId {
    628 //public:
    629     /**
    630      * Constructor used for C2FieldDescriptor that removes the array extent.
    631      *
    632      * \param[in] offset pointer to the field in an object at address 0.
    633      */
    634     template<typename T, class B=typename std::remove_extent<T>::type>
    635     inline _C2FieldId(T* offset)
    636         : // offset is from "0" so will fit on 32-bits
    637           _mOffset((uint32_t)(uintptr_t)(offset)),
    638           _mSize(sizeof(B)) { }
    639 
    640     /**
    641      * Direct constructor from offset and size.
    642      *
    643      * \param[in] offset offset of the field.
    644      * \param[in] size size of the field.
    645      */
    646     inline _C2FieldId(size_t offset, size_t size)
    647         : _mOffset(offset), _mSize(size) {}
    648 
    649     /**
    650      * Constructor used to identify a field in an object.
    651      *
    652      * \param U[type] pointer to the object that contains this field. This is needed in case the
    653      *        field is in an (inherited) base class, in which case T will be that base class.
    654      * \param pm[im] member pointer to the field
    655      */
    656     template<typename R, typename T, typename U, typename B=typename std::remove_extent<R>::type>
    657     inline _C2FieldId(U *, R T::* pm)
    658         : _mOffset((uint32_t)(uintptr_t)(&(((U*)256)->*pm)) - 256u),
    659           _mSize(sizeof(B)) { }
    660 
    661     /**
    662      * Constructor used to identify a field in an object.
    663      *
    664      * \param pm[im] member pointer to the field
    665      */
    666     template<typename R, typename T, typename B=typename std::remove_extent<R>::type>
    667     inline _C2FieldId(R T::* pm)
    668         : _mOffset((uint32_t)(uintptr_t)(&(((T*)0)->*pm))),
    669           _mSize(sizeof(B)) { }
    670 
    671     inline bool operator==(const _C2FieldId &other) const {
    672         return _mOffset == other._mOffset && _mSize == other._mSize;
    673     }
    674 
    675     inline bool operator<(const _C2FieldId &other) const {
    676         return _mOffset < other._mOffset ||
    677             // NOTE: order parent structure before sub field
    678             (_mOffset == other._mOffset && _mSize > other._mSize);
    679     }
    680 
    681     DEFINE_OTHER_COMPARISON_OPERATORS(_C2FieldId)
    682 
    683 #if 0
    684     inline uint32_t offset() const { return _mOffset; }
    685     inline uint32_t size() const { return _mSize; }
    686 #endif
    687 
    688 #if defined(FRIEND_TEST)
    689     friend void PrintTo(const _C2FieldId &d, ::std::ostream*);
    690 #endif
    691 
    692 private:
    693     friend struct _C2ParamInspector;
    694     friend struct C2FieldDescriptor;
    695 
    696     uint32_t _mOffset; // offset of field
    697     uint32_t _mSize;   // size of field
    698 };
    699 
    700 /**
    701  * Structure uniquely specifying a 'field' in a configuration. The field
    702  * can be a field of a configuration, a subfield of a field of a configuration,
    703  * and even the whole configuration. Moreover, if the field can point to an
    704  * element in a array field, or to the entire array field.
    705  *
    706  * This structure is used for querying supported values for a field, as well
    707  * as communicating configuration failures and conflicts when trying to change
    708  * a configuration for a component/interface or a store.
    709  */
    710 struct C2ParamField {
    711 //public:
    712     /**
    713      * Create a field identifier using a configuration parameter (variable),
    714      * and a pointer to member.
    715      *
    716      * ~~~~~~~~~~~~~ (.cpp)
    717      *
    718      * struct C2SomeParam {
    719      *   uint32_t mField;
    720      *   uint32_t mArray[2];
    721      *   C2OtherStruct mStruct;
    722      *   uint32_t mFlexArray[];
    723      * } *mParam;
    724      *
    725      * C2ParamField(mParam, &mParam->mField);
    726      * C2ParamField(mParam, &mParam->mArray);
    727      * C2ParamField(mParam, &mParam->mArray[0]);
    728      * C2ParamField(mParam, &mParam->mStruct.mSubField);
    729      * C2ParamField(mParam, &mParam->mFlexArray);
    730      * C2ParamField(mParam, &mParam->mFlexArray[2]);
    731      *
    732      * ~~~~~~~~~~~~~
    733      *
    734      * \todo fix what this is for T[] (for now size becomes T[1])
    735      *
    736      * \note this does not work for 64-bit members as it triggers a
    737      * 'taking address of packed member' warning.
    738      *
    739      * \param param pointer to parameter
    740      * \param offset member pointer
    741      */
    742     template<typename S, typename T>
    743     inline C2ParamField(S* param, T* offset)
    744         : _mIndex(param->index()),
    745           _mFieldId((T*)((uintptr_t)offset - (uintptr_t)param)) {}
    746 
    747     template<typename S, typename T>
    748     inline static C2ParamField Make(S& param, T& offset) {
    749         return C2ParamField(param.index(), (uintptr_t)&offset - (uintptr_t)&param, sizeof(T));
    750     }
    751 
    752     /**
    753      * Create a field identifier using a configuration parameter (variable),
    754      * and a member pointer. This method cannot be used to refer to an
    755      * array element or a subfield.
    756      *
    757      * ~~~~~~~~~~~~~ (.cpp)
    758      *
    759      * C2SomeParam mParam;
    760      * C2ParamField(&mParam, &C2SomeParam::mMemberField);
    761      *
    762      * ~~~~~~~~~~~~~
    763      *
    764      * \param p pointer to parameter
    765      * \param T member pointer to the field member
    766      */
    767     template<typename R, typename T, typename U>
    768     inline C2ParamField(U *p, R T::* pm) : _mIndex(p->index()), _mFieldId(p, pm) { }
    769 
    770     /**
    771      * Create a field identifier to a configuration parameter (variable).
    772      *
    773      * ~~~~~~~~~~~~~ (.cpp)
    774      *
    775      * C2SomeParam mParam;
    776      * C2ParamField(&mParam);
    777      *
    778      * ~~~~~~~~~~~~~
    779      *
    780      * \param param pointer to parameter
    781      */
    782     template<typename S>
    783     inline C2ParamField(S* param)
    784         : _mIndex(param->index()), _mFieldId(0u, param->size()) { }
    785 
    786     /** Copy constructor. */
    787     inline C2ParamField(const C2ParamField &other) = default;
    788 
    789     /**
    790      * Equality operator.
    791      */
    792     inline bool operator==(const C2ParamField &other) const {
    793         return _mIndex == other._mIndex && _mFieldId == other._mFieldId;
    794     }
    795 
    796     /**
    797      * Ordering operator.
    798      */
    799     inline bool operator<(const C2ParamField &other) const {
    800         return _mIndex < other._mIndex ||
    801             (_mIndex == other._mIndex && _mFieldId < other._mFieldId);
    802     }
    803 
    804     DEFINE_OTHER_COMPARISON_OPERATORS(C2ParamField)
    805 
    806 protected:
    807     inline C2ParamField(C2Param::Index index, uint32_t offset, uint32_t size)
    808         : _mIndex(index), _mFieldId(offset, size) {}
    809 
    810 private:
    811     friend struct _C2ParamInspector;
    812 
    813     C2Param::Index _mIndex; ///< parameter index
    814     _C2FieldId _mFieldId;   ///< field identifier
    815 };
    816 
    817 /**
    818  * A shared (union) representation of numeric values
    819  */
    820 class C2Value {
    821 public:
    822     /// A union of supported primitive types.
    823     union Primitive {
    824         // first member is always zero initialized so it must be the largest
    825         uint64_t    u64;   ///< uint64_t value
    826         int64_t     i64;   ///< int64_t value
    827         c2_cntr64_t c64;   ///< c2_cntr64_t value
    828         uint32_t    u32;   ///< uint32_t value
    829         int32_t     i32;   ///< int32_t value
    830         c2_cntr32_t c32;   ///< c2_cntr32_t value
    831         float       fp;    ///< float value
    832 
    833         // constructors - implicit
    834         Primitive(uint64_t value)    : u64(value) { }
    835         Primitive(int64_t value)     : i64(value) { }
    836         Primitive(c2_cntr64_t value) : c64(value) { }
    837         Primitive(uint32_t value)    : u32(value) { }
    838         Primitive(int32_t value)     : i32(value) { }
    839         Primitive(c2_cntr32_t value) : c32(value) { }
    840         Primitive(uint8_t value)     : u32(value) { }
    841         Primitive(char value)        : i32(value) { }
    842         Primitive(float value)       : fp(value)  { }
    843 
    844         // allow construction from enum type
    845         template<typename E, typename = typename std::enable_if<std::is_enum<E>::value>::type>
    846         Primitive(E value)
    847             : Primitive(static_cast<typename std::underlying_type<E>::type>(value)) { }
    848 
    849         Primitive() : u64(0) { }
    850 
    851         /** gets value out of the union */
    852         template<typename T> const T &ref() const;
    853 
    854         // verify that we can assume standard aliasing
    855         static_assert(sizeof(u64) == sizeof(i64), "");
    856         static_assert(sizeof(u64) == sizeof(c64), "");
    857         static_assert(sizeof(u32) == sizeof(i32), "");
    858         static_assert(sizeof(u32) == sizeof(c32), "");
    859     };
    860     // verify that we can assume standard aliasing
    861     static_assert(offsetof(Primitive, u64) == offsetof(Primitive, i64), "");
    862     static_assert(offsetof(Primitive, u64) == offsetof(Primitive, c64), "");
    863     static_assert(offsetof(Primitive, u32) == offsetof(Primitive, i32), "");
    864     static_assert(offsetof(Primitive, u32) == offsetof(Primitive, c32), "");
    865 
    866     enum type_t : uint32_t {
    867         NO_INIT,
    868         INT32,
    869         UINT32,
    870         CNTR32,
    871         INT64,
    872         UINT64,
    873         CNTR64,
    874         FLOAT,
    875     };
    876 
    877     template<typename T, bool = std::is_enum<T>::value>
    878     inline static constexpr type_t TypeFor() {
    879         using U = typename std::underlying_type<T>::type;
    880         return TypeFor<U>();
    881     }
    882 
    883     // deprectated
    884     template<typename T, bool B = std::is_enum<T>::value>
    885     inline static constexpr type_t typeFor() {
    886         return TypeFor<T, B>();
    887     }
    888 
    889     // constructors - implicit
    890     template<typename T>
    891     C2Value(T value)  : _mType(typeFor<T>()), _mValue(value) { }
    892 
    893     C2Value() : _mType(NO_INIT) { }
    894 
    895     inline type_t type() const { return _mType; }
    896 
    897     template<typename T>
    898     inline bool get(T *value) const {
    899         if (_mType == typeFor<T>()) {
    900             *value = _mValue.ref<T>();
    901             return true;
    902         }
    903         return false;
    904     }
    905 
    906     /// returns the address of the value
    907     void *get() const {
    908         return _mType == NO_INIT ? nullptr : (void*)&_mValue;
    909     }
    910 
    911     /// returns the size of the contained value
    912     size_t inline sizeOf() const {
    913         return SizeFor(_mType);
    914     }
    915 
    916     static size_t SizeFor(type_t type) {
    917         switch (type) {
    918             case INT32:
    919             case UINT32:
    920             case CNTR32: return sizeof(_mValue.i32);
    921             case INT64:
    922             case UINT64:
    923             case CNTR64: return sizeof(_mValue.i64);
    924             case FLOAT: return sizeof(_mValue.fp);
    925             default: return 0;
    926         }
    927     }
    928 
    929 private:
    930     type_t _mType;
    931     Primitive _mValue;
    932 };
    933 
    934 template<> inline const int32_t &C2Value::Primitive::ref<int32_t>() const { return i32; }
    935 template<> inline const int64_t &C2Value::Primitive::ref<int64_t>() const { return i64; }
    936 template<> inline const uint32_t &C2Value::Primitive::ref<uint32_t>() const { return u32; }
    937 template<> inline const uint64_t &C2Value::Primitive::ref<uint64_t>() const { return u64; }
    938 template<> inline const c2_cntr32_t &C2Value::Primitive::ref<c2_cntr32_t>() const { return c32; }
    939 template<> inline const c2_cntr64_t &C2Value::Primitive::ref<c2_cntr64_t>() const { return c64; }
    940 template<> inline const float &C2Value::Primitive::ref<float>() const { return fp; }
    941 
    942 // provide types for enums and uint8_t, char even though we don't provide reading as them
    943 template<> constexpr C2Value::type_t C2Value::TypeFor<char, false>() { return INT32; }
    944 template<> constexpr C2Value::type_t C2Value::TypeFor<int32_t, false>() { return INT32; }
    945 template<> constexpr C2Value::type_t C2Value::TypeFor<int64_t, false>() { return INT64; }
    946 template<> constexpr C2Value::type_t C2Value::TypeFor<uint8_t, false>() { return UINT32; }
    947 template<> constexpr C2Value::type_t C2Value::TypeFor<uint32_t, false>() { return UINT32; }
    948 template<> constexpr C2Value::type_t C2Value::TypeFor<uint64_t, false>() { return UINT64; }
    949 template<> constexpr C2Value::type_t C2Value::TypeFor<c2_cntr32_t, false>() { return CNTR32; }
    950 template<> constexpr C2Value::type_t C2Value::TypeFor<c2_cntr64_t, false>() { return CNTR64; }
    951 template<> constexpr C2Value::type_t C2Value::TypeFor<float, false>() { return FLOAT; }
    952 
    953 // forward declare easy enum template
    954 template<typename E> struct C2EasyEnum;
    955 
    956 /**
    957  * field descriptor. A field is uniquely defined by an index into a parameter.
    958  * (Note: Stream-id is not captured as a field.)
    959  *
    960  * Ordering of fields is by offset. In case of structures, it is depth first,
    961  * with a structure taking an index just before and in addition to its members.
    962  */
    963 struct C2FieldDescriptor {
    964 //public:
    965     /** field types and flags
    966      * \note: only 32-bit and 64-bit fields are supported (e.g. no boolean, as that
    967      * is represented using INT32).
    968      */
    969     enum type_t : uint32_t {
    970         // primitive types
    971         INT32   = C2Value::INT32,  ///< 32-bit signed integer
    972         UINT32  = C2Value::UINT32, ///< 32-bit unsigned integer
    973         CNTR32  = C2Value::CNTR32, ///< 32-bit counter
    974         INT64   = C2Value::INT64,  ///< 64-bit signed integer
    975         UINT64  = C2Value::UINT64, ///< 64-bit signed integer
    976         CNTR64  = C2Value::CNTR64, ///< 64-bit counter
    977         FLOAT   = C2Value::FLOAT,  ///< 32-bit floating point
    978 
    979         // array types
    980         STRING = 0x100, ///< fixed-size string (POD)
    981         BLOB,           ///< blob. Blobs have no sub-elements and can be thought of as byte arrays;
    982                         ///< however, bytes cannot be individually addressed by clients.
    983 
    984         // complex types
    985         STRUCT_FLAG = 0x20000, ///< structs. Marked with this flag in addition to their coreIndex.
    986     };
    987 
    988     typedef std::pair<C2String, C2Value::Primitive> NamedValueType;
    989     typedef std::vector<NamedValueType> NamedValuesType;
    990     //typedef std::pair<std::vector<C2String>, std::vector<C2Value::Primitive>> NamedValuesType;
    991 
    992     /**
    993      * Template specialization that returns the named values for a type.
    994      *
    995      * \todo hide from client.
    996      *
    997      * \return a vector of name-value pairs.
    998      */
    999     template<typename B>
   1000     static NamedValuesType namedValuesFor(const B &);
   1001 
   1002     /** specialization for easy enums */
   1003     template<typename E>
   1004     inline static NamedValuesType namedValuesFor(const C2EasyEnum<E> &) {
   1005 #pragma GCC diagnostic push
   1006 #pragma GCC diagnostic ignored "-Wnull-dereference"
   1007         return namedValuesFor(*(E*)nullptr);
   1008 #pragma GCC diagnostic pop
   1009     }
   1010 
   1011 private:
   1012     template<typename B, bool enabled=std::is_arithmetic<B>::value || std::is_enum<B>::value>
   1013     struct C2_HIDE _NamedValuesGetter;
   1014 
   1015 public:
   1016     inline C2FieldDescriptor(uint32_t type, uint32_t extent, C2String name, size_t offset, size_t size)
   1017         : _mType((type_t)type), _mExtent(extent), _mName(name), _mFieldId(offset, size) { }
   1018 
   1019     inline C2FieldDescriptor(const C2FieldDescriptor &) = default;
   1020 
   1021     template<typename T, class B=typename std::remove_extent<T>::type>
   1022     inline C2FieldDescriptor(const T* offset, const char *name)
   1023         : _mType(this->GetType((B*)nullptr)),
   1024           _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
   1025           _mName(name),
   1026           _mNamedValues(_NamedValuesGetter<B>::getNamedValues()),
   1027           _mFieldId(offset) {}
   1028 
   1029     /// \deprecated
   1030     template<typename T, typename S, class B=typename std::remove_extent<T>::type>
   1031     inline C2FieldDescriptor(S*, T S::* field, const char *name)
   1032         : _mType(this->GetType((B*)nullptr)),
   1033           _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
   1034           _mName(name),
   1035           _mFieldId(&(((S*)0)->*field)) {}
   1036 
   1037     /// returns the type of this field
   1038     inline type_t type() const { return _mType; }
   1039     /// returns the length of the field in case it is an array. Returns 0 for
   1040     /// T[] arrays, returns 1 for T[1] arrays as well as if the field is not an array.
   1041     inline size_t extent() const { return _mExtent; }
   1042     /// returns the name of the field
   1043     inline C2String name() const { return _mName; }
   1044 
   1045     const NamedValuesType &namedValues() const { return _mNamedValues; }
   1046 
   1047 #if defined(FRIEND_TEST)
   1048     friend void PrintTo(const C2FieldDescriptor &, ::std::ostream*);
   1049     friend bool operator==(const C2FieldDescriptor &, const C2FieldDescriptor &);
   1050     FRIEND_TEST(C2ParamTest_ParamFieldList, VerifyStruct);
   1051 #endif
   1052 
   1053 private:
   1054     /**
   1055      * Construct an offseted field descriptor.
   1056      */
   1057     inline C2FieldDescriptor(const C2FieldDescriptor &desc, size_t offset)
   1058         : _mType(desc._mType), _mExtent(desc._mExtent),
   1059           _mName(desc._mName), _mNamedValues(desc._mNamedValues),
   1060           _mFieldId(desc._mFieldId._mOffset + offset, desc._mFieldId._mSize) { }
   1061 
   1062     type_t _mType;
   1063     uint32_t _mExtent; // the last member can be arbitrary length if it is T[] array,
   1064                        // extending to the end of the parameter (this is marked with
   1065                        // 0). T[0]-s are not fields.
   1066     C2String _mName;
   1067     NamedValuesType _mNamedValues;
   1068 
   1069     _C2FieldId _mFieldId;   // field identifier (offset and size)
   1070 
   1071     // NOTE: We do not capture default value(s) here as that may depend on the component.
   1072     // NOTE: We also do not capture bestEffort, as 1) this should be true for most fields,
   1073     // 2) this is at parameter granularity.
   1074 
   1075     // type resolution
   1076     inline static type_t GetType(int32_t*)     { return INT32; }
   1077     inline static type_t GetType(uint32_t*)    { return UINT32; }
   1078     inline static type_t GetType(c2_cntr32_t*) { return CNTR32; }
   1079     inline static type_t GetType(int64_t*)     { return INT64; }
   1080     inline static type_t GetType(uint64_t*)    { return UINT64; }
   1081     inline static type_t GetType(c2_cntr64_t*) { return CNTR64; }
   1082     inline static type_t GetType(float*)       { return FLOAT; }
   1083     inline static type_t GetType(char*)        { return STRING; }
   1084     inline static type_t GetType(uint8_t*)     { return BLOB; }
   1085 
   1086     template<typename T,
   1087              class=typename std::enable_if<std::is_enum<T>::value>::type>
   1088     inline static type_t GetType(T*) {
   1089         typename std::underlying_type<T>::type underlying(0);
   1090         return GetType(&underlying);
   1091     }
   1092 
   1093     // verify C2Struct by having a FieldList() and a CORE_INDEX.
   1094     template<typename T,
   1095              class=decltype(T::CORE_INDEX + 1), class=decltype(T::FieldList())>
   1096     inline static type_t GetType(T*) {
   1097         static_assert(!std::is_base_of<C2Param, T>::value, "cannot use C2Params as fields");
   1098         return (type_t)(T::CORE_INDEX | STRUCT_FLAG);
   1099     }
   1100 
   1101     friend struct _C2ParamInspector;
   1102 };
   1103 
   1104 // no named values for compound types
   1105 template<typename B>
   1106 struct C2FieldDescriptor::_NamedValuesGetter<B, false> {
   1107     inline static C2FieldDescriptor::NamedValuesType getNamedValues() {
   1108         return NamedValuesType();
   1109     }
   1110 };
   1111 
   1112 template<typename B>
   1113 struct C2FieldDescriptor::_NamedValuesGetter<B, true> {
   1114     inline static C2FieldDescriptor::NamedValuesType getNamedValues() {
   1115 #pragma GCC diagnostic push
   1116 #pragma GCC diagnostic ignored "-Wnull-dereference"
   1117         return C2FieldDescriptor::namedValuesFor(*(B*)nullptr);
   1118 #pragma GCC diagnostic pop
   1119     }
   1120 };
   1121 
   1122 #define DEFINE_NO_NAMED_VALUES_FOR(type) \
   1123 template<> inline C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const type &) { \
   1124     return NamedValuesType(); \
   1125 }
   1126 
   1127 // We cannot subtype constructor for enumerated types so insted define no named values for
   1128 // non-enumerated integral types.
   1129 DEFINE_NO_NAMED_VALUES_FOR(int32_t)
   1130 DEFINE_NO_NAMED_VALUES_FOR(uint32_t)
   1131 DEFINE_NO_NAMED_VALUES_FOR(c2_cntr32_t)
   1132 DEFINE_NO_NAMED_VALUES_FOR(int64_t)
   1133 DEFINE_NO_NAMED_VALUES_FOR(uint64_t)
   1134 DEFINE_NO_NAMED_VALUES_FOR(c2_cntr64_t)
   1135 DEFINE_NO_NAMED_VALUES_FOR(uint8_t)
   1136 DEFINE_NO_NAMED_VALUES_FOR(char)
   1137 DEFINE_NO_NAMED_VALUES_FOR(float)
   1138 
   1139 /**
   1140  * Describes the fields of a structure.
   1141  */
   1142 struct C2StructDescriptor {
   1143 public:
   1144     /// Returns the core index of the struct
   1145     inline C2Param::CoreIndex coreIndex() const { return _mType.coreIndex(); }
   1146 
   1147     // Returns the number of fields in this struct (not counting any recursive fields).
   1148     // Must be at least 1 for valid structs.
   1149     inline size_t numFields() const { return _mFields.size(); }
   1150 
   1151     // Returns the list of direct fields (not counting any recursive fields).
   1152     typedef std::vector<C2FieldDescriptor>::const_iterator field_iterator;
   1153     inline field_iterator cbegin() const { return _mFields.cbegin(); }
   1154     inline field_iterator cend() const { return _mFields.cend(); }
   1155 
   1156     // only supplying const iterator - but these names are needed for range based loops
   1157     inline field_iterator begin() const { return _mFields.cbegin(); }
   1158     inline field_iterator end() const { return _mFields.cend(); }
   1159 
   1160     template<typename T>
   1161     inline C2StructDescriptor(T*)
   1162         : C2StructDescriptor(T::CORE_INDEX, T::FieldList()) { }
   1163 
   1164     inline C2StructDescriptor(
   1165             C2Param::CoreIndex type,
   1166             const std::vector<C2FieldDescriptor> &fields)
   1167         : _mType(type), _mFields(fields) { }
   1168 
   1169 private:
   1170     friend struct _C2ParamInspector;
   1171 
   1172     inline C2StructDescriptor(
   1173             C2Param::CoreIndex type,
   1174             std::vector<C2FieldDescriptor> &&fields)
   1175         : _mType(type), _mFields(std::move(fields)) { }
   1176 
   1177     const C2Param::CoreIndex _mType;
   1178     const std::vector<C2FieldDescriptor> _mFields;
   1179 };
   1180 
   1181 /**
   1182  * Describes parameters for a component.
   1183  */
   1184 struct C2ParamDescriptor {
   1185 public:
   1186     /**
   1187      * Returns whether setting this param is required to configure this component.
   1188      * This can only be true for builtin params for platform-defined components (e.g. video and
   1189      * audio encoders/decoders, video/audio filters).
   1190      * For vendor-defined components, it can be true even for vendor-defined params,
   1191      * but it is not recommended, in case the component becomes platform-defined.
   1192      */
   1193     inline bool isRequired() const { return _mAttrib & IS_REQUIRED; }
   1194 
   1195     /**
   1196      * Returns whether this parameter is persistent. This is always true for C2Tuning and C2Setting,
   1197      * but may be false for C2Info. If true, this parameter persists across frames and applies to
   1198      * the current and subsequent frames. If false, this C2Info parameter only applies to the
   1199      * current frame and is not assumed to have the same value (or even be present) on subsequent
   1200      * frames, unless it is specified for those frames.
   1201      */
   1202     inline bool isPersistent() const { return _mAttrib & IS_PERSISTENT; }
   1203 
   1204     inline bool isStrict() const { return _mAttrib & IS_STRICT; }
   1205 
   1206     inline bool isReadOnly() const { return _mAttrib & IS_READ_ONLY; }
   1207 
   1208     inline bool isVisible() const { return !(_mAttrib & IS_HIDDEN); }
   1209 
   1210     inline bool isPublic() const { return !(_mAttrib & IS_INTERNAL); }
   1211 
   1212     /// Returns the name of this param.
   1213     /// This defaults to the underlying C2Struct's name, but could be altered for a component.
   1214     inline C2String name() const { return _mName; }
   1215 
   1216     /// Returns the parameter index
   1217     inline C2Param::Index index() const { return _mIndex; }
   1218 
   1219     /// Returns the indices of parameters that this parameter has a dependency on
   1220     inline const std::vector<C2Param::Index> &dependencies() const { return _mDependencies; }
   1221 
   1222     /// \deprecated
   1223     template<typename T>
   1224     inline C2ParamDescriptor(bool isRequired, C2StringLiteral name, const T*)
   1225         : _mIndex(T::PARAM_TYPE),
   1226           _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
   1227           _mName(name) { }
   1228 
   1229     /// \deprecated
   1230     inline C2ParamDescriptor(
   1231             bool isRequired, C2StringLiteral name, C2Param::Index index)
   1232         : _mIndex(index),
   1233           _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
   1234           _mName(name) { }
   1235 
   1236     enum attrib_t : uint32_t {
   1237         // flags that default on
   1238         IS_REQUIRED   = 1u << 0, ///< parameter is required to be specified
   1239         IS_PERSISTENT = 1u << 1, ///< parameter retains its value
   1240         // flags that default off
   1241         IS_STRICT     = 1u << 2, ///< parameter is strict
   1242         IS_READ_ONLY  = 1u << 3, ///< parameter is publicly read-only
   1243         IS_HIDDEN     = 1u << 4, ///< parameter shall not be visible to clients
   1244         IS_INTERNAL   = 1u << 5, ///< parameter shall not be used by framework (other than testing)
   1245         IS_CONST      = 1u << 6 | IS_READ_ONLY, ///< parameter is publicly const (hence read-only)
   1246     };
   1247 
   1248     inline C2ParamDescriptor(
   1249         C2Param::Index index, attrib_t attrib, C2StringLiteral name)
   1250         : _mIndex(index),
   1251           _mAttrib(attrib),
   1252           _mName(name) { }
   1253 
   1254     inline C2ParamDescriptor(
   1255         C2Param::Index index, attrib_t attrib, C2String &&name,
   1256         std::vector<C2Param::Index> &&dependencies)
   1257         : _mIndex(index),
   1258           _mAttrib(attrib),
   1259           _mName(name),
   1260           _mDependencies(std::move(dependencies)) { }
   1261 
   1262 private:
   1263     const C2Param::Index _mIndex;
   1264     const uint32_t _mAttrib;
   1265     const C2String _mName;
   1266     std::vector<C2Param::Index> _mDependencies;
   1267 
   1268     friend struct _C2ParamInspector;
   1269 };
   1270 
   1271 DEFINE_ENUM_OPERATORS(::C2ParamDescriptor::attrib_t)
   1272 
   1273 
   1274 /// \ingroup internal
   1275 /// Define a structure without CORE_INDEX.
   1276 /// \note _FIELD_LIST is used only during declaration so that C2Struct declarations can end with
   1277 /// a simple list of C2FIELD-s and closing bracket. Mark it unused as it is not used in templated
   1278 /// structs.
   1279 #define DEFINE_BASE_C2STRUCT(name) \
   1280 private: \
   1281     const static std::vector<C2FieldDescriptor> _FIELD_LIST __unused; /**< structure fields */ \
   1282 public: \
   1283     typedef C2##name##Struct _type; /**< type name shorthand */ \
   1284     static const std::vector<C2FieldDescriptor> FieldList(); /**< structure fields factory */
   1285 
   1286 /// Define a structure with matching CORE_INDEX.
   1287 #define DEFINE_C2STRUCT(name) \
   1288 public: \
   1289     enum : uint32_t { CORE_INDEX = kParamIndex##name }; \
   1290     DEFINE_BASE_C2STRUCT(name)
   1291 
   1292 /// Define a flexible structure without CORE_INDEX.
   1293 #define DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) \
   1294 public: \
   1295     FLEX(C2##name##Struct, flexMember) \
   1296     DEFINE_BASE_C2STRUCT(name)
   1297 
   1298 /// Define a flexible structure with matching CORE_INDEX.
   1299 #define DEFINE_FLEX_C2STRUCT(name, flexMember) \
   1300 public: \
   1301     FLEX(C2##name##Struct, flexMember) \
   1302     enum : uint32_t { CORE_INDEX = kParamIndex##name | C2Param::CoreIndex::IS_FLEX_FLAG }; \
   1303     DEFINE_BASE_C2STRUCT(name)
   1304 
   1305 /// \ingroup internal
   1306 /// Describe a structure of a templated structure.
   1307 // Use list... as the argument gets resubsitituted and it contains commas. Alternative would be
   1308 // to wrap list in an expression, e.g. ({ std::vector<C2FieldDescriptor> list; })) which converts
   1309 // it from an initializer list to a vector.
   1310 #define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list...) \
   1311     _DESCRIBE_TEMPLATABLE_C2STRUCT(template<>, strukt, __C2_GENERATE_GLOBAL_VARS__, list)
   1312 
   1313 /// \deprecated
   1314 /// Describe the fields of a structure using an initializer list.
   1315 #define DESCRIBE_C2STRUCT(name, list...) \
   1316     _DESCRIBE_TEMPLATABLE_C2STRUCT(, C2##name##Struct, __C2_GENERATE_GLOBAL_VARS__, list)
   1317 
   1318 /// \ingroup internal
   1319 /// Macro layer to get value of enabled that is passed in as a macro variable
   1320 #define _DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, enabled, list...) \
   1321     __DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, enabled, list)
   1322 
   1323 /// \ingroup internal
   1324 /// Macro layer to resolve to the specific macro based on macro variable
   1325 #define __DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, enabled, list...) \
   1326     ___DESCRIBE_TEMPLATABLE_C2STRUCT##enabled(template, strukt, list)
   1327 
   1328 #define ___DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, list...) \
   1329     template \
   1330     const std::vector<C2FieldDescriptor> strukt::FieldList() { return list; }
   1331 
   1332 #define ___DESCRIBE_TEMPLATABLE_C2STRUCT__C2_GENERATE_GLOBAL_VARS__(template, strukt, list...)
   1333 
   1334 /**
   1335  * Describe a field of a structure.
   1336  * These must be in order.
   1337  *
   1338  * There are two ways to use this macro:
   1339  *
   1340  *  ~~~~~~~~~~~~~ (.cpp)
   1341  *  struct C2VideoWidthStruct {
   1342  *      int32_t width;
   1343  *      C2VideoWidthStruct() {} // optional default constructor
   1344  *      C2VideoWidthStruct(int32_t _width) : width(_width) {}
   1345  *
   1346  *      DEFINE_AND_DESCRIBE_C2STRUCT(VideoWidth)
   1347  *      C2FIELD(width, "width")
   1348  *  };
   1349  *  ~~~~~~~~~~~~~
   1350  *
   1351  *  ~~~~~~~~~~~~~ (.cpp)
   1352  *  struct C2VideoWidthStruct {
   1353  *      int32_t width;
   1354  *      C2VideoWidthStruct() = default; // optional default constructor
   1355  *      C2VideoWidthStruct(int32_t _width) : width(_width) {}
   1356  *
   1357  *      DEFINE_C2STRUCT(VideoWidth)
   1358  *  } C2_PACK;
   1359  *
   1360  *  DESCRIBE_C2STRUCT(VideoWidth, {
   1361  *      C2FIELD(width, "width")
   1362  *  })
   1363  *  ~~~~~~~~~~~~~
   1364  *
   1365  *  For flexible structures (those ending in T[]), use the flexible macros:
   1366  *
   1367  *  ~~~~~~~~~~~~~ (.cpp)
   1368  *  struct C2VideoFlexWidthsStruct {
   1369  *      int32_t widths[];
   1370  *      C2VideoFlexWidthsStruct(); // must have a default constructor
   1371  *
   1372  *  private:
   1373  *      // may have private constructors taking number of widths as the first argument
   1374  *      // This is used by the C2Param factory methods, e.g.
   1375  *      //   C2VideoFlexWidthsGlobalParam::AllocUnique(size_t, int32_t);
   1376  *      C2VideoFlexWidthsStruct(size_t flexCount, int32_t value) {
   1377  *          for (size_t i = 0; i < flexCount; ++i) {
   1378  *              widths[i] = value;
   1379  *          }
   1380  *      }
   1381  *
   1382  *      // If the last argument is T[N] or std::initializer_list<T>, the flexCount will
   1383  *      // be automatically calculated and passed by the C2Param factory methods, e.g.
   1384  *      //   int widths[] = { 1, 2, 3 };
   1385  *      //   C2VideoFlexWidthsGlobalParam::AllocUnique(widths);
   1386  *      template<unsigned N>
   1387  *      C2VideoFlexWidthsStruct(size_t flexCount, const int32_t(&init)[N]) {
   1388  *          for (size_t i = 0; i < flexCount; ++i) {
   1389  *              widths[i] = init[i];
   1390  *          }
   1391  *      }
   1392  *
   1393  *      DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoFlexWidths, widths)
   1394  *      C2FIELD(widths, "widths")
   1395  *  };
   1396  *  ~~~~~~~~~~~~~
   1397  *
   1398  *  ~~~~~~~~~~~~~ (.cpp)
   1399  *  struct C2VideoFlexWidthsStruct {
   1400  *      int32_t mWidths[];
   1401  *      C2VideoFlexWidthsStruct(); // must have a default constructor
   1402  *
   1403  *      DEFINE_FLEX_C2STRUCT(VideoFlexWidths, mWidths)
   1404  *  } C2_PACK;
   1405  *
   1406  *  DESCRIBE_C2STRUCT(VideoFlexWidths, {
   1407  *      C2FIELD(mWidths, "widths")
   1408  *  })
   1409  *  ~~~~~~~~~~~~~
   1410  *
   1411  */
   1412 #define DESCRIBE_C2FIELD(member, name) \
   1413   C2FieldDescriptor(&((_type*)(nullptr))->member, name),
   1414 
   1415 #define C2FIELD(member, name) _C2FIELD(member, name, __C2_GENERATE_GLOBAL_VARS__)
   1416 /// \if 0
   1417 #define _C2FIELD(member, name, enabled) __C2FIELD(member, name, enabled)
   1418 #define __C2FIELD(member, name, enabled) DESCRIBE_C2FIELD##enabled(member, name)
   1419 #define DESCRIBE_C2FIELD__C2_GENERATE_GLOBAL_VARS__(member, name)
   1420 /// \endif
   1421 
   1422 /// Define a structure with matching CORE_INDEX and start describing its fields.
   1423 /// This must be at the end of the structure definition.
   1424 #define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
   1425     _DEFINE_AND_DESCRIBE_C2STRUCT(name, DEFINE_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
   1426 
   1427 /// Define a base structure (with no CORE_INDEX) and start describing its fields.
   1428 /// This must be at the end of the structure definition.
   1429 #define DEFINE_AND_DESCRIBE_BASE_C2STRUCT(name) \
   1430     _DEFINE_AND_DESCRIBE_C2STRUCT(name, DEFINE_BASE_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
   1431 
   1432 /// Define a flexible structure with matching CORE_INDEX and start describing its fields.
   1433 /// This must be at the end of the structure definition.
   1434 #define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
   1435     _DEFINE_AND_DESCRIBE_FLEX_C2STRUCT( \
   1436             name, flexMember, DEFINE_FLEX_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
   1437 
   1438 /// Define a flexible base structure (with no CORE_INDEX) and start describing its fields.
   1439 /// This must be at the end of the structure definition.
   1440 #define DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(name, flexMember) \
   1441     _DEFINE_AND_DESCRIBE_FLEX_C2STRUCT( \
   1442             name, flexMember, DEFINE_BASE_FLEX_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
   1443 
   1444 /// \if 0
   1445 /*
   1446    Alternate declaration of field definitions in case no field list is to be generated.
   1447    The specific macro is chosed based on the value of __C2_GENERATE_GLOBAL_VARS__ (whether it is
   1448    defined (to be empty) or not. This requires two level of macro substitution.
   1449    TRICKY: use namespace declaration to handle closing bracket that is normally after
   1450    these macros.
   1451 */
   1452 
   1453 #define _DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro, enabled) \
   1454     __DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro, enabled)
   1455 #define __DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro, enabled) \
   1456     ___DEFINE_AND_DESCRIBE_C2STRUCT##enabled(name, defineMacro)
   1457 #define ___DEFINE_AND_DESCRIBE_C2STRUCT__C2_GENERATE_GLOBAL_VARS__(name, defineMacro) \
   1458     defineMacro(name) } C2_PACK; namespace {
   1459 #define ___DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro) \
   1460     defineMacro(name) } C2_PACK; \
   1461     const std::vector<C2FieldDescriptor> C2##name##Struct::FieldList() { return _FIELD_LIST; } \
   1462     const std::vector<C2FieldDescriptor> C2##name##Struct::_FIELD_LIST = {
   1463 
   1464 #define _DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro, enabled) \
   1465     __DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro, enabled)
   1466 #define __DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro, enabled) \
   1467     ___DEFINE_AND_DESCRIBE_FLEX_C2STRUCT##enabled(name, flexMember, defineMacro)
   1468 #define ___DEFINE_AND_DESCRIBE_FLEX_C2STRUCT__C2_GENERATE_GLOBAL_VARS__(name, flexMember, defineMacro) \
   1469     defineMacro(name, flexMember) } C2_PACK; namespace {
   1470 #define ___DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro) \
   1471     defineMacro(name, flexMember) } C2_PACK; \
   1472     const std::vector<C2FieldDescriptor> C2##name##Struct::FieldList() { return _FIELD_LIST; } \
   1473     const std::vector<C2FieldDescriptor> C2##name##Struct::_FIELD_LIST = {
   1474 /// \endif
   1475 
   1476 
   1477 /**
   1478  * Parameter reflector class.
   1479  *
   1480  * This class centralizes the description of parameter structures. This can be shared
   1481  * by multiple components as describing a parameter does not imply support of that
   1482  * parameter. However, each supported parameter and any dependent structures within
   1483  * must be described by the parameter reflector provided by a component.
   1484  */
   1485 class C2ParamReflector {
   1486 public:
   1487     /**
   1488      *  Describes a parameter structure.
   1489      *
   1490      *  \param[in] coreIndex the core index of the parameter structure containing at least the
   1491      *  core index
   1492      *
   1493      *  \return the description of the parameter structure
   1494      *  \retval nullptr if the parameter is not supported by this reflector
   1495      *
   1496      *  This methods shall not block and return immediately.
   1497      *
   1498      *  \note this class does not take a set of indices because we would then prefer
   1499      *  to also return any dependent structures, and we don't want this logic to be
   1500      *  repeated in each reflector. Alternately, this could just return a map of all
   1501      *  descriptions, but we want to conserve memory if client only wants the description
   1502      *  of a few indices.
   1503      */
   1504     virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const = 0;
   1505 
   1506 protected:
   1507     virtual ~C2ParamReflector() = default;
   1508 };
   1509 
   1510 /**
   1511  * Generic supported values for a field.
   1512  *
   1513  * This can be either a range or a set of values. The range can be a simple range, an arithmetic,
   1514  * geometric or multiply-accumulate series with a clear minimum and maximum value. Values can
   1515  * be discrete values, or can optionally represent flags to be or-ed.
   1516  *
   1517  * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
   1518  */
   1519 struct C2FieldSupportedValues {
   1520 //public:
   1521     enum type_t {
   1522         EMPTY,      ///< no supported values
   1523         RANGE,      ///< a numeric range that can be continuous or discrete
   1524         VALUES,     ///< a list of values
   1525         FLAGS       ///< a list of flags that can be OR-ed
   1526     };
   1527 
   1528     type_t type; /** Type of values for this field. */
   1529 
   1530     typedef C2Value::Primitive Primitive;
   1531 
   1532     /**
   1533      * Range specifier for supported value. Used if type is RANGE.
   1534      *
   1535      * If step is 0 and num and denom are both 1, the supported values are any value, for which
   1536      * min <= value <= max.
   1537      *
   1538      * Otherwise, the range represents a geometric/arithmetic/multiply-accumulate series, where
   1539      * successive supported values can be derived from previous values (starting at min), using the
   1540      * following formula:
   1541      *  v[0] = min
   1542      *  v[i] = v[i-1] * num / denom + step for i >= 1, while min < v[i] <= max.
   1543      */
   1544     struct {
   1545         /** Lower end of the range (inclusive). */
   1546         Primitive min;
   1547         /** Upper end of the range (inclusive if permitted by series). */
   1548         Primitive max;
   1549         /** Step between supported values. */
   1550         Primitive step;
   1551         /** Numerator of a geometric series. */
   1552         Primitive num;
   1553         /** Denominator of a geometric series. */
   1554         Primitive denom;
   1555     } range;
   1556 
   1557     /**
   1558      * List of values. Used if type is VALUES or FLAGS.
   1559      *
   1560      * If type is VALUES, this is the list of supported values in decreasing preference.
   1561      *
   1562      * If type is FLAGS, this vector contains { min-mask, flag1, flag2... }. Basically, the first
   1563      * value is the required set of flags to be set, and the rest of the values are flags that can
   1564      * be set independently. FLAGS is only supported for integral types. Supported flags should
   1565      * not overlap, as it can make validation non-deterministic. The standard validation method
   1566      * is that starting from the original value, if each flag is removed when fully present (the
   1567      * min-mask must be fully present), we shall arrive at 0.
   1568      */
   1569     std::vector<Primitive> values;
   1570 
   1571     C2FieldSupportedValues()
   1572         : type(EMPTY) {
   1573     }
   1574 
   1575     template<typename T>
   1576     C2FieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
   1577         : type(RANGE),
   1578           range{min, max, step, (T)1, (T)1} { }
   1579 
   1580     template<typename T>
   1581     C2FieldSupportedValues(T min, T max, T num, T den) :
   1582         type(RANGE),
   1583         range{min, max, (T)0, num, den} { }
   1584 
   1585     template<typename T>
   1586     C2FieldSupportedValues(T min, T max, T step, T num, T den)
   1587         : type(RANGE),
   1588           range{min, max, step, num, den} { }
   1589 
   1590     /// \deprecated
   1591     template<typename T>
   1592     C2FieldSupportedValues(bool flags, std::initializer_list<T> list)
   1593         : type(flags ? FLAGS : VALUES),
   1594           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
   1595         for (T value : list) {
   1596             values.emplace_back(value);
   1597         }
   1598     }
   1599 
   1600     /// \deprecated
   1601     template<typename T>
   1602     C2FieldSupportedValues(bool flags, const std::vector<T>& list)
   1603         : type(flags ? FLAGS : VALUES),
   1604           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
   1605         for(T value : list) {
   1606             values.emplace_back(value);
   1607         }
   1608     }
   1609 
   1610     /// \internal
   1611     /// \todo: create separate values vs. flags initializer as for flags we want
   1612     /// to list both allowed and required flags
   1613 #pragma GCC diagnostic push
   1614 #pragma GCC diagnostic ignored "-Wnull-dereference"
   1615     template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)nullptr))>
   1616     C2FieldSupportedValues(bool flags, const T*)
   1617         : type(flags ? FLAGS : VALUES),
   1618           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
   1619               C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)nullptr);
   1620         if (flags) {
   1621             values.emplace_back(0); // min-mask defaults to 0
   1622         }
   1623         for (const C2FieldDescriptor::NamedValueType &item : named){
   1624             values.emplace_back(item.second);
   1625         }
   1626     }
   1627 };
   1628 #pragma GCC diagnostic pop
   1629 
   1630 /**
   1631  * Supported values for a specific field.
   1632  *
   1633  * This is a pair of the field specifier together with an optional supported values object.
   1634  * This structure is used when reporting parameter configuration failures and conflicts.
   1635  */
   1636 struct C2ParamFieldValues {
   1637     C2ParamField paramOrField; ///< the field or parameter
   1638     /// optional supported values for the field if paramOrField specifies an actual field that is
   1639     /// numeric (non struct, blob or string). Supported values for arrays (including string and
   1640     /// blobs) describe the supported values for each element (character for string, and bytes for
   1641     /// blobs). It is optional for read-only strings and blobs.
   1642     std::unique_ptr<C2FieldSupportedValues> values;
   1643 
   1644     // This struct is meant to be move constructed.
   1645     C2_DEFAULT_MOVE(C2ParamFieldValues);
   1646 
   1647     // Copy constructor/assignment is also provided as this object may get copied.
   1648     C2ParamFieldValues(const C2ParamFieldValues &other)
   1649         : paramOrField(other.paramOrField),
   1650           values(other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr) { }
   1651 
   1652     C2ParamFieldValues& operator=(const C2ParamFieldValues &other) {
   1653         paramOrField = other.paramOrField;
   1654         values = other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr;
   1655         return *this;
   1656     }
   1657 
   1658 
   1659     /**
   1660      * Construct with no values.
   1661      */
   1662     C2ParamFieldValues(const C2ParamField &paramOrField_)
   1663         : paramOrField(paramOrField_) { }
   1664 
   1665     /**
   1666      * Construct with values.
   1667      */
   1668     C2ParamFieldValues(const C2ParamField &paramOrField_, const C2FieldSupportedValues &values_)
   1669         : paramOrField(paramOrField_),
   1670           values(std::make_unique<C2FieldSupportedValues>(values_)) { }
   1671 
   1672     /**
   1673      * Construct from fields.
   1674      */
   1675     C2ParamFieldValues(const C2ParamField &paramOrField_, std::unique_ptr<C2FieldSupportedValues> &&values_)
   1676         : paramOrField(paramOrField_),
   1677           values(std::move(values_)) { }
   1678 };
   1679 
   1680 /// @}
   1681 
   1682 // include debug header for C2Params.h if C2Debug.h was already included
   1683 #ifdef C2UTILS_DEBUG_H_
   1684 #include <util/C2Debug-param.h>
   1685 #endif
   1686 
   1687 #endif  // C2PARAM_H_
   1688