diff --git a/applications/MeshingApplication/custom_processes/mmg/mmg_process.cpp b/applications/MeshingApplication/custom_processes/mmg/mmg_process.cpp index deba889512c0..1853be2c8ed7 100755 --- a/applications/MeshingApplication/custom_processes/mmg/mmg_process.cpp +++ b/applications/MeshingApplication/custom_processes/mmg/mmg_process.cpp @@ -32,7 +32,7 @@ /* The mappers includes */ #include "spaces/ublas_space.h" #include "mappers/mapper_flags.h" -#include "factories/mapper_factory.h" +#include "factories/mapper_factory.h" // NOTE: The following contains the license of the MMG library /* ============================================================================= @@ -366,6 +366,10 @@ void MmgProcess::InitializeMeshData() for (auto it_dof = mDofs.begin(); it_dof != mDofs.end(); ++it_dof) (**it_dof).FreeDof(); + mrThisModelPart.Nodes().Unique(); + mrThisModelPart.Conditions().Unique(); + mrThisModelPart.Elements().Unique(); + // Generate the maps of reference mMmgUtilities.GenerateReferenceMaps(mrThisModelPart, aux_ref_cond, aux_ref_elem, mpRefCondition, mpRefElement); @@ -590,7 +594,7 @@ void MmgProcess::ExecuteRemeshing() ModelPart& r_old_auxiliar_model_part = r_old_model_part.GetSubModelPart("AUXILIAR_COLLAPSED_PRISMS"); ModelPart& r_auxiliary_model_part = mrThisModelPart.GetSubModelPart("AUXILIAR_COLLAPSED_PRISMS"); - // Define mapper factory + // Define mapper factory DEFINE_MAPPER_FACTORY_SERIAL if (MapperFactoryType::HasMapper("nearest_element") && mThisParameters["use_mapper_if_available"].GetBool()) { KRATOS_INFO_IF("MmgProcess", mEchoLevel > 0) << "Using MappingApplication to interpolate values" << std::endl; @@ -1504,7 +1508,7 @@ const Parameters MmgProcess::GetDefaultParameters() const "max_num_search_iterations" : 8, "echo_level" : 0 } - }, + }, "extrapolate_contour_values" : true, "surface_elements" : false, "search_parameters" : { diff --git a/applications/MeshingApplication/custom_utilities/mmg/mmg_utilities.cpp b/applications/MeshingApplication/custom_utilities/mmg/mmg_utilities.cpp index d35f93d669ea..54274ffbd38f 100644 --- a/applications/MeshingApplication/custom_utilities/mmg/mmg_utilities.cpp +++ b/applications/MeshingApplication/custom_utilities/mmg/mmg_utilities.cpp @@ -2854,7 +2854,7 @@ void MmgUtilities::SetLocalParameter( double HMin, double HMax, double HausdorffValue - ) + ) { if ( MMG2D_Set_localParameter(mMmgMesh, mMmgMet, MMG5_Edg, rColor, HMin, HMax, HausdorffValue) != 1) KRATOS_ERROR << "Unable to set local parameter" << std::endl; @@ -2869,7 +2869,7 @@ void MmgUtilities::SetLocalParameter( double HMin, double HMax, double HausdorffValue - ) + ) { if ( MMG3D_Set_localParameter(mMmgMesh, mMmgMet, MMG5_Triangle, rColor, HMin, HMax, HausdorffValue) != 1) KRATOS_ERROR << "Unable to set local parameter" << std::endl; @@ -2884,7 +2884,7 @@ void MmgUtilities::SetLocalParameter( double HMin, double HMax, double HausdorffValue - ) + ) { if ( MMGS_Set_localParameter(mMmgMesh, mMmgMet, MMG5_Triangle, rColor, HMin, HMax, HausdorffValue) != 1) KRATOS_ERROR << "Unable to set local parameter" << std::endl; @@ -3578,6 +3578,10 @@ void MmgUtilities::ReorderAllIds(ModelPart& rModelPart) for(IndexType i = 0; i < r_elements_array.size(); ++i) (it_elem_begin + i)->SetId(i + 1); + r_nodes_array.Unique(); + r_conditions_array.Unique(); + r_elements_array.Unique(); + KRATOS_CATCH(""); } @@ -3801,6 +3805,8 @@ void MmgUtilities::GenerateMeshDataFromModelPart( } } + r_nodes_array.Unique(); + /* Conditions */ counter_to_remesh = block_for_each>( r_conditions_array, @@ -3829,6 +3835,8 @@ void MmgUtilities::GenerateMeshDataFromModelPart( } } + r_conditions_array.Unique(); + /* Elements */ counter_to_remesh = block_for_each>( r_elements_array, @@ -3857,6 +3865,8 @@ void MmgUtilities::GenerateMeshDataFromModelPart( } } + r_elements_array.Unique(); + // Now we compute the colors rColors.clear(); ColorsMapType nodes_colors, cond_colors, elem_colors; diff --git a/kratos/containers/key_generator.h b/kratos/containers/key_generator.h new file mode 100644 index 000000000000..2297d2792680 --- /dev/null +++ b/kratos/containers/key_generator.h @@ -0,0 +1,115 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +#pragma once + +// System includes +#include +#include +#include + +// External includes + +// Project includes + +namespace Kratos +{ +///@name Kratos Classes +///@{ + +/** + * @class TestOperators + * @brief Operator class to test whether operators "<" and "==" is defined for given TDataType. + */ +struct TestOperators +{ + template + static auto TestEqual(TDataType*) -> decltype(std::declval() == std::declval()); + template + static auto TestEqual(...) -> std::false_type; + + template + static auto TestLess(TDataType*) -> decltype(std::declval() < std::declval()); + template + static auto TestLess(...) -> std::false_type; +}; + +/** + * @class KeyGenerator + * @brief A functor that serves as the identity function if "<" and "==" operators are defined, otherwise, returns memory location. + * @details This class provides two overloaded operator() functions, one for non-const objects + * and another for const objects. The operator() returns the input objects memory location as it is, + * effectively acting as an identity function for address if the operators "<" and "==" is not defined. Otherwise, + * this returns the exact input object. + * + * The purpose of this functor is to allow objects' memory locations or exact object to be used as keys in sets or other + * containers that require comparison. By using this functor, you can avoid defining + * custom comparison functions or operators when the object itself can be considered + * for comparison. + * @tparam TDataType The data type of the object that the functor operates on. + * @author Suneth Warnakulasuriya + */ +template +class KeyGenerator +{ +private: + ///@name Private static variables + ///@{ + + static constexpr bool HasOperatorEqual = std::is_same_v(0))>; + + static constexpr bool HasOperatorLess = std::is_same_v(0))>; + + static constexpr bool HasOperatorsDefined = HasOperatorEqual && HasOperatorLess; + + ///@} + +public: + ///@name Public operators + ///@{ + + /** + * @brief Operator that returns a non-const reference to the input object if "<" and "==" operators are defined. + * Otherwise this returns a pointer to the input object. + * @param data The input object of type TDataType. + * @return A non-const reference or pointer to the same object as provided in the parameter. + */ + std::conditional_t operator()(TDataType& rData) + { + if constexpr(HasOperatorsDefined) { + return rData; + } else { + return &rData; + } + } + + /** + * @brief Operator that returns a const reference to the input object if "<" and "==" operators are defined. + * Otherwise this returns a pointer to the const input object. + * @param data The input object of type TDataType. + * @return A const reference or pointer to the same object as provided in the parameter. + */ + std::conditional_t operator()(const TDataType& rData) const + { + if constexpr(HasOperatorsDefined) { + return rData; + } else { + return &rData; + } + } + + ///@} +}; + +///@} + +} // namespace Kratos. diff --git a/kratos/containers/pointer_vector_set.h b/kratos/containers/pointer_vector_set.h index eb8ce3b03af4..f64b7068c538 100644 --- a/kratos/containers/pointer_vector_set.h +++ b/kratos/containers/pointer_vector_set.h @@ -27,7 +27,7 @@ // Project includes #include "includes/define.h" #include "includes/serializer.h" -#include "containers/set_identity_function.h" +#include "containers/key_generator.h" namespace Kratos { @@ -63,7 +63,7 @@ namespace Kratos * @author Pooyan Dadvand */ template, + class TGetKeyType = KeyGenerator, class TCompareType = std::less()(std::declval()))>, class TEqualType = std::equal_to()(std::declval()))>, class TPointerType = typename TDataType::Pointer, @@ -126,8 +126,8 @@ class PointerVectorSet final PointerVectorSet(TInputIteratorType First, TInputIteratorType Last, size_type NewMaxBufferSize = 1) : mSortedPartSize(size_type()), mMaxBufferSize(NewMaxBufferSize) { - for (; First != Last; ++First) - insert(begin(), *First); + mData.reserve(std::distance(First, Last)); + insert(First, Last); } /** @@ -136,7 +136,7 @@ class PointerVectorSet final */ PointerVectorSet(const PointerVectorSet& rOther) : mData(rOther.mData), mSortedPartSize(rOther.mSortedPartSize), mMaxBufferSize(rOther.mMaxBufferSize) {} - + /** * @brief Constructs a PointerVectorSet from a container. * @details This constructor initializes a PointerVectorSet with elements from a container. @@ -558,54 +558,118 @@ class PointerVectorSet final mSortedPartSize = mData.size(); } - /** - * @brief Inserts a pointer at the specified position. - * @details This function inserts a given pointer at the specified position in the set. It also maintains - * the sorting order and updates mSortedPartSize if necessary. - * @param Position An iterator pointing to the position where the pointer should be inserted. - * @param pData The pointer to be inserted. + /** + * @brief Inserts a pointer. + * @details This function inserts a given pointer such that the resulting PointerVectorSet + * is kept sorted. If there exists already a pointer with a key same as the key of the value, then + * this will return iterator of that existing pointer (The value will not be inserted.) + * @param value The pointer to be inserted. * @return An iterator pointing to the inserted element. */ - iterator insert(iterator Position, const TPointerType pData) + iterator insert(const TPointerType& value) { - ptr_iterator sorted_part_end; - - key_type key = KeyOf(*pData); - - if (mData.size() - mSortedPartSize >= mMaxBufferSize) { - Sort(); - sorted_part_end = mData.end(); - } else - sorted_part_end = mData.begin() + mSortedPartSize; - - ptr_iterator i(std::lower_bound(mData.begin(), sorted_part_end, key, CompareKey())); - if (i == sorted_part_end) { - mSortedPartSize++; - return mData.insert(sorted_part_end, pData); + auto itr_pos = std::lower_bound(mData.begin(), mData.end(), KeyOf(*value), CompareKey()); + if (itr_pos == mData.end()) { + // the position to insert is at the end. + mData.push_back(value); + mSortedPartSize = mData.size(); + return iterator(mData.end() - 1); + } else if (EqualKeyTo(KeyOf(*value))(*itr_pos)) { + // already found existing element with the same key, hence returning the existing element. + return iterator(itr_pos); + } else { + // insert the new value before the itr_pos. + mSortedPartSize = mData.size() + 1; + return mData.insert(itr_pos, value); } + } - if (!EqualKeyTo(key)(*i)) - if ((i = std::find_if(sorted_part_end, mData.end(), EqualKeyTo(key))) == mData.end()) { - mData.push_back(pData); + /** + * @brief Inserts a pointer at the specified position. + * @details This function inserts a given pointer. If the given position_hint is valid, then + * it uses that to insert the value, otherwise the position_hint is discarded to maintain the dataset + * sorted. If there is an existing element with the same key as in the value, then an iterator for + * the existing element is returned. + * @param position_hint An iterator pointing to the position where the pointer may be inserted. + * @param value The pointer to be inserted. + * @return An iterator pointing to the inserted element. + */ + iterator insert(const_iterator position_hint, const TPointerType& value) + { + if (empty()) { + // the dataset is empty. So use push back. + mData.push_back(value); + mSortedPartSize = mData.size(); + return iterator(mData.end() - 1); + } else if (position_hint == cend()) { + // trying to insert at the end. + if (KeyOf(*(position_hint - 1)) < KeyOf(*value)) { + // key at the position hint is less than the value of key. Hence position hint + // is valid. So using the push back. + mData.push_back(value); + mSortedPartSize = mData.size(); return iterator(mData.end() - 1); + } else { + // given position is invalid. Hence, discarding the hint. + return insert(value); } - - *i = pData; - return i; + } else if (position_hint == cbegin()) { + // trying to insert at the front. + if (KeyOf(*value) < KeyOf(*position_hint)) { + // key at the position hint is greater than the value of key. Hence position hint + // is valid. So using insertion at the beginning. + mSortedPartSize = mData.size() + 1; + return mData.insert(mData.begin(), value); + } else { + // given position is invalid. Hence, discarding the hint. + return insert(value); + } + } else { + // trying to insert at an arbitrary position. + if (KeyOf(*value) < KeyOf(*position_hint) && (KeyOf(*(position_hint - 1)) < KeyOf(*value))) { + mSortedPartSize = mData.size() + 1; + return mData.insert(mData.begin() + (position_hint - cbegin()), value); + } else { + // given position is invalid. Hence, discarding the hint. + return insert(value); + } + } } /** * @brief Insert elements from a range of iterators. - * @details This function inserts elements from a range defined by the iterators `First` and `Last` - * into the set. It uses the `insert` function to insert each element. - * @param First An input iterator pointing to the beginning of the range to insert. - * @param Last An input iterator pointing to the end of the range to insert. + * @details This function inserts element pointers from a range defined by the iterators `first` and `last` + * into the set. This will not insert any elements in the range, if there exists an element with a key + * which is equal to an element's key in the input range. + * @param first An input iterator pointing to the beginning of the range to insert. + * @param last An input iterator pointing to the end of the range to insert. */ template - void insert(InputIterator First, InputIterator Last) + void insert(InputIterator first, InputIterator last) { - for (; First != Last; ++First) - insert(begin(), *First); + // first sorts the input iterators and make the input unique. + std::sort(first, last, CompareKey()); + auto new_last = std::unique(first, last, EqualKeyTo()); + SortedInsert(first, new_last); + } + + /** + * @brief Insert elements from another PointerVectorSet range. + * @details This function inserts element pointers from another PointerVectorSet range specified by first and last into the current set. + * Since, PointerVectorSet is assumed to be sorted and unique, the incoming PointerVectorSet is not + * sorted and made unique again. This will not insert any elements in the incoming set, if there exists an element with a key + * which is equal to an element's key in the input range. + * @param first Other PointerVectorSet starting iterator + * @param last Other PointerVectorSet ending iterator + */ + void insert(PointerVectorSet::const_iterator first, PointerVectorSet::const_iterator last) + { + SortedInsert(first, last); + } + + void insert(const PointerVectorSet& rOther) + { + insert(rOther.begin(), rOther.end()); } /** @@ -789,15 +853,15 @@ class PointerVectorSet final /** * @brief Get the maximum size of buffer used in the container */ - size_type GetMaxBufferSize() const + size_type GetMaxBufferSize() const { return mMaxBufferSize; } - /** + /** * @brief Set the maximum size of buffer used in the container. * @details This container uses a buffer which keep data unsorted. After buffer size arrived to the MaxBufferSize it will sort all container and empties buffer. - * @param NewSize Is the new buffer maximum size. + * @param NewSize Is the new buffer maximum size. */ void SetMaxBufferSize(const size_type NewSize) { @@ -805,16 +869,16 @@ class PointerVectorSet final } /** - * @brief Get the sorted part size of buffer used in the container. + * @brief Get the sorted part size of buffer used in the container. */ - size_type GetSortedPartSize() const + size_type GetSortedPartSize() const { return mSortedPartSize; } - /** + /** * @brief Set the sorted part size of buffer used in the container. - * @param NewSize Is the new buffer maximum size. + * @param NewSize Is the new buffer maximum size. */ void SetSortedPartSize(const size_type NewSize) { @@ -980,10 +1044,10 @@ class PointerVectorSet final /// The data container holding the elements. TContainerType mData; - + /// The size of the sorted portion of the data. size_type mSortedPartSize; - + /// The maximum buffer size for data storage. size_type mMaxBufferSize; @@ -995,6 +1059,66 @@ class PointerVectorSet final ///@name Private Operations ///@{ + template + void SortedInsert(TIteratorType first, TIteratorType last) + { + if (std::distance(first, last) == 0) { + return; + } + + if (empty()) { + mData.reserve(std::distance(first, last)); + for (auto it = first; it != last; ++it) { + mData.push_back(TPointerType(&GetReference(it))); + } + } else { + // first find the largest range + const auto lower_bound_first = std::lower_bound(mData.begin(), mData.end(), KeyOf(GetReference(first)), CompareKey()); + const auto upper_bound_last = std::upper_bound(lower_bound_first, mData.end(), KeyOf(GetReference(last-1)), CompareKey()); + + // then find the compact sub range + const auto upper_bound_first = std::upper_bound(lower_bound_first, upper_bound_last, KeyOf(GetReference(first)), CompareKey()); + const auto lower_bound_last = std::lower_bound(lower_bound_first, upper_bound_last, KeyOf(GetReference(last-1)), CompareKey()); + + if (lower_bound_first == lower_bound_last && + lower_bound_first == upper_bound_first && + lower_bound_first == upper_bound_last) + { + // all 4 bounds are equal, hence this can be inserted without checking further + mData.reserve(mData.size() + std::distance(first, last)); + if (lower_bound_first == mData.end()) { + for (auto it = first; it != last; ++it) { + mData.push_back(TPointerType(&GetReference(it))); + } + } else { + // now if the capacity of the new mData is larger than the existing + // capacity, then the current lower_bound_first is invalidated. + // hence needs to find it again. + const auto new_lower_bound = std::lower_bound(mData.begin(), mData.end(), KeyOf(GetReference(first)), CompareKey()); + auto current_pos = new_lower_bound - 1; + for (auto it = first; it != last; ++it) { + current_pos = mData.insert(current_pos + 1, TPointerType(&GetReference(it))); + } + } + } else { + auto p_current_itr = mData.begin(); + // now add the new elements + for (auto it = first; it != last; ++it) { + // find the lower bound element. + p_current_itr = std::lower_bound(p_current_itr, mData.end(), KeyOf(GetReference(it)), CompareKey()); + if (p_current_itr == mData.end() || !EqualKeyTo(KeyOf(GetReference(it)))(*p_current_itr)) { + p_current_itr = mData.insert(p_current_itr, TPointerType(&GetReference(it))); + } + } + } + } + + // TODO: To be removed once push back is removed. + // insert assumes the PointerVectorSet is already sorted, + // hence mSortedPartSize should be mData.size() + mSortedPartSize = mData.size(); + } + /** * @brief Extract the key from an iterator and apply a key extraction function. * @details This function extracts the key from an iterator and applies a key extraction function of type `TGetKeyType` to it. @@ -1028,6 +1152,37 @@ class PointerVectorSet final return TGetKeyType()(i); } + /** + * @brief Get the reference from an iterator. + * + * This method is used to get reference from an iterator. This is required to support + * both PointerVectorSet::iterator and std::vector::iterators because, their + * "*" operators returns different types of objects. + * + */ + template + inline auto& GetReference(TIteratorType Iterator) const + { + // It is difficult to use std::iterator_traits to get the value + // type of the iterator because, boost::indirect has a value type + // which is harder to guess, and cryptic. Hence, using the decltype. + using iterator_value_type = std::decay_t; + + if constexpr(std::is_same_v>) { + // in here, std::remove_cv is only used for the value_type because, + // the PointerVectorSet can be with TDataType which is const, but the passed pointers + // must be always TDataType::Pointer which is defined for non cost TDataType. This is + // a valid use case. Other way is not possible, hence std::remove_cv is not used on + // iterator_value_type. + return *Iterator; + } else if constexpr(std::is_same_v) { + return **Iterator; + } else { + static_assert(!std::is_same_v, "Unsupported iterator type."); + return 0; + } + } + ///@} ///@name Serialization ///@{ diff --git a/kratos/includes/indexed_object.h b/kratos/includes/indexed_object.h index 47ec06857142..2ff6cbf2d9e5 100644 --- a/kratos/includes/indexed_object.h +++ b/kratos/includes/indexed_object.h @@ -260,6 +260,21 @@ inline std::ostream& operator << (std::ostream& rOStream, return rOStream; } + +inline bool operator<( + const IndexedObject& rFirst, + const IndexedObject& rSecond) +{ + return rFirst.Id() < rSecond.Id(); +} + +inline bool operator==( + const IndexedObject& rFirst, + const IndexedObject& rSecond) +{ + return rFirst.Id() == rSecond.Id(); +} + ///@} } // namespace Kratos. diff --git a/kratos/includes/mesh.h b/kratos/includes/mesh.h index 29d0293ae297..3bd7c6fd582f 100644 --- a/kratos/includes/mesh.h +++ b/kratos/includes/mesh.h @@ -265,7 +265,7 @@ class Mesh : public DataValueContainer, public Flags */ void AddNode(typename NodeType::Pointer pNewNode) { - mpNodes->insert(mpNodes->begin(), pNewNode); + mpNodes->insert(mpNodes->end(), pNewNode); } /** Returns the Node::Pointer corresponding to it's identifier */ @@ -487,7 +487,7 @@ class Mesh : public DataValueContainer, public Flags */ void AddElement(typename ElementType::Pointer pNewElement) { - mpElements->insert(mpElements->begin(), pNewElement); + mpElements->insert(mpElements->end(), pNewElement); } /** Returns the Element::Pointer corresponding to it's identifier */ @@ -610,7 +610,7 @@ class Mesh : public DataValueContainer, public Flags */ void AddCondition(typename ConditionType::Pointer pNewCondition) { - mpConditions->insert(mpConditions->begin(), pNewCondition); + mpConditions->insert(mpConditions->end(), pNewCondition); } /** Returns the Condition::Pointer corresponding to it's identifier */ @@ -736,11 +736,7 @@ class Mesh : public DataValueContainer, public Flags { const auto it_existing_constraint = mpMasterSlaveConstraints->find(pNewMasterSlaveConstraint->Id()); if (it_existing_constraint == mpMasterSlaveConstraints->end()) { - // PointerVectorSet::insert takes a position argument to insert the - // item at but ignores it, which makes it completely irrelevant to - // properly compute (an estimate) of the new constraint's position - // in the container => pass begin as position. - const auto it_insert_position = mpMasterSlaveConstraints->begin(); + const auto it_insert_position = mpMasterSlaveConstraints->end(); mpMasterSlaveConstraints->insert(it_insert_position, pNewMasterSlaveConstraint); return true; } diff --git a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp index b8e062f26786..39729ee27777 100644 --- a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp +++ b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp @@ -30,18 +30,394 @@ namespace Testing { KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetCBeginAndCEnd, KratosCoreFastSuite) { - PointerVectorSet test_container; + PointerVectorSet test_container; auto p_element_1 = Kratos::make_intrusive(1); auto p_element_2 = Kratos::make_intrusive(2); auto p_element_3 = Kratos::make_intrusive(3); - test_container.push_back(p_element_1); - test_container.push_back(p_element_2); - test_container.push_back(p_element_3); + test_container.insert(p_element_1); + test_container.insert(p_element_2); + test_container.insert(p_element_3); KRATOS_EXPECT_EQ(test_container.cbegin()->Id(), 1); KRATOS_EXPECT_EQ((test_container.cend()-1)->Id(), 3); } +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert1, KratosCoreFastSuite) +{ + PointerVectorSet test_container; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_3_ptr_copy = Kratos::intrusive_ptr(p_element_3); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_3), &*p_element_3); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_2), &*p_element_2); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_1), &*p_element_1); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_5), &*p_element_5); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_6), &*p_element_6); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_4), &*p_element_4); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_3_ptr_copy), &*p_element_3); + + KRATOS_EXPECT_EQ(test_container.size(), 6); + + auto itr = test_container.begin(); + for (; itr != test_container.end() - 1; ++itr) { + KRATOS_EXPECT_TRUE(&*(itr) - &*(itr + 1) < 0); + } +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert2, KratosCoreFastSuite) +{ + PointerVectorSet test_container; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_3_copy = Kratos::make_intrusive(3); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_3), &*p_element_3); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_2), &*p_element_2); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_1), &*p_element_1); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_5), &*p_element_5); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_6), &*p_element_6); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_4), &*p_element_4); + KRATOS_EXPECT_EQ(&*test_container.insert(p_element_3_copy), &*p_element_3); + + KRATOS_EXPECT_EQ(test_container.size(), 6); + + auto itr = test_container.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_6); +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert3, KratosCoreFastSuite) +{ + PointerVectorSet test_container; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_3_ptr_copy = Kratos::intrusive_ptr(p_element_3); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.end(), p_element_3), &*p_element_3); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.end(), p_element_6), &*p_element_6); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.end(), p_element_2), &*p_element_2); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.begin(), p_element_1), &*p_element_1); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.begin(), p_element_5), &*p_element_5); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.begin() + 3, p_element_4), &*p_element_4); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.begin() + 3, p_element_1), &*p_element_1); + KRATOS_EXPECT_EQ(&*test_container.insert(test_container.begin() + 3, p_element_3_ptr_copy), &*p_element_3); + + KRATOS_EXPECT_EQ(test_container.size(), 6); + + auto itr = test_container.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_6); +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert4, KratosCoreFastSuite) +{ + PointerVectorSet test_container; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_3_copy = Kratos::make_intrusive(3); + + std::vector tmp; + tmp.push_back(p_element_2); + tmp.push_back(p_element_1); + tmp.push_back(p_element_4); + tmp.push_back(p_element_3); + tmp.push_back(p_element_4); + tmp.push_back(p_element_6); + tmp.push_back(p_element_1); + tmp.push_back(p_element_5); + tmp.push_back(p_element_3_copy); + test_container.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container.size(), 6); + + auto itr = test_container.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_6); +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert5, KratosCoreFastSuite) +{ + PointerVectorSet test_container; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_7 = Kratos::make_intrusive(7); + auto p_element_8 = Kratos::make_intrusive(8); + auto p_element_3_ptr_copy = Kratos::intrusive_ptr(p_element_3); + + std::vector tmp; + tmp.push_back(p_element_2); + tmp.push_back(p_element_1); + tmp.push_back(p_element_5); + tmp.push_back(p_element_8); + test_container.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container.size(), 4); + auto itr = test_container.begin(); + for (; itr != test_container.end() - 1; ++itr) { + KRATOS_EXPECT_TRUE(&*(itr) - &*(itr + 1) < 0); + } + + tmp.clear(); + tmp.push_back(p_element_3); + tmp.push_back(p_element_4); + tmp.push_back(p_element_5); + tmp.push_back(p_element_3); + tmp.push_back(p_element_3_ptr_copy); + tmp.push_back(p_element_1); + tmp.push_back(p_element_7); + tmp.push_back(p_element_6); + test_container.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container.size(), 8); + itr = test_container.begin(); + for (; itr != test_container.end() - 1; ++itr) { + KRATOS_EXPECT_TRUE(&*(itr) - &*(itr + 1) < 0); + } +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert6, KratosCoreFastSuite) +{ + PointerVectorSet test_container; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_7 = Kratos::make_intrusive(7); + auto p_element_8 = Kratos::make_intrusive(8); + auto p_element_3_copy = Kratos::make_intrusive(3); + + std::vector tmp; + tmp.push_back(p_element_2); + tmp.push_back(p_element_1); + tmp.push_back(p_element_5); + tmp.push_back(p_element_8); + test_container.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container.size(), 4); + auto itr = test_container.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_8); + + tmp.clear(); + tmp.push_back(p_element_3); + tmp.push_back(p_element_4); + tmp.push_back(p_element_5); + tmp.push_back(p_element_3); + tmp.push_back(p_element_3_copy); + tmp.push_back(p_element_1); + tmp.push_back(p_element_7); + tmp.push_back(p_element_6); + test_container.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container.size(), 8); + itr = test_container.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_6); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_7); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_8); +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert7, KratosCoreFastSuite) +{ + PointerVectorSet test_container_1, test_container_2, test_container_3; + auto p_element_1 = Kratos::make_intrusive(1); + auto p_element_2 = Kratos::make_intrusive(2); + auto p_element_3 = Kratos::make_intrusive(3); + auto p_element_4 = Kratos::make_intrusive(4); + auto p_element_5 = Kratos::make_intrusive(5); + auto p_element_6 = Kratos::make_intrusive(6); + auto p_element_7 = Kratos::make_intrusive(7); + auto p_element_8 = Kratos::make_intrusive(8); + auto p_element_3_copy = Kratos::make_intrusive(3); + + std::vector tmp; + tmp.push_back(p_element_2); + tmp.push_back(p_element_1); + tmp.push_back(p_element_5); + tmp.push_back(p_element_8); + + test_container_1.insert(tmp.begin(), tmp.end()); + KRATOS_EXPECT_EQ(test_container_1.size(), 4); + auto itr = test_container_1.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_8); + + test_container_2.insert(test_container_1); + KRATOS_EXPECT_EQ(test_container_2.size(), 4); + itr = test_container_2.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_8); + + tmp.clear(); + tmp.push_back(p_element_3); + tmp.push_back(p_element_4); + tmp.push_back(p_element_5); + tmp.push_back(p_element_3); + tmp.push_back(p_element_3_copy); + tmp.push_back(p_element_1); + tmp.push_back(p_element_7); + tmp.push_back(p_element_6); + test_container_3.insert(tmp.begin(), tmp.end()); + + test_container_2.insert(test_container_3); + KRATOS_EXPECT_EQ(test_container_2.size(), 8); + itr = test_container_2.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_6); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_7); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_8); +} + +KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert8, KratosCoreFastSuite) +{ + PointerVectorSet test_container_1, test_container_2, test_container_3; + std::vector elements; + for (IndexType i = 0; i < 50; ++i) { + elements.push_back(Kratos::make_intrusive(i + 1)); + } + auto p_element_4_copy = Kratos::make_intrusive(4); + auto p_element_10_copy = Kratos::make_intrusive(10); + + std::vector tmp; + tmp.push_back(elements[2]); + tmp.push_back(elements[1]); + tmp.push_back(elements[25]); + tmp.push_back(elements[28]); + + test_container_1.insert(tmp.begin(), tmp.end()); + KRATOS_EXPECT_EQ(test_container_1.size(), 4); + auto itr = test_container_1.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); + + test_container_2.insert(test_container_1); + KRATOS_EXPECT_EQ(test_container_2.size(), 4); + itr = test_container_2.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); + + tmp.clear(); + tmp.push_back(elements[3]); + tmp.push_back(elements[4]); + tmp.push_back(elements[5]); + tmp.push_back(elements[3]); + tmp.push_back(p_element_4_copy); + tmp.push_back(p_element_10_copy); + tmp.push_back(elements[7]); + tmp.push_back(elements[6]); + test_container_3.insert(tmp.begin(), tmp.end()); + + test_container_2.insert(test_container_3); + KRATOS_EXPECT_EQ(test_container_2.size(), 10); + itr = test_container_2.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[3]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[4]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[5]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[6]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[7]); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_10_copy); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); + + tmp.clear(); + tmp.push_back(elements[39]); + tmp.push_back(elements[29]); + tmp.push_back(elements[48]); + test_container_2.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container_2.size(), 13); + itr = test_container_2.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[3]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[4]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[5]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[6]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[7]); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_10_copy); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[29]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[39]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[48]); + + tmp.clear(); + tmp.push_back(elements[28]); + tmp.push_back(elements[31]); + tmp.push_back(elements[45]); + test_container_2.insert(tmp.begin(), tmp.end()); + + KRATOS_EXPECT_EQ(test_container_2.size(), 15); + itr = test_container_2.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[3]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[4]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[5]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[6]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[7]); + KRATOS_EXPECT_EQ(&*(itr++), &*p_element_10_copy); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[29]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[31]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[39]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[45]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[48]); +} + KRATOS_TEST_CASE_IN_SUITE(TestPointerVectorSet, KratosCoreFastSuite) { // create model and model part