diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index 4a6adb98a1..80b6239039 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -203,6 +203,7 @@ $(Pstreams)/PstreamBuffers.C dictionary = db/dictionary $(dictionary)/dictionary.C $(dictionary)/dictionaryIO.C +$(dictionary)/dictionarySearch.C entry = $(dictionary)/entry $(entry)/entry.C diff --git a/src/OpenFOAM/db/dictionary/dictionary.C b/src/OpenFOAM/db/dictionary/dictionary.C index 33acac0ace..46cee88d67 100644 --- a/src/OpenFOAM/db/dictionary/dictionary.C +++ b/src/OpenFOAM/db/dictionary/dictionary.C @@ -45,157 +45,6 @@ bool Foam::dictionary::writeOptionalEntries ); -// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // - -namespace Foam -{ - // file-scope - //- Walk lists of patterns and regexps for an exact match - // or regular expression match - template - static bool findInPatterns - ( - const bool patternMatch, - const word& keyword, - WcIterator& wcIter, - ReIterator& reIter - ) - { - while (wcIter.found()) - { - if - ( - patternMatch - ? reIter()->match(keyword) - : wcIter()->keyword() == keyword - ) - { - return true; - } - - ++reIter; - ++wcIter; - } - - return false; - } -} - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr -( - const word& keyword, - bool recursive, - bool patternMatch -) const -{ - string::size_type dotPos = keyword.find('.'); - - if (dotPos == string::npos) - { - // Non-scoped lookup - return lookupEntryPtr(keyword, recursive, patternMatch); - } - else if (dotPos == 0) - { - // Starting with a '.' -> go up for every further '.' found - ++dotPos; - - const dictionary* dictPtr = this; - for - ( - string::const_iterator it = keyword.begin()+1; - it != keyword.end() && *it == '.'; - ++dotPos, ++it - ) - { - // Go to parent - if (&dictPtr->parent_ != &dictionary::null) - { - dictPtr = &dictPtr->parent_; - } - else - { - FatalIOErrorInFunction - ( - *this - ) << "No parent of current dictionary when searching for " - << keyword.substr(1) - << exit(FatalIOError); - - return nullptr; - } - } - - return dictPtr->lookupScopedSubEntryPtr - ( - keyword.substr(dotPos), - false, - patternMatch - ); - } - else - { - // The first word - const entry* entPtr = lookupScopedSubEntryPtr - ( - keyword.substr(0, dotPos), - false, - patternMatch - ); - - if (!entPtr) - { - // Fall back to finding key with '.' so e.g. if keyword is - // a.b.c.d it would try - // a.b, a.b.c, a.b.c.d - - while (true) - { - dotPos = keyword.find('.', dotPos+1); - - entPtr = lookupEntryPtr - ( - keyword.substr(0, dotPos), - false, - patternMatch - ); - - if (dotPos == string::npos) - { - // Parsed the whole word. Return entry or null. - return entPtr; - } - - if (entPtr && entPtr->isDict()) - { - return entPtr->dict().lookupScopedSubEntryPtr - ( - keyword.substr(dotPos), - false, - patternMatch - ); - } - } - } - - if (entPtr->isDict()) - { - return entPtr->dict().lookupScopedSubEntryPtr - ( - keyword.substr(dotPos), - false, - patternMatch - ); - } - } - - return nullptr; -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::dictionary::dictionary() @@ -395,29 +244,7 @@ bool Foam::dictionary::found bool patternMatch ) const { - if (hashedEntries_.found(keyword)) - { - return true; - } - - if (patternMatch && patterns_.size()) - { - pattern_const_iterator wcLink = patterns_.begin(); - regexp_const_iterator reLink = regexps_.begin(); - - // Find in patterns using regular expressions only - if (findInPatterns(patternMatch, keyword, wcLink, reLink)) - { - return true; - } - } - - if (recursive && &parent_ != &dictionary::null) - { - return parent_.found(keyword, recursive, patternMatch); - } - - return false; + return csearch(keyword, recursive, patternMatch).found(); } @@ -428,31 +255,7 @@ const Foam::entry* Foam::dictionary::lookupEntryPtr bool patternMatch ) const { - auto iter = hashedEntries_.cfind(keyword); - - if (iter.found()) - { - return iter(); - } - - if (patternMatch && patterns_.size()) - { - pattern_const_iterator wcLink = patterns_.begin(); - regexp_const_iterator reLink = regexps_.begin(); - - // Find in patterns using regular expressions only - if (findInPatterns(patternMatch, keyword, wcLink, reLink)) - { - return wcLink(); - } - } - - if (recursive && &parent_ != &dictionary::null) - { - return parent_.lookupEntryPtr(keyword, recursive, patternMatch); - } - - return nullptr; + return csearch(keyword, recursive, patternMatch).ptr(); } @@ -463,36 +266,7 @@ Foam::entry* Foam::dictionary::lookupEntryPtr bool patternMatch ) { - auto iter = hashedEntries_.find(keyword); - - if (iter.found()) - { - return iter(); - } - - if (patternMatch && patterns_.size()) - { - pattern_iterator wcLink = patterns_.begin(); - regexp_iterator reLink = regexps_.begin(); - - // Find in patterns using regular expressions only - if (findInPatterns(patternMatch, keyword, wcLink, reLink)) - { - return wcLink(); - } - } - - if (recursive && &parent_ != &dictionary::null) - { - return const_cast(parent_).lookupEntryPtr - ( - keyword, - recursive, - patternMatch - ); - } - - return nullptr; + return search(keyword, recursive, patternMatch).ptr(); } @@ -503,9 +277,9 @@ const Foam::entry& Foam::dictionary::lookupEntry bool patternMatch ) const { - const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch); + auto finder = csearch(keyword, recursive, patternMatch); - if (entryPtr == nullptr) + if (!finder.found()) { FatalIOErrorInFunction ( @@ -515,7 +289,7 @@ const Foam::entry& Foam::dictionary::lookupEntry << exit(FatalIOError); } - return *entryPtr; + return finder.ref(); } @@ -537,29 +311,37 @@ const Foam::entry* Foam::dictionary::lookupScopedEntryPtr bool patternMatch ) const { - if ((keyword[0] == ':' || keyword[0] == '^')) - { - // Go up to top level - const dictionary* dictPtr = this; - while (&dictPtr->parent_ != &dictionary::null) - { - dictPtr = &dictPtr->parent_; - } + return csearchScoped(keyword, recursive, patternMatch).ptr(); +} - return dictPtr->lookupScopedSubEntryPtr - ( - keyword.substr(1), - false, - patternMatch - ); + +bool Foam::dictionary::substituteKeyword(const word& keyword, bool mergeEntry) +{ + if (keyword.size() < 2) + { + return false; } - return lookupScopedSubEntryPtr - ( - keyword, - recursive, - patternMatch - ); + // Drop leading '$' to get the var-name, already validated as word. + const word varName(keyword.substr(1), false); + + // Lookup the variable name in the given dictionary + const_searcher finder = csearch(varName, true, true); + + // If defined insert its entries into this dictionary + if (finder.found()) + { + const dictionary& addDict = finder.dict(); + + forAllConstIters(addDict, iter) + { + add(iter(), mergeEntry); + } + + return true; + } + + return false; } @@ -569,16 +351,21 @@ bool Foam::dictionary::substituteScopedKeyword bool mergeEntry ) { - // Drop first character of keyword to get the var-name, already validated. + if (keyword.size() < 2) + { + return false; + } + + // Drop leading '$' to get the var-name, already validated as word. const word varName(keyword.substr(1), false); // Lookup the variable name in the given dictionary - const entry* ePtr = lookupScopedEntryPtr(varName, true, true); + const_searcher finder = csearchScoped(varName, true, true); // If defined insert its entries into this dictionary - if (ePtr != nullptr) + if (finder.found()) { - const dictionary& addDict = ePtr->dict(); + const dictionary& addDict = finder.dict(); forAllConstIter(parent_type, addDict, iter) { @@ -595,54 +382,30 @@ bool Foam::dictionary::substituteScopedKeyword bool Foam::dictionary::isDict(const word& keyword) const { // Find non-recursive with patterns - const entry* entryPtr = lookupEntryPtr(keyword, false, true); - - if (entryPtr) - { - return entryPtr->isDict(); - } - else - { - return false; - } + return csearch(keyword, false, true).isDict(); } const Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword) const { - const entry* entryPtr = lookupEntryPtr(keyword, false, true); - - if (entryPtr) - { - return &entryPtr->dict(); - } - else - { - return nullptr; - } + // Find non-recursive with patterns + return csearch(keyword, false, true).dictPtr(); } Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword) { - entry* entryPtr = lookupEntryPtr(keyword, false, true); - - if (entryPtr) - { - return &entryPtr->dict(); - } - else - { - return nullptr; - } + // Find non-recursive with patterns + return search(keyword, false, true).dictPtr(); } const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const { - const entry* entryPtr = lookupEntryPtr(keyword, false, true); + // Find non-recursive with patterns + auto finder = csearch(keyword, false, true); - if (entryPtr == nullptr) + if (!finder.found()) { FatalIOErrorInFunction ( @@ -651,15 +414,17 @@ const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const << name() << exit(FatalIOError); } - return entryPtr->dict(); + + return finder.dict(); } Foam::dictionary& Foam::dictionary::subDict(const word& keyword) { - entry* entryPtr = lookupEntryPtr(keyword, false, true); + // Find non-recursive with patterns + auto finder = search(keyword, false, true); - if (entryPtr == nullptr) + if (!finder.found()) { FatalIOErrorInFunction ( @@ -668,7 +433,8 @@ Foam::dictionary& Foam::dictionary::subDict(const word& keyword) << name() << exit(FatalIOError); } - return entryPtr->dict(); + + return finder.dict(); } @@ -678,29 +444,35 @@ Foam::dictionary Foam::dictionary::subOrEmptyDict const bool mustRead ) const { - const entry* entryPtr = lookupEntryPtr(keyword, false, true); + // Find non-recursive with patterns + auto finder = csearch(keyword, false, true); - if (entryPtr == nullptr) + if (finder.isDict()) { - if (mustRead) - { - FatalIOErrorInFunction - ( - *this - ) << "keyword " << keyword << " is undefined in dictionary " - << name() - << exit(FatalIOError); - return entryPtr->dict(); - } - else - { - return dictionary(*this, dictionary(name() + '.' + keyword)); - } + // Found and a sub-dictionary + return finder.dict(); } - else + + if (mustRead) { - return entryPtr->dict(); + FatalIOErrorInFunction + ( + *this + ) << "keyword " << keyword + << " is not a sub-dictionary in dictionary " + << name() + << exit(FatalIOError); } + + if (finder.found()) + { + IOWarningInFunction((*this)) + << "keyword " << keyword + << " found but not a sub-dictionary in dictionary " + << name() << endl; + } + + return dictionary(*this, dictionary(name() + '.' + keyword)); } @@ -709,16 +481,23 @@ const Foam::dictionary& Foam::dictionary::optionalSubDict const word& keyword ) const { - const entry* entryPtr = lookupEntryPtr(keyword, false, true); + auto finder = csearch(keyword, false, true); - if (entryPtr) + if (finder.isDict()) { - return entryPtr->dict(); + // Found and a sub-dictionary + return finder.dict(); } - else + + if (finder.found()) { - return *this; + IOWarningInFunction((*this)) + << "keyword " << keyword + << " found but not a sub-dictionary in dictionary " + << name() << endl; } + + return *this; } @@ -726,10 +505,10 @@ Foam::wordList Foam::dictionary::toc() const { wordList keys(size()); - label nKeys = 0; - forAllConstIter(parent_type, *this, iter) + label n = 0; + forAllConstIters(*this, iter) { - keys[nKeys++] = iter().keyword(); + keys[n++] = iter().keyword(); } return keys; @@ -746,15 +525,15 @@ Foam::List Foam::dictionary::keys(bool patterns) const { List keys(size()); - label nKeys = 0; - forAllConstIter(parent_type, *this, iter) + label n = 0; + forAllConstIters(*this, iter) { if (iter().keyword().isPattern() ? patterns : !patterns) { - keys[nKeys++] = iter().keyword(); + keys[n++] = iter().keyword(); } } - keys.setSize(nKeys); + keys.setSize(n); return keys; } @@ -844,55 +623,55 @@ void Foam::dictionary::add(const entry& e, bool mergeEntry) } -void Foam::dictionary::add(const keyType& k, const word& w, bool overwrite) +void Foam::dictionary::add(const keyType& k, const word& v, bool overwrite) { - add(new primitiveEntry(k, token(w)), overwrite); + add(new primitiveEntry(k, token(v)), overwrite); } void Foam::dictionary::add ( const keyType& k, - const Foam::string& s, + const Foam::string& v, bool overwrite ) { - add(new primitiveEntry(k, token(s)), overwrite); + add(new primitiveEntry(k, token(v)), overwrite); } -void Foam::dictionary::add(const keyType& k, const label l, bool overwrite) +void Foam::dictionary::add(const keyType& k, const label v, bool overwrite) { - add(new primitiveEntry(k, token(l)), overwrite); + add(new primitiveEntry(k, token(v)), overwrite); } -void Foam::dictionary::add(const keyType& k, const scalar s, bool overwrite) +void Foam::dictionary::add(const keyType& k, const scalar v, bool overwrite) { - add(new primitiveEntry(k, token(s)), overwrite); + add(new primitiveEntry(k, token(v)), overwrite); } void Foam::dictionary::add ( const keyType& k, - const dictionary& d, + const dictionary& v, bool mergeEntry ) { - add(new dictionaryEntry(k, *this, d), mergeEntry); + add(new dictionaryEntry(k, *this, v), mergeEntry); } void Foam::dictionary::set(entry* entryPtr) { // Find non-recursive with patterns - entry* existingPtr = lookupEntryPtr(entryPtr->keyword(), false, true); + auto finder = search(entryPtr->keyword(), false, true); // Clear dictionary so merge acts like overwrite - if (existingPtr && existingPtr->isDict()) + if (finder.isDict()) { - existingPtr->dict().clear(); + finder.dict().clear(); } add(entryPtr, true); } @@ -904,134 +683,14 @@ void Foam::dictionary::set(const entry& e) } -void Foam::dictionary::set(const keyType& k, const dictionary& d) +void Foam::dictionary::set(const keyType& k, const dictionary& v) { - set(new dictionaryEntry(k, *this, d)); -} - - -bool Foam::dictionary::remove(const word& keyword) -{ - auto iter = hashedEntries_.find(keyword); - - if (iter.found()) - { - // Delete from patterns - pattern_iterator wcLink = patterns_.begin(); - regexp_iterator reLink = regexps_.begin(); - - // Find in pattern using exact match only - if (findInPatterns(false, keyword, wcLink, reLink)) - { - patterns_.remove(wcLink); - regexps_.remove(reLink); - } - - parent_type::remove(iter()); - delete iter(); - hashedEntries_.erase(iter); - - return true; - } - else - { - return false; - } -} - - -bool Foam::dictionary::changeKeyword -( - const keyType& oldKeyword, - const keyType& newKeyword, - bool forceOverwrite -) -{ - // No change - if (oldKeyword == newKeyword) - { - return false; - } - - // Check that oldKeyword exists and can be changed - auto iter = hashedEntries_.find(oldKeyword); - - if (!iter.found()) - { - return false; - } - - if (iter()->keyword().isPattern()) - { - FatalIOErrorInFunction - ( - *this - ) << "Old keyword "<< oldKeyword - << " is a pattern." - << "Pattern replacement not yet implemented." - << exit(FatalIOError); - } - - - auto iter2 = hashedEntries_.find(newKeyword); - - // newKeyword already exists - if (iter2.found()) - { - if (forceOverwrite) - { - if (iter2()->keyword().isPattern()) - { - // Delete from patterns - pattern_iterator wcLink = patterns_.begin(); - regexp_iterator reLink = regexps_.begin(); - - // Find in patterns using exact match only - if (findInPatterns(false, iter2()->keyword(), wcLink, reLink)) - { - patterns_.remove(wcLink); - regexps_.remove(reLink); - } - } - - parent_type::replace(iter2(), iter()); - delete iter2(); - hashedEntries_.erase(iter2); - } - else - { - IOWarningInFunction - ( - *this - ) << "cannot rename keyword "<< oldKeyword - << " to existing keyword " << newKeyword - << " in dictionary " << name() << endl; - return false; - } - } - - // Change name and HashTable, but leave DL-List untouched - iter()->keyword() = newKeyword; - iter()->name() = name() + '.' + newKeyword; - hashedEntries_.erase(oldKeyword); - hashedEntries_.insert(newKeyword, iter()); - - if (newKeyword.isPattern()) - { - patterns_.insert(iter()); - regexps_.insert - ( - autoPtr(new regExp(newKeyword)) - ); - } - - return true; + set(new dictionaryEntry(k, *this, v)); } bool Foam::dictionary::merge(const dictionary& dict) { - // Check for assignment to self if (this == &dict) { FatalIOErrorInFunction(*this) @@ -1041,7 +700,7 @@ bool Foam::dictionary::merge(const dictionary& dict) bool changed = false; - forAllConstIter(parent_type, dict, iter) + forAllConstIters(dict, iter) { auto fnd = hashedEntries_.find(iter().keyword()); @@ -1112,7 +771,6 @@ Foam::ITstream& Foam::dictionary::operator[](const word& keyword) const void Foam::dictionary::operator=(const dictionary& rhs) { - // Check for assignment to self if (this == &rhs) { FatalIOErrorInFunction(*this) @@ -1126,7 +784,7 @@ void Foam::dictionary::operator=(const dictionary& rhs) // Create clones of the entries in the given dictionary // resetting the parentDict to this dictionary - forAllConstIter(parent_type, rhs, iter) + forAllConstIters(rhs, iter) { add(iter().clone(*this).ptr()); } @@ -1135,7 +793,6 @@ void Foam::dictionary::operator=(const dictionary& rhs) void Foam::dictionary::operator+=(const dictionary& rhs) { - // Check for assignment to self if (this == &rhs) { FatalIOErrorInFunction(*this) @@ -1143,7 +800,7 @@ void Foam::dictionary::operator+=(const dictionary& rhs) << abort(FatalIOError); } - forAllConstIter(parent_type, rhs, iter) + forAllConstIters(rhs, iter) { add(iter().clone(*this).ptr()); } @@ -1152,7 +809,6 @@ void Foam::dictionary::operator+=(const dictionary& rhs) void Foam::dictionary::operator|=(const dictionary& rhs) { - // Check for assignment to self if (this == &rhs) { FatalIOErrorInFunction(*this) @@ -1160,7 +816,7 @@ void Foam::dictionary::operator|=(const dictionary& rhs) << abort(FatalIOError); } - forAllConstIter(parent_type, rhs, iter) + forAllConstIters(rhs, iter) { if (!found(iter().keyword())) { @@ -1172,7 +828,6 @@ void Foam::dictionary::operator|=(const dictionary& rhs) void Foam::dictionary::operator<<=(const dictionary& rhs) { - // Check for assignment to self if (this == &rhs) { FatalIOErrorInFunction(*this) @@ -1180,7 +835,7 @@ void Foam::dictionary::operator<<=(const dictionary& rhs) << abort(FatalIOError); } - forAllConstIter(parent_type, rhs, iter) + forAllConstIters(rhs, iter) { set(iter().clone(*this).ptr()); } diff --git a/src/OpenFOAM/db/dictionary/dictionary.H b/src/OpenFOAM/db/dictionary/dictionary.H index f0c66b97a8..783c643656 100644 --- a/src/OpenFOAM/db/dictionary/dictionary.H +++ b/src/OpenFOAM/db/dictionary/dictionary.H @@ -41,10 +41,13 @@ Description Note Within dictionaries, entries can be referenced by using the '$' syntax - familiar from shell programming. A '.' separator is used when referencing - sub-dictionary entries. Leading '.' prefixes can be used to specify - an entry from a parent directory. A leading ':' or '^' prefix specifies - starting from the top-level entry. For example, + familiar from shell programming. + A '.' separator is used when referencing sub-dictionary entries. + Leading '.' prefixes can be used to specify an entry from a parent + dictionary. + An initial '^' anchor (or ':' for backward compatibility) specifies + starting from the top-level entry. + For example, \verbatim key1 val1; @@ -70,6 +73,7 @@ Note SourceFiles dictionary.C dictionaryIO.C + dictionarySearch.C SeeAlso - Foam::entry @@ -89,6 +93,7 @@ SeeAlso #include "HashTable.H" #include "wordList.H" #include "className.H" +#include // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -148,22 +153,20 @@ public: const word dictName() const { const word scopedName = name_.name(); - const std::string::size_type i = scopedName.rfind('.'); + const auto i = scopedName.rfind('.'); if (i == std::string::npos) { return scopedName; } - else - { - return scopedName.substr(i+1); - } + + return scopedName.substr(i+1); } }; /*---------------------------------------------------------------------------*\ - Class dictionary Declaration + Class dictionary Declaration \*---------------------------------------------------------------------------*/ class dictionary @@ -171,15 +174,157 @@ class dictionary public dictionaryName, public IDLList { +public: + + // Searching + + //- Generic const/non-const dictionary entry %searcher. + // A %searcher provides a uniform means of finding and returning + // an entry pointer as well as the dictionary \a context in which + // the entry was located. + // + // Note that the constructors and set methods are protected such + // that only friends of the class can set things. This safeguards + // against inconsistencies in context/entry. + template + class Searcher + { + public: + friend dictionary; + + //- The const/non-const type for the context and sub-dictionaries + typedef typename std::conditional + ::type dict_type; + + //- The const/non-const type for entries + typedef typename std::conditional + ::type value_type; + + //- A pointer to a const/non-const dictionary + typedef dict_type* dict_pointer; + + //- A reference to a const/non-const dictionary + typedef dict_type& dict_reference; + + //- A pointer to a const/non-const entry + typedef value_type* pointer; + + //- A reference to a const/non-const entry + typedef value_type& reference; + + + protected: + + //- The dictionary context for the entry + dict_pointer dict_; + + //- The entry or nullptr + pointer eptr_; + + + //- Construct null + Searcher() + : + dict_(nullptr), + eptr_(nullptr) + {} + + //- Construct for the given dictionary context + Searcher(dict_pointer dict) + : + dict_(dict), + eptr_(nullptr) + {} + + //- Assign the entry + void set(pointer eptr) + { + eptr_ = eptr; + } + + + public: + + //- Entry was found. + inline bool found() const + { + return eptr_; + } + + //- The containing dictionary context + inline dict_reference context() const + { + return *dict_; + } + + //- A pointer to the entry (nullptr if not found) + inline pointer ptr() const + { + return eptr_; + } + + //- A reference to the entry (Error if not found) + inline reference ref() const + { + return *eptr_; + } + + //- True if found entry is a dictionary. + inline bool isDict() const + { + return eptr_ && eptr_->isDict(); + } + + //- Pointer to the found entry as a dictionary or nullptr otherwise. + inline dict_pointer dictPtr() const + { + return eptr_ && eptr_->isDict() ? eptr_->dictPtr() : nullptr; + } + + //- Reference the found entry as a dictionary. + // (Error if not found, or not a dictionary). + inline dict_reference dict() const + { + return eptr_->dict(); + } + + //- Permit an explicit cast to the other (const/non-const) searcher + inline explicit operator const Searcher&() const + { + return *reinterpret_cast*>(this); + } + }; + + + //- Searcher with const access + typedef Searcher const_searcher; + + //- Searcher with non-const access + typedef Searcher searcher; + + + // Friends + + //- Declare friendship with the entry class for IO + friend class entry; + + //- Declare friendship with the searcher classes + friend const_searcher; + friend searcher; + + +private: + // Private data //- Report optional keywords and values if not present in dictionary + // Set/unset via an InfoSwitch static bool writeOptionalEntries; //- Parent dictionary const dictionary& parent_; - //- HashTable of the entries held on the IDLList for quick lookup + //- Quick lookup of the entries held on the IDLList HashTable hashedEntries_; //- Entries of matching patterns @@ -196,28 +341,49 @@ class dictionary typedef DLList::iterator pattern_iterator; typedef DLList::const_iterator pattern_const_iterator; + typedef DLList>::iterator regexp_iterator; typedef DLList>::const_iterator regexp_const_iterator; // Private Member Functions - //- Find and return an entry data stream pointer if present - // otherwise return nullptr. Allows scoping using '.' - const entry* lookupScopedSubEntryPtr + //- Search using a '.' for scoping. + // A leading dot means to use the parent dictionary. + // An intermediate dot separates a sub-dictionary or sub-entry. + // However, the use of dots is unfortunately ambiguous. + // The value "a.b.c.d" could be a first-level entry, a second-level + // entry (eg, "a" with "b.c.d", "a.b" with "c.d" etc), + // or just about any other combination. + // The heuristic tries sucessively longer top-level entries + // until there is a suitable match. + // + // \param recursive search parent dictionaries + // \param patternMatch use regular expressions + const_searcher csearchDotScoped ( const word& keyword, bool recursive, bool patternMatch ) const; + //- Search using a '/' for scoping. + // Semantics as per normal files: an intermediate "." is the current + // dictionary level, an intermediate ".." is the parent dictionary. + // Note that since a slash is not a valid word character, there is no + // ambiguity between separator and content. + // No possibility or need for recursion. + // + // \param patternMatch use regular expressions + const_searcher csearchSlashScoped + ( + const word& keyword, + bool patternMatch + ) const; + public: - //- Declare friendship with the entry class for IO - friend class entry; - - // Declare name of the class and its debug switch ClassName("dictionary"); @@ -234,7 +400,7 @@ public: explicit dictionary(const fileName& name); //- Construct given the entry name, parent dictionary and Istream, - // reading entries until lastEntry or EOF + // reading entries until EOF dictionary ( const fileName& name, @@ -251,7 +417,7 @@ public: dictionary(Istream& is, const bool keepHeader); //- Construct as copy given the parent dictionary - dictionary(const dictionary& parentDict, const dictionary&); + dictionary(const dictionary& parentDict, const dictionary& dict); //- Construct top-level dictionary as copy dictionary(const dictionary& dict); @@ -303,284 +469,413 @@ public: tokenList tokens() const; - // Search and lookup + // Search and lookup - //- Search dictionary for given keyword - // If recursive, search parent dictionaries - // If patternMatch, use regular expressions - bool found - ( - const word& keyword, - bool recursive = false, - bool patternMatch = true - ) const; + //- Search dictionary for given keyword + // If recursive, search parent dictionaries + // If patternMatch, use regular expressions + // (default search: non-recursive with patterns). + bool found + ( + const word& keyword, + bool recursive = false, + bool patternMatch = true + ) const; - //- Find and return an entry data stream pointer if present - // otherwise return nullptr. - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions - const entry* lookupEntryPtr - ( - const word& keyword, - bool recursive, - bool patternMatch - ) const; + //- Find and return an entry data stream pointer if present + // otherwise return nullptr. + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions + const entry* lookupEntryPtr + ( + const word& keyword, + bool recursive, + bool patternMatch + ) const; - //- Find and return an entry data stream pointer for manipulation - // if present otherwise return nullptr. - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - entry* lookupEntryPtr - ( - const word& keyword, - bool recursive, - bool patternMatch - ); + //- Find and return an entry data stream pointer for manipulation + // if present otherwise return nullptr. + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + entry* lookupEntryPtr + ( + const word& keyword, + bool recursive, + bool patternMatch + ); - //- Find and return an entry data stream if present otherwise error. - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - const entry& lookupEntry - ( - const word& keyword, - bool recursive, - bool patternMatch - ) const; + //- Find and return an entry data stream if present otherwise error. + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + const entry& lookupEntry + ( + const word& keyword, + bool recursive, + bool patternMatch + ) const; - //- Find and return an entry data stream - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - ITstream& lookup - ( - const word& keyword, - bool recursive = false, - bool patternMatch = true - ) const; + //- Find and return an entry data stream + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + // (default search: non-recursive with patterns). + ITstream& lookup + ( + const word& keyword, + bool recursive = false, + bool patternMatch = true + ) const; - //- Find and return a T, - // if not found throw a fatal error. - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - template - T lookupType - ( - const word&, - bool recursive=false, - bool patternMatch=true - ) const; + //- Find and return a T, + // if not found throw a fatal error. + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + // (default search: non-recursive with patterns). + template + T lookupType + ( + const word& keyword, + bool recursive = false, + bool patternMatch = true + ) const; - //- Find and return a T, or return the given default value - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - template - T lookupOrDefault - ( - const word& keyword, - const T& deflt, - bool recursive = false, - bool patternMatch = true - ) const; + //- Find and return a T, or return the given default value + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + // (default search: non-recursive with patterns). + template + T lookupOrDefault + ( + const word& keyword, + const T& deflt, + bool recursive = false, + bool patternMatch = true + ) const; - //- Find and return a T, if not found return the given - // default value, and add to dictionary. - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - template - T lookupOrAddDefault - ( - const word& keyword, - const T& deflt, - bool recursive = false, - bool patternMatch = true - ); + //- Find and return a T, if not found return the default value + // and add it to dictionary. + // Default search: non-recursive with patterns. + // + // \param recursive search parent dictionaries + // \param patternMatch use regular expressions + template + T lookupOrAddDefault + ( + const word& keyword, + const T& deflt, + bool recursive = false, + bool patternMatch = true + ); - //- Find an entry if present, and assign to T - // Returns true if the entry was found. - // If recursive, search parent dictionaries. - // If patternMatch, use regular expressions. - template - bool readIfPresent - ( - const word& keyword, - T& val, - bool recursive = false, - bool patternMatch = true - ) const; + //- Find an entry if present, and assign to T val. + // Default search: non-recursive with patterns. + // + // \param val the value to read + // \param recursive search parent dictionaries + // \param patternMatch use regular expressions + // + // \return true if the entry was found. + template + bool readIfPresent + ( + const word& keyword, + T& val, + bool recursive = false, + bool patternMatch = true + ) const; - //- Find and return an entry data stream pointer if present - // otherwise return nullptr. Allows scoping using '.'. - // Special handling for ':' at start of keyword and '..'. - const entry* lookupScopedEntryPtr - ( - const word& keyword, - bool recursive, - bool patternMatch - ) const; + //- Find and return an entry pointer if present, or return a nullptr. + // Allows scoping using '.'. + // Special handling for an absolute anchor (^) at start of the keyword + // and for '..' to ascend into the parent dictionaries. + // + // \param recursive search parent dictionaries + // \param patternMatch use regular expressions + const entry* lookupScopedEntryPtr + ( + const word& keyword, + bool recursive, + bool patternMatch + ) const; - //- Check if entry is a sub-dictionary - bool isDict(const word& keyword) const; + //- Check if entry exists and is a sub-dictionary. + // (search type: non-recursive with patterns) + bool isDict(const word& keyword) const; - //- Find and return a sub-dictionary pointer if present - // otherwise return nullptr. - const dictionary* subDictPtr(const word& keyword) const; + //- Find and return a sub-dictionary pointer if present + // (and a sub-dictionary) otherwise return nullptr. + // (search type: non-recursive with patterns) + const dictionary* subDictPtr(const word& keyword) const; - //- Find and return a sub-dictionary pointer if present - // otherwise return nullptr. - dictionary* subDictPtr(const word& keyword); + //- Find and return a sub-dictionary pointer if present + // (and a sub-dictionary) otherwise return nullptr. + // + // Search type: non-recursive with patterns. + dictionary* subDictPtr(const word& keyword); - //- Find and return a sub-dictionary - const dictionary& subDict(const word& keyword) const; + //- Find and return a sub-dictionary. + // Fatal if the entry does not exist or is not a sub-dictionary. + // (search type: non-recursive with patterns) + const dictionary& subDict(const word& keyword) const; - //- Find and return a sub-dictionary for manipulation - dictionary& subDict(const word& keyword); + //- Find and return a sub-dictionary for manipulation. + // Fatal if the entry does not exist or is not a sub-dictionary. + // (search type: non-recursive with patterns) + dictionary& subDict(const word& keyword); - //- Find and return a sub-dictionary as a copy, or - // return an empty dictionary if the sub-dictionary does not exist - dictionary subOrEmptyDict - ( - const word& keyword, - const bool mustRead = false - ) const; + //- Find and return a sub-dictionary as a copy, otherwise return + // an empty dictionary. + // Warn if the entry exists but is not a sub-dictionary. + // (search type: non-recursive with patterns) + dictionary subOrEmptyDict + ( + const word& keyword, + const bool mustRead = false + ) const; - //- Find and return a sub-dictionary if found - // otherwise return this dictionary - const dictionary& optionalSubDict(const word&) const; + //- Find and return a sub-dictionary, otherwise return this dictionary. + // Warn if the entry exists but is not a sub-dictionary. + // (search type: non-recursive with patterns) + const dictionary& optionalSubDict(const word& keyword) const; - //- Return the table of contents - wordList toc() const; + //- Return the table of contents + wordList toc() const; - //- Return the sorted table of contents - wordList sortedToc() const; + //- Return the sorted table of contents + wordList sortedToc() const; - //- Return table of contents sorted using the specified comparator - template - wordList sortedToc(const Compare& comp) const; + //- Return table of contents sorted using the specified comparator + template + wordList sortedToc(const Compare& comp) const; - //- Return the list of available keys or patterns - List keys(bool patterns = false) const; + //- Return the list of available keys or patterns + List keys(bool patterns = false) const; - // Editing + // Editing - //- Substitute the given keyword prepended by '$' with the - // corresponding sub-dictionary entries - bool substituteKeyword(const word& keyword, bool mergeEntry=false); + //- Substitute the given keyword (which is prefixed by '$') + // with the corresponding sub-dictionary entries + bool substituteKeyword + ( + const word& keyword, + bool mergeEntry = false + ); - //- Substitute the given scoped keyword prepended by '$' with the - // corresponding sub-dictionary entries - bool substituteScopedKeyword - ( - const word& keyword, - bool mergeEntry=false - ); + //- Substitute the given scoped keyword (which is prefixed by '$') + // with the corresponding sub-dictionary entries + bool substituteScopedKeyword + ( + const word& keyword, + bool mergeEntry = false + ); - //- Add a new entry - // With the merge option, dictionaries are interwoven and - // primitive entries are overwritten - bool add(entry* entryPtr, bool mergeEntry=false); + //- Add a new entry + // With the merge option, dictionaries are interwoven and + // primitive entries are overwritten + bool add(entry* entryPtr, bool mergeEntry=false); - //- Add an entry - // With the merge option, dictionaries are interwoven and - // primitive entries are overwritten - void add(const entry& e, bool mergeEntry=false); + //- Add an entry + // With the merge option, dictionaries are interwoven and + // primitive entries are overwritten + void add(const entry& e, bool mergeEntry=false); - //- Add a word entry - // optionally overwrite an existing entry - void add(const keyType& k, const word& w, bool overwrite=false); + //- Add a word entry + // optionally overwrite an existing entry + void add(const keyType& k, const word& v, bool overwrite=false); - //- Add a string entry - // optionally overwrite an existing entry - void add(const keyType& k, const string& s, bool overwrite=false); + //- Add a string entry + // optionally overwrite an existing entry + void add(const keyType& k, const string& v, bool overwrite=false); - //- Add a label entry - // optionally overwrite an existing entry - void add(const keyType&, const label l, bool overwrite=false); + //- Add a label entry + // optionally overwrite an existing entry + void add(const keyType& k, const label v, bool overwrite=false); - //- Add a scalar entry - // optionally overwrite an existing entry - void add(const keyType&, const scalar s, bool overwrite=false); + //- Add a scalar entry + // optionally overwrite an existing entry + void add(const keyType& k, const scalar v, bool overwrite=false); - //- Add a dictionary entry - // optionally merge with an existing sub-dictionary - void add - ( - const keyType& k, - const dictionary& d, - bool mergeEntry = false - ); + //- Add a dictionary entry + // optionally merge with an existing sub-dictionary + void add + ( + const keyType& k, + const dictionary& d, + bool mergeEntry = false + ); - //- Add a T entry - // optionally overwrite an existing entry - template - void add(const keyType& k, const T& t, bool overwrite=false); + //- Add a T entry + // optionally overwrite an existing entry + template + void add(const keyType& k, const T& v, bool overwrite=false); - //- Assign a new entry, overwrite any existing entry - void set(entry* entryPtr); + //- Assign a new entry, overwrite any existing entry + void set(entry* entryPtr); - //- Assign a new entry, overwrite any existing entry - void set(const entry& e); + //- Assign a new entry, overwrite any existing entry + void set(const entry& e); - //- Assign a dictionary entry, overwrite any existing entry - void set(const keyType& k, const dictionary& d); + //- Assign a dictionary entry, overwrite any existing entry + void set(const keyType& k, const dictionary& v); - //- Assign a T entry, overwrite any existing entry - template - void set(const keyType& k, const T& t); + //- Assign a T entry, overwrite any existing entry + template + void set(const keyType& k, const T& v); - //- Remove an entry specified by keyword - bool remove(const word& Keyword); + //- Remove an entry specified by keyword + bool remove(const word& keyword); - //- Change the keyword for an entry, - // optionally forcing overwrite of an existing entry - bool changeKeyword - ( - const keyType& oldKeyword, - const keyType& newKeyword, - bool forceOverwrite=false - ); + //- Change the keyword for an entry, + // optionally forcing overwrite of an existing entry + bool changeKeyword + ( + const keyType& oldKeyword, + const keyType& newKeyword, + bool forceOverwrite=false + ); - //- Merge entries from the given dictionary. - // Also merge sub-dictionaries as required. - bool merge(const dictionary& dict); + //- Merge entries from the given dictionary. + // Also merge sub-dictionaries as required. + bool merge(const dictionary& dict); - //- Clear the dictionary - void clear(); + //- Clear the dictionary + void clear(); - //- Transfer the contents of the argument and annul the argument. - void transfer(dictionary& dict); + //- Transfer the contents of the argument and annul the argument. + void transfer(dictionary& dict); - //- Transfer contents to the Xfer container - Xfer xfer(); + //- Transfer contents to the Xfer container + Xfer xfer(); - // Read + // Read - //- Read dictionary from Istream - bool read(Istream& is); + //- Read dictionary from Istream + bool read(Istream& is); - //- Read dictionary from Istream, optionally keeping the header - bool read(Istream& is, const bool keepHeader); + //- Read dictionary from Istream, optionally keeping the header + bool read(Istream& is, const bool keepHeader); - // Write + // Write - //- Write sub-dictionary with the keyword as its header - void writeEntry(const keyType& keyword, Ostream& os) const; + //- Write sub-dictionary with the keyword as its header + void writeEntry(const keyType& keyword, Ostream& os) const; - //- Write dictionary entries. - // Optionally with extra new line between entries for - // "top-level" dictionaries - void writeEntries(Ostream& os, const bool extraNewLine=false) const; + //- Write dictionary entries. + // Optionally with extra new line between entries for + // "top-level" dictionaries + void writeEntries(Ostream& os, const bool extraNewLine=false) const; - //- Write dictionary, normally with sub-dictionary formatting - void write(Ostream& os, const bool subDict=true) const; + //- Write dictionary, normally with sub-dictionary formatting + void write(Ostream& os, const bool subDict=true) const; + + + // Searching + + //- Search dictionary for given keyword + // If recursive, search parent dictionaries + // If patternMatch, use regular expressions + // (default search: non-recursive with patterns). + const_searcher csearch + ( + const word& keyword, + bool recursive = false, + bool patternMatch = true + ) const; + + //- Search dictionary for given keyword + // If recursive, search parent dictionaries + // If patternMatch, use regular expressions + // (default search: non-recursive with patterns). + const_searcher search + ( + const word& keyword, + bool recursive = false, + bool patternMatch = true + ) const; + + //- Search dictionary for given keyword + // If recursive, search parent dictionaries + // If patternMatch, use regular expressions + // (default search: non-recursive with patterns). + searcher search + ( + const word& keyword, + bool recursive = false, + bool patternMatch = true + ); + + //- Search using scoping. + // There are two types of scoping available: + // -# dot-scoping, where a '.' is used to delineate the scope + // -# slash-scoping, where a '/' is used to delineate the scope + // + // For dot-scoping, a leading '^' traverses to the top-level + // dictionary, leading dots mean use the parent dictionary and an + // intermediate dot separates a sub-dictionary or sub-entry. + // However, since the use of dots is ambiguous ("a.b.c" could be + // an entry itself or represent a "bc" entry from dictionary "a" etc), + // the heuristic backtracks and attempts successively longer + // top-level entries until a suitable match is found. + // + // For slash-scoping, semantics similar to directory structures are + // used. A leading '/' traverses to the top-level dictionary, + // a single leading or intermediate '.' references the current + // dictionary level. A '..' pair references the parent dictionary. + // Any doubled slashes are silently ignored. + // Since a slash is not a valid keyword character, there is no + // ambiguity between separator and content. + const_searcher csearchScoped + ( + const word& keyword, + bool recursive, + bool patternMatch + ) const; + + //- Search using dot or slash scoping. + const_searcher searchScoped + ( + const word& keyword, + bool recursive, + bool patternMatch + ) const; + + //- Search using dot or slash scoping. + searcher searchScoped + ( + const word& keyword, + bool recursive, + bool patternMatch + ); + + //- Locate a sub-dictionary using slash-scoping + // \return nullptr if the dictionary path does not exist + const dictionary* cfindScopedDictPtr(const fileName& dictPath) const; + + //- Locate a sub-dictionary using slash-scoping + // \return nullptr if the dictionary path does not exist + const dictionary* findScopedDictPtr(const fileName& dictPath) const; + + //- Locate a sub-dictionary using slash-scoping + // \return nullptr if the dictionary path does not exist + dictionary* findScopedDictPtr(const fileName& dictPath); + + //- Locate existing or create sub-dictionary using slash-scoping + // \return nullptr if the dictionary path could not be created + dictionary* makeScopedDictPtr(const fileName& dictPath); // Member Operators - //- Find and return entry + //- Find and return an entry data stream (identical to #lookup method). + // Default search: non-recursive with patterns. + // + // \param recursive search parent dictionaries + // \param patternMatch use regular expressions ITstream& operator[](const word& keyword) const; + //- Copy assignment void operator=(const dictionary& rhs); //- Include entries from the given dictionary. diff --git a/src/OpenFOAM/db/dictionary/dictionaryIO.C b/src/OpenFOAM/db/dictionary/dictionaryIO.C index ddc505c661..9c1e36c1b5 100644 --- a/src/OpenFOAM/db/dictionary/dictionaryIO.C +++ b/src/OpenFOAM/db/dictionary/dictionaryIO.C @@ -128,30 +128,6 @@ bool Foam::dictionary::read(Istream& is) } -bool Foam::dictionary::substituteKeyword(const word& keyword, bool mergeEntry) -{ - const word varName = keyword.substr(1); - - // Lookup the variable name in the given dictionary - const entry* ePtr = lookupEntryPtr(varName, true, true); - - // If defined insert its entries into this dictionary - if (ePtr != nullptr) - { - const dictionary& addDict = ePtr->dict(); - - forAllConstIter(parent_type, addDict, iter) - { - add(iter(), mergeEntry); - } - - return true; - } - - return false; -} - - // * * * * * * * * * * * * * * Istream Operator * * * * * * * * * * * * * * // Foam::Istream& Foam::operator>>(Istream& is, dictionary& dict) diff --git a/src/OpenFOAM/db/dictionary/dictionarySearch.C b/src/OpenFOAM/db/dictionary/dictionarySearch.C new file mode 100644 index 0000000000..93c5bcb884 --- /dev/null +++ b/src/OpenFOAM/db/dictionary/dictionarySearch.C @@ -0,0 +1,719 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +\*---------------------------------------------------------------------------*/ + +#include "dictionary.H" +#include "dictionaryEntry.H" +#include "stringOps.H" + +/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */ + +namespace Foam +{ + // file-scope + //- Walk lists of patterns and regexps for an exact match + // or regular expression match + template + static bool findInPatterns + ( + const bool patternMatch, + const word& keyword, + WcIterator& wcIter, + ReIterator& reIter + ) + { + while (wcIter.found()) + { + if + ( + patternMatch + ? reIter()->match(keyword) + : wcIter()->keyword() == keyword + ) + { + return true; + } + + ++reIter; + ++wcIter; + } + + return false; + } +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::dictionary::const_searcher Foam::dictionary::csearchDotScoped +( + const word& keyword, + bool recursive, + bool patternMatch +) const +{ + std::string::size_type scopePos = keyword.find('.'); + + if (scopePos == string::npos) + { + // Normal, non-scoped search + return csearch(keyword, recursive, patternMatch); + } + + if (scopePos == 0) + { + // Starting with a '.' -> go up for every further '.' found + ++scopePos; + + const dictionary* dictPtr = this; + for + ( + string::const_iterator it = keyword.begin()+1; + it != keyword.end() && *it == '.'; + ++scopePos, ++it + ) + { + // Go to parent + if (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = &dictPtr->parent_; + } + else + { + FatalIOErrorInFunction + ( + *this + ) << "No parent of current dictionary when searching for " + << keyword.substr(1) + << exit(FatalIOError); + + return nullptr; + } + } + + return dictPtr->csearchDotScoped + ( + keyword.substr(scopePos), + false, + patternMatch + ); + } + + // The first word + const_searcher finder = csearchDotScoped + ( + keyword.substr(0, scopePos), + false, + patternMatch + ); + + // Fall back to finding key with '.' so e.g. if keyword is + // a.b.c.d it would try + // a.b, a.b.c, a.b.c.d + + if (!finder.found()) + { + while (!finder.isDict()) + { + scopePos = keyword.find('.', scopePos+1); + + // Local entry: + finder = csearch(keyword.substr(0, scopePos), false, patternMatch); + + if (scopePos == string::npos) + { + // Parsed the whole word. Return entry or null. + return finder; + } + } + } + + if (finder.isDict()) + { + return finder.dict().csearchDotScoped + ( + keyword.substr(scopePos), + false, + patternMatch + ); + } + + return finder; +} + + +Foam::dictionary::const_searcher Foam::dictionary::csearchSlashScoped +( + const word& keyword, + bool patternMatch +) const +{ + const dictionary* dictPtr = this; + + const auto slash = keyword.find('/'); + + if (slash == string::npos) + { + // No slashes: + // Can use normal (non-scoped) search at the current dictionary level + return csearch(keyword, false, patternMatch); + } + else if (slash == 0) + { + // (isAbsolute) + // Ascend to top-level + while (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = &dictPtr->parent_; + } + } + + // Split on '/' + auto cmpts = stringOps::split(keyword, '/'); + auto remaining = cmpts.size(); + + for (const auto& cmpt : cmpts) + { + --remaining; // Decrement now so we can check (remaining == 0) + + if (cmpt == ".") + { + // "." - ignore + } + else if (cmpt == "..") + { + // ".." - go to parent + if (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = &dictPtr->parent_; + } + else + { + FatalIOErrorInFunction + ( + *dictPtr + ) << "No parent of current dictionary when searching for " + << keyword << " at " << cmpt + << exit(FatalIOError); + break; + } + } + else + { + // Find entry + const word key = word::validate(cmpt); + + auto finder = dictPtr->csearch(key, false, patternMatch); + + if (finder.found()) + { + if (remaining) + { + // Intermediate must be a dictionary + if (finder.isDict()) + { + dictPtr = finder.dictPtr(); + } + else + { + return const_searcher(dictPtr); + } + } + else + { + // Last entry - done + return finder; + } + } + else + { + break; + } + } + } + + // Failed at this dictionary level + return const_searcher(dictPtr); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::dictionary::const_searcher Foam::dictionary::csearch +( + const word& keyword, + bool recursive, + bool patternMatch +) const +{ + const_searcher finder(this); + + auto iter = hashedEntries_.cfind(keyword); + + if (iter.found()) + { + finder.set(iter.object()); + return finder; + } + + if (patternMatch && patterns_.size()) + { + pattern_const_iterator wcLink = patterns_.begin(); + regexp_const_iterator reLink = regexps_.begin(); + + // Find in patterns using regular expressions only + if (findInPatterns(patternMatch, keyword, wcLink, reLink)) + { + finder.set(*wcLink); + return finder; + } + } + + if (recursive && &parent_ != &dictionary::null) + { + return parent_.csearch + ( + keyword, + recursive, + patternMatch + ); + } + + return finder; +} + + +Foam::dictionary::const_searcher Foam::dictionary::search +( + const word& keyword, + bool recursive, + bool patternMatch +) const +{ + return csearch(keyword, recursive, patternMatch); +} + + +Foam::dictionary::searcher Foam::dictionary::search +( + const word& keyword, + bool recursive, + bool patternMatch +) +{ + const_searcher finder = csearch(keyword, recursive, patternMatch); + + return static_cast(finder); +} + + +Foam::dictionary::const_searcher Foam::dictionary::csearchScoped +( + const word& keyword, + bool recursive, + bool patternMatch +) const +{ + if (keyword.find('/') != string::npos) + { + return csearchSlashScoped(keyword, patternMatch); + } + + if (keyword[0] == ':' || keyword[0] == '^') + { + // Ascend to top-level + const dictionary* dictPtr = this; + while (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = &dictPtr->parent_; + } + + return dictPtr->csearchDotScoped + ( + keyword.substr(1), + false, + patternMatch + ); + } + + return csearchDotScoped(keyword, recursive, patternMatch); +} + + +Foam::dictionary::const_searcher Foam::dictionary::searchScoped +( + const word& keyword, + bool recursive, + bool patternMatch +) const +{ + return csearchScoped(keyword, recursive, patternMatch); +} + + +Foam::dictionary::searcher Foam::dictionary::searchScoped +( + const word& keyword, + bool recursive, + bool patternMatch +) +{ + const_searcher finder = csearchScoped(keyword, recursive, patternMatch); + + return static_cast(finder); +} + + +const Foam::dictionary* Foam::dictionary::cfindScopedDictPtr +( + const fileName& dictPath +) const +{ + // Or warning + if (dictPath.empty()) + { + return nullptr; + } + + const dictionary* dictPtr = this; + if (fileName::isAbsolute(dictPath)) + { + // Ascend to top-level + while (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = &dictPtr->parent_; + } + } + + fileName path = dictPath.clean(); + const wordList cmpts = path.components(); + + for (const word& cmpt : cmpts) + { + if (cmpt == ".") + { + // "." - ignore + } + else if (cmpt == "..") + { + // ".." - go to parent + if (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = &dictPtr->parent_; + } + else + { + FatalIOErrorInFunction + ( + *dictPtr + ) << "No parent for dictionary while searching " + << path + << exit(FatalIOError); + + return nullptr; + } + } + else + { + // Non-recursive, no patternMatch + // -> can do direct lookup, without csearch(cmpt, false, false); + + auto iter = dictPtr->hashedEntries_.cfind(cmpt); + + if (iter.found()) + { + const entry *eptr = iter.object(); + + if (eptr->isDict()) + { + dictPtr = eptr->dictPtr(); + } + else + { + FatalIOErrorInFunction + ( + *dictPtr + ) << "Found entry '" << cmpt + << "' but not a dictionary, while searching scoped" + << nl + << " " << path + << exit(FatalIOError); + + return nullptr; + } + } + else + { + return nullptr; + } + } + } + + return dictPtr; +} + + +const Foam::dictionary* Foam::dictionary::findScopedDictPtr +( + const fileName& dictPath +) const +{ + return cfindScopedDictPtr(dictPath); +} + + +Foam::dictionary* Foam::dictionary::findScopedDictPtr +( + const fileName& dictPath +) +{ + const dictionary* ptr = cfindScopedDictPtr(dictPath); + return const_cast(ptr); +} + + +Foam::dictionary* Foam::dictionary::makeScopedDictPtr(const fileName& dictPath) +{ + // Or warning + if (dictPath.empty()) + { + return nullptr; + } + + dictionary* dictPtr = this; + if (fileName::isAbsolute(dictPath)) + { + // Ascend to top-level + while (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = const_cast(&dictPtr->parent_); + } + } + + // Work on a copy, without any assumptions + std::string path = dictPath; + fileName::clean(path); + + // Split on '/' + auto cmpts = stringOps::split(path, '/'); + + for (const auto& cmpt : cmpts) + { + if (cmpt == ".") + { + // "." - ignore + } + else if (cmpt == "..") + { + // ".." - go to parent + if (&dictPtr->parent_ != &dictionary::null) + { + dictPtr = const_cast(&dictPtr->parent_); + } + else + { + FatalIOErrorInFunction + ( + *dictPtr + ) << "No parent for dictionary while searching " + << path + << exit(FatalIOError); + + return nullptr; + } + } + else + { + // Non-recursive, no patternMatch + // -> can do direct lookup, without csearch(cmptName, false, false); + const word cmptName(cmpt.str(), false); + + auto iter = dictPtr->hashedEntries_.find(cmptName); + + if (iter.found()) + { + entry *eptr = iter.object(); + + if (eptr->isDict()) + { + dictPtr = eptr->dictPtr(); + } + else + { + FatalIOErrorInFunction + ( + *dictPtr + ) << "Cannot create sub-dictionary entry '" << cmptName + << "' - a non-dictionary entry is in the way" + << nl << "Encountered in scope" << nl + << " " << path + << exit(FatalIOError); + + return nullptr; + } + } + else + { + dictionaryEntry *eptr = + new dictionaryEntry(cmptName, *dictPtr, dictionary()); + + // Add *without* merging, since we just checked that the entry + // doesn't exist and to ensure that the pointer remains valid. + + if (dictPtr->add(eptr, false)) // NO merge + { + dictPtr = eptr; + } + else + { + return nullptr; + } + } + } + } + + return dictPtr; +} + + +bool Foam::dictionary::remove(const word& keyword) +{ + auto iter = hashedEntries_.find(keyword); + + if (iter.found()) + { + // Delete from patterns + pattern_iterator wcLink = patterns_.begin(); + regexp_iterator reLink = regexps_.begin(); + + // Find in pattern using exact match only + if (findInPatterns(false, keyword, wcLink, reLink)) + { + patterns_.remove(wcLink); + regexps_.remove(reLink); + } + + parent_type::remove(iter()); + delete iter(); + hashedEntries_.erase(iter); + + return true; + } + else + { + return false; + } +} + + +bool Foam::dictionary::changeKeyword +( + const keyType& oldKeyword, + const keyType& newKeyword, + bool forceOverwrite +) +{ + // No change + if (oldKeyword == newKeyword) + { + return false; + } + + // Check that oldKeyword exists and can be changed + auto iter = hashedEntries_.find(oldKeyword); + + if (!iter.found()) + { + return false; + } + + if (iter()->keyword().isPattern()) + { + FatalIOErrorInFunction + ( + *this + ) << "Old keyword "<< oldKeyword + << " is a pattern." + << "Pattern replacement not yet implemented." + << exit(FatalIOError); + } + + + auto iter2 = hashedEntries_.find(newKeyword); + + // newKeyword already exists + if (iter2.found()) + { + if (forceOverwrite) + { + if (iter2()->keyword().isPattern()) + { + // Delete from patterns + pattern_iterator wcLink = patterns_.begin(); + regexp_iterator reLink = regexps_.begin(); + + // Find in patterns using exact match only + if (findInPatterns(false, iter2()->keyword(), wcLink, reLink)) + { + patterns_.remove(wcLink); + regexps_.remove(reLink); + } + } + + parent_type::replace(iter2(), iter()); + delete iter2(); + hashedEntries_.erase(iter2); + } + else + { + IOWarningInFunction + ( + *this + ) << "cannot rename keyword "<< oldKeyword + << " to existing keyword " << newKeyword + << " in dictionary " << name() << endl; + return false; + } + } + + // Change name and HashTable, but leave DL-List untouched + iter()->keyword() = newKeyword; + iter()->name() = name() + '.' + newKeyword; + hashedEntries_.erase(oldKeyword); + hashedEntries_.insert(newKeyword, iter()); + + if (newKeyword.isPattern()) + { + patterns_.insert(iter()); + regexps_.insert + ( + autoPtr(new regExp(newKeyword)) + ); + } + + return true; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/db/dictionary/dictionaryTemplates.C b/src/OpenFOAM/db/dictionary/dictionaryTemplates.C index 1e46e5da33..d0446b6770 100644 --- a/src/OpenFOAM/db/dictionary/dictionaryTemplates.C +++ b/src/OpenFOAM/db/dictionary/dictionaryTemplates.C @@ -43,9 +43,9 @@ T Foam::dictionary::lookupType bool patternMatch ) const { - const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch); + auto finder = csearch(keyword, recursive, patternMatch); - if (entryPtr == nullptr) + if (!finder.found()) { FatalIOErrorInFunction ( @@ -55,7 +55,7 @@ T Foam::dictionary::lookupType << exit(FatalIOError); } - return pTraits(entryPtr->stream()); + return pTraits(finder.ptr()->stream()); } @@ -68,11 +68,11 @@ T Foam::dictionary::lookupOrDefault bool patternMatch ) const { - const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch); + auto finder = csearch(keyword, recursive, patternMatch); - if (entryPtr) + if (finder.found()) { - return pTraits(entryPtr->stream()); + return pTraits(finder.ptr()->stream()); } else { @@ -98,11 +98,11 @@ T Foam::dictionary::lookupOrAddDefault bool patternMatch ) { - const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch); + auto finder = csearch(keyword, recursive, patternMatch); - if (entryPtr) + if (finder.found()) { - return pTraits(entryPtr->stream()); + return pTraits(finder.ptr()->stream()); } else { @@ -129,11 +129,11 @@ bool Foam::dictionary::readIfPresent bool patternMatch ) const { - const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch); + auto finder = csearch(keyword, recursive, patternMatch); - if (entryPtr) + if (finder.found()) { - entryPtr->stream() >> val; + finder.ptr()->stream() >> val; return true; } else @@ -152,16 +152,16 @@ bool Foam::dictionary::readIfPresent template -void Foam::dictionary::add(const keyType& k, const T& t, bool overwrite) +void Foam::dictionary::add(const keyType& k, const T& v, bool overwrite) { - add(new primitiveEntry(k, t), overwrite); + add(new primitiveEntry(k, v), overwrite); } template -void Foam::dictionary::set(const keyType& k, const T& t) +void Foam::dictionary::set(const keyType& k, const T& v) { - set(new primitiveEntry(k, t)); + set(new primitiveEntry(k, v)); } diff --git a/src/OpenFOAM/db/dictionary/entry/entryIO.C b/src/OpenFOAM/db/dictionary/entry/entryIO.C index b8a75380ab..f6879570d2 100644 --- a/src/OpenFOAM/db/dictionary/entry/entryIO.C +++ b/src/OpenFOAM/db/dictionary/entry/entryIO.C @@ -224,17 +224,12 @@ bool Foam::entry::New const word varName = keyword.substr(1); // Lookup the variable name in the given dictionary - const entry* ePtr = parentDict.lookupScopedEntryPtr - ( - varName, - true, - true - ); + const auto finder = parentDict.csearchScoped(varName, true, true); - if (ePtr) + if (finder.found()) { // Read as primitiveEntry - const keyType newKeyword(ePtr->stream()); + const keyType newKeyword(finder.ptr()->stream()); return parentDict.add ( @@ -285,14 +280,9 @@ bool Foam::entry::New bool mergeEntry = false; // See (using exact match) if entry already present - entry* existingPtr = parentDict.lookupEntryPtr - ( - keyword, - false, - false - ); + auto finder = parentDict.search(keyword, false, false); - if (existingPtr) + if (finder.found()) { if (mode == inputMode::MERGE) { @@ -301,9 +291,9 @@ bool Foam::entry::New else if (mode == inputMode::OVERWRITE) { // Clear existing dictionary so merge acts like overwrite - if (existingPtr->isDict()) + if (finder.isDict()) { - existingPtr->dict().clear(); + finder.dict().clear(); } mergeEntry = true; }