1
2//
3// This source file is part of appleseed.
4// Visit http://appleseedhq.net/ for additional information and resources.
5//
6// This software is released under the MIT license.
7//
8// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9// Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28//
29
30#ifndef APPLESEED_FOUNDATION_UTILITY_CONTAINERS_DICTIONARY_H
31#define APPLESEED_FOUNDATION_UTILITY_CONTAINERS_DICTIONARY_H
32
33// appleseed.foundation headers.
34#include "foundation/core/exceptions/stringexception.h"
35#include "foundation/utility/string.h"
36
37// appleseed.main headers.
38#include "main/dllsymbol.h"
39
40// Standard headers.
41#include <cstddef>
42#include <string>
43
44// Forward declarations.
45namespace foundation { class Dictionary; }
46
47namespace foundation
48{
49
50//
51// The exception thrown when accessing a non-existing dictionary key.
52//
53
54struct ExceptionDictionaryKeyNotFound
55 : public StringException
56{
57 explicit ExceptionDictionaryKeyNotFound(const char* key)
58 : StringException("dictionary key not found", key)
59 {
60 }
61};
62
63
64//
65// A string-to-string dictionary that can cross DLL boundaries.
66//
67
68class APPLESEED_DLLSYMBOL StringDictionary
69{
70 public:
71 class APPLESEED_DLLSYMBOL const_iterator
72 {
73 public:
74 // Value type.
75 typedef const_iterator value_type;
76
77 // Constructors.
78 const_iterator();
79 const_iterator(const const_iterator& rhs);
80
81 // Destructor.
82 ~const_iterator();
83
84 // Assignment operator.
85 const_iterator& operator=(const const_iterator& rhs);
86
87 // Equality and inequality tests.
88 bool operator==(const const_iterator& rhs) const;
89 bool operator!=(const const_iterator& rhs) const;
90
91 // Preincrement and predecrement operators.
92 const_iterator& operator++();
93 const_iterator& operator--();
94
95 // Dereference operator.
96 const value_type& operator*() const;
97
98 // Get the key of this item.
99 const char* key() const;
100
101 // Get the value of this item.
102 const char* value() const;
103 template <typename T> T value() const;
104
105 private:
106 friend class StringDictionary;
107
108 struct Impl;
109 Impl* impl;
110 };
111
112 // Constructors.
113 StringDictionary();
114 StringDictionary(const StringDictionary& rhs);
115
116 // Destructor.
117 ~StringDictionary();
118
119 // Assignment operator.
120 StringDictionary& operator=(const StringDictionary& rhs);
121
122 // Comparison operators.
123 bool operator==(const StringDictionary& rhs) const;
124 bool operator!=(const StringDictionary& rhs) const;
125
126 // Return the number of items in the dictionary.
127 size_t size() const;
128
129 // Return true if the dictionary is empty.
130 bool empty() const;
131
132 // Remove all items from the dictionary.
133 void clear();
134
135 // Insert an item into the dictionary, replacing the previous item if one exists for that key.
136 // Returns the dictionary itself to allow chaining of operations.
137 StringDictionary& insert(const char* key, const char* value);
138 template <typename T> StringDictionary& insert(const char* key, const T& value);
139 template <typename T> StringDictionary& insert(const std::string& key, const T& value);
140
141 // Set the value of an existing item.
142 // Returns the dictionary itself to allow chaining of operations.
143 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
144 StringDictionary& set(const char* key, const char* value);
145 template <typename T> StringDictionary& set(const char* key, const T& value);
146 template <typename T> StringDictionary& set(const std::string& key, const T& value);
147
148 // Retrieve an item from the dictionary.
149 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
150 const char* get(const char* key) const;
151 template <typename T> T get(const char* key) const;
152 template <typename T> T get(const std::string& key) const;
153
154 // Return true if an item with a given key exists in the dictionary.
155 bool exist(const char* key) const;
156 template <typename T> bool exist(const std::basic_string<T>& key) const;
157
158 // Remove an item from the dictionary, if it exists.
159 // Returns the dictionary itself to allow chaining of operations.
160 StringDictionary& remove(const char* key);
161 template <typename T> StringDictionary& remove(const std::basic_string<T>& key);
162
163 // Return constant begin and end input iterators.
164 const_iterator begin() const;
165 const_iterator end() const;
166
167 private:
168 struct Impl;
169 Impl* impl;
170};
171
172
173//
174// A string-to-dictionary dictionary that can cross DLL boundaries.
175//
176
177class APPLESEED_DLLSYMBOL DictionaryDictionary
178{
179 public:
180 class iterator;
181
182 // Constant iterator.
183 class APPLESEED_DLLSYMBOL const_iterator
184 {
185 public:
186 // Value type.
187 typedef const_iterator value_type;
188
189 // Constructors.
190 const_iterator();
191 const_iterator(const const_iterator& rhs);
192 const_iterator(const iterator& rhs);
193
194 // Destructor.
195 ~const_iterator();
196
197 // Assignment operator.
198 const_iterator& operator=(const const_iterator& rhs);
199
200 // Equality and inequality tests.
201 bool operator==(const const_iterator& rhs) const;
202 bool operator!=(const const_iterator& rhs) const;
203
204 // Preincrement and predecrement operators.
205 const_iterator& operator++();
206 const_iterator& operator--();
207
208 // Dereference operator.
209 const value_type& operator*() const;
210
211 // Get the key of this item.
212 const char* key() const;
213
214 // Get the value of this item.
215 const Dictionary& value() const;
216
217 private:
218 friend class DictionaryDictionary;
219
220 struct Impl;
221 Impl* impl;
222 };
223
224 // Mutable iterator.
225 class APPLESEED_DLLSYMBOL iterator
226 {
227 public:
228 // Value type.
229 typedef iterator value_type;
230
231 // Constructors.
232 iterator();
233 iterator(const iterator& rhs);
234
235 // Destructor.
236 ~iterator();
237
238 // Assignment operator.
239 iterator& operator=(const iterator& rhs);
240
241 // Equality and inequality tests.
242 bool operator==(const iterator& rhs) const;
243 bool operator!=(const iterator& rhs) const;
244
245 // Preincrement and predecrement operators.
246 iterator& operator++();
247 iterator& operator--();
248
249 // Dereference operator.
250 value_type& operator*();
251
252 // Get the key of this item.
253 const char* key() const;
254
255 // Get the value of this item.
256 Dictionary& value();
257
258 private:
259 friend class DictionaryDictionary;
260
261 struct Impl;
262 Impl* impl;
263 };
264
265 // Constructors.
266 DictionaryDictionary();
267 DictionaryDictionary(const DictionaryDictionary& rhs);
268
269 // Destructor.
270 ~DictionaryDictionary();
271
272 // Assignment operator.
273 DictionaryDictionary& operator=(const DictionaryDictionary& rhs);
274
275 // Comparison operators.
276 bool operator==(const DictionaryDictionary& rhs) const;
277 bool operator!=(const DictionaryDictionary& rhs) const;
278
279 // Return the number of items in the dictionary.
280 size_t size() const;
281
282 // Return true if the dictionary is empty.
283 bool empty() const;
284
285 // Remove all items from the dictionary.
286 void clear();
287
288 // Insert an item into the dictionary, replacing the previous item if one exists for that key.
289 // Returns the dictionary itself to allow chaining of operations.
290 DictionaryDictionary& insert(const char* key, const Dictionary& value);
291 template <typename T> DictionaryDictionary& insert(
292 const std::basic_string<T>& key,
293 const Dictionary& value);
294
295 // Set the value of an existing item.
296 // Returns the dictionary itself to allow chaining of operations.
297 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
298 DictionaryDictionary& set(const char* key, const Dictionary& value);
299 template <typename T> DictionaryDictionary& set(
300 const std::basic_string<T>& key,
301 const Dictionary& value);
302
303 // Retrieve an item from the dictionary.
304 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
305 Dictionary& get(const char* key);
306 const Dictionary& get(const char* key) const;
307 template <typename T> Dictionary& get(const std::basic_string<T>& key);
308 template <typename T> const Dictionary& get(const std::basic_string<T>& key) const;
309
310 // Return true if an item with a given key exists in the dictionary.
311 bool exist(const char* key) const;
312 template <typename T> bool exist(const std::basic_string<T>& key) const;
313
314 // Remove an item from the dictionary, if it exists.
315 // Returns the dictionary itself to allow chaining of operations.
316 DictionaryDictionary& remove(const char* key);
317 template <typename T> DictionaryDictionary& remove(const std::basic_string<T>& key);
318
319 // Return mutable begin and end input iterators.
320 iterator begin();
321 iterator end();
322
323 // Return constant begin and end input iterators.
324 const_iterator begin() const;
325 const_iterator end() const;
326
327 private:
328 struct Impl;
329 Impl* impl;
330};
331
332
333//
334// A dictionary that supports nesting and that can cross DLL boundaries.
335//
336
337class APPLESEED_DLLSYMBOL Dictionary
338{
339 public:
340 // Comparison operators.
341 bool operator==(const Dictionary& rhs) const;
342 bool operator!=(const Dictionary& rhs) const;
343
344 // Return the number of items in the dictionary.
345 size_t size() const;
346
347 // Return true if the dictionary is empty.
348 bool empty() const;
349
350 // Remove all items from the dictionary.
351 void clear();
352
353 // Insert an item into the dictionary, replacing the previous item if one exists for that key.
354 // Returns the dictionary itself to allow chaining of operations.
355 Dictionary& insert(const char* key, const char* value);
356 template <typename T> Dictionary& insert(const char* key, const T& value);
357 template <typename T> Dictionary& insert(const std::string& key, const T& value);
358
359 // Set the value of an existing item.
360 // Returns the dictionary itself to allow chaining of operations.
361 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
362 Dictionary& set(const char* key, const char* value);
363 template <typename T> Dictionary& set(const char* key, const T& value);
364 template <typename T> Dictionary& set(const std::string& key, const T& value);
365
366 // Retrieve a string item from the dictionary.
367 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
368 const char* get(const char* key) const;
369 template <typename T> T get(const char* key) const;
370 template <typename T> T get(const std::string& key) const;
371
372 // Access a child dictionary.
373 // Throws a ExceptionDictionaryKeyNotFound exception if the item could not be found.
374 Dictionary& dictionary(const char* key);
375 const Dictionary& dictionary(const char* key) const;
376 template <typename T> Dictionary& dictionary(const std::basic_string<T>& key);
377 template <typename T> const Dictionary& dictionary(const std::basic_string<T>& key) const;
378
379 // Access the string dictionary.
380 StringDictionary& strings();
381 const StringDictionary& strings() const;
382
383 // Access the dictionary dictionary.
384 DictionaryDictionary& dictionaries();
385 const DictionaryDictionary& dictionaries() const;
386
387 // Merge another dictionary into this one.
388 // Returns the dictionary itself to allow chaining of operations.
389 Dictionary& merge(const Dictionary& rhs);
390
391 private:
392 StringDictionary m_strings;
393 DictionaryDictionary m_dictionaries;
394};
395
396
397//
398// StringDictionary::const_iterator class implementation.
399//
400
401template <typename T>
402inline T StringDictionary::const_iterator::value() const
403{
404 return from_string<T>(value());
405}
406
407
408//
409// StringDictionary class implementation.
410//
411
412template <typename T>
413inline StringDictionary& StringDictionary::insert(const char* key, const T& value)
414{
415 return insert(key, to_string(value).c_str());
416}
417
418template <typename T>
419inline StringDictionary& StringDictionary::insert(const std::string& key, const T& value)
420{
421 return insert(key.c_str(), value);
422}
423
424template <typename T>
425inline StringDictionary& StringDictionary::set(const char* key, const T& value)
426{
427 return set(key, to_string(value).c_str());
428}
429
430template <typename T>
431inline StringDictionary& StringDictionary::set(const std::string& key, const T& value)
432{
433 return set(key.c_str(), value);
434}
435
436template <typename T>
437inline T StringDictionary::get(const char* key) const
438{
439 return from_string<T>(get(key));
440}
441
442template <typename T>
443inline T StringDictionary::get(const std::string& key) const
444{
445 return get<T>(key.c_str());
446}
447
448template <typename T>
449inline bool StringDictionary::exist(const std::basic_string<T>& key) const
450{
451 return exist(key.c_str());
452}
453
454template <typename T>
455inline StringDictionary& StringDictionary::remove(const std::basic_string<T>& key)
456{
457 return remove(key.c_str());
458}
459
460
461//
462// DictionaryDictionary class implementation.
463//
464
465template <typename T>
466inline DictionaryDictionary& DictionaryDictionary::insert(
467 const std::basic_string<T>& key,
468 const Dictionary& value)
469{
470 return insert(key.c_str(), value);
471}
472
473template <typename T>
474inline DictionaryDictionary& DictionaryDictionary::set(
475 const std::basic_string<T>& key,
476 const Dictionary& value)
477{
478 return set(key.c_str(), value);
479}
480
481template <typename T>
482inline Dictionary& DictionaryDictionary::get(const std::basic_string<T>& key)
483{
484 return get(key.c_str());
485}
486
487template <typename T>
488inline const Dictionary& DictionaryDictionary::get(const std::basic_string<T>& key) const
489{
490 return get(key.c_str());
491}
492
493template <typename T>
494inline bool DictionaryDictionary::exist(const std::basic_string<T>& key) const
495{
496 return exist(key.c_str());
497}
498
499template <typename T>
500inline DictionaryDictionary& DictionaryDictionary::remove(const std::basic_string<T>& key)
501{
502 return remove(key.c_str());
503}
504
505
506//
507// Dictionary class implementation.
508//
509
510inline bool Dictionary::operator==(const Dictionary& rhs) const
511{
512 return m_strings == rhs.m_strings && m_dictionaries == rhs.m_dictionaries;
513}
514
515inline bool Dictionary::operator!=(const Dictionary& rhs) const
516{
517 return !(*this == rhs);
518}
519
520inline size_t Dictionary::size() const
521{
522 return m_strings.size() + m_dictionaries.size();
523}
524
525inline bool Dictionary::empty() const
526{
527 return m_strings.empty() && m_dictionaries.empty();
528}
529
530inline void Dictionary::clear()
531{
532 m_strings.clear();
533 m_dictionaries.clear();
534}
535
536inline Dictionary& Dictionary::insert(const char* key, const char* value)
537{
538 m_strings.insert(key, value);
539 return *this;
540}
541
542template <typename T>
543inline Dictionary& Dictionary::insert(const char* key, const T& value)
544{
545 return insert(key, to_string(value).c_str());
546}
547
548template <>
549inline Dictionary& Dictionary::insert(const char* key, const Dictionary& value)
550{
551 m_dictionaries.insert(key, value);
552 return *this;
553}
554
555template <typename T>
556inline Dictionary& Dictionary::insert(const std::string& key, const T& value)
557{
558 return insert(key.c_str(), value);
559}
560
561inline Dictionary& Dictionary::set(const char* key, const char* value)
562{
563 m_strings.set(key, value);
564 return *this;
565}
566
567template <typename T>
568inline Dictionary& Dictionary::set(const char* key, const T& value)
569{
570 return set(key, to_string(value).c_str());
571}
572
573template <>
574inline Dictionary& Dictionary::set(const char* key, const Dictionary& value)
575{
576 m_dictionaries.set(key, value);
577 return *this;
578}
579
580template <typename T>
581inline Dictionary& Dictionary::set(const std::string& key, const T& value)
582{
583 return set(key.c_str(), value);
584}
585
586inline const char* Dictionary::get(const char* key) const
587{
588 return m_strings.get(key);
589}
590
591template <typename T>
592inline T Dictionary::get(const char* key) const
593{
594 return m_strings.get<T>(key);
595}
596
597template <typename T>
598inline T Dictionary::get(const std::string& key) const
599{
600 return m_strings.get<T>(key);
601}
602
603inline Dictionary& Dictionary::dictionary(const char* key)
604{
605 return m_dictionaries.get(key);
606}
607
608inline const Dictionary& Dictionary::dictionary(const char* key) const
609{
610 return m_dictionaries.get(key);
611}
612
613template <typename T>
614inline Dictionary& Dictionary::dictionary(const std::basic_string<T>& key)
615{
616 return m_dictionaries.get(key.c_str());
617}
618
619template <typename T>
620inline const Dictionary& Dictionary::dictionary(const std::basic_string<T>& key) const
621{
622 return m_dictionaries.get(key.c_str());
623}
624
625inline StringDictionary& Dictionary::strings()
626{
627 return m_strings;
628}
629
630inline const StringDictionary& Dictionary::strings() const
631{
632 return m_strings;
633}
634
635inline DictionaryDictionary& Dictionary::dictionaries()
636{
637 return m_dictionaries;
638}
639
640inline const DictionaryDictionary& Dictionary::dictionaries() const
641{
642 return m_dictionaries;
643}
644
645} // namespace foundation
646
647#endif // !APPLESEED_FOUNDATION_UTILITY_CONTAINERS_DICTIONARY_H
648