Forward compatibility: flex
[foam-extend-3.2.git] / src / foam / db / dictionary / dictionary.C
blob78e62682dbe0c763451b879106cef9e7db44f3ba
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "dictionary.H"
27 #include "primitiveEntry.H"
28 #include "dictionaryEntry.H"
29 #include "regExp.H"
30 #include "OSHA1stream.H"
32 /* * * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * */
34 defineTypeNameAndDebug(Foam::dictionary, 0);
36 const Foam::dictionary Foam::dictionary::null;
39 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
41 bool Foam::dictionary::findInPatterns
43     const bool patternMatch,
44     const word& Keyword,
45     DLList<entry*>::const_iterator& wcLink,
46     DLList<autoPtr<regExp> >::const_iterator& reLink
47 ) const
49     if (patternEntries_.size())
50     {
51         while (wcLink != patternEntries_.end())
52         {
53             if
54             (
55                 patternMatch
56               ? reLink()->match(Keyword)
57               : wcLink()->keyword() == Keyword
58             )
59             {
60                 return true;
61             }
63             ++reLink;
64             ++wcLink;
65         }
66     }
68     return false;
72 bool Foam::dictionary::findInPatterns
74     const bool patternMatch,
75     const word& Keyword,
76     DLList<entry*>::iterator& wcLink,
77     DLList<autoPtr<regExp> >::iterator& reLink
80     if (patternEntries_.size())
81     {
82         while (wcLink != patternEntries_.end())
83         {
84             if
85             (
86                 patternMatch
87               ? reLink()->match(Keyword)
88               : wcLink()->keyword() == Keyword
89             )
90             {
91                 return true;
92             }
94             ++reLink;
95             ++wcLink;
96         }
97     }
99     return false;
103 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
105 Foam::dictionary::dictionary()
107     parent_(dictionary::null)
111 Foam::dictionary::dictionary(const fileName& name)
113     dictionaryName(name),
114     parent_(dictionary::null)
118 Foam::dictionary::dictionary
120     const dictionary& parentDict,
121     const dictionary& dict
124     dictionaryName(dict.name()),
125     IDLList<entry>(dict, *this),
126     parent_(parentDict)
128     forAllIter(IDLList<entry>, *this, iter)
129     {
130         hashedEntries_.insert(iter().keyword(), &iter());
132         if (iter().keyword().isPattern())
133         {
134             patternEntries_.insert(&iter());
135             patternRegexps_.insert
136             (
137                 autoPtr<regExp>(new regExp(iter().keyword()))
138             );
139         }
140     }
144 Foam::dictionary::dictionary
146     const dictionary& dict
149     dictionaryName(dict.name()),
150     IDLList<entry>(dict, *this),
151     parent_(dictionary::null)
153     forAllIter(IDLList<entry>, *this, iter)
154     {
155         hashedEntries_.insert(iter().keyword(), &iter());
157         if (iter().keyword().isPattern())
158         {
159             patternEntries_.insert(&iter());
160             patternRegexps_.insert
161             (
162                 autoPtr<regExp>(new regExp(iter().keyword()))
163             );
164         }
165     }
169 Foam::dictionary::dictionary
171     const dictionary* dictPtr
174     parent_(dictionary::null)
176     if (dictPtr)
177     {
178         operator=(*dictPtr);
179     }
183 Foam::dictionary::dictionary
185     const dictionary& parentDict,
186     const Xfer<dictionary>& dict
189     parent_(parentDict)
191     transfer(dict());
192     name() = parentDict.name() + "::" + name();
196 Foam::dictionary::dictionary
198     const Xfer<dictionary>& dict
201     parent_(dictionary::null)
203     transfer(dict());
207 Foam::autoPtr<Foam::dictionary> Foam::dictionary::clone() const
209     return autoPtr<dictionary>(new dictionary(*this));
213 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
215 Foam::dictionary::~dictionary()
217     // cerr<< "~dictionary() " << name() << " " << long(this) << std::endl;
221 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
223 Foam::label Foam::dictionary::startLineNumber() const
225     if (size())
226     {
227         return first()->startLineNumber();
228     }
229     else
230     {
231         return -1;
232     }
236 Foam::label Foam::dictionary::endLineNumber() const
238     if (size())
239     {
240         return last()->endLineNumber();
241     }
242     else
243     {
244         return -1;
245     }
249 Foam::SHA1Digest Foam::dictionary::digest() const
251     OSHA1stream os;
253     // process entries
254     forAllConstIter(IDLList<entry>, *this, iter)
255     {
256         os << *iter;
257     }
259     return os.digest();
263 bool Foam::dictionary::found(const word& keyword, bool recursive) const
265     if (hashedEntries_.found(keyword))
266     {
267         return true;
268     }
269     else
270     {
271         if (patternEntries_.size())
272         {
273             DLList<entry*>::const_iterator wcLink =
274                 patternEntries_.begin();
275             DLList<autoPtr<regExp> >::const_iterator reLink =
276                 patternRegexps_.begin();
278             // Find in patterns using regular expressions only
279             if (findInPatterns(true, keyword, wcLink, reLink))
280             {
281                 return true;
282             }
283         }
285         if (recursive && &parent_ != &dictionary::null)
286         {
287             return parent_.found(keyword, recursive);
288         }
289         else
290         {
291             return false;
292         }
293     }
297 const Foam::entry* Foam::dictionary::lookupEntryPtr
299     const word& keyword,
300     bool recursive,
301     bool patternMatch
302 ) const
304     HashTable<entry*>::const_iterator iter = hashedEntries_.find(keyword);
306     if (iter == hashedEntries_.end())
307     {
308         if (patternMatch && patternEntries_.size())
309         {
310             DLList<entry*>::const_iterator wcLink =
311                 patternEntries_.begin();
312             DLList<autoPtr<regExp> >::const_iterator reLink =
313                 patternRegexps_.begin();
315             // Find in patterns using regular expressions only
316             if (findInPatterns(patternMatch, keyword, wcLink, reLink))
317             {
318                 return wcLink();
319             }
320         }
322         if (recursive && &parent_ != &dictionary::null)
323         {
324             return parent_.lookupEntryPtr(keyword, recursive, patternMatch);
325         }
326         else
327         {
328             return NULL;
329         }
330     }
332     return iter();
336 Foam::entry* Foam::dictionary::lookupEntryPtr
338     const word& keyword,
339     bool recursive,
340     bool patternMatch
343     HashTable<entry*>::iterator iter = hashedEntries_.find(keyword);
345     if (iter == hashedEntries_.end())
346     {
347         if (patternMatch && patternEntries_.size())
348         {
349             DLList<entry*>::iterator wcLink =
350                 patternEntries_.begin();
351             DLList<autoPtr<regExp> >::iterator reLink =
352                 patternRegexps_.begin();
354             // Find in patterns using regular expressions only
355             if (findInPatterns(patternMatch, keyword, wcLink, reLink))
356             {
357                 return wcLink();
358             }
359         }
361         if (recursive && &parent_ != &dictionary::null)
362         {
363             return const_cast<dictionary&>(parent_).lookupEntryPtr
364             (
365                 keyword,
366                 recursive,
367                 patternMatch
368             );
369         }
370         else
371         {
372             return NULL;
373         }
374     }
376     return iter();
380 const Foam::entry& Foam::dictionary::lookupEntry
382     const word& keyword,
383     bool recursive,
384     bool patternMatch
385 ) const
387     const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
389     if (entryPtr == NULL)
390     {
391         FatalIOErrorIn
392         (
393             "dictionary::lookupEntry(const word&, bool, bool) const",
394             *this
395         )   << "keyword " << keyword << " is undefined in dictionary "
396             << name()
397             << exit(FatalIOError);
398     }
400     return *entryPtr;
404 Foam::ITstream& Foam::dictionary::lookup
406     const word& keyword,
407     bool recursive,
408     bool patternMatch
409 ) const
411     return lookupEntry(keyword, recursive, patternMatch).stream();
415 bool Foam::dictionary::isDict(const word& keyword) const
417     // Find non-recursive with patterns
418     const entry* entryPtr = lookupEntryPtr(keyword, false, true);
420     if (entryPtr)
421     {
422         return entryPtr->isDict();
423     }
424     else
425     {
426         return false;
427     }
431 const Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword) const
433     const entry* entryPtr = lookupEntryPtr(keyword, false, true);
435     if (entryPtr)
436     {
437         return &entryPtr->dict();
438     }
439     else
440     {
441         return NULL;
442     }
446 const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
448     const entry* entryPtr = lookupEntryPtr(keyword, false, true);
450     if (entryPtr == NULL)
451     {
452         FatalIOErrorIn
453         (
454             "dictionary::subDict(const word& keyword) const",
455             *this
456         )   << "keyword " << keyword << " is undefined in dictionary "
457             << name()
458             << exit(FatalIOError);
459     }
460     return entryPtr->dict();
464 Foam::dictionary& Foam::dictionary::subDict(const word& keyword)
466     entry* entryPtr = lookupEntryPtr(keyword, false, true);
468     if (entryPtr == NULL)
469     {
470         FatalIOErrorIn
471         (
472             "dictionary::subDict(const word& keyword)",
473             *this
474         )   << "keyword " << keyword << " is undefined in dictionary "
475             << name()
476             << exit(FatalIOError);
477     }
478     return entryPtr->dict();
482 Foam::dictionary Foam::dictionary::subOrEmptyDict
484     const word& keyword
485 ) const
487     const entry* entryPtr = lookupEntryPtr(keyword, false, true);
489     if (entryPtr == NULL)
490     {
491         return dictionary(*this, dictionary(name() + "::" + keyword));
492     }
493     else
494     {
495         return entryPtr->dict();
496     }
500 Foam::wordList Foam::dictionary::toc() const
502     wordList keys(size());
504     label nKeys = 0;
505     forAllConstIter(IDLList<entry>, *this, iter)
506     {
507         keys[nKeys++] = iter().keyword();
508     }
510     return keys;
514 Foam::List<Foam::keyType> Foam::dictionary::keys(bool patterns) const
516     List<keyType> keys(size());
518     label nKeys = 0;
519     forAllConstIter(IDLList<entry>, *this, iter)
520     {
521         if (iter().keyword().isPattern() ? patterns : !patterns)
522         {
523             keys[nKeys++] = iter().keyword();
524         }
525     }
526     keys.setSize(nKeys);
528     return keys;
532 bool Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
534     HashTable<entry*>::iterator iter = hashedEntries_.find
535     (
536         entryPtr->keyword()
537     );
539     if (mergeEntry && iter != hashedEntries_.end())
540     {
541         // merge dictionary with dictionary
542         if (iter()->isDict() && entryPtr->isDict())
543         {
544             iter()->dict().merge(entryPtr->dict());
545             delete entryPtr;
547             return true;
548         }
549         else
550         {
551             // replace existing dictionary with entry or vice versa
552             IDLList<entry>::replace(iter(), entryPtr);
553             delete iter();
554             hashedEntries_.erase(iter);
556             if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
557             {
558                 entryPtr->name() = name() + "::" + entryPtr->keyword();
560                 if (entryPtr->keyword().isPattern())
561                 {
562                     patternEntries_.insert(entryPtr);
563                     patternRegexps_.insert
564                     (
565                         autoPtr<regExp>(new regExp(entryPtr->keyword()))
566                     );
567                 }
569                 return true;
570             }
571             else
572             {
573                 IOWarningIn("dictionary::add(entry*, bool)", (*this))
574                     << "problem replacing entry "<< entryPtr->keyword()
575                     << " in dictionary " << name() << endl;
577                 IDLList<entry>::remove(entryPtr);
578                 delete entryPtr;
579                 return false;
580             }
581         }
582     }
584     if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
585     {
586         entryPtr->name() = name() + "::" + entryPtr->keyword();
587         IDLList<entry>::append(entryPtr);
589         if (entryPtr->keyword().isPattern())
590         {
591             patternEntries_.insert(entryPtr);
592             patternRegexps_.insert
593             (
594                 autoPtr<regExp>(new regExp(entryPtr->keyword()))
595             );
596         }
598         return true;
599     }
600     else
601     {
602         IOWarningIn("dictionary::add(entry*, bool)", (*this))
603             << "attempt to add entry "<< entryPtr->keyword()
604             << " which already exists in dictionary " << name()
605             << endl;
607         delete entryPtr;
608         return false;
609     }
613 void Foam::dictionary::add(const entry& e, bool mergeEntry)
615     add(e.clone(*this).ptr(), mergeEntry);
619 void Foam::dictionary::add(const keyType& k, const word& w, bool overwrite)
621     add(new primitiveEntry(k, token(w)), overwrite);
625 void Foam::dictionary::add
627     const keyType& k,
628     const Foam::string& s,
629     bool overwrite
632     add(new primitiveEntry(k, token(s)), overwrite);
636 void Foam::dictionary::add(const keyType& k, const label l, bool overwrite)
638     add(new primitiveEntry(k, token(l)), overwrite);
642 void Foam::dictionary::add(const keyType& k, const scalar s, bool overwrite)
644     add(new primitiveEntry(k, token(s)), overwrite);
648 void Foam::dictionary::add
650     const keyType& k,
651     const dictionary& d,
652     bool mergeEntry
655     add(new dictionaryEntry(k, *this, d), mergeEntry);
659 void Foam::dictionary::set(entry* entryPtr)
661     entry* existingPtr = lookupEntryPtr(entryPtr->keyword(), false, true);
663     // clear dictionary so merge acts like overwrite
664     if (existingPtr && existingPtr->isDict())
665     {
666         existingPtr->dict().clear();
667     }
668     add(entryPtr, true);
672 void Foam::dictionary::set(const entry& e)
674     set(e.clone(*this).ptr());
678 void Foam::dictionary::set(const keyType& k, const dictionary& d)
680     set(new dictionaryEntry(k, *this, d));
684 bool Foam::dictionary::remove(const word& Keyword)
686     HashTable<entry*>::iterator iter = hashedEntries_.find(Keyword);
688     if (iter != hashedEntries_.end())
689     {
690         // Delete from patterns first
691         DLList<entry*>::iterator wcLink =
692             patternEntries_.begin();
693         DLList<autoPtr<regExp> >::iterator reLink =
694             patternRegexps_.begin();
696         // Find in pattern using exact match only
697         if (findInPatterns(false, Keyword, wcLink, reLink))
698         {
699             patternEntries_.remove(wcLink);
700             patternRegexps_.remove(reLink);
701         }
703         IDLList<entry>::remove(iter());
704         delete iter();
705         hashedEntries_.erase(iter);
707         return true;
708     }
709     else
710     {
711         return false;
712     }
716 bool Foam::dictionary::changeKeyword
718     const keyType& oldKeyword,
719     const keyType& newKeyword,
720     bool forceOverwrite
723     // no change
724     if (oldKeyword == newKeyword)
725     {
726         return false;
727     }
729     HashTable<entry*>::iterator iter = hashedEntries_.find(oldKeyword);
731     // oldKeyword not found - do nothing
732     if (iter == hashedEntries_.end())
733     {
734         return false;
735     }
737     if (iter()->keyword().isPattern())
738     {
739         FatalErrorIn
740         (
741             "dictionary::changeKeyword(const word&, const word&, bool)"
742         )   << "Old keyword "<< oldKeyword
743             << " is a pattern."
744             << "Pattern replacement not yet implemented."
745             << exit(FatalError);
746     }
749     HashTable<entry*>::iterator iter2 = hashedEntries_.find(newKeyword);
751     // newKeyword already exists
752     if (iter2 != hashedEntries_.end())
753     {
754         if (forceOverwrite)
755         {
756             if (iter2()->keyword().isPattern())
757             {
758                 // Delete from patterns first
759                 DLList<entry*>::iterator wcLink =
760                     patternEntries_.begin();
761                 DLList<autoPtr<regExp> >::iterator reLink =
762                     patternRegexps_.begin();
764                 // Find in patterns using exact match only
765                 if (findInPatterns(false, iter2()->keyword(), wcLink, reLink))
766                 {
767                     patternEntries_.remove(wcLink);
768                     patternRegexps_.remove(reLink);
769                 }
770             }
772             IDLList<entry>::replace(iter2(), iter());
773             delete iter2();
774             hashedEntries_.erase(iter2);
776         }
777         else
778         {
779             WarningIn
780             (
781                 "dictionary::changeKeyword(const word&, const word&, bool)"
782             )   << "cannot rename keyword "<< oldKeyword
783                 << " to existing keyword " << newKeyword
784                 << " in dictionary " << name() << endl;
785             return false;
786         }
787     }
789     // change name and HashTable, but leave DL-List untouched
790     iter()->keyword() = newKeyword;
791     iter()->name() = name() + "::" + newKeyword;
792     hashedEntries_.erase(oldKeyword);
793     hashedEntries_.insert(newKeyword, iter());
795     if (newKeyword.isPattern())
796     {
797         patternEntries_.insert(iter());
798         patternRegexps_.insert
799         (
800             autoPtr<regExp>(new regExp(newKeyword))
801         );
802     }
804     return true;
808 bool Foam::dictionary::merge(const dictionary& dict)
810     // Check for assignment to self
811     if (this == &dict)
812     {
813         FatalErrorIn("dictionary::merge(const dictionary&)")
814             << "attempted merge to self for dictionary " << name()
815             << abort(FatalError);
816     }
818     bool changed = false;
820     forAllConstIter(IDLList<entry>, dict, iter)
821     {
822         HashTable<entry*>::iterator fnd = hashedEntries_.find(iter().keyword());
824         if (fnd != hashedEntries_.end())
825         {
826             // Recursively merge sub-dictionaries
827             // TODO: merge without copying
828             if (fnd()->isDict() && iter().isDict())
829             {
830                 if (fnd()->dict().merge(iter().dict()))
831                 {
832                     changed = true;
833                 }
834             }
835             else
836             {
837                 add(iter().clone(*this).ptr(), true);
838                 changed = true;
839             }
840         }
841         else
842         {
843             // not found - just add
844             add(iter().clone(*this).ptr());
845             changed = true;
846         }
847     }
849     return changed;
853 void Foam::dictionary::clear()
855     IDLList<entry>::clear();
856     hashedEntries_.clear();
857     patternEntries_.clear();
858     patternRegexps_.clear();
862 void Foam::dictionary::transfer(dictionary& dict)
864     // changing parents probably doesn't make much sense,
865     // but what about the names?
866     name() = dict.name();
868     IDLList<entry>::transfer(dict);
869     hashedEntries_.transfer(dict.hashedEntries_);
870     patternEntries_.transfer(dict.patternEntries_);
871     patternRegexps_.transfer(dict.patternRegexps_);
875 Foam::Xfer<Foam::dictionary> Foam::dictionary::xfer()
877     return xferMove(*this);
881 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
883 Foam::ITstream& Foam::dictionary::operator[](const word& keyword) const
885     return lookup(keyword);
889 void Foam::dictionary::operator=(const dictionary& rhs)
891     // Check for assignment to self
892     if (this == &rhs)
893     {
894         FatalErrorIn("dictionary::operator=(const dictionary&)")
895             << "attempted assignment to self for dictionary " << name()
896             << abort(FatalError);
897     }
899     name() = rhs.name();
900     clear();
902     // Create clones of the entries in the given dictionary
903     // resetting the parentDict to this dictionary
905     forAllConstIter(IDLList<entry>, rhs, iter)
906     {
907         add(iter().clone(*this).ptr());
908     }
912 void Foam::dictionary::operator+=(const dictionary& rhs)
914     // Check for assignment to self
915     if (this == &rhs)
916     {
917         FatalErrorIn("dictionary::operator+=(const dictionary&)")
918             << "attempted addition assignment to self for dictionary " << name()
919             << abort(FatalError);
920     }
922     forAllConstIter(IDLList<entry>, rhs, iter)
923     {
924         add(iter().clone(*this).ptr());
925     }
929 void Foam::dictionary::operator|=(const dictionary& rhs)
931     // Check for assignment to self
932     if (this == &rhs)
933     {
934         FatalErrorIn("dictionary::operator|=(const dictionary&)")
935             << "attempted assignment to self for dictionary " << name()
936             << abort(FatalError);
937     }
939     forAllConstIter(IDLList<entry>, rhs, iter)
940     {
941         if (!found(iter().keyword()))
942         {
943             add(iter().clone(*this).ptr());
944         }
945     }
949 void Foam::dictionary::operator<<=(const dictionary& rhs)
951     // Check for assignment to self
952     if (this == &rhs)
953     {
954         FatalErrorIn("dictionary::operator<<=(const dictionary&)")
955             << "attempted assignment to self for dictionary " << name()
956             << abort(FatalError);
957     }
959     forAllConstIter(IDLList<entry>, rhs, iter)
960     {
961         set(iter().clone(*this).ptr());
962     }
966 /* * * * * * * * * * * * * * * * Global operators  * * * * * * * * * * * * * */
968 Foam::dictionary Foam::operator+
970     const dictionary& dict1,
971     const dictionary& dict2
974     dictionary sum(dict1);
975     sum += dict2;
976     return sum;
980 Foam::dictionary Foam::operator|
982     const dictionary& dict1,
983     const dictionary& dict2
986     dictionary sum(dict1);
987     sum |= dict2;
988     return sum;
992 // ************************************************************************* //