diff options
-rw-r--r-- | src/core/kconfig.cpp | 56 | ||||
-rw-r--r-- | src/core/kconfigdata_p.h | 30 |
2 files changed, 52 insertions, 34 deletions
diff --git a/src/core/kconfig.cpp b/src/core/kconfig.cpp index 4bbceeda..9e62c167 100644 --- a/src/core/kconfig.cpp +++ b/src/core/kconfig.cpp @@ -130,10 +130,16 @@ bool KConfigPrivate::lockLocal() return true; } +static bool isGroupOrSubGroupMatch(KEntryMapConstIterator entryMapIt, const QByteArray &group) +{ + const QByteArray &entryGroup = entryMapIt.key().mGroup; + Q_ASSERT_X(entryGroup.startsWith(group), Q_FUNC_INFO, "Precondition"); + return entryGroup.size() == group.size() || entryGroup[group.size()] == '\x1d'; +} + void KConfigPrivate::copyGroup(const QByteArray &source, const QByteArray &destination, KConfigGroup *otherGroup, KConfigBase::WriteConfigFlags flags) const { KEntryMap &otherMap = otherGroup->config()->d_ptr->entryMap; - const int len = source.length(); const bool sameName = (destination == source); // we keep this bool outside the for loop so that if @@ -141,16 +147,10 @@ void KConfigPrivate::copyGroup(const QByteArray &source, const QByteArray &desti // as dirty erroneously bool dirtied = false; - for (auto entryMapIt = entryMap.cbegin(); entryMapIt != entryMap.cend(); ++entryMapIt) { - const QByteArray &group = entryMapIt.key().mGroup; - - if (!group.startsWith(source)) { // nothing to do - continue; - } - + entryMap.forEachEntryWhoseGroupStartsWith(source, [&source, &destination, flags, &otherMap, sameName, &dirtied](KEntryMapConstIterator entryMapIt) { // don't copy groups that start with the same prefix, but are not sub-groups - if (group.length() > len && group[len] != '\x1d') { - continue; + if (!isGroupOrSubGroupMatch(entryMapIt, source)) { + return; } KEntryKey newKey = entryMapIt.key(); @@ -160,7 +160,7 @@ void KConfigPrivate::copyGroup(const QByteArray &source, const QByteArray &desti } if (!sameName) { - newKey.mGroup.replace(0, len, destination); + newKey.mGroup.replace(0, source.size(), destination); } KEntry entry = entryMapIt.value(); @@ -175,7 +175,7 @@ void KConfigPrivate::copyGroup(const QByteArray &source, const QByteArray &desti } otherMap[newKey] = entry; - } + }); if (dirtied) { otherGroup->config()->d_ptr->bDirty = true; @@ -318,50 +318,38 @@ QStringList KConfigPrivate::groupList(const QByteArray &group) const const QByteArray theGroup = group + '\x1d'; ByteArrayViewSet groups; - for (auto entryMapIt = entryMap.cbegin(); entryMapIt != entryMap.cend(); ++entryMapIt) { + entryMap.forEachEntryWhoseGroupStartsWith(theGroup, [&theGroup, &groups](KEntryMapConstIterator entryMapIt) { const KEntryKey &key = entryMapIt.key(); - if (!key.mKey.isNull() && !entryMapIt->bDeleted && key.mGroup.startsWith(theGroup)) { + if (!key.mKey.isNull() && !entryMapIt->bDeleted) { const auto subgroupStartPos = theGroup.size(); const auto subgroupEndPos = findFirstGroupEndPos(key.mGroup, subgroupStartPos); groups.emplace(key.mGroup.constData() + subgroupStartPos, subgroupEndPos - subgroupStartPos); } - } + }); return stringListFromUtf8Collection(groups); } -static bool isGroupOrSubGroupMatch(const QByteArray &potentialGroup, const QByteArray &group) -{ - if (!potentialGroup.startsWith(group)) { - return false; - } - return potentialGroup.length() == group.length() || potentialGroup[group.length()] == '\x1d'; -} - /// Returns @p parentGroup itself, all its subgroups, subsubgroups, and so on, including deleted groups. QSet<QByteArray> KConfigPrivate::allSubGroups(const QByteArray &parentGroup) const { QSet<QByteArray> groups; - for (KEntryMap::const_iterator entryMapIt = entryMap.begin(); entryMapIt != entryMap.end(); ++entryMapIt) { + entryMap.forEachEntryWhoseGroupStartsWith(parentGroup, [&parentGroup, &groups](KEntryMapConstIterator entryMapIt) { const KEntryKey &key = entryMapIt.key(); - if (key.mKey.isNull() && isGroupOrSubGroupMatch(key.mGroup, parentGroup)) { + if (key.mKey.isNull() && isGroupOrSubGroupMatch(entryMapIt, parentGroup)) { groups << key.mGroup; } - } + }); + return groups; } bool KConfigPrivate::hasNonDeletedEntries(const QByteArray &group) const { - for (KEntryMap::const_iterator it = entryMap.begin(); it != entryMap.end(); ++it) { - const KEntryKey &key = it.key(); - // Check for any non-deleted entry - if (isGroupOrSubGroupMatch(key.mGroup, group) && !key.mKey.isNull() && !it->bDeleted) { - return true; - } - } - return false; + return entryMap.anyEntryWhoseGroupStartsWith(group, [&group](KEntryMapConstIterator entryMapIt) { + return isGroupOrSubGroupMatch(entryMapIt, group) && !entryMapIt.key().mKey.isNull() && !entryMapIt->bDeleted; + }); } QStringList KConfigPrivate::keyListImpl(const QByteArray &theGroup) const diff --git a/src/core/kconfigdata_p.h b/src/core/kconfigdata_p.h index 5e5246f3..beb18f45 100644 --- a/src/core/kconfigdata_p.h +++ b/src/core/kconfigdata_p.h @@ -155,6 +155,17 @@ inline bool operator<(const KEntryKey &k1, const KEntryKey &k2) return (!k1.bDefault && k2.bDefault); } +/** + * Returns the minimum key that has @a mGroup == @p group. + * + * @note The returned "minimum key" is consistent with KEntryKey's operator<(). + * The return value of this function can be passed to KEntryMap::lowerBound(). + */ +inline KEntryKey minimumGroupKey(const QByteArray &group) +{ + return KEntryKey(group, QByteArray{}, true, false); +} + QDebug operator<<(QDebug dbg, const KEntryKey &key); QDebug operator<<(QDebug dbg, const KEntry &entry); @@ -230,6 +241,25 @@ public: } bool revertEntry(const QByteArray &group, const QByteArray &key, EntryOptions options, SearchFlags flags = SearchFlags()); + + template<typename ConstIteratorUser> + void forEachEntryWhoseGroupStartsWith(const QByteArray &groupPrefix, ConstIteratorUser callback) const + { + for (auto it = lowerBound(minimumGroupKey(groupPrefix)), end = cend(); it != end && it.key().mGroup.startsWith(groupPrefix); ++it) { + callback(it); + } + } + + template<typename ConstIteratorPredicate> + bool anyEntryWhoseGroupStartsWith(const QByteArray &groupPrefix, ConstIteratorPredicate predicate) const + { + for (auto it = lowerBound(minimumGroupKey(groupPrefix)), end = cend(); it != end && it.key().mGroup.startsWith(groupPrefix); ++it) { + if (predicate(it)) { + return true; + } + } + return false; + } }; Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions) |