Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 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 C2UTILS_INTERFACE_HELPER_H_
     18 #define C2UTILS_INTERFACE_HELPER_H_
     19 
     20 #include <C2Component.h>
     21 #include <util/C2InterfaceUtils.h>
     22 
     23 #include <map>
     24 #include <mutex>
     25 #include <vector>
     26 
     27 #include <stddef.h>
     28 
     29 /**
     30  * Interface Helper
     31  */
     32 using C2R = C2SettingResultsBuilder;
     33 
     34 template<typename T, bool E=std::is_enum<T>::value>
     35 struct _c2_reduce_enum_to_underlying_type {
     36     typedef T type;
     37 };
     38 
     39 template<typename T>
     40 struct _c2_reduce_enum_to_underlying_type<T, true> {
     41     typedef typename std::underlying_type<T>::type type;
     42 };
     43 
     44 /**
     45  * Helper class to implement parameter reflectors. This class is dynamic and is designed to be
     46  * shared by multiple interfaces. This allows interfaces to add structure descriptors as needed.
     47  */
     48 class C2ReflectorHelper : public C2ParamReflector {
     49 public:
     50     C2ReflectorHelper() = default;
     51     virtual ~C2ReflectorHelper() = default;
     52     virtual std::unique_ptr<C2StructDescriptor> describe(
     53             C2Param::CoreIndex paramIndex) const override;
     54 
     55     /**
     56      * Adds support for describing the given parameters.
     57      *
     58      * \param Params types of codec 2.0 structs (or parameters) to describe
     59      */
     60     template<typename... Params>
     61     C2_INLINE void addStructDescriptors() {
     62         std::vector<C2StructDescriptor> structs;
     63         addStructDescriptors(structs, (_Tuple<Params...> *)nullptr);
     64     }
     65 
     66     /**
     67      * Adds support for describing a specific struct.
     68      *
     69      * \param strukt descriptor for the struct that will be moved out.
     70      */
     71     void addStructDescriptor(C2StructDescriptor &&strukt);
     72 
     73 private:
     74     template<typename... Params>
     75     class C2_HIDE _Tuple { };
     76 
     77     /**
     78      * Adds support for describing the given descriptors.
     79      *
     80      * \param structs List of structure descriptors to add support for
     81      */
     82     void addStructDescriptors(
     83             std::vector<C2StructDescriptor> &structs, _Tuple<> *);
     84 
     85     /**
     86      * Utility method that adds support for describing the given descriptors in a recursive manner
     87      * one structure at a time using a list of structure descriptors temporary.
     88      *
     89      * \param T the type of codec 2.0 struct to describe
     90      * \param Params rest of the structs
     91      * \param structs Temporary list of structure descriptors used to optimize the operation.
     92      */
     93     template<typename T, typename... Params>
     94     C2_INLINE void addStructDescriptors(
     95             std::vector<C2StructDescriptor> &structs, _Tuple<T, Params...> *) {
     96         structs.emplace_back((T*)nullptr);
     97         addStructDescriptors(structs, (_Tuple<Params...> *)nullptr);
     98     }
     99 
    100     mutable std::mutex _mMutex;
    101     std::map<C2Param::CoreIndex, const C2StructDescriptor> _mStructs; ///< descriptors
    102 };
    103 
    104 /**
    105  * Utility class that implements the codec 2.0 interface API-s for some parameters.
    106  *
    107  * This class must be subclassed.
    108  */
    109 class C2InterfaceHelper {
    110 public:
    111     /**
    112      * Returns the base offset of a field at |offset| that could be part of an array or part of a
    113      * sub-structure.
    114      *
    115      * This method does not do field size verification, e.g. if offset if obtained from a structure,
    116      * it will not stop at the structure boundary - this is okay, as we just want the base offset
    117      * here, which is the same.
    118      */
    119     static
    120     size_t GetBaseOffset(const std::shared_ptr<C2ParamReflector> &reflector,
    121                                 C2Param::CoreIndex index, size_t offset);
    122 
    123     /**
    124      * The interface helper class uses references to std::shared_ptr<T> config parameters.
    125      * Internally, these need to be generalized to std::shared_ptr<C2Param> refs, but the cast is
    126      * not allowed (as these are references). As such, this class never returns pointer to the
    127      * shared_ptrs.
    128      */
    129     struct ParamRef {
    130         template<typename T, typename enable=
    131                 typename std::enable_if<std::is_convertible<T, C2Param>::value>::type>
    132         inline C2_HIDE ParamRef(std::shared_ptr<T> &param)
    133             : _mRef(reinterpret_cast<std::shared_ptr<C2Param>*>(&param)) { }
    134 
    135         // used by comparison operator for containers
    136         operator std::shared_ptr<C2Param> *() const { return _mRef; }
    137 
    138         /**
    139          * Returns a shared pointer to the parameter.
    140          */
    141         std::shared_ptr<C2Param> get() const { return *_mRef; }
    142 
    143     private:
    144         std::shared_ptr<C2Param> *_mRef;
    145     };
    146 
    147     /**
    148      * Field helper.
    149      *
    150      * Contains additional information for the field: possible values, and currently supported
    151      * values.
    152      */
    153     class FieldHelper {
    154     public:
    155         /**
    156          * Creates helper for a field with given possible values.
    157          *
    158          * \param param parameter reference. The parameter does not have to be initialized at this
    159          *        point.
    160          * \param field field identifier
    161          * \param values possible values for the field
    162          */
    163         FieldHelper(const ParamRef &param, const _C2FieldId &field,
    164                     std::unique_ptr<C2FieldSupportedValues> &&values);
    165 
    166         /**
    167          * Creates a param-field identifier for this field. This method is called after the
    168          * underlying parameter has been initialized.
    169          *
    170          * \aram index
    171          *
    172          * @return C2ParamField
    173          */
    174         C2ParamField makeParamField(C2Param::Index index) const;
    175 
    176         /**
    177          * Sets the currently supported values for this field.
    178          *
    179          * \param values currently supported values that will be moved out
    180          */
    181         void setSupportedValues(std::unique_ptr<C2FieldSupportedValues> &&values);
    182 
    183         /**
    184          * Gets the currently supported values for this field. This defaults to the possible values
    185          * if currently supported values were never set.
    186          */
    187         const C2FieldSupportedValues *getSupportedValues() const;
    188 
    189         /**
    190          * Gets the possible values for this field.
    191          */
    192         const C2FieldSupportedValues *getPossibleValues() const;
    193 
    194     protected:
    195         // TODO: move to impl for safety
    196         ParamRef mParam;
    197         _C2FieldId mFieldId;
    198         std::unique_ptr<C2FieldSupportedValues> mPossible;
    199         std::unique_ptr<C2FieldSupportedValues> mSupported; ///< if different from possible
    200     };
    201 
    202     template<typename T>
    203     struct C2_HIDE Param;
    204     class ParamHelper;
    205 
    206     /**
    207      * Factory is an interface to get the parameter helpers from a std::shared_ptr<T> &.
    208      */
    209     class Factory {
    210         // \todo this may be already in ParamHelper
    211         virtual std::shared_ptr<C2ParamReflector> getReflector() const = 0;
    212 
    213         virtual std::shared_ptr<ParamHelper> getParamHelper(const ParamRef &param) const = 0;
    214 
    215     public:
    216         virtual ~Factory() = default;
    217 
    218         template<typename T>
    219         Param<T> get(std::shared_ptr<T> &param, std::shared_ptr<T> altValue = nullptr) const {
    220             return Param<T>(getParamHelper(ParamRef(param)),
    221                             altValue == nullptr ? param : altValue,
    222                             getReflector());
    223         }
    224     };
    225 
    226     /**
    227      * Typed field helper.
    228      */
    229     template<typename T>
    230     struct Field {
    231         /**
    232          * Constructor.
    233          *
    234          * \param helper helper for this field
    235          * \param index  parameter index (this is needed as it is not available during parameter
    236          *        construction) \todo remove
    237          */
    238         Field(std::shared_ptr<FieldHelper> helper, C2Param::Index index);
    239 
    240         bool supportsAtAll(T value) const {
    241             return C2FieldSupportedValuesHelper<T>(*_mHelper->getPossibleValues()).supports(value);
    242         }
    243 
    244         bool supportsNow(T value) const {
    245             return C2FieldSupportedValuesHelper<T>(*_mHelper->getSupportedValues()).supports(value);
    246         }
    247 
    248         /**
    249          * Creates a conflict resolution suggestion builder for this field.
    250          */
    251         C2ParamFieldValuesBuilder<T> shouldBe() const;
    252 
    253         /**
    254          * Creates a currently supported values builder for this field. This is only supported
    255          * for non-const fields to disallow setting supported values for dependencies.
    256          */
    257         C2ParamFieldValuesBuilder<T> mustBe();
    258 
    259         operator C2ParamField() const {
    260             return _mField;
    261         }
    262 
    263         // TODO
    264         C2R validatePossible(const T &value __unused) const {
    265             /// TODO
    266             return C2R::Ok();
    267         }
    268 
    269     private:
    270         std::shared_ptr<FieldHelper> _mHelper;
    271         C2ParamField _mField;
    272     };
    273 
    274     class ParamHelper {
    275     public:
    276         ParamHelper(ParamRef param, C2StringLiteral name, C2StructDescriptor &&);
    277         ParamHelper(ParamHelper &&);
    278         ~ParamHelper();
    279 
    280         /**
    281          * Finds a field descriptor.
    282          */
    283         std::shared_ptr<FieldHelper> findField(size_t baseOffs, size_t baseSize) const;
    284 
    285         /// returns the parameter ref for this parameter
    286         const ParamRef ref() const;
    287 
    288         /// returns the current value of this parameter as modifiable. The constness of this
    289         /// object determines the constness of the returned value.
    290         std::shared_ptr<C2Param> value();
    291 
    292         /// returns the current value of this parameter as const
    293         std::shared_ptr<const C2Param> value() const;
    294 
    295         /**
    296          * Performs a configuration change request for this parameter.
    297          *
    298          * \param value    the value that is being assigned to this parameter.
    299          *                 This could be pointing to the current value of the
    300          *                 parameter. This must not change.
    301          * \param mayBlock whether blocking is allowed
    302          * \param endValue the resulting value
    303          * \param factory  parameter factory (to access dependencies)
    304          * \param failures vector of failures to append any failures from this
    305          *                 operation
    306          *
    307          * \retval C2_OK        configuration was successful
    308          * \retval C2_BAD_VALUE value is incorrect (TBD)
    309          * \retval C2_NO_MEMORY not enough memory to perform the assignment
    310          * \retval C2_TIMED_OUT configuration timed out
    311          * \retval C2_BLOCKING  configuration requires blocking to be allowed
    312          * \retval C2_CORRUPTED interface is corrupted
    313          */
    314         c2_status_t trySet(
    315                 const C2Param *value, bool mayBlock,
    316                 bool *changed,
    317                 Factory &factory,
    318                 std::vector<std::unique_ptr<C2SettingResult>>* const failures);
    319 
    320         /// returns parameter indices that depend on this parameter
    321         const std::vector<C2Param::Index> getDownDependencies() const;
    322 
    323         /// adds a dependent parameter
    324         void addDownDependency(C2Param::Index index);
    325 
    326         /// returns that parameter refs for parameters that depend on this
    327         const std::vector<ParamRef> getDependenciesAsRefs() const;
    328 
    329         /// returns and moves out stored struct descriptor
    330         C2StructDescriptor retrieveStructDescriptor();
    331 
    332         /// returns the name of this parameter
    333         C2String name() const;
    334 
    335         /// returns the index of this parameter
    336         C2Param::Index index() const;
    337 
    338         /// returns the parameter descriptor
    339         std::shared_ptr<const C2ParamDescriptor> getDescriptor() const;
    340 
    341         /**
    342          * Validates param helper.
    343          *
    344          * For now, this fills field info for const params.
    345          *
    346          * \retval C2_CORRUPTED the parameter cannot be added as such
    347          */
    348         c2_status_t validate(const std::shared_ptr<C2ParamReflector> &reflector);
    349 
    350     protected:
    351         typedef C2ParamDescriptor::attrib_t attrib_t;
    352         attrib_t& attrib();
    353 
    354         /// sets the default value of this parameter
    355         void setDefaultValue(std::shared_ptr<C2Param> default_);
    356 
    357         /// sets the setter method
    358         void setSetter(std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter);
    359 
    360         /// sets the getter method
    361         void setGetter(std::function<std::shared_ptr<C2Param>(bool)> getter);
    362 
    363         /// sets the dependencies
    364         void setDependencies(std::vector<C2Param::Index> indices, std::vector<ParamRef> refs);
    365 
    366         /// sets the fields and their supported values
    367         void setFields(std::vector<C2ParamFieldValues> &&fields);
    368 
    369         /// build this into a final ParamHelper object
    370         std::shared_ptr<ParamHelper> build();
    371 
    372         class Impl;
    373         std::unique_ptr<Impl> mImpl;
    374     };
    375 
    376     /**
    377      * Typed parameter helper. This provides access to members as well as field helpers.
    378      */
    379     template<typename T>
    380     struct C2_HIDE Param {
    381         Param(
    382                 std::shared_ptr<ParamHelper> helper, std::shared_ptr<T> &param,
    383                 std::shared_ptr<C2ParamReflector> reflector)
    384             : v(*param.get()),
    385               _mTypedParam(param),
    386               _mHelper(helper),
    387               _mReflector(reflector) { }
    388 
    389         template<typename S>
    390         using FieldType = Field<
    391                 typename _c2_reduce_enum_to_underlying_type<
    392                         typename std::remove_const<
    393                                 typename std::remove_extent<S>::type>::type>::type>;
    394 
    395         template<typename S>
    396         FieldType<S> F(S &field) {
    397             size_t offs = (uintptr_t)&field - (uintptr_t)&get();
    398             // this must fall either within sizeof(T) + FLEX_SIZE or param->size()
    399             // size_t size = sizeof(field);
    400             // mParam may be null
    401             size_t baseSize = sizeof(typename std::remove_extent<S>::type);
    402             size_t baseOffs = GetBaseOffset(
    403                     _mReflector, T::CORE_INDEX, offs - sizeof(C2Param));
    404             if (~baseOffs == 0) {
    405                 // C2_LOG(FATAL) << "unknown field at offset " << offs << " size " << sizeof(S)
    406                 //       << " base-size " << baseSize;
    407                 // __builtin_trap();
    408             } else {
    409                 baseOffs += sizeof(C2Param);
    410             }
    411 
    412             std::shared_ptr<FieldHelper> helper = _mHelper->findField(baseOffs, baseSize);
    413             return FieldType<S>(helper, _mTypedParam->index());
    414         }
    415 
    416         // const Param have const Fields; however, remove const from S
    417         template<typename S>
    418         const FieldType<S> F(S &field) const {
    419             return const_cast<const FieldType<S>>(const_cast<Param *>(this)->F(field));
    420         }
    421 
    422         /// Returns a const ref value of this const param.
    423         const T &get() const {
    424             return *_mTypedParam.get();
    425         }
    426 
    427         /// Returns a modifiable ref value of this non-const param.
    428         T &set() {
    429             return *_mTypedParam.get();
    430         }
    431 
    432         /// Const-reference to the value.s
    433         T const &v;
    434 
    435     private:
    436         std::shared_ptr<T> _mTypedParam;
    437         std::shared_ptr<ParamHelper> _mHelper;
    438         std::shared_ptr<C2ParamReflector> _mReflector;
    439     };
    440 
    441     template<typename T>
    442     using C2P = Param<T>;
    443 
    444     /**
    445      * Templated move builder class for a parameter helper.
    446      */
    447     template<typename T>
    448     class C2_HIDE ParamBuilder : private ParamHelper {
    449     public:
    450         /** Construct the parameter builder from minimal info required. */
    451         ParamBuilder(std::shared_ptr<T> &param, C2StringLiteral name)
    452             : ParamHelper(param, name, C2StructDescriptor((T*)nullptr)),
    453               mTypedParam(&param) {
    454             attrib() = attrib_t::IS_PERSISTENT;
    455         }
    456 
    457         /** Makes this parameter required. */
    458         inline ParamBuilder &required() {
    459             attrib() |= attrib_t::IS_REQUIRED;
    460             return *this;
    461         }
    462 
    463         /** Makes this parameter transient (not persistent). */
    464         inline ParamBuilder &transient() {
    465             attrib() &= ~attrib_t::IS_PERSISTENT;
    466             return *this;
    467         }
    468 
    469         /** Makes this parameter hidden (not exposed in JAVA API). */
    470         inline ParamBuilder &hidden() {
    471             attrib() |= attrib_t::IS_HIDDEN;
    472             return *this;
    473         }
    474 
    475         /** Makes this parameter internal (not exposed to query/settings). */
    476         inline ParamBuilder &internal() {
    477             attrib() |= attrib_t::IS_INTERNAL;
    478             return *this;
    479         }
    480 
    481         /** Adds default value. Must be added exactly once. */
    482         inline ParamBuilder &withDefault(std::shared_ptr<T> default_) {
    483             // CHECK(!mDefaultValue);
    484             // WARN_IF(!default_); // could be nullptr if OOM
    485             // technically, this could be in the parent
    486             *mTypedParam = std::shared_ptr<T>(T::From(C2Param::Copy(*default_).release()));
    487             setDefaultValue(default_);
    488             std::shared_ptr<T> *typedParam = mTypedParam;
    489             setGetter([typedParam](bool) -> std::shared_ptr<C2Param> {
    490                 return std::static_pointer_cast<C2Param>(*typedParam);
    491             });
    492             return *this;
    493         }
    494 
    495         /** Adds default value. Must be added exactly once. */
    496         inline ParamBuilder &withDefault(T *default_) {
    497             return withDefault(std::shared_ptr<T>(default_));
    498         }
    499 
    500         /** Adds all fields to this parameter with their possible values. */
    501         inline ParamBuilder &withFields(std::vector<C2ParamFieldValues> &&fields_) {
    502             setFields(std::move(fields_));
    503             return *this;
    504         }
    505 
    506         /**
    507          * Adds a constant value (also as default). Must be added exactly once.
    508          *
    509          * Const parameters by definition have no dependencies.
    510          */
    511         inline ParamBuilder &withConstValue(std::shared_ptr<T> default_) {
    512             attrib() |= attrib_t::IS_CONST;
    513             setSetter([default_](
    514                     const C2Param *value, bool mayBlock __unused, bool *changed, Factory &) -> C2R {
    515                 *changed = false;
    516                 const T *typedValue = T::From(value);
    517                 if (typedValue == nullptr) {
    518                     return C2R::Corrupted(); // TODO BadValue/Invalid. This should not happen here.
    519                 }
    520                 if (*typedValue != *default_) {
    521                     return C2R::Corrupted(); // TODO ReadOnly(*default_);
    522                 }
    523                 *changed = false;
    524                 return C2R::Ok();
    525             });
    526             return withDefault(default_);
    527         }
    528 
    529         /** Adds constant value (also as default). Must be added exactly once. */
    530         inline ParamBuilder &withConstValue(T *default_) {
    531             return withConstValue(std::shared_ptr<T>(default_));
    532         }
    533 
    534         /**
    535          * Use a strict setter.
    536          *
    537          * \param fn   strict setter
    538          * \param deps dependencies (references)
    539          */
    540         template<typename ... Deps>
    541         inline ParamBuilder &withSetter(
    542                 C2R (*fn)(bool, const C2P<T> &, C2P<T> &, const C2P<Deps> &...),
    543                 std::shared_ptr<Deps>& ... deps) {
    544             attrib() |= attrib_t::IS_STRICT;
    545             std::shared_ptr<T> *typedParam = mTypedParam;
    546             setSetter([typedParam, fn, &deps...](
    547                     const C2Param *value, bool mayBlock, bool *changed, Factory &factory) -> C2R {
    548                 *changed = false;
    549                 const T *typedValue = T::From(value);
    550                 if (typedValue == nullptr) {
    551                     return C2R::Corrupted(); // TODO BadValue/Invalid. This should not happen here.
    552                 }
    553                 // Do copy-on-change for parameters in this helper so change can be detected by
    554                 // a change of the pointer. Do this by working on a proposed value.
    555                 std::shared_ptr<T> proposedValue =
    556                     std::shared_ptr<T>(T::From(C2Param::Copy(*value).release()));
    557                 if (proposedValue == nullptr) {
    558                     return C2R::NoMemory(value->index());
    559                 }
    560                 C2P<T> oldValue = factory.get(*typedParam);
    561                 // Get a parameter helper with value pointing to proposedValue
    562                 C2P<T> helper = factory.get(*typedParam, proposedValue);
    563                 C2R result = fn(mayBlock, oldValue, helper, factory.get(deps)...);
    564 
    565                 // If value changed, copy result to current value
    566                 if (helper.get() != *typedParam->get()) {
    567                     *typedParam = proposedValue;
    568                     *changed = true;
    569                 }
    570                 return result;
    571             });
    572             setDependencies(std::vector<C2Param::Index>{ deps->index()... },
    573                             std::vector<ParamRef>{ ParamRef(deps)... });
    574             return *this;
    575         }
    576 
    577         /**
    578          * Use a non-strict setter.
    579          *
    580          * \param fn   non-strict setter
    581          * \param deps dependencies (references)
    582          */
    583         template<typename ... Deps>
    584         inline ParamBuilder &withSetter(
    585                 C2R (*fn)(bool, C2P<T> &, const C2P<Deps> &...), std::shared_ptr<Deps>& ... deps) {
    586             std::shared_ptr<T> *typedParam = mTypedParam;
    587             setSetter([typedParam, fn, &deps...](
    588                     const C2Param *value, bool mayBlock, bool *changed, Factory &factory) -> C2R {
    589                 *changed = false;
    590                 const T *typedValue = T::From(value);
    591                 if (typedValue == nullptr) {
    592                     return C2R::Corrupted(); // TODO BadValue/Invalid. This should not happen here.
    593                 }
    594                 // Do copy-on-change for parameters in this helper so change can be detected by
    595                 // a change of the pointer. Do this by working on a proposed value.
    596                 std::shared_ptr<T> proposedValue =
    597                     std::shared_ptr<T>(T::From(C2Param::Copy(*value).release()));
    598                 if (proposedValue == nullptr) {
    599                     return C2R::NoMemory(value->index());
    600                 }
    601                 // Get a parameter helper with value pointing to proposedValue
    602                 C2P<T> helper = factory.get(*typedParam, proposedValue);
    603                 C2R result = fn(mayBlock, helper, factory.get(deps)...);
    604 
    605                 // If value changed, copy result to current value
    606                 if (helper.get() != *typedParam->get()) {
    607                     *typedParam = proposedValue;
    608                     *changed = true;
    609                 }
    610                 return result;
    611             });
    612             setDependencies(std::vector<C2Param::Index>{ deps->index()... },
    613                             std::vector<ParamRef>{ ParamRef(deps)... });
    614             return *this;
    615         }
    616 
    617         /**
    618          * Marks this a calculated (read-only) field.
    619          *
    620          * \param fn   non-strict setter (calculator)
    621          * \param deps dependencies (references)
    622          */
    623         template<typename ... Deps>
    624         inline ParamBuilder &calculatedAs(
    625                 C2R (*fn)(bool, C2P<T> &, const C2P<Deps> &...), std::shared_ptr<Deps>& ... deps) {
    626             attrib() |= attrib_t::IS_READ_ONLY;
    627             return withSetter(fn, std::forward<decltype(deps)>(deps)...);
    628         }
    629 
    630         inline std::shared_ptr<ParamHelper> build() {
    631             return ParamHelper::build();
    632         }
    633 
    634     protected:
    635         std::shared_ptr<T> *mTypedParam;
    636     };
    637 
    638     template<typename T>
    639     static ParamBuilder<T> DefineParam(std::shared_ptr<T> &param, C2StringLiteral name) {
    640         return ParamBuilder<T>(param, name);
    641     }
    642 
    643 public:
    644     c2_status_t query(
    645             const std::vector<C2Param*> &stackParams,
    646             const std::vector<C2Param::Index> &heapParamIndices,
    647             c2_blocking_t mayBlock,
    648             std::vector<std::unique_ptr<C2Param>>* const heapParams) const;
    649 
    650     /**
    651      * Helper implementing config calls as well as other configuration updates.
    652      *
    653      * This method is virtual, so implementations may provide wrappers around it (and perform
    654      * actions just before and after a configuration).
    655      *
    656      * \param params
    657      * \param mayBlock
    658      * \param failures
    659      * \param updateParams if true, the updated parameter values are copied back into the arguments
    660      *                     passed in |params|
    661      * \param changes      pointed to a vector to receive settings with their values changed. If not
    662      *                     null, settings with their values changed are added to this.
    663      * \return result from config
    664      */
    665     virtual c2_status_t config(
    666             const std::vector<C2Param*> &params, c2_blocking_t mayBlock,
    667             std::vector<std::unique_ptr<C2SettingResult>>* const failures,
    668             bool updateParams = true,
    669             std::vector<std::shared_ptr<C2Param>> *changes = nullptr);
    670 
    671     c2_status_t querySupportedParams(
    672             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const;
    673 
    674     c2_status_t querySupportedValues(
    675             std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const;
    676 
    677     std::shared_ptr<C2ReflectorHelper> getReflector() {
    678         return mReflector;
    679     }
    680 
    681     typedef std::unique_lock<std::mutex> Lock;
    682 
    683     /**
    684      * Locks the interface and returns a lock. This lock must be unlocked or released without
    685      * calling any other blocking call.
    686      */
    687     Lock lock() const;
    688 
    689 private:
    690     void setInterfaceAddressBounds(uintptr_t start, uintptr_t end) {
    691         // TODO: exclude this helper
    692         (void)start;
    693         (void)end;
    694     }
    695 
    696 protected:
    697     mutable std::mutex mMutex;
    698     std::shared_ptr<C2ReflectorHelper> mReflector;
    699     struct FactoryImpl;
    700     std::shared_ptr<FactoryImpl> _mFactory;
    701 
    702     C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector);
    703 
    704     /**
    705      * Adds a parameter to this interface.
    706      * \note This method CHECKs.
    707      *
    708      * \param param parameter to add.
    709      */
    710     void addParameter(std::shared_ptr<ParamHelper> param);
    711 
    712     /**
    713      * Returns the dependency index for a parameter.
    714      *
    715      * \param ix the index of the parameter
    716      */
    717     size_t getDependencyIndex_l(C2Param::Index ix) const;
    718 
    719     virtual ~C2InterfaceHelper() = default;
    720 
    721     /**
    722      * Sets subclass instance's address and size.
    723      *
    724      * \todo allow subclass to specify parameter address range directly (e.g. do not assume that
    725      *       they are local to the subclass instance)
    726      *
    727      * \param T type of the derived instance
    728      * \param instance pointer to the derived instance
    729      */
    730     template<typename T>
    731     inline C2_HIDE void setDerivedInstance(T *instance) {
    732         setInterfaceAddressBounds((uintptr_t)instance, (uintptr_t)(instance + 1));
    733     }
    734 
    735     C2_DO_NOT_COPY(C2InterfaceHelper);
    736 };
    737 
    738 /**
    739  * Creates a C2ParamFieldValuesBuilder class for a field of a parameter
    740  *
    741  * \param spParam a configuration parameter in an interface class subclassed from C2InterfaceHelper.
    742  * \param field   a field of such parameter
    743  */
    744 #define C2F(spParam, field) \
    745     C2ParamFieldValuesBuilder< \
    746             typename _c2_reduce_enum_to_underlying_type< \
    747                     typename std::remove_reference< \
    748                             typename std::remove_extent< \
    749                                     decltype(spParam->field)>::type>::type>::type>( \
    750                                             C2ParamField(spParam.get(), &spParam->field))
    751 
    752 #endif  // C2UTILS_INTERFACE_HELPER_H_
    753