GenericValue based on defined traits to replace DerivedValue, first implementation
parent
95827dd4d8
commit
0681212084
|
|
@ -10,9 +10,10 @@
|
||||||
* -------------------------------------------------------------------------- */
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @file DerivedValue.h
|
* @file GenericValue.h
|
||||||
* @date Jan 26, 2012
|
* @date Jan 26, 2012
|
||||||
* @author Duy Nguyen Ta
|
* @author Duy Nguyen Ta
|
||||||
|
* @author Mike Bosse, Abel Gawel, Renaud Dube
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
@ -40,15 +41,52 @@
|
||||||
|
|
||||||
namespace gtsam {
|
namespace gtsam {
|
||||||
|
|
||||||
template<class DERIVED>
|
namespace traits {
|
||||||
class DerivedValue : public Value {
|
|
||||||
|
|
||||||
|
// trait to wrap the default equals of types
|
||||||
|
template<typename T>
|
||||||
|
bool equals(const T& a, const T& b, double tol) {
|
||||||
|
return a.equals(b,tol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// trait to compute the local coordinates of other with respect to origin
|
||||||
|
template<typename T>
|
||||||
|
Vector localCoordinates(const T& origin, const T& other) {
|
||||||
|
return origin.localCoordinates(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T retract(const T& origin, const Vector& delta) {
|
||||||
|
return origin.retract(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void print(const T& obj, const std::string& str) {
|
||||||
|
obj.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
size_t getDimension(const T& obj) {
|
||||||
|
return obj.dim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class GenericValue : public Value {
|
||||||
|
public:
|
||||||
|
typedef T ValueType;
|
||||||
|
typedef GenericValue This;
|
||||||
protected:
|
protected:
|
||||||
DerivedValue() {}
|
T value_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
GenericValue() {}
|
||||||
|
GenericValue(const T& value) : value_(value) {}
|
||||||
|
|
||||||
virtual ~DerivedValue() {}
|
T& value() { return value_; }
|
||||||
|
const T& value() const { return value_; }
|
||||||
|
|
||||||
|
virtual ~GenericValue() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a duplicate object returned as a pointer to the generic Value interface.
|
* Create a duplicate object returned as a pointer to the generic Value interface.
|
||||||
|
|
@ -56,8 +94,8 @@ public:
|
||||||
* The result must be deleted with Value::deallocate_, not with the 'delete' operator.
|
* The result must be deleted with Value::deallocate_, not with the 'delete' operator.
|
||||||
*/
|
*/
|
||||||
virtual Value* clone_() const {
|
virtual Value* clone_() const {
|
||||||
void *place = boost::singleton_pool<PoolTag, sizeof(DERIVED)>::malloc();
|
void *place = boost::singleton_pool<PoolTag, sizeof(This)>::malloc();
|
||||||
DERIVED* ptr = new(place) DERIVED(static_cast<const DERIVED&>(*this));
|
This* ptr = new(place) This(*this);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,34 +103,35 @@ public:
|
||||||
* Destroy and deallocate this object, only if it was originally allocated using clone_().
|
* Destroy and deallocate this object, only if it was originally allocated using clone_().
|
||||||
*/
|
*/
|
||||||
virtual void deallocate_() const {
|
virtual void deallocate_() const {
|
||||||
this->~DerivedValue(); // Virtual destructor cleans up the derived object
|
this->~GenericValue(); // Virtual destructor cleans up the derived object
|
||||||
boost::singleton_pool<PoolTag, sizeof(DERIVED)>::free((void*)this); // Release memory from pool
|
boost::singleton_pool<PoolTag, sizeof(This)>::free((void*)this); // Release memory from pool
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone this value (normal clone on the heap, delete with 'delete' operator)
|
* Clone this value (normal clone on the heap, delete with 'delete' operator)
|
||||||
*/
|
*/
|
||||||
virtual boost::shared_ptr<Value> clone() const {
|
virtual boost::shared_ptr<Value> clone() const {
|
||||||
return boost::make_shared<DERIVED>(static_cast<const DERIVED&>(*this));
|
return boost::make_shared<This>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// equals implementing generic Value interface
|
/// equals implementing generic Value interface
|
||||||
virtual bool equals_(const Value& p, double tol = 1e-9) const {
|
virtual bool equals_(const Value& p, double tol = 1e-9) const {
|
||||||
// Cast the base class Value pointer to a derived class pointer
|
// Cast the base class Value pointer to a templated generic class pointer
|
||||||
const DERIVED& derivedValue2 = dynamic_cast<const DERIVED&>(p);
|
const This& genericValue2 = dynamic_cast<const This&>(p);
|
||||||
|
|
||||||
|
// Return the result of using the equals traits for the derived class
|
||||||
|
return traits::equals<T>(this->value_, genericValue2.value_, tol);
|
||||||
|
|
||||||
// Return the result of calling equals on the derived class
|
|
||||||
return (static_cast<const DERIVED*>(this))->equals(derivedValue2, tol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic Value interface version of retract
|
/// Generic Value interface version of retract
|
||||||
virtual Value* retract_(const Vector& delta) const {
|
virtual Value* retract_(const Vector& delta) const {
|
||||||
// Call retract on the derived class
|
// Call retract on the derived class using the retract trait function
|
||||||
const DERIVED retractResult = (static_cast<const DERIVED*>(this))->retract(delta);
|
const T retractResult = traits::retract<T>(value_,delta);
|
||||||
|
|
||||||
// Create a Value pointer copy of the result
|
// Create a Value pointer copy of the result
|
||||||
void* resultAsValuePlace = boost::singleton_pool<PoolTag, sizeof(DERIVED)>::malloc();
|
void* resultAsValuePlace = boost::singleton_pool<PoolTag, sizeof(This)>::malloc();
|
||||||
Value* resultAsValue = new(resultAsValuePlace) DERIVED(retractResult);
|
Value* resultAsValue = new(resultAsValuePlace) This(retractResult);
|
||||||
|
|
||||||
// Return the pointer to the Value base class
|
// Return the pointer to the Value base class
|
||||||
return resultAsValue;
|
return resultAsValue;
|
||||||
|
|
@ -100,44 +139,52 @@ public:
|
||||||
|
|
||||||
/// Generic Value interface version of localCoordinates
|
/// Generic Value interface version of localCoordinates
|
||||||
virtual Vector localCoordinates_(const Value& value2) const {
|
virtual Vector localCoordinates_(const Value& value2) const {
|
||||||
// Cast the base class Value pointer to a derived class pointer
|
// Cast the base class Value pointer to a templated generic class pointer
|
||||||
const DERIVED& derivedValue2 = dynamic_cast<const DERIVED&>(value2);
|
const This& genericValue2 = dynamic_cast<const This&>(value2);
|
||||||
|
|
||||||
// Return the result of calling localCoordinates on the derived class
|
// Return the result of calling localCoordinates trait on the derived class
|
||||||
return (static_cast<const DERIVED*>(this))->localCoordinates(derivedValue2);
|
return traits::localCoordinates<T>(value_,genericValue2.value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void print(const std::string& str) const {
|
||||||
|
traits::print<T>(value_,str);
|
||||||
|
}
|
||||||
|
virtual size_t dim() const {
|
||||||
|
return traits::getDimension<T>(value_); // need functional form here since the dimension may be dynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assignment operator
|
/// Assignment operator
|
||||||
virtual Value& operator=(const Value& rhs) {
|
virtual Value& operator=(const Value& rhs) {
|
||||||
// Cast the base class Value pointer to a derived class pointer
|
// Cast the base class Value pointer to a derived class pointer
|
||||||
const DERIVED& derivedRhs = dynamic_cast<const DERIVED&>(rhs);
|
const This& derivedRhs = dynamic_cast<const This&>(rhs);
|
||||||
|
|
||||||
// Do the assignment and return the result
|
// Do the assignment and return the result
|
||||||
return (static_cast<DERIVED*>(this))->operator=(derivedRhs);
|
this->value_ = derivedRhs.value_;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conversion to the derived class
|
/// Conversion to the derived class
|
||||||
operator const DERIVED& () const {
|
operator const T& () const {
|
||||||
return static_cast<const DERIVED&>(*this);
|
return value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conversion to the derived class
|
/// Conversion to the derived class
|
||||||
operator DERIVED& () {
|
operator T& () {
|
||||||
return static_cast<DERIVED&>(*this);
|
return value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Assignment operator, protected because only the Value or DERIVED
|
/// Assignment operator, protected because only the Value or DERIVED
|
||||||
/// assignment operators should be used.
|
/// assignment operators should be used.
|
||||||
DerivedValue<DERIVED>& operator=(const DerivedValue<DERIVED>& rhs) {
|
// DerivedValue<DERIVED>& operator=(const DerivedValue<DERIVED>& rhs) {
|
||||||
// Nothing to do, do not call base class assignment operator
|
// // Nothing to do, do not call base class assignment operator
|
||||||
return *this;
|
// return *this;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Fake Tag struct for singleton pool allocator. In fact, it is never used!
|
/// Fake Tag struct for singleton pool allocator. In fact, it is never used!
|
||||||
struct PoolTag { };
|
struct PoolTag { };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace gtsam */
|
} /* namespace gtsam */
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,36 @@ namespace gtsam {
|
||||||
_ValuesConstKeyValuePair(const _ValuesKeyValuePair<ValueType>& rhs) : key(rhs.key), value(rhs.value) {}
|
_ValuesConstKeyValuePair(const _ValuesKeyValuePair<ValueType>& rhs) : key(rhs.key), value(rhs.value) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
|
||||||
|
// Cast helpers for making _Values[Const]KeyValuePair's from Values::[Const]KeyValuePair
|
||||||
|
// need to use a struct here for later partial specialization
|
||||||
|
template<class ValueType, class CastedKeyValuePairType, class KeyValuePairType>
|
||||||
|
struct ValuesCastHelper {
|
||||||
|
static CastedKeyValuePairType cast(KeyValuePairType key_value) {
|
||||||
|
// Static cast because we already checked the type during filtering
|
||||||
|
return CastedKeyValuePairType(key_value.key, const_cast<GenericValue<ValueType>&>(static_cast<const GenericValue<ValueType>&>(key_value.value)).value());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// partial specialized version for ValueType == Value
|
||||||
|
template<class CastedKeyValuePairType, class KeyValuePairType>
|
||||||
|
struct ValuesCastHelper<Value,CastedKeyValuePairType,KeyValuePairType> {
|
||||||
|
static CastedKeyValuePairType cast(KeyValuePairType key_value) {
|
||||||
|
// Static cast because we already checked the type during filtering
|
||||||
|
// in this case the casted and keyvalue pair are essentially the same type (key,Value&) so perhaps this could be done with just a cast of the key_value?
|
||||||
|
return CastedKeyValuePairType(key_value.key, key_value.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// partial specialized version for ValueType == Value
|
||||||
|
template<class CastedKeyValuePairType, class KeyValuePairType>
|
||||||
|
struct ValuesCastHelper<const Value,CastedKeyValuePairType,KeyValuePairType> {
|
||||||
|
static CastedKeyValuePairType cast(KeyValuePairType key_value) {
|
||||||
|
// Static cast because we already checked the type during filtering
|
||||||
|
// in this case the casted and keyvalue pair are essentially the same type (key,Value&) so perhaps this could be done with just a cast of the key_value?
|
||||||
|
return CastedKeyValuePairType(key_value.key, key_value.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
class Values::Filtered {
|
class Values::Filtered {
|
||||||
|
|
@ -99,19 +129,19 @@ namespace gtsam {
|
||||||
begin_(boost::make_transform_iterator(
|
begin_(boost::make_transform_iterator(
|
||||||
boost::make_filter_iterator(
|
boost::make_filter_iterator(
|
||||||
filter, values.begin(), values.end()),
|
filter, values.begin(), values.end()),
|
||||||
&castHelper<ValueType, KeyValuePair, Values::KeyValuePair>)),
|
&ValuesCastHelper<ValueType, KeyValuePair, Values::KeyValuePair>::cast)),
|
||||||
end_(boost::make_transform_iterator(
|
end_(boost::make_transform_iterator(
|
||||||
boost::make_filter_iterator(
|
boost::make_filter_iterator(
|
||||||
filter, values.end(), values.end()),
|
filter, values.end(), values.end()),
|
||||||
&castHelper<ValueType, KeyValuePair, Values::KeyValuePair>)),
|
&ValuesCastHelper<ValueType, KeyValuePair, Values::KeyValuePair>::cast)),
|
||||||
constBegin_(boost::make_transform_iterator(
|
constBegin_(boost::make_transform_iterator(
|
||||||
boost::make_filter_iterator(
|
boost::make_filter_iterator(
|
||||||
filter, ((const Values&)values).begin(), ((const Values&)values).end()),
|
filter, ((const Values&)values).begin(), ((const Values&)values).end()),
|
||||||
&castHelper<const ValueType, ConstKeyValuePair, Values::ConstKeyValuePair>)),
|
&ValuesCastHelper<const ValueType, ConstKeyValuePair, Values::ConstKeyValuePair>::cast)),
|
||||||
constEnd_(boost::make_transform_iterator(
|
constEnd_(boost::make_transform_iterator(
|
||||||
boost::make_filter_iterator(
|
boost::make_filter_iterator(
|
||||||
filter, ((const Values&)values).end(), ((const Values&)values).end()),
|
filter, ((const Values&)values).end(), ((const Values&)values).end()),
|
||||||
&castHelper<const ValueType, ConstKeyValuePair, Values::ConstKeyValuePair>)) {}
|
&ValuesCastHelper<const ValueType, ConstKeyValuePair, Values::ConstKeyValuePair>::cast)) {}
|
||||||
|
|
||||||
friend class Values;
|
friend class Values;
|
||||||
iterator begin_;
|
iterator begin_;
|
||||||
|
|
@ -175,7 +205,7 @@ namespace gtsam {
|
||||||
Values::Values(const Values::Filtered<ValueType>& view) {
|
Values::Values(const Values::Filtered<ValueType>& view) {
|
||||||
BOOST_FOREACH(const typename Filtered<ValueType>::KeyValuePair& key_value, view) {
|
BOOST_FOREACH(const typename Filtered<ValueType>::KeyValuePair& key_value, view) {
|
||||||
Key key = key_value.key;
|
Key key = key_value.key;
|
||||||
insert(key, key_value.value);
|
insert<ValueType>(key, key_value.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,7 +214,7 @@ namespace gtsam {
|
||||||
Values::Values(const Values::ConstFiltered<ValueType>& view) {
|
Values::Values(const Values::ConstFiltered<ValueType>& view) {
|
||||||
BOOST_FOREACH(const typename ConstFiltered<ValueType>::KeyValuePair& key_value, view) {
|
BOOST_FOREACH(const typename ConstFiltered<ValueType>::KeyValuePair& key_value, view) {
|
||||||
Key key = key_value.key;
|
Key key = key_value.key;
|
||||||
insert(key, key_value.value);
|
insert<ValueType>(key, key_value.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,6 +244,13 @@ namespace gtsam {
|
||||||
return ConstFiltered<ValueType>(boost::bind(&filterHelper<ValueType>, filterFcn, _1), *this);
|
return ConstFiltered<ValueType>(boost::bind(&filterHelper<ValueType>, filterFcn, _1), *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<>
|
||||||
|
inline bool Values::filterHelper<Value>(const boost::function<bool(Key)> filter, const ConstKeyValuePair& key_value) {
|
||||||
|
// Filter and check the type
|
||||||
|
return filter(key_value.key);
|
||||||
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
template<typename ValueType>
|
template<typename ValueType>
|
||||||
const ValueType& Values::at(Key j) const {
|
const ValueType& Values::at(Key j) const {
|
||||||
|
|
@ -225,11 +262,11 @@ namespace gtsam {
|
||||||
throw ValuesKeyDoesNotExist("retrieve", j);
|
throw ValuesKeyDoesNotExist("retrieve", j);
|
||||||
|
|
||||||
// Check the type and throw exception if incorrect
|
// Check the type and throw exception if incorrect
|
||||||
if(typeid(*item->second) != typeid(ValueType))
|
if(typeid(*item->second) != typeid(GenericValue<ValueType>))
|
||||||
throw ValuesIncorrectType(j, typeid(*item->second), typeid(ValueType));
|
throw ValuesIncorrectType(j, typeid(*item->second), typeid(ValueType));
|
||||||
|
|
||||||
// We have already checked the type, so do a "blind" static_cast, not dynamic_cast
|
// We have already checked the type, so do a "blind" static_cast, not dynamic_cast
|
||||||
return static_cast<const ValueType&>(*item->second);
|
return static_cast<const GenericValue<ValueType>&>(*item->second).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
@ -240,14 +277,20 @@ namespace gtsam {
|
||||||
|
|
||||||
if(item != values_.end()) {
|
if(item != values_.end()) {
|
||||||
// Check the type and throw exception if incorrect
|
// Check the type and throw exception if incorrect
|
||||||
if(typeid(*item->second) != typeid(ValueType))
|
if(typeid(*item->second) != typeid(GenericValue<ValueType>))
|
||||||
throw ValuesIncorrectType(j, typeid(*item->second), typeid(ValueType));
|
throw ValuesIncorrectType(j, typeid(*item->second), typeid(ValueType));
|
||||||
|
|
||||||
// We have already checked the type, so do a "blind" static_cast, not dynamic_cast
|
// We have already checked the type, so do a "blind" static_cast, not dynamic_cast
|
||||||
return static_cast<const ValueType&>(*item->second);
|
return static_cast<const GenericValue<ValueType>&>(*item->second).value_;
|
||||||
} else {
|
} else {
|
||||||
return boost::none;
|
return boost::none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<typename ValueType>
|
||||||
|
void Values::insert(Key j, const ValueType& val) {
|
||||||
|
insert(j, static_cast<const Value&>(GenericValue<ValueType>(val)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <gtsam/base/Value.h>
|
#include <gtsam/base/Value.h>
|
||||||
|
#include <gtsam/base/GenericValue.h>
|
||||||
#include <gtsam/base/FastMap.h>
|
#include <gtsam/base/FastMap.h>
|
||||||
#include <gtsam/inference/Key.h>
|
#include <gtsam/inference/Key.h>
|
||||||
|
|
||||||
|
|
@ -248,6 +249,12 @@ namespace gtsam {
|
||||||
/** Add a variable with the given j, throws KeyAlreadyExists<J> if j is already present */
|
/** Add a variable with the given j, throws KeyAlreadyExists<J> if j is already present */
|
||||||
void insert(Key j, const Value& val);
|
void insert(Key j, const Value& val);
|
||||||
|
|
||||||
|
/** Templated verion to add a variable with the given j,
|
||||||
|
* throws KeyAlreadyExists<J> if j is already present
|
||||||
|
* will wrap the val into a GenericValue<ValueType> to insert*/
|
||||||
|
template <typename ValueType> void insert(Key j, const ValueType& val);
|
||||||
|
|
||||||
|
|
||||||
/** Add a set of variables, throws KeyAlreadyExists<J> if a key is already present */
|
/** Add a set of variables, throws KeyAlreadyExists<J> if a key is already present */
|
||||||
void insert(const Values& values);
|
void insert(const Values& values);
|
||||||
|
|
||||||
|
|
@ -259,6 +266,7 @@ namespace gtsam {
|
||||||
|
|
||||||
/** single element change of existing element */
|
/** single element change of existing element */
|
||||||
void update(Key j, const Value& val);
|
void update(Key j, const Value& val);
|
||||||
|
template <typename T> void update(Key j, const T& val);
|
||||||
|
|
||||||
/** update the current available values without adding new ones */
|
/** update the current available values without adding new ones */
|
||||||
void update(const Values& values);
|
void update(const Values& values);
|
||||||
|
|
@ -369,15 +377,9 @@ namespace gtsam {
|
||||||
// supplied \c filter function.
|
// supplied \c filter function.
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
static bool filterHelper(const boost::function<bool(Key)> filter, const ConstKeyValuePair& key_value) {
|
static bool filterHelper(const boost::function<bool(Key)> filter, const ConstKeyValuePair& key_value) {
|
||||||
|
BOOST_STATIC_ASSERT((!std::is_same<ValueType,Value>::value));
|
||||||
// Filter and check the type
|
// Filter and check the type
|
||||||
return filter(key_value.key) && (typeid(ValueType) == typeid(key_value.value) || typeid(ValueType) == typeid(Value));
|
return filter(key_value.key) && (typeid(GenericValue<ValueType>) == typeid(key_value.value) );
|
||||||
}
|
|
||||||
|
|
||||||
// Cast to the derived ValueType
|
|
||||||
template<class ValueType, class CastedKeyValuePairType, class KeyValuePairType>
|
|
||||||
static CastedKeyValuePairType castHelper(KeyValuePairType key_value) {
|
|
||||||
// Static cast because we already checked the type during filtering
|
|
||||||
return CastedKeyValuePairType(key_value.key, static_cast<ValueType&>(key_value.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Serialization function */
|
/** Serialization function */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue