diff --git a/GeoModelCore/GeoModelKernel/CMakeLists.txt b/GeoModelCore/GeoModelKernel/CMakeLists.txt index d49c84e643efde52771c3de5715696e88fbb311c..cd075745137fa0cddbd5193efd4ab401d86ae7a8 100644 --- a/GeoModelCore/GeoModelKernel/CMakeLists.txt +++ b/GeoModelCore/GeoModelKernel/CMakeLists.txt @@ -45,3 +45,10 @@ install(TARGETS GeoModelKernel install( FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/GeoModelKernel COMPONENT Development ) + + + +add_executable(testGeoIntrusivePtr tests/testGeoIntrusivePtr.cxx) +target_link_libraries( testGeoIntrusivePtr GeoModelKernel) +add_test(NAME testGeoIntrusivePtr + COMMAND testGeoIntrusivePtr) \ No newline at end of file diff --git a/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoIntrusivePtr.h b/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoIntrusivePtr.h index 461aacfcc337467548c46857ce8737a693209e30..cef5d0577f9de8ef952cc8453c2b854665646646 100644 --- a/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoIntrusivePtr.h +++ b/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoIntrusivePtr.h @@ -59,12 +59,22 @@ class GeoIntrusivePtr{ if (m_ptr && m_ptr == other.get()) { m_ptr->unref(); } else { - reset(other.get()); + m_ptr = other.get(); + } + other.m_ptr = nullptr; + return *this; + } + template <typename GeoTypeGrp, + typename = typename std::enable_if<!std::is_same<GeoType,GeoTypeGrp>::value, bool>> + GeoIntrusivePtr& operator=(GeoIntrusivePtr<GeoTypeGrp>&& other) { + if (m_ptr && m_ptr == other.get()) { + m_ptr->unref(); + } else { + m_ptr = other.get(); } other.m_ptr = nullptr; return *this; } - /// Reset the pointer void reset(GeoType* ptr = nullptr) { if (m_ptr == ptr) return; diff --git a/GeoModelCore/GeoModelKernel/tests/testGeoIntrusivePtr.cxx b/GeoModelCore/GeoModelKernel/tests/testGeoIntrusivePtr.cxx new file mode 100644 index 0000000000000000000000000000000000000000..afc5e9586b791ddb224923eab5e28de32e3b8046 --- /dev/null +++ b/GeoModelCore/GeoModelKernel/tests/testGeoIntrusivePtr.cxx @@ -0,0 +1,67 @@ +// Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + + +#include <GeoModelKernel/GeoFullPhysVol.h> +#include <GeoModelKernel/GeoPhysVol.h> +#include <GeoModelKernel/GeoBox.h> +#include <iostream> + + + +#define PRINT(OBJ) \ + std::cout<<__FILE__<<":"<<__LINE__<<" Print reference count of "<<(RCBase*)OBJ; \ + if (OBJ) std::cout<<" "<<typeid(*OBJ).name()<<" "<<OBJ->refCount(); \ + std::cout<<std::endl; \ + + +#define CHECKCOUNT(OBJ, EXPECT) \ + if (OBJ->refCount() != EXPECT) { \ + PRINT(OBJ); \ + std::cerr<<__FILE__<<":"<<__LINE__<<" Expect a reference count of "<<EXPECT<<std::endl; \ + return EXIT_FAILURE; \ + } \ + PRINT(OBJ); \ + std::cout<<__FILE__<<":"<<__LINE__<<" Pass ref counter check of "<<EXPECT<<std::endl; \ + +int main(int argc, char *argv[]){ + GeoMaterial* material = new GeoMaterial("Snow", 1.45); + GeoBox* uniCave = new GeoBox(100., 100., 100.); + /// Create the logical volume forklift which should increase the counters by one unit + GeoLogVol* logVol = new GeoLogVol("Forklift", uniCave, material); + + CHECKCOUNT(material, 1); + CHECKCOUNT(uniCave, 1); + + /// The logical volume should be also incremented by one unit then + GeoIntrusivePtr<GeoFullPhysVol> myPhysVol{new GeoFullPhysVol(logVol)}; + CHECKCOUNT(myPhysVol, 1); + CHECKCOUNT(logVol, 1); + /// Temporarilly create a new logical volume pointer + { + GeoIntrusivePtr<GeoLogVol> logInt{logVol}; + CHECKCOUNT(logInt, 2); + } + /// Another check that the logical volume is back to 1 + CHECKCOUNT(logVol, 1); + { + /// Derived constructor from the mother + GeoIntrusivePtr<GeoVFullPhysVol> physVol2{myPhysVol}; + CHECKCOUNT(physVol2, 2); + + /// Test move constructor + GeoIntrusivePtr<GeoVPhysVol> physVol3{std::move(physVol2)}; + CHECKCOUNT(physVol3, 2); + /// Test the copy assignment + GeoIntrusivePtr<GeoVPhysVol> physVol4{}; + physVol4 = physVol3; + CHECKCOUNT(physVol4, 3); + /// Reset + physVol4.reset(); + // We should be back to 2 + CHECKCOUNT(physVol3, 2); + /// Move assignment + physVol4 = std::move(physVol3); + CHECKCOUNT(physVol4, 2); + } + return EXIT_SUCCESS; +}