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 */
31using C2R = C2SettingResultsBuilder;
32
33template<typename T, bool E=std::is_enum<T>::value>
34struct _c2_reduce_enum_to_underlying_type {
35    typedef T type;
36};
37
38template<typename T>
39struct _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 */
47class C2ReflectorHelper : public C2ParamReflector {
48public:
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
72private:
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 */
108class C2InterfaceHelper {
109public:
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
642public:
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
677private:
678    void setInterfaceAddressBounds(uintptr_t start, uintptr_t end) {
679        // TODO: exclude this helper
680        (void)start;
681        (void)end;
682    }
683
684protected:
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