From 999a56a794d4e0ad53efbcccd58a36d9355b4e0e Mon Sep 17 00:00:00 2001 From: panquez Date: Wed, 22 Jan 2020 11:06:34 +0100 Subject: [PATCH] feat(Attribute): add method to get an attribute value as generic type (float). This can be customizable for given types. --- include/geode/basic/attribute.h | 43 ++++++++++++++++++++++++++- tests/basic/test-attribute.cpp | 51 +++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/include/geode/basic/attribute.h b/include/geode/basic/attribute.h index af7ef389c..8bbe49e2c 100644 --- a/include/geode/basic/attribute.h +++ b/include/geode/basic/attribute.h @@ -41,7 +41,40 @@ namespace geode { /*! - * Base classe defining the virtual API used by the AttributeManager. + * Helper struct to convert an Attribute value to generic float. + * This struct may be customized for a given type. + * Example: + * template <> + * struct GenericAttributeConversion< MyType > + * { + * static float converted_value( const MyType& value ) + * { + * return value.get_a_float(); + * } + * }; + */ + template < typename AttributeType > + struct GenericAttributeConversion + { + template < typename T = AttributeType > + static typename std::enable_if< std::is_arithmetic< T >::value, + float >::type + converted_value( const T& value ) + { + return value; + } + + template < typename T = AttributeType > + static typename std::enable_if< !std::is_arithmetic< T >::value, + float >::type + converted_value( const T& /*unused*/ ) + { + return 0.; + } + }; + + /*! + * Base class defining the virtual API used by the AttributeManager. */ class AttributeBase { @@ -56,6 +89,8 @@ namespace geode virtual void copy( const AttributeBase& attribute, index_t nb_elements ) = 0; + virtual float generic_value( index_t element ) const = 0; + private: friend class bitsery::Access; template < typename Archive > @@ -91,6 +126,12 @@ namespace geode return typeid( T ).name(); } + float generic_value( index_t element ) const final + { + return GenericAttributeConversion< T >::converted_value( + value( element ) ); + } + protected: ReadOnlyAttribute() = default; diff --git a/tests/basic/test-attribute.cpp b/tests/basic/test-attribute.cpp index b45bd7acf..c5caf8757 100644 --- a/tests/basic/test-attribute.cpp +++ b/tests/basic/test-attribute.cpp @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -41,6 +43,11 @@ struct Foo return double_ != foo.double_ || int_ != foo.int_; } + float generic_value() const + { + return double_ + int_; + } + template < typename Archive > void serialize( Archive& archive ) { @@ -51,6 +58,18 @@ struct Foo int int_{ 0 }; }; +namespace geode +{ + template <> + struct GenericAttributeConversion< Foo > + { + static float converted_value( const Foo& value ) + { + return value.generic_value(); + } + }; +} // namespace geode + void test_constant_attribute( geode::AttributeManager& manager ) { auto constant_attribute = @@ -116,10 +135,13 @@ void test_foo_sparse_attribute( geode::AttributeManager& manager ) manager.find_or_create_attribute< geode::SparseAttribute, Foo >( "foo_spr" ); sparse_attribute->modify_value( 3, []( Foo& foo ) { foo.double_ = 12.4; } ); + sparse_attribute->modify_value( 3, []( Foo& foo ) { foo.int_ = 3; } ); OPENGEODE_EXCEPTION( sparse_attribute->value( 0 ).double_ == 0, "[Test] Should be equal to 0" ); OPENGEODE_EXCEPTION( sparse_attribute->value( 3 ).double_ == 12.4, "[Test] Should be equal to 12.4" ); + OPENGEODE_EXCEPTION( + sparse_attribute->value( 3 ).int_ == 3, "[Test] Should be equal to 3" ); } void test_double_sparse_attribute( geode::AttributeManager& manager ) @@ -223,6 +245,8 @@ void test_serialize_manager( geode::AttributeManager& manager ) geode::register_basic_serialize_pcontext( std::get< 0 >( context ) ); geode::AttributeManager::register_attribute_type< Foo, geode::Serializer >( std::get< 0 >( context ) ); + geode::AttributeManager::register_attribute_type< std::array< double, 3 >, + geode::Serializer >( std::get< 0 >( context ) ); geode::Serializer archive{ context, file }; archive.object( manager ); archive.adapter().flush(); @@ -236,6 +260,8 @@ void test_serialize_manager( geode::AttributeManager& manager ) std::get< 0 >( reload_context ) ); geode::AttributeManager::register_attribute_type< Foo, geode::Deserializer >( std::get< 0 >( reload_context ) ); + geode::AttributeManager::register_attribute_type< std::array< double, 3 >, + geode::Deserializer >( std::get< 0 >( reload_context ) ); geode::Deserializer unarchive{ reload_context, infile }; unarchive.object( reloaded_manager ); const auto& adapter = unarchive.adapter(); @@ -298,6 +324,24 @@ void test_sparse_attribute_after_element_deletion( "Element 7 of sparse attribute should be 12 " ); } +void test_generic_value( geode::AttributeManager& manager ) +{ + const auto& foo_attr = manager.find_attribute< Foo >( "foo_spr" ); + OPENGEODE_EXCEPTION( foo_attr->generic_value( 3 ) == 15.4f, + "Generic value for element 3 of foo sparse attribute should be 15.4" ); + + const auto& double_attr = manager.find_attribute< double >( "double" ); + OPENGEODE_EXCEPTION( double_attr->generic_value( 7 ) == 7, + "Generic value for element 7 of double attribute should be 7" ); + + auto array_attr = + manager.find_or_create_attribute< geode::VariableAttribute, + std::array< double, 3 > >( "array_double" ); + array_attr->set_value( 2, { 3.1, 1.3 } ); + OPENGEODE_EXCEPTION( array_attr->generic_value( 2 ) == 0., + "Generic value for element 2 of array attribute should be 0." ); +} + void test() { geode::AttributeManager manager; @@ -311,17 +355,18 @@ void test() test_foo_variable_attribute( manager ); test_double_sparse_attribute( manager ); test_foo_sparse_attribute( manager ); + test_generic_value( manager ); test_delete_attribute_elements( manager ); test_sparse_attribute_after_element_deletion( manager ); test_serialize_manager( manager ); test_attribute_types( manager ); - test_number_of_attributes( manager, 7 ); + test_number_of_attributes( manager, 8 ); manager.delete_attribute( "bool" ); - test_number_of_attributes( manager, 6 ); + test_number_of_attributes( manager, 7 ); manager.clear_attributes(); - test_number_of_attributes( manager, 6 ); + test_number_of_attributes( manager, 7 ); manager.resize( 10 ); OPENGEODE_EXCEPTION( manager.nb_elements() == 10, "[Test] Manager should have 10 elements" );