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:
Mark Olesen 2017-07-10 14:06:45 +02:00
parent b4b9303868
commit 971213eb55
7 changed files with 1399 additions and 763 deletions

View File

@ -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

View File

@ -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());
}

View File

@ -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.

View File

@ -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)

View 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;
}
// ************************************************************************* //

View File

@ -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));
}

View File

@ -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;
}