1 /*
2  *  dict.cc
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 #include "dict.h"
24 
25 // C++ includes:
26 #include <algorithm>
27 #include <cstdlib>
28 #include <iomanip>
29 #include <string>
30 #include <vector>
31 
32 // Includes from sli:
33 #include "dictdatum.h"
34 #include "dictutils.h"
35 #include "sliexceptions.h"
36 
37 const Token Dictionary::VoidToken;
38 
~Dictionary()39 Dictionary::~Dictionary()
40 {
41 }
42 
operator [](const char * n) const43 const Token& Dictionary::operator[]( const char* n ) const
44 {
45   return operator[]( Name( n ) );
46 }
47 
operator [](const char * n)48 Token& Dictionary::operator[]( const char* n )
49 {
50   return operator[]( Name( n ) );
51 }
52 
53 void
clear()54 Dictionary::clear()
55 {
56   TokenMap cp( *this );
57   TokenMap::clear();
58 
59   for ( TokenMap::iterator i = cp.begin(); i != cp.end(); ++i )
60   {
61     Token* tok = &i->second;
62     Datum* datum = tok->datum();
63     DictionaryDatum* d = dynamic_cast< DictionaryDatum* >( datum );
64     if ( not d )
65     {
66       continue;
67     }
68 
69     Dictionary* dt = d->get();
70     d->unlock();
71     dt->clear();
72   }
73 }
74 
75 void
info(std::ostream & out) const76 Dictionary::info( std::ostream& out ) const
77 {
78   out.setf( std::ios::left );
79   if ( size() > 0 )
80   {
81     // copy to vector and sort
82     typedef std::vector< std::pair< Name, Token > > DataVec;
83     DataVec data;
84     std::copy( begin(), end(), std::inserter( data, data.begin() ) );
85     std::sort( data.begin(), data.end(), DictItemLexicalOrder() );
86 
87     out << "--------------------------------------------------" << std::endl;
88     out << std::setw( 25 ) << "Name" << std::setw( 20 ) << "Type"
89         << "Value" << std::endl;
90     out << "--------------------------------------------------" << std::endl;
91 
92     for ( DataVec::const_iterator where = data.begin(); where != data.end(); ++where )
93     {
94       out << std::setw( 25 ) << where->first << std::setw( 20 ) << where->second->gettypename() << where->second
95           << std::endl;
96     }
97     out << "--------------------------------------------------" << std::endl;
98   }
99   out << "Total number of entries: " << size() << std::endl;
100 
101   out.unsetf( std::ios::left );
102 }
103 
104 void
add_dict(const std::string & target,SLIInterpreter & i)105 Dictionary::add_dict( const std::string& target, SLIInterpreter& i )
106 {
107   DictionaryDatum targetdict;
108 
109   // retrieve targetdict from interpreter
110   Token d = i.baselookup( Name( target ) );
111   targetdict = getValue< DictionaryDatum >( d );
112 
113   for ( TokenMap::const_iterator it = TokenMap::begin(); it != TokenMap::end(); ++it )
114   {
115     if ( not targetdict->known( it->first ) )
116     {
117       targetdict->insert( it->first, it->second );
118     }
119     else
120     {
121       throw UndefinedName( ( it->first ).toString() );
122       //      throw DictError();
123     }
124   }
125 }
126 
127 void
remove(const Name & n)128 Dictionary::remove( const Name& n )
129 {
130   TokenMap::iterator it = find( n );
131   if ( it != end() )
132   {
133     erase( it );
134   }
135 }
136 
137 void
remove_dict(const std::string & target,SLIInterpreter & i)138 Dictionary::remove_dict( const std::string& target, SLIInterpreter& i )
139 {
140   DictionaryDatum targetdict;
141 
142   // retrieve targetdict from interpreter
143   Token d = i.baselookup( Name( target ) );
144   targetdict = getValue< DictionaryDatum >( d );
145 
146   for ( TokenMap::const_iterator it = TokenMap::begin(); it != TokenMap::end(); ++it )
147   {
148     TokenMap::iterator tgt_it = targetdict->find( it->first );
149     if ( tgt_it != targetdict->end() )
150     {
151       targetdict->erase( tgt_it );
152     }
153   }
154 }
155 
156 void
clear_access_flags()157 Dictionary::clear_access_flags()
158 {
159   for ( TokenMap::iterator it = TokenMap::begin(); it != TokenMap::end(); ++it )
160   {
161     /*
162        Clear flags in nested dictionaries recursively.
163        We first test whether the token is a DictionaryDatum
164        and then call getValue(). This entails two dynamic casts,
165        but is likely more efficient than a try-catch construction.
166     */
167     if ( it->second.is_a< DictionaryDatum >() )
168     {
169       DictionaryDatum subdict = getValue< DictionaryDatum >( it->second );
170       subdict->clear_access_flags();
171     }
172 
173     // in recursion, getValue sets the access flag for it->second, so
174     // we must clear it after recursion is done
175     it->second.clear_access_flag();
176   }
177 }
178 
179 bool
all_accessed_(std::string & missed,std::string prefix) const180 Dictionary::all_accessed_( std::string& missed, std::string prefix ) const
181 {
182   missed = "";
183 
184   // build list of all non-accessed Token names
185   for ( TokenMap::const_iterator it = TokenMap::begin(); it != TokenMap::end(); ++it )
186   {
187     if ( not it->second.accessed() )
188     {
189       missed = missed + " " + prefix + it->first.toString();
190     }
191     else if ( it->second.is_a< DictionaryDatum >() )
192     {
193       // recursively check if nested dictionary content was accessed
194       // see also comments in clear_access_flags()
195 
196       // this sets access flag on it->second, but that does not matter,
197       // since it is anyways set, otherwise we would not be recursing
198       DictionaryDatum subdict = getValue< DictionaryDatum >( it->second );
199 
200       subdict->all_accessed_( missed, prefix + it->first.toString() + "::" );
201     }
202   }
203 
204   return missed.empty();
205 }
206 
operator <<(std::ostream & out,const Dictionary & d)207 std::ostream& operator<<( std::ostream& out, const Dictionary& d )
208 {
209   out << "<<";
210 
211   for ( TokenMap::const_iterator where = d.begin(); where != d.end(); ++where )
212   {
213     out << ( *where ).first << ' ' << ( *where ).second << ',';
214   }
215   out << ">>";
216 
217   return out;
218 }
219 
220 bool
nocase_compare(char c1,char c2)221 Dictionary::DictItemLexicalOrder::nocase_compare( char c1, char c2 )
222 {
223   return std::toupper( c1 ) < std::toupper( c2 );
224 }
225