Cleaned up error handling by introducing the DAI_THROWE macro.
[libdai.git] / include / dai / properties.h
index 7b94a07..00efd07 100644 (file)
@@ -36,6 +36,8 @@
 #include <cassert>
 #include <typeinfo>
 #include <dai/exceptions.h>
+#include <dai/util.h>
+#include <boost/lexical_cast.hpp>
 
 
 namespace dai {
@@ -58,6 +60,16 @@ std::ostream& operator<< (std::ostream & os, const Property & p);
 /// Represents a set of properties, mapping keys (of type PropertyKey) to values (of type PropertyValue)
 class PropertySet : private std::map<PropertyKey, PropertyValue> {
     public:
+        /// Default constructor
+        PropertySet() {}
+
+        /// Construct PropertySet from a string
+        PropertySet( const std::string &s ) {
+            std::stringstream ss;
+            ss << s;
+            ss >> *this;
+        }
+
         /// Gets a property
         const PropertyValue & Get(const PropertyKey &key) const { 
             PropertySet::const_iterator x = find(key); 
@@ -72,15 +84,22 @@ class PropertySet : private std::map<PropertyKey, PropertyValue> {
         /// Sets a property
         PropertySet & Set(const PropertyKey &key, const PropertyValue &val) { this->operator[](key) = val; return *this; }
 
+        /// Set properties according to those in newProps, overriding properties that already exist with new values
+        PropertySet & Set( const PropertySet &newProps ) {
+            const std::map<PropertyKey, PropertyValue> *m = &newProps;
+            foreach(value_type i, *m)
+                Set( i.first, i.second );
+            return *this;
+        }
+
         /// Gets a property, casted as ValueType
         template<typename ValueType>
         ValueType GetAs(const PropertyKey &key) const {
             try {
                 return boost::any_cast<ValueType>(Get(key));
             } catch( const boost::bad_any_cast & ) {
-                std::cerr << "Cannot cast property " << key << " to ";
-                std::cerr << typeid(ValueType).name() << std::endl;
-                return boost::any_cast<ValueType>(Get(key));
+                DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property " + key + " to desired type.");
+                return ValueType();
             }
         }
 
@@ -90,13 +109,11 @@ class PropertySet : private std::map<PropertyKey, PropertyValue> {
             PropertyValue val = Get(key);
             if( val.type() != typeid(ValueType) ) {
                 assert( val.type() == typeid(std::string) );
-
-                std::stringstream ss;
-                ss << GetAs<std::string>(key);
-                ValueType result;
-                ss >> result;
-
-                Set(key, result);
+                try {
+                    Set(key, boost::lexical_cast<ValueType>(GetAs<std::string>(key)));
+                } catch(boost::bad_lexical_cast &) {
+                    DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property " + key + " from string to desired type.");
+                }
             }
         }
 
@@ -104,29 +121,26 @@ class PropertySet : private std::map<PropertyKey, PropertyValue> {
         template<typename ValueType>
         ValueType getStringAs(const PropertyKey &key) const { 
             PropertyValue val = Get(key);
-            if( val.type() == typeid(std::string) ) {
-                std::stringstream ss;
-                ss << GetAs<std::string>(key);
-                ValueType result;
-                ss >> result;
-                return result;
-            } else if( val.type() == typeid(ValueType) ) {
+            if( val.type() == typeid(ValueType) ) {
                 return boost::any_cast<ValueType>(val);
-            } else {
-                DAI_THROW(IMPOSSIBLE_TYPECAST);
-                return ValueType();
-            }
+            } else if( val.type() == typeid(std::string) ) {
+                try {
+                    return boost::lexical_cast<ValueType>(GetAs<std::string>(key));
+                } catch(boost::bad_lexical_cast &) {
+                    DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property " + key + " from string to desired type.");
+                }
+            } else
+                DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property " + key + " from string to desired type.");
+            return ValueType();
         }
 
         /// Converts a property from ValueType to string (if necessary)
         template<typename ValueType>
         PropertySet & setAsString(const PropertyKey &key, ValueType &val) { 
-            if( val.type() == typeid(std::string) ) {
-                return Set(key, val);
-            } else {
-                std::stringstream ss (std::stringstream::out);
-                ss << val;
-                return Set(key, ss.str());
+            try {
+                return Set( key, boost::lexical_cast<std::string>(val) );
+            } catch( boost::bad_lexical_cast & ) {
+                DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property " + key + " to string.");
             }
         }
 
@@ -136,6 +150,15 @@ class PropertySet : private std::map<PropertyKey, PropertyValue> {
         /// Check if a property with the given key exists
         bool hasKey(const PropertyKey &key) const { PropertySet::const_iterator x = find(key); return (x != this->end()); }
 
+        /// Returns a set containing all keys
+        std::set<PropertyKey> allKeys() const {
+            std::set<PropertyKey> res;
+            const_iterator i;
+            for( i = begin(); i != end(); i++ )
+                res.insert( i->first );
+            return res;
+        }
+
         // Friends
         friend std::ostream& operator<< (std::ostream & os, const PropertySet & ps);
         friend std::istream& operator>> (std::istream& is, PropertySet & ps);