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 #include <C2Debug.h>
     18 #include <C2ParamInternal.h>
     19 #include <util/C2InterfaceHelper.h>
     20 
     21 #include <android-base/stringprintf.h>
     22 
     23 using ::android::base::StringPrintf;
     24 
     25 /* --------------------------------- ReflectorHelper --------------------------------- */
     26 
     27 void C2ReflectorHelper::addStructDescriptors(
     28         std::vector<C2StructDescriptor> &structs, _Tuple<> *) {
     29     std::lock_guard<std::mutex> lock(_mMutex);
     30     for (C2StructDescriptor &strukt : structs) {
     31         // TODO: check if structure descriptions conflict with existing ones
     32         addStructDescriptor(std::move(strukt));
     33     }
     34 }
     35 
     36 std::unique_ptr<C2StructDescriptor>
     37 C2ReflectorHelper::describe(C2Param::CoreIndex paramIndex) const {
     38     std::lock_guard<std::mutex> lock(_mMutex);
     39     auto it = _mStructs.find(paramIndex);
     40     if (it == _mStructs.end()) {
     41         return nullptr;
     42     } else {
     43         return std::make_unique<C2StructDescriptor>(it->second);
     44     }
     45 };
     46 
     47 void C2ReflectorHelper::addStructDescriptor(C2StructDescriptor &&strukt) {
     48     if (_mStructs.find(strukt.coreIndex()) != _mStructs.end()) {
     49         // already added
     50         // TODO: validate that descriptor matches stored descriptor
     51     }
     52     // validate that all struct fields are known to this reflector
     53     for (const C2FieldDescriptor &fd : strukt) {
     54         if (fd.type() & C2FieldDescriptor::STRUCT_FLAG) {
     55             C2Param::CoreIndex coreIndex = fd.type() &~ C2FieldDescriptor::STRUCT_FLAG;
     56             if (_mStructs.find(coreIndex) == _mStructs.end()) {
     57                 C2_LOG(INFO) << "missing struct descriptor #" << coreIndex << " for field "
     58                         << fd.name() << " of struct #" << strukt.coreIndex();
     59             }
     60         }
     61     }
     62     _mStructs.emplace(strukt.coreIndex(), strukt);
     63 }
     64 
     65 
     66 /* ---------------------------- ParamHelper ---------------------------- */
     67 
     68 class C2InterfaceHelper::ParamHelper::Impl {
     69 public:
     70     Impl(ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt)
     71         : mParam(param), mName(name), _mStruct(strukt) { }
     72 
     73     Impl(Impl&&) = default;
     74 
     75     void addDownDependency(C2Param::Index index) {
     76         mDownDependencies.push_back(index);
     77     }
     78 
     79     C2InterfaceHelper::ParamHelper::attrib_t& attrib() {
     80         return mAttrib;
     81     }
     82 
     83     void build() {
     84         // move dependencies into descriptor
     85         mDescriptor = std::make_shared<C2ParamDescriptor>(
     86                 index(), (C2ParamDescriptor::attrib_t)mAttrib,
     87                 std::move(mName), std::move(mDependencies));
     88     }
     89 
     90     void createFieldsAndSupportedValues(const std::shared_ptr<C2ParamReflector> &reflector) {
     91         for (const C2FieldUtils::Info &f :
     92                 C2FieldUtils::enumerateFields(*mDefaultValue, reflector)) {
     93             if (!f.isArithmetic()) {
     94                 continue;
     95             }
     96             std::unique_ptr<C2FieldSupportedValues> fsvPointer;
     97 
     98             // create a breakable structure
     99             do {
    100                 C2FieldSupportedValues fsv;
    101                 switch (f.type()) {
    102                     case C2FieldDescriptor::INT32:  fsv = C2SupportedRange<int32_t>::Any(); break;
    103                     case C2FieldDescriptor::UINT32: fsv = C2SupportedRange<uint32_t>::Any(); break;
    104                     case C2FieldDescriptor::INT64:  fsv = C2SupportedRange<int64_t>::Any(); break;
    105                     case C2FieldDescriptor::UINT64: fsv = C2SupportedRange<uint64_t>::Any(); break;
    106                     case C2FieldDescriptor::FLOAT:  fsv = C2SupportedRange<float>::Any(); break;
    107                     case C2FieldDescriptor::BLOB:   fsv = C2SupportedRange<uint8_t>::Any(); break;
    108                     case C2FieldDescriptor::STRING: fsv = C2SupportedRange<char>::Any(); break;
    109                 default:
    110                     continue; // break out of do {} while
    111                 }
    112                 fsvPointer = std::make_unique<C2FieldSupportedValues>(fsv);
    113             } while (false);
    114 
    115             mFields.emplace_hint(
    116                     mFields.end(),
    117                     _C2FieldId(f.offset(), f.size()),
    118                     std::make_shared<FieldHelper>(
    119                             mParam, _C2FieldId(f.offset(), f.size()), std::move(fsvPointer)));
    120         }
    121     }
    122 
    123     /**
    124      * Finds a field descriptor.
    125      */
    126     std::shared_ptr<FieldHelper> findField(size_t baseOffs, size_t baseSize) const {
    127         auto it = mFields.find(_C2FieldId(baseOffs, baseSize));
    128         if (it == mFields.end()) {
    129             return nullptr;
    130         }
    131         return it->second;
    132     }
    133 
    134     const std::vector<ParamRef> getDependenciesAsRefs() const {
    135         return mDependenciesAsRefs;
    136     }
    137 
    138     std::shared_ptr<const C2ParamDescriptor> getDescriptor() const {
    139         return mDescriptor;
    140     }
    141 
    142     const std::vector<C2Param::Index> getDownDependencies() const {
    143         return mDownDependencies;
    144     }
    145 
    146     C2Param::Index index() const {
    147         if (!mDefaultValue) {
    148             fprintf(stderr, "%s missing default value\n", mName.c_str());
    149         }
    150         return mDefaultValue->index();
    151     }
    152 
    153     C2String name() const {
    154         return mName;
    155     }
    156 
    157     const ParamRef ref() const {
    158         return mParam;
    159     }
    160 
    161     C2StructDescriptor retrieveStructDescriptor() {
    162         return std::move(_mStruct);
    163     }
    164 
    165     void setDefaultValue(std::shared_ptr<C2Param> default_) {
    166         mDefaultValue = default_;
    167     }
    168 
    169     void setDependencies(std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) {
    170         mDependencies = indices;
    171         mDependenciesAsRefs = refs;
    172     }
    173 
    174     void setFields(std::vector<C2ParamFieldValues> &&fields) {
    175         // do not allow adding fields multiple times, or to const values
    176         if (!mFields.empty()) {
    177             C2_LOG(FATAL) << "Trying to add fields to param " << mName << " multiple times";
    178         } else if (mAttrib & attrib_t::IS_CONST) {
    179             C2_LOG(FATAL) << "Trying to add fields to const param " << mName;
    180         }
    181 
    182         for (C2ParamFieldValues &pfv : fields) {
    183             mFields.emplace_hint(
    184                     mFields.end(),
    185                     // _C2FieldId constructor
    186                     _C2ParamInspector::GetField(pfv.paramOrField),
    187                     // Field constructor
    188                     std::make_shared<FieldHelper>(mParam,
    189                                             _C2ParamInspector::GetField(pfv.paramOrField),
    190                                             std::move(pfv.values)));
    191         }
    192     }
    193 
    194     void setGetter(std::function<std::shared_ptr<C2Param>(bool)> getter) {
    195         mGetter = getter;
    196     }
    197 
    198     void setSetter(std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) {
    199         mSetter = setter;
    200     }
    201 
    202     c2_status_t trySet(
    203             const C2Param *value, bool mayBlock, bool *changed, Factory &f,
    204             std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
    205         C2R result = mSetter(value, mayBlock, changed, f);
    206         return result.retrieveFailures(failures);
    207     }
    208 
    209     c2_status_t validate(const std::shared_ptr<C2ParamReflector> &reflector) {
    210         if (!mSetter && mFields.empty()) {
    211             C2_LOG(WARNING) << "Param " << mName << " has no setter, making it const";
    212             // dependencies are empty in this case
    213             mAttrib |= attrib_t::IS_CONST;
    214         } else if (!mSetter) {
    215             C2_LOG(FATAL) << "Param " << mName << " has no setter";
    216         }
    217 
    218         if (mAttrib & attrib_t::IS_CONST) {
    219             createFieldsAndSupportedValues(reflector);
    220         } else {
    221             // TODO: update default based on setter and verify that FSV covers the values
    222         }
    223 
    224         if (mFields.empty()) {
    225             C2_LOG(FATAL) << "Param " << mName << " has no fields";
    226         }
    227 
    228         return C2_OK;
    229     }
    230 
    231     std::shared_ptr<C2Param> value() {
    232         return mParam.get();
    233     }
    234 
    235     std::shared_ptr<const C2Param> value() const {
    236         return mParam.get();
    237     }
    238 
    239 private:
    240     typedef _C2ParamInspector::attrib_t attrib_t;
    241     ParamRef mParam;
    242     C2String mName;
    243     C2StructDescriptor _mStruct;
    244     std::shared_ptr<C2Param> mDefaultValue;
    245     attrib_t mAttrib;
    246     std::function<C2R(const C2Param *, bool, bool *, Factory &)> mSetter;
    247     std::function<std::shared_ptr<C2Param>(bool)> mGetter;
    248     std::vector<C2Param::Index> mDependencies;
    249     std::vector<ParamRef> mDependenciesAsRefs;
    250     std::vector<C2Param::Index> mDownDependencies; // TODO: this does not work for stream dependencies
    251     std::map<_C2FieldId, std::shared_ptr<FieldHelper>> mFields;
    252     std::shared_ptr<C2ParamDescriptor> mDescriptor;
    253 };
    254 
    255 C2InterfaceHelper::ParamHelper::ParamHelper(
    256         ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt)
    257     : mImpl(std::make_unique<C2InterfaceHelper::ParamHelper::Impl>(
    258             param, name, std::move(strukt))) { }
    259 
    260 C2InterfaceHelper::ParamHelper::ParamHelper(C2InterfaceHelper::ParamHelper &&) = default;
    261 
    262 C2InterfaceHelper::ParamHelper::~ParamHelper() = default;
    263 
    264 void C2InterfaceHelper::ParamHelper::addDownDependency(C2Param::Index index) {
    265     return mImpl->addDownDependency(index);
    266 }
    267 
    268 C2InterfaceHelper::ParamHelper::attrib_t& C2InterfaceHelper::ParamHelper::attrib() {
    269     return mImpl->attrib();
    270 }
    271 
    272 std::shared_ptr<C2InterfaceHelper::ParamHelper> C2InterfaceHelper::ParamHelper::build() {
    273     mImpl->build();
    274     return std::make_shared<C2InterfaceHelper::ParamHelper>(std::move(*this));
    275 }
    276 
    277 std::shared_ptr<C2InterfaceHelper::FieldHelper>
    278 C2InterfaceHelper::ParamHelper::findField(size_t baseOffs, size_t baseSize) const {
    279     return mImpl->findField(baseOffs, baseSize);
    280 }
    281 
    282 const std::vector<C2InterfaceHelper::ParamRef>
    283 C2InterfaceHelper::ParamHelper::getDependenciesAsRefs() const {
    284     return mImpl->getDependenciesAsRefs();
    285 }
    286 
    287 std::shared_ptr<const C2ParamDescriptor>
    288 C2InterfaceHelper::ParamHelper::getDescriptor() const {
    289     return mImpl->getDescriptor();
    290 }
    291 
    292 const std::vector<C2Param::Index> C2InterfaceHelper::ParamHelper::getDownDependencies() const {
    293     return mImpl->getDownDependencies();
    294 }
    295 
    296 C2Param::Index C2InterfaceHelper::ParamHelper::index() const {
    297     return mImpl->index();
    298 }
    299 
    300 C2String C2InterfaceHelper::ParamHelper::name() const {
    301     return mImpl->name();
    302 }
    303 
    304 const C2InterfaceHelper::ParamRef C2InterfaceHelper::ParamHelper::ref() const {
    305     return mImpl->ref();
    306 }
    307 
    308 C2StructDescriptor C2InterfaceHelper::ParamHelper::retrieveStructDescriptor() {
    309     return mImpl->retrieveStructDescriptor();
    310 }
    311 
    312 void C2InterfaceHelper::ParamHelper::setDefaultValue(std::shared_ptr<C2Param> default_) {
    313     mImpl->setDefaultValue(default_);
    314 }
    315 
    316 void C2InterfaceHelper::ParamHelper::setDependencies(
    317         std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) {
    318     mImpl->setDependencies(indices, refs);
    319 }
    320 
    321 void C2InterfaceHelper::ParamHelper::setFields(std::vector<C2ParamFieldValues> &&fields) {
    322     return mImpl->setFields(std::move(fields));
    323 }
    324 
    325 void C2InterfaceHelper::ParamHelper::setGetter(
    326         std::function<std::shared_ptr<C2Param>(bool)> getter) {
    327     mImpl->setGetter(getter);
    328 }
    329 
    330 void C2InterfaceHelper::ParamHelper::setSetter(
    331         std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) {
    332     mImpl->setSetter(setter);
    333 }
    334 
    335 c2_status_t C2InterfaceHelper::ParamHelper::trySet(
    336         const C2Param *value, bool mayBlock, bool *changed, Factory &f,
    337         std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
    338     return mImpl->trySet(value, mayBlock, changed, f, failures);
    339 }
    340 
    341 c2_status_t C2InterfaceHelper::ParamHelper::validate(
    342         const std::shared_ptr<C2ParamReflector> &reflector) {
    343     return mImpl->validate(reflector);
    344 }
    345 
    346 std::shared_ptr<C2Param> C2InterfaceHelper::ParamHelper::value() {
    347     return mImpl->value();
    348 }
    349 
    350 std::shared_ptr<const C2Param> C2InterfaceHelper::ParamHelper::value() const {
    351     return mImpl->value();
    352 }
    353 
    354 /* ---------------------------- FieldHelper ---------------------------- */
    355 
    356 C2ParamField C2InterfaceHelper::FieldHelper::makeParamField(C2Param::Index index) const {
    357     return _C2ParamInspector::CreateParamField(index, mFieldId);
    358 }
    359 
    360 C2InterfaceHelper::FieldHelper::FieldHelper(const ParamRef &param, const _C2FieldId &field,
    361             std::unique_ptr<C2FieldSupportedValues> &&values)
    362     : mParam(param),
    363       mFieldId(field),
    364       mPossible(std::move(values)) {
    365     C2_LOG(VERBOSE) << "Creating field helper " << field << " "
    366             << C2FieldSupportedValuesHelper<uint32_t>(*mPossible);
    367 }
    368 
    369 void C2InterfaceHelper::FieldHelper::setSupportedValues(
    370         std::unique_ptr<C2FieldSupportedValues> &&values) {
    371     mSupported = std::move(values);
    372 }
    373 
    374 const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getSupportedValues() const {
    375     return (mSupported ? mSupported : mPossible).get();
    376 }
    377 
    378 const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getPossibleValues() const {
    379     return mPossible.get();
    380 }
    381 
    382 
    383 /* ---------------------------- Field ---------------------------- */
    384 
    385 /**
    386  * Wrapper around field-supported-values builder that gets stored in the
    387  * field helper when the builder goes out of scope.
    388  */
    389 template<typename T>
    390 struct SupportedValuesBuilder : C2ParamFieldValuesBuilder<T> {
    391     SupportedValuesBuilder(
    392             C2ParamField &field, std::shared_ptr<C2InterfaceHelper::FieldHelper> helper)
    393         : C2ParamFieldValuesBuilder<T>(field), _mHelper(helper), _mField(field) {
    394     }
    395 
    396     /**
    397      * Save builder values on destruction.
    398      */
    399     virtual ~SupportedValuesBuilder() override {
    400         _mHelper->setSupportedValues(std::move(C2ParamFieldValues(*this).values));
    401     }
    402 
    403 private:
    404     std::shared_ptr<C2InterfaceHelper::FieldHelper> _mHelper;
    405     C2ParamField _mField;
    406 };
    407 
    408 
    409 template<typename T>
    410 C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::shouldBe() const {
    411     return C2ParamFieldValuesBuilder<T>(_mField);
    412 }
    413 
    414 template<typename T>
    415 C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::mustBe() {
    416     return SupportedValuesBuilder<T>(_mField, _mHelper);
    417 }
    418 
    419 /*
    420 template<typename T> C2SettingResultsBuilder C2InterfaceHelper::Field<T>::validatePossible(T &value)
    421 const {
    422     /// TODO
    423     return C2SettingResultsBuilder::Ok();
    424 }
    425 */
    426 
    427 template<typename T>
    428 C2InterfaceHelper::Field<T>::Field(std::shared_ptr<FieldHelper> helper, C2Param::Index index)
    429     : _mHelper(helper), _mField(helper->makeParamField(index)) { }
    430 
    431 template struct C2InterfaceHelper::Field<uint8_t>;
    432 template struct C2InterfaceHelper::Field<char>;
    433 template struct C2InterfaceHelper::Field<int32_t>;
    434 template struct C2InterfaceHelper::Field<uint32_t>;
    435 //template struct C2InterfaceHelper::Field<c2_cntr32_t>;
    436 template struct C2InterfaceHelper::Field<int64_t>;
    437 template struct C2InterfaceHelper::Field<uint64_t>;
    438 //template struct C2InterfaceHelper::Field<c2_cntr64_t>;
    439 template struct C2InterfaceHelper::Field<float>;
    440 
    441 /* --------------------------------- Factory --------------------------------- */
    442 
    443 struct C2InterfaceHelper::FactoryImpl : public C2InterfaceHelper::Factory {
    444     virtual std::shared_ptr<C2ParamReflector> getReflector() const override {
    445         return _mReflector;
    446     }
    447 
    448     virtual std::shared_ptr<ParamHelper>
    449     getParamHelper(const ParamRef &param) const override {
    450         return _mParams.find(param)->second;
    451     }
    452 
    453 public:
    454     FactoryImpl(std::shared_ptr<C2ParamReflector> reflector)
    455         : _mReflector(reflector) { }
    456 
    457     virtual ~FactoryImpl() = default;
    458 
    459     void addParam(std::shared_ptr<ParamHelper> param) {
    460         _mParams.insert({ param->ref(), param });
    461         _mIndexToHelper.insert({param->index(), param});
    462 
    463         // add down-dependencies (and validate dependencies as a result)
    464         size_t ix = 0;
    465         for (const ParamRef &ref : param->getDependenciesAsRefs()) {
    466             // dependencies must already be defined
    467             if (!_mParams.count(ref)) {
    468                 C2_LOG(FATAL) << "Parameter " << param->name() << " has a dependency at index "
    469                         << ix << " that is not yet defined";
    470             }
    471             _mParams.find(ref)->second->addDownDependency(param->index());
    472             ++ix;
    473         }
    474 
    475         _mDependencyIndex.emplace(param->index(), _mDependencyIndex.size());
    476     }
    477 
    478     std::shared_ptr<ParamHelper> getParam(C2Param::Index ix) const {
    479         // TODO: handle streams separately
    480         const auto it = _mIndexToHelper.find(ix);
    481         if (it == _mIndexToHelper.end()) {
    482             return nullptr;
    483         }
    484         return it->second;
    485     }
    486 
    487     /**
    488      * TODO: this could return a copy using proper pointer cast.
    489      */
    490     std::shared_ptr<C2Param> getParamValue(C2Param::Index ix) const {
    491         std::shared_ptr<ParamHelper> helper = getParam(ix);
    492         return helper ? helper->value() : nullptr;
    493     }
    494 
    495     c2_status_t querySupportedParams(
    496             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
    497         for (const auto &it : _mParams) {
    498             // TODO: change querySupportedParams signature?
    499             params->push_back(
    500                     std::const_pointer_cast<C2ParamDescriptor>(it.second->getDescriptor()));
    501         }
    502         // TODO: handle errors
    503         return C2_OK;
    504     }
    505 
    506     size_t getDependencyIndex(C2Param::Index ix) {
    507         // in this version of the helper there is only a single stream so
    508         // we can look up directly by index
    509         auto it = _mDependencyIndex.find(ix);
    510         return it == _mDependencyIndex.end() ? SIZE_MAX : it->second;
    511     }
    512 
    513 private:
    514     std::map<ParamRef, std::shared_ptr<ParamHelper>> _mParams;
    515     std::map<C2Param::Index, std::shared_ptr<ParamHelper>> _mIndexToHelper;
    516     std::shared_ptr<C2ParamReflector> _mReflector;
    517     std::map<C2Param::Index, size_t> _mDependencyIndex;
    518 };
    519 
    520 /* --------------------------------- Helper --------------------------------- */
    521 
    522 namespace {
    523 
    524 static std::string asString(C2Param *p) {
    525     char addr[20];
    526     sprintf(addr, "%p:[", p);
    527     std::string v = addr;
    528     for (size_t i = 0; i < p->size(); ++i) {
    529         char d[4];
    530         sprintf(d, " %02x", *(((uint8_t *)p) + i));
    531         v += d + (i == 0);
    532     }
    533     return v + "]";
    534 }
    535 
    536 }
    537 
    538 C2InterfaceHelper::C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector)
    539     : mReflector(reflector),
    540       _mFactory(std::make_shared<FactoryImpl>(reflector)) { }
    541 
    542 
    543 size_t C2InterfaceHelper::GetBaseOffset(const std::shared_ptr<C2ParamReflector> &reflector,
    544         C2Param::CoreIndex index, size_t offset) {
    545     std::unique_ptr<C2StructDescriptor> param = reflector->describe(index);
    546     if (param == nullptr) {
    547         return ~(size_t)0; // param structure not described
    548     }
    549 
    550     for (const C2FieldDescriptor &field : *param) {
    551         size_t fieldOffset = _C2ParamInspector::GetOffset(field);
    552         size_t fieldSize = _C2ParamInspector::GetSize(field);
    553         size_t fieldExtent = field.extent();
    554         if (offset < fieldOffset) {
    555             return ~(size_t)0; // not found
    556         }
    557         if (offset == fieldOffset) {
    558             // exact match
    559             return offset;
    560         }
    561         if (field.extent() == 0 || offset < fieldOffset + fieldSize * fieldExtent) {
    562             // reduce to first element in case of array
    563             offset = fieldOffset + (offset - fieldOffset) % fieldSize;
    564             if (field.type() >= C2FieldDescriptor::STRUCT_FLAG) {
    565                 // this offset is within a field
    566                 offset = GetBaseOffset(
    567                         reflector, field.type() & ~C2FieldDescriptor::STRUCT_FLAG,
    568                         offset - fieldOffset);
    569                 return ~offset ? fieldOffset + offset : offset;
    570             }
    571         }
    572     }
    573     return ~(size_t)0; // not found
    574 }
    575 
    576 void C2InterfaceHelper::addParameter(std::shared_ptr<ParamHelper> param) {
    577     mReflector->addStructDescriptor(param->retrieveStructDescriptor());
    578     c2_status_t err = param->validate(mReflector);
    579     if (err != C2_CORRUPTED) {
    580         _mFactory->addParam(param);
    581     }
    582 }
    583 
    584 c2_status_t C2InterfaceHelper::config(
    585        const std::vector<C2Param*> &params, c2_blocking_t mayBlock,
    586        std::vector<std::unique_ptr<C2SettingResult>>* const failures, bool updateParams,
    587        std::vector<std::shared_ptr<C2Param>> *changes __unused /* TODO */) {
    588     bool paramWasInvalid = false; // TODO is this the same as bad value?
    589     bool paramNotFound = false;
    590     bool paramBadValue = false;
    591     bool paramNoMemory = false;
    592     bool paramBlocking = false;
    593     bool paramTimedOut = false;
    594     bool paramCorrupted = false;
    595 
    596     // dependencies
    597     // down dependencies are marked dirty, but params set are not immediately
    598     // marked dirty (unless they become down dependency) so that we can
    599     // avoid setting them if they did not change
    600 
    601     // TODO: there could be multiple indices for the same dependency index
    602     // { depIx, paramIx } may be a suitable key
    603     std::map<size_t, std::pair<C2Param::Index, bool>> dependencies;
    604 
    605     // we cannot determine the last valid parameter, so add an extra
    606     // loop iteration after the last parameter
    607     for (size_t p_ix = 0; p_ix <= params.size(); ++p_ix) {
    608         C2Param *p = nullptr;
    609         C2Param::Index paramIx = 0u;
    610         size_t paramDepIx = SIZE_MAX;
    611         bool last = p_ix == params.size();
    612         if (!last) {
    613             p = params[p_ix];
    614             if (!*p) {
    615                 paramWasInvalid = true;
    616                 p->invalidate();
    617                 continue;
    618             }
    619 
    620             paramIx = p->index();
    621             paramDepIx = getDependencyIndex(paramIx);
    622             if (paramDepIx == SIZE_MAX) {
    623                 // unsupported parameter
    624                 paramNotFound = true;
    625                 continue;
    626             }
    627 
    628             //
    629             // first insert - mark not dirty
    630             // it may have been marked dirty by a dependency update
    631             // this does not overrwrite(!)
    632             (void)dependencies.insert({ paramDepIx, { paramIx, false /* dirty */ }});
    633             auto it = dependencies.find(paramDepIx);
    634             C2_LOG(VERBOSE) << "marking dependency for setting at #" << paramDepIx << ": "
    635                     << it->second.first << ", update "
    636                     << (it->second.second ? "always (dirty)" : "only if changed");
    637         } else {
    638             // process any remaining dependencies
    639             if (dependencies.empty()) {
    640                 continue;
    641             }
    642             C2_LOG(VERBOSE) << "handling dirty down dependencies after last setting";
    643         }
    644 
    645         // process any dirtied down-dependencies until the next param
    646         while (dependencies.size() && dependencies.begin()->first <= paramDepIx) {
    647             auto min = dependencies.begin();
    648             C2Param::Index ix = min->second.first;
    649             bool dirty = min->second.second;
    650             dependencies.erase(min);
    651 
    652             std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix);
    653             C2_LOG(VERBOSE) << "old value " << asString(param->value().get());
    654             if (!last) {
    655                 C2_LOG(VERBOSE) << "new value " << asString(p);
    656             }
    657             if (!last && !dirty && ix == paramIx && *param->value() == *p) {
    658                 // no change in value - and dependencies were not updated
    659                 // no need to update
    660                 C2_LOG(VERBOSE) << "ignoring setting unchanged param " << ix;
    661                 continue;
    662             }
    663 
    664             // apply setting
    665             bool changed = false;
    666             C2_LOG(VERBOSE) << "setting param " << ix;
    667             std::shared_ptr<C2Param> oldValue = param->value();
    668             c2_status_t res = param->trySet(
    669                     (!last && paramIx == ix) ? p : param->value().get(), mayBlock,
    670                     &changed, *_mFactory, failures);
    671             std::shared_ptr<C2Param> newValue = param->value();
    672             C2_CHECK_EQ(oldValue == newValue, *oldValue == *newValue);
    673             switch (res) {
    674                 case C2_OK: break;
    675                 case C2_BAD_VALUE: paramBadValue = true; break;
    676                 case C2_NO_MEMORY: paramNoMemory = true; break;
    677                 case C2_TIMED_OUT: paramTimedOut = true; break;
    678                 case C2_BLOCKING:  paramBlocking = true; break;
    679                 case C2_CORRUPTED: paramCorrupted = true; break;
    680                 default: ;// TODO fatal
    681             }
    682 
    683             // copy back result for configured values (or invalidate if it does not fit or match)
    684             if (updateParams && !last && paramIx == ix) {
    685                 if (!p->updateFrom(*param->value())) {
    686                     p->invalidate();
    687                 }
    688             }
    689 
    690             // compare ptrs as params are copy on write
    691             if (changed) {
    692                 C2_LOG(VERBOSE) << "param " << ix << " value changed";
    693                 // value changed update down-dependencies and mark them dirty
    694                 for (const C2Param::Index ix : param->getDownDependencies()) {
    695                     C2_LOG(VERBOSE) << 1;
    696                     auto insert_res = dependencies.insert(
    697                             { getDependencyIndex(ix), { ix, true /* dirty */ }});
    698                     if (!insert_res.second) {
    699                         (*insert_res.first).second.second = true; // mark dirty
    700                     }
    701 
    702                     auto it = dependencies.find(getDependencyIndex(ix));
    703                     C2_CHECK(it->second.second);
    704                     C2_LOG(VERBOSE) << "marking down dependencies to update at #"
    705                             << getDependencyIndex(ix) << ": " << it->second.first;
    706                 }
    707             }
    708         }
    709     }
    710 
    711     return (paramCorrupted ? C2_CORRUPTED :
    712             paramBlocking ? C2_BLOCKING :
    713             paramTimedOut ? C2_TIMED_OUT :
    714             paramNoMemory ? C2_NO_MEMORY :
    715             (paramBadValue || paramWasInvalid) ? C2_BAD_VALUE :
    716             paramNotFound ? C2_BAD_INDEX : C2_OK);
    717 }
    718 
    719 size_t C2InterfaceHelper::getDependencyIndex(C2Param::Index ix) const {
    720     return _mFactory->getDependencyIndex(ix);
    721 }
    722 
    723 c2_status_t C2InterfaceHelper::query(
    724         const std::vector<C2Param*> &stackParams,
    725         const std::vector<C2Param::Index> &heapParamIndices,
    726         c2_blocking_t mayBlock __unused /* TODO */,
    727         std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
    728     bool paramWasInvalid = false;
    729     bool paramNotFound = false;
    730     bool paramDidNotFit = false;
    731     bool paramNoMemory = false;
    732 
    733     for (C2Param* const p : stackParams) {
    734         if (!*p) {
    735             paramWasInvalid = true;
    736             p->invalidate();
    737         } else {
    738             std::shared_ptr<C2Param> value = _mFactory->getParamValue(p->index());
    739             if (!value) {
    740                 paramNotFound = true;
    741                 p->invalidate();
    742             } else if (!p->updateFrom(*value)) {
    743                 paramDidNotFit = true;
    744                 p->invalidate();
    745             }
    746         }
    747     }
    748 
    749     for (const C2Param::Index ix : heapParamIndices) {
    750         std::shared_ptr<C2Param> value = _mFactory->getParamValue(ix);
    751         if (value) {
    752             std::unique_ptr<C2Param> p = C2Param::Copy(*value);
    753             if (p != nullptr) {
    754                 heapParams->push_back(std::move(p));
    755             } else {
    756                 paramNoMemory = true;
    757             }
    758         } else {
    759             paramNotFound = true;
    760         }
    761     }
    762 
    763     return paramNoMemory ? C2_NO_MEMORY :
    764            paramNotFound ? C2_BAD_INDEX :
    765            // the following errors are not marked in the return value
    766            paramDidNotFit ? C2_OK :
    767            paramWasInvalid ? C2_OK : C2_OK;
    768 }
    769 
    770 c2_status_t C2InterfaceHelper::querySupportedParams(
    771         std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
    772     return _mFactory->querySupportedParams(params);
    773 }
    774 
    775 
    776 c2_status_t C2InterfaceHelper::querySupportedValues(
    777         std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock __unused) const {
    778     for (C2FieldSupportedValuesQuery &query : fields) {
    779         C2_LOG(VERBOSE) << "querying field " << query.field();
    780         C2Param::Index ix = _C2ParamInspector::GetIndex(query.field());
    781         std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix);
    782         if (!param) {
    783             C2_LOG(VERBOSE) << "bad param";
    784             query.status = C2_BAD_INDEX;
    785             continue;
    786         }
    787         size_t offs = GetBaseOffset(
    788                 mReflector, ix,
    789                 _C2ParamInspector::GetOffset(query.field()) - sizeof(C2Param));
    790         if (~offs == 0) {
    791             C2_LOG(VERBOSE) << "field could not be found";
    792             query.status = C2_NOT_FOUND;
    793             continue;
    794         }
    795         offs += sizeof(C2Param);
    796         C2_LOG(VERBOSE) << "field resolved to "
    797                 << StringPrintf("@%02zx+%02x", offs, _C2ParamInspector::GetSize(query.field()));
    798         std::shared_ptr<FieldHelper> field =
    799             param->findField(offs, _C2ParamInspector::GetSize(query.field()));
    800         if (!field) {
    801             C2_LOG(VERBOSE) << "bad field";
    802             query.status = C2_NOT_FOUND;
    803             continue;
    804         }
    805 
    806         const C2FieldSupportedValues *values = nullptr;
    807         switch (query.type()) {
    808         case C2FieldSupportedValuesQuery::CURRENT:
    809             values = field->getSupportedValues();
    810             break;
    811         case C2FieldSupportedValuesQuery::POSSIBLE:
    812             values = field->getPossibleValues();
    813             break;
    814         default:
    815             C2_LOG(VERBOSE) << "bad query type: " << query.type();
    816             query.status = C2_BAD_VALUE;
    817         }
    818         if (values) {
    819             query.values = *values;
    820             query.status = C2_OK;
    821         } else {
    822             C2_LOG(DEBUG) << "no values published by component";
    823             query.status = C2_CORRUPTED;
    824         }
    825     }
    826     return C2_OK;
    827 }
    828