@@ -95,7 +95,7 @@ class dictionary : public std::map< std::string, DictEntry_ >
9595 using maptype_::maptype_; // Inherit constructors
9696
9797 /* *
98- * @brief Cast the specified value to the specified type.
98+ * @brief Cast the specified non-vector value to the specified type.
9999 *
100100 * @tparam T Type of element. If the value is not of the specified type, a TypeMismatch error is thrown.
101101 * @param value the any object to cast.
@@ -119,6 +119,44 @@ class dictionary : public std::map< std::string, DictEntry_ >
119119 }
120120 }
121121
122+ /* *
123+ * @brief Cast the specified vector value to the specified type.
124+ *
125+ * @tparam T Type of vector element. If the value is not of the specified type, a TypeMismatch error is thrown.
126+ * @param value the any object to cast.
127+ * @param key key where the value is located in the dictionary, for information upon cast errors.
128+ * @throws TypeMismatch if the value is not of specified type T.
129+ * @return value cast to the specified type.
130+ *
131+ * @note A dedicated cast_vector_value_() allows handling of empty vectors passed from the Python level.
132+ */
133+ template < typename T >
134+ std::vector< T >
135+ cast_vector_value_ ( const boost::any& value, const std::string& key ) const
136+ {
137+ // PyNEST passes vector with element type any if and only if it needs to pass
138+ // and empty vector, because the element type of empty lists cannot be inferred
139+ // at the Python level. The assertion just double-checks that we never get a
140+ // non-empty vector-of-any.
141+ if ( value.type () == typeid ( std::vector< boost::any > ) )
142+ {
143+ assert ( boost::any_cast< std::vector< boost::any > >( value ).empty () );
144+ return std::vector< T >();
145+ }
146+
147+ // Now handle vectors with elements
148+ try
149+ {
150+ return boost::any_cast< std::vector< T > >( value );
151+ }
152+ catch ( const boost::bad_any_cast& )
153+ {
154+ std::string msg = std::string ( " Failed to cast '" ) + key + " ' from " + debug_type ( value ) + " to type "
155+ + std::string ( boost::core::demangle ( typeid ( std::vector< T > ).name () ) );
156+ throw nest::TypeMismatch ( msg );
157+ }
158+ }
159+
122160 /* *
123161 * @brief Cast the specified value to an integer.
124162 *
@@ -180,7 +218,7 @@ class dictionary : public std::map< std::string, DictEntry_ >
180218 }
181219
182220 /* *
183- * @brief Update the specified value if there exists a value at key.
221+ * @brief Update the specified non-vector value if there exists a value at key.
184222 *
185223 * @param key key where the value may be located in the dictionary.
186224 * @param value object to update if there exists a value at key.
@@ -200,6 +238,29 @@ class dictionary : public std::map< std::string, DictEntry_ >
200238 return false ;
201239 }
202240
241+ /* *
242+ * @brief Update the specified vector value if there exists a value at key.
243+ *
244+ * @param key key where the value may be located in the dictionary.
245+ * @param value object to update if there exists a value at key.
246+ * @throws TypeMismatch if the value at key is not the same type as the value argument.
247+ * @return Whether value was updated.
248+ *
249+ * @note The specialisation for values that are vectors allows handling of empty vectors passed from the Python level.
250+ */
251+ template < typename T >
252+ bool
253+ update_value ( const std::string& key, std::vector< T >& value ) const
254+ {
255+ auto it = find ( key );
256+ if ( it != end () )
257+ {
258+ value = cast_vector_value_< T >( it->second .item , key );
259+ return true ;
260+ }
261+ return false ;
262+ }
263+
203264 /* *
204265 * @brief Update the specified value if there exists an integer value at key.
205266 *
0 commit comments