separate setValue() and setCurrentValue()

setValue() also updates the default value.
reset() reset to the default value.
setCurrentValue() only updates the current value, keeping current default.
Thus setCurrentValue() can be reverted (to default) using reset().
This commit is contained in:
Robert Haschke 2018-02-03 11:33:35 +01:00
parent d62b85572a
commit 59fe1e7860
2 changed files with 60 additions and 33 deletions

View File

@ -60,8 +60,12 @@ enum PropertyInitializerSource {
/** Property is a wrapper for a boost::any value, also providing a default value and a description. /** Property is a wrapper for a boost::any value, also providing a default value and a description.
* *
* Properties can be configured to be initialized from another PropertyMap. * Properties can be configured to be initialized from another PropertyMap - if still undefined.
* Potential sources are the properties of the parent of a stage, or the properties passed in the interface. * Potential sources are the properties of the parent of a stage, or the properties passed in the interface.
*
* Setting the value via setValue() updates both, the current value and the default value.
* Using reset() the default value can be restored.
* Using setCurrentValue() only updates the current value, allowing for later reset to the original default.
*/ */
class Property { class Property {
friend class PropertyMap; friend class PropertyMap;
@ -72,11 +76,23 @@ public:
Property(const std::type_index& type_index, const std::string& description, const boost::any& default_value); Property(const std::type_index& type_index, const std::string& description, const boost::any& default_value);
/// set current value and default value
void setValue(const boost::any& value); void setValue(const boost::any& value);
void setCurrentValue(const boost::any& value);
const boost::any& value() const; /// reset to default value (which can be empty)
void reset();
inline bool defined() const { return !value_.empty(); }
/// get current value
inline const boost::any& value() const { return value_; }
/// get default value
const boost::any& defaultValue() const { return default_; } const boost::any& defaultValue() const { return default_; }
/// get description text
const std::string& description() const { return description_; } const std::string& description() const { return description_; }
/// get typename
std::string typeName() const { return type_index_.name(); } std::string typeName() const { return type_index_.name(); }
/// configure initialization from source using an arbitrary function /// configure initialization from source using an arbitrary function
@ -84,6 +100,9 @@ public:
/// configure initialization from source using given other property name /// configure initialization from source using given other property name
Property &configureInitFrom(PropertyInitializerSource source, const std::string& name); Property &configureInitFrom(PropertyInitializerSource source, const std::string& name);
/// set current value using configured initializers
void performInitFrom(PropertyInitializerSource source, const PropertyMap& other);
private: private:
std::string description_; std::string description_;
std::type_index type_index_; std::type_index type_index_;
@ -127,8 +146,10 @@ public:
/// allow initialization from given source for listed properties - always using the same name /// allow initialization from given source for listed properties - always using the same name
void configureInitFrom(PropertyInitializerSource source, const std::set<std::string> &properties = {}); void configureInitFrom(PropertyInitializerSource source, const std::set<std::string> &properties = {});
/// set the value of a property /// set (and, if neccessary, declare) the value of a property
void set(const std::string& name, const boost::any& value); void set(const std::string& name, const boost::any& value);
/// temporarily set the value of a property
void setCurrent(const std::string& name, const boost::any& value);
/// get the value of a property /// get the value of a property
const boost::any& get(const std::string& name) const; const boost::any& get(const std::string& name) const;
@ -143,12 +164,11 @@ public:
/// count number of defined properties from given list /// count number of defined properties from given list
size_t countDefined(const std::vector<std::string>& list) const; size_t countDefined(const std::vector<std::string>& list) const;
/// reset properties to nil, if they have initializers /// reset all properties to their defaults
void reset(); void reset();
/// perform initialization of properties using configured initializers /// perform initialization of still undefined properties using configured initializers
void performInitFrom(PropertyInitializerSource source, const PropertyMap& other, void performInitFrom(PropertyInitializerSource source, const PropertyMap& other, bool enforce = false);
bool checkConsistency = false);
}; };
} // namespace task_constructor } // namespace task_constructor

View File

@ -48,6 +48,7 @@ Property::Property(const std::type_index& type_index, const std::string& descrip
: description_(description) : description_(description)
, type_index_(type_index) , type_index_(type_index)
, default_(default_value) , default_(default_value)
, value_(default_value)
{ {
if (!default_.empty() && std::type_index(default_.type()) != type_index_) if (!default_.empty() && std::type_index(default_.type()) != type_index_)
throw std::runtime_error("type of default value doesn't match declared type"); throw std::runtime_error("type of default value doesn't match declared type");
@ -64,16 +65,24 @@ void typeCheck(const boost::any& value, const std::type_index& type_index)
} }
void Property::setValue(const boost::any &value) { void Property::setValue(const boost::any &value) {
typeCheck(value, type_index_); setCurrentValue(value);
value_ = value; default_ = value_;
// clear all initializers when value was explicitly set
initializers_.clear();
} }
const boost::any &Property::value() const { void Property::setCurrentValue(const boost::any &value)
return value_.empty() ? default_ : value_; {
if (!value.empty())
typeCheck(value, type_index_);
value_ = value;
} }
void Property::reset()
{
value_ = default_;
}
Property& Property::configureInitFrom(PropertyInitializerSource source, const Property::InitializerFunction &f) Property& Property::configureInitFrom(PropertyInitializerSource source, const Property::InitializerFunction &f)
{ {
initializers_[source] = f; initializers_[source] = f;
@ -86,6 +95,14 @@ Property &Property::configureInitFrom(PropertyInitializerSource source, const st
return *this; return *this;
} }
void Property::performInitFrom(PropertyInitializerSource source, const PropertyMap &other)
{
auto it = initializers_.find(source);
if (it == initializers_.end()) return;
setCurrentValue(it->second(other));
}
Property& PropertyMap::declare(const std::string &name, const std::type_info &type, Property& PropertyMap::declare(const std::string &name, const std::type_info &type,
const std::string &description, const boost::any &default_value) const std::string &description, const boost::any &default_value)
@ -128,6 +145,11 @@ void PropertyMap::set(const std::string &name, const boost::any &value)
} }
} }
void PropertyMap::setCurrent(const std::string &name, const boost::any &value)
{
property(name).setCurrentValue(value);
}
const boost::any &PropertyMap::get(const std::string &name) const const boost::any &PropertyMap::get(const std::string &name) const
{ {
return property(name).value(); return property(name).value();
@ -144,31 +166,16 @@ size_t PropertyMap::countDefined(const std::vector<std::string> &list) const
void PropertyMap::reset() void PropertyMap::reset()
{ {
for (auto& pair : props_) { for (auto& pair : props_)
Property &p = pair.second; pair.second.reset();
if (!p.initializers_.empty())
// if there are initializers, reset property value
// explicitly setting the value, clears initializers
p.value_ = boost::any();
}
} }
void PropertyMap::performInitFrom(PropertyInitializerSource source, const PropertyMap &other, void PropertyMap::performInitFrom(PropertyInitializerSource source, const PropertyMap &other, bool enforce)
bool checkConsistency)
{ {
for (auto& pair : props_) { for (auto& pair : props_) {
Property &p = pair.second; Property &p = pair.second;
auto it = p.initializers_.find(source); if (enforce || !p.defined())
if (it == p.initializers_.end()) continue; p.performInitFrom(source, other);
const boost::any& value = it->second(other);
if (value.empty()) continue;
typeCheck(value, p.type_index_);
#if 0 // TODO: we cannot generically check for equality of boost::anys
if (checkConsistency && !p.value_.empty() && p.value_ != value)
throw std::runtime_error ("inconsistent values for property '" + pair.first + "'");
#endif
p.value_ = value;
} }
} }