ENH: add dictionary searcher methods
- csearch(), search(), csearchScoped(), searchScoped() methods can be used to find an entry and also retain the enclosing dictionary context. - To avoid ambiguity between a dot (.) as a scoping character and legal part of a keyword, entries can now be accessed directly using slash-scoping semantics similar to file-names: * cfindScopedDictPtr, findScopedDictPtr - To get or create a sub-dictionary entry: * makeScopedDictPtr, which behaves similarly to mkdirp in that it will create any intermediate dictionaries as required.
This commit is contained in:
parent
b4b9303868
commit
971213eb55
@ -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
|
||||
|
@ -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<class WcIterator, class ReIterator>
|
||||
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<dictionary&>(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::keyType> Foam::dictionary::keys(bool patterns) const
|
||||
{
|
||||
List<keyType> 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<regExp>(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());
|
||||
}
|
||||
|
@ -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 <type_traits>
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -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<entry>
|
||||
{
|
||||
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<bool Const>
|
||||
class Searcher
|
||||
{
|
||||
public:
|
||||
friend dictionary;
|
||||
|
||||
//- The const/non-const type for the context and sub-dictionaries
|
||||
typedef typename std::conditional
|
||||
<Const, const dictionary, dictionary>::type dict_type;
|
||||
|
||||
//- The const/non-const type for entries
|
||||
typedef typename std::conditional
|
||||
<Const, const entry, entry>::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>&() const
|
||||
{
|
||||
return *reinterpret_cast<const Searcher<!Const>*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- Searcher with const access
|
||||
typedef Searcher<true> const_searcher;
|
||||
|
||||
//- Searcher with non-const access
|
||||
typedef Searcher<false> 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<entry*> hashedEntries_;
|
||||
|
||||
//- Entries of matching patterns
|
||||
@ -196,28 +341,49 @@ class dictionary
|
||||
|
||||
typedef DLList<entry*>::iterator pattern_iterator;
|
||||
typedef DLList<entry*>::const_iterator pattern_const_iterator;
|
||||
|
||||
typedef DLList<autoPtr<regExp>>::iterator regexp_iterator;
|
||||
typedef DLList<autoPtr<regExp>>::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<class T>
|
||||
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<class T>
|
||||
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<class T>
|
||||
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<class T>
|
||||
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<class T>
|
||||
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<class T>
|
||||
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<class T>
|
||||
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<class T>
|
||||
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<class Compare>
|
||||
wordList sortedToc(const Compare& comp) const;
|
||||
//- Return table of contents sorted using the specified comparator
|
||||
template<class Compare>
|
||||
wordList sortedToc(const Compare& comp) const;
|
||||
|
||||
//- Return the list of available keys or patterns
|
||||
List<keyType> keys(bool patterns = false) const;
|
||||
//- Return the list of available keys or patterns
|
||||
List<keyType> 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<class T>
|
||||
void add(const keyType& k, const T& t, bool overwrite=false);
|
||||
//- Add a T entry
|
||||
// optionally overwrite an existing entry
|
||||
template<class T>
|
||||
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<class T>
|
||||
void set(const keyType& k, const T& t);
|
||||
//- Assign a T entry, overwrite any existing entry
|
||||
template<class T>
|
||||
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<dictionary> xfer();
|
||||
//- Transfer contents to the Xfer container
|
||||
Xfer<dictionary> 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.
|
||||
|
@ -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)
|
||||
|
719
src/OpenFOAM/db/dictionary/dictionarySearch.C
Normal file
719
src/OpenFOAM/db/dictionary/dictionarySearch.C
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#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<class WcIterator, class ReIterator>
|
||||
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<std::string>(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<const searcher&>(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<const searcher&>(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<dictionary*>(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<dictionary*>(&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<dictionary*>(&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<regExp>(new regExp(newKeyword))
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -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<T>(entryPtr->stream());
|
||||
return pTraits<T>(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<T>(entryPtr->stream());
|
||||
return pTraits<T>(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<T>(entryPtr->stream());
|
||||
return pTraits<T>(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<class T>
|
||||
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<class T>
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user