NEST main@caf0ae8
 
Loading...
Searching...
No Matches
dictionary.h
Go to the documentation of this file.
1/*
2 * dictionary.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 DICTIONARY_H
24#define DICTIONARY_H
25
26#include <concepts>
27#include <map>
28#include <memory>
29#include <string>
30#include <utility>
31#include <variant>
32#include <vector>
33
34#include "config.h"
35#include "exceptions.h"
36#include "logging.h"
37
38#ifdef HAVE_BOOST
39#include <boost/type_index.hpp>
40#endif
41
42namespace nest
43{
44class Parameter;
45class NodeCollection;
46}
47
63class dictionary_;
64class Dictionary;
65class AnyVector;
66struct EmptyList;
67
68
86template < typename... Scalars >
88{
89 template < typename... Extras >
90 using VariantType = std::variant< std::monostate, Scalars..., std::vector< Scalars >..., Extras... >;
91};
92
102
117 std::vector< std::vector< double > >,
118 std::vector< std::vector< std::vector< double > > >,
119 std::vector< std::vector< std::vector< long > > >,
120 std::shared_ptr< nest::Parameter >,
121 AnyVector,
123 EmptyList >;
124
137class AnyVector : public std::vector< any_type >
138{
139 using vectype_ = std::vector< any_type >;
140 using vectype_::vectype_; // Inherit constructors
141};
142
154{
155 bool operator==( const EmptyList& ) const = default;
156};
157
163std::ostream& operator<<( std::ostream& os, const EmptyList& );
164
170std::ostream& operator<<( std::ostream& os, const std::monostate& );
171
177std::ostream& operator<<( std::ostream& os, const AnyVector& av );
178
184std::ostream& operator<<( std::ostream& os, const Dictionary& dict );
185
191template < typename T >
192concept Integer = std::integral< T > and not std::same_as< T, bool > and not std::same_as< T, char >;
193
200template < typename T >
201concept DictionaryEntryType = std::is_constructible_v< any_type, T >;
202
212class Dictionary : public std::shared_ptr< dictionary_ >
213{
214public:
216 : std::shared_ptr< dictionary_ >( std::make_shared< dictionary_ >() )
217 {
218 }
219
220 any_type& operator[]( const std::string& key );
221 any_type& operator[]( std::string&& key );
222 any_type& at( const std::string& key );
223 const any_type& at( const std::string& key ) const;
224
233 bool operator==( const Dictionary& other ) const;
234
235 auto begin() const;
236 auto end() const;
237
238 auto size() const;
239 auto empty() const;
240 void clear();
241 auto find( const std::string& key ) const;
242
252 bool known( const std::string& key ) const;
253
259 void mark_as_accessed( const std::string& key ) const;
260
266 bool has_been_accessed( const std::string& key ) const;
267
274 void init_access_flags( const bool thread_local_dict = false ) const;
275
288 void
289 all_entries_accessed( const std::string& where, const std::string& what, const bool thread_local_dict = false ) const;
290
300 template < DictionaryEntryType T >
301 T get( const std::string& key ) const;
302
308 template < typename T >
309 std::vector< T >& get_or_create_vector( const std::string& key );
310
322 template < typename T >
323 bool update_value( const std::string& key, T& value ) const;
324
334 template < Integer T >
335 bool update_integer_value( const std::string& key, T& value ) const;
336
343 bool update_dictionary( Dictionary& dict_out ) const;
344};
345
352template < typename T >
353std::string
355{
356#ifdef HAVE_BOOST
357 return boost::typeindex::type_id< T >().pretty_name();
358#else
359 return typeid( T ).name();
360#endif
361}
362
368std::string get_typename( const any_type& operand );
369
375std::string get_dict_typenames( const Dictionary& dict );
376
383{
386 : item( any_type() )
387 , accessed( false )
388 {
389 }
390
392 : item( item )
393 , accessed( false )
394 {
395 }
396
397 bool
398 operator==( const DictEntry_& other ) const
399 {
400 return item == other.item;
401 }
402
404 mutable bool accessed;
405};
406
412class dictionary_ : public std::map< std::string, DictEntry_ >
413{
414 using maptype_ = std::map< std::string, DictEntry_ >;
415 using maptype_::maptype_; // Inherit constructors
416
426 template < typename T >
427 T
428 cast_value_( const any_type& value, const std::string& key ) const
429 {
430 try
431 {
432 return std::get< T >( value );
433 }
434 catch ( const std::bad_variant_access& )
435 {
436 std::string msg =
437 String::compose( "Failed to cast '%1' from %2 to type %3", key, get_typename( value ), pretty_typename< T >() );
438 throw nest::TypeMismatch( msg );
439 }
440 }
441
450 template < Integer RetT >
451 RetT
452 cast_to_integer_( const any_type& value, const std::string& key ) const
453 {
454 return std::visit(
455 [ key ]( auto&& arg ) -> RetT
456 {
457 using T = std::decay_t< decltype( arg ) >;
458
459 // Compile-time check: Is it an Integer?
460 if constexpr ( Integer< T > )
461 {
462 // Runtime check: Does the value fit safely?
463 if ( std::in_range< RetT >( arg ) )
464 {
465 return static_cast< RetT >( arg );
466 }
467
468 throw std::out_of_range( "Value causes data loss or overflow." );
469 }
470 else
471 {
472 throw std::runtime_error(
473 String::compose( "The dictionary value with key %1 does not hold a numeric integer type.", key ) );
474 }
475 },
476 value );
477 }
478
480 void register_access_( const DictEntry_& entry ) const;
481
482public:
486 template < DictionaryEntryType T >
487 T
488 get( const std::string& key ) const
489 {
490 return cast_value_< T >( at( key ), key );
491 }
492
496 template < typename T >
497 std::vector< T >&
498 get_or_create_vector( const std::string& key )
499 {
500 // try_emplace will only insert if key doesn't exist.
501 auto [ iter, success ] = maptype_::try_emplace( key, std::vector< T >() );
502
503 return std::get< std::vector< T > >( iter->second.item );
504 }
505
509 template < typename T >
510 bool
511 update_value( const std::string& key, T& value ) const
512 {
513 auto it = find( key );
514 if ( it != end() )
515 {
516 value = cast_value_< T >( it->second.item, key );
517 return true;
518 }
519 return false;
520 }
521
525 template < Integer T >
526 bool
527 update_integer_value( const std::string& key, T& value ) const
528 {
529 auto it = find( key );
530 if ( it != end() )
531 {
532 value = cast_to_integer_< T >( it->second.item, key );
533 return true;
534 }
535 return false;
536 }
537
541 bool
542 update_dictionary( Dictionary& dict_out ) const
543 {
544 for ( const auto& [ key, value ] : *this )
545 {
546 dict_out[ key ] = value.item;
547 }
548 return size() > 0;
549 }
550
554 bool
555 known( const std::string& key ) const
556 {
557 return maptype_::contains( key );
558 }
559
563 void
564 mark_as_accessed( const std::string& key ) const
565 {
566 register_access_( maptype_::at( key ) );
567 }
568
572 bool
573 has_been_accessed( const std::string& key ) const
574 {
575 return maptype_::at( key ).accessed;
576 }
577
581 bool operator==( const dictionary_& other ) const;
582
586 bool
587 operator!=( const dictionary_& other ) const
588 {
589 return not( *this == other );
590 }
591
595 void init_access_flags( const bool thread_local_dict = false ) const;
596
600 void
601 all_entries_accessed( const std::string& where, const std::string& what, const bool thread_local_dict = false ) const;
602
603 // Wrappers for access flags
604 any_type& operator[]( const std::string& key );
605 any_type& operator[]( std::string&& key );
606 any_type& at( const std::string& key );
607 const any_type& at( const std::string& key ) const;
608 iterator find( const std::string& key );
609 const_iterator find( const std::string& key ) const;
610};
611
612
614template <>
615double dictionary_::cast_value_< double >( const any_type& value, const std::string& key ) const;
616
617inline auto
619{
620 return ( *this )->begin();
621}
622
623inline auto
625{
626 return ( *this )->end();
627}
628
635template <>
636std::vector< double > dictionary_::cast_value_< std::vector< double > >( const any_type& value,
637 const std::string& key ) const;
638
642template <>
643std::vector< std::string > dictionary_::cast_value_< std::vector< std::string > >( const any_type& value,
644 const std::string& key ) const;
645
646inline bool
648{
649 return **this == *other;
650}
651
652inline auto
654{
655 return ( *this )->size();
656}
657
658inline auto
660{
661 return ( *this )->empty();
662}
663
664inline void
666{
667 ( *this )->clear();
668}
669
670inline auto
671Dictionary::find( const std::string& key ) const
672{
673 return ( *this )->find( key );
674}
675
676inline bool
677Dictionary::known( const std::string& key ) const
678{
679 return ( *this )->known( key );
680}
681
682inline void
683Dictionary::mark_as_accessed( const std::string& key ) const
684{
685 ( *this )->mark_as_accessed( key );
686}
687
688inline bool
689Dictionary::has_been_accessed( const std::string& key ) const
690{
691 return ( *this )->has_been_accessed( key );
692}
693
694inline void
695Dictionary::init_access_flags( const bool thread_local_dict ) const
696{
697 ( *this )->init_access_flags( thread_local_dict );
698}
699
700inline void
701Dictionary::all_entries_accessed( const std::string& where,
702 const std::string& what,
703 const bool thread_local_dict ) const
704{
705 ( *this )->all_entries_accessed( where, what, thread_local_dict );
706}
707
708template < DictionaryEntryType T >
709inline T
710Dictionary::get( const std::string& key ) const
711{
712 return ( *this )->get< T >( key );
713}
714template < typename T >
715std::vector< T >&
716Dictionary::get_or_create_vector( const std::string& key )
717{
718 return ( *this )->get_or_create_vector< T >( key );
719}
720
721template < typename T >
722inline bool
723Dictionary::update_value( const std::string& key, T& value ) const
724{
725 return ( *this )->update_value( key, value );
726}
727
728template < Integer T >
729inline bool
730Dictionary::update_integer_value( const std::string& key, T& value ) const
731{
732 return ( *this )->update_integer_value( key, value );
733}
734
735inline bool
737{
738 return ( *this )->update_dictionary( out_dict );
739}
740
741#endif /* DICTIONARY_H */
Vector of any_type.
Definition dictionary.h:138
std::vector< any_type > vectype_
Definition dictionary.h:139
Dictionary class for interface to Python and C++ API.
Definition dictionary.h:213
bool update_integer_value(const std::string &key, T &value) const
Update the specified value if there exists an integer value at key.
Definition dictionary.h:730
bool known(const std::string &key) const
Check whether there exists a value with specified key in the dictionary.
Definition dictionary.h:677
void mark_as_accessed(const std::string &key) const
Mark to support checking for unaccessed entries.
Definition dictionary.h:683
auto begin() const
Definition dictionary.h:618
void clear()
Definition dictionary.h:665
bool update_value(const std::string &key, T &value) const
Update the specified non-vector value if there exists a value at key.
Definition dictionary.h:723
any_type & operator[](const std::string &key)
Definition dictionary.cpp:57
void all_entries_accessed(const std::string &where, const std::string &what, const bool thread_local_dict=false) const
Confirm that all entries in dictionary have been accessed.
Definition dictionary.h:701
auto empty() const
Definition dictionary.h:659
bool update_dictionary(Dictionary &dict_out) const
Update the provided dictionary with all key-value pairs in this dictionary.
Definition dictionary.h:736
any_type & at(const std::string &key)
Definition dictionary.cpp:67
bool has_been_accessed(const std::string &key) const
Return true if mark_as_accessed has been called at least once for key.
Definition dictionary.h:689
auto end() const
Definition dictionary.h:624
std::vector< T > & get_or_create_vector(const std::string &key)
Return reference to vector of type T stored under key.
Definition dictionary.h:716
auto size() const
Definition dictionary.h:653
void init_access_flags(const bool thread_local_dict=false) const
Initialize access flags to prepare for later error checking with all_entries_accessed.
Definition dictionary.h:695
T get(const std::string &key) const
Get the value at key in the specified type.
Definition dictionary.h:710
Dictionary()
Definition dictionary.h:215
bool operator==(const Dictionary &other) const
Check whether the dictionary is equal to another dictionary.
Definition dictionary.h:647
auto find(const std::string &key) const
Definition dictionary.h:671
A Python-like dictionary_, based on std::map.
Definition dictionary.h:413
bool update_dictionary(Dictionary &dict_out) const
See Dictionary::update_dictionary.
Definition dictionary.h:542
T cast_value_(const any_type &value, const std::string &key) const
Cast the specified non-vector value to the specified type.
Definition dictionary.h:428
iterator find(const std::string &key)
Definition dictionary.cpp:357
any_type & at(const std::string &key)
Definition dictionary.cpp:339
void init_access_flags(const bool thread_local_dict=false) const
See Dictionary::init_access_flags.
Definition dictionary.cpp:379
RetT cast_to_integer_(const any_type &value, const std::string &key) const
Cast the specified value to an integer.
Definition dictionary.h:452
void all_entries_accessed(const std::string &where, const std::string &what, const bool thread_local_dict=false) const
See Dictionary::all_entries_accessedinit_access_flags.
Definition dictionary.cpp:392
std::map< std::string, DictEntry_ > maptype_
Definition dictionary.h:414
std::vector< T > & get_or_create_vector(const std::string &key)
See Dictionary::get_or_create_vector.
Definition dictionary.h:498
void mark_as_accessed(const std::string &key) const
See Dictionary::marked_as_accessed.
Definition dictionary.h:564
void register_access_(const DictEntry_ &entry) const
Mark dictionary entry as accessed.
Definition dictionary.cpp:309
bool update_integer_value(const std::string &key, T &value) const
See Dictionary::update_integer_value.
Definition dictionary.h:527
bool operator==(const dictionary_ &other) const
See Dictionary::operator==.
Definition dictionary.cpp:278
bool operator!=(const dictionary_ &other) const
See Dictionary::operator!=.
Definition dictionary.h:587
T get(const std::string &key) const
See Dictionary::get.
Definition dictionary.h:488
bool known(const std::string &key) const
See Dictionary::known.
Definition dictionary.h:555
bool has_been_accessed(const std::string &key) const
See Dictionary::has_been_accessed.
Definition dictionary.h:573
bool update_value(const std::string &key, T &value) const
See Dictionary::update_value.
Definition dictionary.h:511
any_type & operator[](const std::string &key)
Definition dictionary.cpp:321
Exception to be thrown if a given type does not match the expected type.
Definition exceptions.h:128
A concept for data types that can be stored in a Dictionary as any_type .
Definition dictionary.h:201
A concept for "integer integers", excluding bool and char.
Definition dictionary.h:192
std::string pretty_typename()
Return typename boost-prettified if available, otherwise as returned by typename().
Definition dictionary.h:354
DictionarySchema::VariantType< std::shared_ptr< nest::NodeCollection >, std::vector< std::vector< double > >, std::vector< std::vector< std::vector< double > > >, std::vector< std::vector< std::vector< long > > >, std::shared_ptr< nest::Parameter >, AnyVector, nest::VerbosityLevel, EmptyList > any_type
Complete any_type by adding specific data types.
Definition dictionary.h:123
std::ostream & operator<<(std::ostream &os, const EmptyList &)
Print EmptyList.
Definition dictionary.cpp:271
std::string get_dict_typenames(const Dictionary &dict)
Return multi-line string displaying dictionary content.
Definition dictionary.cpp:168
std::string get_typename(const any_type &operand)
Return typename of operand.
Definition dictionary.cpp:156
Namespace for the NEST simulation kernel.
Definition beta_normalization_factor.h:33
VerbosityLevel
Report only messages at levels higher than chosen level to user or logs. Default INFO.
Definition logging.h:40
Represent value in dictionary entry with access information.
Definition dictionary.h:383
bool accessed
initially false, set to true once entry is accessed
Definition dictionary.h:404
any_type item
actual item stored
Definition dictionary.h:403
bool operator==(const DictEntry_ &other) const
Definition dictionary.h:398
DictEntry_(const any_type &item)
Definition dictionary.h:391
DictEntry_()
Constructor without arguments needed by std::map::operator[].
Definition dictionary.h:385
Add a set of standard datatypes to any_type variant.
Definition dictionary.h:88
std::variant< std::monostate, Scalars..., std::vector< Scalars >..., Extras... > VariantType
Definition dictionary.h:90
Datatype to allow empty Python lists to be represented without defaulting to a datatype.
Definition dictionary.h:154
bool operator==(const EmptyList &) const =default