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