Skip to content

Commit

Permalink
Added a method to update known properties of a map from another
Browse files Browse the repository at this point in the history
  • Loading branch information
Juan Hernando Vieites committed Dec 14, 2018
1 parent b15dc57 commit 532ba84
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 31 deletions.
61 changes: 34 additions & 27 deletions brayns/common/PropertyMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ void _commandlineToPropertyMap(const po::variables_map& vm,
}
}

void PropertyMap::merge(const PropertyMap& input)
void Property::_copy(const Property& from)
{
const auto setValues = [](Property& dest, const Property& src) {
const auto setValue = [](Property& dest, const Property& src) {
switch (dest.type)
{
case Property::Type::Int:
Expand Down Expand Up @@ -221,7 +221,7 @@ void PropertyMap::merge(const PropertyMap& input)
(t0 == Property::Type::Vec3d && t1 == Property::Type::Vec3i);
};

const auto compatibleEnums = [](Property& dest, const Property& src) {
const auto compatibleEnums = [](const Property& dest, const Property& src) {
// If we have a string to int or an int to string we can try to
// match the enum value
const bool compatible = (dest.type == Property::Type::Int &&
Expand Down Expand Up @@ -256,37 +256,44 @@ void PropertyMap::merge(const PropertyMap& input)
}
};

if (from.type == type)
{
_data = from._data;
}
else if (compatibleEnums(*this, from))
{
setEnum(*this, from);
}
else if (compatibleTypes(type, from.type))
{
setValue(*this, from);
}
else
{
throw std::runtime_error("Incompatible types for property '" +
name + "'");
}
}

void PropertyMap::merge(const PropertyMap& input)
{
for (const auto& otherProperty : input.getProperties())
{
const auto& name = otherProperty->name;

if (auto myProperty = find(name))
{
const auto myType = myProperty->type;
const auto otherType = otherProperty->type;

if (myType == otherType)
{
myProperty->_data = otherProperty->_data;
}
else if (compatibleEnums(*myProperty, *otherProperty))
{
setEnum(*myProperty, *otherProperty);
}
else if (compatibleTypes(myType, otherType))
{
setValues(*myProperty, *otherProperty);
}
else
{
throw std::runtime_error("Incompatible types for property '" +
name + "'");
}
}
myProperty->_copy(*otherProperty);
else
{
setProperty(*otherProperty.get());
}
}
}

void PropertyMap::update(const PropertyMap& input)
{
for (const auto& otherProperty : input.getProperties())
{
if (auto myProperty = find(otherProperty->name))
myProperty->_copy(*otherProperty);
}
}

Expand Down
23 changes: 19 additions & 4 deletions brayns/common/PropertyMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ struct Property

private:
friend class PropertyMap;

boost::any _data;
const boost::any _min;
const boost::any _max;
Expand All @@ -232,6 +233,8 @@ struct Property
_checkType<T>();
return boost::any_cast<T>(v);
}

void _copy(const Property& from);
};

/**
Expand All @@ -252,9 +255,10 @@ class PropertyMap
// std::vector move constructor is not noexcept until C++17, if we want
// this class to be movable we have to do it by hand.
PropertyMap(PropertyMap&& other) noexcept
: _name(std::move(other._name))
, _properties(std::move(other._properties))
{}
: _name(std::move(other._name)),
_properties(std::move(other._properties))
{
}
// Assignment operator valid for both copy and move assignment.
PropertyMap& operator=(PropertyMap other) noexcept
{
Expand All @@ -263,6 +267,7 @@ class PropertyMap
return *this;
}

bool empty() const { return _properties.empty(); }
/**
* @return the name of this property map e.g. to name commandline option
* group
Expand Down Expand Up @@ -353,9 +358,19 @@ class PropertyMap

/** @return all the registered properties. */
const auto& getProperties() const { return _properties; }
/** Merge this property map with properties from another. */
/** Merge this property map with properties from another.
* @throw std::runtime error if a property with the same name but
* incompatible types is found in both maps.
*/
void merge(const PropertyMap& input);

/** Take the values from another property map only for properties that
* are known and compatible to this one.
* @throw std::runtime error if a property with the same name but
* incompatible types is found in both maps.
*/
void update(const PropertyMap& input);

/**
* Parse and fill values from the commandline.
*
Expand Down
47 changes: 47 additions & 0 deletions tests/propertyMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,31 @@ BOOST_AUTO_TEST_CASE(fill_property_map)
BOOST_CHECK_EQUAL(aInts[1], aDoubles[1]);
BOOST_CHECK_EQUAL(aInts[2], aDoubles[2]);
}

propInts.setProperty({"foo", std::string("string")});
propDoubles.setProperty({"foo", 42});
BOOST_CHECK_THROW(propInts.merge(propDoubles), std::runtime_error);
}

BOOST_AUTO_TEST_CASE(update_properties)
{
brayns::PropertyMap source;
source.setProperty({"number", 42});
source.setProperty({"vec2", std::array<int32_t, 2>{{1, 2}}});
source.setProperty({"vec3", std::array<int32_t, 3>{{1, 2, 3}}});

brayns::PropertyMap dest;
dest.setProperty({"number", 27});
dest.setProperty({"vec2", std::array<int32_t, 2>{{0, 1}}});

dest.update(source);
BOOST_CHECK_EQUAL(dest.getProperty<int32_t>("number"), 42);
const auto array = dest.getProperty<std::array<int32_t, 2>>("vec2");
BOOST_CHECK_EQUAL(1, array[0]);
BOOST_CHECK_EQUAL(2, array[1]);

dest.setProperty({"vec3", 10});
BOOST_CHECK_THROW(dest.update(source), std::runtime_error);
}

BOOST_AUTO_TEST_CASE(merge_enums)
Expand All @@ -219,11 +244,25 @@ BOOST_AUTO_TEST_CASE(merge_enums)

{
brayns::PropertyMap propIntsTmp;

propIntsTmp.update(propInts);
BOOST_CHECK(propIntsTmp.empty());
propIntsTmp.update(propStrings);
BOOST_CHECK(propIntsTmp.empty());

propIntsTmp.merge(propInts);
propIntsTmp.merge(propStrings);

BOOST_CHECK(propIntsTmp.getPropertyType("abc") == Type::Int);
BOOST_CHECK_EQUAL(propIntsTmp.getProperty<int32_t>("abc"), 2);

propIntsTmp.update(propInts);
BOOST_CHECK(propIntsTmp.getPropertyType("abc") == Type::Int);
BOOST_CHECK_EQUAL(propIntsTmp.getProperty<int32_t>("abc"), 1);

propIntsTmp.update(propStrings);
BOOST_CHECK(propIntsTmp.getPropertyType("abc") == Type::Int);
BOOST_CHECK_EQUAL(propIntsTmp.getProperty<int32_t>("abc"), 2);
}

{
Expand All @@ -233,6 +272,14 @@ BOOST_AUTO_TEST_CASE(merge_enums)

BOOST_CHECK(propStringsTmp.getPropertyType("abc") == Type::String);
BOOST_CHECK_EQUAL(propStringsTmp.getProperty<std::string>("abc"), "b");

propStringsTmp.update(propStrings);
BOOST_CHECK(propStringsTmp.getPropertyType("abc") == Type::String);
BOOST_CHECK_EQUAL(propStringsTmp.getProperty<std::string>("abc"), "c");

propStringsTmp.update(propInts);
BOOST_CHECK(propStringsTmp.getPropertyType("abc") == Type::String);
BOOST_CHECK_EQUAL(propStringsTmp.getProperty<std::string>("abc"), "b");
}
}

Expand Down

0 comments on commit 532ba84

Please sign in to comment.