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