Replaced the standard assert() macro by DAI_ASSERT
[libdai.git] / include / dai / properties.h
1 /* This file is part of libDAI - http://www.libdai.org/
2 *
3 * libDAI is licensed under the terms of the GNU General Public License version
4 * 2, or (at your option) any later version. libDAI is distributed without any
5 * warranty. See the file COPYING for more details.
6 *
7 * Copyright (C) 2006-2009 Joris Mooij [joris dot mooij at libdai dot org]
8 * Copyright (C) 2006-2007 Radboud University Nijmegen, The Netherlands
9 */
10
11
12 /// \file
13 /// \brief Defines the Property and PropertySet classes
14 /// \todo Improve documentation
15
16
17 #ifndef __defined_libdai_properties_h
18 #define __defined_libdai_properties_h
19
20
21 #include <iostream>
22 #include <sstream>
23 #include <boost/any.hpp>
24 #include <map>
25 #include <vector>
26 #include <typeinfo>
27 #include <dai/exceptions.h>
28 #include <dai/util.h>
29 #include <boost/lexical_cast.hpp>
30
31
32 namespace dai {
33
34
35 /// Type of the key of a Property
36 typedef std::string PropertyKey;
37
38 /// Type of the value of a Property
39 typedef boost::any PropertyValue;
40
41 /// A Property is a pair of a key and a corresponding value
42 typedef std::pair<PropertyKey, PropertyValue> Property;
43
44
45 /// Writes a Property object to an output stream
46 std::ostream& operator<< (std::ostream & os, const Property & p);
47
48
49 /// Represents a set of properties, mapping keys (of type PropertyKey) to values (of type PropertyValue)
50 class PropertySet : private std::map<PropertyKey, PropertyValue> {
51 public:
52 /// Default constructor
53 PropertySet() {}
54
55 /// Construct PropertySet from a string
56 PropertySet( const std::string &s ) {
57 std::stringstream ss;
58 ss << s;
59 ss >> *this;
60 }
61
62 /// Gets a property
63 const PropertyValue & Get(const PropertyKey &key) const {
64 PropertySet::const_iterator x = find(key);
65 if( x == this->end() )
66 DAI_THROWE(OBJECT_NOT_FOUND,"PropertySet::Get cannot find property '" + key + "'");
67 return x->second;
68 }
69
70 /// Sets a property
71 PropertySet & Set(const PropertyKey &key, const PropertyValue &val) { this->operator[](key) = val; return *this; }
72
73 /// Set properties according to those in newProps, overriding properties that already exist with new values
74 PropertySet & Set( const PropertySet &newProps ) {
75 const std::map<PropertyKey, PropertyValue> *m = &newProps;
76 foreach(value_type i, *m)
77 Set( i.first, i.second );
78 return *this;
79 }
80
81 /// Gets a property, casted as ValueType
82 template<typename ValueType>
83 ValueType GetAs(const PropertyKey &key) const {
84 try {
85 return boost::any_cast<ValueType>(Get(key));
86 } catch( const boost::bad_any_cast & ) {
87 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' to desired type.");
88 return ValueType();
89 }
90 }
91
92 /// Converts a property from string to ValueType (if necessary)
93 template<typename ValueType>
94 void ConvertTo(const PropertyKey &key) {
95 PropertyValue val = Get(key);
96 if( val.type() != typeid(ValueType) ) {
97 DAI_ASSERT( val.type() == typeid(std::string) );
98 try {
99 Set(key, boost::lexical_cast<ValueType>(GetAs<std::string>(key)));
100 } catch(boost::bad_lexical_cast &) {
101 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' from string to desired type.");
102 }
103 }
104 }
105
106 /// Converts a property from string to ValueType (if necessary)
107 template<typename ValueType>
108 ValueType getStringAs(const PropertyKey &key) const {
109 PropertyValue val = Get(key);
110 if( val.type() == typeid(ValueType) ) {
111 return boost::any_cast<ValueType>(val);
112 } else if( val.type() == typeid(std::string) ) {
113 try {
114 return boost::lexical_cast<ValueType>(GetAs<std::string>(key));
115 } catch(boost::bad_lexical_cast &) {
116 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' from string to desired type.");
117 }
118 } else
119 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' from string to desired type.");
120 return ValueType();
121 }
122
123 /// Converts a property from ValueType to string (if necessary)
124 template<typename ValueType>
125 PropertySet & setAsString(const PropertyKey &key, ValueType &val) {
126 try {
127 return Set( key, boost::lexical_cast<std::string>(val) );
128 } catch( boost::bad_lexical_cast & ) {
129 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' to string.");
130 }
131 }
132
133 /// Shorthand for (temporarily) adding properties, e.g. PropertySet p()("method","BP")("verbose",1)("tol",1e-9)
134 PropertySet operator()(const PropertyKey &key, const PropertyValue &val) const { PropertySet copy = *this; return copy.Set(key,val); }
135
136 /// Check if a property with the given key exists
137 bool hasKey(const PropertyKey &key) const { PropertySet::const_iterator x = find(key); return (x != this->end()); }
138
139 /// Returns a set containing all keys
140 std::set<PropertyKey> allKeys() const {
141 std::set<PropertyKey> res;
142 const_iterator i;
143 for( i = begin(); i != end(); i++ )
144 res.insert( i->first );
145 return res;
146 }
147
148 /// Returns a vector containing all keys
149 std::vector<PropertyKey> keys() const {
150 std::vector<PropertyKey> result;
151 result.reserve( size() );
152 for( PropertySet::const_iterator i = begin(); i != end(); ++i )
153 result.push_back( i->first );
154 return result;
155 }
156
157 /// Writes a PropertySet object to an output stream
158 friend std::ostream& operator<< (std::ostream & os, const PropertySet & ps);
159
160 /// Reads a PropertySet object from an input stream, storing values as strings
161 friend std::istream& operator>> (std::istream& is, PropertySet & ps);
162 };
163
164
165 } // end of namespace dai
166
167
168 #endif