1 /*
2  *  dict.h
3  *
4  *  This file is part of NEST.
5  *
6  *  Copyright (C) 2004 The NEST Initiative
7  *
8  *  NEST is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  NEST is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #ifndef DICT_H
24 #define DICT_H
25 /*
26     SLI's dictionary class
27 */
28 // C++ includes:
29 #include <map>
30 
31 // Includes from sli:
32 #include "name.h"
33 #include "sliexceptions.h"
34 #include "token.h"
35 
36 
37 typedef std::map< Name, Token, std::less< Name > > TokenMap;
38 
39 inline bool operator==( const TokenMap& x, const TokenMap& y )
40 {
41   return ( x.size() == y.size() ) && equal( x.begin(), x.end(), y.begin() );
42 }
43 
44 /** A class that associates names and tokens.
45  *  @ingroup TokenHandling
46  */
47 class Dictionary : private TokenMap
48 {
49   /**
50    * Helper class for lexicographical sorting of dictionary entries.
51    * Provides comparison operator for ascending, case-insensitive
52    * lexicographical ordering.
53    * @see This is a simplified version of the class presented in
54    * N.M.Josuttis, The C++ Standard Library, Addison Wesley, 1999,
55    * ch. 6.6.6.
56    */
57   class DictItemLexicalOrder
58   {
59   private:
60     static bool nocase_compare( char c1, char c2 );
61 
62   public:
operator()63     bool operator()( const std::pair< Name, Token >& lhs, const std::pair< Name, Token >& rhs ) const
64     {
65       const std::string& ls = lhs.first.toString();
66       const std::string& rs = rhs.first.toString();
67 
68       return std::lexicographical_compare( ls.begin(), ls.end(), rs.begin(), rs.end(), nocase_compare );
69     }
70   };
71 
72 public:
Dictionary()73   Dictionary()
74     : refs_on_dictstack_( 0 )
75   {
76   }
Dictionary(const Dictionary & d)77   Dictionary( const Dictionary& d )
78     : TokenMap( d )
79     , refs_on_dictstack_( 0 )
80   {
81   }
82   ~Dictionary();
83 
84   using TokenMap::erase;
85   using TokenMap::size;
86   using TokenMap::begin;
87   using TokenMap::end;
88   using TokenMap::iterator;
89   using TokenMap::find;
90 
91   void clear();
92 
93   /**
94    * Lookup and return Token with given name in dictionary.
95    * If the name is not found, an empty token is returned.
96    * This version of lookup is deprecated and will disappear in future versions.
97    * Please use lookup2() instead.
98    * @note The token returned should @b always  be stored as a
99    *       <tt>const \&</tt>, so that the control flag for
100    *       dictionary read-out is set on the Token in the dictionary,
101    *       not its copy.
102    */
103 
104   const Token& lookup( const Name& n ) const;
105 
106   /**
107    * lookup a name in the dictionary. If the name is not found an UndefinedName
108    * exception is thrown.
109    * lookup2 is the preferred way to retrieve entries from the dictionary.
110    * @note The token returned should @b always  be stored as a
111    *       <tt>const \&</tt>, so that the control flag for
112    *       dictionary read-out is set on the Token in the dictionary,
113    *       not its copy.
114    */
115   const Token& lookup2( const Name& n ) const; // throws UndefinedName
116   bool known( const Name& ) const;
117 
118   //! Returns true if name is known but token has not been accessed
119   bool known_but_not_accessed( const Name& ) const;
120 
121   Token& insert( const Name& n, const Token& t );
122   Token& insert_move( const Name&, Token& );
123 
124   //! Remove entry from dictionary
125   void remove( const Name& n );
126 
127   const Token& operator[]( const Name& ) const;
128   Token& operator[]( const Name& );
129   const Token& operator[]( const char* ) const;
130   Token& operator[]( const char* );
131 
132   bool
empty(void)133   empty( void ) const
134   {
135     return TokenMap::empty();
136   }
137 
138   void info( std::ostream& ) const;
139 
140   bool operator==( const Dictionary& d ) const
141   {
142     return ::operator==( *this, d );
143   }
144 
145   /**
146    * Add the contents of this dictionary to another.
147    * The target dictionary is given by names and must be retrieved via
148    * the interpreter.
149    * @todo Allow for free formatting of target dictionary entries
150    * via functor, and add traits to allow duplicates.
151    * @see remove_dict
152    */
153   void add_dict( const std::string&, SLIInterpreter& );
154 
155   /**
156    * Remove entries found in another dictionary from this.
157    * @see add_dict
158    */
159   void remove_dict( const std::string&, SLIInterpreter& );
160 
161   /**
162    * Clear access flags on all dictionary elements.
163    * Flags for nested dictionaries are cleared recursively.
164    * @see all_accessed()
165    */
166   void clear_access_flags();
167 
168   /**
169    * Check whether all elements have been accessed.
170    * Checks nested dictionaries recursively.
171    * @param std::string& contains string with names of non-accessed entries
172    * @returns true if all dictionary elements have been accessed
173    * @note this is just a wrapper, all_accessed_() does the work, hides
174    * recursion
175    * @see clear_access_flags(), all_accessed_()
176    */
177   bool
all_accessed(std::string & missed)178   all_accessed( std::string& missed ) const
179   {
180     return all_accessed_( missed );
181   }
182 
183   friend std::ostream& operator<<( std::ostream&, const Dictionary& );
184 
185   /**
186    * Constant iterator for dictionary.
187    * Dictionary inherits privately from std::map to hide implementation
188    * details. To allow for inspection of all elements in a dictionary,
189    * we export the constant iterator type and begin() and end() methods.
190    */
191   typedef TokenMap::const_iterator const_iterator;
192 
193   /**
194    * First element in dictionary.
195    * Dictionary inherits privately from std::map to hide implementation
196    * details. To allow for inspection of all elements in a dictionary,
197    * we export the constant iterator type and begin() and end() methods.
198    */
199   //  const_iterator begin() const;
200 
201   /**
202    * One-past-last element in dictionary.
203    * Dictionary inherits privately from std::map to hide implementation
204    * details. To allow for inspection of all elements in a dictionary,
205    * we export the constant iterator type and begin() and end() methods.
206    */
207   // const_iterator end() const;
208 
209   /**
210    *
211    */
212   void initialize_property_array( Name propname );
213 
214   /**
215    * This function is called when a dictionary is pushed to the dictionary
216    * stack. The dictioray stack must keep track about which dictioraries are on
217    * the dictionary stack. If a dictionary is modified and it is on the
218    * dictionary stack, the cache of the dictionary stack must
219    * be adjusted. This is e.g. the case for the systemdict or the errordict.
220    */
221   void
add_dictstack_reference()222   add_dictstack_reference()
223   {
224     ++refs_on_dictstack_;
225   }
226 
227   /**
228    * This function is called when the dictionary is popped from the dictionary
229    * stack.
230    */
231   void
remove_dictstack_reference()232   remove_dictstack_reference()
233   {
234     --refs_on_dictstack_;
235   }
236 
237   /**
238    * Returns true, if the dictionary has references on the dictionary stack.
239    */
240   bool
is_on_dictstack()241   is_on_dictstack() const
242   {
243     return refs_on_dictstack_ > 0;
244   }
245 
246 
247 private:
248   /**
249    * Worker function checking whether all elements have been accessed.
250    * Checks nested dictionaries recursively.
251    * @param std::string& contains string with names of non-accessed entries
252    * @param std::string prefix for nested dictionary entries, built during
253    * recursion
254    * @returns true if all dictionary elements have been accessed
255    * @note this is just the worker for all_accessed()
256    * @see clear_access_flags(), all_accessed()
257    */
258 
259   int refs_on_dictstack_;
260   bool all_accessed_( std::string&, std::string prefix = std::string() ) const;
261   static const Token VoidToken;
262 };
263 
264 inline const Token&
lookup(const Name & n)265 Dictionary::lookup( const Name& n ) const
266 {
267   TokenMap::const_iterator where = find( n );
268   if ( where != end() )
269   {
270     return ( *where ).second;
271   }
272   else
273   {
274     return Dictionary::VoidToken;
275   }
276 }
277 
278 inline const Token&
lookup2(const Name & n)279 Dictionary::lookup2( const Name& n ) const
280 {
281   TokenMap::const_iterator where = find( n );
282   if ( where != end() )
283   {
284     return ( *where ).second;
285   }
286   else
287   {
288     throw UndefinedName( n.toString() );
289   }
290 }
291 
292 inline bool
known(const Name & n)293 Dictionary::known( const Name& n ) const
294 {
295   TokenMap::const_iterator where = find( n );
296   if ( where != end() )
297   {
298     return true;
299   }
300   else
301   {
302     return false;
303   }
304 }
305 
306 inline bool
known_but_not_accessed(const Name & n)307 Dictionary::known_but_not_accessed( const Name& n ) const
308 {
309   TokenMap::const_iterator where = find( n );
310   if ( where != end() )
311   {
312     return not where->second.accessed();
313   }
314   else
315   {
316     return false;
317   }
318 }
319 
320 inline Token&
insert(const Name & n,const Token & t)321 Dictionary::insert( const Name& n, const Token& t )
322 {
323   return TokenMap::operator[]( n ) = t;
324 }
325 
326 
327 inline const Token& Dictionary::operator[]( const Name& n ) const
328 {
329   TokenMap::const_iterator where = find( n );
330   if ( where != end() )
331   {
332     return ( *where ).second;
333   }
334   else
335   {
336     throw UndefinedName( n.toString() );
337   }
338 }
339 
340 
341 inline Token& Dictionary::operator[]( const Name& n )
342 {
343   return TokenMap::operator[]( n );
344 }
345 
346 inline Token&
insert_move(const Name & n,Token & t)347 Dictionary::insert_move( const Name& n, Token& t )
348 {
349   Token& result = TokenMap::operator[]( n );
350   result.move( t );
351   return result;
352 }
353 
354 
355 #endif
356