diff --git a/Control/xAODRootAccess/CMakeLists.txt b/Control/xAODRootAccess/CMakeLists.txt index efa20e467e6aacfdf4d72a24294a66998fae8ffc..2c916d4e7a76c1bedd99a525ec5eb3b65718fac3 100644 --- a/Control/xAODRootAccess/CMakeLists.txt +++ b/Control/xAODRootAccess/CMakeLists.txt @@ -1,4 +1,4 @@ -# $Id: CMakeLists.txt 793319 2017-01-21 16:21:46Z ssnyder $ +# $Id: CMakeLists.txt 793778 2017-01-25 04:06:29Z ssnyder $ # # Build configuration for the xAODRootAccess package. # @@ -17,6 +17,7 @@ endif() # The dependencies of the package: atlas_depends_on_subdirs( PUBLIC + Control/CxxUtils Control/AthContainersInterfaces Control/AthContainers Event/xAOD/xAODCore @@ -68,7 +69,7 @@ macro( _add_test name ) atlas_add_test( ${name} SOURCES test/${name}.cxx INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers xAODCore xAODRootAccess + LINK_LIBRARIES ${ROOT_LIBRARIES} CxxUtils AthContainers xAODCore xAODRootAccess PROPERTIES TIMEOUT 600 ) endmacro( _add_test ) @@ -77,7 +78,9 @@ _add_test( ut_xaodrootaccess_metadata_test ) _add_test( ut_xaodrootaccess_remap_test ) _add_test( ut_xaodrootaccess_slimming_test ) _add_test( ut_xaodrootaccess_stats_test ) +_add_test( ut_xaodrootaccess_tauxvector_test ) _add_test( ut_xaodrootaccess_tauxstore_test ) +_add_test( ut_xaodrootaccess_tauxstore_insertmove_test ) _add_test( ut_xaodrootaccess_tchain_test ) _add_test( ut_xaodrootaccess_tevent_test ) _add_test( ut_xaodrootaccess_tfileaccesstracer_test ) diff --git a/Control/xAODRootAccess/Root/TAuxStore.cxx b/Control/xAODRootAccess/Root/TAuxStore.cxx index 1bd6baae11b3042c20b09c39986d6f16baa4a4f3..0e1ca3ad9eabde802e1255e72b8c68f390a4e66c 100644 --- a/Control/xAODRootAccess/Root/TAuxStore.cxx +++ b/Control/xAODRootAccess/Root/TAuxStore.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// $Id: TAuxStore.cxx 793319 2017-01-21 16:21:46Z ssnyder $ +// $Id: TAuxStore.cxx 793778 2017-01-25 04:06:29Z ssnyder $ // System include(s): #include <string.h> @@ -637,6 +637,59 @@ namespace xAOD { return; } + bool TAuxStore::insertMove (size_t pos, + IAuxStore& other, + const SG::auxid_set_t& ignore_in) + { + // Guard against multi-threaded execution: + guard_t guard( m_mutex1 ); + + // A sanity check: + if( m_structMode == kObjectStore ) { + ::Error( "xAOD::TAuxStore::insertMove", + XAOD_MESSAGE( "Should not have been called for single-object " + "store" ) ); + return false; + } + + const SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + bool nomove = true; + size_t other_size = other.size(); + + SG::auxid_set_t ignore = ignore_in; + + for (SG::auxid_t id : m_auxIDs) { + SG::IAuxTypeVector* v_dst = nullptr; + if (id < m_vecs.size()) + v_dst = m_vecs[id]; + if (v_dst) { + ignore.insert (id); + if (other.getData (id)) { + void* src_ptr = other.getData (id, other_size, other_size); + if (src_ptr) { + if (!v_dst->insertMove (pos, src_ptr, + reinterpret_cast<char*>(src_ptr) + other_size*r.getEltSize(id))) + nomove = false; + } + } + else { + const void* orig = v_dst->toPtr(); + v_dst->shift (pos, other_size); + if (orig != v_dst->toPtr()) + nomove = false; + } + } + } + + if( m_transientStore ) { + if (!m_transientStore->insertMove( pos, other, ignore )) + nomove = false; + } + + return nomove; + } + + const void* TAuxStore::getIOData( auxid_t auxid ) const { // Guard against multi-threaded execution: diff --git a/Control/xAODRootAccess/Root/TAuxVector.cxx b/Control/xAODRootAccess/Root/TAuxVector.cxx index 0f1fafff19de9d1552f7fc080315c5640876d350..2d799c6b66a3cb80e41550882f152c172a999cbb 100644 --- a/Control/xAODRootAccess/Root/TAuxVector.cxx +++ b/Control/xAODRootAccess/Root/TAuxVector.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// $Id: TAuxVector.cxx 793319 2017-01-21 16:21:46Z ssnyder $ +// $Id: TAuxVector.cxx 793778 2017-01-25 04:06:29Z ssnyder $ // ROOT include(s): #include <TClass.h> @@ -188,6 +188,27 @@ namespace xAOD { return; } + bool TAuxVector::insertMove (size_t pos, void* beg, void* end) + { + TVirtualCollectionProxy::TPushPop bind (m_proxy, m_vec); + size_t eltsz = m_proxy->GetIncrement(); + const void* orig = this->toPtr(); + + char* begp = reinterpret_cast<char*> (beg); + char* endp = reinterpret_cast<char*> (end); + size_t nelt = (endp-begp) / eltsz; + + shift (pos, nelt); + // FIXME: want move, not copy. + // But i don't seem to be able to call move operations through cling, + // so just use copy for now. + copyRange (beg, + reinterpret_cast<char*>(this->toPtr()) + pos*eltsz, + nelt); + return this->toPtr() == orig; + } + + void TAuxVector::copyRange( const void* src, void* dst, size_t n ) { // Size of an element in the vector: diff --git a/Control/xAODRootAccess/test/ut_xaodrootaccess_tauxstore_insertmove_test.cxx b/Control/xAODRootAccess/test/ut_xaodrootaccess_tauxstore_insertmove_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4f2f2683acb41f25a84c8bdd78a5d8e114e20004 --- /dev/null +++ b/Control/xAODRootAccess/test/ut_xaodrootaccess_tauxstore_insertmove_test.cxx @@ -0,0 +1,168 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file xAODRootAccess/test/ut_xaodrootaccess_tauxstore_insertmove_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2017 + * @brief Unit tests TAuxStore::insertMove. + */ + + +#undef NDEBUG +#include "xAODRootAccess/TAuxStore.h" +#include "xAODRootAccess/tools/ReturnCheck.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/AuxStoreInternal.h" +#include "TTree.h" +#include <iostream> +#include <sstream> +#include <cassert> + + +const char* APP_NAME = "ut_xaodrootaccess_tauxstore_insertmove_test"; + + +struct MoveTest +{ + MoveTest(int x=0) : m_v(x) {} + MoveTest(const MoveTest& other): m_v (other.m_v) {} + MoveTest(MoveTest&& other): m_v (std::move(other.m_v)) {} + MoveTest& operator= (const MoveTest& other) { + if (this != &other) m_v = other.m_v; + return *this; + } + MoveTest& operator= (MoveTest&& other) { + if (this != &other) m_v = std::move(other.m_v); + return *this; + } + std::vector<int> m_v; + bool operator== (const MoveTest& other) const { return m_v.size() == other.m_v.size(); } +}; + + +bool wasMoved (const MoveTest& x) { return x.m_v.empty(); } + + +int test1() +{ + std::cout << "test1\n"; + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anotherInt"); + SG::auxid_t ityp3 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt3"); + SG::auxid_t ityp4 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt4"); + SG::auxid_t mtyp1 = SG::AuxTypeRegistry::instance().getAuxID<MoveTest> ("moveTest"); + + TTree tree ("t", "t"); + xAOD::TAuxStore s1( "fooAux." ); + RETURN_CHECK( APP_NAME, s1.readFrom (&tree) ); + s1.resize(5); + + int* i1 = reinterpret_cast<int*> (s1.getData(ityp1, 5, 20)); + int* i2 = reinterpret_cast<int*> (s1.getData(ityp2, 5, 20)); + MoveTest* m1 = reinterpret_cast<MoveTest*> (s1.getData(mtyp1, 5, 20)); + + for (int i=0; i<5; i++) { + i1[i] = i; + i2[i] = i+100; + m1[i] = MoveTest(i); + } + + SG::AuxStoreInternal s2; + s2.resize(5); + + int* i1_2 = reinterpret_cast<int*> (s2.getData(ityp1, 5, 5)); + int* i3_2 = reinterpret_cast<int*> (s2.getData(ityp3, 5, 5)); + int* i4_2 = reinterpret_cast<int*> (s2.getData(ityp4, 5, 5)); + MoveTest* m1_2 = reinterpret_cast<MoveTest*> (s2.getData(mtyp1, 5, 5)); + for (int i=0; i<5; i++) { + i1_2[i] = i+10; + i3_2[i] = i+110; + i4_2[i] = i+210; + m1_2[i] = MoveTest(i+10); + } + + SG::auxid_set_t ignore { ityp4 }; + + s1.insertMove (3, s2, ignore); + assert (s1.size() == 10); + s1.reserve(20); + assert (s1.getData(ityp4) == nullptr); + const int* i3 = reinterpret_cast<const int*> (s1.getData(ityp3)); + assert (i3 != 0); + i1 = reinterpret_cast<int*> (s1.getData(ityp1, 5, 20)); + i2 = reinterpret_cast<int*> (s1.getData(ityp2, 5, 20)); + m1 = reinterpret_cast<MoveTest*> (s1.getData(mtyp1, 5, 20)); + for (int i=0; i<3; i++) { + assert (i1[i] == i); + assert (i2[i] == i+100); + assert (i3[i] == 0); + assert (m1[i] == MoveTest(i)); + } + for (int i=0; i<5; i++) { + assert (i1[3+i] == i+10); + assert (i2[3+i] == 0); + assert (i3[3+i] == i+110); + assert (m1[3+i] == MoveTest(i+10)); + } + for (int i=3; i<5; i++) { + assert (i1[5+i] == i); + assert (i2[5+i] == i+100); + assert (i3[5+i] == 0); + assert (m1[5+i] == MoveTest(i)); + } + for (int i=0; i<5; i++) { + assert (wasMoved (m1_2[i])); + } + + for (int i=0; i<5; i++) { + i1_2[i] = i+20; + i3_2[i] = i+120; + m1_2[i] = MoveTest(i+20); + } + s1.insertMove (10, s2, ignore); + assert (s1.size() == 15); + i1 = reinterpret_cast<int*> (s1.getData(ityp1, 5, 20)); + i2 = reinterpret_cast<int*> (s1.getData(ityp2, 5, 20)); + i3 = reinterpret_cast<int*> (s1.getData(ityp3, 5, 20)); + m1 = reinterpret_cast<MoveTest*> (s1.getData(mtyp1, 5, 20)); + for (int i=0; i<3; i++) { + assert (i1[i] == i); + assert (i2[i] == i+100); + assert (i3[i] == 0); + assert (m1[i] == MoveTest(i)); + } + for (int i=0; i<5; i++) { + assert (i1[3+i] == i+10); + assert (i2[3+i] == 0); + assert (i3[3+i] == i+110); + assert (m1[3+i] == MoveTest(i+10)); + } + for (int i=3; i<5; i++) { + assert (i1[5+i] == i); + assert (i2[5+i] == i+100); + assert (i3[5+i] == 0); + assert (m1[5+i] == MoveTest(i)); + } + for (int i=0; i<5; i++) { + assert (i1[10+i] == i+20); + assert (i2[10+i] == 0); + assert (i3[10+i] == i+120); + assert (m1[10+i] == MoveTest(i+20)); + } + for (int i=0; i<5; i++) { + assert (wasMoved (m1_2[i])); + } + + return 0; +} + + +int main() +{ + test1(); + return 0; +} diff --git a/Control/xAODRootAccess/test/ut_xaodrootaccess_tauxvector_test.cxx b/Control/xAODRootAccess/test/ut_xaodrootaccess_tauxvector_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..18bccccce7808b18307b34ca144b7dd628ad702e --- /dev/null +++ b/Control/xAODRootAccess/test/ut_xaodrootaccess_tauxvector_test.cxx @@ -0,0 +1,107 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file xAODRootAccess/test/ut_xaodrootaccess_tauxvector_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2017 + * @brief Unit tests for TAuxVector. (sadly incomplete) + */ + + +#undef NDEBUG +#include "xAODRootAccess/tools/TAuxVector.h" +#include "xAODRootAccess/tools/TAuxVectorFactory.h" +#include "CxxUtils/StrFormat.h" +#include "TClass.h" +#include <iostream> +#include <sstream> +#include <cassert> + + +std::string str (int x) +{ + return CxxUtils::strformat ("%d", x); +} + + +// Test insertMove. +void test1() +{ + std::cout << "test1\n"; + + TClass* cl_int = TClass::GetClass ("vector<int>"); + xAOD::TAuxVectorFactory fac_int (cl_int); + xAOD::TAuxVector vec_int = xAOD::TAuxVector (&fac_int, cl_int, 5, 5); + int* ptr_int = reinterpret_cast<int*> (vec_int.toPtr()); + + for (int i=0; i < 5; i++) + ptr_int[i] = i; + + std::vector<int> v2_int { 10, 11, 12, 13, 14 }; + vec_int.insertMove (3, v2_int.data(), v2_int.data() + 5); + assert (vec_int.size() == 10); + ptr_int = reinterpret_cast<int*> (vec_int.toPtr()); + for (int i=0; i < 3; i++) + assert (ptr_int[i] == i); + for (int i=0; i < 5; i++) + assert (ptr_int[3+i] == 10+i); + for (int i=3; i < 5; i++) + assert (ptr_int[5+i] == i); + + std::vector<int> v3_int { 20, 21, 22, 23, 24 }; + vec_int.insertMove (10, v3_int.data(), v3_int.data() + 5); + assert (vec_int.size() == 15); + ptr_int = reinterpret_cast<int*> (vec_int.toPtr()); + for (int i=0; i < 3; i++) + assert (ptr_int[i] == i); + for (int i=0; i < 5; i++) + assert (ptr_int[3+i] == 10+i); + for (int i=3; i < 5; i++) + assert (ptr_int[5+i] == i); + for (int i=0; i < 5; i++) + assert (ptr_int[10+i] == 20+i); + + //********************************* + + TClass* cl_str = TClass::GetClass ("vector<std::string>"); + xAOD::TAuxVectorFactory fac_str (cl_str); + xAOD::TAuxVector vec_str = xAOD::TAuxVector (&fac_str, cl_str, 5, 5); + std::string* ptr_str = reinterpret_cast<std::string*> (vec_str.toPtr()); + + for (int i=0; i < 5; i++) + ptr_str[i] = str(i); + + std::vector<std::string> v2_str { str(10), str(11), str(12), str(13), str(14) }; + vec_str.insertMove (3, v2_str.data(), v2_str.data() + 5); + assert (vec_str.size() == 10); + ptr_str = reinterpret_cast<std::string*> (vec_str.toPtr()); + for (int i=0; i < 3; i++) + assert (ptr_str[i] == str(i)); + for (int i=0; i < 5; i++) + assert (ptr_str[3+i] == str(10+i)); + for (int i=3; i < 5; i++) + assert (ptr_str[5+i] == str(i)); + + std::vector<std::string> v3_str { str(20), str(21), str(22), str(23), str(24) }; + vec_str.insertMove (10, v3_str.data(), v3_str.data() + 5); + assert (vec_str.size() == 15); + ptr_str = reinterpret_cast<std::string*> (vec_str.toPtr()); + for (int i=0; i < 3; i++) + assert (ptr_str[i] == str(i)); + for (int i=0; i < 5; i++) + assert (ptr_str[3+i] == str(10+i)); + for (int i=3; i < 5; i++) + assert (ptr_str[5+i] == str(i)); + for (int i=0; i < 5; i++) + assert (ptr_str[10+i] == str(20+i)); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/Control/xAODRootAccess/xAODRootAccess/TAuxStore.h b/Control/xAODRootAccess/xAODRootAccess/TAuxStore.h index 9bb13e7751ee939f032ac6f81da9d6895475ac6a..f520c01d5819ed5586b0c9ba7fa624e8f8a57161 100644 --- a/Control/xAODRootAccess/xAODRootAccess/TAuxStore.h +++ b/Control/xAODRootAccess/xAODRootAccess/TAuxStore.h @@ -4,7 +4,7 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// $Id: TAuxStore.h 793319 2017-01-21 16:21:46Z ssnyder $ +// $Id: TAuxStore.h 793778 2017-01-25 04:06:29Z ssnyder $ #ifndef XAODROOTACCESS_TAUXSTORE_H #define XAODROOTACCESS_TAUXSTORE_H @@ -21,6 +21,8 @@ // Local include(s): #include "xAODRootAccess/tools/TReturnCode.h" +#include "Rtypes.h" + // Forward declaration(s): class TTree; class TBranch; @@ -43,8 +45,8 @@ namespace xAOD { /// /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> /// - /// $Revision: 793319 $ - /// $Date: 2017-01-21 17:21:46 +0100 (Sat, 21 Jan 2017) $ + /// $Revision: 793778 $ + /// $Date: 2017-01-25 05:06:29 +0100 (Wed, 25 Jan 2017) $ /// class TAuxStore : public SG::IAuxStore, public SG::IAuxStoreIO { @@ -147,6 +149,10 @@ namespace xAOD { virtual void reserve( size_t size ); /// Shift the contents of the stored arrays virtual void shift( size_t pos, ptrdiff_t offs ); + /// Insert contents of another store via move. + virtual bool insertMove (size_t pos, + IAuxStore& other, + const SG::auxid_set_t& ignore); /// @} diff --git a/Control/xAODRootAccess/xAODRootAccess/tools/TAuxVector.h b/Control/xAODRootAccess/xAODRootAccess/tools/TAuxVector.h index e16b6c8cc289e97a172714513ef8eaae5a8c0873..432829ff11705f36606846cfa567a0f2073e136c 100644 --- a/Control/xAODRootAccess/xAODRootAccess/tools/TAuxVector.h +++ b/Control/xAODRootAccess/xAODRootAccess/tools/TAuxVector.h @@ -4,12 +4,13 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// $Id: TAuxVector.h 793319 2017-01-21 16:21:46Z ssnyder $ +// $Id: TAuxVector.h 793778 2017-01-25 04:06:29Z ssnyder $ #ifndef XAODROOTACCESS_TOOLS_TAUXVECTOR_H #define XAODROOTACCESS_TOOLS_TAUXVECTOR_H // EDM include(s): #include "AthContainersInterfaces/IAuxTypeVector.h" +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" // Forward declaration(s): class TClass; @@ -31,8 +32,8 @@ namespace xAOD { /// @author Scott Snyder <Scott.Snyder@cern.ch> /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> /// - /// $Revision: 793319 $ - /// $Date: 2017-01-21 17:21:46 +0100 (Sat, 21 Jan 2017) $ + /// $Revision: 793778 $ + /// $Date: 2017-01-25 05:06:29 +0100 (Wed, 25 Jan 2017) $ /// class TAuxVector : public SG::IAuxTypeVector { @@ -68,6 +69,8 @@ namespace xAOD { virtual void reserve( size_t sz ); /// Shift the elements of the vector virtual void shift( size_t pos, ptrdiff_t offs ); + /// Insert a range of elements via move. + virtual bool insertMove (size_t pos, void* beg, void* end) override; /// @}