diff --git a/CMakeLists.txt b/CMakeLists.txt index c3d4a48..6c6b058 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,10 @@ macro(compile_test) compile_example(${TEST_NAME} SOURCE ${TEST_SOURCE}) +if(MSVC) + target_compile_options(${TEST_NAME} PRIVATE /bigobj) +endif(MSVC) + target_link_libraries(${TEST_NAME} PRIVATE GTest::gtest diff --git a/include/xtypes/AliasType.hpp b/include/xtypes/AliasType.hpp index f430114..1aade1f 100644 --- a/include/xtypes/AliasType.hpp +++ b/include/xtypes/AliasType.hpp @@ -177,9 +177,9 @@ class AliasType : public DynamicType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new AliasType(*this); + return std::make_shared(*this); } private: diff --git a/include/xtypes/ArrayType.hpp b/include/xtypes/ArrayType.hpp index 9b1b0fc..62efd0c 100644 --- a/include/xtypes/ArrayType.hpp +++ b/include/xtypes/ArrayType.hpp @@ -319,9 +319,9 @@ class ArrayType : public CollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new ArrayType(*this); + return std::make_shared(*this); } private: diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index 4041e9e..de5d7fe 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -69,7 +69,7 @@ class ReadableDynamicDataRef ReadableDynamicDataRef(const ReadableDynamicDataRef& other) = default; ReadableDynamicDataRef(ReadableDynamicDataRef&& other) - : type_(other.type_) + : type_(std::move(other.type_)) , instance_(other.instance_) , initialize_(other.initialize_) { @@ -82,13 +82,13 @@ class ReadableDynamicDataRef bool operator == ( const ReadableDynamicDataRef& other) const { - if (type_.kind() == TypeKind::ARRAY_TYPE) + if (type_->kind() == TypeKind::ARRAY_TYPE) { // If the data is Array, a fast way to discard equality is that the content or size of the array // is different. We can check both without casting the type by comparing the type (array) name. - return type_.name() == other.type().name() && type_.compare_instance(instance_, other.instance_); + return type_->name() == other.type().name() && type_->compare_instance(instance_, other.instance_); } - return type_.compare_instance(instance_, other.instance_); + return type_->compare_instance(instance_, other.instance_); } /// \brief Deep inequality operator. Inverse of == operator. @@ -110,7 +110,7 @@ class ReadableDynamicDataRef /// \returns a reference to the representing DynamicType const DynamicType& type() const { - return type_; + return *type_; } /// \brief Returns the id of the managed instance. @@ -130,18 +130,18 @@ class ReadableDynamicDataRef template > const T& value() const { - xtypes_assert((type_.kind() == TypeKind::STRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::WSTRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::STRING16_TYPE && std::is_same::value) - || (type_.kind() == primitive_type().kind()) - || (type_.is_enumerated_type()), - "Expected type '" << type_.name() + xtypes_assert((type_->kind() == TypeKind::STRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::WSTRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::STRING16_TYPE && std::is_same::value) + || (type_->kind() == primitive_type().kind()) + || (type_->is_enumerated_type()), + "Expected type '" << type_->name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while getting value."); - if (type_.is_enumerated_type()) + if (type_->is_enumerated_type()) { - xtypes_assert(type_.memory_size() == sizeof(T), - "Incompatible types: '" << type_.name() << "' and '" + xtypes_assert(type_->memory_size() == sizeof(T), + "Incompatible types: '" << type_->name() << "' and '" << PrimitiveTypeKindTrait::name << "'."); } @@ -182,25 +182,25 @@ class ReadableDynamicDataRef { size_t s_index(static_cast(index)); - xtypes_assert(type_.is_aggregation_type() || type_.is_collection_type() || type_.kind() == TypeKind::PAIR_TYPE, - "operator [size_t] isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type() || type_->is_collection_type() || type_->kind() == TypeKind::PAIR_TYPE, + "operator [size_t] isn't available for type '" << type_->name() << "'."); xtypes_assert(s_index < size(), "operator [" << s_index << "] is out of bounds."); - if (type_.is_collection_type()) + if (type_->is_collection_type()) { - const CollectionType& collection = static_cast(type_); + const CollectionType& collection = static_cast(*type_); // The following assert exists because it may be confusing by the user, it will return the pair instead of // the value associated to the "key" representation of the index. - xtypes_assert(type_.kind() != TypeKind::MAP_TYPE, "Cannot access a MapType by index"); + xtypes_assert(type_->kind() != TypeKind::MAP_TYPE, "Cannot access a MapType by index"); return ReadableDynamicDataRef(collection.content_type(), collection.get_instance_at(instance_, s_index)); } - xtypes_assert(type_.kind() != TypeKind::UNION_TYPE, "Members of UnionType cannot be accessed by index."); + xtypes_assert(type_->kind() != TypeKind::UNION_TYPE, "Members of UnionType cannot be accessed by index."); - if (type_.kind() == TypeKind::PAIR_TYPE) + if (type_->kind() == TypeKind::PAIR_TYPE) { xtypes_assert(s_index < 2, "operator[" << s_index << "] is out of bounds."); - const PairType& pair = static_cast(type_); + const PairType& pair = static_cast(*type_); if (s_index == 0) { return ReadableDynamicDataRef(pair.first(), instance_); @@ -211,7 +211,7 @@ class ReadableDynamicDataRef } } - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); const Member& member = aggregation.member(s_index); return ReadableDynamicDataRef(member.type(), instance_ + member.offset()); } @@ -221,8 +221,8 @@ class ReadableDynamicDataRef /// \return A readable reference of the discriminator. ReadableDynamicDataRef d() const { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); - const UnionType& aggregation = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); + const UnionType& aggregation = static_cast(*type_); const Member& member = aggregation.member(0); return ReadableDynamicDataRef(member.type(), instance_); } @@ -232,8 +232,8 @@ class ReadableDynamicDataRef /// \return The current selected member. const Member& current_case() const { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "current_case is only available for UnionType."); - const UnionType& aggregation = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "current_case is only available for UnionType."); + const UnionType& aggregation = static_cast(*type_); return aggregation.get_current_selection(instance_); } @@ -246,13 +246,13 @@ class ReadableDynamicDataRef ReadableDynamicDataRef data) const { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "'at()' method is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); const PairType& pair = static_cast(map.content_type()); uint8_t* instance = map.get_instance_at(instance_, data.instance_); - xtypes_assert(instance != nullptr, "MapType '" << type_.name() << "' doesn't contains the requested key."); + xtypes_assert(instance != nullptr, "MapType '" << type_->name() << "' doesn't contains the requested key."); return ReadableDynamicDataRef(pair.second(), instance + pair.first().memory_size()); } @@ -263,19 +263,19 @@ class ReadableDynamicDataRef /// \returns Element size of the DynamicData. size_t size() const { - xtypes_assert(type_.is_collection_type() || type_.is_aggregation_type() || type_.kind() == TypeKind::PAIR_TYPE, - "size() isn't available for type '" << type_.name() << "'."); - if (type_.is_collection_type()) + xtypes_assert(type_->is_collection_type() || type_->is_aggregation_type() || type_->kind() == TypeKind::PAIR_TYPE, + "size() isn't available for type '" << type_->name() << "'."); + if (type_->is_collection_type()) { - const CollectionType& collection = static_cast(type_); + const CollectionType& collection = static_cast(*type_); return collection.get_instance_size(instance_); } - if (type_.is_aggregation_type()) + if (type_->is_aggregation_type()) { - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); return aggregation.members().size(); } - if (type_.kind() == TypeKind::PAIR_TYPE) + if (type_->kind() == TypeKind::PAIR_TYPE) { return 2; } @@ -288,15 +288,15 @@ class ReadableDynamicDataRef /// If the DynamicData represents an Array, then bounds() == size() size_t bounds() const { - xtypes_assert(type_.is_collection_type(), - "bounds() isn't available for type '" << type_.name() << "'."); - if (type_.is_collection_type()) + xtypes_assert(type_->is_collection_type(), + "bounds() isn't available for type '" << type_->name() << "'."); + if (type_->is_collection_type()) { - if (type_.kind() == TypeKind::ARRAY_TYPE) + if (type_->kind() == TypeKind::ARRAY_TYPE) { return size(); } - const MutableCollectionType& collection = static_cast(type_); + const MutableCollectionType& collection = static_cast(*type_); return collection.bounds(); } return 0; @@ -304,7 +304,7 @@ class ReadableDynamicDataRef uint64_t hash() const { - return type_.hash(instance_); + return type_->hash(instance_); } /// \brief Returns a std::vector representing the underlying collection of types. @@ -313,16 +313,16 @@ class ReadableDynamicDataRef template > std::vector as_vector() const { - const CollectionType& collection = static_cast(type_); - xtypes_assert(type_.is_collection_type(), - "as_vector() isn't available for type '" << type_.name() << "'."); + const CollectionType& collection = static_cast(*type_); + xtypes_assert(type_->is_collection_type(), + "as_vector() isn't available for type '" << type_->name() << "'."); xtypes_assert((collection.content_type().kind() == TypeKind::STRING_TYPE && std::is_same::value) || (collection.content_type().kind() == TypeKind::WSTRING_TYPE && std::is_same::value) || (collection.content_type().kind() == TypeKind::STRING16_TYPE && std::is_same::value) || (collection.content_type().kind() == primitive_type().kind()), "as_vector<" << PrimitiveTypeKindTrait::name << ">() isn't available for type '" - << type_.name() << "'."); + << type_->name() << "'."); const T* location = reinterpret_cast(collection.get_instance_at(instance_, 0)); return std::vector(location, location + size()); @@ -408,10 +408,10 @@ class ReadableDynamicDataRef bool for_each( std::function visitor) const { - Instanceable::InstanceNode root(type_, instance_); + Instanceable::InstanceNode root(*type_, instance_); try { - type_.for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) + type_->for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) { visitor(ReadableNode(instance_node)); }); @@ -458,7 +458,7 @@ class ReadableDynamicDataRef ReadableDynamicDataRef operator * () const { - const CollectionType& collection = static_cast(type_); + const CollectionType& collection = static_cast(*type_); return ReadableDynamicDataRef(collection.content_type(), collection.get_instance_at(instance_, index_)); } @@ -489,7 +489,7 @@ class ReadableDynamicDataRef { } - const DynamicType& type_; + std::shared_ptr type_; uint8_t* instance_; size_t index_; }; @@ -499,8 +499,8 @@ class ReadableDynamicDataRef /// \returns The initial iterator. Iterator begin() const { - xtypes_assert(type_.is_collection_type(), - "begin() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_collection_type(), + "begin() isn't available for type '" << type_->name() << "'."); return Iterator(*this, false); } @@ -509,8 +509,8 @@ class ReadableDynamicDataRef /// \returns The final iterator. Iterator end() const { - xtypes_assert(type_.is_collection_type(), - "end() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_collection_type(), + "end() isn't available for type '" << type_->name() << "'."); return Iterator(*this, true); } @@ -561,7 +561,7 @@ class ReadableDynamicDataRef const MemberPair operator * () const { - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); return MemberPair( aggregation.member(index_), instance_ + aggregation.member(index_).offset()); @@ -583,15 +583,15 @@ class ReadableDynamicDataRef MemberIterator begin() const { - xtypes_assert(type_.is_aggregation_type(), - "begin() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "begin() isn't available for type '" << type_->name() << "'."); return MemberIterator(ref_, false); } MemberIterator end() const { - xtypes_assert(type_.is_aggregation_type(), - "end() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "end() isn't available for type '" << type_->name() << "'."); return MemberIterator(ref_, true); } @@ -617,8 +617,8 @@ class ReadableDynamicDataRef /// \returns An iterable representation of an aggregation dynamic data. MemberIterator items() const { - xtypes_assert(type_.is_aggregation_type(), - "items() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "items() isn't available for type '" << type_->name() << "'."); return MemberIterator(*this, false); } @@ -627,13 +627,29 @@ class ReadableDynamicDataRef ReadableDynamicDataRef( const DynamicType& type, uint8_t* source) - : type_(type.kind() == TypeKind::ALIAS_TYPE ? static_cast(type).rget() : type) - , instance_(source) + : instance_(source) , initialize_(true) { + const DynamicType* local = &type; + + if( type.kind() == TypeKind::ALIAS_TYPE ) + { + local = &static_cast(type).rget(); + } + + try + { + // is already associated to the DynamicData object + type_ = local->shared_from_this(); + } + catch(const std::bad_weak_ptr&) + { + // make a copy (if type changes may blow the DynamicData object) + type_ = local->clone(); + } } - const DynamicType& type_; + std::shared_ptr type_; uint8_t* instance_; bool initialize_ = false; @@ -650,14 +666,14 @@ class ReadableDynamicDataRef const std::string& member_name, bool read_only = true) const { - xtypes_assert(type_.is_aggregation_type(), - "operator [const std::string&] isn't available for type '" << type_.name() << "'."); - const AggregationType& aggregation = static_cast(type_); - xtypes_assert(type_.kind() != TypeKind::PAIR_TYPE, "PairType doesn't have operator [const std::string&]"); + xtypes_assert(type_->is_aggregation_type(), + "operator [const std::string&] isn't available for type '" << type_->name() << "'."); + const AggregationType& aggregation = static_cast(*type_); + xtypes_assert(type_->kind() != TypeKind::PAIR_TYPE, "PairType doesn't have operator [const std::string&]"); xtypes_assert(aggregation.has_member(member_name), - "Type '" << type_.name() << "' doesn't have a member named '" << member_name << "'."); + "Type '" << type_->name() << "' doesn't have a member named '" << member_name << "'."); - if (type_.kind() == TypeKind::UNION_TYPE) + if (type_->kind() == TypeKind::UNION_TYPE) { xtypes_assert( member_name != UNION_DISCRIMINATOR, @@ -679,10 +695,10 @@ class ReadableDynamicDataRef template > inline T _cast() const { - xtypes_assert(type_.is_primitive_type() || type_.is_enumerated_type(), + xtypes_assert(type_->is_primitive_type() || type_->is_enumerated_type(), "Expected a primitive type but '" << PrimitiveTypeKindTrait::name << "' received while casting data."); - switch (type_.kind()) + switch (type_->kind()) { case TypeKind::BOOLEAN_TYPE: { @@ -762,17 +778,17 @@ class ReadableDynamicDataRef case TypeKind::ENUMERATION_TYPE: { // For checking the associated_type, check for its memory_size - if (type_.memory_size() == sizeof(uint8_t)) + if (type_->memory_size() == sizeof(uint8_t)) { uint8_t temp = *this; return static_cast(temp); } - else if (type_.memory_size() == sizeof(uint16_t)) + else if (type_->memory_size() == sizeof(uint16_t)) { uint16_t temp = *this; return static_cast(temp); } - else if (type_.memory_size() == sizeof(uint32_t)) + else if (type_->memory_size() == sizeof(uint32_t)) { uint32_t temp = *this; return static_cast(temp); @@ -803,8 +819,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& operator = ( const WritableDynamicDataRef& other) { - type_.destroy_instance(instance_); - type_.copy_instance(instance_, p_instance(other)); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, p_instance(other)); return *this; } @@ -895,8 +911,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef void d( int64_t disc) { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); - UnionType& un = const_cast(static_cast(type_)); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); + UnionType& un = const_cast(static_cast(*type_)); un.select_disc(instance_, disc); } @@ -907,8 +923,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef void d( ReadableDynamicDataRef disc) { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); - UnionType& un = const_cast(static_cast(type_)); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); + UnionType& un = const_cast(static_cast(*type_)); un.select_disc(disc.type(), instance_, p_instance(disc)); } @@ -921,10 +937,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef ReadableDynamicDataRef data) { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "operator[const DynamicData&] is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); const PairType& pair = static_cast(map.content_type()); uint8_t* instance = map.get_instance_at(instance_, p_instance(data)); if (instance == nullptr) @@ -955,10 +971,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef ReadableDynamicDataRef data) const { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "insert method is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); xtypes_assert(map.content_type().is_compatible(data.type()) == TypeConsistency::EQUALS, "Types doesn't match"); return map.insert_instance(instance_, p_instance(data)) != nullptr; } @@ -969,10 +985,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef ReadableDynamicDataRef key) const { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "has_key method is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); [[maybe_unused]] const PairType& pair = static_cast(map.content_type()); xtypes_assert(pair.first().is_compatible(key.type()) == TypeConsistency::EQUALS, "Key types doesn't match."); return map.has_key(instance_, p_instance(key)); @@ -985,27 +1001,27 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef void value( const T& t) { - xtypes_assert((type_.kind() == TypeKind::STRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::WSTRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::STRING16_TYPE && std::is_same::value) - || (type_.kind() == PrimitiveTypeKindTrait::kind) - || (type_.is_enumerated_type()), - "Expected type '" << type_.name() + xtypes_assert((type_->kind() == TypeKind::STRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::WSTRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::STRING16_TYPE && std::is_same::value) + || (type_->kind() == PrimitiveTypeKindTrait::kind) + || (type_->is_enumerated_type()), + "Expected type '" << type_->name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while setting value.", true); - if (type_.is_enumerated_type()) + if (type_->is_enumerated_type()) { - xtypes_assert(type_.memory_size() == sizeof(T), - "Incompatible types: '" << type_.name() << "' and '" + xtypes_assert(type_->memory_size() == sizeof(T), + "Incompatible types: '" << type_->name() << "' and '" << PrimitiveTypeKindTrait::name << "'."); - [[maybe_unused]] const EnumeratedType& enum_type = static_cast&>(type_); + [[maybe_unused]] const EnumeratedType& enum_type = static_cast&>(*type_); xtypes_assert(enum_type.is_allowed_value(t), - "Trying to set an invalid value for enumerated type '" << type_.name() << "'."); + "Trying to set an invalid value for enumerated type '" << type_->name() << "'."); } - type_.destroy_instance(instance_); - type_.copy_instance(instance_, reinterpret_cast(&t)); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, reinterpret_cast(&t)); } /// \brief Push a primitive or string value into the DynamicData that represents a SequenceType @@ -1017,14 +1033,14 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& push( const T& t) // this = SequenceType { - xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, - "push() is only available for sequence types but called for '" << type_.name() << "'."); - const SequenceType& sequence = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::SEQUENCE_TYPE, + "push() is only available for sequence types but called for '" << type_->name() << "'."); + const SequenceType& sequence = static_cast(*type_); xtypes_assert((sequence.content_type().kind() == TypeKind::STRING_TYPE && std::is_same::value) || (sequence.content_type().kind() == TypeKind::WSTRING_TYPE && std::is_same::value) || (sequence.content_type().kind() == TypeKind::STRING16_TYPE && std::is_same::value) || (sequence.content_type().kind() == primitive_type().kind()), - "Expected type '" << static_cast(type_).content_type().name() + "Expected type '" << static_cast(*type_).content_type().name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while pushing value."); uint8_t* element = sequence.push_instance(instance_, reinterpret_cast(&t)); @@ -1040,9 +1056,9 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& push( const ReadableDynamicDataRef& data) // this = SequenceType { - xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, - "push() is only available for sequence types but called for '" << type_.name() << "'."); - const SequenceType& sequence = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::SEQUENCE_TYPE, + "push() is only available for sequence types but called for '" << type_->name() << "'."); + const SequenceType& sequence = static_cast(*type_); uint8_t* element = sequence.push_instance(instance_, p_instance(data)); xtypes_assert(element != nullptr, "Bound limit reached while pushing value."); (void) element; @@ -1059,13 +1075,13 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& resize( size_t size) // this = SequenceType { - xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, - "resize() is only available for sequence types but called for '" << type_.name() << "'."); + xtypes_assert(type_->kind() == TypeKind::SEQUENCE_TYPE, + "resize() is only available for sequence types but called for '" << type_->name() << "'."); [[maybe_unused]] size_t bound = bounds(); xtypes_assert(!bound || bound >= size, "The desired size (" << size << ") is bigger than maximum allowed size for the type '" - << type_.name() << "' (" << bounds() << ")."); - const SequenceType& sequence = static_cast(type_); + << type_->name() << "' (" << bounds() << ")."); + const SequenceType& sequence = static_cast(*type_); sequence.resize_instance(instance_, size); return *this; } @@ -1102,10 +1118,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef bool for_each( std::function visitor) { - Instanceable::InstanceNode root(type_, instance_); + Instanceable::InstanceNode root(*type_, instance_); try { - type_.for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) + type_->for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) { WritableNode node(instance_node); visitor(node); @@ -1199,7 +1215,7 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef MemberPair operator * () { - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); return MemberPair( aggregation.member(index_), instance_ + aggregation.member(index_).offset()); @@ -1257,8 +1273,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef /// \returns An iterable representation of an aggregation dynamic data. MemberIterator items() { - xtypes_assert(type_.is_aggregation_type(), - "items() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "items() isn't available for type '" << type_->name() << "'."); return MemberIterator(*this, false); } @@ -1267,8 +1283,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef /// \returns An iterable representation of an aggregation dynamic data. ReadableDynamicDataRef::MemberIterator citems() { - xtypes_assert(type_.is_aggregation_type(), - "citems() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "citems() isn't available for type '" << type_->name() << "'."); return ReadableDynamicDataRef::MemberIterator(*this, false); } @@ -1309,7 +1325,7 @@ class DynamicData : public WritableDynamicDataRef : WritableDynamicDataRef(type, new uint8_t[type.memory_size()]) { memset(instance_, 0, type.memory_size()); - type_.construct_instance(instance_); + type_->construct_instance(instance_); initialize_ = true; } @@ -1336,31 +1352,31 @@ class DynamicData : public WritableDynamicDataRef const DynamicType& type) : WritableDynamicDataRef(type, new uint8_t[type.memory_size()]) { - xtypes_assert(type_.is_compatible(other.type()) != TypeConsistency::NONE, + xtypes_assert(type_->is_compatible(other.type()) != TypeConsistency::NONE, "Incompatible types in DynamicData(const ReadableDynamicDataRef&, const DynamicType&): '" - << type_.name() << "' isn't compatible with '" << other.type().name() << "'."); + << type_->name() << "' isn't compatible with '" << other.type().name() << "'."); memset(instance_, 0, type.memory_size()); - type_.copy_instance_from_type(instance_, p_instance(other), other.type()); + type_->copy_instance_from_type(instance_, p_instance(other), other.type()); initialize_ = true; } /// \brief Copy constructor DynamicData( const DynamicData& other) - : WritableDynamicDataRef(other.type_, new uint8_t[other.type_.memory_size()]) + : WritableDynamicDataRef(*other.type_, new uint8_t[other.type_->memory_size()]) { memset(instance_, 0, other.type().memory_size()); - type_.copy_instance(instance_, p_instance(other)); + type_->copy_instance(instance_, p_instance(other)); initialize_ = true; } /// \brief Move constructor DynamicData( DynamicData&& other) - : WritableDynamicDataRef(other.type_, new uint8_t[other.type_.memory_size()]) + : WritableDynamicDataRef(*other.type_, new uint8_t[other.type_->memory_size()]) { memset(instance_, 0, other.type().memory_size()); - type_.move_instance(instance_, p_instance(other), false); + type_->move_instance(instance_, p_instance(other), false); other.initialize_ = false; } @@ -1368,11 +1384,11 @@ class DynamicData : public WritableDynamicDataRef DynamicData& operator = ( const DynamicData& other) { - xtypes_assert(type_.is_compatible(other.type()) == TypeConsistency::EQUALS, + xtypes_assert(type_->is_compatible(other.type()) == TypeConsistency::EQUALS, "Cannot assign DynamicData of type '" << other.type().name() << "' to DynamicData of type '" - << type_.name() << "'."); - type_.destroy_instance(instance_); - type_.copy_instance(instance_, p_instance(other)); + << type_->name() << "'."); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, p_instance(other)); return *this; } @@ -1380,11 +1396,11 @@ class DynamicData : public WritableDynamicDataRef DynamicData& operator = ( ReadableDynamicDataRef other) { - xtypes_assert(type_.is_compatible(other.type()) == TypeConsistency::EQUALS, + xtypes_assert(type_->is_compatible(other.type()) == TypeConsistency::EQUALS, "Cannot assign DynamicData of type '" << other.type().name() << "' to DynamicData of type '" - << type_.name() << "'."); - type_.destroy_instance(instance_); - type_.copy_instance(instance_, p_instance(other)); + << type_->name() << "'."); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, p_instance(other)); return *this; } @@ -1575,7 +1591,7 @@ class DynamicData : public WritableDynamicDataRef { if(initialize_) { - type_.destroy_instance(instance_); + type_->destroy_instance(instance_); } delete[] instance_; } diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 46fe849..02fd2a6 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -27,7 +27,7 @@ namespace xtypes { #define DYNAMIC_DATA_NUMERIC_SIGNED_INT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::INT_8_TYPE:\ MACRO(int8_t, OPERATOR);\ @@ -39,14 +39,14 @@ namespace xtypes { MACRO(int64_t, OPERATOR);\ default:\ xtypes_assert(false,\ - "Operator" << #OPERATOR << "() isn't available for type '" << type_.name() << "'.");\ + "Operator" << #OPERATOR << "() isn't available for type '" << type_->name() << "'.");\ return *this;\ }\ } #define DYNAMIC_DATA_NUMERIC_INT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::UINT_8_TYPE:\ MACRO(uint8_t, OPERATOR);\ @@ -63,7 +63,7 @@ namespace xtypes { #define DYNAMIC_DATA_NUMERIC_FLT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::FLOAT_32_TYPE:\ MACRO(float, OPERATOR);\ @@ -89,7 +89,7 @@ namespace xtypes { #define DYNAMIC_DATA_BASICTYPE_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::CHAR_8_TYPE:\ MACRO(char, OPERATOR);\ @@ -106,7 +106,7 @@ namespace xtypes { #define DYNAMIC_DATA_BASICTYPE_INT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::CHAR_8_TYPE:\ MACRO(char, OPERATOR);\ @@ -236,29 +236,29 @@ inline std::string ReadableDynamicDataRef::to_string() const template<> inline std::string ReadableDynamicDataRef::cast() const { - xtypes_assert(type_.is_primitive_type() || - type_.kind() == TypeKind::STRING_TYPE || - type_.kind() == TypeKind::WSTRING_TYPE || - type_.kind() == TypeKind::STRING16_TYPE || - type_.is_enumerated_type(), - "Expected a primitive or string type but '" << type_.name() << "' received while casting data to 'std::string'."); + xtypes_assert(type_->is_primitive_type() || + type_->kind() == TypeKind::STRING_TYPE || + type_->kind() == TypeKind::WSTRING_TYPE || + type_->kind() == TypeKind::STRING16_TYPE || + type_->is_enumerated_type(), + "Expected a primitive or string type but '" << type_->name() << "' received while casting data to 'std::string'."); // Custom switch-case statement for types not contained in the macros - switch (type_.kind()) + switch (type_->kind()) { case TypeKind::ENUMERATION_TYPE: { // For checking the associated_type, check for its memory_size - if (type_.memory_size() == sizeof(uint8_t)) + if (type_->memory_size() == sizeof(uint8_t)) { uint8_t temp = *this; return std::to_string(temp); } - else if (type_.memory_size() == sizeof(uint16_t)) + else if (type_->memory_size() == sizeof(uint16_t)) { uint16_t temp = *this; return std::to_string(temp); } - else if (type_.memory_size() == sizeof(uint32_t)) + else if (type_->memory_size() == sizeof(uint32_t)) { uint32_t temp = *this; return std::to_string(temp); @@ -347,7 +347,7 @@ inline DynamicData& DynamicData::operator -- () inline bool DynamicData::operator ! () const { - switch(type_.kind()) + switch(type_->kind()) { case TypeKind::STRING_TYPE: return this->value().empty(); @@ -419,7 +419,7 @@ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& #define DYNAMIC_DATA_NUMERIC_SAFE_OPERATOR_IMPLEMENTATION(OPERATOR)\ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& other) const \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::CHAR_8_TYPE:\ case TypeKind::CHAR_16_TYPE:\ @@ -428,7 +428,7 @@ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& {\ std::ostringstream os;\ os << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR)\ - << " is not supported for type " << type_.name();\ + << " is not supported for type " << type_->name();\ throw std::runtime_error(os.str());\ }\ default:\ diff --git a/include/xtypes/DynamicType.hpp b/include/xtypes/DynamicType.hpp index 492d698..fa633d8 100644 --- a/include/xtypes/DynamicType.hpp +++ b/include/xtypes/DynamicType.hpp @@ -24,12 +24,17 @@ #include #include +#include namespace eprosima { namespace xtypes { +class ReadableDynamicDataRef; +class SequenceInstance; + /// \brief Abstract base class for all dynamic types. -class DynamicType : public Instanceable +class DynamicType : public Instanceable, + public std::enable_shared_from_this { public: @@ -214,11 +219,14 @@ class DynamicType : public Instanceable /// \brief Deep clone of the DynamicType. /// \returns a new DynamicType without managing. - virtual DynamicType* clone() const = 0; + virtual std::shared_ptr clone() const = 0; TypeKind kind_; std::string name_; + friend class ReadableDynamicDataRef; + friend class SequenceInstance; + public: /// \brief Special managed pointer for DynamicTypes. @@ -228,35 +236,39 @@ class DynamicType : public Instanceable public: /// \brief Default initialization without pointer any type. - Ptr() - : type_(nullptr) - { - } + Ptr() = default; /// \brief Creates a copy of a DynamicType that will be managed. /// The copy is avoid if DynamnicType is primitive. - Ptr( - const DynamicType& type) - : type_(dont_clone_type(&type) ? &type : type.clone()) + Ptr(const DynamicType& type) { + try + { + if(dont_clone_type(&type)) + { + type_ = type.shared_from_this(); + return; + } + } + catch(const std::bad_weak_ptr&) {} + + // make a copy + type_ = type.clone(); } /// \brief Copy constructor. /// Makes an internal copy of the managed DynamicType. - /// The copy is avoid if DynamnicType is primitive. - Ptr( - const Ptr& ptr) - : type_(dont_clone_type(ptr.type_) ? ptr.type_ : ptr.type_->clone()) + /// The copy is avoid if DynamicType is primitive. + Ptr(const Ptr& ptr) { - } + if(!ptr.type_) + return; - Ptr( - Ptr&& ptr) - : type_(ptr.type_) - { - ptr.type_ = nullptr; + new (this) Ptr(*ptr.type_); } + Ptr(Ptr&& ptr) = default; + Ptr& operator = ( const Ptr& ptr) { @@ -265,24 +277,11 @@ class DynamicType : public Instanceable return *this; } - reset(); - type_ = dont_clone_type(ptr.type_) ? ptr.type_ : ptr.type_->clone(); + type_ = dont_clone_type(ptr.type_.get()) ? ptr.type_ : ptr.type_->clone(); return *this; } - Ptr& operator = ( - Ptr&& ptr) - { - if (type_ == ptr.type_) - { - return *this; - } - - reset(); - type_ = ptr.type_; - ptr.type_ = nullptr; - return *this; - } + Ptr& operator = ( Ptr&& ptr) = default; bool operator == ( const DynamicType::Ptr& ptr) const @@ -290,26 +289,11 @@ class DynamicType : public Instanceable return ptr.type_ == type_; } - virtual ~Ptr() - { - reset(); - } - - /// \brief Remove the managed DynamicType and points to nothing. - void reset() - { - if (!dont_clone_type(type_)) - { - delete type_; - } - type_ = nullptr; - } - /// \brief Free the internal managed DynamicType and points to nothing. - const DynamicType* free() + std::shared_ptr free() { - const DynamicType* freed = type_; - type_ = nullptr; + std::shared_ptr freed; + type_.swap(freed); return freed; } @@ -317,21 +301,21 @@ class DynamicType : public Instanceable /// \returns A pointer of the internal managed DynamicType. const DynamicType* get() const { - return type_; + return type_.get(); } /// \brief Returns a pointer of the internal managed DynamicType. /// \returns A pointer of the internal managed DynamicType. const DynamicType* operator ->() const { - return type_; + return type_.get(); } /// \brief Get a non-const pointer of the internal managed DynamicType. /// \returns A non-const pointer of the interal managed DynamicType DynamicType* operator ->() { - return const_cast(type_); + return const_cast(type_.get()); } /// \brief Returns a reference of the intenral managed DynamicType. @@ -343,7 +327,7 @@ class DynamicType : public Instanceable private: - const DynamicType* type_; + std::shared_ptr type_; static bool dont_clone_type( const DynamicType* type) diff --git a/include/xtypes/EnumeratedType.hpp b/include/xtypes/EnumeratedType.hpp index 8b35c67..6b4587f 100644 --- a/include/xtypes/EnumeratedType.hpp +++ b/include/xtypes/EnumeratedType.hpp @@ -121,19 +121,20 @@ class EnumeratedType : public PrimitiveType return consistency; } -protected: - virtual DynamicType* clone() const override - { - EnumeratedType* result = new EnumeratedType(PrimitiveType::kind(), PrimitiveType::name()); - result->values_ = values_; - return result; - } - EnumeratedType( TypeKind kind, const std::string& name) - : PrimitiveType(kind, name) + : PrimitiveType(typename PrimitiveType::use_function_primitive_type{}, kind, name) + { + } + +protected: + + std::shared_ptr clone() const override { + auto clon = std::make_shared(this->kind(), this->name()); + clon->values_ = values_; + return clon; } /// \brief Insert a enumerator into the enumerated. diff --git a/include/xtypes/MapInstance.hpp b/include/xtypes/MapInstance.hpp index 8d18771..305c0c0 100644 --- a/include/xtypes/MapInstance.hpp +++ b/include/xtypes/MapInstance.hpp @@ -37,11 +37,22 @@ class MapInstance MapInstance( const PairType& content, uint32_t capacity = 0) - : content_(content) - , block_size_(content.memory_size()) + : block_size_(content.memory_size()) , capacity_(capacity) , size_(0) { + std::shared_ptr tmp; + try + { + tmp = (content.shared_from_this()); + } + catch(const std::bad_weak_ptr&) + { + tmp = content.clone(); + } + + content_ = std::static_pointer_cast(std::move(tmp)); + init_memory(memory_, capacity_); } @@ -68,7 +79,7 @@ class MapInstance const MapInstance& other, uint32_t bounds) : content_(other.content_) - , block_size_(content_.memory_size()) + , block_size_(content_->memory_size()) , capacity_(bounds == 0 ? other.capacity_ : std::min(other.capacity_, bounds)) , size_(bounds == 0 ? other.size_ : std::min(other.size_, bounds)) { @@ -100,12 +111,12 @@ class MapInstance return false; } - if (content_.first().is_constructed_type() || content_.second().is_constructed_type()) + if (content_->first().is_constructed_type() || content_->second().is_constructed_type()) { bool comp = true; for (uint32_t i = 0; i < size_; i++) { - comp &= content_.compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); + comp &= content_->compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); } return comp; } @@ -135,7 +146,8 @@ class MapInstance } uint8_t* place = create_place(instance); - content_.first().copy_instance(place, instance); // Only copies the key + content_->first().copy_instance(place, instance); + content_->second().construct_instance(place + content_->first().memory_size()); size_++; @@ -184,10 +196,10 @@ class MapInstance { if (size_ > 0) { - uint64_t h = content_.hash(memory_); + uint64_t h = content_->hash(memory_); for (uint32_t i = 1; i < size_; ++i) { - Instanceable::hash_combine(h, content_.hash(get_element(i))); + Instanceable::hash_combine(h, content_->hash(get_element(i))); } return h; } @@ -198,7 +210,7 @@ class MapInstance friend class MapType; - const PairType& content_; + std::shared_ptr content_; uint32_t block_size_ = 0; uint32_t capacity_ = 0; uint8_t* memory_ = nullptr; @@ -235,7 +247,7 @@ class MapInstance memset(memory, 0, size * block_size_); for (uint32_t idx = 0; idx < size; ++idx) { - content_.construct_instance(memory + idx * block_size_); + content_->construct_instance(memory + idx * block_size_); } } } @@ -245,8 +257,8 @@ class MapInstance const MapInstance& other, uint32_t bounds) { - size_t other_first_size = other.content_.first().memory_size(); - size_t other_second_size = other.content_.second().memory_size(); + size_t other_first_size = other.content_->first().memory_size(); + size_t other_second_size = other.content_->second().memory_size(); // Check bytes to copy uint32_t min_capacity = std::min(capacity_, other.capacity_); @@ -268,17 +280,17 @@ class MapInstance realloc(min_size, bounds); } - if (content_.first().is_constructed_type() - || content_.second().is_constructed_type() - || content_.first().memory_size() != other_first_size - || content_.second().memory_size() != other_second_size) + if (content_->first().is_constructed_type() + || content_->second().is_constructed_type() + || content_->first().memory_size() != other_first_size + || content_->second().memory_size() != other_second_size) { for (uint32_t i = 0; i < min_size; i++) { - content_.copy_instance_from_type( + content_->copy_instance_from_type( memory_ + i * block_size_, - other.memory_ + i * other.content_.memory_size(), - other.content_); + other.memory_ + i * other.content_->memory_size(), + *other.content_); } } else //optimization when the pair are both primitive with same size @@ -295,7 +307,7 @@ class MapInstance { if (source != nullptr) { - if (content_.first().is_constructed_type() || content_.second().is_constructed_type()) + if (content_->first().is_constructed_type() || content_->second().is_constructed_type()) { if (overlap && check_overlap(target, source)) { @@ -303,7 +315,7 @@ class MapInstance uint32_t to_move = size_ - get_key_index(source); for (uint32_t i = to_move; i > 0; --i) { - content_.move_instance(target + (i - 1) * block_size_, source + (i - 1) * block_size_, true); + content_->move_instance(target + (i - 1) * block_size_, source + (i - 1) * block_size_, true); } } else @@ -311,7 +323,7 @@ class MapInstance // Moving full memory for (uint32_t i = 0; i < size_; ++i) { - content_.move_instance(target + i * block_size_, source + i * block_size_, true); + content_->move_instance(target + i * block_size_, source + i * block_size_, true); } } } @@ -438,18 +450,18 @@ class MapInstance uint64_t hash( const uint8_t* instance) const { - return content_.first().hash(instance); + return content_->first().hash(instance); } void free_memory() { if (memory_ != nullptr) { - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { for (int32_t i = capacity_ - 1; i >= 0; i--) { - content_.destroy_instance(memory_ + i * block_size_); + content_->destroy_instance(memory_ + i * block_size_); } } diff --git a/include/xtypes/MapType.hpp b/include/xtypes/MapType.hpp index cfed069..d6bf866 100644 --- a/include/xtypes/MapType.hpp +++ b/include/xtypes/MapType.hpp @@ -71,7 +71,7 @@ class MapType : public MutableCollectionType MapType( MapType&& other) = default; - virtual size_t memory_size() const override + size_t memory_size() const override { return sizeof(MapInstance); } @@ -250,9 +250,9 @@ class MapType : public MutableCollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new MapType(*this); + return std::make_shared(*this); } }; diff --git a/include/xtypes/PairType.hpp b/include/xtypes/PairType.hpp index 056f019..ba59729 100644 --- a/include/xtypes/PairType.hpp +++ b/include/xtypes/PairType.hpp @@ -25,6 +25,8 @@ namespace eprosima { namespace xtypes { +class MapInstance; + class PairType : public DynamicType { public: @@ -80,19 +82,19 @@ class PairType : public DynamicType second_ = DynamicType::Ptr(std::move(second)); } - virtual size_t memory_size() const override + size_t memory_size() const override { return first_->memory_size() + second_->memory_size(); } - virtual void construct_instance( + void construct_instance( uint8_t* instance) const override { first_->construct_instance(instance); second_->construct_instance(instance + first_->memory_size()); } - virtual void copy_instance( + void copy_instance( uint8_t* target, const uint8_t* source) const override { @@ -100,7 +102,7 @@ class PairType : public DynamicType second_->copy_instance(target + first_->memory_size(), source + first_->memory_size()); } - virtual void copy_instance_from_type( + void copy_instance_from_type( uint8_t* target, const uint8_t* source, const DynamicType& arg_other) const override @@ -127,7 +129,7 @@ class PairType : public DynamicType second_->copy_instance_from_type(target + first_->memory_size(), source + first_->memory_size(), pair.second()); } - virtual void move_instance( + void move_instance( uint8_t* target, uint8_t* source, bool initialized) const override @@ -136,14 +138,14 @@ class PairType : public DynamicType second_->move_instance(target + first_->memory_size(), source + first_->memory_size(), initialized); } - virtual void destroy_instance( + void destroy_instance( uint8_t* instance) const override { first_->destroy_instance(instance); second_->destroy_instance(instance + first_->memory_size()); } - virtual bool compare_instance( + bool compare_instance( const uint8_t* instance, const uint8_t* other_instance) const override { @@ -152,7 +154,7 @@ class PairType : public DynamicType second_->compare_instance(instance + first_->memory_size(), other_instance + first_->memory_size()); } - virtual TypeConsistency is_compatible( + TypeConsistency is_compatible( const DynamicType& other) const override { if (other.kind() == TypeKind::ALIAS_TYPE) @@ -171,7 +173,7 @@ class PairType : public DynamicType return TypeConsistency::NONE; } - virtual void for_each_type( + void for_each_type( const TypeNode& node, TypeVisitor visitor) const override { @@ -191,7 +193,7 @@ class PairType : public DynamicType second_->for_each_type(s, visitor); } - virtual void for_each_instance( + void for_each_instance( const InstanceNode& node, InstanceVisitor visitor) const override { @@ -211,7 +213,7 @@ class PairType : public DynamicType second_->for_each_instance(s, visitor); } - virtual uint64_t hash( + uint64_t hash( const uint8_t* instance) const override { uint64_t h = first_->hash(instance); @@ -224,11 +226,12 @@ class PairType : public DynamicType DynamicType::Ptr first_; DynamicType::Ptr second_; - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new PairType(*this); + return std::make_shared(*this); } + friend class MapInstance; }; } // namespace xtypes diff --git a/include/xtypes/PrimitiveType.hpp b/include/xtypes/PrimitiveType.hpp index af4dfef..2e32a73 100644 --- a/include/xtypes/PrimitiveType.hpp +++ b/include/xtypes/PrimitiveType.hpp @@ -80,22 +80,30 @@ template class PrimitiveType : public DynamicType { protected: + // Avoid direct use of the class (there is a factory) + // Allow the use in subclasses + struct use_function_primitive_type {}; - template - friend const DynamicType& primitive_type(); +public: - PrimitiveType() + PrimitiveType(use_function_primitive_type) : DynamicType(PrimitiveTypeKindTrait::kind, PrimitiveTypeKindTrait::name) { } PrimitiveType( + use_function_primitive_type, TypeKind kind, const std::string& name) : DynamicType(kind, name) { } +protected: + + template + friend const DynamicType& primitive_type(); + PrimitiveType( const PrimitiveType& other) = delete; PrimitiveType( @@ -114,8 +122,8 @@ class PrimitiveType : public DynamicType virtual void destroy_instance( uint8_t* /*instance*/) const override - { - } //Default does nothing + { //Default does nothing + } virtual void copy_instance( uint8_t* target, @@ -267,11 +275,11 @@ class PrimitiveType : public DynamicType visitor(node); } - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new PrimitiveType(); - } + return std::make_shared>(use_function_primitive_type{}, this->kind(), this->name()); + } }; /// \brief Helper function to create a PrimitiveType. @@ -284,7 +292,7 @@ const DynamicType& primitive_type() // The creation of PrimitiveType must be always done // by this function in order to not broken the DynamicType::Ptr // optimizations for PrimitiveType - static PrimitiveType p; + static PrimitiveType p(typename PrimitiveType::use_function_primitive_type{}); return p; } diff --git a/include/xtypes/SequenceInstance.hpp b/include/xtypes/SequenceInstance.hpp index 622691c..48779ec 100644 --- a/include/xtypes/SequenceInstance.hpp +++ b/include/xtypes/SequenceInstance.hpp @@ -37,11 +37,21 @@ class SequenceInstance SequenceInstance( const DynamicType& content, uint32_t capacity = 0) - : content_(content) - , block_size_(content.memory_size()) + : block_size_(content.memory_size()) , capacity_(capacity) , size_(0) { + try + { + // is already associated to the DynamicData object + content_ = content.shared_from_this(); + } + catch(const std::bad_weak_ptr&) + { + // make a copy (if type changes may blow the DynamicData object) + content_ = content.clone(); + } + init_memory(memory_, capacity_); } @@ -69,11 +79,21 @@ class SequenceInstance const SequenceInstance& other, const DynamicType& content, uint32_t bounds) - : content_(content) - , block_size_(content.memory_size()) + : block_size_(content.memory_size()) , capacity_(bounds == 0 ? other.capacity_ : std::min(other.capacity_, bounds)) , size_(bounds == 0 ? other.size_ : std::min(other.size_, bounds)) { + try + { + // is already associated to the DynamicData object + content_ = content.shared_from_this(); + } + catch(const std::bad_weak_ptr&) + { + // make a copy (if type changes may blow the DynamicData object) + content_ = content.clone(); + } + init_memory(memory_, capacity_); if (memory_ != nullptr) @@ -102,12 +122,12 @@ class SequenceInstance return false; } - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { bool comp = true; for (uint32_t i = 0; i < size_; i++) { - comp &= content_.compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); + comp &= content_->compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); } return comp; } @@ -136,7 +156,7 @@ class SequenceInstance } uint8_t* place = memory_ + size_ * block_size_; - content_.copy_instance(place, instance); + content_->copy_instance(place, instance); size_++; @@ -160,7 +180,7 @@ class SequenceInstance for (size_t i = size_; i < new_size; i++) { uint8_t* place = memory_ + i * block_size_; - content_.construct_instance(place); + content_->construct_instance(place); } size_ = new_size; @@ -188,7 +208,7 @@ class SequenceInstance friend class SequenceType; - const DynamicType& content_; + std::shared_ptr content_; uint32_t block_size_ = 0; uint32_t capacity_ = 0; uint8_t* memory_ = nullptr; @@ -225,7 +245,7 @@ class SequenceInstance memset(memory, 0, size * block_size_); for (uint32_t idx = 0; idx < size; ++idx) { - content_.construct_instance(memory + idx * block_size_); + content_->construct_instance(memory + idx * block_size_); } } } @@ -235,7 +255,7 @@ class SequenceInstance const SequenceInstance& other, uint32_t bounds) { - size_t other_block_size = other.content_.memory_size(); + size_t other_block_size = other.content_->memory_size(); // Check bytes to copy uint32_t min_capacity = std::min(capacity_, other.capacity_); @@ -257,14 +277,14 @@ class SequenceInstance realloc(min_size, bounds); } - if (content_.is_constructed_type() || block_size_ != other_block_size) + if (content_->is_constructed_type() || block_size_ != other_block_size) { for (uint32_t i = 0; i < min_size; i++) { - content_.copy_instance_from_type( + content_->copy_instance_from_type( memory_ + i * block_size_, other.memory_ + i * other_block_size, - other.content_); + *other.content_); } } else //optimization when the type is primitive with same block_size @@ -280,11 +300,11 @@ class SequenceInstance { if (source != nullptr) { - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { for (uint32_t i = 0; i < size_; i++) { - content_.move_instance(target + i * block_size_, source + i * block_size_, true); + content_->move_instance(target + i * block_size_, source + i * block_size_, true); } } else //optimization when the type is primitive @@ -298,11 +318,11 @@ class SequenceInstance { if (memory_ != nullptr) { - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { for (int32_t i = capacity_ - 1; i >= 0; i--) { - content_.destroy_instance(memory_ + i * block_size_); + content_->destroy_instance(memory_ + i * block_size_); } } diff --git a/include/xtypes/SequenceType.hpp b/include/xtypes/SequenceType.hpp index c5c87c5..84500a0 100644 --- a/include/xtypes/SequenceType.hpp +++ b/include/xtypes/SequenceType.hpp @@ -256,9 +256,9 @@ class SequenceType : public MutableCollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new SequenceType(*this); + return std::make_shared(*this); } }; diff --git a/include/xtypes/StringType.hpp b/include/xtypes/StringType.hpp index 8ac3531..382949b 100644 --- a/include/xtypes/StringType.hpp +++ b/include/xtypes/StringType.hpp @@ -186,9 +186,9 @@ class TStringType : public MutableCollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new TStringType(*this); + return std::make_shared(*this); } }; diff --git a/include/xtypes/StructType.hpp b/include/xtypes/StructType.hpp index d7841e5..6ee3ca1 100644 --- a/include/xtypes/StructType.hpp +++ b/include/xtypes/StructType.hpp @@ -282,9 +282,9 @@ class StructType : public AggregationType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new StructType(*this); + return std::make_shared(*this); } private: diff --git a/include/xtypes/UnionType.hpp b/include/xtypes/UnionType.hpp index cd8489f..65ba758 100644 --- a/include/xtypes/UnionType.hpp +++ b/include/xtypes/UnionType.hpp @@ -465,9 +465,9 @@ class UnionType : public AggregationType friend ReadableDynamicDataRef; friend WritableDynamicDataRef; - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new UnionType(*this); + return std::make_shared(*this); } /// \brief This method adds the discriminator has the first member of the aggregation. diff --git a/test/unitary/xtypes/primitive_types.cpp b/test/unitary/xtypes/primitive_types.cpp index 8634676..0cb65c5 100644 --- a/test/unitary/xtypes/primitive_types.cpp +++ b/test/unitary/xtypes/primitive_types.cpp @@ -193,6 +193,29 @@ TEST (PrimitiveTypes, primitive_type_int32_uint16) EXPECT_TRUE((singleCheck(55, 55))); } +// Comes from issue #105 +TEST(EnumerationType, stack_datatype_deleted) +{ + auto getTestEnum = [] + { + EnumerationType testEnum("TestEnum"); + testEnum.add_enumerator("item0"); + testEnum.add_enumerator("item1"); + testEnum.add_enumerator("item2"); + + DynamicData test(testEnum); + EXPECT_NO_THROW({test.to_string();}); + + DynamicData test2(test); + EXPECT_NO_THROW({test2.to_string();}); + + return test; + }; + + DynamicData testData(getTestEnum()); + EXPECT_NO_THROW({testData.to_string();}); +} + TEST(EnumerationType, enumeration_tests) { // Creation and expected operation