Dictionary.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef DRAIN_DICTIONARY
32 #define DRAIN_DICTIONARY "Dictionary v2.0"
33 
34 //
35 #include <iostream>
36 #include <map>
37 #include <list>
38 #include <string>
39 
40 //#include "Log.h"
41 #include <drain/Sprinter.h>
42 
43 
44 
45 namespace drain {
46 
48 
52 // TODO: consider map<K, V> for faster search and order? But no, if still slow.
53 
62 template <class K, class V>
63 class Dictionary : public std::list<std::pair<K, V> > {
64 
65 public:
66 
67  typedef K key_t;
68  typedef V value_t;
69 
70  typedef std::pair<K, V> entry_t;
71  typedef std::list<entry_t> container_t;
72 
73  typedef std::list<key_t> keylist_t;
74  typedef std::list<value_t> valuelist_t;
75 
76 
77  Dictionary() : separator(','){};
78 
79  Dictionary(const Dictionary & d) : separator(d.separator){};
80 
81  Dictionary(std::initializer_list<entry_t> d) : std::list<entry_t>(d), separator(','){
82  };
83 
84 
85  virtual
86  ~Dictionary(){};
87 
88  inline
89  const container_t & getContainer() const {
90  return *this;
91  }
92 
93  entry_t & add(const K & key, const V & value){
94  this->push_back(entry_t(key, value));
95  return this->back();
96  }
97 
99  entry_t & set(const K & key, const V & value){
100  for (entry_t & entry: *this){
101  if (entry.first == key){
102  entry.second = value;
103  return entry;
104  }
105  }
106  this->push_back(entry_t(key, value));
107  return this->back();
108  }
109 
110  const V & operator[](const K & key) const {
111  return getValue(key);
112  }
113 
114  const V & operator()(const V & value) const {
115  return getKey(value);
116  }
117 
118 
119  typename container_t::const_iterator findByKey(const K & key) const {
120  for (typename container_t::const_iterator it = this->begin(); it != this->end(); ++it){
121  if (it->first == key)
122  return it;
123  }
124  return this->end();
125  }
126 
127  typename container_t::const_iterator findByValue(const V & value) const {
128  for (typename container_t::const_iterator it = this->begin(); it != this->end(); ++it){
129  if (it->second == value)
130  return it;
131  }
132  return this->end();
133  }
134 
135 
136  inline
137  bool hasKey(const K & key) const {
138  return (findByKey(key) != this->end());
139  }
140 
142  inline
143  bool hasValue(const V & value) const {
144  return (findByValue(value) != this->end());
145  }
146 
147 
149  const V & getValue(const K & key, bool lenient=true) const {
150  typename container_t::const_iterator it = findByKey(key);
151  if (it != this->end())
152  return it->second;
153  else if (lenient){
154  static V empty;
155  return empty;
156  }
157  else {
158  drain::Sprinter::sequenceToStream(std::cerr, getContainer(), Sprinter::lineLayout);
159  throw std::runtime_error(drain::StringBuilder<>("key '", key, "' not found"));
160  }
161  }
162 
164 
172  const K & getKey(const V & value, bool lenient=true) const {
173  typename container_t::const_iterator it = findByValue(value);
174  if (it != this->end())
175  return it->first;
176  else if (lenient){
177  static K empty;
178  return empty;
179  }
180  else {
181  drain::Sprinter::sequenceToStream(std::cerr, getContainer(), Sprinter::lineLayout);
182  throw std::runtime_error(drain::StringBuilder<>("value '", value, "' not found"));
183  }
184  }
185 
186 
187  const keylist_t & getKeys() const {
188 
189  #pragma omp critical
190  {
191  keyList.clear();
192  for (const entry_t & entry: *this){
193  keyList.push_back(entry.first);
194  }
195  }
196  return keyList;
197  }
198 
199  void getKeys(keylist_t & l) const {
200  for (const entry_t & entry: *this){
201  l.push_back(entry.first);
202  }
203  }
204 
205 
206  const valuelist_t & getValues() const {
207 
208  #pragma omp critical
209  {
210  valueList.clear();
211  for (const entry_t & entry: *this){
212  valueList.push_back(entry.second);
213  }
214  }
215  return valueList;
216  }
217 
218  void getValues(keylist_t & l) const {
219  for (const entry_t & entry: *this){
220  l.push_back(entry.second);
221  }
222  }
223 
224  char separator;
225 
226 protected:
227 
228  mutable
229  keylist_t keyList;
230 
231  mutable
232  valuelist_t valueList;
233 
234 
235 };
236 
237 /*
238 template <class K, class V>
239 inline
240 std::ostream & operator<<(std::ostream & ostr, const Dictionary<K,V> & dict) {
241  dict.toStream(ostr);
242  return ostr;
243 }
244 */
245 
246 template <class K, class V>
247 inline
248 std::ostream & operator<<(std::ostream & ostr, const Dictionary<K,V> & dict) {
249  // SprinterLayout(const char *arrayChars="[,]", const char *mapChars="{,}", const char *pairChars="(,)", const char *stringChars=nullptr)
250  // static drain::SprinterLayout dict_layout("{,}", "{,}", "{,}", "{,}");
251  static const SprinterLayout cmdArgLayout = {",", "?", "=", ""};
252  // Note: the following cast is (also) the only way to apply layout on a Dictionary
253  //ostr << drain::sprinter(dict.getContainer(), Sprinter::cppLayout);
254  ostr << drain::sprinter(dict.getContainer(), cmdArgLayout);
255  //ostr << drain::sprinter((const typename Dictionary<K,V>::container_t &)dict, Sprinter::cppLayout);
256  return ostr;
257 }
258 
259 /*
260 template <>
261 inline
262 std::ostream & Sprinter::toStream(std::ostream & ostr, const drain::Variable & x, const SprinterLayout & layout){
263  return Sprinter::toStream(ostr, (const drain::Castable &)x, layout);
264 }
265 */
266 
267 
268 
270 template <class K, class V>
271 class DictionaryPtr : public Dictionary<K, V*> {
272 
273 public:
274 
275  typedef Dictionary<K, V*> parent_t;
276 
277  DictionaryPtr(){};
278 
279  virtual
280  ~DictionaryPtr(){};
281 
282  //virtual
283  void add(const K & key, const V & value){
284  Dictionary<K, V*>::add(key, &value);
285  }
286 
287  typename parent_t::container_t::const_iterator findByValue(const V & value) const {
288  return parent_t::findByValue(& value);
289  }
290 
291  //virtual
292  const V & getValue(const K & key) const {
293  return *Dictionary<K, V*>::getValue(key);
294  }
295 
296  //virtual
297  const K & getKey(const V & value) const {
298  return Dictionary<K, V*>::getKey(&value);
299  }
300 
301 
302 };
303 
304 } // drain::
305 
306 
307 #endif
308 
309 // Drain
Associates type info.
Definition: Dictionary.h:271
Two-way mapping between strings and objects of template class T.
Definition: Dictionary.h:63
const K & getKey(const V &value, bool lenient=true) const
Identity mapping useful for type deduction of template arguments in functions.
Definition: Dictionary.h:172
bool hasValue(const V &value) const
Given a key, return the first value associated with it.
Definition: Dictionary.h:143
entry_t & set(const K &key, const V &value)
Replaces existing or adds.
Definition: Dictionary.h:99
const V & getValue(const K &key, bool lenient=true) const
Given a key, return the first value associated with it.
Definition: Dictionary.h:149
static std::ostream & sequenceToStream(std::ostream &ostr, const T &x, const SprinterLayout &layout)
Convenience: if sequence type (array, list, set, map) not given, assume array.
Definition: Sprinter.h:321
static const SprinterLayout lineLayout
Put each array and object element on a separate line.
Definition: Sprinter.h:212
Definition: StringBuilder.h:58
Definition: DataSelector.cpp:1277