From 71e8ed81abb5196f99da9dcdcdab0d4fcb33d6b5 Mon Sep 17 00:00:00 2001 From: root <root@firestarter2.cern.ch> Date: Mon, 25 Mar 2019 14:43:15 +0100 Subject: [PATCH] first commit of calypso --- EDM/Identifier.h | 34 - EDM/README.md | 32 + EDM/StripCluster.h | 52 - EDM/athena/AtlasTest/TestTools/CMakeLists.txt | 34 + .../TestTools/TestTools/FLOATassert.h | 43 + .../AtlasTest/TestTools/TestTools/SGassert.h | 30 + .../TestTools/TestTools/expect_exception.h | 45 + .../AtlasTest/TestTools/TestTools/initGaudi.h | 34 + .../AtlasTest/TestTools/TestTools/random.h | 89 + .../AtlasTest/TestTools/cmt/Makefile.RootCore | 24 + .../AtlasTest/TestTools/cmt/requirements | 45 + EDM/athena/AtlasTest/TestTools/doc/MainPage.h | 89 + .../AtlasTest/TestTools/python/__init__.py | 3 + .../AtlasTest/TestTools/python/iobench.py | 477 ++ .../nightlies/CppUnitSGServiceTestExample.sh | 19 + .../scripts/nightlies/CppUnitTestExample.sh | 19 + .../scripts/nightlies/TestHelloWorld.sh | 19 + .../scripts/nightlies/TestHelloWorld_XML.xml | 14 + .../nightlies/TestHelloWorld_script.xml | 14 + .../TestTools/share/IoAuditor_fragment.py | 19 + EDM/athena/AtlasTest/TestTools/share/post.sh | 225 + .../AtlasTest/TestTools/share/runUnitTests.sh | 27 + .../AtlasTest/TestTools/src/initGaudi.cxx | 77 + .../AtlasTest/TestTools/test/test_iobench.py | 62 + .../AtlasBuildScripts/LCG_RELEASE_BASE.sh | 24 + EDM/athena/Build/AtlasBuildScripts/README.md | 5 + .../AtlasBuildScripts/TDAQ_RELEASE_BASE.sh | 25 + .../Build/AtlasBuildScripts/build_Gaudi.sh | 142 + .../AtlasBuildScripts/build_atlasexternals.sh | 144 + .../Build/AtlasBuildScripts/checkout_Gaudi.sh | 129 + .../checkout_atlasexternals.sh | 129 + .../Build/AtlasBuildScripts/copy_rpm_eos.sh | 114 + .../Build/AtlasBuildScripts/tag_build.sh | 68 + .../AthAllocators/AthAllocators/Arena.h | 344 + .../AthAllocators/ArenaAllocatorBase.h | 415 ++ .../AthAllocators/ArenaAllocatorBase.icc | 174 + .../AthAllocators/ArenaAllocatorCreator.h | 52 + .../AthAllocators/ArenaAllocatorRegistry.h | 101 + .../AthAllocators/AthAllocators/ArenaBase.h | 59 + .../AthAllocators/AthAllocators/ArenaBlock.h | 207 + .../AthAllocators/ArenaBlock.icc | 86 + .../AthAllocators/ArenaBlockAllocatorBase.h | 121 + .../AthAllocators/ArenaCachingHandle.h | 173 + .../AthAllocators/ArenaCachingHandle.icc | 105 + .../AthAllocators/AthAllocators/ArenaHandle.h | 166 + .../AthAllocators/ArenaHandle.icc | 126 + .../AthAllocators/ArenaHandleBase.h | 138 + .../AthAllocators/ArenaHandleBase.icc | 33 + .../AthAllocators/ArenaHandleBaseAllocT.h | 167 + .../AthAllocators/ArenaHandleBaseAllocT.icc | 128 + .../AthAllocators/ArenaHandleBaseT.h | 244 + .../AthAllocators/ArenaHandleBaseT.icc | 212 + .../AthAllocators/AthAllocators/ArenaHeader.h | 175 + .../AthAllocators/ArenaHeader.icc | 38 + .../AthAllocators/ArenaHeapAllocator.h | 200 + .../AthAllocators/ArenaHeapAllocator.icc | 107 + .../AthAllocators/ArenaHeapSTLAllocator.h | 388 ++ .../AthAllocators/ArenaHeapSTLAllocator.icc | 432 ++ .../AthAllocators/ArenaPoolAllocator.h | 256 + .../AthAllocators/ArenaPoolAllocator.icc | 102 + .../AthAllocators/ArenaPoolSTLAllocator.h | 532 ++ .../AthAllocators/ArenaPoolSTLAllocator.icc | 571 ++ .../AthAllocators/ArenaSTLAllocator.h | 89 + .../AthAllocators/ArenaSTLAllocator.icc | 40 + .../ArenaSharedHeapSTLAllocator.h | 410 ++ .../ArenaSharedHeapSTLAllocator.icc | 407 ++ .../AthAllocators/AthAllocatorsDict.h | 5 + .../AthAllocators/AthAllocators/DataPool.h | 160 + .../AthAllocators/AthAllocators/DataPool.icc | 130 + .../AthAllocators/AthAllocators/selection.xml | 3 + .../Control/AthAllocators/CMakeLists.txt | 61 + .../Control/AthAllocators/cmt/requirements | 49 + EDM/athena/Control/AthAllocators/ispellwords | 732 ++ .../share/ArenaAllocatorBase_test.ref | 0 .../share/ArenaAllocatorCreator_test.ref | 0 .../share/ArenaAllocatorRegistry_test.ref | 0 .../AthAllocators/share/ArenaBase_test.ref | 0 .../share/ArenaBlockAllocatorBase_test.ref | 0 .../AthAllocators/share/ArenaBlock_test.ref | 0 .../share/ArenaCachingHandle_test.ref | 0 .../share/ArenaHandleBaseAllocT_test.ref | 0 .../share/ArenaHandleBaseT_test.ref | 0 .../share/ArenaHandleBase_test.ref | 0 .../AthAllocators/share/ArenaHandle_test.ref | 0 .../AthAllocators/share/ArenaHeader_test.ref | 0 .../share/ArenaHeapAllocator_test.ref | 0 .../share/ArenaHeapSTLAllocator_test.ref | 3 + .../share/ArenaPoolAllocator_test.ref | 0 .../share/ArenaPoolSTLAllocator_test.ref | 4 + .../ArenaSharedHeapSTLAllocator_test.ref | 3 + .../AthAllocators/share/Arena_test.ref | 0 .../AthAllocators/share/DataPool_test.ref | 42 + .../AthAllocators/share/DataPool_test.txt | 11 + .../Control/AthAllocators/src/Arena.cxx | 155 + .../AthAllocators/src/ArenaAllocatorBase.cxx | 136 + .../src/ArenaAllocatorRegistry.cxx | 203 + .../Control/AthAllocators/src/ArenaBlock.cxx | 147 + .../src/ArenaBlockAllocatorBase.cxx | 185 + .../AthAllocators/src/ArenaHandleBase.cxx | 104 + .../Control/AthAllocators/src/ArenaHeader.cxx | 218 + .../AthAllocators/src/ArenaHeapAllocator.cxx | 162 + .../AthAllocators/src/ArenaPoolAllocator.cxx | 292 + .../src/ArenaSharedHeapSTLAllocator.cxx | 66 + .../test/ArenaAllocatorBase_test.cxx | 155 + .../test/ArenaAllocatorCreator_test.cxx | 30 + .../test/ArenaAllocatorRegistry_test.cxx | 62 + .../AthAllocators/test/ArenaBase_test.cxx | 46 + .../test/ArenaBlockAllocatorBase_test.cxx | 111 + .../AthAllocators/test/ArenaBlock_test.cxx | 144 + .../test/ArenaCachingHandle_test.cxx | 240 + .../test/ArenaHandleBaseAllocT_test.cxx | 70 + .../test/ArenaHandleBaseT_test.cxx | 184 + .../test/ArenaHandleBase_test.cxx | 72 + .../AthAllocators/test/ArenaHandle_test.cxx | 236 + .../AthAllocators/test/ArenaHeader_test.cxx | 122 + .../test/ArenaHeapAllocator_test.cxx | 218 + .../test/ArenaHeapSTLAllocator_test.cxx | 265 + .../test/ArenaPoolAllocator_test.cxx | 262 + .../test/ArenaPoolSTLAllocator_test.cxx | 318 + .../test/ArenaSharedHeapSTLAllocator_test.cxx | 283 + .../Control/AthAllocators/test/Arena_test.cxx | 100 + .../AthAllocators/test/AthAllocators.xml | 16 + .../AthAllocators/test/DataPool_test.cxx | 147 + .../AthContainers/AthContainersDict.h | 151 + .../AthContainers/AthContainers/AuxElement.h | 1179 ++++ .../AthContainers/AuxElement.icc | 973 +++ .../AthContainers/AuxElementComplete.h | 86 + .../AthContainers/AuxElementComplete.icc | 61 + .../AthContainers/AuxStoreInternal.h | 429 ++ .../AthContainers/AuxStoreStandalone.h | 53 + .../AthContainers/AuxTypeRegistry.h | 711 ++ .../AthContainers/AuxTypeRegistry.icc | 118 + .../AthContainers/AuxVectorBase.h | 726 ++ .../AthContainers/AuxVectorBase.icc | 658 ++ .../AthContainers/AuxVectorData.h | 909 +++ .../AthContainers/AuxVectorData.icc | 587 ++ .../AthContainers/AthContainers/ClassName.h | 49 + .../AthContainers/AthContainers/ClassName.icc | 25 + .../AthContainers/ConstDataList.h | 736 ++ .../AthContainers/ConstDataList.icc | 781 +++ .../AthContainers/ConstDataVector.h | 1001 +++ .../AthContainers/ConstDataVector.icc | 1134 +++ .../AthContainers/AthContainers/DataList.h | 2305 ++++++ .../AthContainers/AthContainers/DataList.icc | 2549 +++++++ .../AthContainers/AthContainers/DataVector.h | 3402 +++++++++ .../AthContainers/DataVector.icc | 3946 +++++++++++ .../AthContainers/IndexTrackingPolicy.h | 53 + .../AthContainers/OwnershipPolicy.h | 22 + .../AthContainers/PackedContainer.h | 139 + .../AthContainers/PackedContainer.icc | 139 + .../AthContainers/PackedConverter.h | 191 + .../AthContainers/PackedConverter.icc | 278 + .../AthContainers/PackedParameters.h | 297 + .../AthContainers/PackedParameters.icc | 131 + .../AthContainers/UserDataStore.h | 213 + .../AthContainers/AthContainers/ViewVector.h | 367 + .../AthContainers/ViewVector.icc | 268 + .../AthContainers/ViewVectorBase.h | 186 + .../AthContainers/ViewVectorBase.icc | 197 + .../AthContainers/dataVectorAsELV.h | 113 + .../AthContainers/AthContainers/debug.h | 186 + .../AthContainers/AthContainers/exceptions.h | 371 + .../AthContainers/normalizedTypeinfoName.h | 53 + .../AthContainers/AthContainers/selection.xml | 191 + .../tools/ATHCONTAINERS_ASSERT.h | 35 + .../AthContainers/tools/AuxDataTraits.h | 113 + .../AthContainers/tools/AuxTypeVector.h | 388 ++ .../AthContainers/tools/AuxTypeVector.icc | 598 ++ .../tools/AuxTypeVectorFactory.h | 138 + .../tools/AuxTypeVectorFactory.icc | 187 + .../AthContainers/tools/ClassID.h | 35 + .../AthContainers/tools/CompareAndPrint.h | 65 + .../AthContainers/tools/CurrentEventStore.h | 42 + .../AthContainers/tools/DVLCast.h | 159 + .../AthContainers/tools/DVLDataBucket.h | 169 + .../AthContainers/tools/DVLDataBucket.icc | 274 + .../AthContainers/tools/DVLEltBaseInfo.icc | 135 + .../AthContainers/tools/DVLInfo.h | 405 ++ .../AthContainers/tools/DVLInfo.icc | 500 ++ .../AthContainers/tools/DVLIterator.h | 393 ++ .../AthContainers/tools/DVLNoBase.h | 39 + .../AthContainers/tools/DVL_algorithms.h | 974 +++ .../AthContainers/tools/DVL_algorithms.icc | 322 + .../AthContainers/tools/DVL_iter_swap.h | 110 + .../AthContainers/tools/ElementProxy.h | 191 + .../AthContainers/tools/ElementProxy.icc | 145 + .../AthContainers/tools/IsMostDerivedFlag.h | 54 + .../AthContainers/tools/UDSLabelHashTable.h | 63 + .../AthContainers/tools/assume.h | 33 + .../AthContainers/tools/copyAuxStoreThinned.h | 48 + .../AthContainers/tools/copyThinned.h | 118 + .../AthContainers/tools/copyThinned.icc | 127 + .../AthContainers/AthContainers/tools/error.h | 61 + .../AthContainers/tools/foreach.h | 31 + .../AthContainers/tools/getThinnedFlags.h | 77 + .../AthContainers/tools/getThinnedFlags.icc | 45 + .../AthContainers/tools/likely.h | 31 + .../AthContainers/tools/threading.h | 266 + .../AthContainers/tools/threading.icc | 123 + .../Control/AthContainers/CMakeLists.txt | 104 + .../Control/AthContainers/Root/AuxElement.cxx | 497 ++ .../AthContainers/Root/AuxStoreInternal.cxx | 677 ++ .../AthContainers/Root/AuxStoreStandalone.cxx | 32 + .../AthContainers/Root/AuxTypeRegistry.cxx | 823 +++ .../AthContainers/Root/AuxVectorBase.cxx | 402 ++ .../AthContainers/Root/AuxVectorData.cxx | 598 ++ .../AthContainers/Root/CompareAndPrint.cxx | 34 + .../Control/AthContainers/Root/DVLInfo.cxx | 125 + .../AthContainers/Root/PackedConverter.cxx | 35 + .../AthContainers/Root/PackedParameters.cxx | 246 + .../AthContainers/Root/UDSLabelHashTable.cxx | 72 + .../AthContainers/Root/UserDataStore.cxx | 118 + .../Control/AthContainers/Root/debug.cxx | 350 + .../Root/dict/PackedContainerStreamer.cxx | 200 + .../Root/dict/ViewVectorBaseStreamer.cxx | 55 + .../Control/AthContainers/Root/error.cxx | 61 + .../Control/AthContainers/Root/exceptions.cxx | 453 ++ .../Root/normalizedTypeinfoName.cxx | 165 + .../AthContainers/cmt/Makefile.RootCore | 24 + .../Control/AthContainers/cmt/requirements | 77 + EDM/athena/Control/AthContainers/ispellwords | 1140 +++ .../share/AuxElementComplete_test.ref | 1 + .../AthContainers/share/AuxElement_test.ref | 7 + .../share/AuxStoreInternal_test.ref | 6 + .../share/AuxStoreStandalone_test.ref | 3 + .../share/AuxTypeRegistry_test.ref | 5 + .../share/AuxTypeVectorFactory_test.ref | 1 + .../share/AuxTypeVector_test.ref | 3 + .../share/AuxVectorBase_test.ref | 12 + .../share/AuxVectorData_test.ref | 8 + .../AthContainers/share/DVLCast_test.ref | 0 .../share/DVLDataBucket_test.ref | 0 .../AthContainers/share/DVLInfo_test.ref | 0 .../AthContainers/share/DVLIterator_test.ref | 0 .../share/DVL_iter_swap_test.ref | 0 .../AthContainers/share/DataList_test.ref | 98 + .../AthContainers/share/DataVector_a_test.ref | 1 + .../AthContainers/share/DataVector_b_test.ref | 1 + .../AthContainers/share/DataVector_c_test.ref | 1 + .../AthContainers/share/DataVector_d_test.ref | 1 + .../AthContainers/share/DataVector_e_test.ref | 1 + .../AthContainers/share/DataVector_f_test.ref | 1 + .../AthContainers/share/DataVector_test.ref | 55 + .../AthContainers/share/ElementProxy_test.ref | 0 .../share/IsMostDerivedFlag_test.ref | 1 + .../share/PackedContainer_test.ref | 1 + .../share/PackedConverter_test.ref | 4 + .../share/PackedParameters_test.ref | 3 + .../share/ViewVectorBase_test.ref | 1 + .../AthContainers/share/ViewVector_test.ref | 4 + .../share/copyAuxStoreThinned_test.ref | 1 + .../AthContainers/share/copyThinned_test.ref | 1 + .../share/dataVectorAsELV_test.ref | 1 + .../AthContainers/share/debug_test.ref | 128 + .../AthContainers/share/error_test.ref | 4 + .../AthContainers/share/exceptions_test.ref | 23 + .../AthContainers/share/foreach_test.ref | 2 + .../share/getThinnedFlags_test.ref | 1 + .../share/normalizedTypeinfoName_test.ref | 1 + .../share/removeDuplicates_test.ref | 8 + .../share/threading_nothreads_test.ref | 17 + .../AthContainers/share/threading_test.ref | 17 + .../AthContainers/src/copyAuxStoreThinned.cxx | 113 + .../AthContainers/src/getThinnedFlags.cxx | 53 + .../AthContainers/test/AthContainers.xml | 16 + .../test/AuxElementComplete_test.cxx | 126 + .../AthContainers/test/AuxElement_test.cxx | 671 ++ .../test/AuxStoreInternal_test.cxx | 541 ++ .../test/AuxStoreStandalone_test.cxx | 44 + .../test/AuxTypeRegistry_test.cxx | 415 ++ .../test/AuxTypeVectorFactory_test.cxx | 112 + .../AthContainers/test/AuxTypeVector_test.cxx | 378 + .../AthContainers/test/AuxVectorBase_test.cxx | 1008 +++ .../AthContainers/test/AuxVectorData_test.cxx | 502 ++ .../AthContainers/test/DVLCast_test.cxx | 105 + .../AthContainers/test/DVLDataBucket_test.cxx | 279 + .../AthContainers/test/DVLInfo_test.cxx | 359 + .../AthContainers/test/DVLIterator_test.cxx | 313 + .../AthContainers/test/DVL_iter_swap_test.cxx | 234 + .../AthContainers/test/DataList_test.cxx | 3484 ++++++++++ .../AthContainers/test/DataVector_a_test.cxx | 44 + .../AthContainers/test/DataVector_b_test.cxx | 44 + .../AthContainers/test/DataVector_c_test.cxx | 44 + .../AthContainers/test/DataVector_d_test.cxx | 44 + .../AthContainers/test/DataVector_e_test.cxx | 44 + .../AthContainers/test/DataVector_f_test.cxx | 44 + .../AthContainers/test/DataVector_test.cxx | 894 +++ .../AthContainers/test/DataVector_test.icc | 6162 +++++++++++++++++ .../AthContainers/test/ElementProxy_test.cxx | 308 + .../test/IsMostDerivedFlag_test.cxx | 44 + .../test/PackedContainer_test.cxx | 95 + .../test/PackedConverter_test.cxx | 329 + .../test/PackedParameters_test.cxx | 203 + .../AthContainers/test/TestThinningSvc.icc | 145 + .../test/ViewVectorBase_test.cxx | 139 + .../AthContainers/test/ViewVector_test.cxx | 227 + .../AthContainers/test/auxid_set_equal.icc | 17 + .../test/copyAuxStoreThinned_test.cxx | 191 + .../AthContainers/test/copyThinned_test.cxx | 173 + .../test/dataVectorAsELV_test.cxx | 93 + .../Control/AthContainers/test/debug_test.cxx | 189 + .../Control/AthContainers/test/error_test.cxx | 30 + .../AthContainers/test/exceptions_test.cxx | 64 + .../AthContainers/test/foreach_test.cxx | 36 + .../test/getThinnedFlags_test.cxx | 85 + .../test/normalizedTypeinfoName_test.cxx | 45 + .../test/removeDuplicates_test.cxx | 52 + .../test/threading_nothreads_test.cxx | 15 + .../AthContainers/test/threading_test.cxx | 124 + .../test/ut_ConstDataVector_basic_test.cxx | 43 + .../AthContainersInterfaces/AuxDataOption.h | 102 + .../AthContainersInterfaces/AuxDataOption.icc | 94 + .../AthContainersInterfaces/AuxStore_traits.h | 181 + .../AthContainersInterfaces/AuxTypes.h | 58 + .../AthContainersInterfaces/CLASS_AUXSTORE.h | 59 + .../AthContainersInterfaces/IAuxElement.h | 47 + .../AthContainersInterfaces/IAuxSetOption.h | 57 + .../AthContainersInterfaces/IAuxStore.h | 193 + .../AthContainersInterfaces/IAuxStoreHolder.h | 80 + .../AthContainersInterfaces/IAuxStoreIO.h | 116 + .../AthContainersInterfaces/IAuxTypeVector.h | 180 + .../IAuxTypeVectorFactory.h | 147 + .../AthContainersInterfaces/IConstAuxStore.h | 155 + .../AthContainersInterfaces/CMakeLists.txt | 33 + .../cmt/Makefile.RootCore | 24 + .../AthContainersInterfaces/cmt/requirements | 20 + .../AthContainersInterfaces/ispellwords | 809 +++ .../share/AuxDataOption_test.ref | 1 + .../share/AuxStore_traits_test.ref | 9 + .../test/AuxDataOption_test.cxx | 46 + .../test/AuxStore_traits_test.cxx | 74 + .../AthLinks/AthLinks/AssociationMap.h | 244 + .../AthLinks/AthLinks/AssociationMap.icc | 285 + .../Control/AthLinks/AthLinks/AthLinksDict.h | 8 + .../Control/AthLinks/AthLinks/DataLink.h | 324 + .../Control/AthLinks/AthLinks/DataLink.icc | 319 + .../Control/AthLinks/AthLinks/DataLinkBase.h | 306 + .../AthLinks/AthLinks/DataLinkBase.icc | 347 + .../Control/AthLinks/AthLinks/DataPtr.h | 174 + .../AthLinks/AthLinks/DeclareIndexingPolicy.h | 60 + .../Control/AthLinks/AthLinks/ElementLink.h | 704 ++ .../Control/AthLinks/AthLinks/ElementLink.icc | 657 ++ .../AthLinks/AthLinks/ElementLinkBase.h | 460 ++ .../AthLinks/AthLinks/ElementLinkBase.icc | 556 ++ .../AthLinks/AthLinks/ElementLinkVector.h | 513 ++ .../AthLinks/AthLinks/ElementLinkVector.icc | 326 + .../AthLinks/AthLinks/ElementLinkVectorBase.h | 70 + .../AthLinks/GenericElementLinkBase.h | 473 ++ .../AthLinks/GenericElementLinkBase.icc | 567 ++ .../Control/AthLinks/AthLinks/exceptions.h | 243 + .../Control/AthLinks/AthLinks/selection.xml | 49 + .../tools/AssociationObjectIterator.h | 311 + .../tools/AssociationVectorIterator.h | 201 + .../AthLinks/AthLinks/tools/DataProxyHolder.h | 422 ++ .../AthLinks/tools/DataProxyHolder.icc | 162 + .../AthLinks/tools/DefaultIndexingPolicy.h | 27 + .../AthLinks/tools/ElementLinkTraits.h | 238 + .../AthLinks/tools/ForwardIndexingPolicy.h | 116 + .../AthLinks/tools/ForwardIndexingPolicy.icc | 105 + .../AthLinks/tools/GenerateIndexingPolicy.h | 42 + .../AthLinks/AthLinks/tools/IdentContIndex.h | 138 + .../AthLinks/tools/IdentContIndexingPolicy.h | 118 + .../tools/IdentContIndexingPolicy.icc | 157 + .../AthLinks/AthLinks/tools/IndexHolder.h | 66 + .../AthLinks/AthLinks/tools/IsSTLSequence.h | 71 + .../AthLinks/tools/MapIndexingPolicy.h | 132 + .../AthLinks/tools/MapIndexingPolicy.icc | 112 + .../AthLinks/AthLinks/tools/RemoveDataPtr.h | 30 + .../AthLinks/AthLinks/tools/SGELVRef.h | 95 + .../AthLinks/AthLinks/tools/SGELVRef.icc | 207 + .../AthLinks/tools/SetIndexingPolicy.h | 130 + .../AthLinks/tools/SetIndexingPolicy.icc | 105 + .../AthLinks/AthLinks/tools/findInContainer.h | 55 + .../AthLinks/AthLinks/tools/selection_ns.h | 66 + EDM/athena/Control/AthLinks/CMakeLists.txt | 138 + EDM/athena/Control/AthLinks/cmt/requirements | 48 + EDM/athena/Control/AthLinks/ispellwords | 875 +++ .../AthLinks/share/AssociationMap_test.ref | 34 + .../AthLinks/share/DataLinkBase_test.ref | 5 + .../Control/AthLinks/share/DataLink_test.ref | 9 + .../AthLinks/share/DataProxyHolder_test.ref | 8 + .../share/DataProxyStorageData_test.ref | 0 .../AthLinks/share/DataProxyStorage_test.ref | 13 + .../Control/AthLinks/share/DataPtr_test.ref | 5 + .../AthLinks/share/ElementHolder_test.ref | 0 .../AthLinks/share/ElementLinkBase_test.ref | 5 + .../AthLinks/share/ElementLinkFwd_test.ref | 1 + .../AthLinks/share/ElementLink_test.ref | 13 + .../share/ForwardIndexingPolicy_test.ref | 1 + .../share/GenericElementLinkBase_test.ref | 4 + .../AthLinks/share/IdentContIndex_test.ref | 1 + .../share/IdentContIndexingPolicy_test.ref | 1 + .../AthLinks/share/IndexHolder_test.ref | 1 + .../AthLinks/share/IsSTLSequence_test.ref | 1 + .../AthLinks/share/MapIndexingPolicy_test.ref | 1 + .../AthLinks/share/SetIndexingPolicy_test.ref | 1 + .../AthLinks/share/exceptions_test.ref | 9 + .../Control/AthLinks/src/DataProxyHolder.cxx | 542 ++ .../AthLinks/src/ElementLinkVectorBase.cxx | 40 + .../Control/AthLinks/src/exceptions.cxx | 256 + .../AthLinks/test/AssociationMap_test.cxx | 281 + EDM/athena/Control/AthLinks/test/AthLinks.xml | 16 + .../AthLinks/test/DataLinkBase_test.cxx | 310 + .../Control/AthLinks/test/DataLink_test.cxx | 382 + .../AthLinks/test/DataProxyHolder_test.cxx | 355 + .../Control/AthLinks/test/DataPtr_test.cxx | 108 + EDM/athena/Control/AthLinks/test/ELFCont.h | 34 + EDM/athena/Control/AthLinks/test/ELFElt.h | 45 + .../AthLinks/test/ElementLinkBase_test.cxx | 547 ++ .../AthLinks/test/ElementLinkFwd_test.cxx | 55 + .../AthLinks/test/ElementLink_test.cxx | 1189 ++++ .../test/ForwardIndexingPolicy_test.cxx | 72 + .../test/GenericElementLinkBase_test.cxx | 504 ++ .../AthLinks/test/IdentContIndex_test.cxx | 79 + .../test/IdentContIndexingPolicy_test.cxx | 129 + .../AthLinks/test/IndexHolder_test.cxx | 39 + .../AthLinks/test/IsSTLSequence_test.cxx | 82 + .../AthLinks/test/MapIndexingPolicy_test.cxx | 69 + .../AthLinks/test/SetIndexingPolicy_test.cxx | 70 + .../Control/AthLinks/test/TestThinningSvc.icc | 93 + .../Control/AthLinks/test/exceptions_test.cxx | 38 + .../AthenaBaseComps/AthAlgTool.h | 257 + .../AthenaBaseComps/AthAlgorithm.h | 302 + .../AthenaBaseComps/AthCheckMacros.h | 59 + .../AthenaBaseComps/AthCnvSvc.h | 329 + .../AthenaBaseComps/AthFilterAlgorithm.h | 135 + .../AthenaBaseComps/AthHistogramAlgorithm.h | 119 + .../AthHistogramFilterAlgorithm.h | 115 + .../AthenaBaseComps/AthHistogramTool.h | 113 + .../AthenaBaseComps/AthHistogramming.h | 349 + .../AthenaBaseComps/AthMemMacros.h | 27 + .../AthenaBaseComps/AthMessaging.h | 127 + .../AthenaBaseComps/AthMsgStreamMacros.h | 42 + .../AthenaBaseComps/AthReentrantAlgorithm.h | 102 + .../AthenaBaseComps/AthService.h | 106 + .../AthenaBaseComps/FilteredAlgorithm.h | 90 + .../Control/AthenaBaseComps/CMakeLists.txt | 40 + .../Control/AthenaBaseComps/cmt/requirements | 33 + .../share/AthReentrantAlgorithm_test.ref | 29 + .../share/propertyHandling_test.ref | 26 + .../share/propertyHandling_test.txt | 16 + .../AthenaBaseComps/src/AthAlgTool.cxx | 107 + .../AthenaBaseComps/src/AthAlgorithm.cxx | 107 + .../Control/AthenaBaseComps/src/AthCnvSvc.cxx | 637 ++ .../src/AthFilterAlgorithm.cxx | 124 + .../src/AthHistogramAlgorithm.cxx | 114 + .../src/AthHistogramFilterAlgorithm.cxx | 114 + .../AthenaBaseComps/src/AthHistogramTool.cxx | 114 + .../AthenaBaseComps/src/AthHistogramming.cxx | 504 ++ .../AthenaBaseComps/src/AthMessaging.cxx | 54 + .../src/AthReentrantAlgorithm.cxx | 26 + .../AthenaBaseComps/src/AthService.cxx | 151 + .../AthenaBaseComps/src/FilteredAlgorithm.cxx | 135 + .../test/AthReentrantAlgorithm_test.cxx | 128 + .../AthenaBaseComps/test/AthenaBaseComps.xml | 16 + .../test/propertyHandling_test.cxx | 248 + .../AthenaKernel/AddressProviderSvc.h | 41 + .../AthenaKernel/AlgorithmTimer.h | 207 + .../AthenaKernel/AthenaKernel/AthDsoUtils.h | 18 + .../AthenaKernel/AthenaKernelDict.h | 37 + .../AthenaKernel/AthenaKernel/Chrono.h | 85 + .../AthenaKernel/AthenaKernel/CloneService.h | 16 + .../AthenaKernel/AthenaKernel/CloneTool.h | 27 + .../AthenaKernel/AthenaKernel/CondCont.h | 339 + .../AthenaKernel/DataObjectSharedPtr.h | 46 + .../AthenaKernel/AthenaKernel/DefaultKey.h | 14 + .../AthenaKernel/AthenaKernel/DirSearchPath.h | 12 + .../Control/AthenaKernel/AthenaKernel/DsoDb.h | 166 + .../AthenaKernel/IAddressProvider.h | 57 + .../AthenaKernel/AthenaKernel/IAtRndmGenSvc.h | 62 + .../AthenaKernel/IAthenaBarCode.h | 101 + .../IAthenaEvtLoopPreSelectTool.h | 40 + .../AthenaKernel/IAthenaIPCTool.h | 31 + .../AthenaKernel/IAthenaOutputStreamTool.h | 128 + .../AthenaKernel/IAthenaOutputTool.h | 45 + .../AthenaKernel/IAthenaSealSvc.h | 55 + .../AthenaKernel/IAthenaSelectorTool.h | 45 + .../AthenaKernel/IAthenaSerializeSvc.h | 28 + .../AthenaKernel/IAthenaSummarySvc.h | 49 + .../AthenaKernel/AthenaKernel/IClassIDSvc.h | 14 + .../AthenaKernel/ICollectionSize.h | 49 + .../AthenaKernel/AthenaKernel/ICoreDumpSvc.h | 53 + .../AthenaKernel/AthenaKernel/ICutFlowSvc.h | 124 + .../AthenaKernel/AthenaKernel/IDataShare.h | 56 + .../AthenaKernel/AthenaKernel/IDecisionSvc.h | 93 + .../AthenaKernel/IDictLoaderSvc.h | 105 + .../AthenaKernel/IEventDumperSvc.h | 41 + .../AthenaKernel/AthenaKernel/IEventSeek.h | 46 + .../AthenaKernel/AthenaKernel/IEventShare.h | 62 + .../AthenaKernel/IEvtIdModifierSvc.h | 116 + .../AthenaKernel/AthenaKernel/IGMASvc.h | 42 + .../AthenaKernel/AthenaKernel/IHiveStore.h | 50 + .../AthenaKernel/AthenaKernel/IHiveStoreMgr.h | 72 + .../AthenaKernel/AthenaKernel/IIOVDbSvc.h | 100 + .../AthenaKernel/AthenaKernel/IIOVSvc.h | 177 + .../AthenaKernel/AthenaKernel/IInputRename.h | 61 + .../AthenaKernel/AthenaKernel/IIoComponent.h | 20 + .../AthenaKernel/IIoComponentMgr.h | 20 + .../AthenaKernel/AthenaKernel/IItemListSvc.h | 79 + .../AthenaKernel/AthenaKernel/IJobIDSvc.h | 49 + .../AthenaKernel/AthenaKernel/ILockable.h | 50 + .../AthenaKernel/ILoggedMessageSvc.h | 49 + .../AthenaKernel/IMemoryMonitorSvc.h | 42 + .../AthenaKernel/INextPassFilter.h | 22 + .../AthenaKernel/AthenaKernel/IOVEntryT.h | 92 + .../AthenaKernel/AthenaKernel/IOVRange.h | 86 + .../AthenaKernel/AthenaKernel/IOVSvcDefs.h | 64 + .../AthenaKernel/AthenaKernel/IOVTime.h | 177 + .../AthenaKernel/IPageAccessControlSvc.h | 62 + .../AthenaKernel/AthenaKernel/IProxyDict.h | 169 + .../AthenaKernel/IProxyProviderSvc.h | 65 + .../AthenaKernel/IProxyRegistry.h | 67 + .../AthenaKernel/AthenaKernel/IRCUSvc.h | 87 + .../AthenaKernel/IRegistrationStreamTool.h | 59 + .../AthenaKernel/AthenaKernel/IResetable.h | 43 + .../AthenaKernel/AthenaKernel/ISlimmingHdlr.h | 60 + .../AthenaKernel/AthenaKernel/IStringPool.h | 90 + .../AthenaKernel/AthenaKernel/ITPCnvBase.h | 92 + .../AthenaKernel/AthenaKernel/ITPCnvSvc.h | 75 + .../AthenaKernel/AthenaKernel/IThinningHdlr.h | 264 + .../AthenaKernel/AthenaKernel/IThinningSvc.h | 437 ++ .../AthenaKernel/AthenaKernel/ITimeKeeper.h | 39 + .../AthenaKernel/AthenaKernel/ITriggerTime.h | 29 + .../AthenaKernel/AthenaKernel/IUserDataSvc.h | 333 + .../AthenaKernel/AthenaKernel/IValgrindSvc.h | 84 + .../AthenaKernel/MsgStreamMember.h | 85 + .../AthenaKernel/POSIXTimeKeeper.h | 49 + .../AthenaKernel/AthenaKernel/RCUObject.h | 484 ++ .../AthenaKernel/AthenaKernel/RCUObject.icc | 365 + .../AthenaKernel/AthenaKernel/StoreID.h | 33 + .../AthenaKernel/AthenaKernel/TPCnvFactory.h | 208 + .../AthenaKernel/AthenaKernel/TimeKeeper.h | 54 + .../AthenaKernel/AthenaKernel/Timeout.h | 83 + .../Control/AthenaKernel/AthenaKernel/Units.h | 126 + .../AthenaKernel/AthenaKernel/errorcheck.h | 492 ++ .../AthenaKernel/AthenaKernel/getMessageSvc.h | 93 + .../AthenaKernel/AthenaKernel/selection.xml | 23 + .../AthenaKernel/AthenaKernel/sgkey_t.h | 36 + .../AthenaKernel/tools/AthenaPackageInfo.h | 66 + .../AthenaKernel/tools/type_tools.h | 96 + .../Control/AthenaKernel/CMakeLists.txt | 92 + .../Control/AthenaKernel/cmt/requirements | 66 + .../Control/AthenaKernel/doc/MainPage.h | 35 + .../share/AthenaPackageInfo_test.ref | 29 + .../AthenaKernel/share/Chrono_test.ref | 1 + .../share/DataObjectSharedPtr_test.ref | 3 + .../AthenaKernel/share/DirSearchPath_test.ref | 2 + .../AthenaKernel/share/IRCUSvc_test.ref | 1 + .../share/MsgStreamMember_test.ref | 30 + .../AthenaKernel/share/RCUObject_test.ref | 3 + .../Control/AthenaKernel/share/Units_test.ref | 2 + .../AthenaKernel/share/errorcheck_test.ref | 37 + .../AthenaKernel/share/getMessageSvc_test.ref | 15 + .../AthenaKernel/share/type_tools_test.ref | 0 .../AthenaKernel/src/AddressProviderSvc.cxx | 9 + .../AthenaKernel/src/AlgorithmTimer.cxx | 289 + .../Control/AthenaKernel/src/AthDsoUtils.cxx | 139 + .../AthenaKernel/src/AthenaPackageInfo.cxx | 41 + .../Control/AthenaKernel/src/CloneService.cxx | 103 + .../Control/AthenaKernel/src/CloneTool.cxx | 83 + EDM/athena/Control/AthenaKernel/src/DsoDb.cxx | 713 ++ .../AthenaKernel/src/IAtRndmGenSvc.cxx | 7 + .../AthenaKernel/src/IAthenaBarCode.cxx | 27 + .../AthenaKernel/src/IAthenaIPCTool.cxx | 13 + .../AthenaKernel/src/IAthenaSerializeSvc.cxx | 13 + .../AthenaKernel/src/IAthenaSummarySvc.cxx | 8 + .../Control/AthenaKernel/src/ICutFlowSvc.cxx | 48 + .../Control/AthenaKernel/src/IDataShare.cxx | 47 + .../Control/AthenaKernel/src/IDecisionSvc.cxx | 48 + .../AthenaKernel/src/IDictLoaderSvc.cxx | 49 + .../Control/AthenaKernel/src/IEventShare.cxx | 47 + .../AthenaKernel/src/IEvtIdModifierSvc.cxx | 49 + .../Control/AthenaKernel/src/IItemListSvc.cxx | 48 + .../Control/AthenaKernel/src/IJobIDSvc.cxx | 8 + .../AthenaKernel/src/ILoggedMessageSvc.cxx | 8 + .../Control/AthenaKernel/src/IOVRange.cxx | 52 + .../Control/AthenaKernel/src/IOVTime.cxx | 210 + .../Control/AthenaKernel/src/IProxyDict.cxx | 52 + .../AthenaKernel/src/ISlimmingHdlr.cxx | 51 + .../Control/AthenaKernel/src/ITPCnvBase.cxx | 43 + .../Control/AthenaKernel/src/ITPCnvSvc.cxx | 51 + .../AthenaKernel/src/IThinningHdlr.cxx | 51 + .../Control/AthenaKernel/src/IThinningSvc.cxx | 143 + .../Control/AthenaKernel/src/ITimeKeeper.cxx | 10 + .../Control/AthenaKernel/src/IValgrindSvc.cxx | 47 + .../AthenaKernel/src/MsgStreamMember.cxx | 38 + .../AthenaKernel/src/POSIXTimeKeeper.cxx | 22 + .../Control/AthenaKernel/src/RCUObject.cxx | 60 + .../Control/AthenaKernel/src/TimeKeeper.cxx | 55 + .../Control/AthenaKernel/src/errorcheck.cxx | 320 + .../AthenaKernel/src/getMessageSvc.cxx | 80 + .../AthenaKernel/src/ubsan_boost_suppress.cxx | 32 + .../AthenaKernel/test/AthenaKernel.xml | 16 + .../test/AthenaPackageInfo_test.cxx | 51 + .../Control/AthenaKernel/test/Chrono_test.cxx | 83 + .../test/DataObjectSharedPtr_test.cxx | 56 + .../AthenaKernel/test/DirSearchPath_test.cxx | 62 + .../AthenaKernel/test/IRCUSvc_test.cxx | 73 + .../test/MsgStreamMember_test.cxx | 111 + .../AthenaKernel/test/RCUObject_test.cxx | 265 + .../Control/AthenaKernel/test/Units_test.cxx | 96 + .../AthenaKernel/test/errorcheck_test.cxx | 219 + .../AthenaKernel/test/getMessageSvc_test.cxx | 66 + .../AthenaKernel/test/type_tools_test.cxx | 21 + EDM/athena/Control/CLIDComps/CMakeLists.txt | 54 + EDM/athena/Control/CLIDComps/cmt/requirements | 28 + .../Control/CLIDComps/python/__init__.py | 6 + .../Control/CLIDComps/python/clidGenerator.py | 167 + .../CLIDComps/share/ClassIDSvc_test.ref | 53 + .../CLIDComps/share/ClassIDSvc_test.txt | 3 + .../Control/CLIDComps/share/Gaudi_clid.db | 24 + .../Control/CLIDComps/share/PYTHONSTARTUP | 8 + EDM/athena/Control/CLIDComps/share/clid | 87 + .../Control/CLIDComps/share/cvs2cliddb.csh | 74 + .../CLIDComps/share/minimalPrintout.opts | 11 + .../Control/CLIDComps/src/ClassIDSvc.cxx | 588 ++ EDM/athena/Control/CLIDComps/src/ClassIDSvc.h | 145 + .../src/components/CLIDComps_entries.cxx | 8 + .../src/components/CLIDComps_load.cxx | 4 + .../Control/CLIDComps/test/CLIDComps.xml | 25 + .../CLIDComps/test/ClassIDSvc_test.cxx | 135 + .../Control/CLIDComps/test/_clid_unittest.py | 45 + .../Control/CLIDComps/util/genCLIDDB.cxx | 148 + EDM/athena/Control/CxxUtils/CMakeLists.txt | 78 + EDM/athena/Control/CxxUtils/CxxUtils/Array.h | 783 +++ .../Control/CxxUtils/CxxUtils/Array.icc | 786 +++ .../Control/CxxUtils/CxxUtils/ArrayScanner.h | 141 + .../CxxUtils/CxxUtils/ArrayScanner.icc | 39 + .../Control/CxxUtils/CxxUtils/Arrayrep.h | 159 + .../Control/CxxUtils/CxxUtils/AthDsoCbk.h | 50 + .../CxxUtils/CxxUtils/AthUnlikelyMacros.h | 20 + .../Control/CxxUtils/CxxUtils/BasicTypes.h | 23 + .../Control/CxxUtils/CxxUtils/BitPacker.h | 200 + .../Control/CxxUtils/CxxUtils/BitPacker.icc | 196 + .../Control/CxxUtils/CxxUtils/BitUnpacker.h | 173 + .../Control/CxxUtils/CxxUtils/BitUnpacker.icc | 170 + .../Control/CxxUtils/CxxUtils/ClassName.h | 478 ++ .../Control/CxxUtils/CxxUtils/FloatPacker.h | 152 + EDM/athena/Control/CxxUtils/CxxUtils/MD5.h | 152 + .../Control/CxxUtils/CxxUtils/PackedArray.h | 311 + .../CxxUtils/CxxUtils/PageAccessControl.h | 116 + .../CxxUtils/CxxUtils/PtrAccessSEGVHandler.h | 54 + .../Control/CxxUtils/CxxUtils/SealCommon.h | 216 + .../Control/CxxUtils/CxxUtils/SealDebug.h | 80 + .../Control/CxxUtils/CxxUtils/SealSharedLib.h | 216 + .../Control/CxxUtils/CxxUtils/SealSignal.h | 319 + .../Control/CxxUtils/CxxUtils/StrFormat.h | 34 + .../Control/CxxUtils/CxxUtils/StringUtils.h | 141 + .../Control/CxxUtils/CxxUtils/algorithms.h | 55 + .../Control/CxxUtils/CxxUtils/bitscan.h | 96 + .../CxxUtils/CxxUtils/cPtrAccessSEGVHandler.h | 30 + EDM/athena/Control/CxxUtils/CxxUtils/clock.h | 29 + .../Control/CxxUtils/CxxUtils/copy_bounded.h | 116 + .../Control/CxxUtils/CxxUtils/enable_if.h | 51 + .../Control/CxxUtils/CxxUtils/excepts.h | 26 + .../Control/CxxUtils/CxxUtils/exctrace.h | 52 + EDM/athena/Control/CxxUtils/CxxUtils/final.h | 39 + .../Control/CxxUtils/CxxUtils/fpcompare.h | 372 + .../Control/CxxUtils/CxxUtils/hashtable.h | 2136 ++++++ .../CxxUtils/CxxUtils/libcalg/arraylist.h | 218 + .../CxxUtils/CxxUtils/libcalg/avl-tree.h | 286 + .../CxxUtils/CxxUtils/libcalg/binary-heap.h | 151 + .../CxxUtils/CxxUtils/libcalg/binomial-heap.h | 151 + .../CxxUtils/CxxUtils/libcalg/bloom-filter.h | 193 + .../CxxUtils/CxxUtils/libcalg/compare-int.h | 69 + .../CxxUtils/libcalg/compare-pointer.h | 67 + .../CxxUtils/libcalg/compare-string.h | 95 + .../CxxUtils/CxxUtils/libcalg/hash-int.h | 49 + .../CxxUtils/CxxUtils/libcalg/hash-pointer.h | 49 + .../CxxUtils/CxxUtils/libcalg/hash-string.h | 58 + .../CxxUtils/CxxUtils/libcalg/hash-table.h | 253 + .../CxxUtils/CxxUtils/libcalg/libcalg.h | 54 + .../Control/CxxUtils/CxxUtils/libcalg/list.h | 312 + .../Control/CxxUtils/CxxUtils/libcalg/queue.h | 164 + .../Control/CxxUtils/CxxUtils/libcalg/set.h | 264 + .../Control/CxxUtils/CxxUtils/libcalg/slist.h | 314 + .../Control/CxxUtils/CxxUtils/libcalg/trie.h | 132 + .../Control/CxxUtils/CxxUtils/make_unique.h | 57 + .../CxxUtils/CxxUtils/no_conversion_warning.h | 19 + .../CxxUtils/CxxUtils/no_sanitize_undefined.h | 32 + .../Control/CxxUtils/CxxUtils/noreturn.h | 53 + EDM/athena/Control/CxxUtils/CxxUtils/ones.h | 39 + .../Control/CxxUtils/CxxUtils/override.h | 39 + .../Control/CxxUtils/CxxUtils/page_access.h | 33 + .../Control/CxxUtils/CxxUtils/pointer_list.h | 341 + .../CxxUtils/CxxUtils/pointer_list.icc | 320 + .../Control/CxxUtils/CxxUtils/prefetch.h | 168 + .../Control/CxxUtils/CxxUtils/procmaps.h | 60 + .../CxxUtils/CxxUtils/read_athena_statm.h | 20 + EDM/athena/Control/CxxUtils/CxxUtils/sincos.h | 108 + .../Control/CxxUtils/CxxUtils/sincosf.h | 23 + .../CxxUtils/CxxUtils/ubsan_suppress.h | 48 + .../Control/CxxUtils/CxxUtils/unordered_map.h | 187 + .../Control/CxxUtils/CxxUtils/unordered_set.h | 182 + EDM/athena/Control/CxxUtils/CxxUtils/unused.h | 36 + EDM/athena/Control/CxxUtils/Root/Array.cxx | 14 + .../Control/CxxUtils/Root/ArrayScanner.cxx | 125 + EDM/athena/Control/CxxUtils/Root/Arrayrep.cxx | 300 + .../Control/CxxUtils/Root/ClassName.cxx | 655 ++ .../Control/CxxUtils/Root/FloatPacker.cxx | 485 ++ EDM/athena/Control/CxxUtils/Root/MD5.cxx | 226 + .../Control/CxxUtils/Root/PackedArray.cxx | 492 ++ .../CxxUtils/Root/PageAccessControl.cxx | 128 + .../CxxUtils/Root/PtrAccessSEGVHandler.cxx | 33 + .../Control/CxxUtils/Root/SealDebug.cxx | 982 +++ .../Control/CxxUtils/Root/SealSharedLib.cxx | 735 ++ .../Control/CxxUtils/Root/SealSignal.cxx | 1624 +++++ .../Control/CxxUtils/Root/StrFormat.cxx | 72 + .../Control/CxxUtils/Root/StringUtils.cxx | 805 +++ .../Control/CxxUtils/Root/StringUtils_aux.h | 229 + .../CxxUtils/Root/cPtrAccessSEGVHandler.cxx | 14 + EDM/athena/Control/CxxUtils/Root/clock.cxx | 34 + EDM/athena/Control/CxxUtils/Root/excepts.cxx | 51 + EDM/athena/Control/CxxUtils/Root/exctrace.cxx | 87 + .../Control/CxxUtils/Root/hashtable.cxx | 67 + .../Control/CxxUtils/Root/page_access.cxx | 25 + .../Control/CxxUtils/Root/pointer_list.cxx | 141 + EDM/athena/Control/CxxUtils/Root/procmaps.cxx | 79 + .../CxxUtils/Root/read_athena_statm.cxx | 45 + EDM/athena/Control/CxxUtils/Root/sincosf.cxx | 22 + .../Control/CxxUtils/Root/ubsan_suppress.cxx | 75 + .../Control/CxxUtils/cmt/Makefile.RootCore | 24 + EDM/athena/Control/CxxUtils/cmt/requirements | 83 + EDM/athena/Control/CxxUtils/ispellwords | 1126 +++ .../CxxUtils/share/ArrayScanner_test.ref | 0 .../Control/CxxUtils/share/Array_test.ref | 0 .../Control/CxxUtils/share/Arrayrep_test.ref | 0 .../CxxUtils/share/BitPackerUnpacker_test.ref | 2 + .../Control/CxxUtils/share/ClassName_test.ref | 5 + .../CxxUtils/share/FloatPacker_test.ref | 0 .../CxxUtils/share/PackedArray_test.ref | 0 .../CxxUtils/share/PageAccessControl_test.ref | 6 + .../CxxUtils/share/SEGVHandler_test.ref | 42 + .../Control/CxxUtils/share/StrFormat_test.ref | 0 .../CxxUtils/share/copy_bounded_test.ref | 1 + .../Control/CxxUtils/share/copyif_test.ref | 0 .../Control/CxxUtils/share/exctrace1_test.ref | 1 + .../Control/CxxUtils/share/exctrace2_test.ref | 7 + .../Control/CxxUtils/share/fpcompare_test.ref | 0 .../Control/CxxUtils/share/hashtable_test.ref | 0 .../CxxUtils/share/make_unique_test.ref | 1 + .../Control/CxxUtils/share/ones_test.ref | 1 + .../CxxUtils/share/pointer_list_test.ref | 0 .../Control/CxxUtils/share/prefetch_test.ref | 88 + .../Control/CxxUtils/share/procmaps_test.ref | 2 + .../CxxUtils/share/read_athena_statm_test.ref | 3 + .../Control/CxxUtils/share/sincos_test.ref | 0 .../CxxUtils/share/stacktrace_test.ref | 5 + .../CxxUtils/share/stringformconvert_test.ref | 7 + .../Control/CxxUtils/share/utf8trim_test.ref | 14 + EDM/athena/Control/CxxUtils/src/AthDsoCbk.c | 348 + .../src/exctrace/exctrace_collector.cxx | 68 + .../Control/CxxUtils/src/libcalg/arraylist.c | 268 + .../Control/CxxUtils/src/libcalg/avl-tree.c | 630 ++ .../CxxUtils/src/libcalg/binary-heap.c | 232 + .../CxxUtils/src/libcalg/binomial-heap.c | 475 ++ .../CxxUtils/src/libcalg/bloom-filter.c | 290 + .../CxxUtils/src/libcalg/compare-int.c | 53 + .../CxxUtils/src/libcalg/compare-pointer.c | 41 + .../CxxUtils/src/libcalg/compare-string.c | 103 + .../Control/CxxUtils/src/libcalg/hash-int.c | 33 + .../CxxUtils/src/libcalg/hash-pointer.c | 29 + .../CxxUtils/src/libcalg/hash-string.c | 61 + .../Control/CxxUtils/src/libcalg/hash-table.c | 498 ++ .../Control/CxxUtils/src/libcalg/list.c | 542 ++ .../Control/CxxUtils/src/libcalg/queue.c | 254 + EDM/athena/Control/CxxUtils/src/libcalg/set.c | 602 ++ .../Control/CxxUtils/src/libcalg/slist.c | 504 ++ .../Control/CxxUtils/src/libcalg/trie.c | 381 + .../CxxUtils/test/ArrayScanner_test.cxx | 70 + .../Control/CxxUtils/test/Array_test.cxx | 232 + .../Control/CxxUtils/test/Arrayrep_test.cxx | 109 + .../CxxUtils/test/BitPackerUnpacker_test.cxx | 195 + .../Control/CxxUtils/test/ClassName_test.cxx | 219 + EDM/athena/Control/CxxUtils/test/CxxUtils.xml | 16 + .../CxxUtils/test/FloatPacker_test.cxx | 312 + .../CxxUtils/test/PackedArray_test.cxx | 209 + .../CxxUtils/test/PageAccessControl_test.cxx | 41 + .../CxxUtils/test/SEGVHandler_test.cxx | 87 + .../Control/CxxUtils/test/StrFormat_test.cxx | 96 + .../Control/CxxUtils/test/bitscan_test.cxx | 59 + .../CxxUtils/test/copy_bounded_test.cxx | 147 + .../Control/CxxUtils/test/copyif_test.cxx | 85 + .../Control/CxxUtils/test/exctrace1_test.cxx | 42 + .../Control/CxxUtils/test/exctrace2_test.cxx | 30 + .../CxxUtils/test/expect_exception.icc | 24 + .../Control/CxxUtils/test/fpcompare_test.cxx | 148 + .../Control/CxxUtils/test/hashtable_test.cxx | 1169 ++++ .../CxxUtils/test/make_unique_test.cxx | 48 + .../Control/CxxUtils/test/ones_test.cxx | 49 + .../CxxUtils/test/pointer_list_test.cxx | 169 + .../Control/CxxUtils/test/prefetch_test.cxx | 113 + .../Control/CxxUtils/test/procmaps_test.cxx | 53 + .../CxxUtils/test/read_athena_statm_test.cxx | 37 + .../Control/CxxUtils/test/sincos_test.cxx | 48 + .../Control/CxxUtils/test/stacktrace_test.cxx | 257 + EDM/athena/Control/DataModel/CMakeLists.txt | 20 + .../Control/DataModel/DataModel/Arena.h | 17 + .../DataModel/DataModel/AssociationMap.h | 12 + .../Control/DataModel/DataModel/ClassName.h | 23 + .../DataModel/DataModel/ConstDataVector.h | 16 + .../Control/DataModel/DataModel/DataLink.h | 26 + .../Control/DataModel/DataModel/DataList.h | 17 + .../Control/DataModel/DataModel/DataPool.h | 17 + .../Control/DataModel/DataModel/DataVector.h | 18 + .../Control/DataModel/DataModel/ElementLink.h | 15 + .../DataModel/DataModel/ElementLinkVector.h | 15 + .../DataModel/DataModel/OwnershipPolicy.h | 10 + .../DataModel/DataModel/UserDataStore.h | 13 + .../DataModel/tools/ArenaPoolSTLAllocator.h | 17 + .../tools/ArenaSharedHeapSTLAllocator.h | 18 + .../DataModel/DataModel/tools/DVLInfo.h | 17 + .../DataModel/tools/IdentContIndex.h | 14 + .../DataModel/DataModel/unordered_map.h | 26 + EDM/athena/Control/DataModel/cmt/requirements | 20 + EDM/athena/Control/DataModel/doc/MainPage.h | 57 + EDM/athena/Control/DataModel/ispellwords | 699 ++ .../Control/DataModelRoot/CMakeLists.txt | 25 + .../DataModelRoot/DataModelRootDict.h | 12 + .../DataModelRoot/DataModelRoot/RootType.h | 269 + .../DataModelRoot/DataModelRoot/selection.xml | 5 + .../Control/DataModelRoot/cmt/requirements | 21 + .../Control/DataModelRoot/src/RootType.cxx | 1002 +++ .../Control/SGMon/SGAudCore/CMakeLists.txt | 17 + .../SGMon/SGAudCore/SGAudCore/ISGAudSvc.h | 63 + .../Control/SGMon/SGAudCore/cmt/requirements | 18 + .../Control/SGMon/SGAudCore/src/ISGAudSvc.cxx | 45 + .../Control/SGMon/SGAudSvc/CMakeLists.txt | 29 + .../SGMon/SGAudSvc/SGAudSvc/SGAudSvc.h | 164 + .../Control/SGMon/SGAudSvc/cmt/requirements | 31 + .../Control/SGMon/SGAudSvc/doc/mainpage.h | 32 + .../Control/SGMon/SGAudSvc/share/SGout2dot.py | 277 + .../SGMon/SGAudSvc/share/checkFileSG.py | 143 + .../Control/SGMon/SGAudSvc/src/SGAudSvc.cxx | 523 ++ .../src/components/SGAudSvc_entries.cxx | 13 + .../SGAudSvc/src/components/SGAudSvc_load.cxx | 3 + EDM/athena/Control/SGTools/CMakeLists.txt | 120 + EDM/athena/Control/SGTools/SGTools/BaseInfo.h | 901 +++ .../Control/SGTools/SGTools/BaseInfo.icc | 675 ++ .../Control/SGTools/SGTools/BuiltinsClids.h | 34 + .../Control/SGTools/SGTools/CLASS_DEF.h | 135 + .../Control/SGTools/SGTools/CLIDRegistry.h | 127 + .../Control/SGTools/SGTools/CallBackID.h | 65 + .../Control/SGTools/SGTools/CallBackID.icc | 56 + .../Control/SGTools/SGTools/ClassID_traits.h | 104 + .../Control/SGTools/SGTools/ClassName.h | 53 + .../Control/SGTools/SGTools/ClassName.icc | 85 + .../SGTools/SGTools/CurrentEventStore.h | 78 + .../SGTools/SGTools/CurrentEventStore.icc | 47 + .../Control/SGTools/SGTools/DataBucket.h | 136 + .../Control/SGTools/SGTools/DataBucket.icc | 256 + .../Control/SGTools/SGTools/DataBucketBase.h | 95 + .../SGTools/SGTools/DataBucketBase.icc | 35 + .../SGTools/SGTools/DataBucketTraitFwd.h | 36 + .../Control/SGTools/SGTools/DataHandleBase.h | 127 + .../Control/SGTools/SGTools/DataProxy.h | 285 + .../Control/SGTools/SGTools/DataProxy.icc | 98 + .../Control/SGTools/SGTools/DataStore.h | 218 + .../SGTools/SGTools/IProxyDictWithPool.h | 29 + .../SGTools/SGTools/IRegisterTransient.h | 47 + .../Control/SGTools/SGTools/IStringPool.h | 23 + EDM/athena/Control/SGTools/SGTools/ProxyMap.h | 31 + .../Control/SGTools/SGTools/SGFolderItem.h | 45 + .../Control/SGTools/SGTools/SGIFolder.h | 55 + .../Control/SGTools/SGTools/SGToolsDict.h | 25 + .../Control/SGTools/SGTools/SGVersionedKey.h | 121 + .../Control/SGTools/SGTools/StlMapClids.h | 39 + .../Control/SGTools/SGTools/StlVectorClids.h | 53 + .../SGTools/SGTools/StorableConversions.h | 267 + .../Control/SGTools/SGTools/StringPool.h | 131 + EDM/athena/Control/SGTools/SGTools/T2pMap.h | 72 + .../Control/SGTools/SGTools/TestStore.h | 139 + .../SGTools/SGTools/TransientAddress.h | 290 + EDM/athena/Control/SGTools/SGTools/crc64.h | 56 + .../Control/SGTools/SGTools/exceptions.h | 97 + .../Control/SGTools/SGTools/hashtable.h | 17 + EDM/athena/Control/SGTools/SGTools/ptrhash.h | 50 + .../Control/SGTools/SGTools/safe_clid.h | 58 + .../Control/SGTools/SGTools/safe_clid.icc | 121 + .../Control/SGTools/SGTools/selection.xml | 12 + .../Control/SGTools/SGTools/unordered_map.h | 15 + EDM/athena/Control/SGTools/cmt/requirements | 46 + EDM/athena/Control/SGTools/doc/MainPage.h | 29 + EDM/athena/Control/SGTools/ispellwords | 620 ++ .../Control/SGTools/share/BaseInfo_test.ref | 2 + .../SGTools/share/CLIDRegistry_test.ref | 2 + .../Control/SGTools/share/ClassName_test.ref | 0 .../SGTools/share/CurrentEventStore_test.ref | 1 + .../Control/SGTools/share/DataBucket_test.ref | 48 + .../Control/SGTools/share/DataProxy_test.ref | 6 + .../Control/SGTools/share/DataStore_test.ref | 15 + .../SGTools/share/SGFolderItem_test.ref | 1 + .../Control/SGTools/share/StringPool_test.ref | 15 + .../SGTools/share/TransientAddress_test.ref | 7 + .../SGTools/share/VersionedKey_test.ref | 3 + .../Control/SGTools/share/crc64_test.ref | 0 .../Control/SGTools/share/exceptions_test.ref | 3 + .../Control/SGTools/share/safe_clid_test.ref | 0 EDM/athena/Control/SGTools/src/BaseInfo.cxx | 702 ++ .../Control/SGTools/src/CLIDRegistry.cxx | 145 + .../Control/SGTools/src/CurrentEventStore.cxx | 35 + .../Control/SGTools/src/DataHandleBase.cxx | 249 + EDM/athena/Control/SGTools/src/DataProxy.cxx | 416 ++ EDM/athena/Control/SGTools/src/DataStore.cxx | 490 ++ .../Control/SGTools/src/SGFolderItem.cxx | 12 + .../Control/SGTools/src/SGToolsClids.cxx | 9 + .../Control/SGTools/src/SGVersionedKey.cxx | 105 + .../SGTools/src/StorableConversions.cxx | 78 + EDM/athena/Control/SGTools/src/StringPool.cxx | 321 + EDM/athena/Control/SGTools/src/T2pMap.cxx | 17 + EDM/athena/Control/SGTools/src/TestStore.cxx | 215 + .../Control/SGTools/src/TransientAddress.cxx | 95 + EDM/athena/Control/SGTools/src/crc64.cxx | 126 + EDM/athena/Control/SGTools/src/exceptions.cxx | 100 + .../Control/SGTools/test/BaseInfo_test.cxx | 354 + .../SGTools/test/CLIDRegistry_test.cxx | 65 + .../Control/SGTools/test/ClassName_test.cxx | 25 + .../SGTools/test/CurrentEventStore_test.cxx | 45 + .../Control/SGTools/test/DataBucket_test.cxx | 433 ++ .../Control/SGTools/test/DataProxy_test.cxx | 275 + .../Control/SGTools/test/DataStore_test.cxx | 537 ++ .../SGTools/test/SGFolderItem_test.cxx | 57 + EDM/athena/Control/SGTools/test/SGTools.xml | 16 + .../Control/SGTools/test/StringPool_test.cxx | 150 + .../SGTools/test/TransientAddress_test.cxx | 181 + .../SGTools/test/VersionedKey_test.cxx | 77 + .../Control/SGTools/test/crc64_test.cxx | 48 + .../Control/SGTools/test/exceptions_test.cxx | 32 + .../Control/SGTools/test/safe_clid_test.cxx | 31 + EDM/athena/Control/StoreGate/AUTHORS | 3 + EDM/athena/Control/StoreGate/CMakeLists.txt | 139 + .../StoreGate/StoreGate/ActiveStoreSvc.h | 176 + .../StoreGate/StoreGate/CondHandleKey.h | 54 + .../StoreGate/StoreGate/CondHandleKey.icc | 86 + .../Control/StoreGate/StoreGate/DataHandle.h | 191 + .../StoreGate/StoreGate/DataHandle.icc | 194 + EDM/athena/Control/StoreGate/StoreGate/RVar.h | 11 + .../Control/StoreGate/StoreGate/RWVar.h | 11 + .../StoreGate/StoreGate/ReadCondHandle.h | 227 + .../StoreGate/StoreGate/ReadCondHandleKey.h | 34 + .../Control/StoreGate/StoreGate/ReadHandle.h | 243 + .../StoreGate/StoreGate/ReadHandle.icc | 268 + .../StoreGate/StoreGate/ReadHandleKey.h | 73 + .../StoreGate/StoreGate/ReadHandleKey.icc | 52 + .../StoreGate/StoreGate/ReadHandleKeyArray.h | 91 + .../StoreGate/StoreGate/SGHiveEventSlot.h | 35 + .../Control/StoreGate/StoreGate/SGIterator.h | 129 + .../StoreGate/StoreGate/SGObjectWithVersion.h | 46 + .../Control/StoreGate/StoreGate/SGWPtr.h | 20 + .../Control/StoreGate/StoreGate/SGtests.h | 61 + .../Control/StoreGate/StoreGate/SegMemSvc.h | 115 + .../Control/StoreGate/StoreGate/SegMemSvc.icc | 61 + .../StoreGate/StoreClearedIncident.h | 52 + .../Control/StoreGate/StoreGate/StoreGate.h | 52 + .../StoreGate/StoreGate/StoreGateSvc.h | 1087 +++ .../StoreGate/StoreGate/StoreGateSvc.icc | 619 ++ .../StoreGate/StoreGate/UpdateHandle.h | 267 + .../StoreGate/StoreGate/UpdateHandle.icc | 306 + .../StoreGate/StoreGate/UpdateHandleKey.h | 73 + .../StoreGate/StoreGate/UpdateHandleKey.icc | 52 + .../StoreGate/StoreGate/VarHandleBase.h | 449 ++ .../StoreGate/StoreGate/VarHandleBase.icc | 48 + .../StoreGate/StoreGate/VarHandleKey.h | 166 + .../StoreGate/StoreGate/VarHandleKeyArray.h | 116 + .../StoreGate/StoreGate/VarHandleKeyArray.icc | 80 + .../StoreGate/VarHandleKeyArrayProperty.h | 104 + .../StoreGate/VarHandleKeyProperty.h | 239 + .../StoreGate/StoreGate/VarHandleProperty.h | 84 + EDM/athena/Control/StoreGate/StoreGate/WVar.h | 11 + .../StoreGate/StoreGate/WriteCondHandle.h | 151 + .../StoreGate/StoreGate/WriteCondHandleKey.h | 33 + .../Control/StoreGate/StoreGate/WriteHandle.h | 383 + .../StoreGate/StoreGate/WriteHandle.icc | 531 ++ .../StoreGate/StoreGate/WriteHandleKey.h | 73 + .../StoreGate/StoreGate/WriteHandleKey.icc | 52 + .../StoreGate/StoreGate/WriteHandleKeyArray.h | 91 + .../StoreGate/constraints/KeyConcept.h | 109 + .../Control/StoreGate/StoreGate/exceptions.h | 269 + .../StoreGate/StoreGate/setupStoreGate.h | 39 + .../StoreGate/StoreGate/tools/SGImplSvc.h | 1215 ++++ .../StoreGate/StoreGate/tools/SGImplSvc.icc | 1276 ++++ .../StoreGate/tools/StorableConversions.h | 20 + .../StoreGate/tools/hash_functions.h | 28 + EDM/athena/Control/StoreGate/cmt/requirements | 72 + EDM/athena/Control/StoreGate/doc/MainPage.h | 57 + .../Control/StoreGate/python/Bindings.py | 23 + .../python/RedirectProxyProviderSvc.py | 13 + .../Control/StoreGate/python/__init__.py | 17 + .../StoreGate/share/ActiveStoreHive_test.ref | 40 + .../StoreGate/share/ActiveStore_test.ref | 32 + .../StoreGate/share/ActiveStore_test.txt | 7 + .../StoreGate/share/DataHandle_test.ref | 18 + .../StoreGate/share/KeyConcept_test.ref | 2 + .../StoreGate/share/ReadHandleKey_test.ref | 16 + .../StoreGate/share/ReadHandle_test.ref | 42 + .../Control/StoreGate/share/SGHive_test.ref | 127 + .../Control/StoreGate/share/SGHive_test.txt | 3 + .../StoreGate/share/SGIterator_test.ref | 24 + .../StoreGate/share/SegMemSvc_test.ref | 13 + .../share/StoreClearedIncident_test.ref | 0 .../share/StoreGateSvcClient_test.txt | 1 + .../StoreGate/share/StoreGate_jobOptions.py | 11 + .../StoreGate/share/StoreGate_jobOptions.txt | 4 + .../StoreGate/share/UpdateHandleKey_test.ref | 17 + .../StoreGate/share/UpdateHandle_test.ref | 49 + .../StoreGate/share/VarHandleBase_test.ref | 61 + .../StoreGate/share/VarHandleBase_test.txt | 2 + .../share/VarHandleKeyProperty_test.ref | 29 + .../share/VarHandleKeyProperty_test.txt | 5 + .../StoreGate/share/VarHandleKey_test.ref | 21 + .../share/VarHandleProperty_test.ref | 22 + .../share/VarHandleProperty_test.txt | 3 + .../StoreGate/share/VarHandles_test.ref | 28 + .../StoreGate/share/WriteHandleKey_test.ref | 17 + .../StoreGate/share/WriteHandle_test.ref | 49 + .../StoreGate/share/exceptions_test.ref | 11 + .../Control/StoreGate/src/ActiveStoreSvc.cxx | 208 + .../Control/StoreGate/src/SGHiveMgrSvc.cxx | 197 + .../Control/StoreGate/src/SGHiveMgrSvc.h | 127 + .../Control/StoreGate/src/SGImplSvc.cxx | 1623 +++++ .../Control/StoreGate/src/SegMemSvc.cxx | 126 + .../StoreGate/src/StoreClearedIncident.cxx | 37 + .../Control/StoreGate/src/StoreGate.cxx | 115 + .../Control/StoreGate/src/StoreGateSvc.cxx | 552 ++ .../Control/StoreGate/src/VarHandleBase.cxx | 831 +++ .../Control/StoreGate/src/VarHandleKey.cxx | 204 + .../src/VarHandleKeyArrayProperty.cxx | 206 + .../StoreGate/src/VarHandleKeyProperty.cxx | 211 + .../src/components/StoreGateSvc_entries.cxx | 16 + .../src/components/StoreGateSvc_load.cxx | 4 + .../Control/StoreGate/src/exceptions.cxx | 340 + .../Control/StoreGate/src/setupStoreGate.cxx | 99 + .../StoreGate/test/ActiveStore_test.cxx | 59 + .../StoreGate/test/DataHandle_test.cxx | 228 + .../StoreGate/test/KeyConcept_test.cxx | 32 + .../StoreGate/test/ReadHandleKey_test.cxx | 69 + .../StoreGate/test/ReadHandle_test.cxx | 264 + .../Control/StoreGate/test/SGHive_test.cxx | 180 + .../StoreGate/test/SGIterator_test.cxx | 142 + EDM/athena/Control/StoreGate/test/SGtests.cxx | 1096 +++ .../Control/StoreGate/test/SegMemSvc_test.cxx | 41 + .../test/StoreClearedIncident_test.cxx | 38 + .../Control/StoreGate/test/StoreGate.xml | 16 + .../StoreGate/test/UpdateHandleKey_test.cxx | 69 + .../StoreGate/test/UpdateHandle_test.cxx | 281 + .../StoreGate/test/VarHandleBase_test.cxx | 555 ++ .../test/VarHandleKeyProperty_test.cxx | 237 + .../StoreGate/test/VarHandleKey_test.cxx | 96 + .../StoreGate/test/VarHandleProperty_test.cxx | 106 + .../StoreGate/test/VarHandles_test.cxx | 316 + .../StoreGate/test/WriteHandleKey_test.cxx | 69 + .../StoreGate/test/WriteHandle_test.cxx | 517 ++ .../StoreGate/test/exceptions_test.cxx | 40 + EDM/athena/Projects/Calypso/CMakeLists.txt | 101 + .../Projects/Calypso/PostConfig.cmake.in | 31 + EDM/athena/Projects/Calypso/README.md | 44 + EDM/athena/Projects/Calypso/build.sh | 133 + EDM/athena/Projects/Calypso/build_env.sh | 105 + .../Projects/Calypso/build_externals.sh | 155 + EDM/athena/Projects/Calypso/externals.txt | 9 + .../Projects/Calypso/externals/Crmc.cmake | 7 + .../Projects/Calypso/externals/EvtGen.cmake | 7 + .../Projects/Calypso/externals/HEPUtils.cmake | 7 + .../Projects/Calypso/externals/Herwig.cmake | 7 + .../Projects/Calypso/externals/Herwig3.cmake | 7 + .../Projects/Calypso/externals/Hydjet.cmake | 7 + .../Projects/Calypso/externals/Lhapdf.cmake | 7 + .../Projects/Calypso/externals/MCUtils.cmake | 7 + .../Calypso/externals/MadGraph5Amc.cmake | 7 + .../Projects/Calypso/externals/Photospp.cmake | 7 + .../Projects/Calypso/externals/Pythia6.cmake | 7 + .../Projects/Calypso/externals/Pythia8.cmake | 7 + .../Projects/Calypso/externals/README.md | 20 + .../Projects/Calypso/externals/Rivet.cmake | 7 + .../Projects/Calypso/externals/Sherpa.cmake | 7 + .../Calypso/externals/Starlight.cmake | 7 + .../Projects/Calypso/externals/Tauolapp.cmake | 7 + .../Projects/Calypso/externals/ThePEG.cmake | 7 + .../Projects/Calypso/externals/YODA.cmake | 7 + .../Projects/Calypso/package_filters.txt | 7 + EDM/athena/Projects/Calypso/version.txt | 1 + EDM/athena/Projects/WorkDir/CMakeLists.txt | 75 + EDM/athena/Projects/WorkDir/README.md | 53 + .../WorkDir/package_filters_example.txt | 19 + EDM/athena/xAOD/xAODCore/CMakeLists.txt | 94 + EDM/athena/xAOD/xAODCore/Root/AddDVProxy.cxx | 34 + .../xAOD/xAODCore/Root/AuxContainerBase.cxx | 668 ++ EDM/athena/xAOD/xAODCore/Root/AuxInfoBase.cxx | 631 ++ .../xAOD/xAODCore/Root/AuxSelection.cxx | 136 + .../xAOD/xAODCore/Root/FloatCompressor.cxx | 68 + EDM/athena/xAOD/xAODCore/Root/IOStats.cxx | 43 + EDM/athena/xAOD/xAODCore/Root/LinkDef.h | 38 + EDM/athena/xAOD/xAODCore/Root/PerfStats.cxx | 334 + .../xAOD/xAODCore/Root/PrintHelpers.cxx | 149 + EDM/athena/xAOD/xAODCore/Root/ReadStats.cxx | 1456 ++++ .../xAOD/xAODCore/Root/SafeDeepCopy.cxx | 81 + .../xAODCore/Root/ShallowAuxContainer.cxx | 509 ++ .../xAOD/xAODCore/Root/ShallowAuxInfo.cxx | 23 + .../xAOD/xAODCore/Root/TDVCollectionProxy.cxx | 582 ++ EDM/athena/xAOD/xAODCore/Root/Utils.cxx | 170 + .../xAOD/xAODCore/cmt/Makefile.RootCore | 24 + EDM/athena/xAOD/xAODCore/cmt/requirements | 52 + .../ut_xaodcore_auxcontainerbase_test.ref | 1 + .../share/ut_xaodcore_auxselection_test.ref | 4 + .../share/ut_xaodcore_class_def_test.ref | 4 + .../ut_xaodcore_clearDecorations_test.ref | 77 + .../ut_xaodcore_floatcompression_test.ref | 12 + .../share/ut_xaodcore_printhelpers_test.ref | 25 + .../share/ut_xaodcore_safedeepcopy_test.ref | 97 + EDM/athena/xAOD/xAODCore/src/README | 3 + .../xAOD/xAODCore/test/inc_AddDVProxy.cxx | 17 + .../xAODCore/test/inc_AuxContainerBase.cxx | 17 + .../xAOD/xAODCore/test/inc_AuxSelection.cxx | 17 + .../xAOD/xAODCore/test/inc_BaseInfo.cxx | 17 + .../xAOD/xAODCore/test/inc_CLASS_DEF.cxx | 17 + .../xAOD/xAODCore/test/inc_ClassID_traits.cxx | 17 + .../xAODCore/test/inc_ShallowAuxContainer.cxx | 17 + .../xAOD/xAODCore/test/inc_ShallowAuxInfo.cxx | 17 + .../xAOD/xAODCore/test/inc_ShallowCopy.cxx | 17 + .../xAODCore/test/inc_tools_AuxPersInfo.cxx | 17 + .../xAODCore/test/inc_tools_AuxPersVector.cxx | 17 + .../xAOD/xAODCore/test/inc_tools_IOStats.cxx | 17 + .../xAODCore/test/inc_tools_PerfStats.cxx | 17 + .../xAODCore/test/inc_tools_PrintHelpers.cxx | 17 + .../xAODCore/test/inc_tools_ReadStats.cxx | 17 + .../xAODCore/test/inc_tools_SafeDeepCopy.cxx | 17 + .../test/inc_tools_TDVCollectionProxy.cxx | 17 + .../xAOD/xAODCore/test/inc_tools_Utils.cxx | 17 + .../xAOD/xAODCore/test/ut_class_def.cxx | 53 + .../ut_xaodcore_auxcontainerbase_test.cxx | 193 + .../test/ut_xaodcore_auxselection_test.cxx | 139 + .../ut_xaodcore_clearDecorations_test.cxx | 73 + .../ut_xaodcore_floatcompression_test.cxx | 54 + .../test/ut_xaodcore_printhelpers_test.cxx | 60 + .../test/ut_xaodcore_safedeepcopy_test.cxx | 160 + .../xAODCore/test/ut_xaodcore_shallowcopy.cxx | 120 + .../xAOD/xAODCore/test/xAODCore_test.xml | 15 + .../xAOD/xAODCore/xAODCore/AddDVProxy.h | 263 + .../xAOD/xAODCore/xAODCore/AuxContainerBase.h | 235 + .../xAODCore/xAODCore/AuxContainerBase.icc | 90 + .../xAOD/xAODCore/xAODCore/AuxInfoBase.h | 222 + .../xAOD/xAODCore/xAODCore/AuxInfoBase.icc | 72 + .../xAOD/xAODCore/xAODCore/AuxSelection.h | 53 + .../xAODCore/AuxStoreAccessorMacros.h | 172 + EDM/athena/xAOD/xAODCore/xAODCore/BaseInfo.h | 62 + EDM/athena/xAOD/xAODCore/xAODCore/CLASS_DEF.h | 79 + .../xAOD/xAODCore/xAODCore/ClassID_traits.h | 83 + .../xAODCore/xAODCore/ShallowAuxContainer.h | 224 + .../xAOD/xAODCore/xAODCore/ShallowAuxInfo.h | 52 + .../xAOD/xAODCore/xAODCore/ShallowCopy.h | 137 + .../xAOD/xAODCore/xAODCore/selection.xml | 102 + .../xAODCore/selectionAthSuppress.xml | 12 + .../xAODCore/xAODCore/selectionAthena.xml | 24 + .../xAODCore/xAODCore/tools/AuxPersInfo.h | 87 + .../xAODCore/xAODCore/tools/AuxPersVector.h | 48 + .../xAODCore/xAODCore/tools/FloatCompressor.h | 65 + .../xAOD/xAODCore/xAODCore/tools/IOStats.h | 52 + .../xAOD/xAODCore/xAODCore/tools/PerfStats.h | 125 + .../xAODCore/xAODCore/tools/PrintHelpers.h | 47 + .../xAOD/xAODCore/xAODCore/tools/ReadStats.h | 341 + .../xAODCore/xAODCore/tools/SafeDeepCopy.h | 42 + .../xAODCore/tools/TDVCollectionProxy.h | 101 + .../xAOD/xAODCore/xAODCore/tools/Utils.h | 34 + .../xAODCore/xAODCore/xAODCoreAthenaDict.h | 25 + .../xAOD/xAODCore/xAODCore/xAODCoreDict.h | 18 + .../xAOD/xAODCore/xAODCore/xAODCoreRflxDict.h | 51 + EDM/athena/xAOD/xAODTracking/CMakeLists.txt | 38 + .../xAOD/xAODTracking/Root/StripCluster.cxx | 58 + .../Root/StripClusterAuxContainer.cxx | 58 + .../Root/dict/ContainerProxies.cxx | 10 + .../xAOD/xAODTracking/cmt/Makefile.RootCore | 27 + EDM/athena/xAOD/xAODTracking/cmt/requirements | 50 + EDM/athena/xAOD/xAODTracking/doc/mainpage.h | 32 + .../share/xAODTracking_TrackParticle_test.ref | 18 + ...Tracking_TrackParticlexAODHelpers_test.ref | 1 + .../test/xAODTracking_StripCluster_test.cxx | 69 + .../xAODTracking/xAODTracking/StripCluster.h | 72 + .../xAODTracking/StripClusterAuxContainer.h | 48 + .../xAODTracking/StripClusterContainer.h | 18 + .../xAODTracking/xAODTracking/selection.xml | 47 + .../xAODTracking/xAODTrackingDict.h | 59 + 1181 files changed, 189026 insertions(+), 86 deletions(-) delete mode 100644 EDM/Identifier.h create mode 100644 EDM/README.md delete mode 100644 EDM/StripCluster.h create mode 100644 EDM/athena/AtlasTest/TestTools/CMakeLists.txt create mode 100644 EDM/athena/AtlasTest/TestTools/TestTools/FLOATassert.h create mode 100644 EDM/athena/AtlasTest/TestTools/TestTools/SGassert.h create mode 100644 EDM/athena/AtlasTest/TestTools/TestTools/expect_exception.h create mode 100644 EDM/athena/AtlasTest/TestTools/TestTools/initGaudi.h create mode 100644 EDM/athena/AtlasTest/TestTools/TestTools/random.h create mode 100644 EDM/athena/AtlasTest/TestTools/cmt/Makefile.RootCore create mode 100644 EDM/athena/AtlasTest/TestTools/cmt/requirements create mode 100644 EDM/athena/AtlasTest/TestTools/doc/MainPage.h create mode 100644 EDM/athena/AtlasTest/TestTools/python/__init__.py create mode 100644 EDM/athena/AtlasTest/TestTools/python/iobench.py create mode 100644 EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitSGServiceTestExample.sh create mode 100644 EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitTestExample.sh create mode 100644 EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld.sh create mode 100644 EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_XML.xml create mode 100644 EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_script.xml create mode 100644 EDM/athena/AtlasTest/TestTools/share/IoAuditor_fragment.py create mode 100644 EDM/athena/AtlasTest/TestTools/share/post.sh create mode 100644 EDM/athena/AtlasTest/TestTools/share/runUnitTests.sh create mode 100644 EDM/athena/AtlasTest/TestTools/src/initGaudi.cxx create mode 100644 EDM/athena/AtlasTest/TestTools/test/test_iobench.py create mode 100644 EDM/athena/Build/AtlasBuildScripts/LCG_RELEASE_BASE.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/README.md create mode 100644 EDM/athena/Build/AtlasBuildScripts/TDAQ_RELEASE_BASE.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/build_Gaudi.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/build_atlasexternals.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/checkout_Gaudi.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/checkout_atlasexternals.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/copy_rpm_eos.sh create mode 100644 EDM/athena/Build/AtlasBuildScripts/tag_build.sh create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/Arena.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaBase.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/DataPool.h create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/DataPool.icc create mode 100644 EDM/athena/Control/AthAllocators/AthAllocators/selection.xml create mode 100644 EDM/athena/Control/AthAllocators/CMakeLists.txt create mode 100644 EDM/athena/Control/AthAllocators/cmt/requirements create mode 100644 EDM/athena/Control/AthAllocators/ispellwords create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaAllocatorBase_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaAllocatorCreator_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaAllocatorRegistry_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaBase_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaBlockAllocatorBase_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaBlock_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaCachingHandle_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHandleBaseAllocT_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHandleBaseT_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHandleBase_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHandle_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHeader_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHeapAllocator_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaPoolAllocator_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/Arena_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/DataPool_test.ref create mode 100644 EDM/athena/Control/AthAllocators/share/DataPool_test.txt create mode 100644 EDM/athena/Control/AthAllocators/src/Arena.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaAllocatorBase.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaBlock.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaHandleBase.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaHeader.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaHeapAllocator.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaPoolAllocator.cxx create mode 100644 EDM/athena/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaBase_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaBlock_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaCachingHandle_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHandleBase_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHandle_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHeader_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/Arena_test.cxx create mode 100644 EDM/athena/Control/AthAllocators/test/AthAllocators.xml create mode 100644 EDM/athena/Control/AthAllocators/test/DataPool_test.cxx create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AthContainersDict.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxElement.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxElement.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxStoreInternal.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxStoreStandalone.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ClassName.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ClassName.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ConstDataList.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ConstDataList.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/DataList.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/DataList.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/DataVector.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/DataVector.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/IndexTrackingPolicy.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/OwnershipPolicy.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/PackedContainer.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/PackedContainer.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/PackedConverter.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/PackedConverter.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/PackedParameters.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/PackedParameters.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/UserDataStore.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ViewVector.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ViewVector.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/dataVectorAsELV.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/debug.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/exceptions.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/normalizedTypeinfoName.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/selection.xml create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/ATHCONTAINERS_ASSERT.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/AuxDataTraits.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/ClassID.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/CompareAndPrint.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/CurrentEventStore.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLCast.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLEltBaseInfo.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLIterator.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVLNoBase.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/DVL_iter_swap.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/IsMostDerivedFlag.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/UDSLabelHashTable.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/assume.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/copyAuxStoreThinned.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/error.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/foreach.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.icc create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/likely.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/threading.h create mode 100644 EDM/athena/Control/AthContainers/AthContainers/tools/threading.icc create mode 100644 EDM/athena/Control/AthContainers/CMakeLists.txt create mode 100644 EDM/athena/Control/AthContainers/Root/AuxElement.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/AuxStoreInternal.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/AuxStoreStandalone.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/AuxTypeRegistry.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/AuxVectorBase.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/AuxVectorData.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/CompareAndPrint.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/DVLInfo.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/PackedConverter.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/PackedParameters.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/UDSLabelHashTable.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/UserDataStore.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/debug.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/dict/PackedContainerStreamer.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/dict/ViewVectorBaseStreamer.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/error.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/exceptions.cxx create mode 100644 EDM/athena/Control/AthContainers/Root/normalizedTypeinfoName.cxx create mode 100644 EDM/athena/Control/AthContainers/cmt/Makefile.RootCore create mode 100644 EDM/athena/Control/AthContainers/cmt/requirements create mode 100644 EDM/athena/Control/AthContainers/ispellwords create mode 100644 EDM/athena/Control/AthContainers/share/AuxElementComplete_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxElement_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxStoreInternal_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxStoreStandalone_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxTypeRegistry_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxTypeVectorFactory_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxTypeVector_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxVectorBase_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/AuxVectorData_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DVLCast_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DVLDataBucket_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DVLInfo_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DVLIterator_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DVL_iter_swap_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataList_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_a_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_b_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_c_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_d_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_e_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_f_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/DataVector_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/ElementProxy_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/IsMostDerivedFlag_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/PackedContainer_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/PackedConverter_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/PackedParameters_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/ViewVectorBase_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/ViewVector_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/copyAuxStoreThinned_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/copyThinned_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/dataVectorAsELV_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/debug_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/error_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/exceptions_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/foreach_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/getThinnedFlags_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/normalizedTypeinfoName_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/removeDuplicates_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/threading_nothreads_test.ref create mode 100644 EDM/athena/Control/AthContainers/share/threading_test.ref create mode 100644 EDM/athena/Control/AthContainers/src/copyAuxStoreThinned.cxx create mode 100644 EDM/athena/Control/AthContainers/src/getThinnedFlags.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AthContainers.xml create mode 100644 EDM/athena/Control/AthContainers/test/AuxElementComplete_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxElement_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxStoreInternal_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxStoreStandalone_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxTypeRegistry_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxTypeVectorFactory_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxTypeVector_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxVectorBase_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/AuxVectorData_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DVLCast_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DVLDataBucket_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DVLInfo_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DVLIterator_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DVL_iter_swap_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataList_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_a_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_b_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_c_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_d_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_e_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_f_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/DataVector_test.icc create mode 100644 EDM/athena/Control/AthContainers/test/ElementProxy_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/IsMostDerivedFlag_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/PackedContainer_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/PackedConverter_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/PackedParameters_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/TestThinningSvc.icc create mode 100644 EDM/athena/Control/AthContainers/test/ViewVectorBase_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/ViewVector_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/auxid_set_equal.icc create mode 100644 EDM/athena/Control/AthContainers/test/copyAuxStoreThinned_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/copyThinned_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/dataVectorAsELV_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/debug_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/error_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/exceptions_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/foreach_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/getThinnedFlags_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/normalizedTypeinfoName_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/removeDuplicates_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/threading_nothreads_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/threading_test.cxx create mode 100644 EDM/athena/Control/AthContainers/test/ut_ConstDataVector_basic_test.cxx create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.icc create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxStore_traits.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxTypes.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/CLASS_AUXSTORE.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxElement.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxSetOption.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStore.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreHolder.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreIO.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVector.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVectorFactory.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IConstAuxStore.h create mode 100644 EDM/athena/Control/AthContainersInterfaces/CMakeLists.txt create mode 100644 EDM/athena/Control/AthContainersInterfaces/cmt/Makefile.RootCore create mode 100644 EDM/athena/Control/AthContainersInterfaces/cmt/requirements create mode 100644 EDM/athena/Control/AthContainersInterfaces/ispellwords create mode 100644 EDM/athena/Control/AthContainersInterfaces/share/AuxDataOption_test.ref create mode 100644 EDM/athena/Control/AthContainersInterfaces/share/AuxStore_traits_test.ref create mode 100644 EDM/athena/Control/AthContainersInterfaces/test/AuxDataOption_test.cxx create mode 100644 EDM/athena/Control/AthContainersInterfaces/test/AuxStore_traits_test.cxx create mode 100644 EDM/athena/Control/AthLinks/AthLinks/AssociationMap.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/AssociationMap.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/AthLinksDict.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/DataLink.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/DataLink.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/DataPtr.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/DeclareIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLink.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLink.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/ElementLinkVectorBase.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/exceptions.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/selection.xml create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/AssociationObjectIterator.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/AssociationVectorIterator.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/DefaultIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/ElementLinkTraits.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/GenerateIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndex.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/IndexHolder.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/IsSTLSequence.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/RemoveDataPtr.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.icc create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/findInContainer.h create mode 100644 EDM/athena/Control/AthLinks/AthLinks/tools/selection_ns.h create mode 100644 EDM/athena/Control/AthLinks/CMakeLists.txt create mode 100644 EDM/athena/Control/AthLinks/cmt/requirements create mode 100644 EDM/athena/Control/AthLinks/ispellwords create mode 100644 EDM/athena/Control/AthLinks/share/AssociationMap_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/DataLinkBase_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/DataLink_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/DataProxyHolder_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/DataProxyStorageData_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/DataProxyStorage_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/DataPtr_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/ElementHolder_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/ElementLinkBase_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/ElementLinkFwd_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/ElementLink_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/ForwardIndexingPolicy_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/GenericElementLinkBase_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/IdentContIndex_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/IdentContIndexingPolicy_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/IndexHolder_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/IsSTLSequence_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/MapIndexingPolicy_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/SetIndexingPolicy_test.ref create mode 100644 EDM/athena/Control/AthLinks/share/exceptions_test.ref create mode 100644 EDM/athena/Control/AthLinks/src/DataProxyHolder.cxx create mode 100644 EDM/athena/Control/AthLinks/src/ElementLinkVectorBase.cxx create mode 100644 EDM/athena/Control/AthLinks/src/exceptions.cxx create mode 100644 EDM/athena/Control/AthLinks/test/AssociationMap_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/AthLinks.xml create mode 100644 EDM/athena/Control/AthLinks/test/DataLinkBase_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/DataLink_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/DataProxyHolder_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/DataPtr_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/ELFCont.h create mode 100644 EDM/athena/Control/AthLinks/test/ELFElt.h create mode 100644 EDM/athena/Control/AthLinks/test/ElementLinkBase_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/ElementLinkFwd_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/ElementLink_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/ForwardIndexingPolicy_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/GenericElementLinkBase_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/IdentContIndex_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/IdentContIndexingPolicy_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/IndexHolder_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/IsSTLSequence_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/MapIndexingPolicy_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/SetIndexingPolicy_test.cxx create mode 100644 EDM/athena/Control/AthLinks/test/TestThinningSvc.icc create mode 100644 EDM/athena/Control/AthLinks/test/exceptions_test.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgTool.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgorithm.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCheckMacros.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCnvSvc.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthFilterAlgorithm.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramAlgorithm.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramFilterAlgorithm.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramTool.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramming.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMemMacros.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMessaging.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMsgStreamMacros.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthReentrantAlgorithm.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthService.h create mode 100644 EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/FilteredAlgorithm.h create mode 100644 EDM/athena/Control/AthenaBaseComps/CMakeLists.txt create mode 100644 EDM/athena/Control/AthenaBaseComps/cmt/requirements create mode 100644 EDM/athena/Control/AthenaBaseComps/share/AthReentrantAlgorithm_test.ref create mode 100644 EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.ref create mode 100644 EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.txt create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthAlgTool.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthAlgorithm.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthCnvSvc.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthFilterAlgorithm.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthHistogramAlgorithm.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthHistogramFilterAlgorithm.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthHistogramTool.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthHistogramming.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthMessaging.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthReentrantAlgorithm.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/AthService.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/src/FilteredAlgorithm.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/test/AthReentrantAlgorithm_test.cxx create mode 100644 EDM/athena/Control/AthenaBaseComps/test/AthenaBaseComps.xml create mode 100644 EDM/athena/Control/AthenaBaseComps/test/propertyHandling_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/AddressProviderSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/AlgorithmTimer.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/AthDsoUtils.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/Chrono.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/CloneService.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/CloneTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/CondCont.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/DataObjectSharedPtr.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/DefaultKey.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/DirSearchPath.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/DsoDb.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAddressProvider.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAtRndmGenSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaBarCode.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaEvtLoopPreSelectTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaIPCTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputStreamTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSealSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSummarySvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IClassIDSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ICollectionSize.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ICoreDumpSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ICutFlowSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IDataShare.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IDictLoaderSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IEventDumperSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IEventSeek.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IEventShare.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IGMASvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStore.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStoreMgr.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVDbSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IInputRename.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponent.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponentMgr.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IItemListSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IJobIDSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ILockable.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ILoggedMessageSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IMemoryMonitorSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/INextPassFilter.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IOVEntryT.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IOVRange.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IOVSvcDefs.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IOVTime.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IPageAccessControlSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyDict.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyProviderSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyRegistry.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IRCUSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IRegistrationStreamTool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IResetable.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ISlimmingHdlr.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IStringPool.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvBase.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningHdlr.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ITimeKeeper.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/ITriggerTime.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IUserDataSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/IValgrindSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/MsgStreamMember.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/POSIXTimeKeeper.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.icc create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/StoreID.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/TPCnvFactory.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/TimeKeeper.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/Timeout.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/Units.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/errorcheck.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/getMessageSvc.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/selection.xml create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/sgkey_t.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/tools/AthenaPackageInfo.h create mode 100644 EDM/athena/Control/AthenaKernel/AthenaKernel/tools/type_tools.h create mode 100644 EDM/athena/Control/AthenaKernel/CMakeLists.txt create mode 100644 EDM/athena/Control/AthenaKernel/cmt/requirements create mode 100644 EDM/athena/Control/AthenaKernel/doc/MainPage.h create mode 100644 EDM/athena/Control/AthenaKernel/share/AthenaPackageInfo_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/Chrono_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/DataObjectSharedPtr_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/DirSearchPath_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/IRCUSvc_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/MsgStreamMember_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/RCUObject_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/Units_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/errorcheck_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/getMessageSvc_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/share/type_tools_test.ref create mode 100644 EDM/athena/Control/AthenaKernel/src/AddressProviderSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/AlgorithmTimer.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/AthDsoUtils.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/AthenaPackageInfo.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/CloneService.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/CloneTool.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/DsoDb.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IAtRndmGenSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IAthenaBarCode.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IAthenaIPCTool.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IAthenaSerializeSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IAthenaSummarySvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ICutFlowSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IDataShare.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IDecisionSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IDictLoaderSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IEventShare.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IEvtIdModifierSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IItemListSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IJobIDSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ILoggedMessageSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IOVRange.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IOVTime.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IProxyDict.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ISlimmingHdlr.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ITPCnvBase.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ITPCnvSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IThinningHdlr.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IThinningSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ITimeKeeper.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/IValgrindSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/MsgStreamMember.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/POSIXTimeKeeper.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/RCUObject.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/TimeKeeper.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/errorcheck.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/getMessageSvc.cxx create mode 100644 EDM/athena/Control/AthenaKernel/src/ubsan_boost_suppress.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/AthenaKernel.xml create mode 100644 EDM/athena/Control/AthenaKernel/test/AthenaPackageInfo_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/Chrono_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/DataObjectSharedPtr_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/DirSearchPath_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/IRCUSvc_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/MsgStreamMember_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/RCUObject_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/Units_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/errorcheck_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/getMessageSvc_test.cxx create mode 100644 EDM/athena/Control/AthenaKernel/test/type_tools_test.cxx create mode 100644 EDM/athena/Control/CLIDComps/CMakeLists.txt create mode 100644 EDM/athena/Control/CLIDComps/cmt/requirements create mode 100644 EDM/athena/Control/CLIDComps/python/__init__.py create mode 100644 EDM/athena/Control/CLIDComps/python/clidGenerator.py create mode 100644 EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.ref create mode 100644 EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.txt create mode 100644 EDM/athena/Control/CLIDComps/share/Gaudi_clid.db create mode 100644 EDM/athena/Control/CLIDComps/share/PYTHONSTARTUP create mode 100644 EDM/athena/Control/CLIDComps/share/clid create mode 100644 EDM/athena/Control/CLIDComps/share/cvs2cliddb.csh create mode 100644 EDM/athena/Control/CLIDComps/share/minimalPrintout.opts create mode 100644 EDM/athena/Control/CLIDComps/src/ClassIDSvc.cxx create mode 100644 EDM/athena/Control/CLIDComps/src/ClassIDSvc.h create mode 100644 EDM/athena/Control/CLIDComps/src/components/CLIDComps_entries.cxx create mode 100644 EDM/athena/Control/CLIDComps/src/components/CLIDComps_load.cxx create mode 100644 EDM/athena/Control/CLIDComps/test/CLIDComps.xml create mode 100644 EDM/athena/Control/CLIDComps/test/ClassIDSvc_test.cxx create mode 100644 EDM/athena/Control/CLIDComps/test/_clid_unittest.py create mode 100644 EDM/athena/Control/CLIDComps/util/genCLIDDB.cxx create mode 100644 EDM/athena/Control/CxxUtils/CMakeLists.txt create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/Array.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/Array.icc create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.icc create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/Arrayrep.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/AthDsoCbk.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/AthUnlikelyMacros.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/BasicTypes.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.icc create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.icc create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/ClassName.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/FloatPacker.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/MD5.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/PackedArray.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/PageAccessControl.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/PtrAccessSEGVHandler.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/SealCommon.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/SealDebug.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/SealSharedLib.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/SealSignal.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/StrFormat.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/StringUtils.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/algorithms.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/bitscan.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/cPtrAccessSEGVHandler.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/clock.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/copy_bounded.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/enable_if.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/excepts.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/exctrace.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/final.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/fpcompare.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/hashtable.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/arraylist.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/avl-tree.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binary-heap.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binomial-heap.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/bloom-filter.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-int.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-pointer.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-string.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-int.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-pointer.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-string.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-table.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/libcalg.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/list.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/queue.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/set.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/slist.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/libcalg/trie.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/make_unique.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/no_conversion_warning.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/no_sanitize_undefined.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/noreturn.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/ones.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/override.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/page_access.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.icc create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/prefetch.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/procmaps.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/read_athena_statm.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/sincos.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/sincosf.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/ubsan_suppress.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/unordered_map.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/unordered_set.h create mode 100644 EDM/athena/Control/CxxUtils/CxxUtils/unused.h create mode 100644 EDM/athena/Control/CxxUtils/Root/Array.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/ArrayScanner.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/Arrayrep.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/ClassName.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/FloatPacker.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/MD5.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/PackedArray.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/PageAccessControl.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/PtrAccessSEGVHandler.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/SealDebug.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/SealSharedLib.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/SealSignal.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/StrFormat.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/StringUtils.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/StringUtils_aux.h create mode 100644 EDM/athena/Control/CxxUtils/Root/cPtrAccessSEGVHandler.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/clock.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/excepts.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/exctrace.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/hashtable.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/page_access.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/pointer_list.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/procmaps.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/read_athena_statm.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/sincosf.cxx create mode 100644 EDM/athena/Control/CxxUtils/Root/ubsan_suppress.cxx create mode 100644 EDM/athena/Control/CxxUtils/cmt/Makefile.RootCore create mode 100644 EDM/athena/Control/CxxUtils/cmt/requirements create mode 100644 EDM/athena/Control/CxxUtils/ispellwords create mode 100644 EDM/athena/Control/CxxUtils/share/ArrayScanner_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/Array_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/Arrayrep_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/BitPackerUnpacker_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/ClassName_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/FloatPacker_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/PackedArray_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/PageAccessControl_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/SEGVHandler_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/StrFormat_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/copy_bounded_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/copyif_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/exctrace1_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/exctrace2_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/fpcompare_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/hashtable_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/make_unique_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/ones_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/pointer_list_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/prefetch_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/procmaps_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/read_athena_statm_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/sincos_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/stacktrace_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/stringformconvert_test.ref create mode 100644 EDM/athena/Control/CxxUtils/share/utf8trim_test.ref create mode 100644 EDM/athena/Control/CxxUtils/src/AthDsoCbk.c create mode 100644 EDM/athena/Control/CxxUtils/src/exctrace/exctrace_collector.cxx create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/arraylist.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/avl-tree.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/binary-heap.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/binomial-heap.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/bloom-filter.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/compare-int.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/compare-pointer.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/compare-string.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/hash-int.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/hash-pointer.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/hash-string.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/hash-table.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/list.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/queue.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/set.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/slist.c create mode 100644 EDM/athena/Control/CxxUtils/src/libcalg/trie.c create mode 100644 EDM/athena/Control/CxxUtils/test/ArrayScanner_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/Array_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/Arrayrep_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/BitPackerUnpacker_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/ClassName_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/CxxUtils.xml create mode 100644 EDM/athena/Control/CxxUtils/test/FloatPacker_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/PackedArray_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/PageAccessControl_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/SEGVHandler_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/StrFormat_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/bitscan_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/copy_bounded_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/copyif_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/exctrace1_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/exctrace2_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/expect_exception.icc create mode 100644 EDM/athena/Control/CxxUtils/test/fpcompare_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/hashtable_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/make_unique_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/ones_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/pointer_list_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/prefetch_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/procmaps_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/read_athena_statm_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/sincos_test.cxx create mode 100644 EDM/athena/Control/CxxUtils/test/stacktrace_test.cxx create mode 100644 EDM/athena/Control/DataModel/CMakeLists.txt create mode 100644 EDM/athena/Control/DataModel/DataModel/Arena.h create mode 100644 EDM/athena/Control/DataModel/DataModel/AssociationMap.h create mode 100644 EDM/athena/Control/DataModel/DataModel/ClassName.h create mode 100644 EDM/athena/Control/DataModel/DataModel/ConstDataVector.h create mode 100644 EDM/athena/Control/DataModel/DataModel/DataLink.h create mode 100644 EDM/athena/Control/DataModel/DataModel/DataList.h create mode 100644 EDM/athena/Control/DataModel/DataModel/DataPool.h create mode 100644 EDM/athena/Control/DataModel/DataModel/DataVector.h create mode 100644 EDM/athena/Control/DataModel/DataModel/ElementLink.h create mode 100644 EDM/athena/Control/DataModel/DataModel/ElementLinkVector.h create mode 100644 EDM/athena/Control/DataModel/DataModel/OwnershipPolicy.h create mode 100644 EDM/athena/Control/DataModel/DataModel/UserDataStore.h create mode 100644 EDM/athena/Control/DataModel/DataModel/tools/ArenaPoolSTLAllocator.h create mode 100644 EDM/athena/Control/DataModel/DataModel/tools/ArenaSharedHeapSTLAllocator.h create mode 100644 EDM/athena/Control/DataModel/DataModel/tools/DVLInfo.h create mode 100644 EDM/athena/Control/DataModel/DataModel/tools/IdentContIndex.h create mode 100644 EDM/athena/Control/DataModel/DataModel/unordered_map.h create mode 100644 EDM/athena/Control/DataModel/cmt/requirements create mode 100644 EDM/athena/Control/DataModel/doc/MainPage.h create mode 100644 EDM/athena/Control/DataModel/ispellwords create mode 100644 EDM/athena/Control/DataModelRoot/CMakeLists.txt create mode 100644 EDM/athena/Control/DataModelRoot/DataModelRoot/DataModelRootDict.h create mode 100644 EDM/athena/Control/DataModelRoot/DataModelRoot/RootType.h create mode 100644 EDM/athena/Control/DataModelRoot/DataModelRoot/selection.xml create mode 100644 EDM/athena/Control/DataModelRoot/cmt/requirements create mode 100644 EDM/athena/Control/DataModelRoot/src/RootType.cxx create mode 100644 EDM/athena/Control/SGMon/SGAudCore/CMakeLists.txt create mode 100644 EDM/athena/Control/SGMon/SGAudCore/SGAudCore/ISGAudSvc.h create mode 100644 EDM/athena/Control/SGMon/SGAudCore/cmt/requirements create mode 100644 EDM/athena/Control/SGMon/SGAudCore/src/ISGAudSvc.cxx create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/CMakeLists.txt create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/SGAudSvc/SGAudSvc.h create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/cmt/requirements create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/doc/mainpage.h create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/share/SGout2dot.py create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/share/checkFileSG.py create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/src/SGAudSvc.cxx create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_entries.cxx create mode 100644 EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_load.cxx create mode 100644 EDM/athena/Control/SGTools/CMakeLists.txt create mode 100644 EDM/athena/Control/SGTools/SGTools/BaseInfo.h create mode 100644 EDM/athena/Control/SGTools/SGTools/BaseInfo.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/BuiltinsClids.h create mode 100644 EDM/athena/Control/SGTools/SGTools/CLASS_DEF.h create mode 100644 EDM/athena/Control/SGTools/SGTools/CLIDRegistry.h create mode 100644 EDM/athena/Control/SGTools/SGTools/CallBackID.h create mode 100644 EDM/athena/Control/SGTools/SGTools/CallBackID.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/ClassID_traits.h create mode 100644 EDM/athena/Control/SGTools/SGTools/ClassName.h create mode 100644 EDM/athena/Control/SGTools/SGTools/ClassName.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/CurrentEventStore.h create mode 100644 EDM/athena/Control/SGTools/SGTools/CurrentEventStore.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/DataBucket.h create mode 100644 EDM/athena/Control/SGTools/SGTools/DataBucket.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/DataBucketBase.h create mode 100644 EDM/athena/Control/SGTools/SGTools/DataBucketBase.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/DataBucketTraitFwd.h create mode 100644 EDM/athena/Control/SGTools/SGTools/DataHandleBase.h create mode 100644 EDM/athena/Control/SGTools/SGTools/DataProxy.h create mode 100644 EDM/athena/Control/SGTools/SGTools/DataProxy.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/DataStore.h create mode 100644 EDM/athena/Control/SGTools/SGTools/IProxyDictWithPool.h create mode 100644 EDM/athena/Control/SGTools/SGTools/IRegisterTransient.h create mode 100644 EDM/athena/Control/SGTools/SGTools/IStringPool.h create mode 100644 EDM/athena/Control/SGTools/SGTools/ProxyMap.h create mode 100644 EDM/athena/Control/SGTools/SGTools/SGFolderItem.h create mode 100644 EDM/athena/Control/SGTools/SGTools/SGIFolder.h create mode 100644 EDM/athena/Control/SGTools/SGTools/SGToolsDict.h create mode 100644 EDM/athena/Control/SGTools/SGTools/SGVersionedKey.h create mode 100644 EDM/athena/Control/SGTools/SGTools/StlMapClids.h create mode 100644 EDM/athena/Control/SGTools/SGTools/StlVectorClids.h create mode 100644 EDM/athena/Control/SGTools/SGTools/StorableConversions.h create mode 100644 EDM/athena/Control/SGTools/SGTools/StringPool.h create mode 100644 EDM/athena/Control/SGTools/SGTools/T2pMap.h create mode 100644 EDM/athena/Control/SGTools/SGTools/TestStore.h create mode 100644 EDM/athena/Control/SGTools/SGTools/TransientAddress.h create mode 100644 EDM/athena/Control/SGTools/SGTools/crc64.h create mode 100644 EDM/athena/Control/SGTools/SGTools/exceptions.h create mode 100644 EDM/athena/Control/SGTools/SGTools/hashtable.h create mode 100644 EDM/athena/Control/SGTools/SGTools/ptrhash.h create mode 100644 EDM/athena/Control/SGTools/SGTools/safe_clid.h create mode 100644 EDM/athena/Control/SGTools/SGTools/safe_clid.icc create mode 100644 EDM/athena/Control/SGTools/SGTools/selection.xml create mode 100644 EDM/athena/Control/SGTools/SGTools/unordered_map.h create mode 100644 EDM/athena/Control/SGTools/cmt/requirements create mode 100644 EDM/athena/Control/SGTools/doc/MainPage.h create mode 100644 EDM/athena/Control/SGTools/ispellwords create mode 100644 EDM/athena/Control/SGTools/share/BaseInfo_test.ref create mode 100644 EDM/athena/Control/SGTools/share/CLIDRegistry_test.ref create mode 100644 EDM/athena/Control/SGTools/share/ClassName_test.ref create mode 100644 EDM/athena/Control/SGTools/share/CurrentEventStore_test.ref create mode 100644 EDM/athena/Control/SGTools/share/DataBucket_test.ref create mode 100644 EDM/athena/Control/SGTools/share/DataProxy_test.ref create mode 100644 EDM/athena/Control/SGTools/share/DataStore_test.ref create mode 100644 EDM/athena/Control/SGTools/share/SGFolderItem_test.ref create mode 100644 EDM/athena/Control/SGTools/share/StringPool_test.ref create mode 100644 EDM/athena/Control/SGTools/share/TransientAddress_test.ref create mode 100644 EDM/athena/Control/SGTools/share/VersionedKey_test.ref create mode 100644 EDM/athena/Control/SGTools/share/crc64_test.ref create mode 100644 EDM/athena/Control/SGTools/share/exceptions_test.ref create mode 100644 EDM/athena/Control/SGTools/share/safe_clid_test.ref create mode 100644 EDM/athena/Control/SGTools/src/BaseInfo.cxx create mode 100644 EDM/athena/Control/SGTools/src/CLIDRegistry.cxx create mode 100644 EDM/athena/Control/SGTools/src/CurrentEventStore.cxx create mode 100644 EDM/athena/Control/SGTools/src/DataHandleBase.cxx create mode 100644 EDM/athena/Control/SGTools/src/DataProxy.cxx create mode 100644 EDM/athena/Control/SGTools/src/DataStore.cxx create mode 100644 EDM/athena/Control/SGTools/src/SGFolderItem.cxx create mode 100644 EDM/athena/Control/SGTools/src/SGToolsClids.cxx create mode 100644 EDM/athena/Control/SGTools/src/SGVersionedKey.cxx create mode 100644 EDM/athena/Control/SGTools/src/StorableConversions.cxx create mode 100644 EDM/athena/Control/SGTools/src/StringPool.cxx create mode 100644 EDM/athena/Control/SGTools/src/T2pMap.cxx create mode 100644 EDM/athena/Control/SGTools/src/TestStore.cxx create mode 100644 EDM/athena/Control/SGTools/src/TransientAddress.cxx create mode 100644 EDM/athena/Control/SGTools/src/crc64.cxx create mode 100644 EDM/athena/Control/SGTools/src/exceptions.cxx create mode 100644 EDM/athena/Control/SGTools/test/BaseInfo_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/CLIDRegistry_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/ClassName_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/CurrentEventStore_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/DataBucket_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/DataProxy_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/DataStore_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/SGFolderItem_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/SGTools.xml create mode 100644 EDM/athena/Control/SGTools/test/StringPool_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/TransientAddress_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/VersionedKey_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/crc64_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/exceptions_test.cxx create mode 100644 EDM/athena/Control/SGTools/test/safe_clid_test.cxx create mode 100644 EDM/athena/Control/StoreGate/AUTHORS create mode 100644 EDM/athena/Control/StoreGate/CMakeLists.txt create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ActiveStoreSvc.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/DataHandle.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/DataHandle.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/RVar.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/RWVar.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadCondHandle.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadCondHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadHandle.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadHandle.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/ReadHandleKeyArray.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SGHiveEventSlot.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SGIterator.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SGObjectWithVersion.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SGWPtr.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SGtests.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/StoreClearedIncident.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/StoreGate.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyProperty.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/VarHandleProperty.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WVar.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteCondHandle.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteCondHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteHandle.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteHandle.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/WriteHandleKeyArray.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/constraints/KeyConcept.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/exceptions.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/setupStoreGate.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.icc create mode 100644 EDM/athena/Control/StoreGate/StoreGate/tools/StorableConversions.h create mode 100644 EDM/athena/Control/StoreGate/StoreGate/tools/hash_functions.h create mode 100644 EDM/athena/Control/StoreGate/cmt/requirements create mode 100644 EDM/athena/Control/StoreGate/doc/MainPage.h create mode 100644 EDM/athena/Control/StoreGate/python/Bindings.py create mode 100644 EDM/athena/Control/StoreGate/python/RedirectProxyProviderSvc.py create mode 100644 EDM/athena/Control/StoreGate/python/__init__.py create mode 100644 EDM/athena/Control/StoreGate/share/ActiveStoreHive_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/ActiveStore_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/ActiveStore_test.txt create mode 100644 EDM/athena/Control/StoreGate/share/DataHandle_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/KeyConcept_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/ReadHandleKey_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/ReadHandle_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/SGHive_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/SGHive_test.txt create mode 100644 EDM/athena/Control/StoreGate/share/SGIterator_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/SegMemSvc_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/StoreClearedIncident_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/StoreGateSvcClient_test.txt create mode 100644 EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.py create mode 100644 EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.txt create mode 100644 EDM/athena/Control/StoreGate/share/UpdateHandleKey_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/UpdateHandle_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleBase_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleBase_test.txt create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.txt create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleKey_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleProperty_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/VarHandleProperty_test.txt create mode 100644 EDM/athena/Control/StoreGate/share/VarHandles_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/WriteHandleKey_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/WriteHandle_test.ref create mode 100644 EDM/athena/Control/StoreGate/share/exceptions_test.ref create mode 100644 EDM/athena/Control/StoreGate/src/ActiveStoreSvc.cxx create mode 100644 EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.cxx create mode 100644 EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.h create mode 100644 EDM/athena/Control/StoreGate/src/SGImplSvc.cxx create mode 100644 EDM/athena/Control/StoreGate/src/SegMemSvc.cxx create mode 100644 EDM/athena/Control/StoreGate/src/StoreClearedIncident.cxx create mode 100644 EDM/athena/Control/StoreGate/src/StoreGate.cxx create mode 100644 EDM/athena/Control/StoreGate/src/StoreGateSvc.cxx create mode 100644 EDM/athena/Control/StoreGate/src/VarHandleBase.cxx create mode 100644 EDM/athena/Control/StoreGate/src/VarHandleKey.cxx create mode 100644 EDM/athena/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx create mode 100644 EDM/athena/Control/StoreGate/src/VarHandleKeyProperty.cxx create mode 100644 EDM/athena/Control/StoreGate/src/components/StoreGateSvc_entries.cxx create mode 100644 EDM/athena/Control/StoreGate/src/components/StoreGateSvc_load.cxx create mode 100644 EDM/athena/Control/StoreGate/src/exceptions.cxx create mode 100644 EDM/athena/Control/StoreGate/src/setupStoreGate.cxx create mode 100644 EDM/athena/Control/StoreGate/test/ActiveStore_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/DataHandle_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/KeyConcept_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/ReadHandleKey_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/ReadHandle_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/SGHive_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/SGIterator_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/SGtests.cxx create mode 100644 EDM/athena/Control/StoreGate/test/SegMemSvc_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/StoreClearedIncident_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/StoreGate.xml create mode 100644 EDM/athena/Control/StoreGate/test/UpdateHandleKey_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/UpdateHandle_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/VarHandleBase_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/VarHandleKeyProperty_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/VarHandleKey_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/VarHandleProperty_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/VarHandles_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/WriteHandleKey_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/WriteHandle_test.cxx create mode 100644 EDM/athena/Control/StoreGate/test/exceptions_test.cxx create mode 100644 EDM/athena/Projects/Calypso/CMakeLists.txt create mode 100644 EDM/athena/Projects/Calypso/PostConfig.cmake.in create mode 100644 EDM/athena/Projects/Calypso/README.md create mode 100755 EDM/athena/Projects/Calypso/build.sh create mode 100755 EDM/athena/Projects/Calypso/build_env.sh create mode 100755 EDM/athena/Projects/Calypso/build_externals.sh create mode 100644 EDM/athena/Projects/Calypso/externals.txt create mode 100644 EDM/athena/Projects/Calypso/externals/Crmc.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/EvtGen.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/HEPUtils.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Herwig.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Herwig3.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Hydjet.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Lhapdf.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/MCUtils.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/MadGraph5Amc.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Photospp.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Pythia6.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Pythia8.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/README.md create mode 100644 EDM/athena/Projects/Calypso/externals/Rivet.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Sherpa.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Starlight.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/Tauolapp.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/ThePEG.cmake create mode 100644 EDM/athena/Projects/Calypso/externals/YODA.cmake create mode 100644 EDM/athena/Projects/Calypso/package_filters.txt create mode 100644 EDM/athena/Projects/Calypso/version.txt create mode 100644 EDM/athena/Projects/WorkDir/CMakeLists.txt create mode 100644 EDM/athena/Projects/WorkDir/README.md create mode 100644 EDM/athena/Projects/WorkDir/package_filters_example.txt create mode 100644 EDM/athena/xAOD/xAODCore/CMakeLists.txt create mode 100644 EDM/athena/xAOD/xAODCore/Root/AddDVProxy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/AuxContainerBase.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/AuxInfoBase.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/AuxSelection.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/FloatCompressor.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/IOStats.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/LinkDef.h create mode 100644 EDM/athena/xAOD/xAODCore/Root/PerfStats.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/PrintHelpers.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/ReadStats.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/SafeDeepCopy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/ShallowAuxContainer.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/ShallowAuxInfo.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/TDVCollectionProxy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/Root/Utils.cxx create mode 100644 EDM/athena/xAOD/xAODCore/cmt/Makefile.RootCore create mode 100644 EDM/athena/xAOD/xAODCore/cmt/requirements create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxcontainerbase_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxselection_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_class_def_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_clearDecorations_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_floatcompression_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_printhelpers_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/share/ut_xaodcore_safedeepcopy_test.ref create mode 100644 EDM/athena/xAOD/xAODCore/src/README create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_AddDVProxy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_AuxContainerBase.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_AuxSelection.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_BaseInfo.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_CLASS_DEF.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_ClassID_traits.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxContainer.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxInfo.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_ShallowCopy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersInfo.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersVector.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_IOStats.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_PerfStats.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_PrintHelpers.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_ReadStats.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_SafeDeepCopy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_TDVCollectionProxy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/inc_tools_Utils.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_class_def.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxcontainerbase_test.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxselection_test.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_clearDecorations_test.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_floatcompression_test.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_printhelpers_test.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_safedeepcopy_test.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/ut_xaodcore_shallowcopy.cxx create mode 100644 EDM/athena/xAOD/xAODCore/test/xAODCore_test.xml create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AddDVProxy.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.icc create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.icc create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AuxSelection.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/AuxStoreAccessorMacros.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/BaseInfo.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/CLASS_DEF.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/ClassID_traits.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxContainer.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxInfo.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/ShallowCopy.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/selection.xml create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/selectionAthSuppress.xml create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/selectionAthena.xml create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersInfo.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersVector.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/FloatCompressor.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/IOStats.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/PerfStats.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/PrintHelpers.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/ReadStats.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/SafeDeepCopy.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/TDVCollectionProxy.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/tools/Utils.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreAthenaDict.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreDict.h create mode 100644 EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreRflxDict.h create mode 100755 EDM/athena/xAOD/xAODTracking/CMakeLists.txt create mode 100644 EDM/athena/xAOD/xAODTracking/Root/StripCluster.cxx create mode 100644 EDM/athena/xAOD/xAODTracking/Root/StripClusterAuxContainer.cxx create mode 100644 EDM/athena/xAOD/xAODTracking/Root/dict/ContainerProxies.cxx create mode 100644 EDM/athena/xAOD/xAODTracking/cmt/Makefile.RootCore create mode 100644 EDM/athena/xAOD/xAODTracking/cmt/requirements create mode 100644 EDM/athena/xAOD/xAODTracking/doc/mainpage.h create mode 100644 EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticle_test.ref create mode 100644 EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticlexAODHelpers_test.ref create mode 100644 EDM/athena/xAOD/xAODTracking/test/xAODTracking_StripCluster_test.cxx create mode 100644 EDM/athena/xAOD/xAODTracking/xAODTracking/StripCluster.h create mode 100644 EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterAuxContainer.h create mode 100644 EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterContainer.h create mode 100644 EDM/athena/xAOD/xAODTracking/xAODTracking/selection.xml create mode 100644 EDM/athena/xAOD/xAODTracking/xAODTracking/xAODTrackingDict.h diff --git a/EDM/Identifier.h b/EDM/Identifier.h deleted file mode 100644 index 62a97d73..00000000 --- a/EDM/Identifier.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - FASER Collaboration -*/ - -#ifndef IDENTIFIER_H -#define IDENTIFIER_H - -#include <iostream> - -using namespace std; - -class Identifier { - - public: - - Identifier(); - ~Identifier(); - Identifier(int); - - const int id(); - - private: - - int m_id; - -}; - -Identifier::Identifier() {} -Identifier::Identifier(int id) : m_id(id) {} -Identifier::~Identifier() {} - -const int Identifier::id() { return m_id; } - -#endif // IDENTIFIER_H diff --git a/EDM/README.md b/EDM/README.md new file mode 100644 index 00000000..b053c096 --- /dev/null +++ b/EDM/README.md @@ -0,0 +1,32 @@ +First barebone project for Calypso based on Athena 21.0. Only packages necessary to implement the current EDM in xAOD are included. The current build relies on Gaudi and AthenaExternals libraries. This should be okay for FASER, as we don.t want or need to build these two on our own. It currently also uses some of the ATLAS scripts to set environment variables . these can be replaced with either the spelled-out commands or our own scripts in the future. + +The following sequence will allow you to compile Calypso 1.0 on any machine with cvmfs access, and the necessary compiler libraries installed. +``` +#clone the (forked) project to your local machine +git clone https://:@gitlab.cern.ch:8443/username/calypso.git +cd calypso/EDM/ +#The next four lines are used to pick up the latest Gaudi and AthenaExternals libraries, and set the correct compiler +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +asetup AthenaExternals,gcc62,latest,21.0 +source ./athena/Build/AtlasBuildScripts/TDAQ_RELEASE_BASE.sh +mkdir build +cd build +#build calypso +cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCTEST_USE_LAUNCHERS=TRUE ../athena/Projects/Calypso ; make +#run a unittest for xAOD::StripCluster +ctest -V -R xAODTracking_StripCluster_test +``` +If everything worked out, you should see the following printout: +``` +test 176 + Start 176: xAODTracking_xAODTracking_StripCluster_test_ctest + +176: Test command: /home/calypso/EDM/build/xAOD/xAODTracking/CMakeFiles/xAODTracking_StripCluster_test.sh +176: Test timeout computed to be: 120 +176: id = 0 +176: local x = 1, local y = 2, local x error = 0.2, local y error = 0.2, local xy correlation = 0.05 +176: global x = 225, global y = -151.4, global z = 144.4 +176: Dumping StripClusterAuxContainer +176: id:0, localX:1, localY:2, localXError:0.2, localYError:0.2, localXYCorrelation:0.05, globalX:225, globalY:-151.4, globalZ:144.4, +``` diff --git a/EDM/StripCluster.h b/EDM/StripCluster.h deleted file mode 100644 index 76af3d8e..00000000 --- a/EDM/StripCluster.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - FASER Collaboration -*/ - -#ifndef STRIPCLUSTER_H -#define STRIPCLUSTER_H - -#include <iostream> -#include <vector> -#include <Eigen/Dense> -#include "Identifier.h" - -using namespace Eigen; -using namespace std; - -class StripCluster { - - public: - - StripCluster(); - ~StripCluster(); - StripCluster(int); - - const int id(); - const std::vector<Identifier>& rdoList(); - const Vector2d localPosition(); - const Vector3d& globalPosition(); - const Matrix2d localCovariance(); - - private: - - Identifier m_id; - std::vector<Identifier> m_rdo; - - Vector2d m_localPosition; - Vector3d *m_globalPosition; - Matrix2d m_localCovariance; - -}; - -StripCluster::StripCluster() {} -StripCluster::StripCluster(int id) : m_id(id) {} -StripCluster::~StripCluster() {} - -const int StripCluster::id() { return m_id.id(); } -const std::vector<Identifier>& StripCluster::rdoList() { return m_rdo; } - -const Vector2d StripCluster::localPosition() { return m_localPosition; } -const Vector3d& StripCluster::globalPosition() { return *m_globalPosition; } -const Matrix2d StripCluster::localCovariance() { return m_localCovariance; } - -#endif // STRIPCLUSTER_H diff --git a/EDM/athena/AtlasTest/TestTools/CMakeLists.txt b/EDM/athena/AtlasTest/TestTools/CMakeLists.txt new file mode 100644 index 00000000..4345698b --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/CMakeLists.txt @@ -0,0 +1,34 @@ +# $Id: CMakeLists.txt 744649 2016-05-03 19:33:39Z krasznaa $ +################################################################################ +# Package: TestTools +################################################################################ + +# Declare the package name: +atlas_subdir( TestTools ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/AthenaCommon + TestPolicy + PRIVATE + GaudiKernel ) + +# In standalone mode we just use the headers from the package. While in +# offline mode we build a proper library. +if( XAOD_STANDALONE ) + atlas_add_library( TestTools + TestTools/*.h + INTERFACE + PUBLIC_HEADERS TestTools ) +else() + atlas_add_library( TestTools + TestTools/*.h src/*.cxx + PUBLIC_HEADERS TestTools + PRIVATE_LINK_LIBRARIES GaudiKernel ) +endif() + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*.py ) +atlas_install_scripts( share/runUnitTests.sh share/post.sh ) diff --git a/EDM/athena/AtlasTest/TestTools/TestTools/FLOATassert.h b/EDM/athena/AtlasTest/TestTools/TestTools/FLOATassert.h new file mode 100644 index 00000000..e25ab15b --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/TestTools/FLOATassert.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** functions & macros to test the difference between floats */ +#ifndef TESTTOOLS_FLOATASSERT_H +#define TESTTOOLS_FLOATASSERT_H + +#include <iostream> +#include <cassert> +#include <cfloat> +#include <cmath> + +#undef NDEBUG + +namespace Athena_test { + inline + bool floatEQ(float lhs, float rhs) { + return fabs(lhs-rhs)<=FLT_EPSILON; + } + inline + bool floatNEQ(float lhs, float rhs) { + return fabs(lhs-rhs)>FLT_EPSILON; + } + + inline + bool isEqual (double x1, double x2, double thresh = 1e-6) + { + double den = std::abs(x1+x2); + if (den < thresh) return true; + double diff = std::abs (x1-x2) / den; + if (diff < thresh) + return true; + std::cout << "Match failure: " << x1 << " " << x2 << " (" << diff << ")\n"; + return false; + } + +} + +#define FLOAT_NEQassert( LHS, RHS ) assert(Athena_test::floatNEQ(LHS, RHS)); +#define FLOAT_EQassert( LHS, RHS ) assert(Athena_test::floatEQ(LHS, RHS)); + +#endif diff --git a/EDM/athena/AtlasTest/TestTools/TestTools/SGassert.h b/EDM/athena/AtlasTest/TestTools/TestTools/SGassert.h new file mode 100644 index 00000000..5479045f --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/TestTools/SGassert.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + macro to assert an error condition + ---------------------------------- + ATLAS Collaboration + ***************************************************************************/ + +// $Id: SGassert.h,v 1.2 2005-11-29 00:51:33 calaf Exp $ + + +#ifndef TEST_SGASSERT_H +# define TEST_SGASSERT_H + +#include <cassert> +#include <iostream> + +#undef NDEBUG + +#define SGASSERT( TRUEEXPR ) assert(TRUEEXPR) +#define SGASSERTERROR( FALSEEXPR ) \ + std::cerr << "Now we expect to see an error message:" << std::endl \ + << "----Error Message Starts--->>" << std::endl; \ + assert(!(FALSEEXPR)); \ + std::cerr<< "<<---Error Message Ends-------" << std::endl + + +#endif // TEST_SGASSERT_H diff --git a/EDM/athena/AtlasTest/TestTools/TestTools/expect_exception.h b/EDM/athena/AtlasTest/TestTools/TestTools/expect_exception.h new file mode 100644 index 00000000..afdcc680 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/TestTools/expect_exception.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file TestTools/expect_exception.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2014 + * @brief Helper to check that an exception is thrown. + */ + + +#ifndef TESTTOOLS_EXPECT_EXCEPTION_H +#define TESTTOOLS_EXPECT_EXCEPTION_H + + +#include <cassert> + + +/** + * @brief Helper to check that an exception is thrown. + * + * Use like this: + * + *@code + * EXPECT_EXCEPTION (std::runtime_error, doSomething()); + @endcode + * + * This will produce an exception failure if @c doSomething() + * does _not_ throw a @c std::runtime_error exception. + */ +#define EXPECT_EXCEPTION(EXC, CODE) do { \ + bool caught = false; \ + try { \ + CODE; \ + } \ + catch (const EXC&) { \ + caught = true; \ + } \ + assert (caught); \ +} while(0) + + +#endif // not TESTTOOLS_EXPECT_EXCEPTION_H diff --git a/EDM/athena/AtlasTest/TestTools/TestTools/initGaudi.h b/EDM/athena/AtlasTest/TestTools/TestTools/initGaudi.h new file mode 100644 index 00000000..93b8c3b0 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/TestTools/initGaudi.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TEST_INITGAUDI_H +# define TEST_INITGAUDI_H +/** @file initGaudi.h + * @brief minimal gaudi initialization for AthenaServices unit testing + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> -ATLAS Collaboration + * $Id: initGaudi.h,v 1.4 2005-11-29 00:51:33 calaf Exp $ + **/ + +#include <string> + +#undef NDEBUG + +class ISvcLocator; + + +namespace Athena_test { + /** @fn bool initGaudi(ISvcLocator*& pSvcLoc) + * @brief minimal gaudi initialization for AthenaServices unit testing + * @param pSvcLoc returns a pointer to the Gaudi ServiceLocator + */ + bool initGaudi(ISvcLocator*& pSvcLoc); + /** @fn initGaudi(const std::string& jobOptsFile, ISvcLocator*& pSvcLoc); + * @brief minimal gaudi initialization for AthenaServices unit testing + * @param jobOptsFile job opts file name (located at ../share/jobOptFiles) + * @param pSvcLoc returns a pointer to the Gaudi ServiceLocator + */ + bool initGaudi(const std::string& jobOptsFile, ISvcLocator*& pSvcLoc); +} +#endif // TEST_INITGAUDI_H diff --git a/EDM/athena/AtlasTest/TestTools/TestTools/random.h b/EDM/athena/AtlasTest/TestTools/TestTools/random.h new file mode 100644 index 00000000..4b44f9f3 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/TestTools/random.h @@ -0,0 +1,89 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file TestTools/random.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2014 + * @brief Very simple random numbers for regression testing. + * + * This file provides a few very simple random number generators + * useful for regression testing. These are 32-bit LCGs, with constants + * taken from Numerical Recipes. These numbers will have poor quality; + * however, the results should be completely reproducible across platforms. + * For regression testing, that's often all that's really needed. + */ + + +#ifndef TESTTOOLS_RANDOM_H +#define TESTTOOLS_RANDOM_H + + +#include <stdint.h> + + +namespace Athena_test { + + +/// Maximum number generated. +static uint32_t rngmax = static_cast<uint32_t> (-1); + + +/// Generate a random number between 0 and @c rngmax +uint32_t rng_seed (uint32_t& seed) +{ + seed = (1664525*seed + 1013904223); + return seed; +} + + +/// Generate a floating-point random number between @c rmin and @c rmax. +float randf_seed (uint32_t& seed, float rmax, float rmin = 0) +{ + return static_cast<float>(rng_seed(seed)) / rngmax * (rmax-rmin) + rmin; +} + + +/// Generate an integer random number between @c rmin and @c rmax. +int randi_seed (uint32_t& seed, int rmax, int rmin = 0) +{ + return static_cast<int> (randf_seed (seed, rmax, rmin)); +} + + +/// Generator compatible with the STL RandomNumberGenerator. +struct RNG +{ + RNG() : seed(1) {} + int operator() (int n) const { return randi_seed (seed, n); } + mutable uint32_t seed; +}; + + +/// Generator compatible with the C++11 STL UniformRandomNumberGenerator. +struct URNG +{ + typedef uint32_t result_type; + URNG() : seed(1) {} + static result_type min() { return 0; } + static result_type max() { return 1000000; } + result_type operator()() const { return randi_seed (seed, max()); } + mutable uint32_t seed; +}; + + +uint32_t seed = 1; +uint32_t rng() { return rng_seed(seed); } +int randi (int rmax, int rmin = 0) { return randi_seed (seed, rmax, rmin); } +float randf (float rmax, float rmin = 0) { return randf_seed (seed, rmax, rmin); } + + + +} // namespace Athena_test + + +#endif // not TESTTOOLS_RANDOM_H diff --git a/EDM/athena/AtlasTest/TestTools/cmt/Makefile.RootCore b/EDM/athena/AtlasTest/TestTools/cmt/Makefile.RootCore new file mode 100644 index 00000000..d59368a1 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/cmt/Makefile.RootCore @@ -0,0 +1,24 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = TestTools +PACKAGE_PRELOAD = +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = +PACKAGE_TRYDEP = +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 0 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 1 +PACKAGE_REFLEX = 0 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/EDM/athena/AtlasTest/TestTools/cmt/requirements b/EDM/athena/AtlasTest/TestTools/cmt/requirements new file mode 100644 index 00000000..c785e43b --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/cmt/requirements @@ -0,0 +1,45 @@ +package TestTools +author Paolo Calafiura <Paolo.Calafiura@cern.ch> +author Sebastien Binet <binet@cern.ch> + +use AtlasPolicy AtlasPolicy-* +use AtlasPython AtlasPython-* External -no_auto_imports + +use AthenaCommon AthenaCommon-* Control -no_auto_imports + +use TestPolicy TestPolicy-* + +private +use GaudiInterface GaudiInterface-* External +branches python share src TestTools test +end_private + +library TestTools *.cxx +apply_pattern installed_library + +apply_pattern declare_scripts files="runUnitTests.sh post.sh" +apply_pattern declare_python_modules files="*.py" +apply_pattern declare_joboptions files="*.py" + +macro whichGroup check +#macro whichGroup "NONE" \ +# debug "check" + +pattern UnitTest_run \ + application <unit_test>_test -group=$(whichGroup) ../test/<unit_test>_test.cxx <extra_sources> ; \ + document athenarun_launcher <unit_test>_utest -group=$(whichGroup) \ + athenarun_exe="'../${CMTCONFIG}/<unit_test>_test.exe'" \ + athenarun_pre="'. ../cmt/setup.sh'" \ + athenarun_opt="" \ + athenarun_out="' > <unit_test>_test.log 2>&1'" \ + athenarun_post="'post.sh <unit_test>_test $(q)<extrapatterns>$(q)'" ; \ + private ; \ + macro_append <unit_test>_utest_dependencies " <unit_test>_test " ; \ + end_private + +private + +macro_append DOXYGEN_INPUT " ../doc" +macro_append DOXYGEN_INPUT " ../share" +macro_append DOXYGEN_FILE_PATTERNS " *.sh" +macro_append DOXYGEN_FILE_PATTERNS " *.txt" diff --git a/EDM/athena/AtlasTest/TestTools/doc/MainPage.h b/EDM/athena/AtlasTest/TestTools/doc/MainPage.h new file mode 100644 index 00000000..df825d76 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/doc/MainPage.h @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + + \mainpage + +This package contains a few tools to help writing unit tests. + +\section UnitTest_run The UnitTest_run cmt pattern + +TestTools requirements file defines the cmt pattern UnitTest_run. UnitTest_run +will compile, link and run a standalone C++ program when a "gmake check" +command is issued. It will then run the share/post.sh script to compare the +program output with a reference one, if available. + The pattern takes one parameter <unit_test> which is used to identify a number of files: + -# $PKGROOT/test/<unit_test>_test.cxx C++ program to be run + -# $PKGROOT/share/<unit_test>_test.ref optional reference output + -# $PKGROOT/run/<unit_test>_test.log program output (stdout & stderr) + -# $PKGROOT/$CMTCONFIG/<unit_test>_test.exe executable + +So for example +<PRE> + apply_pattern UnitTest_run unit_test=DataPool +will compile and link + ../test/DataPool_test.cxx +into + ../$CMTCONFIG/DataPool_test.exe +which will be run and produce + ../run/DataPool_test.log +If you have created the reference output + ../share/DataPool_test.ref +this will be compared to the log file at the end of the job. +</PRE> + +Notice that the comparison tries to ignore a certain +number of differences that are usually harmless (e.g. the execution time +reported by ChronoStatSvc or the package versions and even in certain cases +pointer addresses). This is currently done in a very naive fashion (using +diff -I option) but a more sophisticated "diff" script is in the plans + +\section initGaudi The initGaudi functions +TestTools/initGaudi.h defines two functions in the namespace Athena_test +to initialize Gaudi ApplicationMgr +and be able to run using core Gaudi services. An optional string argument +<jobOptsFile> instructs initGaudi to read in the job options file + $PKGROOT/share/<jobOptsFile> +to configure your job + +\section scripts Scripts + - share/runUnitTests.sh is a sh script that cmt broadcasts gmake check + and filter its output. It is +installed in the run area. It accepts one or more arguments that it passes +to cmt broadcast, for example +<PRE> + ../run/%runUnitTests.sh -select=StoreGate +</PRE> + - share/post.sh is a script used by the UnitTest_run pattern to +analize a job output + +\section toys Toys + +The TestTools component library provides toy implementations of a number of +typical Gaudi classes, namely ToyConverter, ToyConversionSvc (and soon +ToyAlgorithm). These are made available via the job opts file + $TESTTOOLSROOT/share/ToyConversionOpts.txt + + + +\section Examples Examples + +The package AthenaTests/ControlTests contains several examples that use +the initGaudi function. +Control/StoreGate has a couple of non-Gaudi-based, +very simple unit tests (e.g. KeyConcept) as well as more sophisticated ones +that show + - how to link the test program with an extra library (e.g. Clear_Store) + - how to use the ToyConversionSvc provided by TestTools (ProxyProviderSvc) + +\section links More info +The package can be browsed using LXR +(http://atlassw1.phy.bnl.gov/lxr/source/atlas/AtlasTest/TestTools/) + +To generate doxygen doc, run (from the cmt dir) gmake doxygen and point +your browser to .../doc/Doxygen/html/index.html + +\author Paolo Calafiura <Paolo.Calafiura@cern.ch> +*/ diff --git a/EDM/athena/AtlasTest/TestTools/python/__init__.py b/EDM/athena/AtlasTest/TestTools/python/__init__.py new file mode 100644 index 00000000..a40f3f01 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# hook for the TestTools python module diff --git a/EDM/athena/AtlasTest/TestTools/python/iobench.py b/EDM/athena/AtlasTest/TestTools/python/iobench.py new file mode 100644 index 00000000..f248f3bb --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/python/iobench.py @@ -0,0 +1,477 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# @file : iobench.py +# @author: Sebastien Binet <binet@cern.ch> +# @purpose: Measure the I/O performances of an application +# +# @date: July 2006 +# + +""" +A set of python objects to measure the I/O performances of an application. +""" + +__author__ = "$Author: binet $" +__version__ = "$Revision: 1.4 $" + +import sys +import resource +import time +import os + +###----------------------------------------------------- +def getResources( usageMode = resource.RUSAGE_CHILDREN ): + """ + A factory method to fetch the used resources at a given 't' time. + Default mode is 'resource.RUSAGE_CHILDREN' + """ + return Resource( utime = resource.getrusage( usageMode ).ru_utime, + stime = resource.getrusage( usageMode ).ru_stime, + rtime = time.time() ) + +class Resource(object): + """ + A simple class to hold the resources used by a program: + - user time + - system time + - real time + """ + + def __init__( self, + utime, stime, rtime ): + object.__init__(self) + + self.utime = utime + self.stime = stime + self.rtime = rtime + + return + + def __repr__(self): + s = os.linesep.join( [ "user : %s" % str( self.user() ), + "sys : %s" % str( self.sys() ), + "real : %s" % str( self.real() ) ] ) + return s + + def __add__(self, rhs): + return Resource( self.utime + rhs.utime, + self.stime + rhs.stime, + self.rtime + rhs.rtime ) + + def __iadd__(self, rhs): + self.utime += rhs.utime + self.stime += rhs.stime + self.rtime += rhs.rtime + return self + + def __sub__(self, rhs): + return Resource( self.utime - rhs.utime, + self.stime - rhs.stime, + self.rtime - rhs.rtime ) + + def __isub__(self, rhs): + self.utime -= rhs.utime + self.stime -= rhs.stime + self.rtime -= rhs.rtime + return self + + def user( self ): + return self.utime + + def sys( self ): + return self.stime + + def real( self ): + return self.rtime + + pass # Resource + +class Bench(object): + + def __init__( self, + nTimes = 1, + stdout = sys.stdout, + stderr = sys.stderr ): + object.__init__(self) + + self.nTimes = nTimes + self.data = [] + + def run( self, fct, *args, **kwargs ): + + self.data = [] + + for i in range(self.nTimes): + iStart = getResources() + out = fct( *args, **kwargs ) + self.data.append( getResources() - iStart ) + pass + + return + + def stats( self ): + + mean = Resource( 0., 0., 0. ) + for d in self.data: + mean += d + pass + + print "" + print "## stats : (nbenchs = %i)" % self.nTimes + print " time<User> = %8.3f s" % ( mean.user() / float( self.nTimes ) ) + print " time<Sys > = %8.3f s" % ( mean.sys() / float( self.nTimes ) ) + print " time<Real> = %8.3f s" % ( mean.real() / float( self.nTimes ) ) + + return + + def save( self, fileName = "iobench.log" ): + f = open( fileName, "w" ) + for data in self.data: + f.writelines( "%s %s %s %s" % ( data.user(), + data.sys(), + data.real(), + os.linesep ) ) + pass + f.close() + return + + pass # Bench + +## +## ---- Athena specific part ---- +## + +import os +import ConfigParser +class ChronoStatsOutputParser( ConfigParser.ConfigParser ): + """Subclass and specialize ConfigParser to make it case-sensitive + """ + def optionxform( self, optionStr ): + return optionStr + +class ChronoStat(object): + """ + A class mirroring the one from the (Gaudi) ChronoStatSvc which models a + chrono measurement. + It holds the following informations: + - total time + - min + - mean + - RMS + - max + - number of 'events' + """ + def __init__( self, nbr, min, max, mean, rms, total ): + object.__init__(self) + self.total = total + self.min = min + self.mean = mean + self.rms = rms + self.max = max + self.nbr = nbr + pass + + def __repr__(self): + return os.linesep.join( [ + "min = %s" % str( self.min ), + "max = %s" % str( self.max ), + "mean = %s" % str( self.mean ), + "RMS = %s" % str( self.RMS ), + "total = %s" % str( self.total ), + "#evts = %s" % str( self.nbr ), + ] ) + +class ChronoStatReport(object): + + ReadKeyHdr = "cObj_" + WriteKeyHdr = "cRep_" + KeySep = "#" + + """ + This class stores the report of the ChronoStatSvc dump from Athena/Gaudi. + """ + def __init__( self, fileName ): + """ + fileName is supposed to contain the output of the ChronoStatSvc which + has been configured with 'ChronoStatSvc.ChronoDestinationCout = True' + """ + object.__init__( self ) + + self.logFile = ChronoStatsOutputParser() + self.logFile.read( fileName ) + + self.stats = { } + self.chronoStats = { } + self.buildStats() + pass + + def buildStats( self ): + + for hdr in self.logFile.sections(): + stat = [ + ChronoStat( + nbr = int (self.logFile.get(hdr, "cpu_%s_nbr" % item)), + min = float(self.logFile.get(hdr, "cpu_%s_min" % item)), + max = float(self.logFile.get(hdr, "cpu_%s_max" % item)), + mean = float(self.logFile.get(hdr, "cpu_%s_mean" % item)), + rms = float(self.logFile.get(hdr, "cpu_%s_RMS" % item)), + total= float(self.logFile.get(hdr, "cpu_%s_total" % item)) + ) \ + for item in ['user', 'system', 'real'] + ] + + self.chronoStats[hdr] = { + 'user' : stat[0], + 'system' : stat[1], + 'real' : stat[2], + } + del stat + self.stats[hdr] = Resource( + float(self.logFile.get(hdr, "cpu_user_mean")), + float(self.logFile.get(hdr, "cpu_system_mean")), + float(self.logFile.get(hdr, "cpu_real_mean")) + ) + pass + + def getStats(self, key): + return self.stats[key] + + def getPoolStats(self, storeGateKey, ioMode = "r" ): + ioKey = storeGateKey + # 'normalize' key + if ioMode.lower() == "r": + ioKey = storeGateKey.replace(ChronoStatReport.ReadKeyHdr,"") + ioKey = ChronoStatReport.ReadKeyHdr + ioKey + elif ioMode.lower() == "w": + ioKey = storeGateKey.replace(ChronoStatReport.WriteKeyHdr,"") + ioKey = ChronoStatReport.WriteKeyHdr + ioKey + else: + pass + + if not self.stats.has_key( ioKey ): + print "Warning: no such key [%s] in stats !" % ioKey + print "Available keys:",self.stats.keys() + pass + return self.stats[ ioKey ] + + def getPoolKeys(self): + return [ k for k in self.stats.keys() \ + if k.count(ChronoStatReport.WriteKeyHdr) > 0 ] + + pass # ChronoStatReport + + +###----------------------------------------------------- +## For compatibility with ATN tests +def workDir( fileName ): + """Function to provide an automatic work dir, compatible with ATN tests + """ + if os.environ.has_key('ATN_WORK_AREA'): + workArea = os.environ['ATN_WORK_AREA'] + else: + workArea = "/tmp" + pass + if not os.path.exists(workArea): + os.makedirs(workArea) + return os.path.join( workArea, fileName ) + +class ScOutput(object): + + def __init__(self, statusCode = 0, outputLog = ""): + object.__init__(self) + self.sc = statusCode + self.out = outputLog + return + + pass # ScOutput + +###----------------------------------------------------- +## Little helper to validate output of jobs +def doValidation( dbFiles, key ): + """Helper function to validate output of jobs against 'registered' ASCII + files. + """ + import commands + from TestTools.iobench import ScOutput + print "## Validation of ASCII files [%s]:" % key + print "## %15s : %s" % ( 'ref', dbFiles[key]['ref'] ) + print "## %15s : %s" % ( 'chk', dbFiles[key]['chk'] ) + sc,out = commands.getstatusoutput( "diff %s %s" % + ( dbFiles[key]['ref'], + dbFiles[key]['chk'] ) ) + if sc == 0 and len(out) == 0: + print "==> Validation [OK]" + else: + print "==> Validation [ERROR]" + pass + return ScOutput(sc,out) + +###----------------------------------------------------- +## Little helper to validate output of jobs +def doPostCheck( validationName, refFileName, chkFileName, chkFilter ): + import commands + print "## Validation of [%s]" % validationName + print "## ref: %s" % refFileName + print "## chk: %s" % chkFileName + print "## filter: [%s]" % chkFilter + sc, out = commands.getstatusoutput( "cat %s | %s | diff -u %s -" % \ + ( chkFileName, chkFilter, + refFileName ) ) + if sc == 0 and len(out) == 0: print "==> Validation [OK]" + else: print "==> Validation [ERROR]\n",\ + "*"*80,out,"*"*80 + return ScOutput(sc, out) + +###----------------------------------------------------- +from AthenaCommon import ChapPy +from tempfile import NamedTemporaryFile +class AthBench(object): + + def __init__( self, + athenaJob, + logFile, + nTimes = 1, + stdout = sys.stdout, + stderr = sys.stderr, + ioStatsLogFile = workDir("ioStats.out") ): + object.__init__(self) + + self.athena = athenaJob + self.logFileName = logFile + self.nTimes = nTimes + self.data = [] + self.chronoStats= [] + self.ioStatsFileName = ioStatsLogFile + + def run( self ): + + self.data = [] + self.chronoStats= [] + self.athena.jobOptions += [ + ChapPy.JobOptions( "TestTools/IoAuditor_fragment.py" ), + ChapPy.JobOptionsCmd( "svcMgr.ChronoStatSvc.AsciiStatsOutputFile = \"%s\"" % self.ioStatsFileName ) + ] + for i in range(self.nTimes): + self.athena.logFile = open( "%s.%s" % (self.logFileName,i), "w" ) + iStart = getResources() + out = self.athena.run() + self.data.append( getResources() - iStart ) + self.chronoStats.append( ChronoStatReport(self.ioStatsFileName) ) + pass + + return + + def __printStat(self, res, title="Overall", isIO = False, keyType = ""): + if isIO: + u = "us/evt" + else: + u = "s" + pass + if keyType == ChronoStatReport.WriteKeyHdr: keyType = "[WRITE]" + elif keyType == ChronoStatReport.ReadKeyHdr: keyType = "[READ]" + else: + pass + print "" + print "## stats : [%s] (nbenchs = %i) %s" % (title, + self.nTimes, + keyType) + print " time<User> = %12.3f %s" % (res.user() / float(self.nTimes), u) + print " time<Sys > = %12.3f %s" % (res.sys() / float(self.nTimes), u) + print " time<Real> = %12.3f %s" % (res.real() / float(self.nTimes), u) + + def ioStats(self, ioKeys = [], ioMode = "r"): + + if len(ioKeys) == 0: + ioKeys = self.chronoStats[0].getPoolKeys() + pass + keyHdr = "" + if ioMode.lower() == "r": + keyHdr = ChronoStatReport.ReadKeyHdr + elif ioMode.lower() == "w": + keyHdr = ChronoStatReport.WriteKeyHdr + for ioKey in ioKeys: + mean = Resource( 0., 0., 0. ) + for d in self.chronoStats: + mean += d.getPoolStats(ioKey, ioMode) + pass + self.__printStat(mean, + ioKey.replace(keyHdr,""), + isIO = True, + keyType = keyHdr) + pass + + return + + def stats( self, doIoStats = False ): + + ## IO stats + if doIoStats: + self.ioStats() + + ## Overall stats + mean = Resource( 0., 0., 0. ) + for d in self.data: + mean += d + pass + self.__printStat(mean) + return + + def save( self, fileName = "iobench.log" ): + f = open( fileName, "w" ) + for data in self.data: + f.writelines( "%s %s %s %s" % ( data.user(), + data.sys(), + data.real(), + os.linesep ) ) + pass + f.close() + return + + pass # AthBench + +class BenchSequence(object): + """ + Class which holds results of benchs (exit codes) and declares victory + when all the benchs returned successfully. + """ + + def __init__(self, name = "My Bench suite"): + object.__init__(self) + self.name = name + self.benchs = [] + + return + + def __iadd__(self, rhs): + if not isinstance( rhs, ScOutput ) and \ + not isinstance( rhs, list ): + raise Exception, \ + "attempt to add a '%s' to the BenchSuite !" % \ + type(rhs).__name__ + + if isinstance( rhs, ScOutput ): + self.benchs.append( rhs ) + return self + + if isinstance( rhs, list ): + for i in rhs: + self += i + pass + return self + + return self + + def status(self): + import math + sc = 0 + for i in self.benchs: + sc += math.fabs(i.sc) + pass + return sc == 0 + + def printStatus(self): + if self.status(): print "## [All tests SUCCESSFULLY completed]" + else: print "## [ERROR in at least one test !!]" + return + + pass # BenchSequence diff --git a/EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitSGServiceTestExample.sh b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitSGServiceTestExample.sh new file mode 100644 index 00000000..10aff1f8 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitSGServiceTestExample.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# MAILTO : undrus@bnl.gov +echo " ======================================================== " +echo " Starting CppUnitTestExample " +echo " ======================================================== " +if [ "$CMTSTRUCTURINGSTYLE" = "without_version_directory" ]; then +cd ${NIGHTLYAREA}/Atlas*Release/cmt +else +cd ${NIGHTLYAREA}/Atlas*Release/*/cmt +fi +cmt broadcast -select=CppUnitSGServiceExample make CppUnit +stat=$? +if [ "$stat" != "0" ]; then + echo " ------------------------------------------ " + echo " FAILURE : test CppUnitSGServiceTestExample " + echo " ------------------------------------------ " +fi + + diff --git a/EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitTestExample.sh b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitTestExample.sh new file mode 100644 index 00000000..bf9bd180 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/CppUnitTestExample.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# MAILTO : undrus@bnl.gov +echo " ======================================================== " +echo " Starting CppUnitTestExample " +echo " ======================================================== " +if [ "$CMTSTRUCTURINGSTYLE" = "without_version_directory" ]; then +cd ${NIGHTLYAREA}/Atlas*Release/cmt +else +cd ${NIGHTLYAREA}/Atlas*Release/*/cmt +fi +cmt broadcast -select=CppUnitExample make CppUnit +stat=$? +if [ "$stat" != "0" ]; then + echo " -------------------------------- " + echo " FAILURE : test CppUnitTestExample " + echo " -------------------------------- " +fi + + diff --git a/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld.sh b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld.sh new file mode 100644 index 00000000..a7cc1881 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# ERROR_MESSAGE :FAILURE (ERROR) +# SUCCESS_MESSAGE :FATAL A FATAL +# MAILTO : undrus@bnl.gov + +# ----------------------------------------------------------- +# Author: Alex Undrus +# ----------------------------------------------------------- + +echo " ======================================================== " +echo " Starting test with TestHelloWorld.py " +echo " ======================================================== " +athena.py AthExHelloWorld/HelloWorldOptions.py +stat=$? +if [ "$stat" != "0" ]; then + echo " -------------------------------- " + echo " FAILURE (ERROR) : test HelloWorld.py " + echo " -------------------------------- " +fi diff --git a/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_XML.xml b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_XML.xml new file mode 100644 index 00000000..4f3ae79c --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_XML.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<atn> + <TEST name="HelloWorld" type="athena" suite="Examples"> + <options_atn>AthExHelloWorld/HelloWorldOptions.py</options_atn> + <timelimit>2</timelimit> + <author> Atlas Developer </author> + <mailto> somebody@somewhere.ch </mailto> + <expectations> + <errorMessage>FAILURE (ERROR)</errorMessage> + <successMessage>FATAL A FATAL</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_script.xml b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_script.xml new file mode 100644 index 00000000..4c709f0c --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/scripts/nightlies/TestHelloWorld_script.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<atn> + <TEST name="HelloWorld" type="script" suite="Examples"> + <options_atn>AtlasTest/TestTools/scripts/nightlies/TestHelloWorld.sh</options_atn> + <timelimit>2</timelimit> + <author> Atlas Developer </author> + <mailto> somebody@somewhere.ch </mailto> + <expectations> + <errorMessage>FAILURE (ERROR)</errorMessage> + <successMessage>FATAL A FATAL</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/AtlasTest/TestTools/share/IoAuditor_fragment.py b/EDM/athena/AtlasTest/TestTools/share/IoAuditor_fragment.py new file mode 100644 index 00000000..7b369c3f --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/share/IoAuditor_fragment.py @@ -0,0 +1,19 @@ +# +# write out a summary of the time spent +# +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +theAuditorSvc = svcMgr.AuditorSvc +theAuditorSvc.Auditors += [ "ChronoAuditor"] + +svcMgr.ChronoStatSvc.ChronoDestinationCout = True + +svcMgr.ChronoStatSvc.PrintUserTime = True +svcMgr.ChronoStatSvc.PrintSystemTime = True +svcMgr.ChronoStatSvc.PrintEllapsedTime = True + +svcMgr.ChronoStatSvc.AsciiStatsOutputFile = "chronoStats.ascii" + +svcMgr.AthenaPoolCnvSvc.UseDetailChronoStat = True + +from AthenaCommon.AppMgr import theApp +theApp.AuditAlgorithms = True diff --git a/EDM/athena/AtlasTest/TestTools/share/post.sh b/EDM/athena/AtlasTest/TestTools/share/post.sh new file mode 100644 index 00000000..c8cd4531 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/share/post.sh @@ -0,0 +1,225 @@ +#!/bin/sh +#/** @file post.sh +# @brief sh script that check the return code of an executable and compares +# its output with a reference (if available). +# @param test_name +# +# @author Scott Snyder <snyder@fnal.gov> - ATLAS Collaboration. +# @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration. +# $Id: post.sh,v 1.23 2007-11-10 00:00:07 calaf Exp $ +# **/ +test=$1 +extrapatterns="$2" +#verbose="1" +if [ "$POST_SH_NOCOLOR" = "" ]; then + GREEN="[92;1m" + YELLOW="[93;1m" + RED="[97;101;1m" + RESET="[m" +else + GREEN="" + YELLOW="" + RED="" + RESET="" +fi + +if [ "$ATLAS_CTEST_PACKAGE" = "" ]; then + ATLAS_CTEST_PACKAGE="__NOPACKAGE__" +fi + +# consider these name pairs identical in the diff +read -d '' II <<EOF +s/^StoreGateSvc_Impl VERBOSE/StoreGateSvc VERBOSE/ +s/^StoreGateSvc_Impl DEBUG/StoreGateSvc DEBUG/ +s/StoreGateSvc_Impl/StoreGateSvc/ +s/SGImplSvc/StoreGateSvc/ +s/SG::DataProxyHolder::sgkey_t/sgkey_t/ +s!(ERROR|INFO|WARNING|FATAL) [^ ]*/!\\\\1 ../! +s/(\.cxx|\.cpp|\.h|\.icc|LINE):[0-9]+/\\\\1/ +s/.[[][?]1034h// +EOF + +# ignore diff annotations +PP='^---|^[[:digit:]]+[acd,][[:digit:]]+' + +# ignore hex addresses +PP="$PP"'|0x\w{4,}' + +# ignore package names e.g. Package-00-00-00 +PP="$PP"'|\w+-[[:digit:]]{2}-[[:digit:]]{2}-[[:digit:]]{2}' +# ignore trunk package names e.g. Package-r123456 +PP="$PP"'|\w+-r[[:digit:]]+' +# ignore cpu usage printouts +PP="$PP"'|ChronoStatSvc +INFO Time' +PP="$PP"'|Time left.+ Seconds' +PP="$PP"'|Timeleft.+ sec' +PP="$PP"'|INFO Time User' +# ignore clid db file name +PP="$PP"'|from CLIDDB file' +# ignore slug machine printout +PP="$PP"'| Machine: .* System and Processor Info' +PP="$PP"'| Jobname = .* Machine =' +# ignore slug pid printout +PP="$PP"'|Atlas Detector Simulation, Reconstruction and Analysis Running on' +PP="$PP"'|Program: Slug-Dice-Arecon .+ pid +[[:digit:]]+' +#ignore DllClassManager DEBUG messages +PP="$PP"'|DllClassManager DEBUG' +# ignore slug Library printout +PP="$PP"'|Library of +[[:digit:]]+ at +[[:digit:]]+' +PP="$PP"'|Library compiled on +[[:digit:]]' +# ignore ClassIDSvc "in memory db" printouts +PP="$PP"'|CLID: .* - type name:' +# ignore ClassIDSvc "already set" printouts +PP="$PP"'|ClassIDSvc .* setTypeNameForID: .* already set for' +# ignore ClassIDSvc finalize output +PP="$PP"'|ClassIDSvc .* finalize: wrote .*' +# ignore rcs version comments +PP="$PP"'|Id: .+ Exp \$' +# ignore plugin count +PP="$PP"'|PluginMgr +INFO loaded plugin info for' +# ignore HistorySvc registered count +PP="$PP"'|HistorySvc +INFO Registered' +# ignore clid registry entries count +PP="$PP"'|ClassIDSvc +INFO getRegistryEntries: read' +# ignore existsDir path WARNINGS +PP="$PP"'|DirSearchPath::existsDir: WARNING not a directory' +# ignore warnings about duplicate services/converters. +PP="$PP"'|Service factory for type [^ ]+ already declared' +PP="$PP"'|Converter for class:[^ ]+ already exists' +# Number of configurables read can vary from build to build. +PP="$PP"'|INFO Read module info for' +# ignore ApplicationMgr header. +PP="$PP"'|^ApplicationMgr *SUCCESS *$' +PP="$PP"'|^=+$' +PP="$PP"'|^ *Welcome to ApplicationMgr' +PP="$PP"'|^ *running on .* on ' +PP="$PP"'|//GP: ' +#ignore which malloc we are using +PP="$PP"'|^Preloading tcmalloc' +PP="$PP"'|^WARNING: TCMALLOCDIR not defined' +#Sebastien says not to worry about this... +PP="$PP"'|^Py:AthFile .*shutting down athfile-server' +PP="$PP"'|^HistogramPersis... INFO *.CnvServices.:' +PP="$PP"'|StatusCodeSvc INFO initialize' +PP="$PP"'|^ApplicationMgr +INFO Successfully loaded' +PP="$PP"'|^IncidentSvc +DEBUG Service base class' +PP="$PP"'|^ClassIDSvc +WARNING Could not resolve clid DB path notthere.db' +PP="$PP"'|^IncidentSvc DEBUG Adding .* listener '.*' with priority .*' +PP="$PP"'|MessageSvc not found, will use std::cerr' +PP="$PP"'|^AtRndmGenSvc INFO Initializing AtRndmGenSvc' +PP="$PP"'|^AtRanluxGenSvc2 INFO Initializing AtRanluxGenSvc2' +PP="$PP"'|^AtRanluxGenSvc INFO Initializing AtRanluxGenSvc' +#ignore personal .athenarc files +PP="$PP"'|including file \"\$HOME/.athenarc' +#ignore known gaudi python warning +PP="$PP"'|Bindings.py:660: DeprecationWarning' +#ignore the ignored +PP="$PP"'|Warning in <TEnvRec::ChangeValue>: duplicate entry <Root.ErrorIgnoreLevel=Print> for level 1; ignored' +PP="$PP"'|^JobOptionsSvc +INFO' +# Gaudi 31 +PP="$PP"'|PluginService::SetDebug|setting LC_ALL' +# Ignore root6 duplicate dictionary warnings +PP="$PP"'|^Warning in .* (header|class) .* is already in' +# Ignore GaudiHive timeline printouts +PP="$PP"'|^TimelineSvc +INFO' +# StoreGate v3 migration +PP="$PP"'|VERBOSE ServiceLocatorHelper::service: found service IncidentSvc' +PP="$PP"'|VERBOSE ServiceLocatorHelper::service: found service ProxyProviderSvc' +# Pathnames / versions / times / hosts +PP="$PP"'|^IOVDbSvc +INFO (Folder|Connection|Total payload)' +PP="$PP"'|^DBReplicaSvc +INFO Read replica configuration' +PP="$PP"'|^EventInfoMgtInit: Got release version' +PP="$PP"'|^Py:Athena +INFO using release' +PP="$PP"'|servers found for host' +PP="$PP"'|^(Sun|Mon|Tue|Wed|Thu|Fri|Sat) ' + +# Outputs dependent on whether or not a file catalog already exists. +PP="$PP"'|XMLFileCatalog|File is not in Catalog|Failed to open container to check POOL collection|Open DbSession|Access DbDomain|Access DbDatabase|^RootDatabase.open|Deaccess DbDatabase' + +PP="$PP"'|^Py:ConfigurableDb' +PP="$PP"'|^DBReplicaSvc +INFO' +PP="$PP"'|INFO ... COOL exception caught: The database does not exist|Create a new conditions database' +PP="$PP"'|^SetGeometryVersion.py obtained' +PP="$PP"'|^ConditionStore +INFO Start ConditionStore' +PP="$PP"'|^ConditionStore +INFO Stop ConditionStore' + +# Differences between Gaudi versions. +PP="$PP"'|DEBUG input handles:|DEBUG output handles:|DEBUG Data Deps for|DEBUG Property update for OutputLevel :|-ExtraInputs |-ExtraOutputs |-Cardinality |-IsClonable |-NeededResources |-Timeline ' + +# StoreGate INFO messages changed to VERBOSE +PP="$PP"'|^(StoreGateSvc|[^ ]+Store) +(INFO|VERBOSE) (Stop|stop|Start)' + + +if [ "$extrapatterns" != "" ]; then + PP="$PP""|$extrapatterns" +fi + +if [ -z "$testStatus" ] + then + echo "$YELLOW post.sh> Warning: athena exit status is not available $RESET" +else + # check exit status + joblog=${test}.log + if [ "$testStatus" = 0 ] + then + if [ "$verbose" != "" ]; then + echo "$GREEN post.sh> OK: ${test} exited normally. Output is in $joblog $RESET" + fi + reflog=../share/${test}.ref + + # If we can't find the reference file, maybe it's located outside + # the repo. With the switch to git, we have to fall back + # to handling the versioning manually. + # ATLAS_REFERENCE_TAG should be a string of the form PACKAGE/VERSION. + # We first look for it in DATAPATH. If we don't find it, + # we then look under ATLAS_REFERENCE_DATA, which falls back + # to an afs path if it's not found. + if [ \( ! -r $reflog \) -a "$ATLAS_REFERENCE_TAG" != "" ]; then + # Look for the file in DATAPATH. + # We have to look for the directory, not the file itself, + # since get_files is hardcoded not to look more than two + # levels down. + get_files -data -symlink $ATLAS_REFERENCE_TAG > /dev/null + reflog=`basename $ATLAS_REFERENCE_TAG`/${test}.ref + if [ ! -r $reflog ]; then + testdata=$ATLAS_REFERENCE_DATA + if [ "$testdata" = "" ]; then + testdata=/afs/cern.ch/atlas/maxidisk/d33/referencefiles + fi + reflog=$testdata/$ATLAS_REFERENCE_TAG/${test}.ref + fi + fi + + if [ -r $reflog ] + then + jobrep=${joblog}-rep + sed -r "$II" $joblog > $jobrep + refrep=`basename ${reflog}`-rep + sed -r "$II" $reflog > $refrep + jobdiff=${joblog}-todiff + refdiff=`basename ${reflog}`-todiff + egrep -a -v "$PP" < $jobrep > $jobdiff + egrep -a -v "$PP" < $refrep > $refdiff + diff -a -b -E -B -u $jobdiff $refdiff + diffStatus=$? + if [ $diffStatus != 0 ] ; then + echo "$RED post.sh> ERROR: $joblog and $reflog differ $RESET" + # Return with failure in this case: + exit 1 + else + if [ "$verbose" != "" ]; then + echo "$GREEN post.sh> OK: $joblog and $reflog identical $RESET" + fi + fi + else + tail $joblog + echo "$YELLOW post.sh> WARNING: reference output $reflog not available $RESET" + echo " post.sh> Please check ${PWD}/$joblog" + fi + else + tail $joblog + echo "$RED post.sh> ERROR: Athena exited abnormally! Exit code: $testStatus $RESET" + echo " post.sh> Please check ${PWD}/$joblog" + fi +fi +exit $testStatus diff --git a/EDM/athena/AtlasTest/TestTools/share/runUnitTests.sh b/EDM/athena/AtlasTest/TestTools/share/runUnitTests.sh new file mode 100644 index 00000000..acba3fbb --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/share/runUnitTests.sh @@ -0,0 +1,27 @@ +#!/bin/sh +#/** @file runUnitTests.sh +# @brief sh script that cmt broadcasts gmake check and filters out its output +# @param opts options to be passed to cmt (eg -select=Store) +# @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration. +# $Id: runUnitTests.sh,v 1.1 2003-04-04 01:31:24 calaf Exp $ +# **/ +#if [ "$#" = 0 ] +# then +# opts=- +#else + opts="$@" +#fi + +joblog=gmakecheck.log +cmt bro "$opts" gmake check 2>&1 | tee $joblog | egrep "(post.sh>|Now trying)" +tail -1 $joblog | grep -q "check ok" +rc=$? +if [ "$rc" = 0 ] + then + echo "OK: gmake check exited normally. Output is in $joblog" +else + tail $joblog + echo "ERROR: gmake check exited abnormally!" + + echo " Please check ${PWD}/$joblog" +fi diff --git a/EDM/athena/AtlasTest/TestTools/src/initGaudi.cxx b/EDM/athena/AtlasTest/TestTools/src/initGaudi.cxx new file mode 100644 index 00000000..67a622f1 --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/src/initGaudi.cxx @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + minimal gaudi initialization for AthenaServices unit testing + ------------------------------------------------------------ + ATLAS Collaboration + ***************************************************************************/ + +// $Id: initGaudi.cxx,v 1.5 2005-05-04 00:39:51 calaf Exp $ + +//<<<<<< INCLUDES >>>>>> + +#include "TestTools/initGaudi.h" + +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/IProperty.h" +#include "GaudiKernel/ISvcManager.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IAppMgrUI.h" +#include "GaudiKernel/SmartIF.h" +using std::cout; +using std::endl; +using std::string; + +namespace Athena_test { + bool initGaudi(ISvcLocator*& pSvcLoc) { + return initGaudi(string(), pSvcLoc); //wily hack + } + bool initGaudi(const std::string& jobOptsFile, ISvcLocator*& pSvcLoc) { + string jobOptsPath = jobOptsFile; + if (access (jobOptsPath.c_str(), R_OK) != 0) + jobOptsPath = "../share/"+jobOptsFile; + bool noJobOpts(jobOptsFile.empty()); + if (!noJobOpts) { + cout << "\n\nInitializing Gaudi ApplicationMgr using job opts " << jobOptsPath << endl; + } + + // Create an instance of an application manager + IInterface* iface = Gaudi::createApplicationMgr(); + if( 0 == iface ) { + cout << "Fatal error while creating the ApplicationMgr " << endl; + return false; + } + + SmartIF<ISvcManager> svcMgr(iface); + SmartIF<IAppMgrUI> appMgr(iface); + SmartIF<IProperty> propMgr(iface); + SmartIF<ISvcLocator> svcLoc(iface); + if(!svcLoc.isValid() || !appMgr.isValid() || !svcMgr.isValid() || !propMgr.isValid()) { + cout << "Fatal error while creating the AppMgr smart if " << endl; + return false; + } + + pSvcLoc = svcLoc.pRef(); + + (propMgr->setProperty( "EvtSel", "NONE" )).ignore(); + if (noJobOpts) { + (propMgr->setProperty( "JobOptionsType", "NONE" )).ignore(); + } else { + (propMgr->setProperty( "JobOptionsType", "FILE" )).ignore(); + (propMgr->setProperty( "JobOptionsPath", jobOptsPath )).ignore(); + } + + if ((appMgr->configure()).isSuccess() && + (appMgr->initialize()).isSuccess()) { + cout<<"ApplicationMgr Ready"<<endl; + return true; + } else { + cout << "Fatal error while initializing the AppMgr" << endl; + return false; + } + } +} + + diff --git a/EDM/athena/AtlasTest/TestTools/test/test_iobench.py b/EDM/athena/AtlasTest/TestTools/test/test_iobench.py new file mode 100644 index 00000000..3b23150c --- /dev/null +++ b/EDM/athena/AtlasTest/TestTools/test/test_iobench.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# @file: test_iobench.py +# @purpose: unit test file for the iobench module +# @author: Sebastien Binet <binet@cern.ch> +# @date: July 2006 + +import user +import sys +from TestTools import iobench +from AthenaCommon import ChapPy + +if __name__ == "__main__": + print "#"*80 + print "## testing iobench ..." + + jobOptions = [ + ChapPy.JobOptionsCmd( "OUTPUT=\"/tmp/slimmed.aod.pool\"" ), + ChapPy.JobOptions( "McParticleAlgs/test_WriteMcAod_jobOptions.py" ) + ] + athena = ChapPy.Athena( jobOptions = jobOptions, + checkLeak = True ) + athena.EvtMax = 100 + + bench = iobench.AthBench( athena, + nTimes = 10 ) + print "## bench:" + print bench.athena + bench.run() + + bench.ioStats( [ "GEN_AOD", "GEN_EVENT", "SpclMC" ], "w" ) + bench.save( "iobench-%ievts.log" % athena.EvtMax ) + bench.stats() + + print "" + print "## Bye." + print "#"*80 + + # a possible output... + """ + ## stats : [GEN_AOD] (nbenchs = 10) + time<User> = 1231.000 us/evt + time<Sys > = 2.000 us/evt + time<Real> = 1210.000 us/evt + + ## stats : [GEN_EVENT] (nbenchs = 10) + time<User> = 1553.000 us/evt + time<Sys > = 4.000 us/evt + time<Real> = 1577.000 us/evt + + ## stats : [SpclMC] (nbenchs = 10) + time<User> = 1457.000 us/evt + time<Sys > = 4.000 us/evt + time<Real> = 1560.000 us/evt + + ## stats : [Overall] (nbenchs = 10) + time<User> = 26.931 s + time<Sys > = 0.749 s + time<Real> = 41.064 s + """ diff --git a/EDM/athena/Build/AtlasBuildScripts/LCG_RELEASE_BASE.sh b/EDM/athena/Build/AtlasBuildScripts/LCG_RELEASE_BASE.sh new file mode 100644 index 00000000..9125180f --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/LCG_RELEASE_BASE.sh @@ -0,0 +1,24 @@ +# +# This helper script is meant to set up a valid value for the +# LCG_RELEASE_BASE environment variable for the builds. +# +# If the environment variable is already set when the script runs, its +# value is not modified. If it isn't set yet, then the script tries to +# check for the existence of a number of standard directories in which +# LCG releases usually reside. +# + +if [ -z "${LCG_RELEASE_BASE}" ]; then + + if [ -d /cvmfs/sft.cern.ch/lcg/releases ]; then + export LCG_RELEASE_BASE=/cvmfs/sft.cern.ch/lcg/releases + elif [ -d /afs/cern.ch/sw/lcg/releases ]; then + export LCG_RELEASE_BASE=/afs/cern.ch/sw/lcg/releases + elif [ -d /cvmfs/atlas.cern.ch/repo/sw/software/21.0/sw/lcg/releases ]; then + export LCG_RELEASE_BASE=/cvmfs/atlas.cern.ch/repo/sw/software/21.0/sw/lcg/releases + fi + echo "Set LCG_RELEASE_BASE = ${LCG_RELEASE_BASE}" + +else + echo "Leaving LCG_RELEASE_BASE = ${LCG_RELEASE_BASE}" +fi diff --git a/EDM/athena/Build/AtlasBuildScripts/README.md b/EDM/athena/Build/AtlasBuildScripts/README.md new file mode 100644 index 00000000..dd50ee54 --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/README.md @@ -0,0 +1,5 @@ +Build Scripts For ATLAS External Projects +========================================= + +This directory collects the helper scripts needed to build / set up everything +necessary to build the projects of this repository. diff --git a/EDM/athena/Build/AtlasBuildScripts/TDAQ_RELEASE_BASE.sh b/EDM/athena/Build/AtlasBuildScripts/TDAQ_RELEASE_BASE.sh new file mode 100644 index 00000000..297fa9e6 --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/TDAQ_RELEASE_BASE.sh @@ -0,0 +1,25 @@ +# +# This helper script is meant to set up a valid value for the +# TDAQ_RELEASE_BASE environment variable for the builds. +# +# If the environment variable is already set when the script runs, its +# value is not modified. If it isn't set yet, then the script tries to +# check for the existence of a number of standard directories in which +# TDAQ releases usually reside. +# + +if [ -z "${TDAQ_RELEASE_BASE}" ]; then + + if [ -d /cvmfs/atlas.cern.ch/repo/sw/tdaq ]; then + export TDAQ_RELEASE_BASE=/cvmfs/atlas.cern.ch/repo/sw/tdaq + elif [ -d /afs/cern.ch/atlas/project/tdaq/prod ]; then + export TDAQ_RELEASE_BASE=/afs/cern.ch/atlas/project/tdaq/prod + else + echo "Error: Cannot find TDAQ software installation" + return 1 + fi + echo "Set TDAQ_RELEASE_BASE = ${TDAQ_RELEASE_BASE}" + +else + echo "Leaving TDAQ_RELEASE_BASE = ${TDAQ_RELEASE_BASE}" +fi diff --git a/EDM/athena/Build/AtlasBuildScripts/build_Gaudi.sh b/EDM/athena/Build/AtlasBuildScripts/build_Gaudi.sh new file mode 100644 index 00000000..9b27a23f --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/build_Gaudi.sh @@ -0,0 +1,142 @@ +#!/bin/bash +# +# Script used for building Gaudi. +# + +# Don't stop on errors but count them +set +e +ERROR_COUNT=0 + +# consider a pipe failed if ANY of the commands fails +set -o pipefail + +# Function printing the usage information for the script +usage() { + echo "Usage: build_Gaudi.sh <-s source dir> <-b build dir> " \ + "<-i install dir> <-e externals dir> <-p externals project name> " \ + "<-f platform name> [-r RPM dir] [-t build type]" +} + +# Parse the command line arguments: +SOURCEDIR="" +BUILDDIR="" +INSTALLDIR="" +EXTDIR="" +EXTPROJECT="" +PLATFORM="" +RPMDIR="" +BUILDTYPE="Release" +while getopts ":s:b:i:e:p:f:r:t:h" opt; do + case $opt in + s) + SOURCEDIR=$OPTARG + ;; + b) + BUILDDIR=$OPTARG + ;; + i) + INSTALLDIR=$OPTARG + ;; + e) + EXTDIR=$OPTARG + ;; + p) + EXTPROJECT=$OPTARG + ;; + f) + PLATFORM=$OPTARG + ;; + r) + RPMDIR=$OPTARG + ;; + t) + BUILDTYPE=$OPTARG + ;; + h) + usage + exit 0 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +# Make sure that the required options were all specified: +if [ "$SOURCEDIR" = "" ] || [ "$BUILDDIR" = "" ] || [ "$INSTALLDIR" = "" ] \ + || [ "$EXTDIR" = "" ] || [ "$EXTPROJECT" = "" ] \ + || [ "$PLATFORM" = "" ]; then + echo "Not all required parameters received!" + usage + exit 1 +fi + +# Create the build directory if it doesn't exist, and move to it: +mkdir -p ${BUILDDIR} || ((ERROR_COUNT++)) +cd ${BUILDDIR} || ((ERROR_COUNT++)) + +# Set up the externals project: +source ${EXTDIR}/setup.sh || ((ERROR_COUNT++)) + +#FIXME: simplify error counting below while keeping '| tee ...' + +# Configure the build: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ +cmake -DCMAKE_BUILD_TYPE:STRING=${BUILDTYPE} -DCTEST_USE_LAUNCHERS:BOOL=TRUE \ + -DGAUDI_ATLAS:BOOL=TRUE -DGAUDI_ATLAS_BASE_PROJECT:STRING=${EXTPROJECT} \ + -DCMAKE_INSTALL_PREFIX:PATH=/InstallArea/${PLATFORM} \ + ${SOURCEDIR} || touch $error_stamp +} 2>&1 | tee cmake_config.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +# Build it: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ +make -k || touch $error_stamp +} 2>&1 | tee cmake_build.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + + +# Install it: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ +make -k install/fast DESTDIR=${INSTALLDIR} || touch $error_stamp +} 2>&1 | tee cmake_install.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +# If no RPM directory was specified, stop here: +if [ "$RPMDIR" = "" ]; then + exit ${ERROR_COUNT} +fi + +# Build the RPM for the project: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ +cpack || touch $error_stamp +} 2>&1 | tee cmake_cpack.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ +mkdir -p ${RPMDIR} && cp GAUDI*.rpm ${RPMDIR} || touch $error_stamp +} 2>&1 | tee cp_rpm.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +if [ $ERROR_COUNT -ne 0 ]; then + echo "Gaudi build script counted $ERROR_COUNT errors" +fi + +exit ${ERROR_COUNT} diff --git a/EDM/athena/Build/AtlasBuildScripts/build_atlasexternals.sh b/EDM/athena/Build/AtlasBuildScripts/build_atlasexternals.sh new file mode 100644 index 00000000..8b27441a --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/build_atlasexternals.sh @@ -0,0 +1,144 @@ +#!/bin/bash +# +# Example script used for building one of the projects from the atlasexternals +# repository. +# + +# Don't stop on errors but count them +set +e +ERROR_COUNT=0 + +# consider a pipe failed if ANY of the commands fails +set -o pipefail + +# Function printing the usage information for the script +usage() { + echo "Usage: build_atlasexternals.sh <-s source dir> <-b build dir> " \ + "<-i install dir> [-p project] [-r RPM dir] [-t build type] [-l LCG version number]" +} + +# Parse the command line arguments: +SOURCEDIR="" +BUILDDIR="" +INSTALLDIR="" +PROJECT="AthenaExternals" +RPMDIR="" +BUILDTYPE="Release" +PROJECTVERSION="" +LCGVERSION="88" +while getopts ":s:b:i:p:r:t:v:l:h" opt; do + case $opt in + s) + SOURCEDIR=$OPTARG + ;; + b) + BUILDDIR=$OPTARG + ;; + i) + INSTALLDIR=$OPTARG + ;; + p) + PROJECT=$OPTARG + ;; + r) + RPMDIR=$OPTARG + ;; + t) + BUILDTYPE=$OPTARG + ;; + v) + PROJECTVERSION=$OPTARG + ;; + l) + LCGVERSION=$OPTARG + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +# Make sure that the required options were all specified: +if [ "$SOURCEDIR" = "" ] || [ "$BUILDDIR" = "" ] || [ "$INSTALLDIR" = "" ]; then + echo "Not all required parameters received!" + usage + exit 1 +fi + +# Create the build directory if it doesn't exist, and move to it: +mkdir -p ${BUILDDIR} || ((ERROR_COUNT++)) +cd ${BUILDDIR} || ((ERROR_COUNT++)) + +# Extra settings for providing a project version for the build if necessary: +EXTRACONF= +if [ "$PROJECTVERSION" != "" ]; then + PNAME=$(echo ${PROJECT} | awk '{print toupper($0)}') + EXTRACONF=-D${PNAME}_PROJECT_VERSION:STRING=${PROJECTVERSION} +fi + +#FIXME: simplify error counting: + + +# Configure the build: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ + cmake -DCMAKE_BUILD_TYPE:STRING=${BUILDTYPE} -DCTEST_USE_LAUNCHERS:BOOL=TRUE \ + -DLCG_VERSION_NUMBER:STRING=${LCGVERSION} \ + ${EXTRACONF} \ + ${SOURCEDIR}/Projects/${PROJECT}/ || touch $error_stamp +} 2>&1 | tee cmake_config.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp #FIXME: w/o $error_stamp one can't pass the status outside { ... } | tee ... shell + +# Build it: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ + make -k || touch $error_stamp +} 2>&1 | tee cmake_build.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +# Install it: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ + make -k install/fast DESTDIR=${INSTALLDIR} || touch $error_stamp +} 2>&1 | tee cmake_install.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + + +# If no RPM directory was specified, stop here: +if [ "$RPMDIR" = "" ]; then + exit ${ERROR_COUNT} +fi + +# Build the RPM or other package for the project: +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ +cpack || touch $error_stamp +} 2>&1 | tee cmake_cpack.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +error_stamp=`mktemp .tmp.error.XXXXX` ; rm -f $error_stamp +{ + mkdir -p ${RPMDIR} && \ + FILES=`ls ${PROJECT}*.rpm ${PROJECT}*.tar.gz ${PROJECT}*.dmg 2>/dev/null ; true ;` && \ + test "X$FILES" != "X" && \ + cp ${FILES} ${RPMDIR} || touch $error_stamp +} 2>&1 | tee cp_rpm.log +test -f $error_stamp && ((ERROR_COUNT++)) +rm -f $error_stamp + +if [ $ERROR_COUNT -ne 0 ]; then + echo "AtlasExternals build script counted $ERROR_COUNT errors" +fi + +exit ${ERROR_COUNT} diff --git a/EDM/athena/Build/AtlasBuildScripts/checkout_Gaudi.sh b/EDM/athena/Build/AtlasBuildScripts/checkout_Gaudi.sh new file mode 100644 index 00000000..d15a62d7 --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/checkout_Gaudi.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# +# Script for automating the checkout of the Gaudi repository when +# building the whole software stack in a nightly/release. +# +# The script must receive the tag/branch that should be checked out of the +# Gaudi repository. And it can write the commit hash that the +# checkout ended up with, into another file. +# + +# Stop on errors: +set -e + +# Function printing the usage information for the script +usage() { + echo "Usage: checkout_Gaudi.sh [options]" + echo " Options:" + echo " -t branch/tag: Mandatory branch/tag/hash to check out" + echo " -s directory: Mandatory source directory to use" + echo " -e url: Optional source URL to use for the checkout" + echo + echo " This script will allow the environment variables" + echo " Gaudi_URL and Gaudi_REF to override" + echo " other values (even those on the command line)" + echo " If Gaudi_URL is set to 'current' then" + echo " no clone or checkout is done and the working copy" + echo " in the source directory is left untouched." +} + +_max_retry_=5 + +_retry_ () { + local cmd="$*" + local n=0 + while ! $cmd ; do + if test $n -eq $_max_retry_ ; then + echo "ERROR: $cmd FAILED $_max_retry_ times. EXIT(1)" >&2 + exit 1 + fi + echo "WARNING: $cmd FAILED, retry in 30 sec ... " + sleep 30s + n=`expr $n + 1` + done +} + +_max_retry_=5 + +_retry_ () { + local cmd="$*" + local n=0 + while ! $cmd ; do + if test $n -eq $_max_retry_ ; then + echo "ERROR: $cmd FAILED $_max_retry_ times. EXIT(1)" >&2 + exit 1 + fi + echo "WARNING: $cmd FAILED, retry in 30 sec ... " + sleep 30s + n=`expr $n + 1` + done +} + +# Parse the command line arguments: +TAGBRANCH="" +SOURCEDIR="" +GAUDIURL="https://gitlab.cern.ch/atlas/Gaudi.git" +while getopts ":t:o:s:e:h" opt; do + case $opt in + t) + TAGBRANCH=$OPTARG + ;; + s) + SOURCEDIR=$OPTARG + ;; + e) + GAUDIURL=$OPTARG + ;; + h) + usage + exit 0 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +if [ "$Gaudi_URL" != "" ]; then + GAUDIURL=$Gaudi_URL + echo "Gaudi URL overridden to $GAUDIURL from environment" + if [ "$Gaudi_URL" = "current" ]; then + echo "Leaving current checkout in place for build" + exit 0 + fi +fi + +if [ "$Gaudi_REF" != "" ]; then + TAGBRANCH=$Gaudi_REF + echo "Gaudi ref overridden to $TAGBRANCH from environment" +fi + +# The tag/branch and a source directory must have been specified: +if [ "$TAGBRANCH" = "" ] || [ "$SOURCEDIR" = "" ]; then + echo "Not all required arguments were provided!" + usage + exit 1 +fi + +# Tell the user what will happen: +echo "Checking out Gaudi tag/branch: $TAGBRANCH" +echo " from: $GAUDIURL" + +if [ ! -d "${SOURCEDIR}" ]; then + # Clone the repository: + _retry_ git clone ${GAUDIURL} ${SOURCEDIR} +else + echo "${SOURCEDIR} already exists -> assume previous checkout" +fi + +# Get the appropriate version of it: +cd ${SOURCEDIR} +_retry_ git fetch --prune origin +_retry_ git checkout -f ${TAGBRANCH} diff --git a/EDM/athena/Build/AtlasBuildScripts/checkout_atlasexternals.sh b/EDM/athena/Build/AtlasBuildScripts/checkout_atlasexternals.sh new file mode 100644 index 00000000..feaee788 --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/checkout_atlasexternals.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# +# Script for automating the checkout of the atlasexternals repository when +# building the whole software stack in a nightly/release. +# +# The script must receive the tag/branch that should be checked out of the +# atlasexternals repository. And it can write the commit hash that the +# checkout ended up with, into another file. +# + +# Stop on errors: +set -e + +# Function printing the usage information for the script +usage() { + echo "Usage: checkout_atlasexternals.sh [options]" + echo " Options:" + echo " -t branch/tag: Mandatory branch/tag/hash to check out" + echo " -s directory: Mandatory source directory to use" + echo " -e url: Optional source URL to use for the checkout" + echo + echo " This script will allow the environment variables" + echo " AtlasExternals_URL and AtlasExternals_REF to override" + echo " other values (even those on the command line)." + echo " If AtlasExternals_URL is set to 'current' then" + echo " no clone or checkout is done and the working copy" + echo " in the source directory is left untouched." +} + +_max_retry_=5 + +_retry_ () { + local cmd="$*" + local n=0 + while ! $cmd ; do + if test $n -eq $_max_retry_ ; then + echo "ERROR: $cmd FAILED $_max_retry_ times. EXIT(1)" >&2 + exit 1 + fi + echo "WARNING: $cmd FAILED, retry in 30 sec ... " + sleep 30s + n=`expr $n + 1` + done +} + +_max_retry_=5 + +_retry_ () { + local cmd="$*" + local n=0 + while ! $cmd ; do + if test $n -eq $_max_retry_ ; then + echo "ERROR: $cmd FAILED $_max_retry_ times. EXIT(1)" >&2 + exit 1 + fi + echo "WARNING: $cmd FAILED, retry in 30 sec ... " + sleep 30s + n=`expr $n + 1` + done +} + +# Parse the command line arguments: +TAGBRANCH="" +SOURCEDIR="" +EXTERNALSURL="https://gitlab.cern.ch/atlas/atlasexternals.git" +while getopts ":t:o:s:e:h" opt; do + case $opt in + t) + TAGBRANCH=$OPTARG + ;; + s) + SOURCEDIR=$OPTARG + ;; + e) + EXTERNALSURL=$OPTARG + ;; + h) + usage + exit 0 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +if [ "$AtlasExternals_URL" != "" ]; then + EXTERNALSURL=$AtlasExternals_URL + echo "Externals URL overridden to $EXTERNALSURL from environment" + if [ "$AtlasExternals_URL" = "current" ]; then + echo "Leaving current checkout in place for build" + exit 0 + fi +fi + +if [ "$AtlasExternals_REF" != "" ]; then + TAGBRANCH=$AtlasExternals_REF + echo "Externals ref overridden to $TAGBRANCH from environment" +fi + +# The tag/branch and a source directory must have been specified: +if [ "$TAGBRANCH" = "" ] || [ "$SOURCEDIR" = "" ]; then + echo "Not all required arguments were provided!" + usage + exit 1 +fi + +# Tell the user what will happen: +echo "Checking out atlasexternals tag/branch: $TAGBRANCH" +echo " from: $EXTERNALSURL" + +if [ ! -d "${SOURCEDIR}" ]; then + # Clone the repository: + _retry_ git clone ${EXTERNALSURL} ${SOURCEDIR} +else + echo "${SOURCEDIR} already exists -> assume previous checkout" +fi + +# Get the appropriate version of it: +cd ${SOURCEDIR} +_retry_ git fetch --prune origin +_retry_ git checkout -f ${TAGBRANCH} diff --git a/EDM/athena/Build/AtlasBuildScripts/copy_rpm_eos.sh b/EDM/athena/Build/AtlasBuildScripts/copy_rpm_eos.sh new file mode 100644 index 00000000..cef9c84b --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/copy_rpm_eos.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# +# Script to copy local nightly RPMs to EOS and run createrepo +# + +ERROR_COUNT=0 + +# Function printing the usage information for the script +usage() { + echo "Usage: copy_rpm_eos.sh <-b branch> <-a arch> <-d week_day> <-s source dir> " + echo "copy_rpm_eos.sh -b 22.0.X -a x86_64-slc6-gcc49-opt -s /build2/atnight/localbuilds/nightlies/22.0.X-GIT/build" + +} + +# Parse the command line arguments +BRANCH="" +ARCH="" +SOURCEDIR="" +WEEKDAY="" +DESTDIR="/eos/project/a/atlas-software-dist/www/RPMs/nightlies" + +while getopts ":b:a:s:d:" opt; do + case $opt in + b) + BRANCH=$OPTARG + ;; + a) + ARCH=$OPTARG + ;; + s) + SOURCEDIR=$OPTARG + ;; + d) + WEEKDAY=$OPTARG + ;; + + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done +# Make sure that the required options were all specified: +if [ "$BRANCH" = "" ] || [ "$ARCH" = "" ] || [ "$SOURCEDIR" = "" ] ; then + echo "Not all required parameters received!" + usage + exit 1 +fi + +if [ "$WEEKDAY" = "" ]; then + DDAY=rel_`date +%w` +else + DDAY=${WEEKDAY} +fi + +echo "=====================================================" +echo "=== STARTING RPMs copy to /eos at `date`" +echo "=====================================================" + + +DESTDIR=${DESTDIR}/${BRANCH}/${ARCH}/${DDAY} + +_retry_() { + local cmd="$*" dt=16 retr=0 + while ! $cmd ; do + if test $retr -ge 6 ; then + echo "ERROR: 6 retries of $cmd FAILED ... " >&2 + return 1 + fi + echo "WARNING: $cmd failed, waiting $dt sec ..." + sleep ${dt}s + dt=`expr $dt + $dt` + retr=`expr $retr + 1` + done + return 0 +} + +if [ ! -d ${DESTDIR} ] ; then + echo "mkdir -p ${DESTDIR}" + _retry_ mkdir -p ${DESTDIR} + if [ ! -d ${DESTDIR} ] ; then ((ERROR_COUNT++)) ; fi #avoid false positive eos error if the directory was actually created +fi + +echo "=====================================================" +echo "=== Create repodata on local machine" +echo "=====================================================" +echo "nicos_rpm::::::: createrepo --workers 8 --update ${SOURCEDIR} :::::::" `date` +createrepo --workers 8 --update ${SOURCEDIR} || ((ERROR_COUNT++)) + +arr_rpm=(`(shopt -s nocaseglob; ls ${SOURCEDIR}/*.rpm)`) +if [ "${#arr_rpm[@]}" -le 0 ]; then + echo "nicos_rpm: Warning: no rpm files are found in ${SOURCEDIR}" + ((ERROR_COUNT++)) + else + for ele in "${arr_rpm[@]}" + do + echo "Info: copying $ele to ${DESTDIR}" + _retry_ cp -a $ele ${DESTDIR} || ((ERROR_COUNT++)) + done +fi + +echo "=====================================================" +echo "=== Copy repodata to nightly eos location" +echo "=====================================================" +echo "Info: copying ${SOURCEDIR}/repodata to ${DESTDIR}" +_retry_ cp -a -rf ${SOURCEDIR}/repodata ${DESTDIR} || ((ERROR_COUNT++)) + +exit ${ERROR_COUNT} diff --git a/EDM/athena/Build/AtlasBuildScripts/tag_build.sh b/EDM/athena/Build/AtlasBuildScripts/tag_build.sh new file mode 100644 index 00000000..bf55462a --- /dev/null +++ b/EDM/athena/Build/AtlasBuildScripts/tag_build.sh @@ -0,0 +1,68 @@ +#! /bin/bash +# +# Copyright (C) 2017 CERN for the benefit of the ATLAS collaboration +# + +# Function printing the usage information for the script +usage() { + echo "Usage: tag_build.sh [-d date_stamp] [-u repository_url]" \ + " Tag a 'nightly' build based on the current branch and timestamp."\ + " This script should really only be used by NICOS to tag nightly builds."\ + " Private builds should not do this."\ + " 'date_stamp' defaults to $datestamp, repository_url to the ATLAS athena"\ + " repository in CERN GitLab (krb5 authenticated)" +} + +# Parse the command line arguments: +DATESTAMP="$datestamp" +REPOURL="https://:@gitlab.cern.ch:8443/atlas/athena.git" +while getopts ":d:u:h" opt; do + case $opt in + d) + DATESTAMP=$OPTARG + ;; + u) + REPOURL=$OPTARG + ;; + h) + usage + exit 0 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +# Check we got a datestamp and that it's a valid format +if [ "$DATESTAMP" = "" ]; then + echo "No date_stamp defined from NICOS or given as a parameter" + exit 1 +fi +echo $DATESTAMP | egrep "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{4}$" >& /dev/null +if [ $? != "0" ]; then + echo "Datestamp '$DATESTAMP' does not correspond to the ATLAS format YYYY-MM-DDTHHMM" + exit 1 +fi + +# Abort if any of the next commands fail +set -e + +# Use the source of this script to ensure that we cd to within the root of the +# local repository +ScriptSrcDir=$(dirname ${BASH_SOURCE[0]}) +cd $ScriptSrcDir/../.. + +# Get branch name, then tag and push +BRANCH=$(git symbolic-ref --short HEAD) +TAG="nightly/$BRANCH/$DATESTAMP" +echo "Creating tag $TAG" +git tag $TAG +git push $REPOURL $TAG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/Arena.h b/EDM/athena/Control/AthAllocators/AthAllocators/Arena.h new file mode 100644 index 00000000..f6738561 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/Arena.h @@ -0,0 +1,344 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/Arena.h + * @author scott snyder + * @date May 2007 + * @brief Collection of memory allocators with a common lifetime, + * plus subsystem summary. + * + * The Arena classes provide a framework for memory allocation. + * It supports the following general features: + * + * - Segregated storage. Objects of identical type are grouped together. + * Memory is allocated from the system in large blocks and carved + * up into the individual objects. This allows eliminating malloc + * overhead and it helps with reducing problems due to heap fragmentation. + * + * - Objects may be `cached': the object constructor is run only when + * the memory is first allocated. If it is freed and then reallocated + * by the application, the destructor/constructor calls may be eliminated. + * + * - Memory allocations of similar lifetimes may be grouped together + * in ``Arenas''. All memory in a given Arena may be freed at once. + * + * - We attempt to make individual object allocation and deallocation + * very fast. The code for the `common' case can be entirely inlined, + * and should compile to a handful of instructions. + * + * - We keep statistics about the amount of memory allocated + * per type per Arena. + * + * First, a bit of terminology; this also summarizes the major components + * of the library. This will be followed by more detailed descriptions. + * See also the individual class headers. + * + * - An @em element is an individual piece of memory that the application + * requests. + * + * - A @em block is a piece of memory allocated from the system + * It will usually be divided up into individual elements. + * + * - An @em Allocator is the fundamental memory allocator, managing + * storage for a single type of object. Memory allocated from the + * system associated with a single Allocator. The Allocator + * classes themselves do not depend on the types being allocated; + * however, functions operating on these objects, such as constructors + * and destructors, may be given to the Allocator to be called + * at an appropriate time. Multiple Allocator implementations + * may be available, implementing different strategies. + * + * - An @em Arena is a group of Allocators, which share a common lifetime. + * The memory allocated by all Allocators in an Arena may be freed + * in a single operation. + * + * - An @em ArenaHeader represents a group of Arenas. One Arena + * is considered the `current' Arena; it is the one from which + * memory allocations will be made. Arenas within the group + * may be made current in a stack-like manner. + * + * - A @em Handle is the interface the application uses to allocate memory. + * A Handle is templated on the type being allocated as well as on the + * underlying Allocator. When a Handle is constructed, it is associated + * with the Allocator associated with the Arena that is current at that time + * (a new Allocator is automatically created if required). Therefore, + * a Handle should not be passed between threads, and Handle objects + * should not exist across any point where the current store/Arena + * may be changed. + * Multiple Handle implementations may be available, implementing + * different strategies for initializing the elements. + * + * Here are some more details about these components. For full details, + * see the individual class headers. + * + * An @em Allocator is the fundamental allocator for a single type. + * Allocator instances generally request memory from the system + * in big blocks and then divide it up into individual elements. + * The memory allocated from the system is generally not returned + * to the system unless explicitly requested; elements not currently + * in use are kept in a pool for fast allocation. An Allocator + * class does not depend on the type being allocated. Instead, the + * necessary information is passed to the Allocator on creation + * in a parameters structure. This includes the element size, + * as well as three function pointers: + * + * - The constructor function is called when an element is first + * allocated from the system. + * - The destructor function is called just before an element's + * memory is released back to the system. + * - The clear function is called after the application frees + * an element. + * + * Any of these may be null, in which case the corresponding call is skipped. + * + * An Allocator has a name, which is used both to identify it in the + * Allocator registry when Allocators are created on demand and + * in memory statistics reports. + * An Allocator must support these operations: + * + * - @c allocate, to allocate a new element. + * - @c reset, to free all allocated elements. The memory will generally + * be retained by the Allocator to be reused again quickly. + * - @c erase, to free all allocated elements, and return all + * allocated memory to the system. + * - @c reserve, to adjust the amount of current unused memory which + * the Allocator keeps in its pool. If the amount of memory requested + * is greater than what is currently available, the new memory will + * usually be allocated in a single block. If the amount of memory + * requested is less than what is currently available, free blocks + * will be returned to the system, if possible. + * - @c name to return the Allocator's name, and @c stats to return + * the current statistics for the Allocator. + * + * There are some additional operations which an Allocator may optionally + * implement: + * + * - @c free, to free an individual element. + * - @c resetTo, to free all elements that were allocated after + * a given element, as well as the element itself. + * - An iterator, which iterates over all allocated blocks. + * + * Two @c Allocator implementations are currently available in the library: + * + * - @c ArenaPoolAllocator: Allocates elements in a stack-like manner. + * Implements the @c resetTo operation and an iterator, but does + * not implement @c free. + * + * - @c ArenaHeapAllocator: An Allocator that allows elements to be + * individually freed. Implements @c free, but not @c resetTo + * nor an iterator. This Allocator requires maintaining + * a pointer with each free element. By default, this pointer + * is kept outside the element, increasing the effective size + * per element. However, if part of the element may be overwritten + * while it is free, then the allocator may be configured + * to have this pointer overlap part of the element. + * + * @c Allocator objects are grouped into @c Arenas. Each @c Arena + * contains a vector of @c Allocator objects. Each distinct @c Allocator + * type is assigned an index into this vector; these indices are + * globally unique. An @c Arena is associated with a @c ArenaHeader, + * which maintains a notion of the `current' @c Arena; the @c ArenaHeader + * holds a reference to the @c Allocator vector of the current @c Arena. + * An @c Arena has a @c makeCurrent operation to nominate it as the + * current @c Arena for its @c ArenaHeader. A helper class @c Arena::Push + * is provided to change the current @c Arena in a stack-like manner. + * An @c Arena also has operations to @c reset or @c erase all of its + * @c Allocators, as well as for summing statistics over them all. + * An @c Arena also has a name, which is used in printing statistics reports. + * + * The object that the application uses to allocate memory is provided + * by the @c Handle classes. These are templated on the type being + * allocated as well as on the underlying @c Allocator class. + * A @c Handle is created by passing in the @c Arena (or @c ArenaHeader) + * with which it is created, as well as any optional creation + * parameters for the @c Allocator. The first time a given type + * is seen, it is assigned an index the the @c Arena @c Allocator + * vector. When a @c Handle is created, it will look up the proper + * @c Allocator instance in the current @c Arena, creating it if needed. + * The @c Handle will then forward operations to the underlying + * @c Allocator. The library provides two @c Handle implementations: + * + * - @c ArenaHandle: When this @c Handle is used, the element + * constructor/destructor are expected to be called every time + * an element is allocated/freed by the application. The @c allocate + * method returns a @c void*; it is expected that this will then + * be used in a placement new. The destructor will be called + * by the library when elements are freed. + * + * - @ ArenaCachingHandle: This @c Handle allows `caching' already-constructed + * objects, such that the constructor is run only when the element's + * memory is first allocated from the system, and the destructor + * is run only when the element's memory is released back to the system. + * The @c allocate method thus returns an already-initialized @c T*. + * An optional @c clear function may be called when the element + * is freed by the application. + * + * An example of the basic usage might be something like this. + * + *@code + * class Example { ... + * SG::Arena m_arena; + * SG::ArenaCachingHandle<MyObj, SG::ArenaPoolAllocator> m_handle; + * ...}; + * + * Example::Example() + * // Associates with the default ArenaHeader. + * : m_arena ("myarena") { ... + * ...} + * + * ret Example::execute() { ... + * SG::Arena::Push push (m_arena); + * SG::ArenaCachingHandle<MyObj, SG::ArenaPoolAllocator> handle; + * MyObj* obj = handle.allocate(); + * ...} + * + * ret Example::newEvent() { ... + * m_arena.reset(); + * ... } + @endcode + * + * See also the unit tests for the Handle classes. + */ + + +#ifndef ATLALLOCATORS_ARENA_H +#define ATLALLOCATORS_ARENA_H + + +#include "AthAllocators/ArenaBase.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cstdlib> +#include <string> +#include <string> +#include <ostream> + + +namespace SG { + + +/** + * @brief Collection of memory allocators with a common lifetime, + * + * See the file-level comments for a full description. + */ +class Arena + : public SG::ArenaBase +{ +public: + /** + * @brief Constructor. + * @param name The name of this @c Arena; to use in reports. + * @param header The header with which this @c Arena is associated. + * If defaulted, the global default @c ArenaHeader will be used. + */ + Arena (const std::string& name, ArenaHeader* header = 0); + + + /** + * @brief Destructor. + */ + ~Arena(); + + + /** + * @brief reset all contained allocators. All elements will be freed. + */ + void reset(); + + + /** + * @brief erase all contained allocators. All elements will be freed, + * and the memory returned to the system. + */ + void erase(); + + + /** + * @brief Generate a report of the memory in use by this @c Arena. + * @param os The stream to which to write the report. + */ + virtual void report (std::ostream& os) const; + + + /** + * @brief Return statistics summed over all allocators in this @c Arena. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return the @c ArenaHeader with which this @c Arena is associated. + */ + ArenaHeader* header() const; + + + /** + * @brief Return this @c Arena's name. + */ + virtual const std::string& name() const; + + + /** + * @brief Make this @c Arena the current one for its @c ArenaHeader. + * @returns The previously current allocator vector. + */ + ArenaHeader::ArenaAllocVec_t* makeCurrent(); + + + /** + * @brief Helper class for making @c Arena instances current + * in a stack-like manner. + */ + class Push + { + public: + + /** + * @brief Constructor. Make @c a current. + * @param a The @c Arena to make current. + */ + Push (Arena& a); + + + /** + * @brief Destructor. Undoes the effect of the constructor. + */ + ~Push(); + + + private: + /// The @c ArenaHeader for the stack we're managing. + ArenaHeader* m_header; + + /// The previously-current allocator vector. + ArenaHeader::ArenaAllocVec_t* m_allocs; + }; + + +private: + /// The @c ArenaHeader with which we're associated. + ArenaHeader* m_header; + + /// Our allocator vector. + ArenaHeader::ArenaAllocVec_t m_allocs; + + /// Our summed statistics block. + mutable ArenaAllocatorBase::Stats m_stats; + + /// Our name. + std::string m_name; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENA_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h new file mode 100644 index 00000000..60d4c21a --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h @@ -0,0 +1,415 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaAllocatorBase.h + * @author scott snyder + * @date May 2007 + * @brief Common base class for arena allocator classes. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAALLOCATORBASE_H +#define ATLALLOCATORS_ARENAALLOCATORBASE_H + + +#include <cstdlib> +#include <new> +#include <string> +#include <iosfwd> +#include "boost/type_traits.hpp" + + +namespace SG { + + +/** + * @brief Common base class for arena allocator classes. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This base class provides the interfaces and common behavior for + * arena allocator classes. An allocator class is responsible for the + * actual allocation and deletion of objects. It is expected that + * unallocated objects may be maintained in a pool for efficiency. + * In addition, it should be possible to free at once all the objects + * that this allocator has allocated. See below for the details + * of the interface that classes deriving from this should implement. + * + * A matter of terminology. The objects that we allocate and free are + * called `elements'. As mentioned, it is expected that the memory will + * be allocated from the system for large groups of elements at any one + * time; these groups are called `blocks'. + * + * The allocator classes do not themselves depend on the type of the + * object being allocated. Instead, the necessary information is included + * in a parameters object of class @c Params that is passed to the allocator + * on construction. These parameters include: + * + * - @c name: The name of this allocator. This is used both in printed + * reports and to identify this allocator in the registry. + * - @c eltSize: The size in bytes of the individual elements + * we're allocating. + * - @c minSize: The minimum size that this Allocator allows for + * an element. + * - @c nblock: A hint for the number of elements to allocate in a single + * block. This is only a hint; the allocator may allocate + * a different number if that would be more efficient. + * - @c linkOffset: Some allocators may require keeping a pointer along + * with the element. This gives the offset (in bytes) + * from the start of the element where that pointer + * lives. In some cases, it may be safe to save space + * by allowing this pointer to overlap part of the element. + * Calling code is responsible for setting this up correctly. + * - @c constructor, @c destructor: It may be more efficient to call the + * element's constructor and destructor not each time the element + * is allocated and freed, but instead just when the element's + * block is allocated from or freed to the system. We thus + * cache a free pool of already-initialized objects. These + * parameters are to support this case. These are pointers + * to functions with the signature void (*)(char*). The + * @c constructor function is called when an element is first + * allocated from the system, and the @c destructor function + * is called when the element is finally released to the system. + * Either may be 0 to skip the call. + * - @c clear: In addition to the constructor and destructor, it may be + * necessary to reset the element state after the application + * releases it. If @c clear is not-null, this function will + * be called when an application frees an element. + * - @c canReclear: If true (the default), then it is safe to call @c clear + * more than once on a given element after it has been released. + * - @c mustClear: If true, then @c clear must be called before calling + * @c destructor. Otherwise (the default), @c destructor + * may be called directly without calling @c clear. + * + * The allocator class should maintain statistics for the memory it has + * allocated. These are grouped in the @c Stats structure. It should + * report the amount of space in use, the amount of free space (allocated + * from the system but not allocated by the application), and the total + * space allocated from the system, broken down into blocks, elements, + * and bytes. The derived allocator class may of course extend + * the provided statistics. + * + * The interface provided by derived allocator classes should consist + * of at least the following: + * + * - A constructor from a @c Params structure. + * + * - Implementations of the virtual methods @c reset, @c erase, @c reserve, + * @c name, @c stats. See documentation below. + * + * - An implementation of the method + *@code + * pointer allocate(); + @endcode + * This should be non-virtual, and may be inlined. It should return + * a pointer to an new element. If @c constructor was provided, + * then it should have been called on the element. + * + * - Optionally, an implementation of the non-virtual method + *@code + * void free (pointer); + @endcode + * to free a single element. @c clear will be called on the element + * if it was provided. + * + * - Optionally, an implementation of the non-virtual method + *@code + * void resetTo (pointer); + @endcode + * @c pointer should be a pointer to an element that was allocated + * from this allocator. That element and all elements that were + * allocated after it will be freed. + * + * - Optionally, @c iterator and @c const_iterator types and the + * corresponding const and non-const @c begin and @c end methods. + * These iterators should range over all allocated elements. + * The @c value_type should be @c pointer, and they should be at least + * forward iterators. + */ +class ArenaAllocatorBase +{ +public: + /// Type for pointers to elements. + typedef char* pointer; + + /// And a const version of the pointer. + typedef const char* const_pointer; + + /// Type of functions for @c constructor, etc. + typedef void func_t (pointer); + + + /** + * @brief Allocator parameters. See above for more details. + */ + struct Params + { + /// The name of this allocator. + std::string name; + + /// The size in bytes of the individual elements we're allocating. + size_t eltSize; + + /// The minimum size that this Allocator allows for an element. + size_t minSize; + + /// The number of elements we should allocate in a single block + /// (hint only). + size_t nblock; + + /// Offset from the start of a free element to a pointer to be used + /// by the allocator. Only used if the allocator requires it. + size_t linkOffset; + + /// Constructor function for elements. + + func_t* constructor; + /// Destructor function for elements. + func_t* destructor; + + /// Clear function for elements. + func_t* clear; + + /// If true, @c clear can be called more than once on a given element. + bool canReclear; + + /// If true, the @c clear call cannot be skipped before @c destructor. + bool mustClear; + }; + + + /** + * @brief Statistics for an allocator. See above for more details. + */ + struct Stats { + /// A single statistic. + struct Stat { + /// Default constructor. + Stat(); + /// Reset to zero. + void clear(); + /// Accumulate. + Stat& operator+= (const Stat& other); + + /// Number of items currently allocated by the application. + size_t inuse; + /// Number of items currently not allocated by the application + /// but cached by the allocator. + size_t free; + /// Total number of items held by the allocator. + size_t total; + }; + /// Reset to zero. + void clear(); + /// Accumulate. + Stats& operator+= (const Stats& other); + /// Print report header. + static void header (std::ostream& os); + + /// Counts of blocks. + Stat blocks; + /// Counts of elements. + Stat elts; + /// Counts of bytes. + Stat bytes; + }; + + + /** + * @brief Destructor. + */ + virtual ~ArenaAllocatorBase() {} + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + virtual void reset() = 0; + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase() = 0; + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + virtual void reserve (size_t size) = 0; + + + /** + * @brief Return the statistics block for this allocator. + */ + virtual const Stats& stats() const = 0; + + + /** + * @brief Return the name of this allocator. + */ + virtual const std::string& name() const = 0; + + + /** + * @brief Generate a report on the memory usage of this allocator. + * @param os Stream to which the report should be written. + */ + virtual void report (std::ostream& os) const; + + + //========================================================================= + /** + * @brief Helper to initialize a parameters structure. + * + * This creates a @c Params class appropriately initialized for class @c T. + * Assumptions made: + * - The constructor and destructor calls will be filled in + * if non-trivial, unless no_ctor or no_dtor is set to true. + * These two arguments are useful if the ctor/dtor are to + * be run elsewhere, or if they are trivial and can be skipped, + * but the compiler cannot detect that by itself. + * - The clear call will be filled in if the optional template parameter + * @c clear is true. + * - No space will be reserved for an extra link. + * - @c canReclear is @c true and @c mustClear is @c false. + * + * If these are not appropriate, you can derive from this class + * and make the appropriate changes. + */ + template <typename T, + bool clear = false, + bool no_ctor = false, + bool no_dtor = false> + struct initParams + { + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + initParams (size_t nblock = 1000, const std::string& name = ""); + + /// Return an initialized parameters structure. + Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator Params() const { return params(); } + + + private: + /// Saved value of the number of elements to allocate per block. + size_t m_nblock; + + /// Saved value of the allocator name. + std::string m_name; + }; + + + /// Make a constructor function pointer for a non-trivial constructor. + template <class T> + static func_t* makeConstructor (const boost::false_type&); + + /// Make a constructor function pointer for a trivial constructor. + template <class T> + static func_t* makeConstructor (const boost::true_type&); + + /// Make a constructor function pointer for a non-trivial destructor. + template <class T> + static func_t* makeDestructor (const boost::false_type&); + + /// Make a constructor function pointer for a trivial destructor. + template <class T> + static func_t* makeDestructor (const boost::true_type&); + + /// Make a function pointer for a @c clear function. + template <class T> + static func_t* makeClear (const boost::false_type&); + + /// Make a dummy @c clear function pointer. + template <class T> + static func_t* makeClear (const boost::true_type&); + +private: + /** + * @brief Call @c T's default constructor on the object at @c p. + * @param p The object on which to run the constructor. + */ + template <typename T> + static void construct_fcn (pointer p); + + + /** + * @brief Call @c T's destructor on the object at @c p. + * @param p The object on which to run the destructor. + */ + template <typename T> + static void destroy_fcn (pointer p); + + + /** + * @brief Call @c T::clear on the object at @c p. + * @param p The object on which to run the @c clear. + */ + template <typename T> + static void clear_fcn (pointer p); +}; + + +/** + * @brief Format a statistic structure. + * @param os The stream to which to write. + * @param stat The statistic structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats::Stat& stat); + + +/** + * @brief Format a complete statistics structure. + * @param os The stream to which to write. + * @param stats The statistics structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats& stats); + +} // namespace SG + + +#include "AthAllocators/ArenaAllocatorBase.icc" + + +#endif // not ATLALLOCATORS_ARENAALLOCATORBASE_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc new file mode 100644 index 00000000..260a0f05 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc @@ -0,0 +1,174 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaAllocatorBase.icc + * @author scott snyder + * @date May 2007 + * @brief Common base class for arena allocator classes. + * Inline/template implementations. + */ + + +namespace SG { + + +/** + * @brief Make a constructor function pointer for a non-trivial constructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeConstructor (const boost::false_type&) +{ + return &construct_fcn<T>; +} + + +/** + * @brief Make a constructor function pointer for a trivial constructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeConstructor (const boost::true_type&) +{ + return 0; +} + + +/** + * @brief Make a constructor function pointer for a non-trivial destructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeDestructor (const boost::false_type&) +{ + return &destroy_fcn<T>; +} + + +/** + * @brief Make a constructor function pointer for a trivial destructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeDestructor (const boost::true_type&) +{ + return 0; +} + + +/** + * @brief Make a function pointer for a @c clear function. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeClear (const boost::false_type&) +{ + return &clear_fcn<T>; +} + + +/** + * @brief Make a dummy @c clear function pointer. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeClear (const boost::true_type&) +{ + return 0; +} + + +/** + * @brief Call @c T's default constructor on the object at @c p. + * @param p The object on which to run the constructor. + */ +template <typename T> +void ArenaAllocatorBase::construct_fcn (pointer p) +{ + new(p) T; +} + + +/** + * @brief Call @c T's destructor on the object at @c p. + * @param p The object on which to run the destructor. + */ +template <typename T> +void ArenaAllocatorBase::destroy_fcn (pointer p) +{ + reinterpret_cast<T*>(p)->~T(); +} + + +/** + * @brief Call @c T::clear on the object at @c p. + * @param p The object on which to run the @c clear. + */ +template <typename T> +void ArenaAllocatorBase::clear_fcn (pointer p) +{ + reinterpret_cast<T*>(p)->clear(); +} + + +/** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor>::initParams + (size_t nblock /*=1000*/, + const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaAllocatorBase::Params +ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor>::params() const +{ + Params params; + + // Fill in the parameters that were passed to our constructor. + params.nblock = m_nblock; + params.name = m_name; + + // We're not setting up a link. + params.linkOffset = 0; + params.eltSize = sizeof (T); + params.minSize = 1; + + // Defaults for these. + params.canReclear = true; + params.mustClear = false; + + // Set up the constructor/destructor. + // We want the pointers to be null if they're trivial. + params.constructor = + makeConstructor<T> (::boost::integral_constant<bool, + ::boost::has_trivial_constructor<T>::value || + no_ctor>()); + params.destructor = + makeDestructor<T> (::boost::integral_constant<bool, + ::boost::has_trivial_destructor<T>::value || + no_dtor>()); + + // Set up the clear function --- only if the flag is set! + params.clear = makeClear<T> (::boost::integral_constant<bool, !clear>()); + + return params; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h new file mode 100644 index 00000000..789b770c --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h @@ -0,0 +1,52 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorCreator.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaAllocatorCreator.h + * @author scott snyder + * @date May 2007 + * @brief Provide an interface for creating an arena Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAALLOCATORCREATOR_H +#define ATLALLOCATORS_ARENAALLOCATORCREATOR_H + + +namespace SG { + + +class ArenaAllocatorBase; + + +/** + * @brief Provide an interface for creating an arena Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * Objects deriving from this will be stored in @c ArenaAllocatorRegistry, + * and are used to create allocator instances on demand. + */ +class ArenaAllocatorCreator +{ +public: + /// Destructor. + virtual ~ArenaAllocatorCreator() {} + + + /** + * @brief Create an allocator instance. + */ + virtual ArenaAllocatorBase* create() = 0; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENAALLOCATORCREATOR_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h new file mode 100644 index 00000000..1d74bd6a --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h @@ -0,0 +1,101 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorRegistry.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaAllocatorRegistry.h + * @author scott snyder + * @date May 2007 + * @brief Registry of allocator factories. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENAALLOCATORREGISTRY_H +#define ATLALLOCATORS_ARENAALLOCATORREGISTRY_H + + +#include <cstdlib> +#include <string> + + +namespace SG { + + +class ArenaAllocatorBase; +class ArenaAllocatorCreator; +class ArenaAllocatorRegistryImpl; + + +/** + * @brief Registry of allocator factories. + * See Arena.h for an overview of the arena-based memory allocators. + * + * Each Allocator type that the application uses is registered here; + * we assign to each one a small integer index. We can then create an instance + * of the Allocator given the index. Allocators have names; we also + * handle finding the index for an Allocator given the name. + */ +class ArenaAllocatorRegistry +{ +public: + /** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ + size_t registerCreator (const std::string& name, + ArenaAllocatorCreator* creator); + + + /** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ + size_t lookup (const std::string& name); + + + /** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ + ArenaAllocatorBase* create (size_t i); + + + /** + * @brief Return a pointer to the global @c ArenaAllocatorRegistry instance. + */ + static ArenaAllocatorRegistry* instance(); + + +private: + /// The implementation object. + ArenaAllocatorRegistryImpl* m_impl; + + // Disallow copying. + ArenaAllocatorRegistry (const ArenaAllocatorRegistry&); + ArenaAllocatorRegistry& operator= (const ArenaAllocatorRegistry&); + + /// Constructor. Called only by @c instance. + ArenaAllocatorRegistry(); + + /// Destructor. Called only by @c instance. + ~ArenaAllocatorRegistry(); + + // Just to avoid compiler warnings. + friend class ArenaAllocatorRegistryImpl; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENAALLOCATORREGISTRY_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBase.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBase.h new file mode 100644 index 00000000..85f0fef5 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBase.h @@ -0,0 +1,59 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaBase.h + * @author scott snyder + * @date May 2007 + * @brief Reporting interface for @c Arena, to avoid a dependency + * loop with @c ArenaHeader. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENABASE_H +#define ATLALLOCATORS_ARENABASE_H + + +#include <iosfwd> +#include <string> + + +namespace SG { + + +/** + * @brief Reporting interface for @c Arena, to avoid a dependency + * loop with @c ArenaHeader. + * See Arena.h for an overview of the arena-based memory allocators. + */ +class ArenaBase +{ +public: + /// Destructor. + virtual ~ArenaBase() {} + + + /** + * @brief Generate a report of the memory in use by this @c Arena. + * @param os The stream to which to write the report. + */ + virtual void report (std::ostream& os) const = 0; + + + /** + * @brief Return this @c Arena's name. + */ + virtual const std::string& name() const = 0; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENABASE_H + diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.h new file mode 100644 index 00000000..1cde0662 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.h @@ -0,0 +1,207 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaBlock.h + * @author scott snyder + * @date May 2007 + * @brief A large memory block that gets carved into smaller uniform elements. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENABLOCK_H +#define ATLALLOCATORS_ARENABLOCK_H + + +#include <cstdlib> + + +namespace SG { + + +class ArenaAllocatorBase; + + +/** + * @brief A large memory block that gets carved into smaller uniform elements. + * See Arena.h for an overview of the arena-based memory allocators. + * + * The block-based memory allocators allocate memory in large blocks + * and then carve them up into smaller, uniform elements. This class + * is used for those large blocks. Actually, the contents of this class + * is a fixed header for the block; the contents of the block itself + * will immediately follow the class contents. + * + * Each block keeps some housekeeping information: the element size in bytes, + * the number of elements in the block, and a pointer that can be used + * to chain blocks together in singly-linked lists. There are a few + * functions available to help manage such lists. + */ +class ArenaBlock +{ +public: + /// Type for a pointer to an element. + typedef char* pointer; + + /// Function that operates on an element. + typedef void func_t (pointer); + + + /** + * @brief Create a new block. + * @param n The number of elements in the new block. + * @param elt_size The size in bytes of each element. + * @param ctor If non-null, call this function on each element + * in the new block. + */ + static ArenaBlock* newBlock (size_t n, size_t elt_size, func_t* ctor); + + + /** + * @brief Destroy a block. + * @param p The block to destroy. + * @param dtor If non-null, call this function on each element in the block. + */ + static void destroy (ArenaBlock* p, func_t* dtor); + + + /** + * @brief Destroy all blocks in a list. + * @param p The first block to destroy. + * @param dtor If non-null, call this function on each element in the blocks. + * + * Will destroy all blocks in the linked list headed by @c p. + */ + static void destroyList (ArenaBlock* p, func_t* dtor); + + + /** + * @brief Concatenate two lists of blocks. + * @param headp Pointer to pointer to the head of the list. + * @param tail Pointer to list to append to the end. + * + * The list @c tail is appended to the end of the list @c *headp. + * (@c headp is a pointer-to-pointer to be able to handle the case + * of an empty list.) + */ + static void appendList (ArenaBlock** headp, ArenaBlock* tail); + + + /** + * @brief Call a function on elements in a list of blocks. + * @param p Pointer to the head of the list. + * @param func Function to apply. + * @param n Number of elements in the first block on which + * to call the function. + * + * This will loop through the elements in all blocks on the list, + * calling @c func. In the first block, we apply the function + * only to the first @c n elements. In subsequent blocks, the + * function is applied to all elements. + */ + static void applyList (ArenaBlock* p, func_t* func, size_t n); + + + /** + * @brief Return the number of elements in the block. + */ + size_t size() const; + + + /** + * @brief Return the size of the elements in the block. + */ + size_t eltSize() const; + + + /** + * @brief Return the link pointer of the block. + */ + ArenaBlock* & link(); + + + /** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + */ + pointer index (size_t i); + + + /** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + * @param elt_size The block's element size. + * + * This is provided in addition to the previous function as it may + * allow for better inlined code in when used in a loop, if @c elt_size + * is saved in a local. + */ + pointer index (size_t i, size_t elt_size); + + + /** + * @brief Return the per-block memory overhead, in bytes. + * + * This tries to include malloc overhead as well, but that may just + * be an estimate. Don't rely on this to be exact. + */ + static size_t overhead(); + + + /// Return the global number of blocks in use. + static size_t nactive(); + + +private: + /// Prohibit calling these. + ArenaBlock (size_t n, size_t elt_size); + ~ArenaBlock() {} + ArenaBlock (const ArenaBlock&); + ArenaBlock& operator= (const ArenaBlock&); + + // This is not really needed. It's just to squelch the g++ warning + // about classes with all private ctors/dtors and no friends. + friend class ArenaAllocatorBase; + + /// The link for the linked list. + ArenaBlock* m_link; + + /// Number of elements in this block. + size_t m_size; + + /// Size, in bytes, of each element in this block. + size_t m_elt_size; + + /// The start of the block body. + // Try to make sure it's maximally aligned. + // __attribute__ ((aligned)) will do that with gcc; on other compilers, + // try to get at least what a double requires. That's probably enough. + double m_dummy +#ifdef __GCC__ + __attribute__ ((aligned)) +#endif + ; + + + /// Global count of the number of blocks in use. + static size_t s_nactive; +}; + + +/// The offset from the start of the block to the first element. +static const int ArenaBlockBodyOffset = + sizeof (ArenaBlock) - sizeof (double); + + +} // namespace SG + + +#include "AthAllocators/ArenaBlock.icc" + + +#endif // not ATLALLOCATORS_ARENABLOCK_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.icc new file mode 100644 index 00000000..2719a126 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlock.icc @@ -0,0 +1,86 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaBlock.icc + * @author scott snyder + * @date May 2007 + * @brief These are large blocks of memory that get allocated and + * divided up into smaller, uniform elements. + * Inline/template implementations. + */ + +namespace SG { + + +/** + * @brief Return the number of elements in the block. + */ +inline +size_t ArenaBlock::size() const +{ + return m_size; +} + + +/** + * @brief Return the size of the elements in the block. + */ +inline +size_t ArenaBlock::eltSize() const +{ + return m_elt_size; +} + + +/** + * @brief Return the link pointer of the block. + */ +inline +ArenaBlock*& ArenaBlock::link() +{ + return m_link; +} + + +/** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + */ +inline +ArenaBlock::pointer ArenaBlock::index (size_t i) +{ + return reinterpret_cast<char*>(this) + + ArenaBlockBodyOffset + i*eltSize(); +} + + +/** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + * @param elt_size The block's element size. + * + * This is provided in addition to the previous function as it may + * allow for better inlined code in when used in a loop, if @c elt_size + * is saved in a local. + */ +inline +ArenaBlock::pointer ArenaBlock::index (size_t i, size_t elt_size) +{ + return reinterpret_cast<char*>(this) + ArenaBlockBodyOffset + i*elt_size; +} + + +/** + * @brief Return the global number of blocks in use. + */ +inline +size_t ArenaBlock::nactive() +{ + return s_nactive; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h new file mode 100644 index 00000000..87155e58 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h @@ -0,0 +1,121 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlockAllocatorBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaBlockAllocatorBase.h + * @author scott snyder + * @date May 2007 + * @brief Common functionality for block-oriented allocators. + */ + + +#ifndef ATLALLOCATORS_ARENABLOCKALLOCATORBASE_H +#define ATLALLOCATORS_ARENABLOCKALLOCATORBASE_H + + +#include "AthAllocators/ArenaAllocatorBase.h" + + +namespace SG { + + +class ArenaBlock; + + +/** + * @brief Common functionality for block-oriented allocators. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This class factors out some common functionality for allocators + * that use @c ArenaBlock. + */ +class ArenaBlockAllocatorBase + : public ArenaAllocatorBase +{ +public: + /** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ + ArenaBlockAllocatorBase (const Params& params); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + virtual void reserve (size_t size); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase(); + + + /** + * @brief Return the statistics block for this allocator. + */ + virtual const Stats& stats() const; + + + /** + * @brief Return the name of this allocator. + */ + virtual const std::string& name() const; + + + /** + * @brief Return this Allocator's parameters. + */ + const Params& params() const; + + +protected: + /** + * @brief Return an empty block, either newly-allocated or from the + * free list. Update statistics appropriately. + */ + ArenaBlock* getBlock(); + + /// The parameters for this allocator. + Params m_params; + + /// The list of blocks currently in use. + ArenaBlock* m_blocks; + + /// The list of free blocks. + ArenaBlock* m_freeblocks; + + /// The statistics structure. + mutable ArenaAllocatorBase::Stats m_stats; +}; + + +} // namespace SG + +#endif // not ATLALLOCATORS_ARENABLOCKALLOCATORBASE_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h new file mode 100644 index 00000000..4a564295 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h @@ -0,0 +1,173 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaCachingHandle.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaCachingHandle.h + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory that caches constructed objects. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENACACHINGHANDLE_H +#define ATLALLOCATORS_ARENACACHINGHANDLE_H + + +#include "AthAllocators/ArenaHandleBaseT.h" +#include "AthAllocators/Arena.h" + + +namespace SG { + + +/** + * @brief User interface for allocating memory that caches constructed objects. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A @em Handle is the interface the application uses to allocate memory. + * A Handle is templated on the type being allocated as well as on the + * underlying Allocator. When a Handle is constructed, it is associated + * with the Allocator associated with the Arena that is current at that time + * (a new Allocator is automatically created if required). Therefore, + * a Handle should not be passed between threads, and Handle objects + * should not exist across any point where the current store/Arena + * may be changed. + * + * This particular Handle implementation calls the element constructor + * only when the memory is first allocated by the system, and calls + * the destructor only when the memory is returned to the system. + * The @c allocate method thus returns an already-initialized pointer + * to the element. The element's default constructor must work + * for this. + * + * Note that it's possible to set up an additional @c clear method + * that's called when the element is freed; see @c ArenaAllocatorBase. + * + * Here's an example of how you might create the Handle and allocate + * memory: + * + *@code + * SG::ArenaCachingHandle<MyObj, SG::ArenaPoolAllocator> handle; + * MyObj* obj = handle.allocate(); + @endcode + * + * This associates the Handle with the default @c ArenaHeader. + * You can then erase all objects allocated though this Handle + * in the current Allocator with + * + *@code + * handle.reset(); + @endcode + * + * Note that most of the public interface for this class is inherited + * from the base classes. + */ +template <class T, class ALLOC> +class ArenaCachingHandle + : public ArenaHandleBaseT<T, ALLOC> +{ +public: + /// Shorthand for our base class. + typedef ArenaHandleBaseT<T, ALLOC> Base; + + /// Pointer to an element. + typedef T* pointer; + + /// Iterators over elements. + /// (May only be instantiated if the underlying Allocator supports them.) + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + + /** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaCachingHandle (ArenaHeader* header, size_t index); + + + /// The class that initializes the default parameter set. + typedef typename ALLOC::template initParams<T, false> defaultParams_t; + + + /** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ + ArenaCachingHandle (const typename ALLOC::Params& params = + defaultParams_t()); + + + + /** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaCachingHandle (ArenaHeader* header, + const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaCachingHandle (Arena* arena, const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Allocate a new element. + * + * This returns an already-initialized element. + */ + pointer allocate() const; + + + /** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ + static + ArenaAllocatorBase* makeAllocator (const typename ALLOC::Params& params); + + + // The following methods are inherited: + // const ALLOC::Params& params() const; + // void reset(); + // void erase(); + // void reserve(size_t); + // const ArenaAllocatorBase::Stats& stats() const; + // + // The following inherited functions may be instantiated only + // if the Allocator supports them: + // iterator begin(); + // const_iterator begin() const; + // iterator end(); + // const_iterator end() const; + // void free (pointer p) const; + // void resetTo (pointer p) const; +}; + + +} // namespace SG + + + +#include "AthAllocators/ArenaCachingHandle.icc" + + + +#endif // not ATLALLOCATORS_ARENACACHINGHANDLE_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc new file mode 100644 index 00000000..525b810e --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaCachingHandle.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaCachingHandle.icc + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory that caches constructed objects. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle (ArenaHeader* header, + size_t index) + : ArenaHandleBaseT<T, ALLOC> (header, index) +{ +} + + +/** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle + (const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (0, typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle + (ArenaHeader* header, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (header, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle + (Arena* arena, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (arena ? arena->header() : 0, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Allocate a new element. + * + * This returns an already-initialized element. + * + * This is on the fast path for element allocation, so keep it small + * and inline. + */ +template <class T, class ALLOC> +inline +typename ArenaCachingHandle<T, ALLOC>::pointer +ArenaCachingHandle<T, ALLOC>::allocate() const +{ + return reinterpret_cast<pointer> (this->allocator()->allocate()); +} + + +/** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ +template <class T, class ALLOC> +ArenaAllocatorBase* ArenaCachingHandle<T, ALLOC>::makeAllocator + (const typename ALLOC::Params& params) +{ + return new ALLOC (params); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.h new file mode 100644 index 00000000..fd60d44a --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.h @@ -0,0 +1,166 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandle.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandle.h + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHANDLE_H +#define ATLALLOCATORS_ARENAHANDLE_H + + +#include "AthAllocators/ArenaHandleBaseT.h" +#include "AthAllocators/Arena.h" + + +namespace SG { + + +/** + * @brief User interface for allocating memory. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A @em Handle is the interface the application uses to allocate memory. + * A Handle is templated on the type being allocated as well as on the + * underlying Allocator. When a Handle is constructed, it is associated + * with the Allocator associated with the Arena that is current at that time + * (a new Allocator is automatically created if required). Therefore, + * a Handle should not be passed between threads, and Handle objects + * should not exist across any point where the current store/Arena + * may be changed. + * + * This particular Handle implementation does not call element constructors, + * and calls destructors when elements are freed. The @c allocate + * method returns a @c void*, so you're expected to use it in a placement new. + * Here's an example of how you might create the Handle and allocate + * memory: + * + *@code + * SG::ArenaHandle<MyObj, SG::ArenaPoolAllocator> handle; + * MyObj* obj = new (handle.allocate()) (...); + @endcode + * + * This associates the Handle with the default @c ArenaHeader. + * You can then erase all objects allocated though this Handle + * in the current Allocator with + * + *@code + * handle.reset(); + @endcode + * + * The destructors for the allocated objects will be called at that time. + * + * Note that most of the public interface for this class is inherited + * from the base classes. + */ +template <class T, class ALLOC> +class ArenaHandle + : public ArenaHandleBaseT<T, ALLOC> +{ +public: + /// Shorthand for our base class. + typedef ArenaHandleBaseT<T, ALLOC> Base; + + /// Pointer to an element. + typedef typename Base::pointer pointer; + + /// Iterators over elements. + /// (May only be instantiated if the underlying Allocator supports them.) + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + + /** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandle (ArenaHeader* header, size_t index); + + + /// The class that initializes the default parameter set. + typedef typename ALLOC::template initParams<T, false, true> defaultParams_t; + + + /** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ + ArenaHandle (const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaHandle (ArenaHeader* header, + const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaHandle (Arena* arena, const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Allocate a new element. + * + * The element's constructor will not have been called; thus, the memory + * is returned as a @c void*. + */ + void* allocate() const; + + + /** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ + static + ArenaAllocatorBase* makeAllocator (const typename ALLOC::Params& params); + + + // The following methods are inherited: + // const ALLOC::Params& params() const; + // void reset(); + // void erase(); + // void reserve(size_t); + // const ArenaAllocatorBase::Stats& stats() const; + // + // The following inherited functions may be instantiated only + // if the Allocator supports them: + // iterator begin(); + // const_iterator begin() const; + // iterator end(); + // const_iterator end() const; + // void free (pointer p) const; + // void resetTo (pointer p) const; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandle.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLE_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.icc new file mode 100644 index 00000000..26cb4c87 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandle.icc @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandle.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandle.icc + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle (ArenaHeader* header, + size_t index) + : ArenaHandleBaseT<T, ALLOC> (header, index) +{ +} + + +/** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle + (const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (0, typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle + (ArenaHeader* header, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (header, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle + (Arena* arena, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (arena ? arena->header() : 0, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Allocate a new element. + * + * The element's constructor will not be called; thus, the memory + * is returned as a @c void*. + * + * This is on the fast path for element allocation, so keep it small + * and inline. + */ +template <class T, class ALLOC> +inline +void* ArenaHandle<T, ALLOC>::allocate() const +{ + return this->allocator()->allocate(); +} + + +/** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ +template <class T, class ALLOC> +ArenaAllocatorBase* ArenaHandle<T, ALLOC>::makeAllocator + (const typename ALLOC::Params& params) +{ + typename ALLOC::Params newparams = params; + + // We don't call the element constructor. + newparams.constructor = 0; + + // The destructor is called when we free an element --- not when + // we return it to the system. + newparams.clear = newparams.destructor; + newparams.destructor = 0; + + // We can't skip running the destructor. + newparams.mustClear = true; + + // We can't call the destructor twice. + newparams.canReclear = false; + + // If we need a link, it can overlap the element. + newparams.eltSize = std::max (sizeof(T), newparams.minSize); + newparams.linkOffset = 0; + + // Make the Allocator. + return new ALLOC (newparams); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.h new file mode 100644 index 00000000..7543ebbf --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.h @@ -0,0 +1,138 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandleBase.h + * @author scott snyder + * @date May 2007 + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENAHANDLEBASE_H +#define ATLALLOCATORS_ARENAHANDLEBASE_H + +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cstdlib> + + +namespace SG { + + +/** + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A @em Handle is the interface the application uses to allocate memory. + * A Handle is templated on the type being allocated as well as on the + * underlying Allocator. When a Handle is constructed, it is associated + * with the Allocator associated with the Arena that is current at that time + * (a new Allocator is automatically created if required). Therefore, + * a Handle should not be passed between threads, and Handle objects + * should not exist across any point where the current store/Arena + * may be changed. + * Multiple Handle implementations may be available, implementing + * different strategies for initializing the elements. + * + * This class contains the parts of the Handle interface that do not + * depend on the template parameters. + * + * The first time a given Handle type is seen, it is assigned an index + * in the the the @c Arena @c Allocator vector. A @c Handle forwards + * operations to the underlying @c Allocator. + */ +class ArenaHandleBase +{ +public: + /** + * @brief Constructor. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandleBase (ArenaHeader* header, size_t index); + + + /** + * @brief Free all allocated elements (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are returned to the + * free state. @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system + * (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator + * (in the current Arena). + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator, + * for the current Arena. + */ + const ArenaAllocatorBase::Stats& stats() const; + + +protected: + /** + * @brief Return the current Allocator which we are referencing. + * + * This may cause a new Allocator to be created. + */ + ArenaAllocatorBase* baseAllocator() const; + + +private: + /// The associated allocator object. + ArenaAllocatorBase* m_allocator; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandleBase.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLEBASE_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc new file mode 100644 index 00000000..d3079713 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandleBase.icc + * @author scott snyder + * @date May 2007 + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + * Inline implementations. + */ + + +namespace SG { + + +/** + * @brief Return the current Allocator which we are referencing. + * + * This may cause a new Allocator to be created. + * + * This is on the fast path for allocations, so keep it small and inline. + */ +inline +ArenaAllocatorBase* ArenaHandleBase::baseAllocator() const +{ + return m_allocator; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h new file mode 100644 index 00000000..13001143 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h @@ -0,0 +1,167 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseAllocT.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandleBaseAllocT.h + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * depend only on the Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHANDLEBASEALLOCT_H +#define ATLALLOCATORS_ARENAHANDLEBASEALLOCT_H + + +#include "AthAllocators/ArenaHandleBase.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "GaudiKernel/System.h" +#include <string> + + +namespace SG { + + +/** + * @brief Base class for @c Handle classes, containing parts that + * depend only on the Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This is the part of @c Handle that depends only on the Allocator class + * (on which it is templated). This implementation here is responsible + * for registering the Allocator and handling its possible creation. + * + * A @c Handle uses an index to identify the particular Allocator + * class which it uses; the @c ArenaAllocatorRegistry class maps between + * these indices and instances of @c ArenaAllocatorCreator, which are + * capable of creating new @c Allocator instances. + * An @c ArenaHandleBaseAllocT may be created by either passing + * in the index directly or by passing in a concrete instance + * of @c ArenaAllocatorCreator. In the latter case, we will + * look up the index, registering the creator if needed. + */ +template <typename ALLOC> +class ArenaHandleBaseAllocT + : public ArenaHandleBase +{ +public: + /// The @c Allocator we use. + typedef ALLOC alloc_t; + + + /** + * @brief Concrete ArenaAllocatorCreator class used to create + * the Allocator for this handle. + * + * There are two members of this class: @c m_makeFunc is the function + * which actually creates the Allocator, and @c m_params is the + * parameters structure to pass to the new Allocator. These will + * get filled in by @c ArenaAllocatorCreatorInit, which derives + * from this. + */ + class Creator + : public ArenaAllocatorCreator + { + public: + /// Type for @c m_makeFunc --- a function returning a new Allocator + /// from a parameters structure. + typedef + ArenaAllocatorBase* makeFunc_t (const typename ALLOC::Params&); + + + /** + * @brief Constructor. + * @param hand Dummy to set the template argument type. + * @param params Allocator parameters. + * + * This initializes the @c Creator for creating an Allocator + * appropriate for the Handle class @c HANDLE. The @c HANDLE + * class should have a static function @c makeAllocator + */ + template <class HANDLE> + Creator (HANDLE* hand, const typename ALLOC::Params& params); + + + /** + * @brief Create an allocator instance. + */ + virtual ArenaAllocatorBase* create(); + + + /** + * @brief Return the name of the Allocator we create. + */ + const std::string& name() const; + + + protected: + /// Function that creates an Allocator given a set of parameters. + makeFunc_t* m_makeFunc; + + /// Set of parameters to use to create our allocator. + typename ALLOC::Params m_params; + }; + + + /** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandleBaseAllocT (ArenaHeader* header, size_t index); + + + /** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ + ArenaHandleBaseAllocT (ArenaHeader* header, const Creator& creator); + + + /** + * @brief Return our Allocator's parameters. + */ + const typename ALLOC::Params& params() const; + + +protected: + /** + * @brief Return our current Allocator. + */ + ALLOC* allocator() const; + + +private: + /** + * @brief Find the index for @c Creator, registering it if needed. + * + * We look up in the registry the Allocator name we get from @c creator. + * If not found, then we register @c creator and return the new index. + */ + size_t makeIndex (const Creator& creator); +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandleBaseAllocT.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLEBASEALLOCT_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc new file mode 100644 index 00000000..16ab2bab --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc @@ -0,0 +1,128 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseAllocT.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandleBaseAllocT.icc + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * depend only on the Allocator. + * Inline and template implementations. + */ + + +namespace SG { + + +template <typename ALLOC> +template <class HANDLE> +ArenaHandleBaseAllocT<ALLOC>::Creator::Creator + (HANDLE*, const typename ALLOC::Params& params) + : m_makeFunc (HANDLE::makeAllocator), + m_params (params) +{ + if (m_params.name.empty()) + m_params.name = System::typeinfoName (typeid (HANDLE)); +} + + +/** + * @brief Create an allocator instance. + */ +template <typename ALLOC> +ArenaAllocatorBase* ArenaHandleBaseAllocT<ALLOC>::Creator::create() +{ + return m_makeFunc (m_params); +} + + +/** + * @brief Return the name of the Allocator we create. + */ +template <typename ALLOC> +const std::string& +ArenaHandleBaseAllocT<ALLOC>::Creator::name() const +{ + return m_params.name; +} + + +/** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <typename ALLOC> +ArenaHandleBaseAllocT<ALLOC>::ArenaHandleBaseAllocT + (ArenaHeader* header, size_t index) + : ArenaHandleBase (header, index) +{ +} + + +/** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ +template <typename ALLOC> +ArenaHandleBaseAllocT<ALLOC>::ArenaHandleBaseAllocT (ArenaHeader* header, + const Creator& creator) + : ArenaHandleBase (header, makeIndex (creator)) +{ +} + + +/** + * @brief Return our Allocator's parameters. + */ +template <typename ALLOC> +const typename ALLOC::Params& +ArenaHandleBaseAllocT<ALLOC>::params() const +{ + return dynamic_cast<const ALLOC*>(this->baseAllocator())->params(); +} + + +/** + * @brief Return our current Allocator. + * + * This is on the fast path for allocation. It should be kept + * simple and inline. + */ +template <typename ALLOC> +inline +ALLOC* ArenaHandleBaseAllocT<ALLOC>::allocator() const +{ + return reinterpret_cast<ALLOC*> (this->baseAllocator()); +} + + +/** + * @brief Find the index for @c Creator, registering it if needed. + * + * We look up in the registry the Allocator name we get from @c creator. + * If not found, then we register @c creator and return the new index. + */ +template <typename ALLOC> +size_t +ArenaHandleBaseAllocT<ALLOC>::makeIndex (const Creator& creator) +{ + ArenaAllocatorRegistry* reg = ArenaAllocatorRegistry::instance(); + size_t i = reg->lookup (creator.name()); + if (i != std::string::npos) + return i; + return reg->registerCreator (creator.name(), new Creator (creator)); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h new file mode 100644 index 00000000..150a3665 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h @@ -0,0 +1,244 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseT.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandleBaseT.h + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * are independent of how the Allocator gets created. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHANDLEBASET_H +#define ATLALLOCATORS_ARENAHANDLEBASET_H + +#include "AthAllocators/ArenaHandleBaseAllocT.h" +#include "AthAllocators/ArenaHeader.h" +#include "boost/iterator/iterator_adaptor.hpp" +#include <cstdlib> + + +namespace SG { + + +/** + * @brief Base class for @c Handle classes, containing parts that + * are independent of how the Allocator gets created. + * See Arena.h for an overview of the arena-based memory allocators. + */ +template <class T, class ALLOC> +class ArenaHandleBaseT + : public ArenaHandleBaseAllocT<ALLOC> +{ +public: + /// A pointer to the element type we're allocating. + typedef T* pointer; + + /// Shorthand for our base class. + typedef ArenaHandleBaseAllocT<ALLOC> Base; + + /// @c AllocatorCreatorBase concrete derived class for creating + /// our Allocator. + typedef typename Base::Creator Creator; + + + /** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandleBaseT (ArenaHeader* header, size_t index); + + + /** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ + ArenaHandleBaseT (ArenaHeader* header, const Creator& creator); + + + // Forward declaration. + class const_iterator; + + + /** + * @brief Non-const iterator. + * It iterates over all unallocated blocks in the current + * Allocator (in unspecified order). It will be at least + * a @c forward_iterator. + * + * Note that this is only supported if the underlying Allocator + * supports it. If it does not, you will not be able + * to instantiate this type. + * + * This uses @c boost::iterator_adaptor to handle casting + * the element pointers to the proper type. + */ + class iterator + : public boost::iterator_adaptor< + iterator, + typename ALLOC::iterator, + T, + boost::forward_traversal_tag> + { + public: + /** + * @brief Constructor. + * @param it The base iterator. + */ + iterator (const typename ALLOC::iterator& it); + + + // To allow initializing a @c const_iterator from an @c iterator. + friend class const_iterator; + + + private: + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + + /** + * @brief Dereference the iterator. + */ + typename iterator::reference dereference() const; + }; + + + /** + * @brief Const iterator. + * It iterates over all unallocated blocks in the current + * Allocator (in unspecified order). It will be at least + * a @c forward_iterator. + * + * Note that this is only supported if the underlying Allocator + * supports it. If it does not, you will not be able + * to instantiate this type. + * + * This uses @c boost::iterator_adaptor to handle casting + * the element pointers to the proper type. + */ + class const_iterator + : public boost::iterator_adaptor< + const_iterator, + typename ALLOC::const_iterator, + T const, + boost::forward_traversal_tag> + { + + public: + /** + * @brief Constructor. + * @param it The base iterator. + */ + const_iterator (const typename ALLOC::const_iterator& it); + + + /** + * @brief Constructor from a non-const iterator. + * @param it The non-const iterator. + */ + const_iterator (const iterator& it); + + + private: + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + + /** + * @brief Dereference the iterator. + */ + typename const_iterator::reference dereference() const; + }; + + + /** + * @brief Starting iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + iterator begin(); + + + /** + * @brief Starting const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + const_iterator begin() const; + + + /** + * @brief Ending iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + iterator end(); + + + /** + * @brief Ending const iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + const_iterator end() const; + + + /** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ + void free (pointer p); + + + /** + * @brief Reset pool back to a previous state. + * @param p The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ + void resetTo (pointer p); +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandleBaseT.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLEBASET_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc new file mode 100644 index 00000000..90ceeafe --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc @@ -0,0 +1,212 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseT.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandleBaseT.icc + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * are independent of how the Allocator gets created. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <typename T, typename ALLOC> +ArenaHandleBaseT<T, ALLOC>::ArenaHandleBaseT (ArenaHeader* header, + size_t index) + : Base (header, index) +{ +} + + +/** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ +template <typename T, typename ALLOC> +ArenaHandleBaseT<T, ALLOC>::ArenaHandleBaseT (ArenaHeader* header, + const Creator& creator) + : Base (header, creator) +{ +} + + +/** + * @brief Constructor. + * @param it The base iterator. + */ +template <typename T, typename ALLOC> +inline +ArenaHandleBaseT<T, ALLOC>::iterator::iterator + (const typename ALLOC::iterator& it) + : iterator::iterator_adaptor_ (it) +{ +} + + +/** + * @brief Dereference the iterator. + */ +template <typename T, typename ALLOC> +inline +typename ArenaHandleBaseT<T, ALLOC>::iterator::reference +ArenaHandleBaseT<T, ALLOC>::iterator::dereference() const +{ + return reinterpret_cast<T&> (*this->base_reference()); +} + + +/** + * @brief Constructor. + * @param it The base iterator. + */ +template <typename T, typename ALLOC> +inline +ArenaHandleBaseT<T, ALLOC>::const_iterator::const_iterator + (const typename ALLOC::const_iterator& it) + : const_iterator::iterator_adaptor_ (it) +{ +} + + +/** + * @brief Constructor from a non-const iterator. + * @param it The non-const iterator. + */ +template <typename T, typename ALLOC> +inline +ArenaHandleBaseT<T, ALLOC>::const_iterator::const_iterator + (const iterator& it) + : const_iterator::iterator_adaptor_ (it.base_reference()) +{ +} + + +/** + * @brief Dereference the iterator. + */ +template <typename T, typename ALLOC> +inline +typename ArenaHandleBaseT<T, ALLOC>::const_iterator::reference +ArenaHandleBaseT<T, ALLOC>::const_iterator::dereference() const +{ + return reinterpret_cast<const T&> (*this->base_reference()); +} + + +/** + * @brief Starting iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::iterator +ArenaHandleBaseT<T, ALLOC>::begin() +{ + return const_cast<ALLOC*>(this->allocator())->begin(); +} + + +/** + * @brief Starting const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::const_iterator +ArenaHandleBaseT<T, ALLOC>::begin() const +{ + return const_cast<const ALLOC*>(this->allocator())->begin(); +} + + +/** + * @brief Ending iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::iterator +ArenaHandleBaseT<T, ALLOC>::end() +{ + return const_cast<ALLOC*>(this->allocator())->end(); +} + + +/** + * @brief Ending const iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::const_iterator +ArenaHandleBaseT<T, ALLOC>::end() const +{ + return const_cast<const ALLOC*>(this->allocator())->end(); +} + + +/** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ +template <class T, class ALLOC> +inline +void ArenaHandleBaseT<T, ALLOC>::free (pointer p) +{ + this->allocator()->free + (reinterpret_cast<typename ALLOC::pointer>(p)); +} + + +/** + * @brief Reset pool back to a previous state. + * @param p The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ +template <class T, class ALLOC> +void ArenaHandleBaseT<T, ALLOC>::resetTo(pointer p) +{ + return this->allocator()->resetTo + (reinterpret_cast<typename ALLOC::pointer>(p)); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.h new file mode 100644 index 00000000..5cb23467 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.h @@ -0,0 +1,175 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHeader.h + * @author scott snyder + * @date May 2007 + * @brief Proxy for a group of Arenas. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHEADER_H +#define ATLALLOCATORS_ARENAHEADER_H + + +#include <vector> +#include <cstdlib> +#include <string> +#include <iosfwd> +#include <mutex> +#include "boost/thread/tss.hpp" + + +namespace SG { + + +class ArenaAllocatorBase; +class ArenaBase; + + +/** + * @brief Proxy for a group of Arenas. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A Header collects a group of Arenas. One of these is the current Arena, + * in which memory operations will take place. We can also generate + * a report of memory usage from all the Arenas in the group. + * + * This is also where we handle the mapping from indices to Allocator + * instances. This is done simply with a vector of Allocator pointers. + * Each Arena has such a vector. We keep a pointer to one of these; + * that's what defines the notion of the current Arena. + */ +class ArenaHeader +{ +public: + /// Vector of pointers to Allocator instances. + typedef std::vector<ArenaAllocatorBase*> ArenaAllocVec_t; + + + /** + * @brief Constructor. + */ + ArenaHeader(); + + + /** + * @brief Destructor. + * + * This will clean up any memory allocated in the default Arena. + */ + ~ArenaHeader(); + + + /** + * @brief Translate an integer index to an Allocator index. + * @param i The index to look up. + * + * If the index isn't valid, an assertion will be tripped. + */ + ArenaAllocatorBase* allocator (size_t i); + + + /** + * @brief Set the current Arena. + * @param allocvec New vector of Allocator instances. + * @return The previous vector. + * + * This sets the notion of the current Arena. + */ + ArenaAllocVec_t* setAllocVec (ArenaAllocVec_t* allocvec); + + + /** + * @brief Add a new Arena to the group. + * @param a The Arena to add. + */ + void addArena (ArenaBase* a); + + + /** + * @brief Remove an Arena from the group. + * @param a The Arena to remove. + * + * Will trip an assertion if the Arena is not in the group. + */ + void delArena (ArenaBase* a); + + + /** + * @brief Generate a report of all Arenas in the group. + * @param os Stream to which to send a report. + */ + void report (std::ostream& os) const; + + + /** + * @brief Generate a report of all Arenas in the group, and return + * the result as a string. + * + * We have this in addition to @c report() in order to make it easier + * to call from scripting languages. + */ + std::string reportStr () const; + + + /** + * @brief Call @c reset on all Allocators in the current Arena. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Return the global default Header instance. + */ + static ArenaHeader* defaultHeader(); + + +private: + /** + * @brief Make a new Allocator for index i. + * @param i The index of the Allocator. + * + * The Allocator vector was empty for index @c i. Make an appropriate + * new Allocator, store it in the vector, and return it. Will trip + * an assertion if the index is not valid. + */ + ArenaAllocatorBase* makeAllocator (size_t i); + + + /// Current vector of Allocators. + boost::thread_specific_ptr<ArenaAllocVec_t> m_allocvec; + + /// Vector of Allocators which are owned by this object. + /// This constitutes the default Arena. + ArenaAllocVec_t* m_ownedAllocvec; + + /// List of all Arenas in our group. + std::vector<ArenaBase*> m_arenas; + + /// Mutex to protect access to m_ownedAllocvec and m_arenas. + mutable std::mutex m_mutex; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHeader.icc" + + + +#endif // not ATLALLOCATORS_ARENAHEADER_H + diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.icc new file mode 100644 index 00000000..b79ef5a5 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeader.icc @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHeader.icc + * @author scott snyder + * @date May 2007 + * @brief Proxy for a group of Arenas. + * Inline implementations. + */ + + +namespace SG { + + +/** + * @brief Translate an integer index to an Allocator index. + * @param i The index to look up. + * + * If the index isn't valid, an assertion will be tripped. + * + * This is on the fast path for element allocation, so keep + * it small and inline. + */ +inline +ArenaAllocatorBase* ArenaHeader::allocator (size_t i) +{ + if (m_allocvec.get() && i < m_allocvec->size()) { + ArenaAllocatorBase* allocbase = (*m_allocvec)[i]; + if (allocbase) return allocbase; + } + return makeAllocator (i); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h new file mode 100644 index 00000000..4f278d5a --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h @@ -0,0 +1,200 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHeapAllocator.h + * @author scott snyder + * @date May 2007 + * @brief Heap-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHEAPALLOCATOR_H +#define ATLALLOCATORS_ARENAHEAPALLOCATOR_H + + +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include <cstdlib> + + +namespace SG { + + +class ArenaBlock; + + +/** + * @brief Heap-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This is a block-based memory allocator, with heap-like behavior. + * This allows freeing individual elements, but we don't implement + * @c resetTo or an iterator. + * + * There are some extra costs though. + * + * - We need an additional pointer (`link') for each free element. + * + * By default, this is done by increasing the element size by a pointer, + * since we don't know whether there is data in the element itself + * that must be preserved across free/allocate. However, if you know + * that part of the element may be safely while it is free, then + * the allocator can be configured to use that as the link instead. + * + * - When @c reset() is called, we need to call @c clear() on all + * allocated elements (if it is defined). If @c canReclear is set, + * then we just call @c clear() on all elements in allocated blocks + * on @c reset(), regardless of whether or not the individual elements + * are allocated or not. Otherwise, we make two passes over the elements, + * first to build a list of those that are allocated and second + * to actually call @c clear(). + * + * An intermediate strategy, not currently implemented, could be used + * if the link does not overlap the element: set the link to a magic + * value when an element is allocated. + */ +class ArenaHeapAllocator + : public ArenaBlockAllocatorBase +{ +public: + /** + * @brief Helper to initialize a parameters structure. + * + * This creates a @c Params class appropriately initialized for class @c T. + * Assumptions made: + * - The constructor and destructor calls will be filled in + * if non-trivial, unless no_ctor or no_dtor is set to true. + * - The clear call will be filled in if the optional template parameter + * @c clear is true. + * - No space will be reserved for an extra link. + * - @c canReclear is @c true and @c mustClear is @c false. + * - The link will be allocated externally to the element. + * + * If these are not appropriate, you can derive from this class + * and make the appropriate changes. + */ + template <typename T, + bool clear = false, + bool no_ctor = false, + bool no_dtor = false> + struct initParams + : public ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor> + { + // Short name for our base class. + typedef ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor> Base; + + + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + initParams (size_t nblock = 1000, const std::string& name = ""); + + /// Return an initialized parameters structure. + ArenaAllocatorBase::Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator ArenaAllocatorBase::Params() const { return params(); } + }; + + + /** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ + ArenaHeapAllocator (const Params& params); + + + /** + * @brief Destructor. This will free all the Allocator's storage. + */ + ~ArenaHeapAllocator(); + + + /** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ + pointer allocate(); + + + /** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + */ + void free (pointer p); + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + virtual void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase(); + + + // These are just placeholders --- the iterators are not implemented. + typedef void iterator; + typedef void const_iterator; + + +private: + /** + * @brief Call @c clear() for all allocated elements. + */ + void slowClear(); + + + /** + * @brief Add more free elements to the pool, and allocate a new element. + */ + pointer refill(); + + + /** + * @brief Return a reference to the link for an element. + * @param p The element. + */ + pointer& link (pointer p) const; + + /// Pointer to the next free element. + pointer m_freeptr; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHeapAllocator.icc" + + +#endif // not ATLALLOCATORS_ARENAHEAPALLOCATOR_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc new file mode 100644 index 00000000..47706751 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaPoolAllocator.icc + * @author scott snyder + * @date May 2007 + * @brief Heap-based allocator. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor for parameters helper. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaHeapAllocator::initParams<T, clear, no_ctor, no_dtor>:: +initParams (size_t nblock /*=1000*/, const std::string& name /*=""*/) + : Base (nblock, name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaAllocatorBase::Params +ArenaHeapAllocator::initParams<T, clear, no_ctor, no_dtor>::params() const +{ + // Do the base class stuff. + Params p = Base::operator ArenaAllocatorBase::Params(); + + // Allow space for an extra pointer. + struct Dummy { + T x; + pointer y; + }; + p.eltSize = sizeof (Dummy); + Dummy* dummy = (Dummy*)0x1234; + p.linkOffset = (char*)&dummy->y - (char*)dummy; + + // Need to allow at least enough space for a pointer. + p.minSize = sizeof (pointer); + + return p; +} + + +/** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ +inline +ArenaHeapAllocator::pointer ArenaHeapAllocator::allocate() +{ + ++m_stats.elts.inuse; + pointer ret = m_freeptr; + if (ret) { + m_freeptr = link (ret); + return ret; + } + return refill(); +} + + +/** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + */ +inline +void ArenaHeapAllocator::free (pointer p) +{ + if (m_params.clear) + m_params.clear (p); + link (p) = m_freeptr; + m_freeptr = p; + --m_stats.elts.inuse; +} + + +/** + * @brief Return a reference to the link for an element. + * @param p The element. + */ +inline +ArenaHeapAllocator::pointer& ArenaHeapAllocator::link (pointer p) const +{ + return *reinterpret_cast<pointer*> (p + m_params.linkOffset); +} + + +} // namespace SG + diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h new file mode 100644 index 00000000..259f5ce2 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h @@ -0,0 +1,388 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapSTLAllocator.h,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ + +/** + * @file AthAllocators/ArenaHeapSTLAllocator.h + * @author scott snyder + * @date Nov 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + * + * This class defines a STL-style allocator for types @c T with the + * following special properties. + * + * - We use an @c ArenaHeapAllocator for allocations. + * - The memory is owned directly by the allocator object. + * - Only one object at a time may be allocated. + * + * So, this allocator is suitable for an STL container which allocates + * lots of fixed-size objects, such as @c std::list. + * + * Much of the complexity here is due to the fact that the allocator + * type that gets passed to the container is an allocator for the + * container's value_type, but that allocator is not actually + * used to allocate memory. Instead, an allocator for the internal + * node type is used. This makes it awkward if you want to have + * allocators that store state. + * + * Further, to avoid creating a pool for the allocator for the container's + * value_type (when the container doesn't actually use that for allocation), + * this template has a second argument. This defaults to the first argument, + * but is passed through by rebind. If the first and second argument + * are the same, then we don't create a pool. + * + * The effect of all this is that you can give an allocator type like + * ArenaHeapSTLAllocator<Mytype> + * to a STL container. Allocators for Mytype won't use + * a pool, but an allocator for node<Mytype> will use the pool. + */ + + +#ifndef ATLALLOCATORS_ARENAHEAPSTLALLOCATOR +#define ATLALLOCATORS_ARENAHEAPSTLALLOCATOR + + +#include "AthAllocators/ArenaHeapAllocator.h" +#include <string> + + +namespace SG { + + +/** + * @brief Initializer for pool allocator parameters. + * + * We override the defaults to disable calling the payload ctor/dtor. + */ +template <class T> +class ArenaHeapSTLAllocator_initParams + : public ArenaHeapAllocator::initParams<T, false, true, true> +{ +public: + /// We take defaults from this. + typedef ArenaHeapAllocator::initParams<T, false, true, true> Base; + + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaHeapSTLAllocator_initParams (size_t nblock = 1000, + const std::string& name = ""); + + /// Return an initialized parameters structure. + ArenaAllocatorBase::Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator ArenaAllocatorBase::Params() const { return params(); } +}; + + +/** + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + * This is the generic specialization, which uses the heap allocator. + * + * See the file-level comments for details. + */ +template <class T, class VETO=T> +class ArenaHeapSTLAllocator +{ +public: + /// Standard STL allocator typedefs. + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaHeapSTLAllocator<U, VETO> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaHeapSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaHeapSTLAllocator (const ArenaHeapSTLAllocator<U, V>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /// Convert a reference to an address. + pointer address (reference x) const; + const_pointer address (const_reference x) const; + + + /** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ + pointer allocate (size_type n, const void* hint = 0); + + + /** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + */ + void deallocate (pointer, size_type n); + + + /** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ + size_type max_size() const throw(); + + + /** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ + void construct (pointer p, const T& val); + + + /** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ + void destroy (pointer p); + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// The underlying allocator. + ArenaHeapAllocator m_pool; +}; + + + +/** + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + * This is the specialization for the case of the vetoed type. + * + * See the file-level comments for details. + */ +template <class T> +class ArenaHeapSTLAllocator<T, T> + : public std::allocator<T> +{ +public: + typedef std::allocator<T> base; + + /// Standard STL allocator typedefs. + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaHeapSTLAllocator<U, T> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaHeapSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaHeapSTLAllocator (const ArenaHeapSTLAllocator<U, V>& a); + + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// Saved hinted number of objects per block. + size_t m_nblock; + + /// Saved allocator name. + std::string m_name; + + /// Point at an underlying allocator from a different specialization. + ArenaAllocatorBase* m_poolptr; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHeapSTLAllocator.icc" + + +#endif // ATLALLOCATORS_ARENAHEAPSTLALLOCATOR diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc new file mode 100644 index 00000000..570fc5d2 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc @@ -0,0 +1,432 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapSTLAllocator.icc,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +/** + * @file AthAllocators/ArenaHeapSTLAllocator.icc + * @author scott snyder + * @date Nov 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + */ + + +#include <cassert> + + +namespace SG { + + + +//**************************************************************************** +// Generic specialization +// + + +/** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaHeapSTLAllocator_initParams<T>::ArenaHeapSTLAllocator_initParams + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : Base (nblock, name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <class T> +ArenaAllocatorBase::Params ArenaHeapSTLAllocator_initParams<T>::params() const +{ + // Do the base class stuff. + ArenaAllocatorBase::Params p = + Base::operator ArenaAllocatorBase::Params(); + + // Disable ctor/dtor. + p.constructor = 0; + p.destructor = 0; + + // Overlap link over free struct. + p.eltSize = std::max (sizeof(T), p.minSize); + p.linkOffset = 0; + + return p; +} + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T, class VETO> +ArenaHeapSTLAllocator<T, VETO>::ArenaHeapSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_pool (ArenaHeapSTLAllocator_initParams<T> (nblock, name)) +{ +} + + +/** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T, class VETO> +template <class U, class V> +ArenaHeapSTLAllocator<T, VETO>::ArenaHeapSTLAllocator + (const ArenaHeapSTLAllocator<U, V>& a) + : m_pool (ArenaHeapSTLAllocator_initParams<T> (a.nblock(), a.name())) +{ +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::pointer +ArenaHeapSTLAllocator<T, VETO>::address (reference x) const +{ + return &x; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::const_pointer +ArenaHeapSTLAllocator<T, VETO>::address (const_reference x) const +{ + return &x; +} + + + +/** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::pointer +ArenaHeapSTLAllocator<T, VETO>::allocate (size_type +#ifndef NDEBUG + n +#endif + , const void* /*hint = 0*/) +{ + assert (n == 1); + return reinterpret_cast<pointer> (m_pool.allocate()); +} + + +/** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ +template <class T, class VETO> +inline +void ArenaHeapSTLAllocator<T, VETO>::deallocate (pointer p, size_type +#ifndef NDEBUG + n +#endif + ) +{ + assert (n == 1); + m_pool.free (reinterpret_cast<ArenaHeapAllocator::pointer> (p)); +} + + +/** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::size_type +ArenaHeapSTLAllocator<T, VETO>::max_size() const throw() +{ + return 1; +} + + +/** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ +template <class T, class VETO> +inline +void ArenaHeapSTLAllocator<T, VETO>::construct (pointer p, const T& val) +{ + new (reinterpret_cast<void*>(p)) T(val); +} + + +/** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ +template <class T, class VETO> +inline +void ArenaHeapSTLAllocator<T, VETO>::destroy (pointer p) +{ + p->~T(); +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T, class VETO> +inline +size_t ArenaHeapSTLAllocator<T, VETO>::nblock() const +{ + return m_pool.params().nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T, class VETO> +inline +const std::string& ArenaHeapSTLAllocator<T, VETO>::name() const +{ + return m_pool.name(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T, class VETO> +void ArenaHeapSTLAllocator<T, VETO>::reset() +{ + m_pool.reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T, class VETO> +void ArenaHeapSTLAllocator<T, VETO>::erase() +{ + m_pool.erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T, class VETO> +void ArenaHeapSTLAllocator<T, VETO>::reserve (size_t size) +{ + m_pool.reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T, class VETO> +const ArenaAllocatorBase::Stats& ArenaHeapSTLAllocator<T, VETO>::stats() const +{ + return m_pool.stats(); +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T, class VETO> +ArenaAllocatorBase* ArenaHeapSTLAllocator<T, VETO>::poolptr() const +{ + const ArenaAllocatorBase* tmp = &m_pool; + return const_cast<ArenaAllocatorBase*> (tmp); +} + + +//**************************************************************************** +// Vetoed specialization. +// + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaHeapSTLAllocator<T, T>::ArenaHeapSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name), + m_poolptr (0) +{ +} + + +/** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T> +template <class U, class V> +ArenaHeapSTLAllocator<T, T>::ArenaHeapSTLAllocator + (const ArenaHeapSTLAllocator<U, V>& a) + : m_nblock (a.nblock()), + m_name (a.name()), + m_poolptr (a.poolptr()) +{ +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T> +inline +size_t ArenaHeapSTLAllocator<T, T>::nblock() const +{ + return m_nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T> +inline +const std::string& ArenaHeapSTLAllocator<T, T>::name() const +{ + return m_name; +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T> +void ArenaHeapSTLAllocator<T, T>::reset() +{ + if (m_poolptr) + m_poolptr->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T> +void ArenaHeapSTLAllocator<T, T>::erase() +{ + if (m_poolptr) + m_poolptr->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T> +void ArenaHeapSTLAllocator<T, T>::reserve (size_t size) +{ + if (m_poolptr) + m_poolptr->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T> +const ArenaAllocatorBase::Stats& +ArenaHeapSTLAllocator<T, T>::stats() const +{ + if (m_poolptr) + return m_poolptr->stats(); + static ArenaAllocatorBase::Stats tmp; + return tmp; +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T> +ArenaAllocatorBase* ArenaHeapSTLAllocator<T, T>::poolptr() const +{ + return m_poolptr; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h new file mode 100644 index 00000000..be2743f3 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h @@ -0,0 +1,256 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaPoolAllocator.h + * @author scott snyder + * @date May 2007 + * @brief Pool-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENAPOOLALLOCATOR_H +#define ATLALLOCATORS_ARENAPOOLALLOCATOR_H + + +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include "boost/iterator/iterator_adaptor.hpp" +#include <cstdlib> + + +namespace SG { + + +class ArenaBlock; + + +/** + * @brief Pool-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This is a block-based memory allocator, with stack-like behavior + * (like the @c DataPool class). We do not allow freeing individual + * elements; instead, we support @c resetTo(p), which frees @p and all + * elements allocated after it (in this allocator). We also implement + * an iterator over the allocated blocks. + */ +class ArenaPoolAllocator + : public ArenaBlockAllocatorBase +{ +public: + // Needed forward declaration. + class const_iterator; + + /** + * @brief Non-const iterator for the pool. + * It iterates over all allocated blocks (in unspecified order). + * + * We use @c boost::iterator_adaptor, and take a @c pointer + * as the base iterator type. Besides that, we also need + * to record the current block which we're within. + */ + class iterator + : public boost::iterator_adaptor< + iterator, + pointer, + boost::use_default, + boost::forward_traversal_tag> + { + public: + /** + * @brief Default constructor. + */ + iterator (); + + + /** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ + iterator (pointer p, ArenaBlock* block); + + + // To allow initializing a @c const_iterator from an @c iterator. + friend class const_iterator; + + + private: + /// Block containing the current element. + ArenaBlock* m_block; + + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + /// Move the iterator forward. + void increment(); + }; + + + /** + * @brief Const iterator for the pool. + * It iterates over all allocated blocks (in unspecified order). + * + * We use @c boost::iterator_adaptor, and take a @c pointer + * as the base iterator type. Besides that, we also need + * to record the current block which we're within. + */ + class const_iterator + : public boost::iterator_adaptor< + const_iterator, + const_pointer, + boost::use_default, + boost::forward_traversal_tag> + { + public: + /** + * @brief Default constructor. + */ + const_iterator (); + + + /** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ + const_iterator (pointer p, ArenaBlock* block); + + + /** + * @brief Constructor from @c iterator. + * @param it The iterator to copy. + */ + const_iterator (const iterator& it); + + + private: + /// Block containing the current element. + ArenaBlock* m_block; + + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + /// Move the iterator forward. + void increment(); + }; + + + /** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ + ArenaPoolAllocator (const Params& params); + + + /** + * @brief Destructor. This will free all the Allocator's storage. + */ + ~ArenaPoolAllocator(); + + + /** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ + pointer allocate(); + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + virtual void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase(); + + + /** + * @brief Reset pool back to a previous state. + * @param p The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + */ + void resetTo (pointer p); + + + /** + * @brief Starting pool iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ + iterator begin(); + + + /** + * @brief Starting pool const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ + const_iterator begin() const; + + + /** + * @brief Ending pool iterator. + */ + iterator end(); + + + /** + * @brief Ending pool const iterator. + */ + const_iterator end() const; + + +private: + /** + * @brief Add more free elements to the pool. + */ + void refill(); + + + /** + * @brief Reset all elements in the topmost block, and move the block + * to the free list. + */ + void clearBlock(); + + + /// Pointer to the next free element to allocate, or null. + pointer m_ptr; + + /// One past the last available element in the current block, of null. + pointer m_end; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaPoolAllocator.icc" + + +#endif // not ATLALLOCATORS_ARENABLOCK_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc new file mode 100644 index 00000000..ea333449 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc @@ -0,0 +1,102 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaPoolAllocator.icc + * @author scott snyder + * @date May 2007 + * @brief Pool-based allocator. + * Inline implementations. + */ + + +namespace SG { + + +/** + * @brief Default constructor. + */ +inline +ArenaPoolAllocator::iterator::iterator() + : iterator::iterator_adaptor_ (0), + m_block (0) +{ +} + + +/** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ +inline +ArenaPoolAllocator::iterator::iterator (pointer p, ArenaBlock* block) + : iterator::iterator_adaptor_ (p), + m_block (block) +{ +} + + +/** + * @brief Default constructor. + */ +inline +ArenaPoolAllocator::const_iterator::const_iterator () + : const_iterator::iterator_adaptor_ (0), + m_block (0) +{ +} + + +/** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ +inline +ArenaPoolAllocator::const_iterator::const_iterator (pointer p, + ArenaBlock* block) + : const_iterator::iterator_adaptor_ (p), + m_block (block) +{ +} + + +/** + * @brief Constructor from @c iterator. + * @param it The iterator to copy. + */ +inline +ArenaPoolAllocator::const_iterator::const_iterator (const iterator& it) + : const_iterator::iterator_adaptor_ (it.base_reference()), + m_block (it.m_block) +{ +} + + +/** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ +inline +ArenaPoolAllocator::pointer ArenaPoolAllocator::allocate() +{ + // If there are no free elements get more. + if (m_ptr >= m_end) + refill(); + + // Take the first free element. + pointer ret = m_ptr; + m_ptr = m_ptr + m_params.eltSize; + + // Update statistics. + ++m_stats.elts.inuse; + + return ret; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h new file mode 100644 index 00000000..5cbff761 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h @@ -0,0 +1,532 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator.h,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ + +/** + * @file AthAllocators/ArenaPoolSTLAllocator.h + * @author scott snyder + * @date Jul 2008 + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * + * This class defines a STL-style allocator for types @c T with the + * following special properties. + * + * - For non-pointer @c T's, we use an @c ArenaPoolAllocator. + * For pointer @c T's, we use the standard STL allocator. + * STL @c pair<> types will also use the standard STL allocator. + * Further comments below apply to the first case. + * - The memory is owned directly by the allocator object. + * - Only one object at a time may be allocated. + * - Deallocate doesn't do anything. The only way to release + * the memory is to delete the allocator. + * + * So, this allocator is suitable for an STL container which allocates + * lots of fixed-size objects, where the usage pattern is to fill the + * container up, use it for a while, then delete the container. + * (The particular scenario that inspired this was the map for + * @c NavigationToken.) + * + * Much of the complexity here is due to the fact that the allocator + * type that gets passed to the container is an allocator for the + * container's value_type, but that allocator is not actually + * used to allocate memory. Instead, an allocator for the internal + * node type is used. This makes it awkward if you want to have + * allocators that store state. We also need to support hash tables, + * which make two types of allocation. Nodes are fixed-size and + * are allocated individually, while the hash table is variable-sized + * and is of pointer type. + * + * Further, to avoid creating a pool for the allocator for the container's + * value_type (when the container doesn't actually use that for allocation), + * this template has a second argument. This defaults to the first argument, + * but is passed through by rebind. If the first and second argument + * are the same, then we don't create a pool. + * + * The effect of all this is that you can give an allocator type like + * ArenaPoolSTLAllocator<Mytype> + * to a STL container. Allocators for Mytype and Mytype* won't use + * a pool, but an allocator for node<Mytype> will use the pool. + */ + + +#ifndef ATLALLOCATORS_ARENAPOOLSTLALLOCATOR +#define ATLALLOCATORS_ARENAPOOLSTLALLOCATOR + + +#include "AthAllocators/ArenaPoolAllocator.h" +#include <string> + + +namespace SG { + + +/** + * @brief Initializer for pool allocator parameters. + * + * We override the defaults to disable calling the payload ctor/dtor. + */ +template <class T> +class ArenaPoolSTLAllocator_initParams + : public ArenaAllocatorBase::initParams<T, false, true, true> +{ +public: + /// We take defaults from this. + typedef ArenaAllocatorBase::initParams<T, false, true, true> Base; + + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator_initParams (size_t nblock = 1000, + const std::string& name = ""); + + /// Return an initialized parameters structure. + ArenaAllocatorBase::Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator ArenaAllocatorBase::Params() const { return params(); } +}; + + +/** + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * This is the generic specialization, which uses the pool allocator. + * + * See the file-level comments for details. + */ +template <class T, class VETO=T> +class ArenaPoolSTLAllocator +{ +public: + /// Standard STL allocator typedefs. + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaPoolSTLAllocator<U, VETO> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaPoolSTLAllocator (const ArenaPoolSTLAllocator<U, V>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /// Convert a reference to an address. + pointer address (reference x) const; + const_pointer address (const_reference x) const; + + + /** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ + pointer allocate (size_type n, const void* hint = 0); + + + /** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ + void deallocate (pointer, size_type n); + + + /** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ + size_type max_size() const throw(); + + + /** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ + void construct (pointer p, const T& val); + + + /** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ + void destroy (pointer p); + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// The underlying allocator. + ArenaPoolAllocator m_pool; +}; + + + +/** + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * This is the specialization for pointers, which uses + * the standard STL allocator. + * + * See the file-level comments for details. + */ +template <class T, class VETO> +class ArenaPoolSTLAllocator<T*, VETO> + : public std::allocator<T*> +{ +public: + typedef std::allocator<T*> base; + + /// Standard STL allocator typedefs. + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaPoolSTLAllocator<U, VETO> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaPoolSTLAllocator (const ArenaPoolSTLAllocator<U, V>& a); + + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// Saved hinted number of objects per block. + size_t m_nblock; + + /// Saved allocator name. + std::string m_name; + + /// Point at an underlying allocator from a different specialization. + ArenaAllocatorBase* m_poolptr; +}; + + +/** + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * This is the specialization for the case of the vetoed type. + * + * See the file-level comments for details. + */ +template <class T> +class ArenaPoolSTLAllocator<T, T> + : public std::allocator<T> +{ +public: + typedef std::allocator<T> base; + + /// Standard STL allocator typedefs. + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaPoolSTLAllocator<U, T> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaPoolSTLAllocator (const ArenaPoolSTLAllocator<U, V>& a); + + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// Saved hinted number of objects per block. + size_t m_nblock; + + /// Saved allocator name. + std::string m_name; + + /// Point at an underlying allocator from a different specialization. + ArenaAllocatorBase* m_poolptr; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaPoolSTLAllocator.icc" + + +#endif // ATLALLOCATORS_ARENAPOOLSTLALLOCATOR diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc new file mode 100644 index 00000000..994ac729 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc @@ -0,0 +1,571 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator.icc,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +/** + * @file AthAllocators/ArenaPoolSTLAllocator.icc + * @author scott snyder + * @date Jul 2008 + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + */ + + +#include <cassert> + + +namespace SG { + + + +//**************************************************************************** +// Generic specialization +// + + +/** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaPoolSTLAllocator_initParams<T>::ArenaPoolSTLAllocator_initParams + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : Base (nblock, name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <class T> +ArenaAllocatorBase::Params ArenaPoolSTLAllocator_initParams<T>::params() const +{ + // Do the base class stuff. + ArenaAllocatorBase::Params p = + Base::operator ArenaAllocatorBase::Params(); + + // Disable ctor/dtor. + p.constructor = 0; + p.destructor = 0; + + return p; +} + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T, class VETO> +ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_pool (ArenaPoolSTLAllocator_initParams<T> (nblock, name)) +{ +} + + +/** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T, class VETO> +template <class U, class V> +ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator + (const ArenaPoolSTLAllocator<U, V>& a) + : m_pool (ArenaPoolSTLAllocator_initParams<T> (a.nblock(), a.name())) +{ +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::pointer +ArenaPoolSTLAllocator<T, VETO>::address (reference x) const +{ + return &x; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::const_pointer +ArenaPoolSTLAllocator<T, VETO>::address (const_reference x) const +{ + return &x; +} + + + +/** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::pointer +ArenaPoolSTLAllocator<T, VETO>::allocate (size_type +#if !defined(NDEBUG) && !defined(__CLING__) + n +#endif + , const void* /*hint = 0*/) +{ +#if !defined(__CLING__) + assert (n == 1); +#endif + return reinterpret_cast<pointer> (m_pool.allocate()); +} + + +/** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ +template <class T, class VETO> +inline +void ArenaPoolSTLAllocator<T, VETO>::deallocate (pointer, size_type +#if !defined(NDEBUG) && !defined(__CLING__) + n +#endif + ) +{ +#if !defined(__CLING__) + assert (n == 1); +#endif +} + + +/** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::size_type +ArenaPoolSTLAllocator<T, VETO>::max_size() const throw() +{ + return 1; +} + + +/** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ +template <class T, class VETO> +inline +void ArenaPoolSTLAllocator<T, VETO>::construct (pointer p, const T& val) +{ + new (reinterpret_cast<void*>(p)) T(val); +} + + +/** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ +template <class T, class VETO> +inline +void ArenaPoolSTLAllocator<T, VETO>::destroy (pointer p) +{ + p->~T(); +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T, class VETO> +inline +size_t ArenaPoolSTLAllocator<T, VETO>::nblock() const +{ + return m_pool.params().nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T, class VETO> +inline +const std::string& ArenaPoolSTLAllocator<T, VETO>::name() const +{ + return m_pool.name(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T, VETO>::reset() +{ + m_pool.reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T, VETO>::erase() +{ + m_pool.erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T, VETO>::reserve (size_t size) +{ + m_pool.reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T, class VETO> +const ArenaAllocatorBase::Stats& ArenaPoolSTLAllocator<T, VETO>::stats() const +{ + return m_pool.stats(); +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T, class VETO> +ArenaAllocatorBase* ArenaPoolSTLAllocator<T, VETO>::poolptr() const +{ + const ArenaAllocatorBase* tmp = &m_pool; + return const_cast<ArenaAllocatorBase*> (tmp); +} + + +//**************************************************************************** +// Pointer specialization. +// + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T, class VETO> +ArenaPoolSTLAllocator<T*, VETO>::ArenaPoolSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name), + m_poolptr (0) +{ +} + + +/** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T, class VETO> +template <class U, class V> +ArenaPoolSTLAllocator<T*, VETO>::ArenaPoolSTLAllocator + (const ArenaPoolSTLAllocator<U, V>& a) + : m_nblock (a.nblock()), + m_name (a.name()), + m_poolptr (a.poolptr()) +{ +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T, class VETO> +inline +size_t ArenaPoolSTLAllocator<T*, VETO>::nblock() const +{ + return m_nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T, class VETO> +inline +const std::string& ArenaPoolSTLAllocator<T*, VETO>::name() const +{ + return m_name; +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T*, VETO>::reset() +{ + if (m_poolptr) + m_poolptr->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T*, VETO>::erase() +{ + if (m_poolptr) + m_poolptr->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T*, VETO>::reserve (size_t size) +{ + if (m_poolptr) + m_poolptr->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T, class VETO> +const ArenaAllocatorBase::Stats& ArenaPoolSTLAllocator<T*, VETO>::stats() const +{ + if (m_poolptr) + return m_poolptr->stats(); + static ArenaAllocatorBase::Stats tmp; + return tmp; +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T, class VETO> +ArenaAllocatorBase* ArenaPoolSTLAllocator<T*, VETO>::poolptr() const +{ + return m_poolptr; +} + + +//**************************************************************************** +// Vetoed specialization. +// + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaPoolSTLAllocator<T, T>::ArenaPoolSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name), + m_poolptr (0) +{ +} + + +/** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T> +template <class U, class V> +ArenaPoolSTLAllocator<T, T>::ArenaPoolSTLAllocator + (const ArenaPoolSTLAllocator<U, V>& a) + : m_nblock (a.nblock()), + m_name (a.name()), + m_poolptr (a.poolptr()) +{ +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T> +inline +size_t ArenaPoolSTLAllocator<T, T>::nblock() const +{ + return m_nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T> +inline +const std::string& ArenaPoolSTLAllocator<T, T>::name() const +{ + return m_name; +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T> +void ArenaPoolSTLAllocator<T, T>::reset() +{ + if (m_poolptr) + m_poolptr->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T> +void ArenaPoolSTLAllocator<T, T>::erase() +{ + if (m_poolptr) + m_poolptr->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T> +void ArenaPoolSTLAllocator<T, T>::reserve (size_t size) +{ + if (m_poolptr) + m_poolptr->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T> +const ArenaAllocatorBase::Stats& +ArenaPoolSTLAllocator<T, T>::stats() const +{ + if (m_poolptr) + return m_poolptr->stats(); + static ArenaAllocatorBase::Stats tmp; + return tmp; +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T> +ArenaAllocatorBase* ArenaPoolSTLAllocator<T, T>::poolptr() const +{ + return m_poolptr; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h new file mode 100644 index 00000000..879f0eea --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h @@ -0,0 +1,89 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSTLAllocator.h 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/ArenaSTLAllocator.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief + */ + + +#ifndef ATLALLOCATORS_ARENASTLALLOCATOR_H +#define ATLALLOCATORS_ARENASTLALLOCATOR_H + + +#include <string> +#include <cstdlib> + + +namespace SG { + + +template <class BASE> +class ArenaSTLAllocator + : public BASE +{ +public: + /// Standard STL allocator typedefs. + typedef typename BASE::value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaSTLAllocator<U> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ + ArenaSTLAllocator (size_t nblock = 1000, + const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + ArenaSTLAllocator (const ArenaSTLAllocator& a); + + + /** + * @brief Constructor from another @c ArenaSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + template <class U> + ArenaSTLAllocator (const ArenaSTLAllocator<U>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + +}; + + +} // namespace SG + + + +#include "AthAllocators/ArenaSTLAllocator.icc" + +#endif // not ATLALLOCATORS_ARENASTLALLOCATOR_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc new file mode 100644 index 00000000..e056f0d9 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSTLAllocator.icc 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/ArenaSTLAllocator.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief + */ + + +namespace SG { + + +template <class BASE> +ArenaSTLAllocator<BASE>::ArenaSTLAllocator (size_t nblock /*= 1000*/, + const std::string& name /*= ""*/) + : BASE (nblock, name) +{ +} + + +template <class BASE> +ArenaSTLAllocator<BASE>::ArenaSTLAllocator (const ArenaSTLAllocator& a) + : BASE (a) +{ +} + + +template <class BASE> +template <class U> +ArenaSTLAllocator<BASE>::ArenaSTLAllocator (const ArenaSTLAllocator<U>& a) + : BASE (a) +{ +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h new file mode 100644 index 00000000..80dacc23 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h @@ -0,0 +1,410 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.h 552460 2013-06-25 17:29:25Z ssnyder $ +/** + * @file AthAllocators/ArenaSharedHeapSTLAllocator.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + * + * This class defines a STL-style allocator for types @c T with the + * following special properties. + * + * - We use an @c ArenaHeapAllocator for allocations. + * - Only one object at a time may be allocated. + * - The memory from several allocators may be grouped + * together in the same memory pool. + * + * So, this allocator is suitable for an STL container which allocates + * lots of fixed-size objects, such as @c std::list, and further, + * you want to be able to have multiple list instances use + * the same pool. + * + * Note that this allocator will not work for containers that + * make variable-sized allocations, such as vector and the + * hash table containers. + * + * To use it, you should first explicitly create the allocator class, + * and then pass it to the constructors of the containers. + * The memory pool will be deleted when the original allocator + * instance is deleted. Example: + * + *@code + * { + * typedef SG::ArenaSharedHeapSTLAllocator<int> alloc_t; + * typedef std::list<int> list_t; + * + * alloc_t allocator; + * list_t list1 (allocator); + * list_t list2 (allocator); + * ... Now list1 and list2 will both use the same memory pool. + * } + * ... The memory pool is freed when the object `allocator' is deleted. + @endcode + * + * Implementation: Each allocator references a Header object, + * which is common to all allocators in the pool. When an allocator + * is copied, the header pointer is copied too. The Header object + * remembers the address of the allocator which originally created it, + * so that we can clean things up when that allocator goes away. + * + * A Header contains a list of ArenaHeapAllocator objects, one per + * payload type. We use ArenaAllocatorRegistry to assign indices + * to the different allocator types. + */ + + +#ifndef ATLALLOCATORS_ARENASHAREDHEAPSTLALLOCATOR_H +#define ATLALLOCATORS_ARENASHAREDHEAPSTLALLOCATOR_H + + +#include "AthAllocators/ArenaSTLAllocator.h" +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaHeapSTLAllocator.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include <string> +#include <vector> + + +namespace SG { + +/// Forward declaration. +template <class T> +class ArenaSharedHeapSTLAllocator; + + +/** + * @brief Common header class for ArenaSharedHeapSTLAllocator. + * + * Each ArenaSharedHeapSTLAllocator has a pointer to a Header class. + * When a new ASHSTLAllocator object is constructed, we make a new Header; + * after that, the Header pointer is copied on copy-construction. + * The Header remembers the address of the object that created it, + * so that it can be deleted when that allocator is. + * + * The Header contains a list of ArenaHeapAllocator objects, one for + * each type we're allocating. + */ +class ArenaSharedHeapSTLHeader +{ +public: + /** + * @brief Constructor. + * @param owner Address of the object that owns this Header. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ + ArenaSharedHeapSTLHeader (const void* owner, + int nblock, + const std::string& name); + + + /** + * @brief Destructor. + * + * Destroy all the allocators we own. + */ + ~ArenaSharedHeapSTLHeader(); + + + /** + * @brief Call this when an allocator is being deleted. + * @param a The address of calling allocator. + * + * If the address matches the address we were given when we were created, + * this object will be destroyed. + */ + void maybe_delete (const void* a); + + + /** + * @brief Return allocator statistics summed over all our owned allocators. + */ + ArenaAllocatorBase::Stats totstats() const; + + + /** + * @brief Return the name to use for an allocator for type @c T. + */ + template <class T> + std::string get_name(); + + + /** + * @brief Return the heap allocator for type @c T. + * @param index Reference to the index for type @c T. + * Before the first call, this should be initialized + * to std::string::npos. This should generally + * be a static variable. + */ + template <class T> + ArenaHeapAllocator* get_pool (size_t& index); + + + void report (std::ostream& os) const + { + for (size_t i = 0; i < m_allocators.size(); i++) + if (m_allocators[i]) + m_allocators[i]->report (os); + } + + +private: + /// Address of the allocator that created this header. + const void* m_owner; + + /// Saved value for nblock parameter. + size_t m_nblock; + + /// Saved value for base name. + std::string m_name; + + /// List of allocators. + std::vector<ArenaHeapAllocator*> m_allocators; +}; + + + + +/** + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + * + * See the file-level comments for details. + */ +template <class T> +class ArenaSharedHeapSTLAllocator +{ +public: + /// Make all instantiations of this class friends + /// (to be able to copy the header pointer). + template <class U> friend class ArenaSharedHeapSTLAllocator; + + /// Standard STL allocator typedefs. + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaSharedHeapSTLAllocator<U> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ + ArenaSharedHeapSTLAllocator (size_t nblock = 1000, + const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + ArenaSharedHeapSTLAllocator (const ArenaSharedHeapSTLAllocator& a); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + template <class U> + ArenaSharedHeapSTLAllocator (const ArenaSharedHeapSTLAllocator<U>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + ~ArenaSharedHeapSTLAllocator(); + + + /** + * @brief Assignment. + * + * We allow assignment only if the two objects involved represent + * the same arena, in which case it's a no-op. + * In other cases, we raise an exception. + * + * FIXME: By default, swap() is implemented in terms of this. + * It might be useful, though, to have a swap() that could + * handle different arenas. We would need to be able handle + * updating the ownership back pointers from the headers, though; + * but that's much easier for swap than for the case of general + * assignments. + */ + ArenaSharedHeapSTLAllocator& + operator= (const ArenaSharedHeapSTLAllocator& a); + + + /// Convert a reference to an address. + pointer address (reference x) const; + const_pointer address (const_reference x) const; + + + /** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ + pointer allocate (size_type n, const void* hint = 0); + + + /** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + */ + void deallocate (pointer, size_type n); + + + /** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ + size_type max_size() const throw(); + + + /** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ + void construct (pointer p, const T& val); + + + /** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ + void destroy (pointer p); + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return the statistics blocks summed up over all allocators + * using this pool. + */ + ArenaAllocatorBase::Stats totstats() const; + + + /** + * @brief Return a pointer to the underlying allocator. + * This creates the allocator if needed. + */ + ArenaHeapAllocator* poolptr() const; + + + void report (std::ostream& os) const + { + m_header->report(os); + } + + + + /** + * @brief Compare two allocators. Needed by some @c swap implementations. + * + * We consider two allocators to be the same if they're + * referencing the same Header. + */ + bool operator!= (const ArenaSharedHeapSTLAllocator& other) const; + + +private: + /** + * @brief Ask the Header for the allocator to use. + * This will either return an existing one or create a new one. + */ + void get_pool() const; + + ArenaSharedHeapSTLHeader* m_header; + mutable ArenaHeapAllocator* m_pool; + + static size_t s_index; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaSharedHeapSTLAllocator.icc" + + +#endif // not ATLALLOCATORS_ARENASHAREDHEAPSTLALLOCATOR_H diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc new file mode 100644 index 00000000..633010dd --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc @@ -0,0 +1,407 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.icc 496835 2012-04-20 07:58:52Z ssnyder $ +/** + * @file AthAllocators/ArenaSharedHeapSTLAllocator.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + */ + + +#include "GaudiKernel/System.h" +#include <cassert> +#include <stdexcept> + + +namespace SG { + + +/** + * @brief Call this when an allocator is being deleted. + * @param a The address of calling allocator. + * + * If the address matches the address we were given when we were created, + * this object will be destroyed. + */ +inline +void ArenaSharedHeapSTLHeader::maybe_delete (const void* a) +{ + if (a == m_owner) { + delete this; + } +} + + +/** + * @brief Return the name to use for an allocator for type @c T. + */ +template <class T> +std::string ArenaSharedHeapSTLHeader::get_name() +{ + return m_name + "::ArenaSharedHeapSTLAllocator<" + + System::typeinfoName (typeid (T)) + ">"; +} + + +/** + * @brief Return the heap allocator for type @c T. + * @param index Reference to the index for type @c T. + * Before the first call, this should be initialized + * to std::string::npos. This should generally + * be a static variable. + */ +template <class T> +ArenaHeapAllocator* ArenaSharedHeapSTLHeader::get_pool (size_t& index) +{ + // If we need the name, we'll put it here. + std::string name; + + // If we don't have an index yet, ask the global registry. + // Note: We're only using the registry for the name<->index + // mapping; we're not using it to construct the allocators + // for us. This, we pass in a null pointer for the constructor. + // (We don't construct the allocators from the registry because + // we cant to be able to change the number of blocks from instance + // to instance, but there's no way passing that to the Registry + // interface.) + if (index == std::string::npos) { + name = get_name<T>(); + ArenaAllocatorRegistry* reg = ArenaAllocatorRegistry::instance(); + index = reg->lookup (name); + if (index == std::string::npos) + index = reg->registerCreator (name, 0); + } + + // Expand the list of allocators if needed. + if (index >= m_allocators.size()) + m_allocators.resize (index+1); + + // Create the allocator if we haven't done so yet. + if (!m_allocators[index]) { + if (name.empty()) // Only construct the name once. + name = get_name<T>(); + m_allocators[index] = new ArenaHeapAllocator + (ArenaHeapSTLAllocator_initParams<T> (m_nblock, name)); + } + + // Return the allocator. + return m_allocators[index]; +} + + + +//=========================================================================== + + +template <class T> +size_t ArenaSharedHeapSTLAllocator<T>::s_index = -1; + + +template <class T> +ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator + (size_t nblock /*= 1000*/, + const std::string& name /*= ""*/) + : m_header (new ArenaSharedHeapSTLHeader (this, nblock, name)), + m_pool (0) +{ +} + + +template <class T> +inline +ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator + (const ArenaSharedHeapSTLAllocator& a) + : m_header (const_cast<ArenaSharedHeapSTLHeader*>(a.m_header)), + m_pool (const_cast<ArenaHeapAllocator*> (a.m_pool)) +{ +} + + +template <class T> +template <class U> +inline +ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator + (const ArenaSharedHeapSTLAllocator<U>& a) + : m_header (const_cast<ArenaSharedHeapSTLHeader*>(a.m_header)), + m_pool (0) +{ +} + + +template <class T> +inline +ArenaSharedHeapSTLAllocator<T>::~ArenaSharedHeapSTLAllocator() +{ + m_header->maybe_delete (this); +} + + +/** + * @brief Assignment. + * + * We allow assignment only if the two objects involved represent + * the same arena, in which case it's a no-op. + * In other cases, we raise an exception. + */ +template <class T> +ArenaSharedHeapSTLAllocator<T>& +ArenaSharedHeapSTLAllocator<T>::operator= + (const ArenaSharedHeapSTLAllocator& a) +{ + if (&a != this) { + if (m_header != a.m_header) + throw std::runtime_error + ("Attempt to assign between ArenaSharedHeapSTLAllocators " + "for different arenas"); + assert (m_pool == a.m_pool); + } + return *this; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::pointer +ArenaSharedHeapSTLAllocator<T>::address (reference x) const +{ + return &x; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::const_pointer +ArenaSharedHeapSTLAllocator<T>::address (const_reference x) const +{ + return &x; +} + + +/** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::pointer +ArenaSharedHeapSTLAllocator<T>::allocate (size_type +#ifndef NDEBUG + n +#endif + , const void* /*hint = 0*/) +{ + assert (n == 1); + return reinterpret_cast<pointer> (poolptr()->allocate()); +} + + +/** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::deallocate (pointer p, size_type +#ifndef NDEBUG + n +#endif + ) +{ + assert (n == 1); + poolptr()->free (reinterpret_cast<ArenaAllocatorBase::pointer> (p)); +} + + +/** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::size_type +ArenaSharedHeapSTLAllocator<T>::max_size() const throw() +{ + return 1; +} + + +/** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::construct (pointer p, const T& val) +{ + new (reinterpret_cast<void*>(p)) T(val); +} + + +/** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::destroy (pointer p) +{ + p->~T(); +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T> +inline +size_t ArenaSharedHeapSTLAllocator<T>::nblock() const +{ + return poolptr()->params().nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T> +inline +const std::string& ArenaSharedHeapSTLAllocator<T>::name() const +{ + return poolptr()->name(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T> +void ArenaSharedHeapSTLAllocator<T>::reset() +{ + poolptr()->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T> +void ArenaSharedHeapSTLAllocator<T>::erase() +{ + poolptr()->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T> +void ArenaSharedHeapSTLAllocator<T>::reserve (size_t size) +{ + poolptr()->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T> +const ArenaAllocatorBase::Stats& +ArenaSharedHeapSTLAllocator<T>::stats() const +{ + return poolptr()->stats(); +} + + +/** + * @brief Return the statistics blocks summed up over all allocators + * using this pool. + */ +template <class T> +inline +ArenaAllocatorBase::Stats ArenaSharedHeapSTLAllocator<T>::totstats() const +{ + return m_header->totstats(); +} + + +/** + * @brief Return a pointer to the underlying allocator. + * This creates the allocator if needed. + */ +template <class T> +inline +ArenaHeapAllocator* ArenaSharedHeapSTLAllocator<T>::poolptr() const +{ + if (!m_pool) + get_pool(); + return m_pool; +} + + +/** + * @brief Compare two allocators. Needed by some @c swap implementations. + * + * We consider two allocators to be the same if they're + * referencing the same Header. + */ +template <class T> +inline +bool ArenaSharedHeapSTLAllocator<T>::operator!= + (const ArenaSharedHeapSTLAllocator& other) const +{ + return m_header != other.m_header; +} + + +/** + * @brief Ask the Header for the allocator to use. + * This will either return an existing one or create a new one. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::get_pool() const +{ + m_pool = m_header->get_pool<T> (s_index); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h b/EDM/athena/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h new file mode 100644 index 00000000..09baf47b --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h @@ -0,0 +1,5 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthAllocators/ArenaHeader.h" diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/DataPool.h b/EDM/athena/Control/AthAllocators/AthAllocators/DataPool.h new file mode 100644 index 00000000..a64a8818 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/DataPool.h @@ -0,0 +1,160 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHALLOCATORS_DATAPOOL_H +#define ATHALLOCATORS_DATAPOOL_H +/** @class DataPool + * @brief a typed memory pool that saves time spent + * allocation small object. This is typically used + * by container such as DataVector and DataList + * + * Traditionally, these objects were declared as static, even after that + * was no longer needed due to the rewrite which based them on the Allocator + * classes. However, declaring @c DataPool instances as static will + * cause thread-safety problems, and thus should no longer be done. + * + * @author Srini Rajagopalan - ATLAS Collaboration + *$Id: DataPool.h 470529 2011-11-24 23:54:22Z ssnyder $ + */ + +#include "AthAllocators/ArenaCachingHandle.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include <string> +#include "boost/iterator/iterator_adaptor.hpp" + +template <typename VALUE> +class DataPool +{ +private: + typedef SG::ArenaPoolAllocator alloc_t; + typedef SG::ArenaCachingHandle<VALUE, alloc_t> handle_t; + +public: + typedef typename handle_t::pointer pointer; + typedef size_t size_type; + + class const_iterator; + + class iterator + : public boost::iterator_adaptor< + iterator, + typename handle_t::iterator, + VALUE *, + boost::forward_traversal_tag, + VALUE *> + { + public: + iterator (const typename handle_t::iterator& it) + : iterator::iterator_adaptor_ (it) + { + } + + friend class const_iterator; + + private: + friend class boost::iterator_core_access; + + typename iterator::reference dereference() const + { return &*this->base_reference(); } + }; + + class const_iterator + : public boost::iterator_adaptor< + const_iterator, + typename handle_t::const_iterator, + VALUE const *, + boost::forward_traversal_tag, + VALUE const *> + { + public: + const_iterator (const typename handle_t::const_iterator& it) + : const_iterator::iterator_adaptor_ (it) + { + } + + const_iterator (const iterator& it) + : const_iterator::iterator_adaptor_ (it.base_reference()) + { + } + + private: + friend class boost::iterator_core_access; + + typename const_iterator::reference dereference() const + { return &*this->base_reference(); } + }; + + + ////////////////////////////////////////////////////////////////////// + /// Constructors: + ////////////////////////////////////////////////////////////////////// + + /// default constructor will initialize the pool with m_minRefCount + DataPool(size_type n = 0, + size_type block_size = 0, + SG::Arena* arena = 0); + + /////////////////////////////////////////////////////// + + /// release all elements in the pool. + void reset(); + + /// free all memory in the pool. + void erase(); + + void reserve(unsigned int size); + + /// return capacity of pool OK + unsigned int capacity(); + + /// return size already allocated OK + unsigned int allocated(); + + /// begin iterators over pool + iterator begin(); + const_iterator begin() const; + + /// the end() method will allow looping over only valid elements + /// and not over ALL elements of the pool + iterator end(); + const_iterator end() const; + + /// obtain the next available element in pool by pointer + /// pool is resized if its limit has been reached + /// This may be faster than calling the constructors with + /// the following two methods. But one must be sure to + /// completely reset each object since it has values set in the + /// previous event. + pointer nextElementPtr(); + + /// obtain the next available element in pool by pointer + /// return as void* to minimize misuse, client usage is: + /// MyElement* m = new(pool->mem) MyElement(...); // pool is ptr + /// DANGEROUS --- do we need this??? + void* mem(); + + /// can also say: + /// MyElement* m = new ((*pool)()) MyElement(...); // pool = pointer + /// MyElement* m = new (pool()) MyElement(...); // pool = value + /// DANGEROUS --- do we need this??? + void *operator ()(); + + /// typename of pool + static const std::string& typeName(); + +//-----------------------------------------------------------// + + private: + + handle_t m_handle; + + /// minimum number of elements in pool + static const unsigned int m_minRefCount = 1024; +}; + +#include "AthAllocators/DataPool.icc" + +#endif + + diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/DataPool.icc b/EDM/athena/Control/AthAllocators/AthAllocators/DataPool.icc new file mode 100644 index 00000000..27d1a63d --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/DataPool.icc @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------- +// .icc file for DataPool +//----------------------------------------------------------- +// includes: +#include <algorithm> +#include "GaudiKernel/System.h" +//----------------------------------------------------------- + +/// default constructor will initialize the pool with m_minRefCount +template <typename VALUE> +DataPool<VALUE>::DataPool(size_type n /*= 0*/, + size_type block_size /*= 0*/, + SG::Arena* arena /*= 0*/) + : m_handle (arena, + typename alloc_t::initParams<VALUE> (std::max (block_size, + static_cast<size_type>(1024u)))) +{ + if (n > 0) + m_handle.reserve (n); +} + +//----------------------------------------------------------- +/// release all elements in the pool. +template <typename VALUE> +void DataPool<VALUE>::reset() +{ + m_handle.reset(); +} + +/// free all memory in the pool. +template <typename VALUE> +void DataPool<VALUE>::erase() +{ + m_handle.erase(); +} +//----------------------------------------------------------- +// reserve space for the pool +// allocated elements will not be deleted. + +template <typename VALUE> +void DataPool<VALUE>::reserve(unsigned int size) +{ + m_handle.reserve (size); +} + + +template <typename VALUE> +unsigned int DataPool<VALUE>::capacity() +{ + return m_handle.stats().elts.total; +} + +template <typename VALUE> +unsigned int DataPool<VALUE>::allocated() +{ + return m_handle.stats().elts.inuse; +} + + +//----------------------------------------------------------- +/// begin iterators over pool +template <typename VALUE> +typename DataPool<VALUE>::iterator DataPool<VALUE>::begin() +{ + return iterator (m_handle.begin()); +} + +template <typename VALUE> +typename DataPool<VALUE>::const_iterator DataPool<VALUE>::begin() const +{ + return const_Iterator (m_handle.begin()); +} + +//----------------------------------------------------------- +/// the end() method will allow looping over only valid elements +/// and not over ALL elements of the pool + +template <typename VALUE> +typename DataPool<VALUE>::iterator DataPool<VALUE>::end() +{ + return iterator (m_handle.end()); +} + +template <typename VALUE> +typename DataPool<VALUE>::const_iterator DataPool<VALUE>::end() const { + return const_iterator (m_handle.end()); +} + +//----------------------------------------------------------- +/// obtain the next available element in pool by pointer +/// return as void* to minimize misuse, client usage is: +/// MyElement* m = new(pool->mem) MyElement(...); // pool is ptr +template <typename VALUE> +void* DataPool<VALUE>::mem() { + pointer p = nextElementPtr(); + return p; +} + +/// can also say: +/// MyElement* m = new ((*pool)()) MyElement(...); // pool = pointer +/// MyElement* m = new (pool()) MyElement(...); // pool = value + +template <typename VALUE> +void* DataPool<VALUE>::operator()() { + return mem(); +} + +//----------------------------------------------------------- +/// typename of pool +template <typename VALUE> +const std::string& DataPool<VALUE>::typeName() { + static std::string name = System::typeinfoName (typeid (VALUE)); + return name; +} + +//----------------------------------------------------------- +/// obtain the next available element in pool by pointer +/// pool is resized if reached its limit +template <typename VALUE> +inline +typename DataPool<VALUE>::pointer DataPool<VALUE>::nextElementPtr() +{ + return m_handle.allocate(); +} + + diff --git a/EDM/athena/Control/AthAllocators/AthAllocators/selection.xml b/EDM/athena/Control/AthAllocators/AthAllocators/selection.xml new file mode 100644 index 00000000..7bde1fab --- /dev/null +++ b/EDM/athena/Control/AthAllocators/AthAllocators/selection.xml @@ -0,0 +1,3 @@ +<lcgdict> + <class name="SG::ArenaHeader"/> +</lcgdict> diff --git a/EDM/athena/Control/AthAllocators/CMakeLists.txt b/EDM/athena/Control/AthAllocators/CMakeLists.txt new file mode 100644 index 00000000..f943ff4e --- /dev/null +++ b/EDM/athena/Control/AthAllocators/CMakeLists.txt @@ -0,0 +1,61 @@ +# $Id: CMakeLists.txt 729177 2016-03-11 14:32:18Z krasznaa $ +################################################################################ +# Package: AthAllocators +################################################################################ + +# Declare the package name: +atlas_subdir( AthAllocators ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + GaudiKernel + PRIVATE + AtlasTest/TestTools + Control/CxxUtils ) + +# External dependencies: +find_package( Boost COMPONENTS thread ) + +# Component(s) in the package: +atlas_add_library( AthAllocators AthAllocators/*.h AthAllocators/*.icc src/*.cxx + PUBLIC_HEADERS AthAllocators + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} GaudiKernel + PRIVATE_LINK_LIBRARIES CxxUtils ) + +atlas_add_dictionary( AthAllocatorsDict + AthAllocators/AthAllocatorsDict.h AthAllocators/selection.xml + LINK_LIBRARIES AthAllocators ) + +# Test(s) in the package: +macro( _simple_test name ) + atlas_add_test( ${name} + SOURCES test/${name}.cxx + LINK_LIBRARIES CxxUtils AthAllocators ) +endmacro( _simple_test ) + +_simple_test( ArenaAllocatorBase_test ) +_simple_test( ArenaBlockAllocatorBase_test ) +_simple_test( ArenaBlock_test ) +_simple_test( ArenaPoolAllocator_test ) +_simple_test( ArenaHeapAllocator_test ) +_simple_test( ArenaHandleBase_test ) +_simple_test( ArenaHandleBaseAllocT_test ) +_simple_test( ArenaHandleBaseT_test ) +_simple_test( ArenaHeader_test ) +_simple_test( ArenaCachingHandle_test ) +_simple_test( ArenaHandle_test ) +_simple_test( ArenaAllocatorCreator_test ) +_simple_test( ArenaAllocatorRegistry_test ) +_simple_test( Arena_test ) +_simple_test( ArenaBase_test ) +_simple_test( ArenaPoolSTLAllocator_test ) +_simple_test( ArenaHeapSTLAllocator_test ) +_simple_test( ArenaSharedHeapSTLAllocator_test ) + +atlas_add_test( DataPool_test + SOURCES test/DataPool_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthAllocators CxxUtils + EXTRA_PATTERNS "^IncidentSvc +DEBUG Adding|^HistogramPersis.* (INFO|DEBUG)|^JobOptionsSvc +INFO|DEBUG Property update for OutputLevel" + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) diff --git a/EDM/athena/Control/AthAllocators/cmt/requirements b/EDM/athena/Control/AthAllocators/cmt/requirements new file mode 100644 index 00000000..5129d5b7 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/cmt/requirements @@ -0,0 +1,49 @@ +package AthAllocators + +author scott snyder <snyder@bnl.gov> + +use AtlasPolicy AtlasPolicy-* +use GaudiInterface GaudiInterface-* External +use AtlasBoost AtlasBoost-* External + + +private +use CxxUtils CxxUtils-* Control +end_private + + +apply_pattern installed_library +library AthAllocators *.cxx + + +private +use TestTools TestTools-* AtlasTest + +apply_pattern UnitTest_run unit_test=ArenaAllocatorBase +apply_pattern UnitTest_run unit_test=ArenaBlockAllocatorBase +apply_pattern UnitTest_run unit_test=ArenaBlock +apply_pattern UnitTest_run unit_test=ArenaPoolAllocator +apply_pattern UnitTest_run unit_test=ArenaHeapAllocator +apply_pattern UnitTest_run unit_test=ArenaHandleBase +apply_pattern UnitTest_run unit_test=ArenaHandleBaseAllocT +apply_pattern UnitTest_run unit_test=ArenaHandleBaseT +apply_pattern UnitTest_run unit_test=ArenaHeader +apply_pattern UnitTest_run unit_test=ArenaCachingHandle +apply_pattern UnitTest_run unit_test=ArenaHandle +apply_pattern UnitTest_run unit_test=ArenaAllocatorCreator +apply_pattern UnitTest_run unit_test=ArenaAllocatorRegistry +apply_pattern UnitTest_run unit_test=Arena +apply_pattern UnitTest_run unit_test=ArenaBase +apply_pattern UnitTest_run unit_test=ArenaPoolSTLAllocator +apply_pattern UnitTest_run unit_test=ArenaHeapSTLAllocator +apply_pattern UnitTest_run unit_test=ArenaSharedHeapSTLAllocator +apply_pattern UnitTest_run unit_test=DataPool \ + extrapatterns="^IncidentSvc +DEBUG Adding|^HistogramPersis.* (INFO|DEBUG)|^JobOptionsSvc +INFO" + +macro_append DOXYGEN_INPUT " ../doc" + + +private +use AtlasReflex AtlasReflex-* External +apply_pattern lcgdict dict=AthAllocators selectionfile=selection.xml headerfiles="../AthAllocators/AthAllocatorsDict.h" + diff --git a/EDM/athena/Control/AthAllocators/ispellwords b/EDM/athena/Control/AthAllocators/ispellwords new file mode 100644 index 00000000..915b514e --- /dev/null +++ b/EDM/athena/Control/AthAllocators/ispellwords @@ -0,0 +1,732 @@ +personal_ws-1.1 en 698 +assoPointer +persistency +IdentifiableContainer +multi +toContainedElement +GaudiKernel +situ +someone's +refcnt +GENERATEINDEXINGPOLICIES +elementShortRef +originalSize +unary +blk +arg +objectContainer +dataID +bkt +Amram +endif +typeid +fooB +ForwardIndexingPolicy +JetCollection +resized +constr +PackedArray +const's +RandomAccessIterator +CompareAndPrint +del +IProxyDict +deallocate +dep +DVLNoBase +cassert +creat +ASHSTLAllocator +ness +Resizes +autoselect +doinit +setElement +DataVector +theAsso +addHostDObj +gaudi +Dreizin +scott +theAssociatedObjects +cmt +objIndex +assocIndex +dir +ArenaAllocatorRegistry +allocator's +persistifiable +InhVectorIntLink +functor +nclear +crc +elmts +ssnyder +Predwrapper +MessageSvc +DNC +readback +binet +theTrack +DL's +DataPool +Faz +newAssoc +fdl +GenerateIndexingPolicy +ConstDataVector +AtlasReflex +fangled +fdv +LongRef +pCont's +gcc +Ilija +HistogramPersis +absFluff +liint +getAssociations +allo +isDefault +utest +ArenaCachingHandle +depcy +nctor +ELs +CVS +ClassName +destructor +tTrack +elt +hashtable's +PlainPtrElementLink +ELV +DList +DSO +resetWithKeyAndIndex +DataLinkVector +ElemLink +resetWithKey +typedef +pbad +dum +firstAssoc +cxx +theStore +BaseContainer +persistified +dvl +endAssociation +ispellwords +ILink +endHostDObjs +shortRefs +shortrefs +GenParticleIndexing +Elsing +DV's +BinaryPredicate +anOther +FooDequeLink +moveHostDObjs +theObjects +FooDeque +ArenaBase +AtlasSEAL +FNV +NoBase +icc +iCtr +NOGAUDI +swapElement +defaultHeader +objectPointer +src's +StoreGateSvc +hashtable +CopyConstructible +findProxy +BeginEvent +GNUC +toPersistentDL +iff +firstAssObject +bitsize +pCopyDerFluff +findAssociationObjects +DataVectorBase +fdvlcopy +line'll +func +ArenaHandleBaseAllocT +asDataList +CLID's +CLIDs +convertable +fdlcopy +hoc +DHAVE +functionalities +addArena +dataGet +namespaces +StoreGate +IOSTREAMS +oldElem +DataProxy +paolo +eltest +jobOs +AssociationLinks +DataLink +RVersion +pAssoc +hpp +TODO +valgrind +DataProxyStorageBase +srini +getObject +ASSCONT +cerr +proxying +ASSOCONT +DataListBase +AthenaPOOL +Calafiura +MapIndexingPolicy +param +AssociationVector +IProxyDictWithPool +persistify +changeState +canReclear +doxygen +setHashAndIndex +runtime +lcg +args +DataList +DataPtrs +rebinder +theAssociations +inserters +uint +ndtor +DVLCast +theAssociationObjects +assoStore +AssociationVectorCollection +isStreamable +irt +resetTo +AssociationVectorIterator +wronglmint +pairtype +pdata +RemoveDataPtr +theType +printf +setStorableObject +ArenaHeapSTLAllocator +iJet +doRemap +toPersistable +OBJCONT +deallocation +iTracks +getFirstAssociation +SGFolder +AssociationLinkCollection +objectIter +lhs +storeName +ArenaBlockAllocatorBase +rvalue +DerivedFluff +ElemLinkVector +ArenaHeaderGaudiClear +mem +hasher +dobjs +assoIter +Quarrie +hasAssociations +assoContainer +dereferencing +cinquanta +IdentContIndexingPolicy +DVLDataBucket +ElementLinkVector +vers +PDTR +nav +Hong +forwardContainer +cinq +eltSize +AtlasBoost +CINT +typeinfoName +reverseIterators +ArenaPoolAllocator +kwd +ndx +resize +indexingPolicy +tradeoff +ClusterContainer +oldInt +getDataSourcePointer +MacOSX +NavigationToken +asso +PlainPtrStorage +bool +shortref +shortRef +dieci +DataMap +Nir +OBJTYPE +asDataVector +ArenaHeapAllocator +DataLinks +gmake +mLink +castfn +AssociationBaseCollection +clid +deps +LWG +namespace +IOHandler +ArenaAllocatorCreatorInit +pdf +pAssocs +dflt +dfluff +pDL +reflextion +typename +typeName +DVLIterator +iTrack +getDataSource +initParams +LXR +DataBucket +pDV +pJets +refCount +snyder +ASSOBJECT +initGaudi +Srini's +multimap +pTransient +DataBucketTrait +dict +ElemLinkRefs +interoperate +nreserve +lastAssObject +theAssoc +TrackContainer +init +minRefCount +impl +OwnershipPolicy +otherElemLinkRefs +AssociativeIndexingPolicy +DataVector's +oper +IsSTLSequence +findProxyFromKey +newAss +mutators +addTrack +IncidentSvc +makeIndex +sgkey +StrictWeakOrdering +lastTrack +ClassID +classID +calaf +rbegin +containsAssociation +SetIndexingPolicy +ifndef +assocPointer +BaseConstReference +pos +PtrVector +ret +pre +params +BList +theAssocs +ArenaAllocatorBase +Dufus +GaudiClear +ppvInterface +reextracted +lookup +arghh +rhs +pointee +maxRefCount +config +toPersistentState +intL +Sep +hostDObjs +ClassIDSvc +ptr +BVec +intV +pvp +getDataSourcePointerFromGaudi +RNG +pTracks +Metafunction +ArenaHandleBase +shortIterFromLong +tCluster +successFlag +genreflex +DataProxyStorage +DataProxyStorageData +theJet +ElementType +ELVDEBUG +PtrList +AllocatorCreatorBase +asStorable +ArenaSharedHeapSTLAllocator +AthenaKernel +ChangeLog +getLastAssocation +nblock +dvlinfo +DVLInfo +PlainPtrDataLink +src +cout +IDtype +pcopy +jobO +Vec +resizePool +TestTools +dtors +DataPtr +tdefs +enums +ArenaSTLAllocator +findHostDObj +DataList's +toIndexedElement +stl +sizeof +svc +cptr +sss +checkreq +dobj +Vukotic +packageinfo +frexp +str +setData +MyObj +iter +DVLEltBase +AssociationType +clidsvc +CLIDSvc +backNavigation +toPersistent +theCluster +mustClear +storable +IInterface +AssociationObjectIterator +DefaultKey +TSS +inlined +Rajagopalan +makeFunc +savannah +ArenaBlock +multiset +GeneratorObjects +reverseLookup +DefaultState +Obreshkov +pred +malloc +myassert +AthExStoreGateExamples +DVLInfoBase +setOwner +txt +myCluster +FIXME +LIBSTDCXX +ArenaAllocatorCreator +Gemmeren +makeAllocator +JetTrackAssociation +IOVSvc +prev +newElement +beginAssociation +specializable +removeHostDObj +toAccessible +RefVector +EndEvent +PersistentState +tinfo +myassertion +elcnv +ctor +struct +vpvp +dereference +allocvec +getDataRef +ElementParameter +fdvl +AthenaROOTAccess +ControlTest +objectIndex +iHost +emacs +alloc +pElem +riid +accessor +setValid +DataObject +makeCurrent +dpint +symLink +decls +ElementLink +bb +anAss +DataSource +linkOffset +linkoffset +lookups +refVector's +DPSB +isValid +ibadlint +ForwardIterator +assoIndex +firstTrack +NDEBUG +NULLs +templated +endl +br +getDataPtr +venti +eg +dl +mainpage +VirtBases +DefaultIndexingPolicy +utests +reportStr +fd +FooDataVectorLink +CxxUtils +ivint +findInContainer +dv +DVLTYPE +RehashPolicy +ElementProxy +theObject +fn +JetTrackAssociationCollection +SGASSERTERROR +checkForRemap +iliint +toTransient +anotherString +ctors +AssociationLink +FolderItem +IdentContIndex +dereferences +iptrlint +intLF +DataModel +getLastAssociation +IP +indices +multithreaded +sstream +intLL +ld +destructors +Elts +ownPolicy +tryELRemap +li +rvalues +DeclareIndexingPolicy +Koenig +IndexingPolicies +nd +xyz +Austern +delArena +TrackParticleContainer +minSize +toAccessibleState +storagePolicy +NavFourMon +ArenaHandle +ConstDataList +ok +TrackParticle +ChronoStatSvc +ElemLinkRef +ns +findAssociation +Compwrapper +proxied +gccxml +RegisterDVLEltBaseInit +badI +DataPoolTest +os +stdcont +stdCont +initializer +lastAssoc +DVec +ri +BaseInfo +sg +ElemLinks +ElemLink's +targ +DirSearchPath +ELVRef +intVF +headp +BidirectionalIterator +cplusplus +Tavori +SGElvRef +dtor +enum +schaffer +intVL +vd +ForwardContainerConcept +InUse +sz +WG +ArenaPoolSTLAllocator +inline +typedefs +typedef's +Vo +getE +vp +sgname +sgName +rObj +SequenceIndexing +setStorable +trenta +AssociationMap +abc +thinning's +newElem +jobOptions +getAssociationObjects +myarena +lvalues +CategoryOrTraversal +PTAss +accessors +Mytype +raiseInvalidErrorBase +MyElement +rdata +adaptors +toPersistentNomap +DVL's +endcode +aFoo +ftemplate +ExtractKey +ArenaHandleBaseT +defaultDataSource +IdentifiedState +lvalue +ElementHolder +adaptor +preload +ifdef +AssociationBase +theContext +AssociationObject +ArenaHeader +ElementLinks +toIdentified +wrongvint +AssociationObjects +Baz +overridable +const +SGTools +NULLLINK +DefaultKeyState +getDataSourcePointerFunc +libstdc +persistable +SGgetDataSource +allocator +Allocator +allocators +AthAllocators +ATLALLOCATORS +unallocated +doesn +hasn +isn +ve +shouldn +list2 +list1 +instantiations +ArenaSharedHeapSTLAllocators +wasn +inuse +elts +a1 +a2 +test1 +a3 +test2 +test3 +test4 +p1 +p2 +Payload2 +alloc2 +alloc1 +JobOptionsSvc +ain +resizing diff --git a/EDM/athena/Control/AthAllocators/share/ArenaAllocatorBase_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaAllocatorBase_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaAllocatorCreator_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaAllocatorCreator_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaAllocatorRegistry_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaAllocatorRegistry_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaBase_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaBase_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaBlockAllocatorBase_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaBlockAllocatorBase_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaBlock_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaBlock_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaCachingHandle_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaCachingHandle_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHandleBaseAllocT_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHandleBaseAllocT_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHandleBaseT_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHandleBaseT_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHandleBase_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHandleBase_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHandle_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHandle_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHeader_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHeader_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHeapAllocator_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHeapAllocator_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref new file mode 100644 index 00000000..76983460 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/EDM/athena/Control/AthAllocators/share/ArenaPoolAllocator_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaPoolAllocator_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref new file mode 100644 index 00000000..fadbf1d8 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref @@ -0,0 +1,4 @@ +test1 +test2 +test3 +test4 diff --git a/EDM/athena/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref b/EDM/athena/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref new file mode 100644 index 00000000..76983460 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/EDM/athena/Control/AthAllocators/share/Arena_test.ref b/EDM/athena/Control/AthAllocators/share/Arena_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthAllocators/share/DataPool_test.ref b/EDM/athena/Control/AthAllocators/share/DataPool_test.ref new file mode 100644 index 00000000..21159b5c --- /dev/null +++ b/EDM/athena/Control/AthAllocators/share/DataPool_test.ref @@ -0,0 +1,42 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/DataPool_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/user/s/ssnyder/atlas-work5/Control/DataModel/run/../share/DataPool_test.txt) +JobOptionsSvc INFO # (5,1): ApplicationMgr.DLLs += ["StoreGate"] +JobOptionsSvc INFO # (6,1): MessageSvc.OutputLevel = 2 +JobOptionsSvc INFO # (8,1): ApplicationMgr.ExtSvc += ["IncidentSvc", "ChronoStatSvc", "AuditorSvc"] +JobOptionsSvc INFO Job options successfully read in from ../share/DataPool_test.txt +ApplicationMgr DEBUG Getting my own properties +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v1r3p3) + running on lxplus446.cern.ch on Mon Apr 22 17:38:11 2013 +==================================================================================================================================== +ApplicationMgr INFO Successfully loaded modules : StoreGate +ApplicationMgr INFO Application Manager Configured successfully +ServiceManager DEBUG Initializing service IncidentSvc +IncidentSvc DEBUG Service base class initialized successfully +ServiceManager DEBUG Initializing service ChronoStatSvc +ChronoStatSvc DEBUG Service base class initialized successfully +ChronoStatSvc INFO Number of skipped events for MemStat-1 +ServiceManager DEBUG Initializing service AuditorSvc +AuditorSvc DEBUG Service base class initialized successfully +ServiceManager DEBUG Initializing service AppMgrRunable +AppMgrRunable DEBUG Service base class initialized successfully +ServiceManager DEBUG Initializing service EventLoopMgr +EventLoopMgr DEBUG Service base class initialized successfully +IncidentSvc DEBUG Adding [AbortEvent] listener '<unknown>' with priority 0 +EventDataSvc DEBUG Service base class initialized successfully +EventPersistenc... DEBUG Service base class initialized successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramDataSvc DEBUG Service base class initialized successfully +HistogramPersis... DEBUG 'CnvServices':[ 'RootHistSvc' ] +HistogramPersis... DEBUG Service base class initialized successfully +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready + *** DataPool test in progress: +IncidentSvc DEBUG Adding [BeginEvent] listener '<unknown>' with priority 100 + **** DataPool test successfully completed **** +ChronoStatSvc INFO Time User : Tot= 0 [us] #= 1 diff --git a/EDM/athena/Control/AthAllocators/share/DataPool_test.txt b/EDM/athena/Control/AthAllocators/share/DataPool_test.txt new file mode 100644 index 00000000..a47946e0 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/share/DataPool_test.txt @@ -0,0 +1,11 @@ +// common job opts for SG unit tests + +// $Id: DataPool_test.txt,v 1.1 2003-04-02 19:35:10 calaf Exp $ + +//ApplicationMgr.DLLs += { "StoreGate" }; +MessageSvc.OutputLevel = 2; + +ApplicationMgr.ExtSvc += {"IncidentSvc", "ChronoStatSvc", "AuditorSvc"}; + +//AuditorSvc.Auditors += {"ChronoAuditor", "MemStatAuditor"}; +//MemStatAuditor.OutputLevel = 4; diff --git a/EDM/athena/Control/AthAllocators/src/Arena.cxx b/EDM/athena/Control/AthAllocators/src/Arena.cxx new file mode 100644 index 00000000..df1c3ec5 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/Arena.cxx @@ -0,0 +1,155 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/Arena.cxx + * @author scott snyder + * @date May 2007 + * @brief Collection of memory allocators with a common lifetime. + * Out-of-line implementations. + */ + +#include "AthAllocators/Arena.h" +#include "AthAllocators/ArenaAllocatorBase.h" + +namespace SG { + + +/** + * @brief Constructor. + * @param name The name of this @c Arena; to use in reports. + * @param header The header with which this @c Arena is associated. + * If defaulted, the global default @c ArenaHeader will be used. + */ +Arena::Arena (const std::string& name, ArenaHeader* header /*= 0*/) + : m_header (header), + m_name (name) +{ + if (!m_header) + m_header = SG::ArenaHeader::defaultHeader(); + m_header->addArena (this); +} + + +/** + * @brief Destructor. + */ +Arena::~Arena() +{ + m_header->delArena (this); + for (size_t i = 0; i < m_allocs.size(); i++) + delete m_allocs[i]; +} + + +/** + * @brief reset all contained allocators. All elements will be freed. + */ +void Arena::reset() +{ + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) + m_allocs[i]->reset(); + } +} + + +/** + * @brief erase all contained allocators. All elements will be freed, + * and the memory returned to the system. + */ +void Arena::erase() +{ + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) + m_allocs[i]->erase(); + } +} + + +/** + * @brief Generate a report of the memory in use by this @c Arena. + * @param os The stream to which to write the report. + */ +void Arena::report (std::ostream& os) const +{ + bool first = true; + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) { + if (first) { + ArenaAllocatorBase::Stats::header (os); + os << std::endl; + first = false; + } + m_allocs[i]->report (os); + } + } +} + + +/** + * @brief Return statistics summed over all allocators in this @c Arena. + */ +const ArenaAllocatorBase::Stats& Arena::stats () const +{ + m_stats = ArenaAllocatorBase::Stats(); + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) { + m_stats += m_allocs[i]->stats(); + } + } + return m_stats; +} + + +/** + * @brief Return the @c ArenaHeader with which this @c Arena is associated. + */ +ArenaHeader* Arena::header() const +{ + return m_header; +} + + +/** + * @brief Return this @c Arena's name. + */ +const std::string& Arena::name() const +{ + return m_name; +} + + +/** + * @brief Make this @c Arena the current one for its @c ArenaHeader. + * @returns The previously current allocator vector. + */ +ArenaHeader::ArenaAllocVec_t* Arena::makeCurrent() +{ + return m_header->setAllocVec (&m_allocs); +} + + +/** + * @brief Constructor. Make @c a current. + * @param a The @c Arena to make current. + */ +Arena::Push::Push (Arena& a) + : m_header (a.header()), + m_allocs (a.makeCurrent()) +{ +} + + +/** + * @brief Destructor. Undoes the effect of the constructor. + */ +Arena::Push::~Push() +{ + m_header->setAllocVec (m_allocs); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaAllocatorBase.cxx b/EDM/athena/Control/AthAllocators/src/ArenaAllocatorBase.cxx new file mode 100644 index 00000000..466807f9 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaAllocatorBase.cxx @@ -0,0 +1,136 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaAllocatorBase.cxx + * @author scott snyder + * @date May 2007 + * @brief Common base class for arena allocator classes. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaAllocatorBase.h" +#include <ostream> +#include <iomanip> + + +namespace SG { + + +/** + * @brief Constructor for a single statistic. + */ +ArenaAllocatorBase::Stats::Stat::Stat() + : inuse (0), + free (0), + total (0) +{ +} + + +/** + * @brief Zero a statistic. + */ +void ArenaAllocatorBase::Stats::Stat::clear() +{ + inuse = free = total = 0; +} + + +/** + * @brief Accumulate a statistic. + * @param other The statistic to accumulate into this one. + */ +ArenaAllocatorBase::Stats::Stat& +ArenaAllocatorBase::Stats::Stat::operator+= (const Stat& other) +{ + inuse += other.inuse; + free += other.free; + total += other.total; + return *this; +} + + +/* (hide from doxygen) + * @brief Format a statistic structure. + * @param os The stream to which to write. + * @param stat The statistic structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats::Stat& stat) +{ + os << std::setw(7) << stat.inuse << "/" + << std::setw(7) << stat.free << "/" + << std::setw(7) << stat.total; + return os; +} + + +//=========================================================================== + + +/** + * @brief Zero a complete statistics block. + */ +void ArenaAllocatorBase::Stats::clear() +{ + elts.clear(); + bytes.clear(); + blocks.clear(); +} + + +/** + * @brief Accumulate a complete statistics block. + * @param other The statistics block to accumulate into this one. + */ +ArenaAllocatorBase::Stats& +ArenaAllocatorBase::Stats::operator+= (const Stats& other) +{ + elts += other.elts; + bytes += other.bytes; + blocks += other.blocks; + return *this; +} + + +/* (hide from doxygen) + * @brief Format a complete statistics structure. + * @param os The stream to which to write. + * @param stats The statistics structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats& stats) +{ + os << stats.elts << " " << stats.bytes << " " << stats.blocks; + return os; +} + + +/** + * @brief Write a header for the statistics report. + * @param os The stream to which to write. + */ +void ArenaAllocatorBase::Stats::header (std::ostream& os) +{ + os << "Elts InUse/Free/Total" + << " Bytes InUse/Free/Total Blocks InUse/Free/Total"; +} + + +//=========================================================================== + + +/** + * @brief Generate a report on the memory usage of this allocator. + * @param os Stream to which the report should be written. + */ +void ArenaAllocatorBase::report (std::ostream& os) const +{ + os << " " << stats() << " " << name() << std::endl; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx b/EDM/athena/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx new file mode 100644 index 00000000..48eaeb5c --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx @@ -0,0 +1,203 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file AthAllocators/src/ArenaAllocatorRegistry.cxx + * @author scott snyder + * @date May 2007 + * @brief Registry of allocator factories. + * Out-of-line implementation. + */ + +// xxx FIXME: not thread-safe. + +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include <vector> +#include <map> +#include <cassert> + + +namespace SG { + + +/** + * @brief ArenaAllocatorRegistry implementation class. + */ +class ArenaAllocatorRegistryImpl +{ +public: + /// Destructor. + ~ArenaAllocatorRegistryImpl(); + + + /** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ + size_t registerCreator (const std::string& name, + ArenaAllocatorCreator* creator); + + + /** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ + size_t lookup (const std::string& name); + + + /** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ + ArenaAllocatorBase* create (size_t i); + + +private: + /// Map from names to indices. + typedef std::map<std::string, size_t> map_t; + map_t m_map; + + /// Vector of factory instances. + std::vector<ArenaAllocatorCreator*> m_creators; +}; + + +/** + * @brief Destructor. + */ +ArenaAllocatorRegistryImpl::~ArenaAllocatorRegistryImpl() +{ + // Free the saved factory instances. + for (size_t i = 0; i < m_creators.size(); i++) + delete m_creators[i]; +} + + +/** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ +size_t +ArenaAllocatorRegistryImpl::registerCreator (const std::string& name, + ArenaAllocatorCreator* creator) +{ + // The name must not already exist. + assert (m_map.count (name) == 0); + + // The new index. + size_t i = m_creators.size(); + + // Remember the index and store the creator. + m_map[name] = i; + m_creators.push_back (creator); + return i; +} + + +/** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ +size_t ArenaAllocatorRegistryImpl::lookup (const std::string& name) +{ + map_t::iterator it = m_map.find (name); + if (it == m_map.end()) + return std::string::npos; + return it->second; +} + + +/** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ +ArenaAllocatorBase* ArenaAllocatorRegistryImpl::create (size_t i) +{ + assert (i < m_creators.size()); + return m_creators[i]->create(); +} + + +//========================================================================== + +/** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ +size_t +ArenaAllocatorRegistry::registerCreator (const std::string& name, + ArenaAllocatorCreator* creator) +{ + return m_impl->registerCreator (name, creator); +} + + +/** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ +size_t ArenaAllocatorRegistry::lookup (const std::string& name) +{ + return m_impl->lookup (name); +} + + +/** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ +ArenaAllocatorBase* ArenaAllocatorRegistry::create (size_t i) +{ + return m_impl->create (i); +} + + +/** + * @brief Return a pointer to the global @c ArenaAllocatorRegistry instance. + */ +ArenaAllocatorRegistry* ArenaAllocatorRegistry::instance() +{ + static ArenaAllocatorRegistry tmp; + return &tmp; +} + + +/** + * @brief Constructor. + */ +ArenaAllocatorRegistry::ArenaAllocatorRegistry() + : m_impl (new ArenaAllocatorRegistryImpl) +{ +} + + +/** + * @brief Destructor. + */ +ArenaAllocatorRegistry::~ArenaAllocatorRegistry() +{ + delete m_impl; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaBlock.cxx b/EDM/athena/Control/AthAllocators/src/ArenaBlock.cxx new file mode 100644 index 00000000..82c675b1 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaBlock.cxx @@ -0,0 +1,147 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaBlock.cxx + * @author scott snyder + * @date May 2007 + * @brief These are large blocks of memory that get allocated and + * divided up into smaller, uniform elements. + * Out-of-line implementation. + */ + + +#include "AthAllocators/ArenaBlock.h" +#include <cstdlib> + + +namespace SG { + + +/// Global number of blocks in use. +size_t ArenaBlock::s_nactive = 0; + + +/** + * @brief Create a new block. + * @param n The number of elements in the new block. + * @param elt_size The size in bytes of each element. + * @param ctor If non-null, call this function on each element + * in the new block. + */ +ArenaBlock* +ArenaBlock::newBlock (size_t n, size_t elt_size, func_t* ctor) +{ + size_t tot_size = n*elt_size + ArenaBlockBodyOffset; + ArenaBlock* p = reinterpret_cast<ArenaBlock*> (std::malloc (tot_size)); + ++s_nactive; + p->m_link = 0; + p->m_elt_size = elt_size; + p->m_size = n; + if (ctor) { + for (size_t i = 0; i < n; i++) + ctor (p->index (i, elt_size)); + } + return p; +} + + +/** + * @brief Destroy a block. + * @param p The block to destroy. + * @param dtor If non-null, call this function on each element in the block. + */ +void ArenaBlock::destroy (ArenaBlock* p, func_t* dtor) +{ + if (dtor) { + size_t elt_size = p->eltSize(); + size_t n = p->size(); + for (size_t i = 0; i < n; i++) + dtor (p->index (i, elt_size)); + } + --s_nactive; + std::free (p); +} + + +/** + * @brief Destroy all blocks in a list. + * @param p The first block to destroy. + * @param dtor If non-null, call this function on each element the blocks. + * + * Will destroy all blocks in the linked list headed by @c p. + */ +void +ArenaBlock::destroyList (ArenaBlock* p, func_t* dtor) +{ + while (p) { + ArenaBlock* next = p->link(); + destroy (p, dtor); + p = next; + } +} + + +/** + * @brief Concatenate two lists of blocks. + * @param headp Pointer to pointer to the head of the list. + * @param tail Pointer to list to append to the end. + * + * The list @c tail is appended to the end of the list @c *headp. + * (@c headp is a pointer-to-pointer to be able to handle the case + * of an empty list.) + */ +void ArenaBlock::appendList (ArenaBlock** link, ArenaBlock* tail) +{ + while (*link) + link = &(*link)->link(); + *link = tail; +} + + +/** + * @brief Call a function on elements in a list of blocks. + * @param p Pointer to the head of the list. + * @param func Function to apply. + * @param Number of elements in the first block on which + * to call the function. + * + * This will loop through the elements in all blocks on the list, + * calling @c func. In the first block, we apply the function + * only to the first @c n elements. In subsequent blocks, the + * function is applied to all elements. + */ +void ArenaBlock::applyList (ArenaBlock* p, + func_t* func, + size_t n) +{ + if (!p) return; + size_t elt_size = p->eltSize(); + if (n > p->size()) + n = p->size(); + while (1) { + for (size_t i = 0; i < n; i++) + func (p->index (i, elt_size)); + p = p->link(); + if (!p) break; + n = p->size(); + } +} + + +/** + * @brief Return the per-block memory overhead, in bytes. + * + * This tries to include malloc overhead as well, but that may just + * be an estimate. Don't rely on this to be exact. + */ +size_t ArenaBlock::overhead() +{ + // The extra size_t is a guesstimate of malloc overhead. + return ArenaBlockBodyOffset + sizeof (size_t); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx b/EDM/athena/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx new file mode 100644 index 00000000..de10b438 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx @@ -0,0 +1,185 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlockAllocatorBase.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaBlockAllocatorBase.cxx + * @author scott snyder + * @date May 2007 + * @brief Common functionality for block-oriented allocators. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include "AthAllocators/ArenaBlock.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ +ArenaBlockAllocatorBase::ArenaBlockAllocatorBase (const Params& params) + : m_params (params), + m_blocks (0), + m_freeblocks (0) +{ +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +void ArenaBlockAllocatorBase::reserve (size_t size) +{ + if (size > m_stats.elts.total) { + // Growing the pool. + // Make a new block of the required size (but not less than nblock). + size_t sz = size - m_stats.elts.total; + if (sz < m_params.nblock) + sz = m_params.nblock; + ArenaBlock* newblock = ArenaBlock::newBlock (sz, m_params.eltSize, + m_params.constructor); + + // Update statistics (others are derived in stats()). + ++m_stats.blocks.free; + ++m_stats.blocks.total; + m_stats.elts.total += sz; + + // Add to the free list. + newblock->link() = m_freeblocks; + m_freeblocks = newblock; + } + else { + // Shrinking the pool. + // Loop while we can get rid of the first free block. + while (size < m_stats.elts.total && + m_freeblocks && + m_freeblocks->size() <= (m_stats.elts.total - size)) + { + // Remove it from the free list. + ArenaBlock* p = m_freeblocks; + m_freeblocks = m_freeblocks->link(); + + // Update statistics (others are derived in stats()). + m_stats.elts.total -= p->size(); + --m_stats.blocks.free; + --m_stats.blocks.total; + + // Free the block. + ArenaBlock::destroy (p, m_params.destructor); + } + } +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaBlockAllocatorBase::erase() +{ + // Do we need to run clear() on the allocated elements? + // If so, do so via reset(). + if (m_params.mustClear && m_params.clear) + reset(); + + // Kill the block lists (both free and in use). + ArenaBlock::destroyList (m_blocks, m_params.destructor); + ArenaBlock::destroyList (m_freeblocks, m_params.destructor); + m_blocks = m_freeblocks = 0; + + // Reset statistics. + m_stats.clear(); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +const ArenaAllocatorBase::Stats& ArenaBlockAllocatorBase::stats() const +{ + // Calculate derived statistics. + m_stats.elts.free = m_stats.elts.total - m_stats.elts.inuse; + m_stats.bytes.inuse = m_stats.elts.inuse * m_params.eltSize + + m_stats.blocks.inuse * ArenaBlock::overhead(); + m_stats.bytes.total = m_stats.elts.total * m_params.eltSize + + m_stats.blocks.total * ArenaBlock::overhead(); + m_stats.bytes.free = m_stats.elts.free * m_params.eltSize + + m_stats.blocks.free * ArenaBlock::overhead(); + return m_stats; +} + + +/** + * @brief Return the name of this allocator. + */ +const std::string& ArenaBlockAllocatorBase::name() const +{ + return m_params.name; +} + + +/** + * @brief Return this allocator's parameters. + */ +const ArenaAllocatorBase::Params& +ArenaBlockAllocatorBase::params() const +{ + return m_params; +} + + +/** + * @brief Return an empty block, either newly-allocated or from the + * free list. Update statistics appropriately. + */ +ArenaBlock* ArenaBlockAllocatorBase::getBlock() +{ + ArenaBlock* newblock = m_freeblocks; + if (newblock) { + // There's something on the free list. Remove it and update statistics. + m_freeblocks = newblock->link(); + --m_stats.blocks.free; + } + else { + // Otherwise, we need to make a new block. + newblock = ArenaBlock::newBlock (m_params.nblock, m_params.eltSize, + m_params.constructor); + m_stats.elts.total += m_params.nblock; + ++m_stats.blocks.total; + } + // Finish updating statistics. + // (Remaining ones are computed in stats().) + ++m_stats.blocks.inuse; + + // Link it into the in-use list and return. + newblock->link() = m_blocks; + m_blocks = newblock; + return newblock; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaHandleBase.cxx b/EDM/athena/Control/AthAllocators/src/ArenaHandleBase.cxx new file mode 100644 index 00000000..09c15254 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaHandleBase.cxx @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaHandleBase.cxx + * @author scott snyder + * @date May 2007 + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + */ + + +#include "AthAllocators/ArenaHandleBase.h" +#include "AthAllocators/ArenaAllocatorBase.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +ArenaHandleBase::ArenaHandleBase (ArenaHeader* header, size_t index) +{ + // If the supplied header is null, use the global default. + if (!header) + header = ArenaHeader::defaultHeader(); + + // Get the allocator. + m_allocator = header->allocator (index); +} + + +/** + * @brief Free all allocated elements (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are returned to the + * free state. @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaHandleBase::reset() +{ + return baseAllocator()->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system + * (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaHandleBase::erase() +{ + return baseAllocator()->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator + * (in the current Arena). + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +void ArenaHandleBase::reserve (size_t size) +{ + return baseAllocator()->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator, + * for the current Arena. + */ +const ArenaAllocatorBase::Stats& ArenaHandleBase::stats() const +{ + return baseAllocator()->stats(); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaHeader.cxx b/EDM/athena/Control/AthAllocators/src/ArenaHeader.cxx new file mode 100644 index 00000000..36a20304 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaHeader.cxx @@ -0,0 +1,218 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaHeader.cxx + * @author scott snyder + * @date May 2007 + * @brief Proxy for a group of Arenas. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaBase.h" +#include <algorithm> +#include <ostream> +#include <sstream> +#include <cassert> + + +namespace SG { + + +void null_allocvec_deleter (ArenaHeader::ArenaAllocVec_t*) {} + + +/** + * @brief Constructor. + */ +ArenaHeader::ArenaHeader() + // m_allocvec doesn't own the vectors to which it points. + // Need to pass in a dummy deleter to prevent them from being deleted. + : m_allocvec (null_allocvec_deleter), + m_ownedAllocvec (0) +{ +} + + +/** + * @brief Destructor. + * + * This will clean up any memory allocated in the default Arena. + */ +ArenaHeader::~ArenaHeader() +{ + if (m_ownedAllocvec) { + for (size_t i = 0 ; i < m_ownedAllocvec->size(); i++) + delete (*m_ownedAllocvec)[i]; + delete m_ownedAllocvec; + } + + // We don't own this. + m_allocvec.release(); +} + + +/** + * @brief Set the current Arena. + * @param allocvec New vector of Allocator instances. + * @return The previous vector. + * + * This sets the notion of the current Arena. + */ +ArenaHeader::ArenaAllocVec_t* +ArenaHeader::setAllocVec (ArenaAllocVec_t* allocvec) +{ + ArenaAllocVec_t* ret = m_allocvec.get(); + m_allocvec.release(); + m_allocvec.reset (allocvec); + return ret; +} + + +/** + * @brief Add a new Arena to the group. + * @param a The Arena to add. + */ +void ArenaHeader::addArena (ArenaBase* a) +{ + std::lock_guard<std::mutex> lock (m_mutex); + m_arenas.push_back (a); +} + + +/** + * @brief Remove an Arena from the group. + * @param a The Arena to remove. + * + * Will trip an assertion if the Arena is not in the group. + */ +void ArenaHeader::delArena (ArenaBase* a) +{ + std::lock_guard<std::mutex> lock (m_mutex); + std::vector<ArenaBase*>::iterator it = + std::find (m_arenas.begin(), m_arenas.end(), a); + assert (it != m_arenas.end()); + m_arenas.erase (it); +} + + +/** + * @brief Generate a report of all Arenas in the group. + * @param os Stream to which to send a report. + */ +void ArenaHeader::report (std::ostream& os) const +{ + std::lock_guard<std::mutex> lock (m_mutex); + // All Allocators in the group. + for (size_t i = 0; i < m_arenas.size(); i++) { + os << "=== " << m_arenas[i]->name() << " ===" << std::endl; + m_arenas[i]->report (os); + } + + // The default Arena. + if (m_ownedAllocvec) { + os << "=== default ===" << std::endl; + ArenaAllocatorBase::Stats::header (os); + os << std::endl; + for (size_t i = 0; i < m_ownedAllocvec->size(); i++) { + if ((*m_ownedAllocvec)[i]) + (*m_ownedAllocvec)[i]->report (os); + } + } +} + + +/** + * @brief Generate a report of all Arenas in the group, and return + * the result as a string. + * + * We have this in addition to @c report() in order to make it easier + * to call from scripting languages. + */ +std::string ArenaHeader::reportStr() const +{ + std::ostringstream s; + report (s); + return s.str(); +} + + +/** + * @brief Call @c reset on all Allocators in the current Arena. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaHeader::reset() +{ + if (m_allocvec.get()) { + for (size_t i = 0; i < m_allocvec->size(); i++) { + if ((*m_allocvec)[i]) + (*m_allocvec)[i]->reset(); + } + } +} + + +/** + * @brief Return the global default Header instance. + */ +ArenaHeader* ArenaHeader::defaultHeader() +{ + static ArenaHeader head; + return &head; +} + + +/** + * @brief Make a new Allocator for index i. + * @param i The index of the Allocator. + * + * The Allocator vector was empty for index @c i. Make an appropriate + * new Allocator, store it in the vector, and return it. Will trip + * an assertion if the index is not valid. + */ +ArenaAllocatorBase* ArenaHeader::makeAllocator (size_t i) +{ + // If we don't have an Arena set, use the default one. + if (!m_allocvec.get()) { + std::lock_guard<std::mutex> lock (m_mutex); + + // Create the default Arena if needed. + if (!m_ownedAllocvec) + m_ownedAllocvec = new ArenaAllocVec_t; + + // Install the default Arena. + m_allocvec.reset (m_ownedAllocvec); + + // See if the index is now in the default Arena. + if (i < m_allocvec->size()) { + ArenaAllocatorBase* allocbase = (*m_allocvec)[i]; + if (allocbase) return allocbase; + } + } + + // We have to create a new Allocator. + // Make sure there's room in the vector. + if (m_allocvec->size() <= i) + m_allocvec->resize (i+1); + + // Create the Allocator, using the Registry. + ArenaAllocatorBase* alloc = + ArenaAllocatorRegistry::instance()->create (i); + + // Install it in the vector. + (*m_allocvec)[i] = alloc; + + return alloc; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaHeapAllocator.cxx b/EDM/athena/Control/AthAllocators/src/ArenaHeapAllocator.cxx new file mode 100644 index 00000000..9d9e546d --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaHeapAllocator.cxx @@ -0,0 +1,162 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaHeapAllocator.cxx + * @author scott snyder + * @date May 2007 + * @brief Heap-based allocator. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <vector> +#include <algorithm> +#include <cassert> + + +namespace SG { + + +/** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ +ArenaHeapAllocator::ArenaHeapAllocator (const Params& params) + : ArenaBlockAllocatorBase (params), + m_freeptr (0) +{ + // Consistency check. + assert (params.linkOffset + sizeof (pointer) <= params.eltSize); +} + + +/** + * @brief Destructor. This will free all the Allocator's storage. + */ +ArenaHeapAllocator::~ArenaHeapAllocator() +{ + erase(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaHeapAllocator::reset() +{ + if (!m_blocks) return; + if (m_params.clear) { + if (m_params.canReclear || m_freeptr == 0) { + // Just call clear() on all blocks --- allocated or not. + ArenaBlock::applyList (m_blocks, m_params.clear, m_blocks->size()); + } + else { + // We can only call clear() on allocated blocks. + slowClear(); + } + } + + // Move all blocks back to the free list. + ArenaBlock::appendList (&m_freeblocks, m_blocks); + + // Reset state. + m_blocks = 0; + m_freeptr = 0; + m_stats.elts.inuse = 0; + m_stats.blocks.free += m_stats.blocks.inuse; + m_stats.blocks.inuse = 0; +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaHeapAllocator::erase() +{ + ArenaBlockAllocatorBase::erase(); + m_freeptr = 0; +} + + +/** + * @brief Add more free elements to the pool, and allocate a new element. + */ +ArenaHeapAllocator::pointer ArenaHeapAllocator::refill() +{ + // Get a new block. + ArenaBlock* newblock = getBlock(); + + // Set up the links for the new free elements. + pointer lastelt = 0; + size_t sz = newblock->size(); + size_t elt_size = newblock->eltSize(); + for (size_t i=1; i < sz; i++) { + pointer elt = newblock->index (i, elt_size); + link(elt) = lastelt; + lastelt = elt; + } + // Set the free pointer to the next-to-last one. + m_freeptr = newblock->index (sz-1, elt_size); + + // And return the last one. + return newblock->index (0, elt_size); +} + + +/** + * @brief Call @c clear() for all allocated elements. + */ +void ArenaHeapAllocator::slowClear() +{ + // Make a list of all free elements, in sorted order. + std::vector<pointer> free_ptrs; + free_ptrs.reserve (m_stats.elts.total - m_stats.elts.inuse); + for (pointer p = m_freeptr; p; p = link(p)) + free_ptrs.push_back (p); + std::sort (free_ptrs.begin(), free_ptrs.end()); + + // Make a list of all used blocks, in sorted order. + std::vector<ArenaBlock*> blocks; + for (ArenaBlock* p = m_blocks; p; p = p->link()) + blocks.push_back (p); + std::sort (blocks.begin(), blocks.end()); + + // Walk through both of these lists. + // For each block, walk through its elements, and call @c clear + // for those not on the free list. + std::vector<pointer>::iterator pi = free_ptrs.begin(); + std::vector<pointer>::iterator pi_end = free_ptrs.end(); + std::vector<ArenaBlock*>::iterator bi = blocks.begin(); + std::vector<ArenaBlock*>::iterator bi_end = blocks.end(); + func_t* clear = m_params.clear; + for (; bi != bi_end; bi++) { + ArenaBlock& bl = **bi; + size_t sz = bl.size(); + size_t elt_size = bl.eltSize(); + for (size_t i = 0; i < sz; i++) { + pointer ptr = bl.index (i, elt_size); + if (pi != pi_end && ptr == *pi) + ++pi; + else + clear (ptr); + } + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaPoolAllocator.cxx b/EDM/athena/Control/AthAllocators/src/ArenaPoolAllocator.cxx new file mode 100644 index 00000000..104520c9 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaPoolAllocator.cxx @@ -0,0 +1,292 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaPoolAllocator.cxx + * @author scott snyder + * @date May 2007 + * @brief Pool-based allocator. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + + +namespace SG { + + +/** + * @brief Helper: common code for advancing an iterator. + * @param base Element pointer. + * @param block Block pointer. + */ +inline +ArenaPoolAllocator::pointer +ArenaPoolAllocator_iterator_increment (ArenaPoolAllocator::pointer base, + ArenaBlock* & block) +{ + // If we haven't yet reached the start of this block, move the iterator + // back one. + if (base > block->index(0,0)) + return base - block->eltSize(); + else { + // Move to the previous block. + block = block->link(); + if (block) + return block->index (block->size()-1, block->eltSize()); + else + return 0; + } +} + + +/** + * @brief Move the iterator forward. + */ +void ArenaPoolAllocator::iterator::increment() +{ + this->base_reference() = + ArenaPoolAllocator_iterator_increment (this->base_reference(), m_block); +} + + +/** + * @brief Move the iterator forward. + */ +void ArenaPoolAllocator::const_iterator::increment() +{ + ArenaPoolAllocator::pointer base = + const_cast<ArenaPoolAllocator::pointer> (this->base_reference()); + base = ArenaPoolAllocator_iterator_increment (base, m_block); + this->base_reference() = base; +} + + +/** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ +ArenaPoolAllocator::ArenaPoolAllocator (const Params& params) + : ArenaBlockAllocatorBase (params), + m_ptr (0), + m_end (0) +{ +} + + +/** + * @brief Destructor. This will free all the Allocator's storage. + */ +ArenaPoolAllocator::~ArenaPoolAllocator() +{ + erase(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaPoolAllocator::reset() +{ + // Clear each block in turn. + while (m_blocks) + clearBlock(); + + // Check that things are consistent. + assert (m_stats.elts.inuse == 0); + assert (m_ptr == 0); + assert (m_end == 0); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaPoolAllocator::erase() +{ + // Delete all the blocks. + ArenaBlockAllocatorBase::erase(); + + // Reset pointers. + m_ptr = m_end = 0; +} + + +/** + * @brief Reset pool back to a previous state. + * @param blk The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + */ +void ArenaPoolAllocator::resetTo (pointer blk) +{ + // Clear the topmost block, as long as it doesn't contain the sought-after + // pointer. + ArenaBlock* p = m_blocks; + assert (p != 0); + size_t elt_size = p->eltSize(); + while (p && !(blk >= p->index(0, elt_size) && + blk < p->index(p->size(), elt_size))) + { + clearBlock(); + p = m_blocks; + } + + // We'll trip this if the supplied pointer wasn't in any block. + assert (p != 0); + + // If the element is at the beginning of this block, just clear the whole + // thing. + if (blk == p->index(0, elt_size)) + clearBlock(); + else { + // Otherwise, we need to clear some of the elements in this block. + // See if we need to call @c clear. + func_t* clear = m_params.clear; + if (clear) { + // Yeah, we do. Call @c clear on each element in turn. + while (m_ptr > blk) { + m_ptr -= elt_size; + clear (m_ptr); + --m_stats.elts.inuse; + } + // We'll trip this if the supplied pointer wasn't on an element + // boundary. + assert (m_ptr == blk); + } + else { + // We don't need to call @c clear. + // So we can do it the fast way --- just reset pointers. + m_stats.elts.inuse -= (m_ptr - blk) / elt_size; + m_ptr = blk; + } + } +} + + +/** + * @brief Starting pool iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ +ArenaPoolAllocator::iterator ArenaPoolAllocator::begin() +{ + // If @c m_ptr is one set, it is one more than the last allocated element. + return iterator (m_ptr ? m_ptr - m_params.eltSize : 0, m_blocks); +} + + +/** + * @brief Starting pool const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ +ArenaPoolAllocator::const_iterator ArenaPoolAllocator::begin() const +{ + // If @c m_ptr is one set, it is one more than the last allocated element. + return const_iterator (m_ptr ? m_ptr - m_params.eltSize : 0, m_blocks); +} + + +/** + * @brief Ending pool iterator. + */ +ArenaPoolAllocator::iterator ArenaPoolAllocator::end() +{ + // Use a null iterator to signal the end. + return iterator (); +} + + +/** + * @brief Ending pool const iterator. + */ +ArenaPoolAllocator::const_iterator ArenaPoolAllocator::end() const +{ + // Use a null iterator to signal the end. + return const_iterator (); +} + + +/** + * @brief Add more free elements to the pool. + */ +void ArenaPoolAllocator::refill() +{ + // Get a new block. + ArenaBlock* newblock = getBlock(); + + // Set the pointers. + m_ptr = newblock->index (0, m_params.eltSize); + m_end = newblock->index (newblock->size(), m_params.eltSize); +} + + +/** + * @brief Reset all elements in the topmost block, and move the block + * to the free list. + */ +void ArenaPoolAllocator::clearBlock() +{ + // The topmost block. + ArenaBlock* p = m_blocks; + + // Nothing to do if there are no allocated blocks! + if (!p) return; + + size_t elt_size = p->eltSize(); + + // The first element of the block. + pointer base = p->index(0, elt_size); + + // Do we need to call @c clear? If so, call it on all allocated elements + // in this block. + func_t* clear = m_params.clear; + if (clear) { + pointer elt = base; + while (elt < m_ptr) { + clear (elt); + elt += elt_size; + } + } + + // Update statistics. + --m_stats.blocks.inuse; + ++m_stats.blocks.free; + m_stats.elts.inuse -= (m_ptr - base) / elt_size; + + // Move the block from the allocated to the free list. + m_blocks = p->link(); + p->link() = m_freeblocks; + m_freeblocks = p; + p = m_blocks; + + // Reset the pointers. + if (p) { + m_ptr = m_end = p->index(p->size()); + } + else { + m_ptr = m_end = 0; + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx b/EDM/athena/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx new file mode 100644 index 00000000..aa1966fc --- /dev/null +++ b/EDM/athena/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.cxx 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + */ + + +#include "AthAllocators/ArenaSharedHeapSTLAllocator.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param owner Address of the object that owns this Header. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ +ArenaSharedHeapSTLHeader::ArenaSharedHeapSTLHeader (const void* owner, + int nblock, + const std::string& name) + : m_owner (owner), + m_nblock (nblock), + m_name (name) +{ +} + + +/** + * @brief Destructor. + * + * Destroy all the allocators we own. + */ +ArenaSharedHeapSTLHeader::~ArenaSharedHeapSTLHeader() +{ + size_t sz = m_allocators.size(); + for (size_t i = 0; i < sz; i++) + delete m_allocators[i]; +} + + +/** + * @brief Return allocator statistics summed over all our owned allocators. + */ +ArenaAllocatorBase::Stats ArenaSharedHeapSTLHeader::totstats() const +{ + ArenaAllocatorBase::Stats stats; + size_t sz = m_allocators.size(); + for (size_t i = 0; i < sz; i++) { + if (m_allocators[i]) + stats += m_allocators[i]->stats(); + } + return stats; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx new file mode 100644 index 00000000..ca62319f --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx @@ -0,0 +1,155 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaAllocatorBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaAllocatorBase. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> +#include <sstream> + + +int testcount = 0; + +class Test +{ +public: + Test() { ++testcount; } + ~Test() { --testcount; } + + int x = 0; +}; + +class Test2 + : public Test +{ +public: + void clear() { testcount += 10; } +}; + + +class ArenaTestAllocator + : public SG::ArenaAllocatorBase +{ +public: + virtual void reset() {} + virtual void erase() {} + virtual void reserve (size_t /*size*/) { } + virtual const ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } + ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + + +void set_stat (SG::ArenaAllocatorBase::Stats::Stat& stat, int x) +{ + stat.inuse = x; + stat.free = x+1; + stat.total = x+2; +} + +void set_stats (SG::ArenaAllocatorBase::Stats& stats, int x) +{ + set_stat (stats.elts, x); + set_stat (stats.bytes, x + 1000); + set_stat (stats.blocks, x + 2000); +} + + +void check_stat_sum (const SG::ArenaAllocatorBase::Stats::Stat& stat1, + const SG::ArenaAllocatorBase::Stats::Stat& stat2, + const SG::ArenaAllocatorBase::Stats::Stat& stat3) +{ + assert (stat1.inuse + stat2.inuse == stat3.inuse); + assert (stat1.free + stat2.free == stat3.free); + assert (stat1.total + stat2.total == stat3.total); +} +void check_stats_sum (const SG::ArenaAllocatorBase::Stats& stats1, + const SG::ArenaAllocatorBase::Stats& stats2, + const SG::ArenaAllocatorBase::Stats& stats3) +{ + check_stat_sum (stats1.elts, stats2.elts, stats3.elts); + check_stat_sum (stats1.bytes, stats2.bytes, stats3.bytes); + check_stat_sum (stats1.blocks, stats2.blocks, stats3.blocks); +} + +void check_stat_zero (const SG::ArenaAllocatorBase::Stats::Stat& stat) +{ + assert (stat.inuse == 0); + assert (stat.free == 0); + assert (stat.total == 0); +} +void check_stats_zero (const SG::ArenaAllocatorBase::Stats& stats) +{ + check_stat_zero (stats.elts); + check_stat_zero (stats.bytes); + check_stat_zero (stats.blocks); +} + + +int main() +{ + ArenaTestAllocator ata; + ata.reset(); + ata.erase(); + ata.reserve(0); + assert (ata.stats().elts.inuse == 0); + assert (ata.name() == ""); + + SG::ArenaAllocatorBase::Params params = + SG::ArenaAllocatorBase::initParams<Test>(500, "foo"); + assert (params.name == "foo"); + assert (params.nblock == 500); + assert (params.eltSize == sizeof (Test)); + char* p = new char[sizeof(Test)]; + assert (testcount == 0); + params.constructor (p); + assert (testcount == 1); + params.destructor (p); + assert (testcount == 0); + + params = SG::ArenaAllocatorBase::initParams<Test2>(500); + assert (params.clear == 0); + params = SG::ArenaAllocatorBase::initParams<Test2, true>(500); + assert (params.clear != 0); + params.clear (p); + assert (testcount == 10); + + params = SG::ArenaAllocatorBase::initParams<int>(500); + assert (params.constructor == 0); + assert (params.destructor == 0); + + SG::ArenaAllocatorBase::Stats stats1; + SG::ArenaAllocatorBase::Stats stats2; + + set_stats (stats1, 1); + set_stats (stats2, 20); + + SG::ArenaAllocatorBase::Stats stats3 = stats1; + stats3 += stats2; + check_stats_sum (stats1, stats2, stats3); + stats3.clear(); + check_stats_zero (stats3); + + ata.m_name = "foo"; + assert (ata.name() == "foo"); + set_stats (ata.m_stats, 1); + std::ostringstream os; + ata.report (os); + assert (os.str() == " 1/ 2/ 3 1001/ 1002/ 1003 2001/ 2002/ 2003 foo\n"); + std::ostringstream os2; + stats1.header (os2); + assert (os2.str() == "Elts InUse/Free/Total Bytes InUse/Free/Total Blocks InUse/Free/Total"); + + delete [] p; + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx new file mode 100644 index 00000000..e878e9fa --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorCreator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaAllocatorCreator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaAllocatorCreator. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaAllocatorCreator.h" +#include <cassert> + +class Test + : public SG::ArenaAllocatorCreator +{ +public: + virtual SG::ArenaAllocatorBase* create() { return 0; } +}; + + +int main() +{ + Test test; + assert (test.create() == 0); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx new file mode 100644 index 00000000..281f8bcc --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorRegistry_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaAllocatorRegistry_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaAllocatorRegistry. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include <cassert> + +class Alloc + : public SG::ArenaAllocatorBase +{ +public: + Alloc(int x) { m_stats.elts.total = x; } + virtual void reset() {} + virtual void erase() {} + virtual void reserve (size_t /*size*/) {} + virtual const std::string& name() const { return m_name; } + virtual const SG::ArenaAllocatorBase::Stats& stats() const + { return m_stats; } +private: + SG::ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + +class Creator + : public SG::ArenaAllocatorCreator +{ +public: + Creator (int x) : m_x (x) {} + virtual SG::ArenaAllocatorBase* create() { return new Alloc (m_x); } +private: + int m_x; +}; + +void test1() +{ + SG::ArenaAllocatorRegistry* reg = + SG::ArenaAllocatorRegistry::instance(); + assert (reg->lookup ("foo") == std::string::npos); + assert (reg->registerCreator ("foo", new Creator (0)) == 0); + assert (reg->registerCreator ("bar", new Creator (1)) == 1); + assert (reg->lookup ("foo") == 0); + assert (reg->lookup ("bar") == 1); + assert (reg->create(0)->stats().elts.total == 0); + assert (reg->create(1)->stats().elts.total == 1); +} + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaBase_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaBase_test.cxx new file mode 100644 index 00000000..63f7a021 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaBase_test.cxx @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaBase. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaBase.h" +#include <ostream> +#include <sstream> +#include <cassert> + + +std::string xname = "bar"; + +class TestArena + : public SG::ArenaBase +{ +public: + virtual void report (std::ostream& os) const { os << "foo"; } + virtual const std::string& name() const { return xname; } +}; + + +void test1() +{ + TestArena t; + std::ostringstream s; + t.report (s); + assert (s.str() == "foo"); + assert (t.name() == "bar"); +} + + +int main() +{ + test1(); + return 0; +} + diff --git a/EDM/athena/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx new file mode 100644 index 00000000..e46534b5 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx @@ -0,0 +1,111 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlockAllocatorBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaBlockAllocatorBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaBlockAllocatorBase. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + + +struct Payload +{ + Payload(); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + //static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + y = 0; + //v.push_back (x); +} + +Payload::~Payload() +{ + //v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +//std::vector<int> Payload::v; + + +class TestAlloc + : public SG::ArenaBlockAllocatorBase +{ +public: + TestAlloc (const Params& params) : SG::ArenaBlockAllocatorBase (params){} + virtual void reset() {} +}; + + +void test_stats (const SG::ArenaBlockAllocatorBase& bab, + size_t nblock, + size_t nelt) +{ + size_t elt_size = bab.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + const SG::ArenaAllocatorBase::Stats& stats = bab.stats(); + assert (stats.blocks.total == nblock); + assert (stats.blocks.inuse == 0); + assert (stats.blocks.free == nblock); + assert (stats.elts.total == nelt); + assert (stats.elts.inuse == 0); + assert (stats.elts.free == nelt); + assert (stats.bytes.total == nelt * elt_size + nblock * block_ov); + assert (stats.bytes.inuse == 0); + assert (stats.bytes.free == nelt * elt_size + nblock * block_ov); +} + + +void test1() +{ + TestAlloc bab + (SG::ArenaAllocatorBase::initParams<Payload, true> (100, "foo")); + assert (bab.name() == "foo"); + assert (bab.params().name == "foo"); + test_stats (bab, 0, 0); + + bab.reserve (1000); + test_stats (bab, 1, 1000); + + bab.reserve (500); + test_stats (bab, 1, 1000); + + bab.reserve (0); + test_stats (bab, 0, 0); + + bab.reserve (500); + test_stats (bab, 1, 500); + bab.reserve (1000); + test_stats (bab, 2, 1000); + bab.reserve (500); + test_stats (bab, 1, 500); + bab.erase(); + test_stats (bab, 0, 0); +} + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaBlock_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaBlock_test.cxx new file mode 100644 index 00000000..3c1df22c --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaBlock_test.cxx @@ -0,0 +1,144 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaBlock_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaBlock. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaBlock.h" +#include <cassert> +#include <vector> + +//========================================================================== + +struct Payload +{ + Payload(); + ~Payload(); + static void constructor (char*); + static void destructor (char*); + static void scan (char*); + + int x; + static int n; + static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + v.push_back (x); +} + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::constructor (char* p) +{ + new (p) Payload; +} + +void Payload::destructor (char* p) +{ + reinterpret_cast<Payload*>(p)->~Payload(); +} + +void Payload::scan (char* p) +{ + Payload::v.push_back (reinterpret_cast<Payload*>(p)->x); +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +const size_t elt_size = sizeof (Payload); + +int& word (SG::ArenaBlock* bl, size_t i=0) +{ + return *(int*)bl->index (i, elt_size); +} + +Payload& payload (SG::ArenaBlock* bl, size_t i=0) +{ + return *(Payload*)bl->index (i, elt_size); +} + +void test1() +{ + assert (SG::ArenaBlock::nactive() == 0); + SG::ArenaBlock* bl = SG::ArenaBlock::newBlock (20, elt_size, 0); + assert (SG::ArenaBlock::nactive() == 1); + assert (bl->overhead() > 0 && bl->overhead() < 100); + assert (bl->size() == 20); + assert (bl->eltSize() == elt_size); + word(bl, 0) = 0; + word(bl, 1) = 0; + assert ((char*)bl->index(1) - + (char*)bl->index(0) == (int)elt_size); + assert (bl->link() == 0); + bl->link() = bl; + assert (bl->link() == bl); + SG::ArenaBlock::destroy (bl, 0); + assert (SG::ArenaBlock::nactive() == 0); +} + + +void test2() +{ + SG::ArenaBlock* b1 = SG::ArenaBlock::newBlock (20, elt_size, + Payload::constructor); + SG::ArenaBlock* b2 = SG::ArenaBlock::newBlock (20, elt_size, + Payload::constructor); + SG::ArenaBlock* b3 = SG::ArenaBlock::newBlock (20, elt_size, + Payload::constructor); + int i = 0; + for (size_t j = 0; j < b1->size(); j++) { + assert (payload(b1, j).x == i); + assert (Payload::v[i] == i); + ++i; + } + b1->link() = b2; + SG::ArenaBlock::appendList (&b1, b3); + assert (payload(b1).x == 0); + assert (payload(b1->link()).x == 20); + assert (payload(b1->link()->link()).x == 40); + assert(b1->link()->link()->link() == 0); + SG::ArenaBlock* bb = 0; + SG::ArenaBlock::appendList (&bb, b1); + assert (bb == b1); + + Payload::v.clear(); + SG::ArenaBlock::applyList (b1, Payload::scan, 10); + assert (Payload::v.size() == 50); + for (size_t j = 0; j < 10; ++j) { + assert (Payload::v[j] == (int)j); + } + for (size_t j = 10; j < Payload::v.size(); ++j) { + assert (Payload::v[j] == (int)j+10); + } + + Payload::v.clear(); + SG::ArenaBlock::destroyList (b1, Payload::destructor); + assert (Payload::v.size() == 60); + for (size_t j = 0; j < Payload::v.size(); ++j) { + assert (Payload::v[j] == -(int)j); + } +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaCachingHandle_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaCachingHandle_test.cxx new file mode 100644 index 00000000..ac0f86f7 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaCachingHandle_test.cxx @@ -0,0 +1,240 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaCachingHandle_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaCachingHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaCachingHandle. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaCachingHandle.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + +int count = 0; +int nctor = 0; +int ndtor = 0; +int nclear = 0; +struct Payload +{ + int x; + int y; + Payload() { x = ++count; y = 0; ++nctor; } + ~Payload() { ++ndtor; } + void clear() { y = 0; ++nclear; } +}; + +void test1() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaCachingHandle<Payload, SG::ArenaPoolAllocator> Handtype; + SG::ArenaHeader head; + SG::Arena arena ("a", &head); + SG::Arena::Push push (arena); + + Handtype hand (&arena, + SG::ArenaPoolAllocator::initParams<Payload, true>(50)); + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + size_t elt_size = hand.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + std::vector<int> v; + for (Handtype::iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + const Handtype& chand = hand; + v.clear(); + for (Handtype::const_iterator ii = chand.begin(); + ii != chand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + v.clear(); + for (Handtype::const_iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 100); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i + 1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 100); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + Handtype hand2 (&head, 0); + + hand2.resetTo (ptrs[50]); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 150); + assert (hand2.stats().elts.inuse == 50); + assert (hand2.stats().elts.free == 50); + assert (hand2.stats().elts.total == 100); + assert (hand2.stats().blocks.inuse == 1); + assert (hand2.stats().blocks.free == 1); + assert (hand2.stats().blocks.total == 2); + assert (hand2.stats().bytes.inuse == 50 * elt_size + block_ov); + assert (hand2.stats().bytes.free == 50 * elt_size + block_ov); + assert (hand2.stats().bytes.total == 100 * elt_size + 2*block_ov); + + hand2.erase(); + assert (nctor == 100); + assert (ndtor == 100); + assert (nclear == 150); + assert (hand2.stats().elts.inuse == 0); + assert (hand2.stats().elts.free == 0); + assert (hand2.stats().elts.total == 0); +} + + +void test2() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaCachingHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + Handtype hand (SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + size_t elt_size = hand.params().eltSize; + assert (elt_size > sizeof (Payload)); + + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + //printf ("%d %d %d\n", nctor, ndtor, nclear); + //printf ("%d %d %d\n", hand.stats().elts.inuse, hand.stats().elts.free, hand.stats().elts.total()); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + for (size_t i = 0; i < ptrs.size(); i+=2) { + hand.free (ptrs[i]); + } + + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 50); + assert (hand.stats().elts.inuse == 50); + assert (hand.stats().elts.free == 50); + assert (hand.stats().elts.total == 100); + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 150); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 150); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); +} + + +void test3() +{ + typedef + SG::ArenaCachingHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + SG::ArenaHeader head; + Handtype hand (&head, + SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + + hand.reserve (100); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx new file mode 100644 index 00000000..96ee5f7a --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseAllocT_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandleBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandleBaseAllocT. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHandleBaseAllocT.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> + +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + TestAlloc (const Params& params) : m_params (params) {} + virtual void reset() {} + virtual void erase() {} + virtual void reserve(size_t) {} + virtual const std::string& name() const { return m_params.name; } + virtual const Stats& stats() const { return m_stats; } + const Params& params() const { return m_params; } + int foo() { return 42; } + + static SG::ArenaAllocatorBase* makeAllocator (const Params& params) + { return new TestAlloc (params); } + +private: + Stats m_stats; + Params m_params; +}; + +class TestHandle + : public SG::ArenaHandleBaseAllocT<TestAlloc> +{ +public: + typedef SG::ArenaHandleBaseAllocT<TestAlloc> Base; + TestHandle (SG::ArenaHeader* header, size_t index) + : Base (header, index) {} + TestHandle (SG::ArenaHeader* header, const Creator& creator) + : Base (header, creator) {} + int foo() { return allocator()->foo(); } +}; + +void test1() +{ + SG::ArenaHeader head; + typedef typename TestAlloc::initParams<int> defaultParams_t; + TestAlloc::Params params = defaultParams_t (1000, "foo"); + TestHandle hand (&head, TestHandle::Creator (static_cast<TestAlloc*>(0), + params)); + assert (hand.params().name == "foo"); + + TestHandle hand2 (&head, 0); + assert (hand2.foo() == 42); +} + +int main() +{ + test1(); + return 0; +} + diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx new file mode 100644 index 00000000..f7e53b55 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx @@ -0,0 +1,184 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseT_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandleBaseT_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandleBaseT. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHandleBaseT.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> +#include <iterator> + + +class Payload +{ +public: + Payload (int i) : m_x (i) {} + int m_x; +}; + + +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + TestAlloc (const Params& params); + virtual void reset() {} + virtual void erase() {} + virtual void reserve(size_t) {} + virtual const std::string& name() const { return m_params.name; } + virtual const Stats& stats() const { return m_stats; } + const Params& params() const { return m_params; } + int foo() { return 42; } + void free (pointer p) { ptmp = p; } + void resetTo (pointer p) { ptmp = p+1; } + static pointer ptmp; + + class const_iterator; + + class iterator + : public std::iterator<std::forward_iterator_tag, Payload> + { + public: + iterator (std::vector<Payload>::iterator it) + : m_it (it) {} + reference operator*() const { return *m_it; } + iterator& operator++() { m_it++; return *this; } + bool operator== (const iterator& other) const + { return m_it == other.m_it; } + + friend class const_iterator; + + private: + std::vector<Payload>::iterator m_it; + }; + + class const_iterator + : public std::iterator<std::forward_iterator_tag, const Payload> + { + public: + const_iterator (std::vector<Payload>::const_iterator it) + : m_it (it) {} + const_iterator (TestAlloc::iterator it) + : m_it (&*it) {} + reference operator*() const { return *m_it; } + const_iterator& operator++() { m_it++; return *this; } + bool operator== (const const_iterator& other) const + { return m_it == other.m_it; } + bool operator== (const TestAlloc::iterator& other) const + { return m_it == other.m_it; } + + private: + std::vector<Payload>::const_iterator m_it; + }; + + iterator begin() { return iterator (m_vec.begin()); } + iterator end() { return iterator (m_vec.end()); } + const_iterator begin() const { return const_iterator (m_vec.begin()); } + const_iterator end() const { return const_iterator (m_vec.end()); } + + static SG::ArenaAllocatorBase* makeAllocator (const Params& params) + { return new TestAlloc (params); } + +private: + std::vector<Payload> m_vec; + Stats m_stats; + Params m_params; +}; + + +TestAlloc::TestAlloc (const Params& params) + : m_params (params) +{ + for (int i = 0; i < 10; i++) + m_vec.push_back (i); +} + +TestAlloc::pointer TestAlloc::ptmp = 0; + +class TestHandle + : public SG::ArenaHandleBaseT<Payload, TestAlloc> +{ +public: + typedef SG::ArenaHandleBaseT<Payload, TestAlloc> Base; + TestHandle (SG::ArenaHeader* header, size_t index) + : Base (header, index) {} + TestHandle (SG::ArenaHeader* header, const Creator& creator) + : Base (header, creator) {} + int foo() { return allocator()->foo(); } +}; + +void test1() +{ + SG::ArenaHeader head; + TestAlloc::Params params; + params.name = "foo"; + + // These are never used, but fully initialize anyway in order to avoid + // ubsan errors. + params.eltSize = 0; + params.minSize = 0; + params.nblock = 0; + params.linkOffset = 0; + params.constructor = nullptr; + params.destructor = nullptr; + params.clear = nullptr; + params.canReclear = false; + params.mustClear = false; + + TestHandle hand (&head, TestHandle::Creator (static_cast<TestAlloc*>(0), + params)); + assert (hand.params().name == "foo"); + TestHandle::pointer p = reinterpret_cast<TestHandle::pointer>(0x1234); + hand.free (p); + assert (TestAlloc::ptmp == reinterpret_cast<TestAlloc::pointer>(p)); + hand.resetTo (p); + assert (TestAlloc::ptmp == reinterpret_cast<TestAlloc::pointer>(p)+1); + + TestHandle hand2 (&head, 0); + int i = 0; + for (TestHandle::iterator it = hand2.begin(); + it != hand2.end(); + ++it) + { + assert ((*it).m_x == i); + assert (it->m_x == i); + ++i; + } + + i = 0; + const TestHandle& chand = hand2; + for (TestHandle::const_iterator it = chand.begin(); + it != chand.end(); + ++it) + { + assert ((*it).m_x == i); + assert (it->m_x == i); + ++i; + } + + i = 0; + for (TestHandle::const_iterator it = hand2.begin(); + it != hand2.end(); + ++it) + { + assert ((*it).m_x == i); + assert (it->m_x == i); + ++i; + } +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHandleBase_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHandleBase_test.cxx new file mode 100644 index 00000000..b183c4f3 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHandleBase_test.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandleBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandleBase. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaHandleBase.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + +struct Payload +{ + int x; +}; + +void test1() +{ + SG::ArenaHeader header; + SG::ArenaHeader::ArenaAllocVec_t vec; + vec.push_back (new SG::ArenaPoolAllocator + (SG::ArenaPoolAllocator::initParams<Payload>(1000))); + header.setAllocVec (&vec); + SG::ArenaHandleBase test (&header, 0); + size_t elt_size = + dynamic_cast<SG::ArenaPoolAllocator*>(vec[0])->params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 0); + assert (test.stats().elts.total == 0); + test.reserve (10); + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 1000); + assert (test.stats().elts.total == 1000); + assert (test.stats().blocks.inuse == 0); + assert (test.stats().blocks.free == 1); + assert (test.stats().blocks.total == 1); + assert (test.stats().bytes.inuse == 0); + assert (test.stats().bytes.free == 1000 * elt_size + block_ov); + assert (test.stats().bytes.total == 1000 * elt_size + block_ov); + test.reset (); + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 1000); + assert (test.stats().elts.total == 1000); + test.erase (); + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 0); + assert (test.stats().elts.total == 0); + + SG::ArenaHeader::defaultHeader()->setAllocVec (&vec); + SG::ArenaHandleBase test2 (0, 0); + test2.reserve (10); + assert (test2.stats().elts.inuse == 0); + assert (test2.stats().elts.free == 1000); + assert (test2.stats().elts.total == 1000); +} + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHandle_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHandle_test.cxx new file mode 100644 index 00000000..733d2137 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHandle_test.cxx @@ -0,0 +1,236 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandle_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandle. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHandle.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + +int count = 0; +int nctor = 0; +int ndtor = 0; +int nclear = 0; +struct Payload +{ + int x; + int y; + Payload() { x = ++count; y = 0; ++nctor; } + ~Payload() { ++ndtor; } + void clear() { y = 0; ++nclear; } +}; + +void test1() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaHandle<Payload, SG::ArenaPoolAllocator> Handtype; + SG::ArenaHeader head; + SG::Arena arena ("a", &head); + SG::Arena::Push push (arena); + + + Handtype hand (&arena, + SG::ArenaPoolAllocator::initParams<Payload, true>(50)); + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + std::vector<int> v; + for (Handtype::iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + const Handtype& chand = hand; + v.clear(); + for (Handtype::const_iterator ii = chand.begin(); + ii != chand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + v.clear(); + for (Handtype::const_iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + p->y = i + 1; + ptrs.push_back (p); + } + assert (nctor == 200); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + Handtype hand2 (&head, 0); + + hand2.resetTo (ptrs[50]); + assert (nctor == 200); + assert (ndtor == 150); + assert (nclear == 00); + assert (hand2.stats().elts.inuse == 50); + assert (hand2.stats().elts.free == 50); + assert (hand2.stats().elts.total == 100); + + hand2.erase(); + assert (nctor == 200); + assert (ndtor == 200); + assert (nclear == 0); + assert (hand2.stats().elts.inuse == 0); + assert (hand2.stats().elts.free == 0); + assert (hand2.stats().elts.total == 0); +} + + +void test2() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + Handtype hand (SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + size_t elt_size = hand.params().eltSize; + assert (elt_size == sizeof (Payload)); + size_t block_ov = SG::ArenaBlock::overhead(); + + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + for (size_t i = 0; i < ptrs.size(); i+=2) { + hand.free (ptrs[i]); + } + assert (nctor == 100); + assert (ndtor == 50); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 50); + assert (hand.stats().elts.free == 50); + assert (hand.stats().elts.total == 100); + assert (hand.stats().blocks.inuse == 2); + assert (hand.stats().blocks.free == 0); + assert (hand.stats().blocks.total == 2); + assert (hand.stats().bytes.inuse == 50 * elt_size + 2 * block_ov); + assert (hand.stats().bytes.free == 50 * elt_size); + assert (hand.stats().bytes.total == 100 * elt_size + 2 * block_ov); + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 200); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); +} + + +void test3() +{ + typedef + SG::ArenaHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + SG::ArenaHeader head; + Handtype hand (&head, + SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + + hand.reserve (100); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHeader_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHeader_test.cxx new file mode 100644 index 00000000..58702bf4 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHeader_test.cxx @@ -0,0 +1,122 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHeader_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHeader. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaBase.h" +#include <cassert> +#include <ostream> + +std::string reset; +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + TestAlloc (int x, const std::string& name) + : m_name (name) { m_stats.bytes.total = x; } + virtual void reset() { ::reset = m_name; } + virtual void erase() {} + virtual void reserve (size_t /*size*/) {} + virtual const SG::ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } +private: + SG::ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + +class Creator + : public SG::ArenaAllocatorCreator +{ +public: + Creator (int x) : m_x (x) {} + virtual SG::ArenaAllocatorBase* create() + { return new TestAlloc (m_x, "creat"); } +private: + int m_x; +}; + + +class TestArena + : public SG::ArenaBase +{ +public: + TestArena (const std::string& name, int x) : m_name (name), m_x (x) {} + virtual void report (std::ostream& os) const + { os << "foo " << m_x << "\n"; } + virtual const std::string& name() const { return m_name; } +private: + std::string m_name; + int m_x; +}; + + +void test1() +{ + SG::ArenaHeader::ArenaAllocVec_t vec1; + vec1.resize (10); + vec1[2] = new TestAlloc (0, "a"); + SG::ArenaHeader::ArenaAllocVec_t vec2; + vec2.resize (10); + vec2[5] = new TestAlloc (1, "b"); + + SG::ArenaHeader* head = SG::ArenaHeader::defaultHeader(); + assert (head->setAllocVec(&vec1) == 0); + assert (head->allocator(2) == vec1[2]); + assert (head->setAllocVec(&vec2) == &vec1); + assert (head->allocator(5) == vec2[5]); + head->reset(); + assert (reset == "b"); + + SG::ArenaHeader::ArenaAllocVec_t vec3; + assert (head->setAllocVec(0) == &vec2); + SG::ArenaAllocatorRegistry* reg = + SG::ArenaAllocatorRegistry::instance(); + size_t i = reg->registerCreator ("foo", new Creator (1)); + assert (i == 0); + assert (head->allocator(i)->stats().bytes.total == 1); +} + + +void test2() +{ + SG::ArenaHeader head; + TestArena a1 ("a1", 1); + TestArena a2 ("a2", 2); + head.addArena (&a1); + head.addArena (&a2); + std::string s = head.reportStr(); + assert (s == "=== a1 ===\n\ +foo 1\n\ +=== a2 ===\n\ +foo 2\n"); + head.delArena (&a1); + assert (head.allocator(0)->stats().bytes.total == 1); + s = head.reportStr(); + assert (s == "=== a2 ===\n\ +foo 2\n\ +=== default ===\n\ +Elts InUse/Free/Total Bytes InUse/Free/Total Blocks InUse/Free/Total\n\ + 0/ 0/ 0 0/ 0/ 1 0/ 0/ 0 creat\n"); + +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx new file mode 100644 index 00000000..493a64c3 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx @@ -0,0 +1,218 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHeapAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHeapAllocator. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <vector> +#include <cassert> +#include <algorithm> + +//========================================================================== + +int nclear; +struct Payload +{ + Payload(); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + y = 0; + v.push_back (x); +} + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; + ++nclear; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +void test1() +{ + SG::ArenaHeapAllocator aha + (SG::ArenaHeapAllocator::initParams<Payload, true>(100, "foo")); + assert (aha.name() == "foo"); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 0); + assert (aha.stats().elts.total == 0); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 0); + size_t elt_size = aha.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + int nptr = 987; + std::vector<Payload*> ptrs; + for (int i=0; i < nptr; i++) { + Payload* p = reinterpret_cast<Payload*> (aha.allocate()); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 1000); + for (int i=0; i < 1000; ++i) { + assert (Payload::v[i] == i); + } + assert (aha.stats().elts.inuse == 987); + assert (aha.stats().elts.free == 13); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 10); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 10); + + for (size_t i = 0; i < ptrs.size(); i += 2) + aha.free ((char*)ptrs[i]); + assert (aha.stats().elts.inuse == 493); + assert (aha.stats().elts.free == 507); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 10); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 10); + for (size_t i = 0; i < ptrs.size(); i += 2) + assert (ptrs[i]->y == 0); + for (size_t i = 0; i < 300; i++) + ptrs.push_back (reinterpret_cast<Payload*>(aha.allocate())); + //printf ("%d %d %d\n", aha.stats().elts.inuse, aha.stats().elts.free, aha.stats().elts.total); + assert (aha.stats().elts.inuse == 793); + assert (aha.stats().elts.free == 207); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 10); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 10); + + assert (aha.stats().bytes.inuse == (793 * elt_size + 10 * block_ov)); + assert (aha.stats().bytes.free == 207 * elt_size); + assert (aha.stats().bytes.total == (1000 * elt_size + 10 * block_ov)); + + aha.reset(); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 1000); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 10); + assert (aha.stats().blocks.total == 10); + + ptrs.clear(); + for (size_t i = 0; i < 300; i++) + ptrs.push_back (reinterpret_cast<Payload*>(aha.allocate())); + assert (aha.stats().elts.inuse == 300); + assert (aha.stats().elts.free == 700); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 3); + assert (aha.stats().blocks.free == 7); + assert (aha.stats().blocks.total == 10); + + aha.reserve (550); + assert (aha.stats().elts.inuse == 300); + assert (aha.stats().elts.free == 300); + assert (aha.stats().elts.total == 600); + assert (aha.stats().blocks.inuse == 3); + assert (aha.stats().blocks.free == 3); + assert (aha.stats().blocks.total == 6); + + aha.reserve (1000); + //printf ("%d %d %d\n", aha.stats().elts.inuse, aha.stats().elts.free, aha.stats().elts.total); + assert (aha.stats().elts.inuse == 300); + assert (aha.stats().elts.free == 700); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 3); + assert (aha.stats().blocks.free == 4); + assert (aha.stats().blocks.total == 7); + + Payload::v.clear(); + aha.erase(); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 0); + assert (aha.stats().elts.total == 0); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 0); + assert (Payload::v.size() == 1000); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i = 0; i < 700; i++) { + assert (Payload::v[i] == (int)i-1399); + //printf ("%d %d\n", Payload::v[i], i); + } + for (size_t i = 700; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i-999); + } +} + + +void test2() +{ + SG::ArenaHeapAllocator::Params params = + SG::ArenaHeapAllocator::initParams<Payload, true>(100); + params.mustClear = true; + params.canReclear = false; + SG::ArenaHeapAllocator aha (params); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 0); + assert (aha.stats().elts.total == 0); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 0); + + nclear = 0; + std::vector<Payload*> ptrs; + for (int i=0; i < 987; i++) { + Payload* p = reinterpret_cast<Payload*> (aha.allocate()); + ptrs.push_back (p); + p->y = 2*p->x; + } + for (size_t i = 0; i < ptrs.size(); i+=2) { + aha.free ((char*)ptrs[i]); + assert (ptrs[i]->y == 0); + ptrs[i]->y = 1; + } + aha.reset(); + assert (nclear == 987); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 1000); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 10); + assert (aha.stats().blocks.total == 10); + + for (size_t i = 0; i < ptrs.size(); i++) { + if ((i&1) != 0) + assert (ptrs[i]->y == 0); + else + assert (ptrs[i]->y == 1); + } +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx new file mode 100644 index 00000000..3c573e47 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx @@ -0,0 +1,265 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapSTLAllocator_test.cxx,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +/** + * @file AthAllocators/test/ArenaHeapSTLAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov 2011 + * @brief Regression tests for ArenaHeapSTLAllocator. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaHeapSTLAllocator.h" +#include "boost/assign/list_of.hpp" +#include <list> +#include <vector> +#include <cassert> +#include <iostream> + +using boost::assign::list_of; + + + +//========================================================================== + +struct Payload +{ + Payload(int = 0); + Payload(const Payload& p); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload(int the_y) +{ + x = n++; + y = the_y; + v.push_back (x); +} + +Payload::Payload (const Payload& p) + : x (p.x), + y (p.y) +{ + v.push_back (x); +} + + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +// Test generic specialization. +void test1() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test1\n"; + + SG::ArenaHeapSTLAllocator<Payload> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + + SG::ArenaHeapSTLAllocator<Payload> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + + SG::ArenaHeapSTLAllocator<Payload*, int> a3 (100, "a3"); + assert (a3.nblock() == 100); + assert (a3.name() == "a3"); + + SG::ArenaHeapSTLAllocator<Payload, int> a4 (a3); + assert (a4.nblock() == 100); + assert (a4.name() == "a3"); + assert (a4.poolptr() != 0); + + { + Payload p; + Payload& pr = p; + const Payload& pcr = p; + assert (a4.address (pr) == &p); + assert (a4.address (pcr) == &p); + } + assert (Payload::n == 1); + assert (Payload::v.size() == 2); + Payload::v.clear(); + + std::vector<Payload*> pv; + for (int i=0; i < 10; i++) + pv.push_back (a4.allocate (1)); + + assert (Payload::n == 1); + assert (Payload::v.size() == 0); + + assert (a4.max_size() == 1); + + a4.construct (pv[0], Payload(10)); + a4.destroy (pv[0]); + + assert (Payload::n == 2); + std::vector<int> exp1 = list_of(1)(1)(-1)(-1); + assert (Payload::v == exp1); + Payload::v.clear(); + + for (int i=0; i < 9; i++) { + if (i > 0) + assert (pv[i] != pv[i-1]); + a4.deallocate (pv[i], 1); + } + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 100); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 100); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(5000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 5000); + + assert (Payload::n == 2); + assert (Payload::v.size() == 0); +} + + +// Test vetoed specialization. +void test2() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test2\n"; + + SG::ArenaHeapSTLAllocator<int, int> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + assert (a1.poolptr() == 0); + + SG::ArenaHeapSTLAllocator<int, int> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + assert (a2.poolptr() == 0); + + a2.reset(); + a2.erase(); + a2.reserve(10); + assert (a2.stats().elts.total == 0); + + SG::ArenaHeapSTLAllocator<Payload, int> a3 (500, "a3"); + a3.reserve (1000); + SG::ArenaHeapSTLAllocator<int> a4 (a3); + assert (a4.nblock() == 500); + assert (a4.name() == "a3"); + assert (a4.poolptr() == a3.poolptr()); + + (void)a3.allocate (1); + assert (a3.stats().elts.inuse == 1); + assert (a3.stats().elts.total == 1000); + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 1000); + assert (&a3.stats() == &a4.stats()); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(1000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + int* p = a4.allocate (2, 0); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.deallocate (p, 2); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +// In-situ test. +void test3() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test3\n"; + + typedef std::list<int, SG::ArenaHeapSTLAllocator<int> > list_t; + + list_t::allocator_type allo (500, "allo"); + list_t list (allo); + + for (int i = 0; i < 10; i++) + list.push_back (i); + + assert (list.size() == 10); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 10); + + for (list_t::iterator i = list.begin(); + i != list.end(); + ++i) + { + i = list.erase (i); + if (i == list.end()) break; + } + + assert (list.size() == 5); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 5); + + list.clear(); + assert (list.size() == 0); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 0); + + list.get_allocator().reset(); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 0); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx new file mode 100644 index 00000000..7c705cc1 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx @@ -0,0 +1,262 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaPoolAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaPoolAllocator. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <vector> +#include <cassert> +#include <algorithm> + +//========================================================================== + +struct Payload +{ + Payload(); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + y = 0; + v.push_back (x); +} + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +void test1() +{ + SG::ArenaPoolAllocator apa + (SG::ArenaPoolAllocator::initParams<Payload, true>(100, "foo")); + assert (apa.name() == "foo"); + assert (apa.stats().elts.inuse == 0); + assert (apa.stats().elts.free == 0); + assert (apa.stats().elts.total == 0); + assert (apa.stats().blocks.inuse == 0); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 0); + assert (apa.params().eltSize == sizeof (Payload)); + + int nptr = 987; + std::vector<Payload*> ptrs; + for (int i=0; i < nptr; i++) { + Payload* p = reinterpret_cast<Payload*> (apa.allocate()); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 1000); + for (int i=0; i < 1000; ++i) { + assert (Payload::v[i] == i); + } + assert (apa.stats().elts.inuse == 987); + assert (apa.stats().elts.free == 13); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 10); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 10); + + Payload::v.clear(); + apa.reset(); + assert (apa.stats().elts.inuse == 0); + assert (apa.stats().elts.free == 1000); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 0); + assert (apa.stats().blocks.free == 10); + assert (apa.stats().blocks.total == 10); + + for (int i=0; i < 300; i++) { + Payload* p = reinterpret_cast<Payload*> (apa.allocate()); + assert (p->y == 0); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 0); + assert (apa.stats().elts.inuse == 300); + assert (apa.stats().elts.free == 700); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 3); + assert (apa.stats().blocks.free == 7); + assert (apa.stats().blocks.total == 10); + + apa.allocate(); + std::vector<int> vv; + for (SG::ArenaPoolAllocator::iterator ii = apa.begin(); + ii != apa.end(); + ++ii) + { + vv.push_back (reinterpret_cast<Payload*> (&*ii)->x); + } + std::sort (vv.begin(), vv.end()); + assert (vv.size() == 301); + for (size_t jj = 0; jj < vv.size(); jj++) { + assert (vv[jj] == (int)jj); + } + + vv.clear(); + const SG::ArenaPoolAllocator& capa = apa; + for (SG::ArenaPoolAllocator::const_iterator ii = capa.begin(); + ii != capa.end(); + ++ii) + { + vv.push_back (reinterpret_cast<const Payload*> (&*ii)->x); + } + std::sort (vv.begin(), vv.end()); + assert (vv.size() == 301); + for (size_t jj = 0; jj < vv.size(); jj++) { + assert (vv[jj] == (int)jj); + } + + vv.clear(); + for (SG::ArenaPoolAllocator::const_iterator ii = apa.begin(); + ii != apa.end(); + ++ii) + { + vv.push_back (reinterpret_cast<const Payload*> (&*ii)->x); + } + std::sort (vv.begin(), vv.end()); + assert (vv.size() == 301); + for (size_t jj = 0; jj < vv.size(); jj++) { + assert (vv[jj] == (int)jj); + } + + Payload::v.clear(); + apa.reset(); + for (int i=0; i < 400; i++) { + Payload* p = reinterpret_cast<Payload*> (apa.allocate()); + assert (p->y == 0); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 0); + assert (apa.stats().elts.inuse == 400); + assert (apa.stats().elts.free == 600); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 6); + assert (apa.stats().blocks.total == 10); + + Payload::v.clear(); + apa.reserve (550); + assert (apa.stats().elts.inuse == 400); + assert (apa.stats().elts.free == 200); + assert (apa.stats().elts.total == 600); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 2); + assert (apa.stats().blocks.total == 6); + assert (Payload::v.size() == 400); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i=0; i < 100; i++) { + assert (Payload::v[i] == (int)i-799); + } + for (size_t i=100; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i-799); + } + + Payload::v.clear(); + apa.reserve (950); + assert (apa.stats().elts.inuse == 400); + assert (apa.stats().elts.free == 550); + assert (apa.stats().elts.total == 950); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 3); + assert (apa.stats().blocks.total == 7); + assert (Payload::v.size() == 350); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i=0; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i+1000); + } + + Payload::v.clear(); + apa.erase(); + assert (Payload::v.size() == 950); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i=0; i < 550; i++) { + assert (Payload::v[i] == (int)i-1349); + } + for (size_t i=550; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i-949); + } + assert (apa.stats().elts.inuse == 0); + assert (apa.stats().elts.free == 0); + assert (apa.stats().elts.total == 0); + assert (apa.stats().blocks.inuse == 0); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 0); +} + + +void test2() +{ + Payload::v.clear(); + SG::ArenaPoolAllocator apa + (SG::ArenaPoolAllocator::initParams<Payload, true>(100)); + for (int i=0; i < 150; i++) { + apa.allocate(); + } + assert (Payload::v.size() == 200); + SG::ArenaPoolAllocator::pointer p = apa.allocate(); + assert (Payload::v.size() == 200); + for (int i=0; i < 150; i++) { + apa.allocate(); + } + assert (Payload::v.size() == 400); + assert (apa.stats().elts.inuse == 301); + assert (apa.stats().elts.free == 99); + assert (apa.stats().elts.total == 400); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 4); + + size_t elt_size = apa.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + apa.resetTo (p); + + assert (apa.stats().elts.inuse == 150); + assert (apa.stats().elts.free == 250); + assert (apa.stats().elts.total == 400); + assert (apa.stats().blocks.inuse == 2); + assert (apa.stats().blocks.free == 2); + assert (apa.stats().blocks.total == 4); + + assert (apa.stats().bytes.inuse == (150 * elt_size + 2 * block_ov)); + assert (apa.stats().bytes.free == (250 * elt_size + 2 * block_ov)); + assert (apa.stats().bytes.total == (400 * elt_size + 4 * block_ov)); +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx new file mode 100644 index 00000000..050e8d6c --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx @@ -0,0 +1,318 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaPoolAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2008 + * @brief Regression tests for ArenaPoolSTLAllocator. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaPoolSTLAllocator.h" +#include "CxxUtils/unordered_map.h" +#include "boost/assign/list_of.hpp" +#include <vector> +#include <cassert> +#include <iostream> + +using boost::assign::list_of; + + + +//========================================================================== + +struct Payload +{ + Payload(int = 0); + Payload(const Payload& p); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload(int the_y) +{ + x = n++; + y = the_y; + v.push_back (x); +} + +Payload::Payload (const Payload& p) + : x (p.x), + y (p.y) +{ + v.push_back (x); +} + + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +// Test generic specialization. +void test1() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test1\n"; + + SG::ArenaPoolSTLAllocator<Payload> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + + SG::ArenaPoolSTLAllocator<Payload> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + + SG::ArenaPoolSTLAllocator<Payload*, int> a3 (100, "a3"); + assert (a3.nblock() == 100); + assert (a3.name() == "a3"); + + SG::ArenaPoolSTLAllocator<Payload, int> a4 (a3); + assert (a4.nblock() == 100); + assert (a4.name() == "a3"); + assert (a4.poolptr() != 0); + + { + Payload p; + Payload& pr = p; + const Payload& pcr = p; + assert (a4.address (pr) == &p); + assert (a4.address (pcr) == &p); + } + assert (Payload::n == 1); + assert (Payload::v.size() == 2); + Payload::v.clear(); + + std::vector<Payload*> pv; + for (int i=0; i < 10; i++) + pv.push_back (a4.allocate (1)); + + assert (Payload::n == 1); + assert (Payload::v.size() == 0); + + assert (a4.max_size() == 1); + + a4.construct (pv[0], Payload(10)); + a4.destroy (pv[0]); + + assert (Payload::n == 2); + std::vector<int> exp1 = list_of(1)(1)(-1)(-1); + assert (Payload::v == exp1); + Payload::v.clear(); + + for (int i=0; i < 10; i++) { + if (i > 0) + assert (pv[i] != pv[i-1]); + a4.deallocate (pv[i], 1); + } + + assert (a4.stats().elts.inuse == 10); + assert (a4.stats().elts.total == 100); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 100); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(5000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 5000); + + assert (Payload::n == 2); + assert (Payload::v.size() == 0); +} + + +// Test pointer specialization. +void test2() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test2\n"; + + SG::ArenaPoolSTLAllocator<Payload*, int> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + assert (a1.poolptr() == 0); + + SG::ArenaPoolSTLAllocator<Payload*, int> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + assert (a2.poolptr() == 0); + + a2.reset(); + a2.erase(); + a2.reserve(10); + assert (a2.stats().elts.total == 0); + + SG::ArenaPoolSTLAllocator<Payload, int> a3 (500, "a3"); + a3.reserve (1000); + SG::ArenaPoolSTLAllocator<Payload*, int> a4 (a3); + assert (a4.nblock() == 500); + assert (a4.name() == "a3"); + assert (a4.poolptr() == a3.poolptr()); + + (void)a3.allocate (1); + assert (a3.stats().elts.inuse == 1); + assert (a3.stats().elts.total == 1000); + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 1000); + assert (&a3.stats() == &a4.stats()); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(1000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + Payload** p = a4.allocate (2, 0); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.deallocate (p, 2); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +// Test vetoed specialization. +void test3() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test3\n"; + + SG::ArenaPoolSTLAllocator<int, int> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + assert (a1.poolptr() == 0); + + SG::ArenaPoolSTLAllocator<int, int> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + assert (a2.poolptr() == 0); + + a2.reset(); + a2.erase(); + a2.reserve(10); + assert (a2.stats().elts.total == 0); + + SG::ArenaPoolSTLAllocator<Payload, int> a3 (500, "a3"); + a3.reserve (1000); + SG::ArenaPoolSTLAllocator<int> a4 (a3); + assert (a4.nblock() == 500); + assert (a4.name() == "a3"); + assert (a4.poolptr() == a3.poolptr()); + + (void)a3.allocate (1); + assert (a3.stats().elts.inuse == 1); + assert (a3.stats().elts.total == 1000); + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 1000); + assert (&a3.stats() == &a4.stats()); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(1000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + int* p = a4.allocate (2, 0); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.deallocate (p, 2); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +// In-situ test. +void test4() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test4\n"; + + typedef SG::unordered_map<int, int, SG::hash<int>, std::equal_to<int>, + SG::ArenaPoolSTLAllocator<std::pair<const int, int> > > map_t; + + map_t::allocator_type allo (500, "allo"); + map_t map (10, map_t::hasher(), map_t::key_equal(), allo); + + for (int i = 0; i < 10; i++) + map[i] = i; + + assert (map.size() == 10); + assert (map.get_allocator().stats().elts.total == 500); + assert (map.get_allocator().stats().elts.inuse == 10); + + map.clear(); + assert (map.size() == 0); + assert (map.get_allocator().stats().elts.total == 500); + assert (map.get_allocator().stats().elts.inuse == 10); + + map.get_allocator().reset(); + assert (map.get_allocator().stats().elts.total == 500); + assert (map.get_allocator().stats().elts.inuse == 0); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx b/EDM/athena/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx new file mode 100644 index 00000000..ef3025b1 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx @@ -0,0 +1,283 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator_test.cxx 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov 2011 + * @brief Regression tests for ArenaSharedHeapSTLAllocator. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaSharedHeapSTLAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include "boost/assign/list_of.hpp" +#include <list> +#include <vector> +#include <cassert> +#include <iostream> + +using boost::assign::list_of; + + + +//========================================================================== + +struct Payload +{ + Payload(int = 0); + Payload(const Payload& p); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload(int the_y) +{ + x = n++; + y = the_y; + v.push_back (x); +} + +Payload::Payload (const Payload& p) + : x (p.x), + y (p.y) +{ + v.push_back (x); +} + + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + + +struct Payload2 : public Payload +{ + Payload2() {} + Payload2(int y) : Payload(y) {} +}; + +//========================================================================== + +// Test generic specialization. +void test1() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test1\n"; + + SG::ArenaSharedHeapSTLAllocator<Payload> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == "::ArenaSharedHeapSTLAllocator<Payload>"); + + SG::ArenaSharedHeapSTLAllocator<Payload> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2::ArenaSharedHeapSTLAllocator<Payload>"); + + { + Payload p; + Payload& pr = p; + const Payload& pcr = p; + assert (a2.address (pr) == &p); + assert (a2.address (pcr) == &p); + } + assert (Payload::n == 1); + assert (Payload::v.size() == 2); + Payload::v.clear(); + + std::vector<Payload*> pv; + for (int i=0; i < 10; i++) + pv.push_back (a2.allocate (1)); + + assert (Payload::n == 1); + assert (Payload::v.size() == 0); + + assert (a2.max_size() == 1); + + a2.construct (pv[0], Payload(10)); + a2.destroy (pv[0]); + + assert (Payload::n == 2); + std::vector<int> exp1 = list_of(1)(1)(-1)(-1); + assert (Payload::v == exp1); + Payload::v.clear(); + + for (int i=0; i < 9; i++) { + if (i > 0) + assert (pv[i] != pv[i-1]); + a2.deallocate (pv[i], 1); + } + + assert (a2.stats().elts.inuse == 1); + assert (a2.stats().elts.total == 100); + + a2.reset(); + assert (a2.stats().elts.inuse == 0); + assert (a2.stats().elts.total == 100); + + a2.erase(); + assert (a2.stats().elts.inuse == 0); + assert (a2.stats().elts.total == 0); + + a2.reserve(5000); + assert (a2.stats().elts.inuse == 0); + assert (a2.stats().elts.total == 5000); + + assert (Payload::n == 2); + assert (Payload::v.size() == 0); + + SG::ArenaSharedHeapSTLAllocator<Payload> a3 (a2); + assert (a2.nblock() == 100); + assert (a2.name() == "a2::ArenaSharedHeapSTLAllocator<Payload>"); + + Payload* p1 = a2.allocate (1); + assert (a2.stats().elts.inuse == 1); + assert (a2.stats().elts.total == 5000); + + Payload* p2 = a3.allocate (1); + assert (a3.stats().elts.inuse == 2); + assert (a3.stats().elts.total == 5000); + + SG::ArenaSharedHeapSTLAllocator<int> a4 (a2); + assert (a4.nblock() == 100); + assert (a4.name() == "a2::ArenaSharedHeapSTLAllocator<int>"); + + int* p3 = a4.allocate(1); + assert (a3.stats().elts.inuse == 2); + assert (a3.stats().elts.total == 5000); + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 100); + + a2.deallocate (p1, 1); + a3.deallocate (p2, 1); + a4.deallocate (p3, 1); + } + + +// Test deallocation. +void test2() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test2\n"; + + //Payload* p1; + //Payload2* p2; + + { + SG::ArenaSharedHeapSTLAllocator<Payload> a1; + SG::ArenaSharedHeapSTLAllocator<Payload2> a2 (a1); + + a1.allocate(1); + a2.allocate(1); + } +} + + +// In-situ test. +void test3() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test3\n"; + + typedef std::list<int, SG::ArenaSharedHeapSTLAllocator<int> > list_t; + + list_t::allocator_type allo (500, "allo"); + list_t list (allo); + + for (int i = 0; i < 10; i++) + list.push_back (i); + + assert (list.size() == 10); + SG::ArenaAllocatorBase::Stats stats; + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 10); + + for (list_t::iterator i = list.begin(); + i != list.end(); + ++i) + { + i = list.erase (i); + if (i == list.end()) break; + } + + assert (list.size() == 5); + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 5); + + list_t list2 (allo); + list2.push_back (10); + stats = list2.get_allocator().totstats(); + assert (stats.elts.inuse == 6); + + list_t list3 (list2); + stats = list2.get_allocator().totstats(); + assert (stats.elts.inuse == 7); + + list.clear(); + assert (list.size() == 0); + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 2); + + list2.clear(); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 1); + + list3.clear(); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 0); + + list.get_allocator().reset(); + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 0); + + list.push_back(1); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 1); + + list2 = list; + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 2); + + list.swap(list2); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 2); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + assert (SG::ArenaBlock::nactive() == 0); + return 0; +} diff --git a/EDM/athena/Control/AthAllocators/test/Arena_test.cxx b/EDM/athena/Control/AthAllocators/test/Arena_test.cxx new file mode 100644 index 00000000..e912824f --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/Arena_test.cxx @@ -0,0 +1,100 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/Arena_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for Arena. + */ + +#undef NDEBUG +#include "AthAllocators/Arena.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include <cassert> +#include <sstream> + + +int xxx = 0; +class Alloc + : public SG::ArenaAllocatorBase +{ +public: + Alloc(int x); + virtual void reset() { xxx += m_x; } + virtual void erase() { xxx += 2*m_x; } + virtual void reserve (size_t /*size*/) {} + virtual const SG::ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } +private: + std::string m_name; + int m_x; + SG::ArenaAllocatorBase::Stats m_stats; +}; + +Alloc::Alloc (int x) + : m_x (x) +{ + m_stats.bytes.inuse = x; + m_stats.bytes.free = 2*x; + m_stats.bytes.total = 3*x; + + std::ostringstream os; + os << "alloc" << x; + m_name = os.str(); +} + +class Creator + : public SG::ArenaAllocatorCreator +{ +public: + Creator (int x) : m_x (x) {} + virtual SG::ArenaAllocatorBase* create() { return new Alloc (m_x); } +private: + int m_x; +}; + +void test1() +{ + SG::ArenaHeader head; + SG::Arena a ("a", &head); + { + SG::Arena::Push p (a); + SG::ArenaAllocatorRegistry* reg = + SG::ArenaAllocatorRegistry::instance(); + assert (reg->registerCreator ("1", new Creator(1)) == 0); + assert (reg->registerCreator ("2", new Creator(2)) == 1); + assert (head.allocator(0)->stats().bytes.inuse == 1); + assert (head.allocator(1)->stats().bytes.inuse == 2); + + assert (a.stats().bytes.inuse == 3); + assert (a.stats().bytes.free == 6); + assert (a.stats().bytes.total == 9); + + std::ostringstream os; + a.report (os); + assert (os.str() == "Elts InUse/Free/Total Bytes InUse/Free/Total Blocks InUse/Free/Total\n\ + 0/ 0/ 0 1/ 2/ 3 0/ 0/ 0 alloc1\n\ + 0/ 0/ 0 2/ 4/ 6 0/ 0/ 0 alloc2\n"); + + assert (xxx == 0); + a.reset(); + assert (xxx == 3); + a.erase(); + assert (xxx == 9); + } +} + + +int main() +{ + test1(); + return 0; +} + diff --git a/EDM/athena/Control/AthAllocators/test/AthAllocators.xml b/EDM/athena/Control/AthAllocators/test/AthAllocators.xml new file mode 100644 index 00000000..df18d250 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/AthAllocators.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AthAllocatorsTest" type="makecheck" suite="Examples"> + <package>Control/AthAllocators</package> + <timelimit>40</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov, snyder@fnal.gov, binet@cern.ch</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/AthAllocators/test/DataPool_test.cxx b/EDM/athena/Control/AthAllocators/test/DataPool_test.cxx new file mode 100644 index 00000000..2716d833 --- /dev/null +++ b/EDM/athena/Control/AthAllocators/test/DataPool_test.cxx @@ -0,0 +1,147 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG + +#include "AthAllocators/DataPool.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IChronoStatSvc.h" +#include "TestTools/initGaudi.h" +#include "CxxUtils/ubsan_suppress.h" +#include "boost/format.hpp" + +#include <cassert> +#include <iostream> +#include <string> +#include <vector> + +using namespace std; + +class Fluff +{ + public: + virtual ~Fluff() { } + Fluff() : m_int(1), m_float(-379.456f), + m_string("this is the Fluff struct") + { + } + + Fluff(const Fluff& f) + { + m_int = f.m_int; + m_float = f.m_float; + m_string = f.m_string; + } + + void setPar(int j) { m_int = j; } + int value() const { return m_int; } + + private: + + int m_int; + float m_float; + string m_string; + +}; + +int main () +{ + CxxUtils::ubsan_suppress ([]() { boost::format("%1%") % "asd"; }); + + + ISvcLocator* pSvcLoc; + if (!Athena_test::initGaudi("DataPool_test.txt", pSvcLoc)) + { + std::cerr << " This test cannot be run without init Gaudi" << endl; + } + assert(pSvcLoc); + + IChronoStatSvc* p_svc; + if ((pSvcLoc->service("ChronoStatSvc", p_svc)).isSuccess()) + { + p_svc->chronoStart("ChronoStatSvc"); + } + + std::cout << " *** DataPool test in progress: " << std::endl; + + // ask for 10 Fluff's in memory, but default is 1024! + DataPool<Fluff>* df = new DataPool<Fluff>(10); + DataPool<Fluff>::const_iterator iter = df->begin(); + DataPool<Fluff>::const_iterator iend = df->end(); + assert(iter == iend); // because pool ain't accessed yet. + assert (0 == df->allocated()); + // check pool capacity: default is 1024 even though we asked for 10 + assert (1024 == df->capacity()); + + // Now use the first 5 of these Fluff's + for (int j = 10; j < 15; j++) + { + Fluff* f = df->nextElementPtr(); + f->setPar(j); + } + assert (5 == df->allocated()); + + // loop again and check whether the first five are set: + int k = 10; + DataPool<Fluff>::const_iterator iter2 = df->begin(); + DataPool<Fluff>::const_iterator iend2 = df->end(); + for (; iter2 != iend2; iter2++) + { + assert(0 != (*iter2)); + // Note: we iterate backwards... + assert(24-k == (*iter2)->value()); + k++; + } + + + df->reset(); // reset DataPool + DataPool<Fluff>::const_iterator iter3 = df->begin(); + DataPool<Fluff>::const_iterator iend3 = df->end(); + assert (iter3 == iend3); // after reset + assert (0 == df->allocated()); + assert (1024 == df->capacity()); // should be same + + // Now use 1500 of these Fluff's.. should automatically resize + //cout << "You should see a message on automatic increase of pool size" << endl; + + for (int j = 0; j < 1500; j++) + { + Fluff* f = df->nextElementPtr(); + f->setPar(j); + } + + assert(1500 == df->allocated()); // up by 2 automatically + + assert(2048 == df->capacity()); + + // check that resizing to less than m_refCount doesn't work + df->reserve(1000); + assert(2048==df->capacity()); + assert(1500==df->allocated()); + + // check that resizing to less than m_maxRefCount works + // changes related to m_maxRefCount are not visible in capacity() or allocated(). + df->reserve(1600); + + assert(2048==df->capacity()); + assert(1500==df->allocated()); + + // this is test by cheating. We reset the data pool (objects are not deleted + // we go to the memory location and check if all values are still ok. + df->reset(); + for (int j = 0; j < 1500; j++) + { + Fluff* f = static_cast<Fluff*>(df->mem()); + assert(j == f->value()); + } + + // call the pool destructor + delete df; + + cout << " **** DataPool test successfully completed **** " << endl; + p_svc->chronoStop("ChronoStatSvc"); + p_svc->chronoPrint("ChronoStatSvc"); + + return 0; +} diff --git a/EDM/athena/Control/AthContainers/AthContainers/AthContainersDict.h b/EDM/athena/Control/AthContainers/AthContainers/AthContainersDict.h new file mode 100644 index 00000000..2a7e46d5 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AthContainersDict.h @@ -0,0 +1,151 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "AthContainers/UserDataStore.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/AuxVectorData.h" +#include "AthContainers/AuxVectorBase.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/ViewVectorBase.h" +#include "AthContainersInterfaces/IAuxElement.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainersInterfaces/IAuxStoreIO.h" +#include "AthContainersInterfaces/IAuxStoreHolder.h" +#include "AthContainersInterfaces/IAuxSetOption.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/PackedParameters.h" +#include "AthContainers/PackedContainer.h" +#include "AthContainers/debug.h" +#include "AthLinks/DataLink.h" + + +struct AthContainersInstan +{ + std::pair<SG::auxid_set_t::iterator, bool> p1; + std::pair<SG::auxid_set_t::const_iterator, bool> p2; +}; + + +inline bool +operator!=(const CxxUtils_Internal::hashtable_iterator<unsigned long, true, false>& x, + const CxxUtils_Internal::hashtable_iterator<unsigned long, true, false>& y) +{ + typedef CxxUtils_Internal::hashtable_iterator_base<unsigned long, false> base; + return static_cast<const base&>(x) != static_cast<const base&>(y); +} + +inline bool +operator!=(const CxxUtils_Internal::hashtable_const_iterator<unsigned long, true, false>& x, + const CxxUtils_Internal::hashtable_const_iterator<unsigned long, true, false>& y) +{ + typedef CxxUtils_Internal::hashtable_iterator_base<unsigned long, false> base; + return static_cast<const base&>(x) != static_cast<const base&>(y); +} + + +inline bool +operator==(const CxxUtils_Internal::hashtable_iterator<unsigned long, true, false>& x, + const CxxUtils_Internal::hashtable_iterator<unsigned long, true, false>& y) +{ + typedef CxxUtils_Internal::hashtable_iterator_base<unsigned long, false> base; + return static_cast<const base&>(x) == static_cast<const base&>(y); +} + +inline bool +operator==(const CxxUtils_Internal::hashtable_const_iterator<unsigned long, true, false>& x, + const CxxUtils_Internal::hashtable_const_iterator<unsigned long, true, false>& y) +{ + typedef CxxUtils_Internal::hashtable_iterator_base<unsigned long, false> base; + return static_cast<const base&>(x) == static_cast<const base&>(y); +} + + +namespace { + struct GCCXML_DUMMY_INSTANTIATION_ATHCONTAINERS { + DataLink<SG::IConstAuxStore> dummy1; + + SG::PackedContainer<char> pchar; + SG::PackedContainer<unsigned char> puchar; + SG::PackedContainer<short> pshort; + SG::PackedContainer<unsigned short> pushort; + SG::PackedContainer<int> pint; + SG::PackedContainer<unsigned int> puint; + SG::PackedContainer<float> pfloat; + SG::PackedContainer<double> pdouble; + + SG::PackedContainer<std::vector<char> > pvchar; + SG::PackedContainer<std::vector<unsigned char> > pvuchar; + SG::PackedContainer<std::vector<short> > pvshort; + SG::PackedContainer<std::vector<unsigned short> > pvushort; + SG::PackedContainer<std::vector<int> > pvint; + SG::PackedContainer<std::vector<unsigned int> > pvuint; + SG::PackedContainer<std::vector<float> > pvfloat; + SG::PackedContainer<std::vector<double> > pvdouble; + + SG::PackedContainer<std::vector<std::vector<char> > > pvvchar; + SG::PackedContainer<std::vector<std::vector<unsigned char> > > pvvuchar; + SG::PackedContainer<std::vector<std::vector<short> > > pvvshort; + SG::PackedContainer<std::vector<std::vector<unsigned short> > > pvvushort; + SG::PackedContainer<std::vector<std::vector<int> > > pvvint; + SG::PackedContainer<std::vector<std::vector<unsigned int> > > pvvuint; + SG::PackedContainer<std::vector<std::vector<float> > > pvvfloat; + SG::PackedContainer<std::vector<std::vector<double> > > pvvdouble; + }; +} + +// Work around cling error. +template class std::vector<std::pair<unsigned int, unsigned int> >; + + +#define ARGS1 (const std::string&) +#define ARGS2 (const std::string&, const std::string&) +#define INSTAN_TYPE(TYP) \ + template class SG::AuxElement::ConstAccessor<TYP>; \ + template class SG::AuxElement::Accessor<TYP>; \ + template class SG::AuxElement::Decorator<TYP>; \ + template TYP& SG::AuxElement::auxdata<TYP> ARGS1; \ + template TYP& SG::AuxElement::auxdata<TYP> ARGS2; \ + template const TYP& SG::AuxElement::auxdata<TYP> ARGS1 const; \ + template const TYP& SG::AuxElement::auxdata<TYP> ARGS2 const; \ + template const TYP& SG::AuxElement::auxdataConst<TYP> ARGS1 const; \ + template const TYP& SG::AuxElement::auxdataConst<TYP> ARGS2 const; \ + template TYP& SG::AuxElement::auxdecor<TYP> ARGS1 const; \ + template TYP& SG::AuxElement::auxdecor<TYP> ARGS2 const + +INSTAN_TYPE(char); +INSTAN_TYPE(unsigned char); +INSTAN_TYPE(int); +INSTAN_TYPE(short); +INSTAN_TYPE(long); +INSTAN_TYPE(unsigned int); +INSTAN_TYPE(unsigned short); +INSTAN_TYPE(unsigned long); +INSTAN_TYPE(unsigned long long); +INSTAN_TYPE(float); +INSTAN_TYPE(double); +INSTAN_TYPE(bool); +INSTAN_TYPE(std::string); + +INSTAN_TYPE(std::vector<char>); +INSTAN_TYPE(std::vector<unsigned char>); +INSTAN_TYPE(std::vector<int>); +INSTAN_TYPE(std::vector<short>); +INSTAN_TYPE(std::vector<long>); +INSTAN_TYPE(std::vector<unsigned int>); +INSTAN_TYPE(std::vector<unsigned short>); +INSTAN_TYPE(std::vector<unsigned long>); +INSTAN_TYPE(std::vector<unsigned long long>); +INSTAN_TYPE(std::vector<float>); +INSTAN_TYPE(std::vector<double>); +INSTAN_TYPE(std::vector<bool>); +INSTAN_TYPE(std::vector<std::string>); + +#undef ARGS1 +#undef ARGS2 +#undef INSTAN_TYPE diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxElement.h b/EDM/athena/Control/AthContainers/AthContainers/AuxElement.h new file mode 100644 index 00000000..c494298f --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxElement.h @@ -0,0 +1,1179 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxElement.h 741471 2016-04-19 20:58:27Z ssnyder $ +/** + * @file AthContainers/AuxElement.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Base class for elements of a container that can have aux data. + */ + + +#ifndef ATHCONTAINERS_AUXELEMENTBASE_H +#define ATHCONTAINERS_AUXELEMENTBASE_H + + +#include "AthContainersInterfaces/IAuxElement.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthLinks/DataLink.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/AuxVectorData.h" +#include "AthContainers/tools/AuxDataTraits.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/likely.h" +#include <cstddef> + + + +namespace SG { + + +class AuxElementData; +class AuxElementStandaloneData; +class AuxVectorData_test; +class AuxVectorBase; +class AuxVectorBase_test; + + +/** + * @brief Base class for elements of a container that can have aux data. + * + * Classes that want to have associated auxiliary data should derive + * from this class. (It is also possible to use this class directly, + * if you want a container that _only_ stores auxiliary data.) + * + * The first thing that happens when you derive from @c AuxElement + * is that when an object is inserted into a @c DataVector, the + * vector will maintain information in the object telling were + * it is within the vector. For example: + * + *@code + * DataVector<SG::AuxElement> v (2); + * v[1] = new SG::AuxElement; + * assert (v[1]->index() == 1); + * assert (v[1]=>container() == &v); + @endcode + * + * As long as you don't use @c DataVector::stdcont or use unsafe + * casts, @c DataVector will correctly maintain this information. + * + * When an object deriving from @c AuxElement is in a @c DataVector + * it may have auxiliary data associated with it; that is, + * named data objects of arbitrary type. The recommended way + * of accessing auxiliary data is through the @c Accessor + * and @c ConstAccessor classes, which cache the lookup between + * the aux data item name and its internal representation. + * The difference between these two is that @c ConstAccessor allows + * only const access to the element, while @c Accessor, which derives + * from it, allows non-const access as well. A given name must always + * have the same type, no matter where it is used (even across + * different classes); otherwise, an exception will be thrown. + * To help prevent conflicts between different classes, aux data item + * names may be optionally qualified with a class name. + * Here's an example of using @c ConstAccessor: + * + *@code + * // Only need to do this once. + * Myclass::ConstAccessor<int> vint1 ("myInt"); + * ... + * const Myclass* m = ...; + * int x = vint1 (*m); + @endcode + * + * The @c auxdata methods can be used as a shortcut for this, + * but that's not recommended for anything for which performance + * is an issue. + * + * You can also define getters/setters in your class: + * + *@code + * class Myclass { + * ... + * int get_x() const + * { const static ConstAccessor<int> acc ("x", "Myclass"); + * return acc (*this); } + * int& get_x() + * { const static Accessor<int> acc ("x", "Myclass"); + * return acc (*this); } + @endcode + * + * In addition, one sometimes wants to add additional auxiliary data to + * an existing const container; for example, after a container has been + * retrieved from StoreGate. This is called `decoration', and is handled + * by the @c Decorator object, which is much like @c Accessor and + * @c ConstAccessor. The difference + * is that @c Decorator can take a const container and return a non-const, + * modifiable reference. If the container has been locked by calling + * @c StoreGateSvc::setConst, then this is allowed only if this is a new + * auxiliary item, in which case it is marked as a decoration, or if it + * is already marked as a decoration. This prevents changing existing + * variables in a locked container. An @c auxdecor method is also + * available, analogous to @c auxdata. + * + * In addition to the above, the class @c TypelessConstAccessor is a + * non-templated class that allows access to auxiliary data items + * directly as a `void *`. This is useful for code which operates + * on auxiliary data generically; it shouldn't really be used + * in other contexts. + * + * Normally, an object can have auxiliary data only when it is part + * of a container. But sometimes it is useful to be able to associate + * aux data with an object before it has been added to a container. + * You can enable this by creating a `private store' for the + * object with @c makePrivateStore. This can optionally take + * an argument from which aux data should be copied. + * (Using a private store adds overhead, which is why it is not enabled + * by default.) Example: + * + *@code + * class Myclass : public SG::AuxElement { ... }; + * ... + * Myclass::Accessor<int> myint ("myint"); + * const Myclass* m = new Myclass; + * m->makePrivateStore(); + * myint(*m) = 10; + * DataVector<Myclass> v; + * v.push_back(m); + * assert (myint(v[0]) == 10); + @endcode + * + * When an object with a private store is added to a container, + * the aux data is copied to the container and the private store + * is released. However, the fact that we had a private store + * is remembered; if the object is later removed from the container, + * the private store will be remade, and the aux data will be copied + * back from the container to the private store. To explicitly + * release the private store (so that it won't come back automatically), + * call @c releasePrivateStore. + * + * If you add @c makePrivateStore calls to the constructors of your class, + * then you should be able to treat aux data as if it were part + * of the object itself; the required copying will be handled automatically. + * + *@code + * class Myclass : public SG::AuxElement + * { + * public: + * Myclass() { makePrivateStore(); } + * Myclass(const Myclass* other) { makePrivateStore(other); } + @endcode + * + * The @c SG::AuxElementComplete template class may be helpful + * in setting this up. + * + * It is also possible to associate one of these objects with an external + * aux data store. This is the `standalone' mode. To do this, use + * the @c setStore methods, exactly as you would for a container + * that has aux data. @c setStore will throw an exception if the + * object is a member of a container or has a private store. + * + * This class should not have any virtual methods (to avoid forcing + * derived classes to have a vtable). + */ +class AuxElement + : public SG::IAuxElement +{ +public: + /// Default constructor. + AuxElement(); + + + /** + * @brief Copy Constructor. + * @param other Object being copied. + * + * We do not copy the container/index --- the new object is not yet + * in a container! + * + * In the case of constructing an object with a private store, + * @c makePrivateStore will take care of copying the aux data. + */ + AuxElement (const AuxElement& other); + + + /** + * @brief Assignment. + * @param other The object from which we're assigning. + * + * We don't copy container/index, as assignment doesn't change where + * this object is. However, if we have aux data, then we copy aux data + * if we're copying from an object that also has it; otherwise, + * if we're copying from an object with no aux data, then we clear ours. + */ + AuxElement& operator= (const AuxElement& other); + + + /** + * @brief Destructor. + * + * Any private store is deleted. + */ + ~AuxElement(); + + + /** + * @brief Return the container holding this element. + */ + SG::AuxVectorData* container(); + + + /** + * @brief Return the container holding this element. + */ + const SG::AuxVectorData* container() const; + + + /** + * @brief Return the index of this element within its container. + */ + size_t index() const; + + + /** + * @brief Helper class to provide const generic access to aux data. + * + * This is written as a separate class in order to be able + * to cache the name -> auxid lookup. + * + * This should generally only be used by code which treats + * auxiliary data generically (that is, where the type is not + * known at compile-time). Most of the time, you'd want to use + * the type-safe versions @c ConstAccessor and @c Accessor. + */ + class TypelessConstAccessor + { + public: + /** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ + TypelessConstAccessor (const std::string& name); + + + /** + * @brief Constructor. + * @param ti The type for this aux data item. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ + TypelessConstAccessor (const std::type_info& ti, + const std::string& name); + + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ + TypelessConstAccessor (const std::string& name, + const std::string& clsname); + + + /** + * @brief Constructor. + * @param ti The type for this aux data item. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ + TypelessConstAccessor (const std::type_info& ti, + const std::string& name, + const std::string& clsname); + + + /** + * @brief Fetch the variable for one element, as a const pointer. + * @param e The element for which to fetch the variable. + */ + const void* operator() (const AuxElement& e) const; + + + /** + * @brief Fetch the variable for one element, as a const pointer. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + */ + const void* operator() (const AuxVectorData& container, size_t index) const; + + + /** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + */ + const void* getDataArray (const AuxVectorData& container) const; + + + /** + * @brief Test to see if this variable exists in the store. + * @param e An element of the container which to test the variable. + */ + bool isAvailable (const AuxElement& e) const; + + + /** + * @brief Return the aux id for this variable. + */ + SG::auxid_t auxid() const; + + + protected: + /// The cached @c auxid. + SG::auxid_t m_auxid; + + /// Cached element size. + size_t m_eltSize; + }; + + + /** + * @brief Helper class to provide constant type-safe access to aux data. + * + * This is written as a separate class in order to be able + * to cache the name -> auxid lookup. + * + * You might use this something like this: + * + *@code + * // Only need to do this once. + * Myclass::ConstAccessor<int> vint1 ("myInt"); + * ... + * const Myclass* m = ...; + * int x = vint1 (*m); + @endcode + * + * This class can be used only for reading data. + * To modify data, see the class @c Accessor. + */ + template <class T> + class ConstAccessor + { + public: + /// Type referencing an item. + typedef typename AuxDataTraits<T>::const_reference_type + const_reference_type; + + /// Pointer into the container holding this item. + typedef typename AuxDataTraits<T>::const_container_pointer_type + const_container_pointer_type; + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ + ConstAccessor (const std::string& name); + + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ + ConstAccessor (const std::string& name, const std::string& clsname); + + + /** + * @brief Fetch the variable for one element, as a const reference. + * @param e The element for which to fetch the variable. + */ + const_reference_type operator() (const AuxElement& e) const; + + + /** + * @brief Fetch the variable for one element, as a const reference. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + */ + const_reference_type + operator() (const AuxVectorData& container, size_t index) const; + + + /** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + */ + const_container_pointer_type + getDataArray (const AuxVectorData& container) const; + + + /** + * @brief Test to see if this variable exists in the store. + * @param e An element of the container which to test the variable. + */ + bool isAvailable (const AuxElement& e) const; + + + /** + * @brief Return the aux id for this variable. + */ + SG::auxid_t auxid() const; + + + protected: + /// The cached @c auxid. + SG::auxid_t m_auxid; + }; + + + /** + * @brief Helper class to provide type-safe access to aux data. + * + * This is written as a separate class in order to be able + * to cache the name -> auxid lookup. + * + * You might use this something like this: + * + *@code + * // Only need to do this once. + * Myclass::Accessor<int> vint1 ("myInt"); + * ... + * const Myclass* m = ...; + * int x = vint1 (*m); + @endcode + * + * You can also use this to define getters/setters in your class: + * + *@code + * class Myclass { + * ... + * int get_x() const + * { const static Accessor<int> acc ("x", "Myclass"); + * return acc (*this); } + * int& get_x() + * { const static Accessor<int> acc ("x", "Myclass"); + * return acc (*this); } + @endcode + */ + template <class T> + class Accessor + : public ConstAccessor<T> + { + public: + /// Type referencing an item. + typedef typename AuxDataTraits<T>::reference_type + reference_type; + + /// Type the user sees. + typedef typename AuxDataTraits<T>::element_type + element_type; + + /// Pointer into the container holding this item. + typedef typename AuxDataTraits<T>::container_pointer_type + container_pointer_type; + + using ConstAccessor<T>::operator(); + using ConstAccessor<T>::getDataArray; + + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ + Accessor (const std::string& name); + + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ + Accessor (const std::string& name, const std::string& clsname); + + + /** + * @brief Fetch the variable for one element, as a non-const reference. + * @param e The element for which to fetch the variable. + */ + reference_type operator() (AuxElement& e) const; + + + /** + * @brief Fetch the variable for one element, as a non-const reference. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + */ + reference_type operator() (AuxVectorData& container, size_t index) const; + + + /** + * @brief Set the variable for one element. + * @param e The element for which to fetch the variable. + * @param x The variable value to set. + */ + void set (AuxElement& e, const element_type& x) const; + + + /** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + */ + container_pointer_type getDataArray (AuxVectorData& container) const; + + + /** + * @brief Test to see if this variable exists in the store and is writable. + * @param e An element of the container which to test the variable. + */ + bool isAvailableWritable (const AuxElement& e) const; + }; + + + /** + * @brief Helper class to provide type-safe access to aux data. + * + * This is like @c Accessor, except that it only `decorates' the container. + * What this means is that this object can operate on a const container + * and return a non-const reference. However, if the container is locked, + * this will only work if either this is a reference to a new variable, + * in which case it is marked as a decoration, or it is a reference + * to a variable already marked as a decoration. + * + * This is written as a separate class in order to be able + * to cache the name -> auxid lookup. + * + * You might use this something like this: + * + *@code + * // Only need to do this once. + * Myclass::Decorator<int> vint1 ("myInt"); + * ... + * const Myclass* m = ...; + * vint1 (*m) = 123; + @endcode + */ + template <class T> + class Decorator + { + public: + /// Type referencing an item. + typedef typename AuxDataTraits<T>::reference_type + reference_type; + + /// Type the user sees. + typedef typename AuxDataTraits<T>::element_type + element_type; + + /// Pointer into the container holding this item. + typedef typename AuxDataTraits<T>::container_pointer_type + container_pointer_type; + typedef typename AuxDataTraits<T>::const_container_pointer_type + const_container_pointer_type; + + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ + Decorator (const std::string& name); + + + /** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ + Decorator (const std::string& name, const std::string& clsname); + + + /** + * @brief Fetch the variable for one element, as a non-const reference. + * @param e The element for which to fetch the variable. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ + reference_type operator() (const AuxElement& e) const; + + + /** + * @brief Fetch the variable for one element, as a non-const reference. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ + reference_type + operator() (const AuxVectorData& container, size_t index) const; + + + /** + * @brief Set the variable for one element. + * @param e The element for which to fetch the variable. + * @param x The variable value to set. + */ + void set (const AuxElement& e, const element_type& x) const; + + + /** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ + const_container_pointer_type getDataArray (const AuxVectorData& container) const; + + + /** + * @brief Test to see if this variable exists in the store. + * @param e An element of the container which to test the variable. + */ + bool isAvailable (const AuxElement& e) const; + + + /** + * @brief Test to see if this variable exists in the store and is writable. + * @param e An element of the container which to test the variable. + */ + bool isAvailableWritable (const AuxElement& e) const; + + + /** + * @brief Return the aux id for this variable. + */ + SG::auxid_t auxid() const; + + + private: + /// The cached @c auxid. + SG::auxid_t m_auxid; + }; + + + /** + * @brief Fetch an aux data variable, as a non-const reference. + * @param name Name of the aux variable. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ + template <class T> + typename AuxDataTraits<T>::reference_type + auxdata (const std::string& name); + + + /** + * @brief Fetch an aux data variable, as a non-const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ + template <class T> + typename AuxDataTraits<T>::reference_type + auxdata (const std::string& name, + const std::string& clsname); + + + /** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * or @c ConstAccessor classes above. + */ + template <class T> + typename AuxDataTraits<T>::const_reference_type + auxdata (const std::string& name) const; + + + /** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * or @c ConstAccessor classes above. + */ + template <class T> + typename AuxDataTraits<T>::const_reference_type + auxdata (const std::string& name, + const std::string& clsname) const; + + + /** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c ConstAccessor + * class above. + */ + template <class T> + typename AuxDataTraits<T>::const_reference_type + auxdataConst (const std::string& name) const; + + + /** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c ConstAccessor + * class above. + */ + template <class T> + typename AuxDataTraits<T>::const_reference_type + auxdataConst (const std::string& name, + const std::string& clsname) const; + + + /** + * @brief Check if an aux variable is available for reading + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ + template <class T> + bool isAvailable (const std::string& name, + const std::string& clsname = "") const; + + + /** + * @brief Check if an aux variable is available for writing + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ + template <class T> + bool isAvailableWritable (const std::string& name, + const std::string& clsname = "") const; + + + /** + * @brief Check if an aux variable is available for writing as a decoration. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ + template <class T> + bool isAvailableWritableAsDecoration (const std::string& name, + const std::string& clsname = "") const; + + + /** + * @brief Fetch an aux decoration, as a non-const reference. + * @param name Name of the aux variable. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ + template <class T> + typename AuxDataTraits<T>::reference_type + auxdecor (const std::string& name) const; + + + /** + * @brief Fetch an aux decoration, as a non-const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ + template <class T> + typename AuxDataTraits<T>::reference_type + auxdecor (const std::string& name, + const std::string& clsname) const; + + + /** + * @brief Create a new (empty) private store for this object. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + */ + void makePrivateStore(); + + + /** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * If @c other is an object that has aux data, then those data will + * be copied; otherwise, nothing will be done. + */ + template <class U1> + void makePrivateStore (const U1& other); + + + /** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * If @c other is an object that has aux data, then those data will + * be copied; otherwise, nothing will be done. + */ + template <class U1> + void makePrivateStore (const U1* other); + + + /** + * @brief Release and free any private store associated with this object. + * + * @c ExcBadPrivateStore will be thrown if this object does not + * have a private store. + */ + void releasePrivateStore(); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * If store is nonzero, this adds a standalone store to the object. + * The object must not be in a container and must not have a private store. + * If store is zero, this removes a standalone store. + */ + void setStore (const SG::IConstAuxStore* store); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * If store is nonzero, this adds a standalone store to the object. + * The object must not be in a container and must not have a private store. + * If store is zero, this removes a standalone store. + */ + void setStore (SG::IAuxStore* store); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * If store is nonzero, this adds a standalone store to the object. + * The object must not be in a container and must not have a private store. + * If store is zero, this removes a standalone store. + */ + void setStore (const DataLink< SG::IConstAuxStore >& store); + + + /** + * @brief Synonym for @c setStore with @c IConstAuxStore. + * @param store The new store. + */ + void setConstStore (const SG::IConstAuxStore* store); + + + /** + * @brief Synonym for @c setStore with @c IAuxStore. + * @param store The new store. + */ + void setNonConstStore (SG::IAuxStore* store); + + + /** + * @brief Test to see if this object is currently using a private store. + */ + bool usingPrivateStore() const; + + + /** + * @brief Test to see if this object is currently using a standalone store. + */ + bool usingStandaloneStore() const; + + + /** + * @brief Return the current store, as a const interface. + * + * This will be non-zero if either a const or non-const store + * is associated with this object. + * This will fetch either a private or standalone store. + */ + const SG::IConstAuxStore* getConstStore() const; + + + /** + * @brief Return the current store, as a non-const interface. + * + * This will be non-zero if a non-const store is associated with this object. + * This will fetch either a private or standalone store. + */ + SG::IAuxStore* getStore() const; + + + /** + * @brief Clear the cached aux data pointers. + * + * You should call this any time something changes in the aux store + * that could invalidate the vector pointers. + */ + void clearCache(); + + + /** + * @brief Return a set of identifiers for existing data items + * for this object. + * + * If this object has a private or standalone store, then information + * from that will be returned. Otherwise, if this element + * is part of a container, then information for the container + * will be returned. Otherwise, return an empty set. + */ + const SG::auxid_set_t& getAuxIDs() const; + + + /** + * @brief Return true if this object has an associated store. + * + * This will be true for either a private or standalone store. + */ + bool hasStore() const; + + + /** + * @brief Return true if this object has an associated non-const store. + * + * This will be true for either a private or standalone store. + */ + bool hasNonConstStore() const; + + + /** + * @brief Clear all decorations. + * + * Erase all decorations from an associated store, restoring the state to when + * @c lock was called. + */ + void clearDecorations() const; + + +private: + friend class SG::AuxVectorBase; + friend class SG::AuxVectorBase_test; + + + /** + * @brief Constructor with explicit container / index. + * @param container Container of which this element will be a part. + * @param index Index of this element within the container. + * + * This does not make any changes to aux data. + */ + AuxElement (SG::AuxVectorData* container, size_t index); + + + + /** + * @brief Out-of-line portion of destructor. + * + * Delete a private store if we have one. + */ + void releasePrivateStoreForDtor(); + + + /** + * @brief Set the index/container for this element. + * @param index The index of this object within the container. + * @param container The container holding this object. + * May be null if this object is being removed + * from a container. + * + * Usually this simply sets the index and container members + * of this object. However, in the case where this object has + * an associated private store, then we need to deal with + * releasing the store if the object is being added to a container, + * or making a new store if the object is being removed from a container. + */ + void setIndex (size_t index, SG::AuxVectorData* container); + + + /** + * @brief Set the index/container for this element. + * @param index The index of this object within the container. + * @param container The container holding this object. + * May be null if this object is being removed + * from a container. + * + * This is called from @c setIndex when we have a private store to deal with. + */ + bool setIndexPrivate (size_t index, SG::AuxVectorData* container); + + + /** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * This overload handles the case where @c other does not have aux data. + */ + void makePrivateStore1 (const void*); + + + /** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * This overload handles the case where @c other does have aux data. + */ + void makePrivateStore1 (const AuxElement* other); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * Helper for @c setStore. Creates the @c AuxElementStandaloneData + * object if needed and returns it. + */ + AuxElementStandaloneData* setStore1 (const SG::IConstAuxStore* store); + + + /** + * @brief Clear all aux data associated with this element. + * + * If this object has no associated store, this does nothing. + * If the associated aux data is const, this throws @c ExcConstAuxData. + */ + void clearAux(); + + + /** + * @brief Copy aux data from another object. + * @param other The object from which to copy. + * + * If this object has no associated store, this does nothing. + * If the associated aux data is const, this throws @c ExcConstAuxData. + * + * All aux data items from @c other are copied to this object. + * Any aux data items associated with this object that are not present + * in @c other are cleared. (If @c other has no aux data, then all + * aux data items for this object are cleared.) + */ + void copyAux (const AuxElement& other); + + + /** + * @brief Helper to test if m_privateData is valid. + */ + bool privateDataValid() const; + + + /// The index of this element within its container. + /// Should be 0 if this object is not within a container. + size_t m_index; + + /// The container of which this object is an element. + /// Should be null if this object is not within a container, + /// except for the case where this object as a private store. + /// In that case, @c m_container should be the same as @c m_privateData. + SG::AuxVectorData* m_container; + + /// If this object has a current private store, then this points + /// at the container object holding the store. In that case, + /// @c m_container should have the same value. If this object + /// had a private store but it was released because the object + /// was added to a container, then this should be set to + /// @c s_privatePlaceholder. That way, we know to reconstruct + /// the private store in the event this object is removed from + /// the container. Otherwise, if we no private store association at all, + /// then this should be null. + SG::AuxElementData* m_privateData; + + /// Special value used to mark that an object had a private store, + /// but it was released because it was added to a container. + /// (And therefore we should recreate the private store if the + /// object is later removed.) + static SG::AuxElementData* s_privatePlaceholder; +}; + + +} // namespace SG + + +#include "AthContainers/AuxElement.icc" + + +#endif // not ATHCONTAINERS_AUXELEMENTBASE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxElement.icc b/EDM/athena/Control/AthContainers/AthContainers/AuxElement.icc new file mode 100644 index 00000000..499083c7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxElement.icc @@ -0,0 +1,973 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxElement.icc 627952 2014-11-12 17:27:57Z ssnyder $ +/** + * @file AthContainers/AuxElement.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Base class for elements of a container that can have aux data. + */ + + +#include "AthContainers/tools/likely.h" +#include <cassert> + + +namespace SG { + + +/** + * @brief Default constructor. + */ +inline +AuxElement::AuxElement() + : m_index(0), + m_container(0), + m_privateData(0) +{ +} + + +/** + * @brief Constructor with explicit container / index. + * @param container Container of which this element will be a part. + * @param index Index of this element within the container. + * + * This does not make any changes to aux data. + */ +inline +AuxElement::AuxElement (SG::AuxVectorData* container, + size_t index) + : m_index(index), + m_container (container), + m_privateData(0) +{ +} + + +/** + * @brief Copy Constructor. + * @param other Object being copied. + * + * We do not copy the container/index --- the new object is not yet + * in a container! + * + * In the case of constructing an object with a private store, + * @c makePrivateStore will take care of copying the aux data. + */ +inline +AuxElement::AuxElement (const AuxElement& /*other*/) + : m_index(0), + m_container(0), + m_privateData(0) +{ +} + + +/** + * @brief Assignment. + * @param other The object from which we're assigning. + * + * We don't copy container/index, as assignment doesn't change where + * this object is. However, if we have aux data, then we copy aux data + * if we're copying from an object that also has it; otherwise, + * if we're copying from an object with no aux data, then we clear ours. + */ +inline +AuxElement& AuxElement::operator= (const AuxElement& other) +{ + if (this != &other) { + if (this->container()) { + if (!other.container()) { + // Copying from an object with no aux data. + // Clear our aux data. + this->clearAux(); + } + else { + // Copying from an object with aux data. + // Copy the aux data too. + this->copyAux (other); + } + } + } + return *this; +} + + +/** + * @brief Destructor. + * + * Any private store is deleted. + */ +inline +AuxElement::~AuxElement() +{ + if (ATHCONTAINERS_UNLIKELY (m_privateData)) + releasePrivateStoreForDtor(); +} + + +/** + * @brief Return the container holding this element. + */ +inline +SG::AuxVectorData* AuxElement::container() +{ + return m_container; +} + + +/** + * @brief Return the container holding this element. + */ +inline +const SG::AuxVectorData* AuxElement::container() const +{ + return m_container; +} + + +/** + * @brief Return the index of this element within its container. + */ +inline +size_t AuxElement::index() const +{ + return m_index; +} + + +//****************************************************************************** + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ +inline +AuxElement::TypelessConstAccessor::TypelessConstAccessor (const std::string& name) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + m_auxid = r.findAuxID(name); + if (m_auxid == null_auxid) + SG::throwExcUnknownAuxItem (name); + m_eltSize = r.getEltSize (m_auxid); +} + + +/** + * @brief Constructor. + * @param ti The type for this aux data item. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ +inline +AuxElement::TypelessConstAccessor::TypelessConstAccessor (const std::type_info& ti, + const std::string& name) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + m_auxid = r.getAuxID (ti, name); + if (m_auxid == null_auxid) + SG::throwExcUnknownAuxItem (name, "", &ti); + m_eltSize = r.getEltSize (m_auxid); +} + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ +inline +AuxElement::TypelessConstAccessor::TypelessConstAccessor (const std::string& name, + const std::string& clsname) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + m_auxid = r.findAuxID(name, clsname); + if (m_auxid == null_auxid) + SG::throwExcUnknownAuxItem (name, clsname); + m_eltSize = r.getEltSize (m_auxid); +} + + +/** + * @brief Constructor. + * @param ti The type for this aux data item. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ +inline +AuxElement::TypelessConstAccessor::TypelessConstAccessor (const std::type_info& ti, + const std::string& name, + const std::string& clsname) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + m_auxid = r.getAuxID (ti, name, clsname); + if (m_auxid == null_auxid) + SG::throwExcUnknownAuxItem (name, clsname, &ti); + m_eltSize = r.getEltSize (m_auxid); +} + + +/** + * @brief Fetch the variable for one element, as a const pointer. + * @param e The element for which to fetch the variable. + */ +inline +const void* +AuxElement::TypelessConstAccessor::operator() (const AuxElement& e) const +{ + assert (e.container() != 0); + return (*this) (*e.container(), e.m_index); +} + + +/** + * @brief Fetch the variable for one element, as a const pointer. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + */ +inline +const void* +AuxElement::TypelessConstAccessor::operator() (const AuxVectorData& container, + size_t index) const +{ + const char* ptr = reinterpret_cast<const char*> (getDataArray (container)); + return ptr + index * m_eltSize; +} + + +/** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + */ +inline +const void* +AuxElement::TypelessConstAccessor::getDataArray (const AuxVectorData& container) const +{ + return container.getDataArray (m_auxid); +} + + +/** + * @brief Test to see if this variable exists in the store. + * @param e An element of the container which to test the variable. + */ +inline +bool +AuxElement::TypelessConstAccessor::isAvailable (const AuxElement& e) const +{ + return e.container() && e.container()->isAvailable (m_auxid); +} + + +/** + * @brief Return the aux id for this variable. + */ +inline +SG::auxid_t +AuxElement::TypelessConstAccessor::auxid() const +{ + return m_auxid; +} + + +//****************************************************************************** + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ +template <class T> +inline +AuxElement::ConstAccessor<T>::ConstAccessor (const std::string& name) + : m_auxid (SG::AuxTypeRegistry::instance().getAuxID<T> (name)) +{ +} + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ +template <class T> +inline +AuxElement::ConstAccessor<T>::ConstAccessor (const std::string& name, + const std::string& clsname) + : m_auxid (SG::AuxTypeRegistry::instance().getAuxID<T> (name, clsname)) +{ +} + + +/** + * @brief Fetch the variable for one element, as a const reference. + * @param e The element for which to fetch the variable. + */ +template <class T> +inline +typename AuxElement::ConstAccessor<T>::const_reference_type +AuxElement::ConstAccessor<T>::operator() (const AuxElement& e) const +{ + assert (e.container() != 0); + return e.container()->template getData<T> (m_auxid, e.m_index); +} + + +/** + * @brief Fetch the variable for one element, as a const reference. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + */ +template <class T> +inline +typename AuxElement::ConstAccessor<T>::const_reference_type +AuxElement::ConstAccessor<T>::operator() (const AuxVectorData& container, + size_t index) const +{ + return container.template getData<T> (m_auxid, index); +} + + + +/** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + */ +template <class T> +inline +typename AuxElement::ConstAccessor<T>::const_container_pointer_type +AuxElement::ConstAccessor<T>::getDataArray (const AuxVectorData& container) const +{ + return reinterpret_cast<const_container_pointer_type> + (container.getDataArray (m_auxid)); +} + + +/** + * @brief Test to see if this variable exists in the store. + * @param e An element of the container which to test the variable. + */ +template <class T> +inline +bool +AuxElement::ConstAccessor<T>::isAvailable (const AuxElement& e) const +{ + return e.container() && e.container()->isAvailable (m_auxid); +} + + +/** + * @brief Return the aux id for this variable. + */ +template <class T> +inline +SG::auxid_t +AuxElement::ConstAccessor<T>::auxid() const +{ + return m_auxid; +} + + +//****************************************************************************** + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ +template <class T> +inline +AuxElement::Accessor<T>::Accessor (const std::string& name) + : ConstAccessor<T> (name) +{ +} + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ +template <class T> +inline +AuxElement::Accessor<T>::Accessor (const std::string& name, + const std::string& clsname) + : ConstAccessor<T> (name, clsname) +{ +} + + +/** + * @brief Fetch the variable for one element, as a non-const reference. + * @param e The element for which to fetch the variable. + */ +template <class T> +inline +typename AuxElement::Accessor<T>::reference_type +AuxElement::Accessor<T>::operator() (AuxElement& e) const +{ + assert (e.container() != 0); + return e.container()->template getData<T> (this->m_auxid, e.m_index); +} + + +/** + * @brief Fetch the variable for one element, as a non-const reference. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + */ +template <class T> +inline +typename AuxElement::Accessor<T>::reference_type +AuxElement::Accessor<T>::operator() (AuxVectorData& container, + size_t index) const +{ + return container.template getData<T> (this->m_auxid, index); +} + + +/** + * @brief Set the variable for one element. + * @param e The element for which to fetch the variable. + * @param x The variable value to set. + */ +template <class T> +inline +void AuxElement::Accessor<T>::set (AuxElement& e, const element_type& x) const +{ + (*this)(e) = x; +} + + +/** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + */ +template <class T> +inline +typename AuxElement::Accessor<T>::container_pointer_type +AuxElement::Accessor<T>::getDataArray (AuxVectorData& container) const +{ + return reinterpret_cast<container_pointer_type> + (container.getDataArray (this->m_auxid)); +} + + +/** + * @brief Test to see if this variable exists in the store and is writable. + * @param e An element of the container which to test the variable. + */ +template <class T> +inline +bool +AuxElement::Accessor<T>::isAvailableWritable (const AuxElement& e) const +{ + return e.container() && e.container()->isAvailableWritable (this->m_auxid); +} + + +//****************************************************************************** + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * + * The name -> auxid lookup is done here. + */ +template <class T> +inline +AuxElement::Decorator<T>::Decorator (const std::string& name) + : m_auxid (SG::AuxTypeRegistry::instance().getAuxID<T> (name)) +{ +} + + +/** + * @brief Constructor. + * @param name Name of this aux variable. + * @param clsname The name of its associated class. May be blank. + * + * The name -> auxid lookup is done here. + */ +template <class T> +inline +AuxElement::Decorator<T>::Decorator (const std::string& name, + const std::string& clsname) + : m_auxid (SG::AuxTypeRegistry::instance().getAuxID<T> (name, clsname)) +{ +} + + +/** + * @brief Fetch the variable for one element, as a non-const reference. + * @param e The element for which to fetch the variable. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ +template <class T> +inline +typename AuxElement::Decorator<T>::reference_type +AuxElement::Decorator<T>::operator() (const AuxElement& e) const +{ + assert (e.container() != 0); + return e.container()->template getDecoration<T> (m_auxid, e.m_index); +} + + +/** + * @brief Fetch the variable for one element, as a non-const reference. + * @param container The container from which to fetch the variable. + * @param index The index of the desired element. + * + * This allows retrieving aux data by container / index. + * Looping over the index via this method will be faster then + * looping over the elements of the container. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ +template <class T> +inline +typename AuxElement::Decorator<T>::reference_type +AuxElement::Decorator<T>::operator() (const AuxVectorData& container, + size_t index) const +{ + return container.template getDecoration<T> (m_auxid, index); +} + + +/** + * @brief Set the variable for one element. + * @param e The element for which to fetch the variable. + * @param x The variable value to set. + */ +template <class T> +inline +void AuxElement::Decorator<T>::set (const AuxElement& e, + const element_type& x) const +{ + (*this)(e) = x; +} + + +/** + * @brief Get a pointer to the start of the auxiliary data array. + * @param container The container from which to fetch the variable. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ +template <class T> +inline +typename AuxElement::Decorator<T>::const_container_pointer_type +AuxElement::Decorator<T>::getDataArray (const AuxVectorData& container) const +{ + return reinterpret_cast<const_container_pointer_type> + (container.getDataArray (m_auxid)); +} + + + +/** + * @brief Test to see if this variable exists in the store. + * @param e An element of the container which to test the variable. + */ +template <class T> +inline +bool +AuxElement::Decorator<T>::isAvailable (const AuxElement& e) const +{ + return e.container() && e.container()->isAvailable (m_auxid); +} + + +/** + * @brief Test to see if this variable exists in the store and is writable. + * @param e An element of the container which to test the variable. + */ +template <class T> +inline +bool +AuxElement::Decorator<T>::isAvailableWritable (const AuxElement& e) const +{ + return e.container() && e.container()->isAvailableWritableAsDecoration (m_auxid); +} + + +/** + * @brief Return the aux id for this variable. + */ +template <class T> +inline +SG::auxid_t +AuxElement::Decorator<T>::auxid() const +{ + return m_auxid; +} + + +//****************************************************************************** + + +/** + * @brief Fetch an aux data variable, as a non-const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ +template <class T> +typename AuxDataTraits<T>::reference_type +AuxElement::auxdata (const std::string& name) +{ + return Accessor<T>(name, "")(*this); +} + + +/** + * @brief Fetch an aux data variable, as a non-const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ +template <class T> +typename AuxDataTraits<T>::reference_type +AuxElement::auxdata (const std::string& name, + const std::string& clsname) +{ + return Accessor<T>(name, clsname)(*this); +} + + +/** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * or @c ConstAccessor classes above. + */ +template <class T> +typename AuxDataTraits<T>::const_reference_type +AuxElement::auxdata (const std::string& name) const +{ + return Accessor<T>(name, "")(*this); +} + + +/** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * or @c ConstAccessor classes above. + */ +template <class T> +typename AuxDataTraits<T>::const_reference_type +AuxElement::auxdata (const std::string& name, + const std::string& clsname) const +{ + return Accessor<T>(name, clsname)(*this); +} + + +/** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c ConstAccessor + * class above. + */ +template <class T> +typename AuxDataTraits<T>::const_reference_type +AuxElement::auxdataConst (const std::string& name) const +{ + return Accessor<T>(name, "")(*this); +} + + +/** + * @brief Fetch an aux data variable, as a const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c ConstAccessor + * class above. + */ +template <class T> +typename AuxDataTraits<T>::const_reference_type +AuxElement::auxdataConst (const std::string& name, + const std::string& clsname) const +{ + return Accessor<T>(name, clsname)(*this); +} + + +/** + * @brief Check if an aux variable is available for reading + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ +template <class T> +bool AuxElement::isAvailable (const std::string& name, + const std::string& clsname /*= ""*/) const +{ + return Accessor<T>(name, clsname).isAvailable(*this); +} + + +/** + * @brief Check if an aux variable is available for writing + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ +template <class T> +bool AuxElement::isAvailableWritable (const std::string& name, + const std::string& clsname /*= ""*/) const +{ + return Accessor<T>(name, clsname).isAvailableWritable(*this); +} + + +/** + * @brief Check if an aux variable is available for writing as a decoration. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + */ +template <class T> +bool AuxElement::isAvailableWritableAsDecoration (const std::string& name, + const std::string& clsname /*= ""*/) const +{ + return Decorator<T>(name, clsname).isAvailableWritable(*this); +} + + +/** + * @brief Fetch an aux decoration, as a non-const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ +template <class T> +typename AuxDataTraits<T>::reference_type +AuxElement::auxdecor (const std::string& name) const +{ + return Decorator<T>(name, "")(*this); +} + + +/** + * @brief Fetch an aux decoration, as a non-const reference. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + * + * This method has to translate from the aux data name to the internal + * representation each time it is called. Using this method + * inside of loops is discouraged; instead use the @c Accessor + * class above. + * + * If the container is locked, this will allow fetching only variables + * that do not yet exist (in which case they will be marked as decorations) + * or variables already marked as decorations. + */ +template <class T> +typename AuxDataTraits<T>::reference_type +AuxElement::auxdecor (const std::string& name, + const std::string& clsname) const +{ + return Decorator<T>(name, clsname)(*this); +} + + +/** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * If @c other is an object that has aux data, then those data will + * be copied; otherwise, nothing will be done. + */ +template <class U1> +inline +void AuxElement::makePrivateStore (const U1& other) +{ + // Dispatch to the proper overload depending on whether or not + // other derives from AuxElement. + makePrivateStore1 (&other); +} + + +/** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * If @c other is an object that has aux data, then those data will + * be copied; otherwise, nothing will be done. + */ +template <class U1> +inline +void AuxElement::makePrivateStore (const U1* other) +{ + // Dispatch to the proper overload depending on whether or not + // other derives from AuxElement. + makePrivateStore1 (other); +} + + +/** + * @brief Synonym for @c setStore with @c IConstAuxStore. + * @param store The new store. + */ +inline +void AuxElement::setConstStore (const SG::IConstAuxStore* store) +{ + setStore (store); +} + + +/** + * @brief Synonym for @c setStore with @c IAuxStore. + * @param store The new store. + */ +inline +void AuxElement::setNonConstStore (SG::IAuxStore* store) +{ + setStore (store); +} + + +/** + * @brief Set the index/container for this element. + * @param index The index of this object within the container. + * @param container The container holding this object. + * May be null if this object is being removed + * from a container. + * + * Usually this simply sets the index and container members + * of this object. However, in the case where this object has + * an associated private store, then we need to deal with + * releasing the store if the object is being added to a container, + * or making a new store if the object is being removed from a container. + */ +inline +void AuxElement::setIndex (size_t index, SG::AuxVectorData* container) +{ + if (ATHCONTAINERS_UNLIKELY (m_privateData != 0)) { + // out-of-line piece, dealing with private store. + setIndexPrivate (index, container); + return; + } + + m_index = index; + m_container = container; +} + + +/** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * This overload handles the case where @c other does not have aux data. + */ +inline +void AuxElement::makePrivateStore1 (const void*) +{ + makePrivateStore(); +} + + +/** + * @brief Helper to test if m_privateData is valid. + */ +inline +bool AuxElement::privateDataValid() const +{ + return m_privateData != 0 && m_privateData != s_privatePlaceholder; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.h b/EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.h new file mode 100644 index 00000000..49fee59c --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.h @@ -0,0 +1,86 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxElementComplete.h 770199 2016-08-25 21:16:39Z ssnyder $ +/** + * @file AthContainers/AuxElementComplete.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Wrapper to automatically create a private store for an element. + */ + + +#ifndef ATHCONTAINERS_AUXELEMENTCOMPLETE_H +#define ATHCONTAINERS_AUXELEMENTCOMPLETE_H + + +#include "AthContainers/AuxElement.h" + + +namespace SG { + + +/** + * @brief Wrapper to automatically create a private store for an element. + * + * A class deriving from @c SG::AuxElement can be given a private store + * by calling @c makePrivateStore; after that, it can have + * auxiliary data attached to it. Using this wrapper makes a class + * that will automatically create a private store when it is constructed. + * + *@code + * class MyClass : public SG::AuxElement { ... }; + * typedef SG::AuxElementComplete<MyClass> MyClassComplete; + * + * MyClassComplete obj; // obj gets a private store. + * obj.auxdata<int> ("mydata") = 1; + * MyClassComplete obj2 (obj); // aux data gets copied. + @endcode + */ +template <class T> +class AuxElementComplete + : public T +{ +public: + /** + * @brief Default constructor. + * + * A private store is created for this object. + */ + AuxElementComplete(); + + + /** + * @brief Generic constructor. + * @param u1 Constructor argument. + * + * A private store is created for this object. + */ + template <class U1> + AuxElementComplete (const U1& u1); + + + /** + * @brief Copy constructor. + * @param other The object being copied. + * + * A private store is created for this object. + */ + AuxElementComplete (const AuxElementComplete& other); + + + // Declare default assignment explicitly to prevent coverity warning. + AuxElementComplete& operator= (const AuxElementComplete& other) = default; +}; + + +} // namespace SG + + +#include "AthContainers/AuxElementComplete.icc" + + +#endif // not ATHCONTAINERS_AUXELEMENTCOMPLETE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.icc b/EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.icc new file mode 100644 index 00000000..65aca79f --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxElementComplete.icc @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxElementComplete.icc 581165 2014-02-03 10:42:54Z krasznaa $ +/** + * @file AthContainers/AuxElementComplete.icc + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Wrapper to automatically create a private store for an element. + */ + + +namespace SG { + + +/** + * @brief Default constructor. + * + * A private store is created for this object. + */ +template <class T> +inline +AuxElementComplete<T>::AuxElementComplete() +{ + this->makePrivateStore(); +} + + +/** + * @brief Generic constructor. + * @param u1 Constructor argument. + * + * A private store is created for this object. + */ +template <class T> +template <class U1> +inline +AuxElementComplete<T>::AuxElementComplete (const U1& u1) + : T(u1) +{ + this->makePrivateStore(u1); +} + + +/** + * @brief Copy constructor. + * @param other The object being copied. + * + * A private store is created for this object. + */ +template <class T> +inline +AuxElementComplete<T>::AuxElementComplete (const AuxElementComplete& other) + : T(other) +{ + this->makePrivateStore(other); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxStoreInternal.h b/EDM/athena/Control/AthContainers/AthContainers/AuxStoreInternal.h new file mode 100644 index 00000000..6145820a --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxStoreInternal.h @@ -0,0 +1,429 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxStoreInternal.h 797205 2017-02-14 19:38:03Z ssnyder $ +/** + * @file AthContainers/AuxStoreInternal.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief An auxiliary data store that holds data internally. + */ + + +#ifndef ATHCONTAINERS_AUXSTOREINTERNAL_H +#define ATHCONTAINERS_AUXSTOREINTERNAL_H + + +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IAuxStoreIO.h" +#include "AthContainers/tools/threading.h" +#include "CxxUtils/override.h" +#include <vector> + + +namespace SG { + + +class IAuxTypeVector; + + +/** + * @brief An auxiliary data store that holds data internally. + * + * When auxiliary data are associated with a container, the data themselves + * are managed by a separate `store' object, described by the interfaces + * @c SG::IAuxStore and @c SG::IConstAuxStore. + * + * This class is an implementation of those interfaces that stores the + * data itself. This is suitable, for example, for transient + * auxiliary data. + */ +class AuxStoreInternal + : public IAuxStore, public IAuxStoreIO +{ +public: + /** + * @brief Constructor. + * @param standalone If true, then write this in standalone mode. + */ + AuxStoreInternal (bool standalone = false); + + + /** + * @brief Destructor. + * + * All contained data will be deleted. + */ + virtual ~AuxStoreInternal(); + + + /** + * @brief Copy constructor. + */ + AuxStoreInternal (const AuxStoreInternal& orig); + + + /** + * @brief Return the standalone flag. + */ + bool standalone() const; + + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * This should return 0 if the item doesn't exist. + */ + virtual const void* getData (SG::auxid_t auxid) const ATH_OVERRIDE; + + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + */ + virtual void* getData (SG::auxid_t auxid, size_t size, size_t capacity) + ATH_OVERRIDE; + + + /** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it then it will be created and initialized + * with default values. If the container is locked, then the new + * item will be marked as a decoration. @c size and @c capacity give + * the size for the new aux data item vector. + * + * If the data item already exists, then we return it if either the + * container is not locked or the item is marked as a decoration. + * Otherwise we throw an exception. + */ + virtual void* getDecoration (auxid_t auxid, size_t size, size_t capacity) + ATH_OVERRIDE; + + + /** + * @brief Change the size of all aux data vectors. + * @param sz The new size. + * + * This should be called when the size of the container changes. + * This should resize the vectors for all aux data items. + * + * If the size of the container grows, the new elements should + * be default-initialized; if it shrinks, destructors should + * be run as appropriate. + * + * Should return @c true if it is known that none of the data pointers + * changed (and thus the cache does not need to be cleared), false + * otherwise. + */ + virtual bool resize (size_t sz) ATH_OVERRIDE; + + + /** + * @brief Change the capacity of all aux data vectors. + * @param sz The new capacity. + * + * This should be called when the capacity of the container changes + * (by @c reserve). This should change the capacity for the vectors + * for all aux data items. + */ + virtual void reserve (size_t sz) ATH_OVERRIDE; + + + /** + * @brief Shift the elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + virtual void shift (size_t pos, ptrdiff_t offs) ATH_OVERRIDE; + + + /** + * @brief Move all elements from @c other to this store. + * @param pos The starting index of the insertion. + * @param other Store from which to do the move. + * @param ignore Set of variables that should not be added to the store. + * + * Let @c len be the size of @c other. The store will be increased + * in size by @c len elements, with the elements at @c pos being + * copied to @c pos+len. Then, for each auxiliary variable, the + * entire contents of that variable for @c other will be moved to + * this store at index @c pos. This will be done via move semantics + * if possible; otherwise, it will be done with a copy. Variables + * present in this store but not in @c other will have the corresponding + * elements default-initialized. Variables in @c other but not in this + * store will be added unless they are in @c ignore. + * + * Returns true if it is known that none of the vectors' memory moved, + * false otherwise. + */ + virtual bool insertMove (size_t pos, + IAuxStore& other, + const SG::auxid_set_t& ignore = SG::auxid_set_t()) ATH_OVERRIDE; + + + /** + * @brief Return a set of identifiers for existing data items + * in this store. + * + * This should include identifiers for all items, + * const and non-const. + */ + virtual const SG::auxid_set_t& getAuxIDs() const ATH_OVERRIDE; + + + /** + * @brief Return a set of identifiers for writable data items + * in this store. + * + * This should include only non-const identifiers. + */ + virtual const SG::auxid_set_t& getWritableAuxIDs() const ATH_OVERRIDE; + + + /** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ + virtual const void* getIOData (SG::auxid_t auxid) const ATH_OVERRIDE; + + + /** + * @brief Return the type of the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * For an aux data item of type @c T, this will usually be + * @c std::vector<T>. For standalone objects, however, it will + * usually be @c T; and @c std::vector<char> will be used instead + * of @c std::vector<bool>. + * + * Returns 0 if the requested aux data item does not exist. + */ + virtual const std::type_info* getIOType (SG::auxid_t auxid) const ATH_OVERRIDE; + + + /** + * @brief Get the list of all variables that need to be handled. + */ + virtual const SG::auxid_set_t& getDynamicAuxIDs() const ATH_OVERRIDE; + + + /** + * @brief Lock the container. + * + * After this, only decorations can be changed/modified. + * If the container is already locked, this is a no-op. + */ + virtual void lock() ATH_OVERRIDE; + + + /** + * @brief Clear all decorations. + * + * Erase all decorations from the store, restoring the state to when + * @c lock was called. Be sure to clear the cache of the referencing + * container! + */ + virtual void clearDecorations() ATH_OVERRIDE; + + + /** + * @brief Return the number of elements in the store. + * + * May return 0 for a store with no aux data. + */ + virtual size_t size() const ATH_OVERRIDE; + + + /** + * @brief Set an option for an auxiliary data variable. + * @param id The variable for which we want to set the option. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + virtual bool setOption (auxid_t id, const AuxDataOption& option) ATH_OVERRIDE; + + +protected: + /** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * @param quiet If true, then don't print an error on failure. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ + const void* getIODataInternal (auxid_t auxid, bool quiet) const; + + + /** + * @brief Add a new auxid to the set of those being managed by this store. + * @param auxid The auxid to add. + */ + void addAuxID (auxid_t auxid); + + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * @param no_lock_check If true, then skip the test for a locked container. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + */ + virtual void* getDataInternal (SG::auxid_t auxid, + size_t size, + size_t capacity, + bool no_lock_check); + + + /** + * @brief Explicitly add a vector to the store. + * @param auxid The identifier of the aux data item being added. + * @param vec Vector data being added. + * @param isDecoration Should this variable be marked as a decoration? + * + * For internal use. The @c auxid must not already exist in the store. + */ + void addVector (SG::auxid_t auxid, + std::unique_ptr<IAuxTypeVector> vec, + bool isDecoration); + + +private: + /// Implementation of getDataInternal; no locking. + virtual void* getDataInternal_noLock (SG::auxid_t auxid, + size_t size, + size_t capacity, + bool no_lock_check); + + /// Return the number of elements in the store; no locking. + size_t size_noLock() const; + + /// Are we being written in standalone mode? + bool m_standalone; + + /// The collection of vectors of aux data that we're managing, + /// indexed by @c auxid. + std::vector<IAuxTypeVector*> m_vecs; + + /// Record which variables are decorations. + std::vector<bool> m_isDecoration; + + // Hide this from root --- otherwise we get errors about the dictionary + // for this guy's allocator. +#ifndef __REFLEX__ + /// Set of @c auxid's for which we've created a vector. + SG::auxid_set_t m_auxids; +#endif + + /// Count changes to @c m_auxids. + size_t m_tick; + + /// Has this container been locked? + bool m_locked; + + /// Mutex used to synchronize modifications to the cache vector. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard<mutex_t> guard_t; + mutable mutex_t m_mutex; + + /// Thread-local versions of the auxid set. + struct TSAuxidSet + { + size_t m_tick; + auxid_set_t m_set; + TSAuxidSet (size_t tick, const auxid_set_t& set) + : m_tick (tick), m_set (set) {} + }; + mutable AthContainers_detail::thread_specific_ptr<TSAuxidSet> m_tsAuxids; + + +private: + // Don't allow assignment. + AuxStoreInternal& operator= (const AuxStoreInternal&); +}; + + +} // namespace SG + + + +#ifndef XAOD_STANDALONE + +#include "SGTools/BaseInfo.h" +#include "SGTools/CLASS_DEF.h" +SG_BASE( SG::AuxStoreInternal, SG::IAuxStore ); +CLASS_DEF( SG::AuxStoreInternal , 16428258 , 1 ) + +#endif // not XAOD_STANDALONE + + +#endif // not ATHCONTAINERS_AUXSTOREINTERNAL_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxStoreStandalone.h b/EDM/athena/Control/AthContainers/AthContainers/AuxStoreStandalone.h new file mode 100644 index 00000000..b7de87cd --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxStoreStandalone.h @@ -0,0 +1,53 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxStoreStandalone.h 597621 2014-05-18 04:19:29Z ssnyder $ +/** + * @file AthContainers/AuxStoreStandalone.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Auxiliary data store for standalone objects. + */ + + +#ifndef ATHCONTAINERS_AUXSTORESTANDALONE_H +#define ATHCONTAINERS_AUXSTORESTANDALONE_H + + +#include "AthContainers/AuxStoreInternal.h" + + +namespace SG { + + +/** + * @brief Auxiliary data store for standalone objects. + * + * This is a variant of @c AuxStoreInternal (from which it derives), + * meant to be used with standalone objects. (That is, objects + * that have aux data but are not in a container; this includes + * objects with a private store.) + * + * The difference from @c AuxStoreInternal is what we return for + * the @c IAuxStoreIO methods. For @c getIOData, we return a pointer + * to the start of the vector data, rather than the vector itself; and + * for @c getIOType, we return the type itself rather than the vector type. + */ +class AuxStoreStandalone + : public AuxStoreInternal +{ +public: + /** + * @brief Constructor. + */ + AuxStoreStandalone(); +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERS_AUXSTORESTANDALONE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.h b/EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.h new file mode 100644 index 00000000..97191311 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.h @@ -0,0 +1,711 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxTypeRegistry.h 637169 2014-12-19 23:10:51Z ssnyder $ +/** + * @file AthContainers/AuxTypeRegistry.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Handle mappings between names and auxid_t. + */ + + +#ifndef ATHCONTAINERS_AUXTYPEREGISTRY_H +#define ATHCONTAINERS_AUXTYPEREGISTRY_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include "AthContainersInterfaces/IAuxTypeVector.h" +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" +#include "AthContainers/tools/AuxTypeVector.h" +#include "AthContainers/tools/AuxTypeVectorFactory.h" +#include "AthContainers/tools/threading.h" +#include <cstddef> +#include <typeinfo> +#include <vector> + + +#if __cplusplus < 201100 +# include "CxxUtils/unordered_map.h" +namespace SG_STD_OR_SG = SG; +#else +# include <unordered_map> +# include <functional> +namespace SG_STD_OR_SG = std; +#endif + + +namespace SG { + + +/** + * @brief Handle mappings between names and auxid_t. + * + * Each auxiliary data item associated with a container has a name. + * Internally, they are identified by small integers of type @c auxid_t. + * This class handles the mapping between names and @c auxid_t's. + * It also keeps track of the type of each aux data item, and provides + * some generic methods for operating on this data. + * + * The @c auxid_t namespace is global, shared among all classes. + * It's no problem for two classes to use aux data with the same + * @c auxid_t, as long as the type is the same. If they want to define + * them as different types, though, that's a problem. To help with this, + * an optional class name may be supplied; this qualifies the aux data + * name to make it unique across classes. + * + * This class is meant to be used as a singleton. Use the @c instance + * method to get the singleton instance. + * + * Methods are locked internally, so access is thread-safe. + * However, since calls to registry methods are often used in a loop, + * externally-locked variants are also provided in order to reduce + * the overhead of locking. Use them like this: + * + *@code + * SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + * SG::AuxTypeRegistry::lock_t lock (r); + * std::string name = r.getName (lock, auxid); + @endcode + * + * Thread-safety is not supported in standalone builds. + */ +class AuxTypeRegistry +{ +public: + typedef AthContainers_detail::upgrade_mutex mutex_t; + typedef AthContainers_detail::strict_shared_lock<AuxTypeRegistry> lock_t; + typedef AthContainers_detail::upgrading_lock<mutex_t> upgrading_lock_t; + + /** + * @brief Return the singleton registry instance. + */ + static AuxTypeRegistry& instance(); + + + /** + * @brief Look up a name -> @c auxid_t mapping. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * + * The type of the item is given by the template parameter @c T. + * If an item with the same name was previously requested + * with a different type, then raise @c SG::ExcAuxTypeMismatch. + */ + template <class T> + SG::auxid_t getAuxID (const std::string& name, + const std::string& clsname = ""); + + + /** + * @brief Look up a name -> @c auxid_t mapping. + * @param ti Type of the aux data item. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * + * The type of the item is given by @a ti. + * Return @c null_auxid if we don't know how to make vectors of @a ti. + * (Use @c addFactory to register additional types.) + * If an item with the same name was previously requested + * with a different type, then raise @c SG::ExcAuxTypeMismatch. + */ + SG::auxid_t getAuxID (const std::type_info& ti, + const std::string& name, + const std::string& clsname = ""); + + + /** + * @brief Look up a name -> @c auxid_t mapping. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * + * Will only find an existing @c auxid_t; unlike @c getAuxID, + * this won't make a new one. If the item isn't found, this + * returns @c null_auxid. + */ + SG::auxid_t findAuxID( const std::string& name, + const std::string& clsname = "" ) const; + + + /** + * @brief Construct a new vector to hold an aux item. + * @param auxid The desired aux data item. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + IAuxTypeVector* makeVector (SG::auxid_t auxid, + size_t size, + size_t capacity) const; + + + /** + * @brief Construct a new vector to hold an aux item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + IAuxTypeVector* makeVector (lock_t& lock, + SG::auxid_t auxid, + size_t size, + size_t capacity) const; + + + /** + * @brief Construct an @c IAuxTypeVector object from a vector. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * But if @c isPacked is @c true, then @c data + * should instead point at an object of type @c SG::PackedContainer<T>. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + IAuxTypeVector* makeVectorFromData (SG::auxid_t auxid, + void* data, + bool isPacked, + bool ownFlag) const; + + + /** + * @brief Return the name of an aux data item. + * @param auxid The desired aux data item. + */ + std::string getName (SG::auxid_t auxid) const; + + + /** + * @brief Return the name of an aux data item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ + std::string getName (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Return the class name associated with an aux data item + * (may be blank). + * @param auxid The desired aux data item. + */ + std::string getClassName (SG::auxid_t auxid) const; + + + /** + * @brief Return the class name associated with an aux data item + * (may be blank). [external locking.] + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ + std::string getClassName (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Return the type of an aux data item. + * @param auxid The desired aux data item. + */ + const std::type_info* getType (SG::auxid_t auxid) const; + + + /** + * @brief Return the type of an aux data item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ + const std::type_info* getType (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Return the type name of an aux data item. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ + std::string getTypeName (SG::auxid_t auxid) const; + + + /** + * @brief Return the type name of an aux data item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ + std::string getTypeName (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Return the type of the STL vector used to hold an aux data item. + * @param auxid The desired aux data item. + */ + const std::type_info* getVecType (SG::auxid_t auxid) const; + + + /** + * @brief Return the type name of the STL vector used to hold an aux data item + * (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ + const std::type_info* getVecType (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Return the type of the STL vector used to hold an aux data item. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ + std::string getVecTypeName (SG::auxid_t auxid) const; + + + /** + * @brief Return the type name of the STL vector used to hold an aux data item + * (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ + std::string getVecTypeName (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Return size of an element in the STL vector. + * @param auxid The desired aux data item. + */ + size_t getEltSize (SG::auxid_t auxid) const; + + + /** + * @brief Return size of an element in the STL vector + * (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ + size_t getEltSize (lock_t& lock, + SG::auxid_t auxid) const; + + + /** + * @brief Copy an element between vectors. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + void copy (SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index); + + + /** + * @brief Copy an element between vectors (external locking). + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + void copy (lock_t& lock, + SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index); + + + /** + * @brief Copy an element between vectors. + * Apply any transformations needed for output. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + void copyForOutput (SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index); + + + /** + * @brief Copy an element between vectors (external locking). + * Apply any transformations needed for output. + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + void copyForOutput (lock_t& lock, + SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index); + + + /** + * @brief Swap an element between vectors. + * @param auxid The aux data item being operated on. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ + void swap (SG::auxid_t auxid, + void* a, size_t aindex, + void* b, size_t bindex); + + + /** + * @brief Swap an element between vectors (external locking). + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ + void swap (lock_t& lock, + SG::auxid_t auxid, + void* a, size_t aindex, + void* b, size_t bindex); + + + /** + * @brief Clear an element within a vector. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ + void clear (SG::auxid_t auxid, void* dst, size_t dst_index); + + + /** + * @brief Clear an element within a vector (external locking). + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ + void clear (lock_t& lock, + SG::auxid_t auxid, void* dst, size_t dst_index); + + + /** + * @brief Return the vector factory for a given vector element type. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ + const IAuxTypeVectorFactory* getFactory (const std::type_info& ti) const; + + + /** + * @brief Return the vector factory for a given vector element type. + * (external locking) + * @param lock The registry lock. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ + const IAuxTypeVectorFactory* getFactory (lock_t& lock, + const std::type_info& ti) const; + + + /** + * @brief Return the vector factory for a given vector element type. + * (external locking) + * @param lock The registry lock. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ + const IAuxTypeVectorFactory* getFactory (upgrading_lock_t& lock, + const std::type_info& ti) const; + + + /** + * @brief Add a new type -> factory mapping. + * @param ti Type of the vector element. + * @param factory The factory instance. The registry will take ownership. + * + * This records that @c factory can be used to construct vectors with + * an element type of @c ti. If a mapping already exists, the new + * factory is discarded, unless the old one is a dynamic factory and + * the new one isn't, in which case the new replaces the old one. + */ + void addFactory (const std::type_info& ti, IAuxTypeVectorFactory* factory); + + + /** + * @brief Lock the registry for shared access. + */ + void lock_shared() const; + + + /** + * @brief Unlock the registry for shared access. + */ + void unlock_shared() const; + + +private: + /** + * @brief Constructor. + * + * Populates the type -> factory mappings for standard C++ types. + */ + AuxTypeRegistry(); + + + /** + * @brief Destructor. + * + * Delete factory instances. + */ + ~AuxTypeRegistry(); + + + /// Disallow copy construction and assignment. + AuxTypeRegistry (const AuxTypeRegistry&); + AuxTypeRegistry& operator= (const AuxTypeRegistry&); + + + /** + * @brief Look up a name -> @c auxid_t mapping. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * @param ti The type of this aux data item. + * @param makeFactory Function to create a factory for this type, if needed. + * May return 0 if the type is unknown. + * + * + * If the aux data item already exists, check to see if the provided + * type matches the type that was used before. If so, then set + * return the auxid; otherwise, raise @c SG::ExcAuxTypeMismatch. + * + * If the aux data item does not already exist, then see if we + * have a factory registered for this @c type_info. If not, then + * call @c makeFactory and use what it returns. If that returns 0, + * then fail and return null_auxid. Otherwise, assign a new auxid + * and return it. + */ + SG::auxid_t + findAuxID (const std::string& name, + const std::string& clsname, + const std::type_info& ti, + IAuxTypeVectorFactory* (AuxTypeRegistry::*makeFactory) () const); + + + /** + * @brief Return the vector factory for a given vector element type. + * The registry lock must be held. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ + const IAuxTypeVectorFactory* getFactoryLocked (const std::type_info& ti) const; + + + /** + * @brief Return the vector factory for a given auxid. + * @param auxid The desired aux data item. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ + const IAuxTypeVectorFactory* getFactory (SG::auxid_t auxid) const; + + + /** + * @brief Return the vector factory for a given auxid. (external locking) + * @param lock The registry lock. + * @param auxid The desired aux data item. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ + const IAuxTypeVectorFactory* getFactory (lock_t& /*lock*/, + SG::auxid_t auxid) const; + + + /** + * @brief Add a new type -> factory mapping. (external locking) + * @param lock The registry lock. + * @param ti Type of the vector element. + * @param factory The factory instance. The registry will take ownership. + * + * This records that @c factory can be used to construct vectors with + * an element type of @c ti. If a mapping already exists, the new + * factory is discarded, unless the old one is a dynamic factory and + * the new one isn't, in which case the new replaces the old one. + */ + void addFactory (upgrading_lock_t& lock, + const std::type_info& ti, + IAuxTypeVectorFactory* factory); + + + /** + * @brief Create an @c AuxTypeVectorFactory instance. + * + * This is passed to @c findAuxID when we're looking up an item + * for which we know the type at compile-time. + */ + template <class T> + IAuxTypeVectorFactory* makeFactory() const; + + + /** + * @brief @c makeFactory implementation that always returns 0. + * + * This is passed to @c findAuxID when we're looking up an item + * for which we do not know the type at compile-time. + */ + IAuxTypeVectorFactory* makeFactoryNull() const; + + + /** + * @brief Initialize the m_isEL* flags for a given variable. + * @param auxid The variable for which the flags should be initialized. + * @param lock The registry lock (must be locked). + * + * ??? Should go away when we extend the factory interface. + */ + void setELFlags (upgrading_lock_t& lock, auxid_t auxid); + + + /** + * @brief Apply @c ElementLink output transformations to a single element. + * @param dst Pointer to the element. + * + * ??? Should go away when we extend the factory interface. + */ + void applyELThinning (void* dst); + + + /** + * @brief Apply @c ElementLink output transformations to a vector. + * @param dst Pointer to the vector. + * + * ??? Should go away when we extend the factory interface. + */ + void applyELVecThinning (void* dst); + + + /// Hold information about one aux data item. + struct typeinfo_t + { + /// Factory object. + const IAuxTypeVectorFactory* m_factory; + + /// Type of the aux data item. + const std::type_info* m_ti; + + /// Aux data name. + std::string m_name; + + /// Class name associated with this aux data item. May be blank. + std::string m_clsname; + }; + + + /// Table of aux data items, indexed by @c auxid. + std::vector<typeinfo_t> m_types; + + + /// Key used for name -> auxid lookup. + /// First element is name, second is class name. + typedef std::pair<std::string, std::string> key_t; + + + /// Helper to hash the key type. + struct stringpair_hash + { + size_t operator() (const key_t& key) const + { + return shash (key.first) + shash (key.second); + } + SG_STD_OR_SG::hash<std::string> shash; + }; + + +#ifndef __REFLEX__ + // As of gcc 4.8.3, the compiler will choke on an unordered_map decl + // if the hash object does not define operator(). However, that happens + // with reflex's shadow class generation. Easiest fix for now is just + // to hide this from reflex. + + /// Map from name -> auxid. + typedef SG_STD_OR_SG::unordered_map<key_t, SG::auxid_t, stringpair_hash> + id_map_t; + id_map_t m_auxids; + + /// Map from type_info -> IAuxTypeVectorFactory. + typedef SG_STD_OR_SG::unordered_map<const std::type_info*, + const IAuxTypeVectorFactory*> ti_map_t; + ti_map_t m_factories; +#endif + + /// Hold additional factory instances we need to delete. + std::vector<const IAuxTypeVectorFactory*> m_oldFactories; + + /// Mutex controlling access to the registry. + /// Reads should be much more common than writes, so use an upgrade_mutex. + mutable mutex_t m_mutex; + + /// Flag that a variable is an ElementLink. + /// ??? Should go away when we extend the factory interface. + /// ??? Separate from typeinfo_t to avoid the need for a full rebuild. + std::vector<bool> m_isEL; + + /// Flag that a variable is a vector of ElementLink. + /// ??? Should go away when we extend the factory interface. + /// ??? Separate from typeinfo_t to avoid the need for a full rebuild. + std::vector<bool> m_isELVec; +}; + + +} // namespace SG + + +#include "AthContainers/AuxTypeRegistry.icc" + + +#endif // not ATHCONTAINERS_AUXTYPEREGISTRY_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.icc b/EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.icc new file mode 100644 index 00000000..65ddcf51 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxTypeRegistry.icc @@ -0,0 +1,118 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxTypeRegistry.icc 602003 2014-06-16 17:07:01Z ssnyder $ +/** + * @file AthContainers/AuxTypeRegistry.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Handle mappings between names and auxid_t. + */ + + +namespace SG { + + +/** + * @brief Look up a name -> @c auxid_t mapping. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * + * The type of the item is given by the template parameter @c T. + * If an item with the same name was previously requested + * with a different type, then raise an @c AuxTypeMismatch exception. + */ +template <class T> +SG::auxid_t +AuxTypeRegistry::getAuxID (const std::string& name, + const std::string& clsname /*= ""*/) +{ + return findAuxID (name, clsname, typeid(T), &AuxTypeRegistry::makeFactory<T>); +} + + +/** + * @brief Lock the registry for shared access. + */ +inline +void AuxTypeRegistry::lock_shared() const +{ + m_mutex.lock_shared(); +} + + +/** + * @brief Unlock the registry for shared access. + */ +inline +void AuxTypeRegistry::unlock_shared() const +{ + m_mutex.unlock_shared(); +} + + +/** + * @brief Return the vector factory for a given auxid. + * @param auxid The desired aux data item. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ +inline +const IAuxTypeVectorFactory* +AuxTypeRegistry::getFactory (SG::auxid_t auxid) const +{ + lock_t lock (*this); + if (auxid >= m_types.size()) + return 0; + return m_types[auxid].m_factory; +} + + +/** + * @brief Return the vector factory for a given auxid. (external locking) + * @param lock The registry lock. + * @param auxid The desired aux data item. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ +inline +const IAuxTypeVectorFactory* +AuxTypeRegistry::getFactory (lock_t& /*lock*/, + SG::auxid_t auxid) const +{ + if (auxid >= m_types.size()) return 0; + return m_types[auxid].m_factory; +} + + +/** + * @brief Create an @c AuxTypeVectorFactory instance. + * + * This is passed to @c findAuxID when we're looking up an item + * for which we know the type at compile-time. + */ +template <class T> +inline +IAuxTypeVectorFactory* AuxTypeRegistry::makeFactory() const +{ + return new SG::AuxTypeVectorFactory<T>; +} + + +/** + * @brief @c makeFactory implementation that always returns 0. + * + * This is passed to @c findAuxID when we're looking up an item + * for which we do not know the type at compile-time. + */ +inline +IAuxTypeVectorFactory* AuxTypeRegistry::makeFactoryNull() const +{ + return 0; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.h b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.h new file mode 100644 index 00000000..68b2c7a9 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.h @@ -0,0 +1,726 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxVectorBase.h 797205 2017-02-14 19:38:03Z ssnyder $ +/** + * @file AthContainers/AuxVectorBase.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Manage index tracking and synchronization of auxiliary data. + */ + + +#ifndef ATHCONTAINERS_AUXVECTORBASE_H +#define ATHCONTAINERS_AUXVECTORBASE_H + + +#include "AthContainers/AuxVectorData.h" +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/IndexTrackingPolicy.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/ATHCONTAINERS_ASSERT.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/AuxStore_traits.h" +#include <vector> + + +namespace SG { + + +/** + * @brief Manage index tracking and synchronization of auxiliary data. + * + * An object, usually a @c DataVector, can have vectors of auxiliary + * data associated with it. In order to be able to find the auxiliary + * data for a given container element, the elements must hold their + * indices within the container (done by the @c AuxElement class). + * + * When the container changes, this information must be updated. + * Indices need to be changed, and corresponding changes need to be made + * in the vectors of associated auxiliary data. Most of the code + * in this class consists of helpers that effect these changes. + * These are intended to be called only by the deriving container class. + * + * This class also contains a flag to control whether or not indices + * should be tracked like this. This is controlled by the type of the + * payload and by the selected ownership and indexing policies. + * + * If the payload type does not derive from @c SG::AuxElement, then no index + * tracking is possible, and the flag is always false. + * + * Otherwise, it depends on the setting of the policies. The default + * value for the index tracking policy is DEFAULT_TRACK_INDICES. In that + * case, we track indices if this container owns its elements + * (OWN_ELEMENTS) and we don't if the container does not down its + * elements (VIEW_ELEMENTS). This is the usual case. However, + * the index tracking policy may also be set to ALWAYS_TRACK_INDICES + * or NEVER_TRACK_INDICES to override this. (The major foreseen use case + * for this is to allow index tracking for a view container populated + * with objects allocated from a @c DataPool.) + * + * The derived container should initialize this class by calling + * @c initAuxVectorBase. The derived container class is passed + * as a template argument; the ownership and index tracking policies + * are also passed. This method can be called again if the policies change. + * + * There are only a couple user-callable methods. The @c trackIndices + * method returns the current state of the index tracking flag. + * There are also wrappers for @c setStore method, which enforce the + * condition that one can't set a store for a container that does + * not do index tracking. + * + * The remaining methods are intended to be called only from the derived + * container class (and thus they are declared as protected). + * Besides a @c swap method, these include + * + * - @c setIndices, to reset the indices within a range to sequential values. + * - @c clearIndex, to clear the index / container for a single element. + * - @c clearIndices, to clear the index / container for elements + * within a range. + * - @c resize, to change the size of the aux data. + * - @c reserve, to change the capacity of the aux data. + * - @c shift, to shift a range of aux data up or down, to track + * insertions or deletions from within the container. + * - @c moveAux, to be used when an element or range of elements is moved + * into the container. + * - @c swapElementsAux, to swap aux data for two elements, possibly in + * different containers. + * - @c resortAux, to rearrange indices and aux data correctly after + * an operation that permuted the elements of the container. + * + */ +class AuxVectorBase + : public AuxVectorData +{ +public: + /** + * @brief Default constructor. + * + * This will disable index tracking by default. + * The constructor should be followed by a call to @c initAuxVectorBase. + * (This is separated from the constructor because calling non-default + * constructors of @c DataVector base classes can be awkward in the case + * of virtual derivation.) + */ + AuxVectorBase(); + + +#if __cplusplus > 201100 + /** + * @brief Move constructor. + * @param rhs The container from which to move. + */ + AuxVectorBase (AuxVectorBase&& rhs); + + + /** + * @brief Move assignment. + * @param rhs The container from which to move. + */ + AuxVectorBase& operator= (AuxVectorBase&& rhs); +#endif + + + /** + * @brief Destructor. + */ + virtual ~AuxVectorBase(); + + + /** + * @brief Return true if index tracking is enabled for this container. + */ + bool trackIndices() const; + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + * + * It is an error to set a store for a container for which index tracking + * is disabled. That will raise an @c ExcUntrackedSetStore exception. + */ + void setStore (const SG::IConstAuxStore* store); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will set both the const and non-const store pointers, and also + * clear the cache. + * + * It is an error to set a store for a container for which index tracking + * is disabled. That will raise an @c ExcUntrackedSetStore exception. + */ + void setStore (SG::IAuxStore* store); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + * + * It is an error to set a store for a container for which index tracking + * is disabled. That will raise an @c ExcUntrackedSetStore exception. + */ + void setStore (const DataLink< SG::IConstAuxStore >& store); + + + /** + * @brief Synonym for @c setStore with @c IConstAuxStore. + * @param store The new store. + */ + void setConstStore (const SG::IConstAuxStore* store); + + + /** + * @brief Synonym for @c setStore with @c IAuxStore. + * @param store The new store. + */ + void setNonConstStore (SG::IAuxStore* store); + + +protected: + /** + * @brief Initialize index tracking mode. + * @param ownPolicy The container ownership policy. + * @param indexTrackingPolicy The requested index tracking policy. + * + * DVL should be the most-derived class for this container. + * + * This handles the logic for setting the state of index tracking. + * If this container does not handle aux data, then index tracking + * is always off. Otherwise, it depends on the requested policies. + * In any case, it is an error to turn off index tracking + * for a container that has an associated aux store. + */ + template <class DVL> + void initAuxVectorBase (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy indexTrackingPolicy); + + + /** + * @brief Swap with another container. + * @param other The container with which to swap. + */ + void swap (AuxVectorBase& other); + + + /** + * @brief Set container/index for all elements within a range. + * @param beg Beginning of the range. + * @param end End of the range. + * @param first Index to set for the first element in the range. + * + * For all elements in the range, the container will be set to this container, + * and indices will be set sequentially, starting with @c first. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ + template <class ForwardIterator> + void setIndices (ForwardIterator beg, + ForwardIterator end, + size_t first = 0); + + + /** + * @brief Clear the container / index for element @c elt. + * @param elt Iterator to the element to clear. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ + template <class ForwardIterator> + void clearIndex (ForwardIterator elt); + + + /** + * @brief Clear the container / index for a range of elements. + * @param beg Beginning of the range. + * @param end End of the range. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ + template <class ForwardIterator> + void clearIndices (ForwardIterator beg, ForwardIterator end); + + + /** + * @brief Resize the aux data associated with this container. + * @param size The new container size. + * + * DVL should be the most-derived class for this container. + */ + template <class DVL> + void resize (size_t size); + + + /** + * @brief Change the capacity of the aux data associated with this container. + * @param size The new container size. + * + * DVL should be the most-derived class for this container. + */ + template <class DVL> + void reserve (size_t size); + + + /** + * @brief Shift the elements of the container. + * @param cont The container that's being shifted. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * The container should be the derived container. + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + template <class DVL> + void shift (DVL& cont, size_t pos, ptrdiff_t offs); + + + /** + * @brief Set index on an element and copy auxiliary data. + * @param index Container index at which the new element is being added. + * @param p The new element being added. + * @param clear If true, then any auxiliary data initially associated + * with @c p are cleared after being copied. + * @param skipDestClear Normally, if @c p does not have auxiliary data, + * then the variables of the destination are cleared. + * If this flag is true, then this clear is skipped. + * This can be appropriate as part of a push_back, + * where the destiniation is already known to be clear. + * + * Element @c p is being added to the container at @c index. + * If @c p has associated auxiliary data, copy it to the container + * at @c index. Then set the container / index on @c p. + */ + void moveAux (size_t index, SG::AuxElement* p, + bool clear = false, + bool skipDestClear = false); + + + /** + * @brief Set index on an element and copy auxiliary data. + * @param index Container index at which the new element is being added. + * @param p The new element being added. + * @param clear If true, then any auxiliary data initially associated + * with @c p are cleared after being copied. + * @param skipDestClear Normally, if @c p does not have auxiliary data, + * then the variables of the destination are cleared. + * If this flag is true, then this clear is skipped. + * This can be appropriate as part of a push_back, + * where the destiniation is already known to be clear. + * + * Overload for the no-auxdata case. + */ + void moveAux (size_t index, const void* p, bool clear = false, + bool skipDestClear = false); + + + /** + * @brief Set index on a range of elements and copy auxiliary data. + * @param index Container index at which the first new element is being added. + * @param beg The start of the range of new elements. + * @param end The end of the range of new elements. + * + * The elements in the range are being a added to the container at @c index. + * If the new elements have associated auxiliary data, + * copy it to the container starting at @c index. + * Then set the container / index on the elements in the range. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ + template <class ForwardIterator> + void moveAux (size_t index, ForwardIterator beg, ForwardIterator end); + + + /** + * @brief Swap indices and auxiliary data between two elements. + * @param aindex Index of the first element, in this container. + * @param bindex Index of the second element, in @c bcont. + * @param a Pointer to the first element. + * @param b Pointer to the second element. + * @param bcont Container holding the second element. + * (May be the same as this, but doesn't have to be.) + * + * Elements @c a at @c aindex in @c this and @c b at @c bindex in @c bcont + * are being swapped. Swap the index / container references between the + * elements and also swap the auxiliary data if it exists. + */ + void swapElementsAux (size_t aindex, + size_t bindex, + SG::AuxElement* a, + SG::AuxElement* b, + AuxVectorBase* bcont); + + + /** + * @brief Swap indices and auxiliary data between two elements. + * @param aindex Index of the first element, in this container. + * @param bindex Index of the second element, in @c bcont. + * @param a Pointer to the first element. + * @param b Pointer to the second element. + * @param bcont Container holding the second element. + * (May be the same as this, but doesn't have to be.) + * + * This is the no-auxdata case; it is a no-op except for checking + * @c m_trackIndices. + */ + void swapElementsAux (size_t aindex, + size_t bindex, + const void* a, + const void* b, + AuxVectorBase* bcont); + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param index Index in the container of the start of the range. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ + template <class ForwardIterator> + void resortAux (size_t index, + ForwardIterator beg, + ForwardIterator end); + + +private: + /** + * @brief Initialize index tracking mode --- no-auxdata specialization. + * @param ownPolicy The container ownership policy. + * @param indexTrackingPolicy The requested index tracking policy. + * + * Since this is the no-auxdata case, it always sets index tracking to false. + * An exception is raised if the container has an associated store + * (but that should never actually happen). + */ + void initAuxVectorBase1 (const SG_STD_OR_BOOST::false_type&, + SG::OwnershipPolicy /*ownPolicy*/, + SG::IndexTrackingPolicy /*indexTrackingPolicy*/); + + + /** + * @brief Initialize index tracking mode --- auxdata specialization. + * @param ownPolicy The container ownership policy. + * @param indexTrackingPolicy The requested index tracking policy. + * + * Sets index tracking based on the requested policies. + * An exception is raised if index tracking is disabled and the container + * has an associated store. + */ + void initAuxVectorBase1 (const SG_STD_OR_BOOST::true_type&, + SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy indexTrackingPolicy); + + + /** + * @brief Set container/index for all elements within a range. + * @param beg Beginning of the range. + * @param end End of the range. + * @param first Index to set for the first element in the range. + * + * This is the no-auxdata case; doesn't do anything other than checking + * @c m_trackIndices. + */ + template <class ForwardIterator> + void setIndices1 (const SG_STD_OR_BOOST::false_type&, + ForwardIterator beg, + ForwardIterator end, + size_t first); + + + /** + * @brief Set container/index for all elements within a range. + * @param beg Beginning of the range. + * @param end End of the range. + * @param first Index to set for the first element in the range. + * + * This is the auxdata case. + * For all elements in the range, the container will be set to this container, + * and indices will be set sequentially, starting with @c first. + */ + template <class ForwardIterator> + void setIndices1 (const SG_STD_OR_BOOST::true_type&, + ForwardIterator beg, + ForwardIterator end, + size_t first); + + + /** + * @brief Clear the container / index for element @c elt. + * @param elt Iterator to the element to clear. + * + * This is the no-auxdata case; doesn't do anything other than checking + * @c m_trackIndices. + */ + template <class ForwardIterator> + void clearIndex1 (const SG_STD_OR_BOOST::false_type&, ForwardIterator elt); + + + /** + * @brief Clear the container / index for element @c elt. + * @param elt Iterator to the element to clear. + * + * This is the auxdata case. + */ + template <class ForwardIterator> + void clearIndex1 (const SG_STD_OR_BOOST::true_type&, ForwardIterator elt); + + + /** + * @brief Clear the container / index for a range of elements. + * @param beg Beginning of the range. + * @param end End of the range. + * + * No-auxdata case; a no-op except for checking @c m_trackIndices. + */ + template <class ForwardIterator> + void clearIndices1 (const SG_STD_OR_BOOST::false_type&, + ForwardIterator, + ForwardIterator); + + + /** + * @brief Clear the container / index for a range of elements. + * @param beg Beginning of the range. + * @param end End of the range. + * + * Auxdata case. + */ + template <class ForwardIterator> + void clearIndices1 (const SG_STD_OR_BOOST::true_type&, + ForwardIterator beg, + ForwardIterator end); + + + + /** + * @brief Resize the aux data associated with this container. + * @param size The new container size. + * + * The no-auxdata case; a no-op except for checking @c m_trackIndices. + */ + void resize1 (const SG_STD_OR_BOOST::false_type&, size_t size); + + + /** + * @brief Resize the aux data associated with this container. + * @param size The new container size. + * + * The auxdata case. + */ + void resize1 (const SG_STD_OR_BOOST::true_type&, size_t size); + + + /** + * @brief Change the capacity of the aux data associated with this container. + * @param size The new container size. + * + * The no-auxdata case; a no-op except for checking @c m_trackIndices. + */ + void reserve1 (const SG_STD_OR_BOOST::false_type&, size_t size); + + + /** + * @brief Change the capacity of the aux data associated with this container. + * @param size The new container size. + * + * The auxdata case. + */ + void reserve1 (const SG_STD_OR_BOOST::true_type&, size_t size); + + + /** + * @brief Shift the elements of the container. + * @param cont The container that's being shifted. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * No-auxdata version; a no-op except for checking @c m_trackIndices. + */ + template <class DVL> + void shift1 (const SG_STD_OR_BOOST::false_type&, + DVL& cont, size_t pos, ptrdiff_t offs); + + + /** + * @brief Shift the elements of the container. + * @param cont The container that's being shifted. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * Auxdata version. + * + * The container should be the derived container. + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + template <class DVL> + void shift1 (const SG_STD_OR_BOOST::true_type&, + DVL& cont, size_t pos, ptrdiff_t offs); + + + /** + * @brief Set index on a range of elements and copy auxiliary data. + * @param index Container index at which the first new element is being added. + * @param beg The start of the range of new elements. + * @param end The end of the range of new elements. + * + * No-auxdata version; a no-op except for checking @c m_trackIndices. + */ + template <class ForwardIterator> + void moveAux1 (const SG_STD_OR_BOOST::false_type&, + size_t index, + ForwardIterator beg, + ForwardIterator end); + + + /** + * @brief Set index on a range of elements and copy auxiliary data. + * @param index Container index at which the first new element is being added. + * @param beg The start of the range of new elements. + * @param end The end of the range of new elements. + * + * The elements in the range are being a added to the container at @c index. + * If the new elements have associated auxiliary data, + * copy it to the container starting at @c index. + * Then set the container / index on the elements in the range. + * + * The auxdata case. + */ + template <class ForwardIterator> + void moveAux1 (const SG_STD_OR_BOOST::true_type&, + size_t index, + ForwardIterator beg, + ForwardIterator end); + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param index Index in the container of the start of the range. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * No-auxdata version; a no-op except for checking @c m_trackIndices. + */ + template <class ForwardIterator> + void resortAux1 (const SG_STD_OR_BOOST::false_type&, + size_t index, + ForwardIterator beg, + ForwardIterator end); + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param index Index in the container of the start of the range. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + * + * The auxdata case. + */ + template <class ForwardIterator> + void resortAux1 (const SG_STD_OR_BOOST::true_type&, + size_t index, + ForwardIterator a, + ForwardIterator b); + + +private: + /** + * @brief Helper to factor out template-independent part of @c resortAux. + * + * See the cxx file for more details. + */ + class ResortAuxHelper + { + public: + ResortAuxHelper (size_t sz, size_t index, AuxVectorBase& vec); + void resortElement (size_t idx, SG::AuxElement* elt); + + private: + AuxVectorBase& m_vec; + size_t m_index; + std::vector<size_t> m_imap; + std::vector<size_t> m_rmap; + std::vector<void*> m_auxdata; + std::vector<SG::auxid_t> m_auxids; + SG::AuxTypeRegistry::lock_t m_lock; + + ResortAuxHelper(); + }; + void* getDataArrayForResort (SG::auxid_t auxid); + void setIndexForResort (SG::AuxElement* elt, size_t idx); + friend class ResortAuxHelper; + + + /// Flag if index tracking is enabled. + bool m_trackIndices; +}; + + +} // namespace SG + + +#include "AthContainers/AuxVectorBase.icc" + + +#endif // not DATAMODEL_AUXVECTORBASE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.icc b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.icc new file mode 100644 index 00000000..58178986 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorBase.icc @@ -0,0 +1,658 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxVectorBase.icc 797205 2017-02-14 19:38:03Z ssnyder $ +/** + * @file AthContainers/AuxVectorBase.icc + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Manage index tracking and synchronization of auxiliary data. + */ + + +namespace SG { + + +/** + * @brief Return true if index tracking is enabled for this container. + */ +inline +bool AuxVectorBase::trackIndices() const +{ + return m_trackIndices; +} + + +/** + * @brief Synonym for @c setStore with @c IConstAuxStore. + * @param store The new store. + */ +inline +void AuxVectorBase::setConstStore (const SG::IConstAuxStore* store) +{ + setStore (store); +} + + +/** + * @brief Synonym for @c setStore with @c IAuxStore. + * @param store The new store. + */ +inline +void AuxVectorBase::setNonConstStore (SG::IAuxStore* store) +{ + setStore (store); +} + + +/** + * @brief Initialize index tracking mode. + * @param ownPolicy The container ownership policy. + * @param indexTrackingPolicy The requested index tracking policy. + * + * DVL should be the most-derived class for this container. + * + * This handles the logic for setting the state of index tracking. + * If this container does not handle aux data, then index tracking + * is always off. Otherwise, it depends on the requested policies. + * In any case, it is an error to turn off index tracking + * for a container that has an associated aux store. + */ +template <class DVL> +inline +void +AuxVectorBase::initAuxVectorBase (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy indexTrackingPolicy) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + this->initAuxVectorBase1 (typename AuxStore_traits<DVL>::flag(), + ownPolicy, + indexTrackingPolicy); +} + + +/** + * @brief Swap with another container. + * @param other The container with which to swap. + */ +inline +void AuxVectorBase::swap (AuxVectorBase& other) +{ + std::swap (m_trackIndices, other.m_trackIndices); + SG::AuxVectorData::swap (other); +} + + +/** + * @brief Set container/index for all elements within a range. + * @param beg Beginning of the range. + * @param end End of the range. + * @param first Index to set for the first element in the range. + * + * For all elements in the range, the container will be set to this container, + * and indices will be set sequentially, starting with @c first. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ +template <class ForwardIterator> +inline +void AuxVectorBase::setIndices (ForwardIterator beg, + ForwardIterator end, + size_t first /*= 0*/) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + typedef typename std::iterator_traits<ForwardIterator>::value_type valtype; + setIndices1 (typename AuxStore_traits<valtype>::flag(), + beg, end, first); +} + + +/** + * @brief Set container/index for all elements within a range. + * @param beg Beginning of the range. + * @param end End of the range. + * @param first Index to set for the first element in the range. + * + * This is the no-auxdata case; doesn't do anything other than checking + * @c m_trackIndices. + */ +template <class ForwardIterator> +inline +void AuxVectorBase::setIndices1 (const SG_STD_OR_BOOST::false_type&, + ForwardIterator, + ForwardIterator, + size_t) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Set container/index for all elements within a range. + * @param beg Beginning of the range. + * @param end End of the range. + * @param first Index to set for the first element in the range. + * + * This is the auxdata case. + * For all elements in the range, the container will be set to this container, + * and indices will be set sequentially, starting with @c first. + */ +template <class ForwardIterator> +void AuxVectorBase::setIndices1 (const SG_STD_OR_BOOST::true_type&, + ForwardIterator beg, + ForwardIterator end, + size_t first) +{ + if (!m_trackIndices) + return; + + for (; beg != end; ++beg) { + if (*beg) + (*beg)->setIndex (first, this); + ++first; + } +} + + +/** + * @brief Clear the container / index for element @c elt. + * @param elt Iterator to the element to clear. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ +template <class ForwardIterator> +inline +void AuxVectorBase::clearIndex (ForwardIterator elt) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + typedef typename std::iterator_traits<ForwardIterator>::value_type valtype; + clearIndex1 (typename AuxStore_traits<valtype>::flag(), elt); +} + + +/** + * @brief Clear the container / index for element @c elt. + * @param elt Iterator to the element to clear. + * + * This is the no-auxdata case; doesn't do anything other than checking + * @c m_trackIndices. + */ +template <class ForwardIterator> +inline +void AuxVectorBase::clearIndex1 (const SG_STD_OR_BOOST::false_type&, + ForwardIterator /*elt*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Clear the container / index for element @c elt. + * @param elt Iterator to the element to clear. + * + * This is the auxdata case. + */ +template <class ForwardIterator> +void AuxVectorBase::clearIndex1 (const SG_STD_OR_BOOST::true_type&, + ForwardIterator elt) +{ + if (!m_trackIndices) + return; + + if (*elt) + (*elt)->setIndex (0, 0); +} + + +/** + * @brief Clear the container / index for a range of elements. + * @param beg Beginning of the range. + * @param end End of the range. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ +template <class ForwardIterator> +void AuxVectorBase::clearIndices (ForwardIterator beg, + ForwardIterator end) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + typedef typename std::iterator_traits<ForwardIterator>::value_type valtype; + clearIndices1 (typename AuxStore_traits<valtype>::flag(), + beg, end); +} + + +/** + * @brief Clear the container / index for a range of elements. + * @param beg Beginning of the range. + * @param end End of the range. + * + * No-auxdata case; a no-op except for checking @c m_trackIndices. + */ +template <class ForwardIterator> +inline +void AuxVectorBase::clearIndices1 (const SG_STD_OR_BOOST::false_type&, + ForwardIterator, + ForwardIterator) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Clear the container / index for a range of elements. + * @param beg Beginning of the range. + * @param end End of the range. + * + * Auxdata case. + */ +template <class ForwardIterator> +void AuxVectorBase::clearIndices1 (const SG_STD_OR_BOOST::true_type&, + ForwardIterator beg, + ForwardIterator end) +{ + if (!m_trackIndices) + return; + + for (; beg != end; ++beg) + if (*beg) + (*beg)->setIndex (0, 0); +} + + +/** + * @brief Resize the aux data associated with this container. + * @param size The new container size. + * + * DVL should be the most-derived class for this container. + */ +template <class DVL> +inline +void AuxVectorBase::resize (size_t size) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + resize1 (typename AuxStore_traits<DVL>::flag(), size); +} + + +/** + * @brief Resize the aux data associated with this container. + * @param size The new container size. + * + * The no-auxdata case; a no-op except for checking @c m_trackIndices. + */ +inline +void +AuxVectorBase::resize1 (const SG_STD_OR_BOOST::false_type&, size_t /*size*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Change the capacity of the aux data associated with this container. + * @param size The new container size. + * + * DVL should be the most-derived class for this container. + */ +template <class DVL> +inline +void AuxVectorBase::reserve (size_t size) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + reserve1 (typename AuxStore_traits<DVL>::flag(), size); +} + + +/** + * @brief Change the capacity of the aux data associated with this container. + * @param size The new container size. + * + * The no-auxdata case; a no-op except for checking @c m_trackIndices. + */ +inline +void AuxVectorBase::reserve1 (const SG_STD_OR_BOOST::false_type&, size_t) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Shift the elements of the container. + * @param cont The container that's being shifted. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * The container should be the derived container. + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +template <class DVL> +inline +void AuxVectorBase::shift (DVL& cont, + size_t pos, + ptrdiff_t offs) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + shift1 (typename AuxStore_traits<DVL>::flag(), + cont, pos, offs); +} + + +/** + * @brief Shift the elements of the container. + * @param cont The container that's being shifted. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * No-auxdata version; a no-op except for checking @c m_trackIndices. + */ +template <class DVL> +inline +void AuxVectorBase::shift1 (const SG_STD_OR_BOOST::false_type&, + DVL& /*cont*/, + size_t /*pos*/, ptrdiff_t /*offs*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Shift the elements of the container. + * @param cont The container that's being shifted. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * Auxdata version. + * + * The container should be the derived container. + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +template <class DVL> +void AuxVectorBase::shift1 (const SG_STD_OR_BOOST::true_type&, + DVL& cont, + size_t pos, ptrdiff_t offs) +{ + if (!m_trackIndices) return; + + typename DVL::iterator end = cont.end(); + typename DVL::iterator pos_it = cont.begin() + pos + offs; + for (; pos_it != end; ++pos_it) + { + SG::AuxElement* elt = *pos_it; + elt->setIndex (elt->index() + offs, this); + } + + if (this->hasNonConstStore()) { + this->getStore()->shift (pos, offs); + clearCache(); + } + else if (this->hasStore()) + throw SG::ExcConstAuxData ("shift"); +} + + +/** + * @brief Set index on an element and copy auxiliary data. + * @param index Container index at which the new element is being added. + * @param p The new element being added. + * @param clear If true, then any auxiliary data initially associated + * with @c p are cleared after being copied. + * + * Overload for the no-auxdata case. + */ +inline +void +AuxVectorBase::moveAux (size_t /*index*/, + const void /*p*/*, + bool /*clear = false*/, + bool /*skipDestClear = false*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Set index on a range of elements and copy auxiliary data. + * @param index Container index at which the first new element is being added. + * @param beg The start of the range of new elements. + * @param end The end of the range of new elements. + * + * The elements in the range are being a added to the container at @c index. + * If the new elements have associated auxiliary data, + * copy it to the container starting at @c index. + * Then set the container / index on the elements in the range. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ +template <class ForwardIterator> +void +AuxVectorBase::moveAux (size_t index, ForwardIterator beg, ForwardIterator end) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + typedef typename std::iterator_traits<ForwardIterator>::value_type valtype; + moveAux1 (typename AuxStore_traits<valtype>::flag(), + index, beg, end); +} + + +/** + * @brief Set index on a range of elements and copy auxiliary data. + * @param index Container index at which the first new element is being added. + * @param beg The start of the range of new elements. + * @param end The end of the range of new elements. + * + * No-auxdata version; a no-op except for checking @c m_trackIndices. + */ +template <class ForwardIterator> +inline +void AuxVectorBase::moveAux1 (const SG_STD_OR_BOOST::false_type&, + size_t /*index*/, + ForwardIterator /*beg*/, + ForwardIterator /*end*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Set index on a range of elements and copy auxiliary data. + * @param index Container index at which the first new element is being added. + * @param beg The start of the range of new elements. + * @param end The end of the range of new elements. + * + * The elements in the range are being a added to the container at @c index. + * If the new elements have associated auxiliary data, + * copy it to the container starting at @c index. + * Then set the container / index on the elements in the range. + * + * The auxdata case. + */ +template <class ForwardIterator> +void AuxVectorBase::moveAux1 (const SG_STD_OR_BOOST::true_type&, + size_t index, + ForwardIterator beg, + ForwardIterator end) +{ + if (!m_trackIndices) + return; + + while (beg != end) { + this->moveAux (index, *beg); + ++beg; + ++index; + } +} + + +/** + * @brief Swap indices and auxiliary data between two elements. + * @param aindex Index of the first element, in this container. + * @param bindex Index of the second element, in @c bcont. + * @param a Pointer to the first element. + * @param b Pointer to the second element. + * @param bcont Container holding the second element. + * (May be the same as this, but doesn't have to be.) + * + * This is the no-auxdata case; it is a no-op except for checking + * @c m_trackIndices. + */ +inline +void AuxVectorBase::swapElementsAux (size_t /*aindex*/, + size_t /*bindex*/, + const void* /*a*/, + const void* /*b*/, + AuxVectorBase* /*bcont*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param index Index in the container of the start of the range. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ +template <class ForwardIterator> +inline +void AuxVectorBase::resortAux (size_t index, + ForwardIterator beg, + ForwardIterator end) +{ + // If the xAOD base classes are used, then they always report that + // static auxids are present. However, if the container is empty, + // these variables are not actually retrievable, which can cause + // an exception in the ResortAuxHelper ctor. Work around here. + if (beg==end) return; + + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + typedef typename std::iterator_traits<ForwardIterator>::value_type valtype; + resortAux1 (typename AuxStore_traits<valtype>::flag(), + index, beg, end); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param index Index in the container of the start of the range. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * No-auxdata version; a no-op except for checking @c m_trackIndices. + */ +template <class ForwardIterator> +inline +void AuxVectorBase::resortAux1 (const SG_STD_OR_BOOST::false_type&, + size_t /*index*/, + ForwardIterator /*beg*/, + ForwardIterator /*end*/) +{ + ATHCONTAINERS_ASSERT (!m_trackIndices); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param index Index in the container of the start of the range. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + * + * The auxdata case. + */ +template <class ForwardIterator> +void AuxVectorBase::resortAux1 (const SG_STD_OR_BOOST::true_type&, + size_t index, + ForwardIterator beg, + ForwardIterator end) +{ + if (!m_trackIndices) return; + if (!this->hasStore()) { + this->setIndices (beg, end, index); + return; + } + if (!this->hasNonConstStore()) { + throw SG::ExcConstAuxData ("resortAux"); + } + + ResortAuxHelper h (end-beg, index, *this); + for (size_t i = 0; beg < end; ++beg, ++i) + h.resortElement (i, *beg); +} + + +/// Helper to call @c getDataArray from @c ResortAuxHelper. +inline +void* AuxVectorBase::getDataArrayForResort (SG::auxid_t auxid) +{ + return this->getDataArray (auxid); +} + + +/// Helper to call @c setIndex from @c ResortAuxHelper. +inline +void AuxVectorBase::setIndexForResort (SG::AuxElement* elt, size_t i) +{ + elt->setIndex (i, this); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.h b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.h new file mode 100644 index 00000000..11a359df --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.h @@ -0,0 +1,909 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxVectorData.h 797205 2017-02-14 19:38:03Z ssnyder $ +/** + * @file AthContainers/AuxVectorData.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Manage lookup of vectors of auxiliary data. + */ + + +#ifndef ATHCONTAINERS_AUXVECTORDATA_H +#define ATHCONTAINERS_AUXVECTORDATA_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainersInterfaces/AuxDataOption.h" +#include "AthContainers/tools/AuxDataTraits.h" +#include "AthLinks/DataLink.h" +#ifndef XAOD_STANDALONE +# include "AthenaKernel/ILockable.h" +# include "AthenaKernel/IThinningSvc.h" +#endif // not XAOD_STANDALONE +#include "CxxUtils/override.h" +#include <vector> +#include <utility> +#include <cstdlib> + +#include "AthContainers/tools/likely.h" +#include "AthContainers/tools/assume.h" +#include "AthContainers/tools/threading.h" + + +namespace SG { + + +class AuxElement; +class IAuxStore; +class AuxDataOption; + + +/** + * @brief Manage lookup of vectors of auxiliary data. + * + * An object, usually a @c DataVector, can have vectors of auxiliary + * data associated with it. This class manages this association. + * + * An auxiliary data item is identified by an integer of type + * @c SG::auxid_t. The @c getData methods can be used to get + * a reference to one auxiliary data element given the @c auxid + * and the vector index. However, @c getData does not do type checking, + * so it should generally not be used. (Use instead the @c Accessor + * or @c ConstAccessor classes defined in @c AuxElement.) + * + * The auxiliary data is not managed by this class, but rather by + * a separate `aux store' class, to which we hold a pointer. + * Actually, there can be two pointers. We define two interfaces + * for an aux store, @c IConstAuxStore, which defines operations + * for accessing data read-only, and @c IAuxStore, which defines + * operations for modifying data. If we have a const store, + * only the pointer to the const interface is set; if we have + * non-const store, then both pointers are set (to the same object). + * + * To speed up access to aux data, we cache pointers to the start + * of the data for each vector. There are separate caches + * for const and non-const pointers. If you make any changes + * to the aux store behind the back of this container object, + * you should call @c clearCache. + * + * We also support adding `decorations' to a const container. These are + * new auxiliary data items that don't conflict with existing ones. + * See IConstAuxStore for more information. + * + * Notes on thread safety: + * + * It's a little tricky to make this class thread-safe without spoiling + * the optimizations in getDataArray. This section outlines some of the + * considerations that went into the chosen solution. + * + * First, by `thread-safe', we mean that getDataArray can be called + * in different threads without problems. This is necessary to allow + * simultaneous reads of the container. We make no attempt to any + * synchronization on modifications to the container, such as adding elements. + * Such operations must be synchronized externally. This is the same + * sort of thread semantics that the STL containers supply. So our + * considerations of thread-safety involve only the management + * of the cache vector. + * + * Second, reads (of the cache vector) are very common (and inlined), + * while modifications of it are uncommon (and handled by out-of-line code). + * Thus, we would like reading to be entirely lock-free. If we need + * to make modifications, though, we can do whatever locking we need. + * Making the reader lock-free, though, is complicated by the fact + * that the cache vector may relocate in memory if is expanded. + * + * A way forward is suggested by read-copy-update (RCU) synchronization. + * The idea there is that when you want to change some structure, + * you copy it and work on the copy. When the modifications are done, + * the new structure is copied to the old one in such a manner that + * at any instant in time, any reader will see a consistent version + * of the structure (even though it may not be the most recent one). + * + * For this case, we can store the vector as a length and a pointer + * to the beginning. When we want to access AUXID, we first + * compare it to the length. If that's ok, then we test the + * pointer at index AUXID. If that's non-null, we go ahead and use it; + * if either test fails, we go to the out-of-line code. + * + * The out-of-line code can then take out a lock and will in the new + * pointer in the vector. If it is necessary to expand the the vector, + * we allocate a new one and copy the old vector to the new one. + * Then we update the values: first, the pointer, then the length. + * This ensures that the inline code will always see something + * consistent. Then we must delay freeing the old vector until we're + * sure that no thread can possibly be using it anymore. For now, + * we just avoid deleting the old vectors until the container itself + * is deleted; the memory wasted by this should be negligible in the + * context of reconstruction. + * + * This allows the inline part of the code to avoid locking. However, + * there is an additional critical detail. We have a test like this: + * + * m_cache_length <= auxid || !m_cache[auxid] + * + * As long as the length is read before the cache pointer itself, + * everything's fine, even if those reads were some time in the past. + * But if the reads can be in the other order, we could face disaster. + * While the short-circuit operator should prevent the array indexing + * from happening before the length is read, there is nothing a priori + * to prevent a speculative read of m_cache before the length. For the + * cognoscenti, this is a `control dependency' (rather than a `data dependency'), + * which implies no ordering guarantees. + * + * Now, we can deal with this by inserting a read barrier between the two loads. + * That should be correct in all cases. However, that tends to destroy + * the optimization below for repeated references to the same aux data item + * (see the use of @c ATHCONTAINERS_ASSUME in @c getDataArray in the icc file). + * + * It turns out that on x86 machines, memory ordering guarantees are relatively + * strong. In particular, loads cannot be reordered with other loads, + * and stores from one CPU are seen in the same order by all other CPUs. + * So in this case, no barrier is actually needed --- provided that the + * compiler emits the loads in the correct order. The supported way + * to do this with gcc is to use `asm volatile ("":::"memory")' --- however, + * that explicitly clobbers member, which again spoils our optimization. + * + * While it seems unlikely that the compiler would actually find it worthwhile + * to reorder the loads on an x86 machine, some extra safety would be nice. + * We try to prevent this reordering by adding an explicit data dependency. + * Instead of a single m_cache pointer, we have an array of two pointers + * (which will be identical) and use m_cache[m_cache_len&1]. This + * provides an explicit data dependency which should prevent reading the + * pointer before the length; the cost is an added and operation and adding + * an index register to the dereference operation. + * + * Actually, this is not completely watertight; the compiler could in principle + * decide to speculate the reads of both pointers, or speculate one and + * then throw it away if it guessed wrong. This seems sufficiently unlikely + * to be an issue that we'll live with it for now --- though it might + * be worth having something to validate the generated code. + */ +class AuxVectorData +#ifndef XAOD_STANDALONE + : public ILockable +#endif // not XAOD_STANDALONE +{ +public: + /// Constructor. + AuxVectorData(); + + +#if __cplusplus > 201100 + /** + * @brief Move constructor. + * @param rhs The container from which to move. + */ + AuxVectorData (AuxVectorData&& rhs); + + + /** + * @brief Move assignment. + * @param rhs The container from which to move. + */ + AuxVectorData& operator= (AuxVectorData&& rhs); +#endif + + + /// Destructor. + virtual ~AuxVectorData(); + + + /** + * @brief Return the size of the container. + * + * This is used when we need to create a new aux data vector. + */ + virtual size_t size_v() const = 0; + + + /** + * @brief Return the capacity of the container. + * + * This is used when we need to create a new aux data vector. + */ + virtual size_t capacity_v() const = 0; + + + //======================================================================== + /** @name Aux store management. */ + //@{ + + + /** + * @brief Return the current store, as a const interface. + * + * This will be non-zero if either a const or non-const store + * is associated with this object. + */ + const SG::IConstAuxStore* getConstStore() const; + + + /** + * @brief Return the data link to the current store, as a const interface. + * + * This is set by persistency when reading an object, but it may + * be overridden by setting the store pointer directly. + */ + const DataLink<SG::IConstAuxStore> getConstStoreLink() const; + + + /** + * @brief Return the current store, as a non-const interface. + * + * This will be non-zero if a non-const store is associated with this object. + */ + SG::IAuxStore* getStore() const; + + + /** + * @brief Return true if this object has an associated store. + */ + bool hasStore() const; + + + /** + * @brief Return true if this object has an associated non-const store. + */ + bool hasNonConstStore() const; + + + /** + * @brief Set an option for an auxiliary data variable. + * @param id The variable for which we want to set the option. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + bool setOption (auxid_t id, const AuxDataOption& option); + + + /** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + bool setOption (const std::string& name, + const AuxDataOption& option); + + + /** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param clsname The name of the associated class. May be blank. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + bool setOption (const std::string& name, + const std::string& clsname, + const AuxDataOption& option); + + + /** + * @brief Set an option for an auxiliary data variable. + * @param id The variable for which we want to set the option. + * @param optname The name of the option to set. + * @param arg The option value to set. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + template <class T> + bool setOption (auxid_t id, const std::string& optname, T arg); + + + /** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param optname The name of the option to set. + * @param arg The option value to set. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + bool setOption (const std::string& name, + const std::string& optname, + int arg); + bool setOption (const std::string& name, + const std::string& optname, + float arg); + bool setOption (const std::string& name, + const std::string& optname, + double arg); + + + /** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param clsname The name of the associated class. May be blank. + * @param optname The name of the option to set. + * @param arg The option value to set. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ + template <class T> + bool setOption (const std::string& name, + const std::string& clsname, + const std::string& optname, + T arg); + + + +protected: + // These are protected. They shouldn't be called directly but + // instead from @c setStore methods in derived classes, which do + // extra consistency checking. + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + */ + void setStore (const SG::IConstAuxStore* store); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will set both the const and non-const store pointers, and also + * clear the cache. + */ + void setStore (SG::IAuxStore* store); + + + /** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + */ + void setStore (const DataLink< SG::IConstAuxStore >& store); + + + //@} + //======================================================================== + /** @name Data access. */ + //@{ +public: + + + /** + * @brief Return a set of identifiers for existing data items + * in store associated with this object. + * + * This will include identifiers for all items, + * const and non-const. If no store is associated + * with this object, this will return an empty set. + */ + const SG::auxid_set_t& getAuxIDs() const; + + + /** + * @brief Return a set of identifiers for writable data items + * in this store. + * + * This will include only non-const identifiers. + * If no store is associated + * with this object, this will return an empty set. + */ + const SG::auxid_set_t& getWritableAuxIDs() const; + + + /** + * @brief Test to see if a variable exists in the store. + * @param id The variable to test. + */ + bool isAvailable (auxid_t id) const; + + + /** + * @brief Test to see if a variable exists in the store. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + */ + template <class T> + bool isAvailable (const std::string& name, + const std::string& clsname = "") const; + + + /** + * @brief Test to see if a variable is available for writing. + * @param id The variable to test. + */ + bool isAvailableWritable (auxid_t id) const; + + + /** + * @brief Test to see if a variable is available for writing. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + */ + template <class T> + bool isAvailableWritable (const std::string& name, + const std::string& clsname = "") const; + + + /** + * @brief Test to see if a variable is available for writing as a decoration. + * @param id The variable to test. + */ + bool isAvailableWritableAsDecoration (auxid_t id) const; + + + /** + * @brief Test to see if a variable is available for writing as a decoration. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + */ + template <class T> + bool isAvailableWritableAsDecoration (const std::string& name, + const std::string& clsname = "") const; + + + /** + * @brief Return reference to an aux data item. + * @param auxid The desired aux data item. + * @param ndx Index of the element to return. + * + * This will return a reference to element @c ndx of aux data item @c auxid. + * If the aux data item does not exist, it will be created. + * Errors are signaled by raising an exception. + * + * Warning: no type checking is done. You should usually access + * the data via @c AuxElement::Accessor or @c AuxElement::ConstAccessor. + */ + template <class T> + typename AuxDataTraits<T>::reference_type + getData (SG::auxid_t auxid, size_t ndx); + + + /** + * @brief Return const reference to an aux data item. + * @param auxid The desired aux data item. + * @param ndx Index of the element to return. + * + * This will return a reference to element @c ndx of aux data item @c auxid. + * Errors are signaled by raising an exception. + * + * Warning: no type checking is done. You should usually access + * the data via @c AuxElement::Accessor or @c AuxElement::ConstAccessor. + */ + template <class T> + typename AuxDataTraits<T>::const_reference_type + getData (SG::auxid_t auxid, size_t ndx) const; + + + /** + * @brief Return reference to an aux decoration item. + * @param auxid The desired aux decoration item. + * @param ndx Index of the element to return. + * + * This will return a reference to element @c ndx of aux decoration + * item @c auxid. + * If the aux data item does not exist, it will be created. + * Errors are signaled by raising an exception. + * + * Warning: no type checking is done. You should usually access + * the data via @c AuxElement::Decorator. + * + * The difference between @c getDecoration and @c getData is that + * @c getDecoration takes a const container as input, but returns + * a non-const reference. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ + template <class T> + typename AuxDataTraits<T>::reference_type + getDecoration (SG::auxid_t auxid, size_t ndx) const; + + + /** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. + * Errors are signaled by raising an exception. + */ + const void* getDataArray (SG::auxid_t auxid) const; + + + /** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item does not exist, + * this will return nullptr rather than raising an exception. + */ + const void* getDataArrayAllowMissing (SG::auxid_t auxid) const; + + +protected: + /** + * @brief Return a pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + */ + void* getDataArray (SG::auxid_t auxid); + + + /** + * @brief Return a pointer to the start of an aux data vector for a decoration. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + * + * The difference between @c getDecorationArray and @c getDataArray is that + * @c getDecorationArray takes a const container as input, but returns + * a non-const pointer. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ + void* getDecorationArray (SG::auxid_t auxid) const; + + + /// Minimum length to use for the cache vector. + /// This can be changed for regression tests. + static size_t s_minCacheLen; + + + //@} + //======================================================================== + /** @name Other operations. */ + //@{ +public: + + + /** + * @brief Swap this instance with another. + * @param other The other instance with which to swap. + */ + void swap (AuxVectorData& other); + + + /** + * @brief Clear the cached aux data pointers. + * + * You should call this any time something changes in the aux store + * that could invalidate the vector pointers. + */ + void clearCache(); + + + /** + * @brief Lock the container. + * + * After this, only decorations can be changed/modified. + * If the container is already locked, this is a no-op. + */ +#ifndef XAOD_STANDALONE + virtual +#endif // not XAOD_STANDALONE + void lock() +#ifndef XAOD_STANDALONE + ATH_OVERRIDE +#endif // not XAOD_STANDALONE + ; + + + /** + * @brief Clear all decorations. + * + * Erase all decorations from the store, restoring the state to when + * @c lock was called. + */ + void clearDecorations() const; + + + //@} + + + +private: + /** + * @brief Manage cache of pointers to aux element vectors. + * + * See the thread-safety comments at the start of this file + * for notes on what's going on here. + */ + class Cache + { + public: + /** + * @brief Cache manager constructor. + */ + Cache(); + + +#if __cplusplus > 201100 + /** + * @brief Cache manager move constructor. + * @param rhs The cache from which to copy. + */ + Cache (Cache&& rhs); + + + /** + * @brief Cache manager move assignment. + * @param rhs The cache from which to copy. + */ + Cache& operator= (Cache&& rhs); +#endif + + + /** + * @brief Cache manager destructor. + */ + ~Cache(); + + + /** + * @brief Test to see if @c auxid is valid in the cache. + * @returns If @c auxid is valid, return the pointer to the vector, else 0. + */ + void* cachePtr (SG::auxid_t auxid); + + + /** + * @brief Return a pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + */ + void* getDataArray (SG::auxid_t auxid, AuxVectorData& parent); + + + /** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. + * Errors are signaled by raising an exception. + */ + const void* getDataArray (SG::auxid_t auxid, const AuxVectorData& parent); + + + /** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item does not exist, + * this will return nullptr rather than raising an exception. + */ + const void* getDataArrayAllowMissing (SG::auxid_t auxid, + const AuxVectorData& parent); + + + /** + * @brief Return a pointer to the start of an aux decoration vector. + * @param auxid The desired aux decoration item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * decoration item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + * + * The difference between @c getDecorationArray and @c getDataArray is that + * @c getDecorationArray takes a const container as input, but returns + * a non-const pointer. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ + void* getDecorationArray (SG::auxid_t auxid, const AuxVectorData& parent); + + + /** + * @brief Swap this cache object with another. + * @param other The cache object with which to swap. + */ + void swap (Cache& other); + + + /** + * @brief Clear the cache (and free any old cache vectors). + */ + void clear(); + + + /** + * @brief Store a pointer for @c auxid in the cache. + * @param auxid The aux data item being stored. + * @param ptr Pointer to the start of the aux vector for @c auxid. + */ + void store (SG::auxid_t auxid, void* ptr); + + + /// Pointer to the cache vector. + /// The two pointers here are the same; see the thread-safety + /// discussion in the file header above. + void** m_cache[2]; + + /// Length of the cache vector. + size_t m_cache_len; + + /// All cache vectors that have been allocated. + // See the thread-safety discussion in the file header above. + // Could be a vector of unique_ptr, but we want to avoid + // relying on c++11 for now. + std::vector<void**> m_allcache; + + + private: + Cache (const Cache&); + Cache& operator= (const Cache&); + }; + + friend class Cache; + + + /// Copy not allowed. + AuxVectorData (const AuxVectorData&); + AuxVectorData& operator= (const AuxVectorData&); + + // Needed for access to getDataArray + friend class SG::AuxElement; + + + /** + * @brief Out-of-line portion of isAvailable. + * @param id The variable to test. + */ + bool isAvailableOol (auxid_t id) const; + + + /** + * @brief Out-of-line portion of isAvailableWritable. + * @param id The variable to test. + */ + bool isAvailableWritableOol (auxid_t id) const; + + + /** + * @brief Out-of-line portion of isAvailableWritableAsDecoration. + * @param id The variable to test. + */ + bool isAvailableWritableAsDecorationOol (auxid_t id) const; + + + /** + * @brief Out-of-line portion of data access. + * @param auxid aux data item being accessed. + * @param allowMissing If true, then return nullptr if the variable + * is missing rather than throwing an exception. + * + * When this function returns, the cache entry @c m_cache[auxid] + * will be valid. That entry is also returned. If there's an error, + * the function will throw an exception rather than returning. + */ + void* getDataOol (SG::auxid_t auxid, bool allowMissing); + + + /** + * @brief Out-of-line portion of data access (const version). + * @param auxid aux data item being accessed. + * @param allowMissing If true, then return nullptr if the variable + * is missing rather than throwing an exception. + * + * When this function returns, the cache entry @c m_constCache[auxid] + * will be valid. That entry is also returned. If there's an error, + * the function will throw an exception rather than returning. + */ + const void* getDataOol (SG::auxid_t auxid, bool allowMissing) const; + + + /** + * @brief Out-of-line portion of data access (decorator version). + * @param auxid aux data item being accessed. + * + * When this function returns, the cache entry @c m_cache[auxid] + * will be valid. That entry is also returned. If there's an error, + * the function will throw an exception rather than returning. + * + * The difference between @c getDecorationOol and @c getDataOol is that + * @c getDecorationOol takes a const container as input, but returns + * a non-const pointer. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ + void* getDecorationOol (SG::auxid_t auxid) const; + + + /// Cached pointers to the start of aux data vectors, non-const. + mutable Cache m_cache; + + /// Cached pointers to the start of aux data vectors, const. + mutable Cache m_constCache; + + /// Cached pointers to the start of aux data vectors, decorations. + mutable Cache m_decorCache; + + + /// Associated store, non-const. + SG::IAuxStore* m_store; + + + /// Associated store, const. + const SG::IConstAuxStore* m_constStore; + + + /// Associated store link, const. + DataLink< SG::IConstAuxStore > m_constStoreLink; + + + /// Mutex used to synchronize modifications to the cache vector. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard<mutex_t> guard_t; + mutable mutex_t m_mutex; + + /// Empty auxid set, used for a return value when we have no associated store. + static SG::auxid_set_t s_emptySet; +}; + + +} // namespace SG + + +#ifndef XAOD_STANDALONE + + +/** + * @brief Propagate thinning. Called after applying thinning to @c in. + * @param in The object that was thinned. + * @param svc The thinning service (for convenience). + * @param filter Lists the elements to be kept. + * @param op How to merge results: AND or OR. + * + * This will be called whenever a request is made to thin a @c DataVector. + * + * Otherwise, we pass the thinning request on to the aux store, provided + * that it exists and is in the event store. + */ +StatusCode thinningHook (const SG::AuxVectorData* in, + IThinningSvc* svc, + const IThinningSvc::Filter_t& filter, + const IThinningSvc::Operator::Type op ); + + +#endif + + +#include "AthContainers/AuxVectorData.icc" + + +#endif // not ATHCONTAINERS_AUXVECTORDATA_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.icc b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.icc new file mode 100644 index 00000000..60265e38 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/AuxVectorData.icc @@ -0,0 +1,587 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxVectorData.icc 718910 2016-01-20 22:30:05Z ssnyder $ +/** + * @file AthContainers/AuxVectorData.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Manage lookup of vectors of auxiliary data. + */ + + +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainers/tools/likely.h" +#include "AthContainers/tools/assume.h" + + +namespace SG { + + +/** + * @brief Return the current store, as a const interface. + * + * This will be non-zero if either a const or non-const store + * is associated with this object. + */ +inline +const SG::IConstAuxStore* AuxVectorData::getConstStore() const +{ + if( m_constStore ) { + return m_constStore; + } + if( !m_constStoreLink.isDefault() ) { + return m_constStoreLink.cptr(); + } + return 0; +} + + +/** + * @brief Return the data link to the current store, as a const interface. + * + * This is set by persistency when reading an object, but it may + * be overridden by setting the store pointer directly. + */ +inline +const DataLink<SG::IConstAuxStore> AuxVectorData::getConstStoreLink() const +{ + return m_constStoreLink; +} + + +/** + * @brief Return the current store, as a non-const interface. + * + * This will be non-zero if a non-const store is associated with this object. + */ +inline +SG::IAuxStore* AuxVectorData::getStore() const +{ + return m_store; +} + + +/** + * @brief Return true if this object has an associated store. + */ +inline +bool AuxVectorData::hasStore() const +{ + return ( getConstStore() != 0 ); +} + + +/** + * @brief Return true if this object has an associated non-const store. + */ +inline +bool AuxVectorData::hasNonConstStore() const +{ + return m_store != 0; +} + + +/** + * @brief Test to see if a variable exists in the store. + * @param id The variable to test. + */ +inline +bool AuxVectorData::isAvailable (auxid_t id) const +{ + // First check to see if this variable is present in the cache. + if (m_constCache.cachePtr (id)) return true; + return isAvailableOol (id); +} + + +/** + * @brief Test to see if a variable exists in the store. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + */ +template <class T> +inline +bool AuxVectorData::isAvailable (const std::string& name, + const std::string& clsname /*= ""*/) const +{ + auxid_t id = SG::AuxTypeRegistry::instance().getAuxID<T> (name, clsname); + return isAvailable (id); +} + + +/** + * @brief Test to see if a variable is available for writing. + * @param id The variable to test. + */ +inline +bool AuxVectorData::isAvailableWritable (auxid_t id) const +{ + // First check to see if this variable is present in the cache. + if (m_cache.cachePtr (id)) return true; + return isAvailableWritableOol (id); +} + + +/** + * @brief Test to see if a variable is available for writing. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + */ +template <class T> +inline +bool +AuxVectorData::isAvailableWritable (const std::string& name, + const std::string& clsname /*= ""*/) const +{ + auxid_t id = SG::AuxTypeRegistry::instance().getAuxID<T> (name, clsname); + return isAvailableWritable (id); +} + + +/** + * @brief Test to see if a variable is available for writing as a decoration. + * @param id The variable to test. + */ +inline +bool AuxVectorData::isAvailableWritableAsDecoration (auxid_t id) const +{ + // First check to see if this variable is present in the cache. + if (m_decorCache.cachePtr (id)) return true; + return isAvailableWritableAsDecorationOol (id); +} + + +/** + * @brief Test to see if a variable is available for writing as a decoration. + * @param name Name of the aux variable. + * @param clsname The name of the associated class. May be blank. + */ +template <class T> +inline +bool +AuxVectorData::isAvailableWritableAsDecoration (const std::string& name, + const std::string& clsname /*= ""*/) const +{ + auxid_t id = SG::AuxTypeRegistry::instance().getAuxID<T> (name, clsname); + return isAvailableWritableAsDecoration (id); +} + + +/** + * @brief Return reference to an aux data item. + * @param auxid The desired aux data item. + * @param ndx Index of the element to return. + * + * This will return a reference to element @c ndx of aux data item @c auxid. + * If the aux data item does not exist, it will be created. + * Errors are signaled by raising an exception. + * + * Warning: no type checking is done. You should usually access + * the data via @c AuxElement::Accessor. + */ +template <class T> +inline +typename AuxDataTraits<T>::reference_type +AuxVectorData::getData (SG::auxid_t auxid, size_t ndx) +{ + return AuxDataTraits<T>::index (this->getDataArray (auxid), ndx); +} + + +/** + * @brief Return const reference to an aux data item. + * @param auxid The desired aux data item. + * @param ndx Index of the element to return. + * + * This will return a reference to element @c ndx of aux data item @c auxid. + * If the aux data item does not exist, it will be created. + * Errors are signaled by raising an exception. + * + * Warning: no type checking is done. You should usually access + * the data via @c AuxElement::Accessor. + */ +template <class T> +inline +typename AuxDataTraits<T>::const_reference_type +AuxVectorData::getData (SG::auxid_t auxid, size_t ndx) const +{ + return AuxDataTraits<T>::index (this->getDataArray (auxid), ndx); +} + + +/** + * @brief Return reference to an aux decoration item. + * @param auxid The desired aux decoration item. + * @param ndx Index of the element to return. + * + * This will return a reference to element @c ndx of aux decoration + * item @c auxid. + * If the aux data item does not exist, it will be created. + * Errors are signaled by raising an exception. + * + * Warning: no type checking is done. You should usually access + * the data via @c AuxElement::Decorator. + * + * The difference between @c getDecoration and @c getData is that + * @c getDecoration takes a const container as input, but returns + * a non-const reference. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ +template <class T> +inline +typename AuxDataTraits<T>::reference_type +AuxVectorData::getDecoration (SG::auxid_t auxid, size_t ndx) const +{ + return AuxDataTraits<T>::index (this->getDecorationArray (auxid), ndx); +} + + + +#ifndef __GCCXML__ + + +/** + * @brief Return a pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + */ +inline +void* +AuxVectorData::getDataArray (SG::auxid_t auxid) +{ + return m_cache.getDataArray (auxid, *this); +} + + +/** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. + * Errors are signaled by raising an exception. + */ +inline +const void* +AuxVectorData::getDataArray (SG::auxid_t auxid) const +{ + return m_constCache.getDataArray (auxid, *this); +} + + +/** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item does not exist, + * this will return nullptr rather than raising an exception. + */ +inline +const void* +AuxVectorData::getDataArrayAllowMissing (SG::auxid_t auxid) const +{ + return m_constCache.getDataArrayAllowMissing (auxid, *this); +} + + +/** + * @brief Return a pointer to the start of an aux data vector for a decoration. + * @param auxid The desired aux data item. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + * + * The difference between @c getDecorationArray and @c getDataArray is that + * @c getDecorationArray takes a const container as input, but returns + * a non-const pointer. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ +inline +void* AuxVectorData::getDecorationArray (SG::auxid_t auxid) const +{ + return m_decorCache.getDecorationArray (auxid, *this); +} + + +#endif // not __GCCXML__ + + +/** + * @brief Swap this instance with another. + * @param other The other instance with which to swap. + */ +inline +void AuxVectorData::swap (AuxVectorData& other) +{ + m_cache.swap (other.m_cache); + m_constCache.swap (other.m_constCache); + m_decorCache.swap (other.m_decorCache); + std::swap (m_store, other.m_store); + std::swap (m_constStore, other.m_constStore); + std::swap (m_constStoreLink, other.m_constStoreLink); +} + + +/** + * @brief Clear the cached aux data pointers. + * + * You should call this anytime something changes in the aux store + * that could invalidate the vector pointers. + */ +inline +void AuxVectorData::clearCache() +{ + m_cache.clear(); + m_constCache.clear(); + m_decorCache.clear(); +} + + +/** + * @brief Test to see if @c auxid is valid in the cache. + * @returns If @c auxid is valid, return the pointer to the vector, else 0. + */ +inline +void* AuxVectorData::Cache::cachePtr (SG::auxid_t auxid) +{ + // This function is important for performance. + // Be careful when changing it. + + // auxid must not be larger than the length of the cache vector. + if (auxid >= m_cache_len) return 0; +#if !(defined(__x86_64__) || defined(__i386)) + // Memory fence not strictly required on x86, and spoils optimizations. + // See header comments. + AthContainers_detail::fence_acq_rel(); +#endif + // Return the cache entry. + return m_cache[m_cache_len&1][auxid]; +} + + +#ifndef __GCCXML__ + + +/** + * @brief Return a pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + */ +inline +void* +AuxVectorData::Cache::getDataArray (SG::auxid_t auxid, + AuxVectorData& parent) +{ + // This function is important for performance. + // Be careful when changing it. + + void* ptr = cachePtr (auxid); + if (ATHCONTAINERS_UNLIKELY (ptr == 0)) { + // We don't have the variable cached. + // Call the out-of-line routine to get it cached. + ptr = parent.getDataOol (auxid, false); + + // These inform the compiler of what the previous call did. + // They tell the optimizer that it can now assume that this cache + // entry is valid. + ATHCONTAINERS_ASSUME (ptr != 0); + ATHCONTAINERS_ASSUME (cachePtr (auxid) != 0); + ATHCONTAINERS_ASSUME (cachePtr (auxid) == ptr); + } + return ptr; +} + + +/** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. + * Errors are signaled by raising an exception. + */ +inline +const void* +AuxVectorData::Cache::getDataArray (SG::auxid_t auxid, + const AuxVectorData& parent) +{ + // This function is important for performance. + // Be careful when changing it. + + const void* ptr = cachePtr (auxid); + if (ATHCONTAINERS_UNLIKELY (ptr == 0)) { + // We don't have the variable cached. + // Call the out-of-line routine to get it cached. + ptr = parent.getDataOol (auxid, false); + + // These inform the compiler of what the previous call did. + // They tell the optimizer that it can now assume that this cache + // entry is valid. + ATHCONTAINERS_ASSUME (ptr != 0); + ATHCONTAINERS_ASSUME (cachePtr (auxid) != 0); + ATHCONTAINERS_ASSUME (cachePtr (auxid) == ptr); + } + return ptr; +} + + +/** + * @brief Return a const pointer to the start of an aux data vector. + * @param auxid The desired aux data item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * data item @c auxid. If the item does not exist, + * this will return nullptr rather than raising an exception. + */ +inline +const void* +AuxVectorData::Cache::getDataArrayAllowMissing (SG::auxid_t auxid, + const AuxVectorData& parent) +{ + const void* ptr = cachePtr (auxid); + if (ATHCONTAINERS_UNLIKELY (ptr == 0)) { + // We don't have the variable cached. + // Call the out-of-line routine to get it cached. + ptr = parent.getDataOol (auxid, true); + } + return ptr; +} + + +/** + * @brief Return a pointer to the start of an aux decoration vector. + * @param auxid The desired aux decoration item. + * @param parent The containing @c AuxVectorData object. + * + * This will return a pointer to the start of the data for aux + * decoration item @c auxid. If the item doesn't exist, it will be created. + * Errors are signaled by raising an exception. + * + * The difference between @c getDecorationArray and @c getDataArray is that + * @c getDecorationArray takes a const container as input, but returns + * a non-const pointer. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ +inline +void* AuxVectorData::Cache::getDecorationArray (SG::auxid_t auxid, + const AuxVectorData& parent) +{ + // This function is important for performance. + // Be careful when changing it. + + void* ptr = cachePtr (auxid); + if (ATHCONTAINERS_UNLIKELY (ptr == 0)) { + // We don't have the variable cached. + // Call the out-of-line routine to get it cached. + ptr = parent.getDecorationOol (auxid); + + // These inform the compiler of what the previous call did. + // They tell the optimizer that it can now assume that this cache + // entry is valid. + ATHCONTAINERS_ASSUME (ptr != 0); + ATHCONTAINERS_ASSUME (cachePtr (auxid) != 0); + ATHCONTAINERS_ASSUME (cachePtr (auxid) == ptr); + } + return ptr; +} + + +#endif // not __GCCXML__ + + +/** + * @brief Set an option for an auxiliary data variable. + * @param id The variable for which we want to set the option. + * @param optname The name of the option to set. + * @param arg The option value to set. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +template <class T> +bool AuxVectorData::setOption (auxid_t id, + const std::string& optname, + T arg) +{ + return this->setOption (id, AuxDataOption (optname, arg)); +} + + +/** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param optname The name of the option to set. + * @param arg The option value to set. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +inline +bool AuxVectorData::setOption (const std::string& name, + const std::string& optname, + int arg) +{ + return this->setOption (name, AuxDataOption (optname, arg)); +} +inline +bool AuxVectorData::setOption (const std::string& name, + const std::string& optname, + float arg) +{ + return this->setOption (name, AuxDataOption (optname, arg)); +} +inline +bool AuxVectorData::setOption (const std::string& name, + const std::string& optname, + double arg) +{ + return this->setOption (name, AuxDataOption (optname, arg)); +} + + +/** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param clsname The name of the associated class. May be blank. + * @param optname The name of the option to set. + * @param arg The option value to set. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +template <class T> +bool AuxVectorData::setOption (const std::string& name, + const std::string& clsname, + const std::string& optname, + T arg) +{ + return this->setOption (name, clsname, AuxDataOption (optname, arg)); +} + + +} // namespace SG + + diff --git a/EDM/athena/Control/AthContainers/AthContainers/ClassName.h b/EDM/athena/Control/AthContainers/AthContainers/ClassName.h new file mode 100644 index 00000000..c7c83366 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ClassName.h @@ -0,0 +1,49 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ClassName.h 581165 2014-02-03 10:42:54Z krasznaa $ +#ifndef ATHCONTAINERS_CLASSNAME_H +#define ATHCONTAINERS_CLASSNAME_H + +#ifndef XAOD_STANDALONE + +// Get the code from SGTools: +#include "SGTools/ClassName.h" + +#else + +// STL include(s): +#include <string> + +/** + * @short A copy of the ClassName class for standalone compilation + * + * Since the standalone compilation doesn't use SGTools, but + * the standalone code also needs to be able to get the names + * of DataVector types in a nicely formatted way, we have this + * copy of the SGTools class in here for standalone compilation. + * + * @author Scott Snyder <Scott.Snyder@cern.ch> + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + * + * $Revision: 581165 $ + * $Date: 2014-02-03 11:42:54 +0100 (Mon, 03 Feb 2014) $ + */ +template< class T > +class ClassName { + +public: + /// Returns the name of class @c T as a string + static std::string name(); + +}; // class ClassName + +// Include the implementation: +#include "ClassName.icc" + +#endif // not XAOD_STANDALONE + +#endif // not ATHCONTAINERS_CLASSNAME_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/ClassName.icc b/EDM/athena/Control/AthContainers/AthContainers/ClassName.icc new file mode 100644 index 00000000..71672705 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ClassName.icc @@ -0,0 +1,25 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ClassName.icc 581165 2014-02-03 10:42:54Z krasznaa $ +#ifndef ATHCONTAINERS_CLASSNAME_ICC +#define ATHCONTAINERS_CLASSNAME_ICC + +// A little sanity check: +#ifndef XAOD_STANDALONE +#error "ClassName.icc is not to be used outside of Athena!" +#endif + +// Local include(s): +#include "AthContainers/tools/error.h" + +template< class T > +std::string ClassName< T >::name() { + + return AthContainers_detail::typeinfoName( typeid( T ) ); +} + +#endif // ATHCONTAINERS_CLASSNAME_ICC diff --git a/EDM/athena/Control/AthContainers/AthContainers/ConstDataList.h b/EDM/athena/Control/AthContainers/AthContainers/ConstDataList.h new file mode 100644 index 00000000..6d413834 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ConstDataList.h @@ -0,0 +1,736 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ConstDataList.h 610620 2014-08-06 21:15:52Z ssnyder $ +/** + * @file AthContainers/ConstDataList.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2011 + * @brief @c DataList adapter that acts like it holds const pointers. + * + * A @c DataList\<T> acts as a container of @c T*. + * This means, though, that one cannot put a <code>const T*</code> + * into a @c DataList\<T>. However, one sometimes wants + * to do that. A typical case is that one retrieves + * a const @c DataList from StoreGate, filters the contents, + * and then stores them in a new @c DataList. Recall that + * a const @c DataList will return <code>const T*</code>. + * So the pointers one gets from a const @c DataList + * cannot be inserted into another @c DataList. + * (The root cause of this is that we don't want to have + * to deal with distinct <code>DataList\<T></code> and + * <code>DataList\<const T></code> types, and thus + * @c DataList [and StoreGate] don't have standard const semantics.) + * + * To solve this, we introduce the template class @c ConstDataList\<DL>. + * The template argument should be a @c DataList class or something + * that derives from one. (The reason the template argument is the + * @c DataList class rather than the element type @c T is to allow + * for types that derive from @c DataList.) @c ConstDataList\<DL> + * derives from @c DL, but privately --- so it is a @c DL, but clients + * cannot use it as a @c DL. Instead, we provide only methods that + * retrieve const pointers. Further, the insertion methods will + * take const rather than non-const pointers. + * + * There are two ways (short of casting) to convert a @c ConstDataList\<DL> + * to a <code>const DL</code>. The @c asDataList method will directly + * do this conversion. Also, if the object is recorded in StoreGate, + * it will automatically be made const, so a retrieval will get + * a <code>const DL</code>. A @c ConstDataList should not convert + * to a non-const @c DL. + * + * So, for example, filtering might look something like this: + * + *@code + * const DataList<T>* v_in = 0; + * CHECK( sg->retrieve (v_in) ); + * ConstDataList<DataList<T> >* v_out = + * new ConstDataList<DataList<T> > (SG::VIEW_ELEMENTS); + * CHECK( sg->record (v_out, "key") ); + * for (const T* t : *v_in) { + * if (filter (*it)) + * v_out->push_back (*it); + * } + @endcode + * + * Note that if you are not recording the result in StoreGate, + * it may well be preferable to just use a <code>std::list<const T*></code> + * rather than @c ConstDataList. + */ + + +#ifndef ATHCONTAINERS_CONSTDATALIST_H +#define ATHCONTAINERS_CONSTDATALIST_H + +#include "AthContainers/DataList.h" +#include "SGTools/ClassID_traits.h" + + +/** + * @brief @c DataList adapter that acts like it holds const pointers. + */ +template <class DL> +class ConstDataList + : private DL +{ +public: + /// Basic types, forwarded from the base. + typedef typename DL::size_type size_type; + typedef typename DL::difference_type difference_type; + typedef typename DL::allocator_type allocator_type; + typedef typename DL::base_value_type base_value_type; + typedef typename DL::BaseContainer BaseContainer; + typedef typename DL::DVL_BASE DVL_BASE; + typedef typename DL::const_iterator const_iterator; + typedef typename DL::const_reverse_iterator const_reverse_iterator; + + /// These types get modified so that the base's @c const_value_type + /// becomes our @c value_type. + typedef typename DL::const_value_type value_type; + typedef typename DL::const_value_type const_value_type; + typedef typename DL::const_value_type & reference; + typedef typename DL::const_value_type const & const_reference; + typedef typename DL::const_value_type * pointer; + typedef typename DL::const_value_type const * const_pointer; + + /// This needs to be forwarded from the base as well. + static const bool has_virtual = DL::has_virtual; + + /// This type is used to proxy lvalue accesses to @c DataList + /// elements, in order to handle ownership. + typedef DataModel_detail::ElementProxy<ConstDataList> ElementProxy; + + /// The iterator for this type. + typedef typename DataModel_detail::iterator<ConstDataList> iterator; + + /// Standard @c reverse_iterator. Note that lvalue references here will + /// yield an @c ElementProxy, not a @c reference. + typedef typename std::reverse_iterator<iterator> + reverse_iterator; + + /// Expose methods from the base that don't allow getting back + /// non-const pointers. + using DL::size; + using DL::max_size; + using DL::resize; + using DL::empty; + using DL::pop_front; + using DL::pop_back; + using DL::clear; + using DL::sort; + using DL::ownPolicy; + using DL::reverse; + using DL::remove_if; + using DL::unique; + using DL::testInsert; + + + /// Expose the const versions of these methods too. + /// We'll need to be sure to override the non-const versions of all of these + /// below. + using DL::begin; + using DL::end; + using DL::rbegin; + using DL::rend; + using DL::front; + using DL::back; + + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit ConstDataList(SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard list constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit ConstDataList(size_type n, + SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS); + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + template <class InputIterator> + ConstDataList(InputIterator first, InputIterator last, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS); + + + /** + * @brief Assignment operator. + * @param rhs The DataList from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataList + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + ConstDataList& operator= (const ConstDataList& rhs); + + + /** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataList's ownership policy determines whether it will take + * ownership of the new elements. + */ + template <class InputIterator> + void assign(InputIterator first, InputIterator last); + + + //@} + //======================================================================== + /** @name Element access. */ + //@{ + + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy front (); + + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy back (); + + + //@} + //======================================================================== + /** @name Iterator creation. */ + //@{ + + + /** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator begin(); + + + /** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator end(); + + + /** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rbegin(); + + + /** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rend(); + + + //@} + //======================================================================== + /** @name Insertion operations. */ + //@{ + + + /** + * @brief Add an element at the beginning of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void push_front(value_type pElem); + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void push_back(value_type pElem); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + iterator insert(iterator position, value_type pElem); + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + template <class InputIterator> + void insert(iterator position, InputIterator first, InputIterator last); + + + //@} + //======================================================================== + /** @name Erasure operations. */ + //@{ + + + /** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ + iterator erase(iterator position); + + + /** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + iterator erase(iterator first, iterator last); + + + //@} + //======================================================================== + /** @name Swap and sort. */ + //@{ + + + /** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataList in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataList. + */ + void swap(ConstDataList& rhs); + + + /** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ + static void iter_swap (iterator a, iterator b); + + + //@} + //======================================================================== + /** @name List operations. */ + //@{ + + + /** + * @brief Insert contents of another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * + * The elements of @a l are inserted in constant time in front of + * the element referenced by @a position. @a l becomes an empty + * list. + */ + void splice( iterator position, ConstDataList& l ); + + + /** + * @brief Insert element from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param i Iterator referencing the element to move. + * + * Removes the element in list @a l referenced by @a i and + * inserts it into the current list before @a position. + */ + void splice( iterator position, ConstDataList& l, iterator i ); + + + /** + * @brief Insert range from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param first Iterator referencing the start of range in @a l. + * @param last Iterator referencing the end of range in @a l. + * + * Removes elements in the range [@a first, @a last ) and inserts them + * before @a position in constant time. + * + * Undefined if @a position is in [@a first, @a last ). + */ + void splice( iterator position, ConstDataList& l, + iterator first, + iterator last ); + + + /** + * @brief Remove all elements equal to value. + * @param value The value to remove. + * + * Removes every element in the list equal to @a value. + * Remaining elements stay in list order. + */ + void remove( const value_type& value ); + + + /** + * @brief Merge sorted lists. + * @param l Sorted list to merge. + * + * Assumes that both @a l and this list are sorted according to + * operator<(). Merges elements of @a l into this list in + * sorted order, leaving @a l empty when complete. Elements in + * this list precede elements in @a l that are equal. + */ + void merge( ConstDataList& l ); + + + /** + * @brief Merge sorted lists according to comparison function. + * @param l Sorted list to merge. + * @param predicate Comparison function defining a sort order (which + * must be strictly weak ordering). + * + * Assumes that both @a l and this @c DataList are sorted according to + * COMPARE predicate. Merges elements of @a l into this list + * in sorted order, leaving @a l empty when complete. Elements + * in this list precede elements in @a x that are equivalent + * according to StrictWeakOrdering(). + */ + template<typename COMPARE> + void merge( ConstDataList& l, COMPARE predicate ); + + + //@} + //======================================================================== + /** @name Non-standard operations. */ + //@{ + + +public: + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, value_type newElem, reference oldElem); + + + /** + * @brief Return a pointer to this object, as a const @c DataList. + */ + const DL* asDataList() const; + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c ConstDataList. + */ + void resortAux (iterator beg, iterator end); + + + //@} + //======================================================================== + /** @name Relational operators. */ + //@{ + + + /** + * @brief List ordering relation. + * @param a A @c ConstDataList. + * @param b A @c ConstDataList of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * lists. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ + bool operator< (const ConstDataList& b) const; + + /// Based on operator< + bool operator> (const ConstDataList& b) const; + + /// Based on operator< + bool operator<= (const ConstDataList& b) const; + + /// Based on operator< + bool operator>= (const ConstDataList& b) const; + + /** + * @brief List equality comparison. + * @param a A @c ConstDataList. + * @param b A @c ConstDataList of the same type as @a x. + * @return True iff the size and elements of the lists are equal. + * + * This is an equivalence relation. It is linear in the size of the + * lists. Lists are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ + bool operator== (const ConstDataList& b) const; + + /// Based on operator== + bool operator!= (const ConstDataList& b) const; + + +private: + //@} + //======================================================================== + /** @name Private helpers. */ + //@{ + + + friend class DataModel_detail::ElementProxy<ConstDataList>; + friend void test2_assignelement1<ConstDataList>(); + + + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ + void assignElement (typename BaseContainer::iterator pos, value_type newElem); + + + /** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ + void + assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem); + + + /** + * @brief Convert a @c ConstDataVector::iterator to an iterator + * of the base @c DataVector. + * @param it The @c ConstDataVector::iterator to convert. + */ + static + typename DL::iterator to_base_iterator (iterator it); + + + /** + * @brief Convert an iterator of the base @c DataList to + * a @c ConstDataList::iterator. + * @param it The base @c DataList iterator to convert. + */ + iterator to_my_iterator (typename DL::iterator it); + + + /** + * @brief Convert an iterator of the base @c vector + * an @c ElementProxy for the @c ConstDataVector. + * @param it The base @c vector iterator to convert. + */ + ElementProxy to_element_proxy (typename BaseContainer::iterator i); + + + //@} +}; + + +/// See <code>DataList<T, BASE>::swap()</code>. +template <class T> +void swap( ConstDataList<T>& a, ConstDataList<T>& b ); + + +/** + * @brief Specialize @c ClassID_traits for @c ConstDataList so that + * they will be automatically made const when recorded in StoreGate. + */ +template <class DL> +struct ClassID_traits<ConstDataList<DL> > + : public ClassID_traits<DL> +{ +public: + BOOST_STATIC_CONSTANT(bool, s_isConst = true); +}; + + +namespace SG { + + +/** + * @brief @c DataBucket class for @c ConstDataList. + * + * This is just the same as @c DVLDataBucket, except that we've + * got to convert the @c ConstDataList to @c DataList. + * + * Note: Can be used to violate const-correctness. + * Don't use this yourself! + */ +template <class T> +class DVLConstDataListBucket + : public DVLDataBucket<T> +{ +public: + /** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ + DVLConstDataListBucket (ConstDataList<T>* data); + + +#if __cplusplus > 201100 + /** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ + DVLConstDataListBucket (std::unique_ptr<ConstDataList<T> > data); +#endif +}; + + +/** + * @brief Metafunction to find the proper @c DataBucket class for + * the first template argument. + * + * Specialize this for @c ConstDataVector. + * See SGTools/StorableConversions.h for an explanation. + */ +template <class T, class U> +struct DataBucketTrait<ConstDataList<T>, U> +{ + typedef SG::DVLConstDataListBucket<T> type; + static void init() { DataList<T>::dvlinfo(); } +}; + + +/** + * @brief Let the @c BaseInfo for @c ConstDataList forward to that + * of the base @c DataList. + */ +template <class T> +class BaseInfo<ConstDataList<T> > + : public BaseInfo<T> +{ +}; + + +} // namespace SG + + +#include "AthContainers/ConstDataList.icc" + + +#endif // not ATHCONTAINERS_CONSTDATALIST_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/ConstDataList.icc b/EDM/athena/Control/AthContainers/AthContainers/ConstDataList.icc new file mode 100644 index 00000000..3f0b81ee --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ConstDataList.icc @@ -0,0 +1,781 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ConstDataList.icc 610620 2014-08-06 21:15:52Z ssnyder $ +/** + * @file AthContainers/ConstDataList.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2011 + * @brief @c DataList adapter that acts like it holds const pointers. + */ + + +//=== Constructors, destructors, assignment. + + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DL> +inline +ConstDataList<DL>::ConstDataList + (SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/) + : DL (ownPolicy) +{ +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard list constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DL> +inline +ConstDataList<DL>::ConstDataList + (size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/) + : DL (n, ownPolicy) +{ +} + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DL> +template <class InputIterator> +inline +ConstDataList<DL>::ConstDataList + (InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/) + : DL (ownPolicy) +{ + while (first != last) + push_back (*first++); +} + + +/** + * @brief Assignment operator. + * @param rhs The DataList from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataList + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DL> +inline +ConstDataList<DL>& +ConstDataList<DL>::operator= (const ConstDataList& rhs) +{ + *static_cast<DL*>(this) = rhs; + return *this; +} + + +/** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataList's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class DL> +template <class InputIterator> +inline +void ConstDataList<DL>::assign(InputIterator first, InputIterator last) +{ + clear(); + while (first != last) + push_back (*first++); +} + + +//=== Element access. + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class DL> +inline +typename ConstDataList<DL>::ElementProxy +ConstDataList<DL>::front () +{ + return to_element_proxy (this->m_pCont.begin()); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class DL> +inline +typename ConstDataList<DL>::ElementProxy +ConstDataList<DL>::back () +{ + typename DL::BaseContainer::iterator it = this->m_pCont.end(); + --it; + return to_element_proxy (it); +} + + +//=== Iterator creation. + + +/** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DL> +inline +typename ConstDataList<DL>::iterator +ConstDataList<DL>::begin() +{ + return to_my_iterator (DL::begin()); +} + + +/** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DL> +inline +typename ConstDataList<DL>::iterator +ConstDataList<DL>::end() +{ + return to_my_iterator (DL::end()); +} + + +/** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DL> +inline +typename ConstDataList<DL>::reverse_iterator +ConstDataList<DL>::rbegin() +{ + return reverse_iterator (to_my_iterator (DL::end())); +} + + +/** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DL> +inline +typename ConstDataList<DL>::reverse_iterator +ConstDataList<DL>::rend() +{ + return reverse_iterator (to_my_iterator (DL::begin())); +} + + +//=== Insertion operations. + + +/** + * @brief Add an element at the beginning of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DL> +inline +void +ConstDataList<DL>::push_front(value_type pElem) +{ + DL::push_front (const_cast<typename DL::value_type> (pElem)); +} + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DL> +inline +void +ConstDataList<DL>::push_back(value_type pElem) +{ + DL::push_back (const_cast<typename DL::value_type> (pElem)); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DL> +inline +typename ConstDataList<DL>::iterator +ConstDataList<DL>::insert(iterator position, value_type pElem) +{ + return to_my_iterator + (DL::insert (to_base_iterator (position), + const_cast<typename DL::value_type> (pElem))); +} + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DL> +template <class InputIterator> +inline +void +ConstDataList<DL>::insert(iterator position, InputIterator first, InputIterator last) +{ + typename DL::iterator it = to_base_iterator (position); + while (first != last) { + DL::insert (it, const_cast<typename DL::value_type> (*first)); + ++first; + } +} + + +//=== Erasure operations. + + +/** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ +template <class DL> +inline +typename ConstDataList<DL>::iterator +ConstDataList<DL>::erase(iterator position) +{ + return to_my_iterator (DL::erase (to_base_iterator (position))); +} + +/** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class DL> +inline +typename ConstDataList<DL>::iterator +ConstDataList<DL>::erase(iterator first, iterator last) +{ + return to_my_iterator + (DL::erase (to_base_iterator (first), + to_base_iterator (last))); +} + + +//=== Swap and sort. + + +/** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataList in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataList. + */ +template <class DL> +inline +void ConstDataList<DL>::swap(ConstDataList& rhs) +{ + DL::swap (rhs); +} + + +/** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ +template <class DL> +inline +void ConstDataList<DL>::iter_swap (iterator a, iterator b) +{ + DL::iter_swap (to_base_iterator (a), + to_base_iterator (b)); +} + + +//=== List operations. + + +/** + * @brief Insert contents of another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * + * The elements of @a l are inserted in constant time in front of + * the element referenced by @a position. @a l becomes an empty + * list. + */ +template <class DL> +inline +void +ConstDataList<DL>::splice( iterator position, ConstDataList& l ) +{ + DL::splice (to_base_iterator (position), l); +} + + +/** + * @brief Remove all elements equal to value. + * @param value The value to remove. + * + * Removes every element in the list equal to @a value. + * Remaining elements stay in list order. + */ +template <class DL> +inline +void +ConstDataList<DL>::remove( const value_type& value ) +{ + DL::remove (const_cast<typename DL::value_type> (value)); +} + + +/** + * @brief Insert element from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param i Iterator referencing the element to move. + * + * Removes the element in list @a l referenced by @a i and + * inserts it into the current list before @a position. + */ +template <class DL> +inline +void +ConstDataList<DL>::splice( iterator position, ConstDataList& l, iterator i ) +{ + DL::splice (to_base_iterator(position), l, to_base_iterator(i)); +} + + +/** + * @brief Insert range from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param first Iterator referencing the start of range in @a l. + * @param last Iterator referencing the end of range in @a l. + * + * Removes elements in the range [@a first, @a last ) and inserts them + * before @a position in constant time. + * + * Undefined if @a position is in [@a first, @a last ). + */ +template <class DL> +inline +void +ConstDataList<DL>::splice( iterator position, + ConstDataList& l, + iterator first, + iterator last ) +{ + DL::splice (to_base_iterator(position), + l, + to_base_iterator(first), + to_base_iterator(last)); +} + + +/** + * @brief Merge sorted lists. + * @param l Sorted list to merge. + * + * Assumes that both @a l and this list are sorted according to + * operator<(). Merges elements of @a l into this list in + * sorted order, leaving @a l empty when complete. Elements in + * this list precede elements in @a l that are equal. + */ +template <class DL> +inline +void +ConstDataList<DL>::merge( ConstDataList& l ) +{ + DL::merge (l); +} + + +/** + * @brief Merge sorted lists according to comparison function. + * @param l Sorted list to merge. + * @param predicate Comparison function defining a sort order (which + * must be strictly weak ordering). + * + * Assumes that both @a l and this @c DataList are sorted according to + * COMPARE predicate. Merges elements of @a l into this list + * in sorted order, leaving @a l empty when complete. Elements + * in this list precede elements in @a x that are equivalent + * according to StrictWeakOrdering(). + */ +template <class DL> +template<typename COMPARE> +inline +void +ConstDataList<DL>::merge( ConstDataList& l, COMPARE predicate ) +{ + DL::merge (l, predicate); +} + + +//=== Non-standard operations. + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DL> +inline +void +ConstDataList<DL>::swapElement (iterator pos, + value_type newElem, + reference oldElem) +{ + DL::swapElement (to_base_iterator(pos), + const_cast<typename DL::value_type>(newElem), + const_cast<typename DL::reference>(oldElem)); +} + + +/** + * @brief Return a pointer to this object, as a const @c DataVector. + */ +template <class DL> +inline +const DL* +ConstDataList<DL>::asDataList() const +{ + return static_cast<const DL*>(this); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c ConstDataList. + */ +template <class DL> +inline +void ConstDataList<DL>::resortAux (iterator /*beg*/, iterator /*end*/) +{ +} + + +//=== Relational operators. + + +/** + * @brief List ordering relation. + * @param a A @c ConstDataList. + * @param b A @c ConstDataList of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * lists. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ +template <class DL> +inline +bool ConstDataList<DL>::operator< (const ConstDataList& b) const +{ + return static_cast<const DL&>(*this) < static_cast<const DL&>(b); +} + + +/// Based on operator< +template <class DL> +inline +bool ConstDataList<DL>::operator> (const ConstDataList& b) const +{ + return static_cast<const DL&>(*this) > static_cast<const DL&>(b); +} + + +/// Based on operator< +template <class DL> +inline +bool ConstDataList<DL>::operator<= (const ConstDataList& b) const +{ + return static_cast<const DL&>(*this) <= static_cast<const DL&>(b); +} + + +/// Based on operator< +template <class DL> +inline +bool ConstDataList<DL>::operator>= (const ConstDataList& b) const +{ + return static_cast<const DL&>(*this) >= static_cast<const DL&>(b); +} + + +/** + * @brief List equality comparison. + * @param a A @c ConstDataList. + * @param b A @c ConstDataList of the same type as @a x. + * @return True iff the size and elements of the lists are equal. + * + * This is an equivalence relation. It is linear in the size of the + * lists. Lists are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ +template <class DL> +inline +bool ConstDataList<DL>::operator== (const ConstDataList& b) const +{ + return static_cast<const DL&>(*this) == static_cast<const DL&>(b); +} + + +/// Based on operator== +template <class DL> +inline +bool ConstDataList<DL>::operator!= (const ConstDataList& b) const +{ + return static_cast<const DL&>(*this) != static_cast<const DL&>(b); +} + + +//=== Private helpers. + + +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ +template <class DL> +inline +void +ConstDataList<DL>::assignElement (typename BaseContainer::iterator pos, + value_type newElem) +{ + DL::assignElement (pos, const_cast<typename DL::value_type> (newElem)); +} + + +/** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class DL> +inline +void +ConstDataList<DL>::assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem) +{ + DL::assignBaseElement (pos, newElem); +} + + +/** + * @brief Convert a @c ConstDataVector::iterator to an iterator + * of the base @c DataVector. + * @param it The @c ConstDataVector::iterator to convert. + */ +template <class DL> +inline +typename DL::iterator +ConstDataList<DL>::to_base_iterator (iterator it) +{ + return typename DL::iterator (it.base(), it.container()); +} + + +/** + * @brief Convert an iterator of the base @c DataList to + * a @c ConstDataList::iterator. + * @param it The base @c DataList iterator to convert. + */ +template <class DL> +inline +typename ConstDataList<DL>::iterator +ConstDataList<DL>::to_my_iterator (typename DL::iterator it) +{ + return iterator (it.base(), this); +} + + +/** + * @brief Convert an iterator of the base @c vector + * an @c ElementProxy for the @c ConstDataVector. + * @param it The base @c vector iterator to convert. + */ +template <class DL> +inline +typename ConstDataList<DL>::ElementProxy +ConstDataList<DL>::to_element_proxy (typename BaseContainer::iterator i) +{ + return ElementProxy (i, this); +} + + +/// Out-of-line functions. + + +/// See <code>DataList<T, BASE>::swap()</code>. +template <class T> +inline +void swap( ConstDataList<T>& a, ConstDataList<T>& b ) +{ + a.swap(b); +} + + +//=== Other helper classes. + + +/** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ +namespace SG { +template <class DL> +DVLConstDataListBucket<DL>::DVLConstDataListBucket + (ConstDataList<DL>* data) + : DVLDataBucket<DL> (const_cast<DL*> (data->asDataList())) +{ +} + + +#if __cplusplus > 201100 +/** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ +template <class DL> +DVLConstDataListBucket<DL>::DVLConstDataListBucket + (std::unique_ptr<ConstDataList<DL> > data) + : DVLDataBucket<DL> (std::unique_ptr<DL> (const_cast<DL*> (data.release()->asDataList()))) +{ +} +#endif + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.h b/EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.h new file mode 100644 index 00000000..8629ab30 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.h @@ -0,0 +1,1001 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ConstDataVector.h 800990 2017-03-19 23:15:21Z ssnyder $ +/** + * @file AthContainers/ConstDataVector.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2011 + * @brief @c DataVector adapter that acts like it holds const pointers. + * + * A @c DataVector\<T> acts as a container of @c T*. + * This means, though, that one cannot put a <code>const T*</code> + * into a @c DataVector\<T>. However, one sometimes wants + * to do that. A typical case is that one retrieves + * a const @c DataVector from StoreGate, filters the contents, + * and then stores them in a new @c DataVector. Recall that + * a const @c DataVector will return <code>const T*</code>. + * So the pointers one gets from a const @c DataVector + * cannot be inserted into another @c DataVector. + * (The root cause of this is that we don't want to have + * to deal with distinct <code>DataVector\<T></code> and + * <code>DataVector\<const T></code> types, and thus + * @c DataVector [and StoreGate] don't have standard const semantics.) + * + * To solve this, we introduce the template class @c ConstDataVector\<DV>. + * The template argument should be a @c DataVector class or something + * that derives from one. (The reason the template argument is the + * @c DataVector class rather than the element type @c T is to allow + * for types that derive from @c DataVector.) @c ConstDataVector\<DV> + * derives from @c DV, but privately --- so it is a @c DV, but clients + * cannot use it as a @c DV. Instead, we provide only methods that + * retrieve const pointers. Further, the insertion methods will + * take const rather than non-const pointers. + * + * There are two ways (short of casting) to convert a @c ConstDataVector\<DV> + * to a <code>const DV</code>. The @c asDataVector method will directly + * do this conversion. Also, if the object is recorded in StoreGate, + * it will automatically be made const, so a retrieval will get + * a <code>const DV</code>. A @c ConstDataVector should not convert + * to a non-const @c DV. + * + * So, for example, filtering might look something like this: + * + *@code + * const DataVector<T>* v_in = 0; + * CHECK( sg->retrieve (v_in) ); + * ConstDataVector<DataVector<T> >* v_out = + * new ConstDataVector<DataVector<T> > (SG::VIEW_ELEMENTS); + * CHECK( sg->record (v_out, "key") ); + * for (const T* t : *v_in) { + * if (filter (t)) + * v_out->push_back (t); + * } + @endcode + * + * Note that if you are not recording the result in StoreGate, + * it may well be preferable to just use a <code>std::vector<const T*></code> + * rather than @c ConstDataVector. + */ + + +#ifndef ATHCONTAINERS_CONSTDATAVECTOR_H +#define ATHCONTAINERS_CONSTDATAVECTOR_H + +#include "AthContainers/DataVector.h" +#include "AthLinks/ElementLink.h" +#if __cplusplus > 201100 +#include <initializer_list> +#endif + + +/** + * @brief @c DataVector adapter that acts like it holds const pointers. + */ +template <class DV> +class ConstDataVector + : private DV +{ +public: + /// Basic types, forwarded from the base. + typedef typename DV::size_type size_type; + typedef typename DV::difference_type difference_type; + typedef typename DV::allocator_type allocator_type; + typedef typename DV::base_value_type base_value_type; + typedef typename DV::BaseContainer BaseContainer; + typedef typename DV::DVL_BASE DVL_BASE; + typedef typename DV::const_iterator const_iterator; + typedef typename DV::const_reverse_iterator const_reverse_iterator; + + // Not necessarily DV; DV may be an intermediate class. + typedef DataVector<base_value_type> base_data_vector; + + /// These types get modified so that the base's @c const_value_type + /// becomes our @c value_type. + typedef typename DV::const_value_type value_type; + typedef typename DV::const_value_type const_value_type; + typedef typename DV::const_value_type & reference; + typedef typename DV::const_value_type const & const_reference; + typedef typename DV::const_value_type * pointer; + typedef typename DV::const_value_type const * const_pointer; + + /// This needs to be forwarded from the base as well. + static const bool has_virtual = DV::has_virtual; + + /// This type is used to proxy lvalue accesses to @c DataVector + /// elements, in order to handle ownership. + typedef DataModel_detail::ElementProxy<ConstDataVector> ElementProxy; + + /// The iterator for this type. + typedef typename DataModel_detail::iterator<ConstDataVector> iterator; + + /// Standard @c reverse_iterator. Note that lvalue references here will + /// yield an @c ElementProxy, not a @c reference. + typedef typename std::reverse_iterator<iterator> + reverse_iterator; + + typedef boost::true_type isSequence; + + /// Expose methods from the base that don't allow getting back + /// non-const pointers. + using DV::size; + using DV::max_size; + using DV::resize; + using DV::capacity; + using DV::empty; + using DV::reserve; + using DV::pop_back; + using DV::sort; + using DV::ownPolicy; + using DV::trackIndices; + using DV::testInsert; + using DV::getConstStore; + using DV::setStore; + using DV::setConstStore; + using DV::setNonConstStore; + using DV::cbegin; + using DV::cend; + using DV::crbegin; + using DV::crend; +#if __cplusplus > 201100 + using DV::shrink_to_fit; +#endif + + + /// Expose the const versions of these methods too. + /// We'll need to be sure to override the non-const versions of all of these + /// below. + using DV::begin; + using DV::end; + using DV::rbegin; + using DV::rend; + using DV::front; + using DV::back; + using DV::operator[]; + using DV::at; + + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit ConstDataVector(SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit ConstDataVector(size_type n, + SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS); + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a view container is made, which does not own its elements. + * To have the container take ownership of the pointers passed + * to this constructor, pass @c SG::OWN_ELEMENTS for @a ownPolicy. + */ + template <class InputIterator> + ConstDataVector(InputIterator first, InputIterator last, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS); + + + /** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ + // The copy constructor for derived classes is deliberately omitted, + // as otherwise we get warnings about not calling the copy constructors + // for base classes, which are problematic when we have virtual + // inheritance. Most of what needs doing is done in the base class anyway, + // except for setting @c m_isMostDerived. We arrange for these flags + // to all get set to false; they'll get set correctly when + // @c testInsert is called. +#if __cplusplus > 201100 + // Need this to get the default copy ctor defined when a move + // ctor is also present. + ConstDataVector (const ConstDataVector&) = default; +#endif + + +#if __cplusplus > 201100 + /** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + ConstDataVector (ConstDataVector&& rhs); + + + /** + * @brief Constructor from an initializer list. + * @param l An initializer list. + * @param ownPolicy The ownership mode for the container. + * + * By default, a view container is made, which does not own its elements. + * To have the container take ownership of the pointers passed + * to this constructor, pass @c SG::OWN_ELEMENTS for @a ownPolicy. + */ + ConstDataVector(std::initializer_list<value_type> l, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS); +#endif + + + /** + * @brief Constructor from a vector of ElementLinks. + * @param v The vector from which to initialize. + * + * This will make a view container. + */ + template <class CONTAINER> + ConstDataVector (const std::vector<ElementLink<CONTAINER> >& v); + + + /** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + ConstDataVector& operator= (const ConstDataVector& rhs) ; + + +#if __cplusplus > 201100 + /** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + ConstDataVector& operator= (ConstDataVector&& rhs); + + + /** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + ConstDataVector& operator= (std::initializer_list<value_type> l); +#endif + + + /** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + template <class InputIterator> + void assign(InputIterator first, InputIterator last); + + +#if __cplusplus > 201100 + /** + * @brief Assign from an initializer list. + * @param l An initializer list. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + void assign(std::initializer_list<value_type> l); +#endif + + + /** + * @brief Assign from a vector of ElementLinks. + * @param v The vector from which to initialize. + * + * This will change the container to a view container. + */ + template <class CONTAINER> + void assign (const std::vector<ElementLink<CONTAINER> >& v); + + + //@} + //======================================================================== + /** @name Element access. */ + //@{ + + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy operator[] (size_type n); + + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy at (size_type n); + + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy front (); + + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy back (); + + + //@} + //======================================================================== + /** @name Iterator creation. */ + //@{ + + + /** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator begin(); + + + /** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator end(); + + + /** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rbegin(); + + + /** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rend(); + + + //@} + //======================================================================== + /** @name Insertion operations. */ + //@{ + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void push_back(value_type pElem); + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c push_back. + * It's included just for interface compatibility with `std::vector`. + */ + void emplace_back(value_type pElem); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + iterator insert(iterator position, value_type pElem); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c insert. + * It's included just for interface compatibility with `std::vector`. + */ + iterator emplace(iterator position, value_type pElem); + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + template <class InputIterator> + void insert(iterator position, InputIterator first, InputIterator last); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void push_back(std::unique_ptr<const base_value_type> pElem); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + iterator insert(iterator position, std::unique_ptr<const base_value_type> pElem); +#endif + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param l An initializer list. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void insert(iterator position, std::initializer_list<value_type> l); +#endif + + + //@} + //======================================================================== + /** @name Erasure operations. */ + //@{ + + + /** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ + iterator erase(iterator position); + + + /** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + iterator erase(iterator first, iterator last); + + + /** + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear(); + + + //@} + //======================================================================== + /** @name Swap and sort. */ + //@{ + + + /** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataVector in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataVector. + */ + void swap(ConstDataVector& rhs); + + + /** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ + static void iter_swap (iterator a, iterator b); + + + //@} + //======================================================================== + /** @name Non-standard operations. */ + //@{ + + + + /** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(size_type index, value_type newElem, reference oldElem); + + + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, value_type newElem, reference oldElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(size_type index, + std::unique_ptr<const base_value_type> newElem, + std::unique_ptr<const base_value_type>& oldElem); + + + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, + std::unique_ptr<const base_value_type> newElem, + std::unique_ptr<const base_value_type>& oldElem); +#endif +#endif + + +public: + /** + * @brief Return a pointer to this object, as a const @c DataVector. + */ + const DV* asDataVector() const; + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c ConstDataVector. + */ + void resortAux (iterator /*beg*/, iterator /*end*/); + + + /** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy); + + + /** + * @fn void clear + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices); + + + /** + * @brief Convert to @c AuxVectorBase. + * + * Needed to get @x AuxVectorBase from a @c ConstDataVector. + * Present in @c DataVector as well for consistency. + */ + const SG::AuxVectorBase& auxbase() const; + + + //@} + //======================================================================== + /** @name Relational operators. */ + //@{ + + + /** + * @brief Vector ordering relation. + * @param a A @c ConstDataVector. + * @param b A @c ConstDataVector of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * vectors. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ + bool operator< (const ConstDataVector& b) const; + + /// Based on operator< + bool operator> (const ConstDataVector& b) const; + + /// Based on operator< + bool operator<= (const ConstDataVector& b) const; + + /// Based on operator< + bool operator>= (const ConstDataVector& b) const; + + + /** + * @brief Vector equality comparison. + * @param a A @c ConstDataVector. + * @param b A @c ConstDataVector of the same type as @a x. + * @return True iff the size and elements of the vectors are equal. + * + * This is an equivalence relation. It is linear in the size of the + * vectors. Vectors are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ + bool operator== (const ConstDataVector& b) const; + + /// Based on operator== + bool operator!= (const ConstDataVector& b) const; + + + +private: + //@} + //======================================================================== + /** @name Private helpers. */ + //@{ + + + friend class DataModel_detail::ElementProxy<ConstDataVector>; + friend void test2_assignelement1<ConstDataVector>(); + + + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, value_type newElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The container must own its elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, + std::unique_ptr<const base_value_type> newElem); +#endif +#endif + + + /** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void + assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem); + + + /** + * @brief Convert a @c ConstDataVector::iterator to an iterator + * of the base @c DataVector. + * @param it The @c ConstDataVector::iterator to convert. + */ + static + typename DV::iterator to_base_iterator (iterator it); + + + /** + * @brief Convert an iterator of the base @c DataVector to + * a @c ConstDataVector::iterator. + * @param it The base @c DataVector iterator to convert. + */ + iterator to_my_iterator (typename DV::iterator it); + + + /** + * @brief Convert an iterator of the base @c vector to + * an @c ElementProxy for the @c ConstDataVector. + * @param it The base @c vector iterator to convert. + */ + ElementProxy to_element_proxy (typename BaseContainer::iterator i); + + + //@} +}; + + +#ifndef XAOD_STANDALONE + +#include "SGTools/ClassID_traits.h" + +/** + * @brief Specialize @c ClassID_traits for @c ConstDataVector so that + * they will be automatically made const when recorded in StoreGate. + */ +template <class DV> +struct ClassID_traits<ConstDataVector<DV> > + : public ClassID_traits<DV> +{ +public: + BOOST_STATIC_CONSTANT(bool, s_isConst = true); +}; + + +namespace SG { + + +/** + * @brief @c DataBucket class for @c ConstDataVector. + * + * This is just the same as @c DVLDataBucket, except that we've + * got to convert the @c ConstDataVector to @c DataVector. + * + * Note: Can be used to violate const-correctness. + * Don't use this yourself! + */ +template <class DV> +class DVLConstDataVectorBucket + : public DVLDataBucket<DV> +{ +public: + /** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ + DVLConstDataVectorBucket (ConstDataVector<DV>* data); + + +#if __cplusplus > 201100 + /** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ + DVLConstDataVectorBucket (std::unique_ptr<ConstDataVector<DV> > data); +#endif +}; + + +/** + * @brief Metafunction to find the proper @c DataBucket class for + * the first template argument. + * + * Specialize this for @c ConstDataVector. + * See SGTools/StorableConversions.h for an explanation. + */ +template <class DV, class U> +struct DataBucketTrait<ConstDataVector<DV>, U> +{ + typedef SG::DVLConstDataVectorBucket<DV> type; + static void init() { DV::dvlinfo(); } +}; + + +/** + * @brief Let the @c BaseInfo for @c ConstDataVector forward to that + * of the base @c DataVector. + */ +template <class DV> +class BaseInfo<ConstDataVector<DV> > + : public BaseInfo<DV> +{ +}; + + +} // namespace SG + + +#endif // not XAOD_STANDALONE + + +#include "AthContainers/ConstDataVector.icc" + + +#endif // not ATHCONTAINERS_CONSTDATAVECTOR_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.icc b/EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.icc new file mode 100644 index 00000000..59dcb0e7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ConstDataVector.icc @@ -0,0 +1,1134 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ConstDataVector.icc 717853 2016-01-14 21:41:19Z ssnyder $ +/** + * @file AthContainers/ConstDataVector.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2011 + * @brief @c DataVector adapter that acts like it holds const pointers. + */ + + +#include <boost/iterator/transform_iterator.hpp> +#include <functional> + + +namespace ConstDataVector_detail { + + +/// Functional to cast const away. +template <class T> +class remove_const + : public std::unary_function<const T*, T*> +{ +public: + T* operator() (const T* p) const { return const_cast<T*> (p); } +}; + + +} // namespace ConstDataVector_detail + + +//=== Constructors, destructors, assignment. + + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DV> +inline +ConstDataVector<DV>::ConstDataVector + (SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/) + : DV (ownPolicy) +{ + base_data_vector::clear (ownPolicy, SG::NEVER_TRACK_INDICES); +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DV> +inline +ConstDataVector<DV>::ConstDataVector + (size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/) + : DV (n, ownPolicy) +{ + base_data_vector::clear (ownPolicy, SG::NEVER_TRACK_INDICES); + DV::resize (n); +} + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataVector will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DV> +template <class InputIterator> +inline +ConstDataVector<DV>::ConstDataVector + (InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/) + : DV (ownPolicy) +{ + base_data_vector::clear (ownPolicy, SG::NEVER_TRACK_INDICES); + reserve (std::distance (first, last)); + while (first != last) + push_back (*first++); +} + + +#if __cplusplus > 201100 +/** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class DV> +inline +ConstDataVector<DV>::ConstDataVector (ConstDataVector&& rhs) + : DV (std::move (rhs)) +{ +} + + +/** + * @brief Constructor from an initializer list. + * @param l An initializer list. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataVector will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class DV> +inline +ConstDataVector<DV>::ConstDataVector + (std::initializer_list<value_type> l, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/) + : ConstDataVector (l.begin(), l.end(), ownPolicy) +{ +} +#endif + + +/** + * @brief Constructor from a vector of ElementLinks. + * @param v The vector from which to initialize. + * + * This will make a view container. + */ +template <class DV> +template <class CONTAINER> +ConstDataVector<DV>::ConstDataVector + (const std::vector<ElementLink<CONTAINER> >& v) + : DV (SG::VIEW_ELEMENTS) +{ + this->reserve (v.size()); + for (const ElementLink<CONTAINER>& el : v) + this->push_back (*el); +} + + +/** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +ConstDataVector<DV>& +ConstDataVector<DV>::operator= (const ConstDataVector& rhs) +{ + *static_cast<DV*>(this) = rhs; + return *this; +} + + +#if __cplusplus > 201100 +/** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class DV> +inline +ConstDataVector<DV>& +ConstDataVector<DV>::operator= (ConstDataVector&& rhs) +{ + if (this != &rhs) { + DV::operator= (std::move (rhs)); + } + return *this; +} + + +/** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class DV> +inline +ConstDataVector<DV>& +ConstDataVector<DV>::operator= (std::initializer_list<value_type> l) +{ + this->assign (l.begin(), l.end()); + return *this; +} +#endif + + +/** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class DV> +template <class InputIterator> +inline +void ConstDataVector<DV>::assign(InputIterator first, InputIterator last) +{ + clear(); + reserve (std::distance (first, last)); + while (first != last) + push_back (*first++); +} + + +#if __cplusplus > 201100 +/** + * @brief Assign from an initializer list. + * @param l An initializer list. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class DV> +inline +void ConstDataVector<DV>::assign(std::initializer_list<value_type> l) +{ + this->assign (l.begin(), l.end()); +} +#endif + + +/** + * @brief Assign from a vector of ElementLinks. + * @param v The vector from which to initialize. + * + * This will change the container to a view container. + */ +template <class DV> +template <class CONTAINER> +void ConstDataVector<DV>::assign (const std::vector<ElementLink<CONTAINER> >& v) +{ + this->clear(SG::VIEW_ELEMENTS); + this->reserve (v.size()); + for (const ElementLink<CONTAINER>& el : v) + this->push_back (*el); +} + + +//=== Element access. + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::ElementProxy +ConstDataVector<DV>::operator[] (size_type n) +{ + return to_element_proxy (this->m_pCont.begin() + n); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::ElementProxy +ConstDataVector<DV>::at (size_type n) +{ + if (n >= this->size()) + throw std::out_of_range ("DataVector::at range check"); + return to_element_proxy (this->m_pCont.begin() + n); +} + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::ElementProxy +ConstDataVector<DV>::front () +{ + return to_element_proxy (this->m_pCont.begin()); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::ElementProxy +ConstDataVector<DV>::back () +{ + return to_element_proxy (this->m_pCont.end()-1); +} + + +//=== Iterator creation. + + +/** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::begin() +{ + return to_my_iterator (DV::begin()); +} + + +/** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::end() +{ + return to_my_iterator (DV::end()); +} + + +/** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::reverse_iterator +ConstDataVector<DV>::rbegin() +{ + return reverse_iterator (to_my_iterator (DV::end())); +} + + +/** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class DV> +inline +typename ConstDataVector<DV>::reverse_iterator +ConstDataVector<DV>::rend() +{ + return reverse_iterator (to_my_iterator (DV::begin())); +} + + +//=== Insertion operations. + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +void ConstDataVector<DV>::push_back(value_type pElem) +{ + DV::push_back (const_cast<typename DV::value_type> (pElem)); +} + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c push_back. + * It's included just for interface compatibility with `std::vector`. + */ +template <class DV> +inline +void ConstDataVector<DV>::emplace_back(value_type pElem) +{ + this->push_back (pElem); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::insert(iterator position, value_type pElem) +{ + return to_my_iterator + (DV::insert (to_base_iterator (position), + const_cast<typename DV::value_type> (pElem))); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c insert. + * It's included just for interface compatibility with `std::vector`. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::emplace(iterator position, value_type pElem) +{ + return this->insert (position, pElem); +} + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +template <class InputIterator> +inline +void ConstDataVector<DV>::insert (iterator position, + InputIterator first, + InputIterator last) +{ + typedef boost::transform_iterator + <ConstDataVector_detail::remove_const<typename DV::base_value_type>, + InputIterator> + iterator_t; + DV::insert (to_base_iterator(position), + iterator_t (first), + iterator_t (last)); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +void ConstDataVector<DV>::push_back(std::unique_ptr<const base_value_type> pElem) +{ + std::unique_ptr<typename DV::base_value_type> ptr + (const_cast<typename DV::value_type> (pElem.release())); + DV::push_back (std::move (ptr)); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::insert(iterator position, + std::unique_ptr<const base_value_type> pElem) +{ + std::unique_ptr<typename DV::base_value_type> ptr + (const_cast<typename DV::value_type> (pElem.release())); + return to_my_iterator + (DV::insert (to_base_iterator (position), std::move (ptr))); +} +#endif + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param l An initializer list. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +void ConstDataVector<DV>::insert (iterator position, + std::initializer_list<value_type> l) +{ + this->insert (position, l.begin(), l.end()); +} +#endif + + +//=== Erasure operations. + + +/** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::erase(iterator position) +{ + return to_my_iterator (DV::erase (to_base_iterator (position))); +} + + +/** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::erase(iterator first, iterator last) +{ + return to_my_iterator + (DV::erase (to_base_iterator (first), + to_base_iterator (last))); +} + + +/** + * @brief clear() + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class DV> +inline +void ConstDataVector<DV>::clear() +{ + DV::clear(); +} + + +/** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataVector in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataVector. + */ +template <class DV> +inline +void ConstDataVector<DV>::swap (ConstDataVector& rhs) +{ + DV::swap (rhs); +} + + +/** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ +template <class DV> +inline +void ConstDataVector<DV>::iter_swap (iterator a, iterator b) +{ + DV::iter_swap (to_base_iterator (a), + to_base_iterator (b)); +} + + +//=== Non-standard operations. + + +/** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +void +ConstDataVector<DV>::swapElement (size_type index, + value_type newElem, + reference oldElem) +{ + DV::swapElement (index, + const_cast<typename DV::value_type>(newElem), + const_cast<typename DV::reference>(oldElem)); +} + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DV> +inline +void +ConstDataVector<DV>::swapElement (iterator pos, + value_type newElem, + reference oldElem) +{ + DV::swapElement (to_base_iterator(pos), + const_cast<typename DV::value_type>(newElem), + const_cast<typename DV::reference>(oldElem)); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +void +ConstDataVector<DV>::swapElement (size_type index, + std::unique_ptr<const base_value_type> newElem, + std::unique_ptr<const base_value_type>& oldElem) +{ + std::unique_ptr<typename DV::base_value_type> new_u + (const_cast<typename DV::value_type> (newElem.release())); + std::unique_ptr<typename DV::base_value_type> old_u; + DV::swapElement (index, std::move(new_u), old_u); + oldElem = std::move (old_u); +} + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class DV> +inline +void +ConstDataVector<DV>::swapElement (iterator pos, + std::unique_ptr<const base_value_type> newElem, + std::unique_ptr<const base_value_type>& oldElem) +{ + std::unique_ptr<typename DV::base_value_type> new_u + (const_cast<typename DV::value_type> (newElem.release())); + std::unique_ptr<typename DV::base_value_type> old_u; + DV::swapElement (to_base_iterator(pos), std::move(new_u), old_u); + oldElem = std::move (old_u); +} +#endif +#endif + + +/** + * @brief Return a pointer to this object, as a const @c DataVector. + */ +template <class DV> +inline +const DV* +ConstDataVector<DV>::asDataVector() const +{ + return static_cast<const DV*>(this); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c ConstDataVector. + */ +template <class DV> +inline +void ConstDataVector<DV>::resortAux (iterator /*beg*/, iterator /*end*/) +{ +} + + +/** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class DV> +inline +void ConstDataVector<DV>::clear (SG::OwnershipPolicy ownPolicy) +{ + DV::clear (ownPolicy, SG::NEVER_TRACK_INDICES); +} + + +/** + * @fn void clear + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class DV> +inline +void ConstDataVector<DV>::clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices) +{ + DV::clear (ownPolicy, trackIndices); + if (DV::trackIndices()) std::abort(); +} + + +/** + * @brief Convert to @c AuxVectorBase. + * + * Needed to get @x AuxVectorBase from a @c ConstDataVector. + * Present in @c DataVector as well for consistency. + */ +template <class DV> +inline +const SG::AuxVectorBase& ConstDataVector<DV>::auxbase() const +{ + return *this; +} + + +//=== Relational operators. + + +/** + * @brief Vector ordering relation. + * @param a A @c ConstDataVector. + * @param b A @c ConstDataVector of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * vectors. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ +template <class DV> +inline +bool ConstDataVector<DV>::operator< (const ConstDataVector& b) const +{ + return static_cast<const DV&>(*this) < static_cast<const DV&>(b); +} + + +/// Based on operator< +template <class DV> +inline +bool ConstDataVector<DV>::operator> (const ConstDataVector& b) const +{ + return static_cast<const DV&>(*this) > static_cast<const DV&>(b); +} + + +/// Based on operator< +template <class DV> +inline +bool ConstDataVector<DV>::operator<= (const ConstDataVector& b) const +{ + return static_cast<const DV&>(*this) <= static_cast<const DV&>(b); +} + + +/// Based on operator< +template <class DV> +inline +bool ConstDataVector<DV>::operator>= (const ConstDataVector& b) const +{ + return static_cast<const DV&>(*this) >= static_cast<const DV&>(b); +} + + +/** + * @brief Vector equality comparison. + * @param a A @c ConstDataVector. + * @param b A @c ConstDataVector of the same type as @a x. + * @return True iff the size and elements of the vectors are equal. + * + * This is an equivalence relation. It is linear in the size of the + * vectors. Vectors are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ +template <class DV> +inline +bool ConstDataVector<DV>::operator== (const ConstDataVector& b) const +{ + return static_cast<const DV&>(*this) == static_cast<const DV&>(b); +} + + +/// Based on operator== +template <class DV> +inline +bool ConstDataVector<DV>::operator!= (const ConstDataVector& b) const +{ + return static_cast<const DV&>(*this) != static_cast<const DV&>(b); +} + + +//=== Private helpers. + + +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class DV> +inline +void +ConstDataVector<DV>::assignElement (typename BaseContainer::iterator pos, + value_type newElem) +{ + DV::assignElement (pos, const_cast<typename DV::value_type> (newElem)); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The container must own its elements. + * Auxiliary data are copied if appropriate. + */ +template <class DV> +inline +void +ConstDataVector<DV>::assignElement (typename BaseContainer::iterator pos, + std::unique_ptr<const base_value_type> newElem) +{ + std::unique_ptr<typename DV::base_value_type> new_u + (const_cast<typename DV::value_type> (newElem.release())); + DV::assignElement (pos, std::move(new_u)); +} +#endif +#endif + + +/** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class DV> +inline +void +ConstDataVector<DV>::assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem) +{ + DV::assignBaseElement (pos, newElem); +} + + +/** + * @brief Convert a @c ConstDataVector::iterator to an iterator + * of the base @c DataVector. + * @param it The @c ConstDataVector::iterator to convert. + */ +template <class DV> +inline +typename DV::iterator +ConstDataVector<DV>::to_base_iterator (iterator it) +{ + return typename DV::iterator (it.base(), it.container()); +} + + +/** + * @brief Convert an iterator of the base @c DataVector to + * a @c ConstDataVector::iterator. + * @param it The base @c DataVector iterator to convert. + */ +template <class DV> +inline +typename ConstDataVector<DV>::iterator +ConstDataVector<DV>::to_my_iterator (typename DV::iterator it) +{ + return iterator (it.base(), this); +} + + +/** + * @brief Convert an iterator of the base @c vector + * an @c ElementProxy for the @c ConstDataVector. + * @param it The base @c vector iterator to convert. + */ +template <class DV> +inline +typename ConstDataVector<DV>::ElementProxy +ConstDataVector<DV>::to_element_proxy (typename BaseContainer::iterator i) +{ + return ElementProxy (i, this); +} + + +//=== Other helper classes. + + +#ifndef XAOD_STANDALONE + + +/** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ +namespace SG { + + +template <class DV> +DVLConstDataVectorBucket<DV>::DVLConstDataVectorBucket + (ConstDataVector<DV>* data) + : DVLDataBucket<DV> (const_cast<DV*> (data->asDataVector())) +{ +} + + +#if __cplusplus > 201100 +/** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ +template <class DV> +DVLConstDataVectorBucket<DV>::DVLConstDataVectorBucket + (std::unique_ptr<ConstDataVector<DV> > data) + : DVLDataBucket<DV> (std::unique_ptr<DV> (const_cast<DV*> (data.release()->asDataVector()))) +{ +} +#endif // C++11 + + +} // namespace SG + + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/AthContainers/DataList.h b/EDM/athena/Control/AthContainers/AthContainers/DataList.h new file mode 100644 index 00000000..2129e7f1 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/DataList.h @@ -0,0 +1,2305 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataList.h 772789 2016-09-12 15:55:30Z ssnyder $ + +/** + * @file AthContainers/DataList.h + * @author Srini Rajagopalan, Sebastien Binet - ATLAS Collaboration + * @date February 2006; rewritten from earlier version. + * @brief An STL list of pointers that by default owns its pointed-to + * elements + * + * For further information, see + * <https://twiki.cern.ch/twiki/bin/view/Atlas/DataVector> + * + * A @c DataList<T> acts like a @c std::list<T*>, except that it can + * optionally manage the memory that it contains. The constructors take + * an (optional) extra argument, which can be either @c SG::OWN_ELEMENTS + * or @c SG::VIEW_ELEMENTS (defaulting to @c SG::OWN_ELEMENTS except for a + * copy constructor). This tells whether the @c DataList owns its contained + * elements or not. + * + * If a @c DataList owns its elements, then they are deleted when the + * container itself is. Further, they are deleted by actions which + * erase elements from the container (i.e.: @c erase(), @c pop_back() ). + * A replacement (such as <code> (*l.front()) = new T; </code>) will result + * in the old element being deleted and the container taking ownership of + * the new element. It is an error to assign directly between two + * owning containers (<code> (*list1.front()) = (*list2.front());</code>). + * + * Beware of ownership issues when modify a @c DataList . + * Obviously you should not delete explicitly a @c DataList element + * (because this is already taken care of by this object). + * A @c DataList should never have two elements pointing to the same object. + * This may seem obvious but certain STL algorithms (eg: @c remove_if ) may + * leave a @c DataList with two copies of the same element in the "left-over" + * range. To avoid a crash when clearing the list (eg: in the destructor we + * have introduced a @f$ n\log n @f$ helper function that searches and removes + * duplicates in the @c DataList . This is used by the destructor by @c clear() + * and by <code>erase(first, last)</code>. As this may change in the future to + * improve performance, do not rely on this functionality and do avoid + * introducing duplicated elements in a @c DataList . + * + * All these cautions do not apply when a @c DataList it is created with + * the flag @c SG::VIEW_ELEMENTS (see <code>enum OwnershipPolicy</code>) + * and hence does not own its elements. This is typically used + * to have @c DataList elements allocated by @c DataPool. + * Otherwise consider the cleaner alternative of using a @c list<T*>. + * + * The interface for @c DataList should be mostly compatible with that + * of @c std::list. There are a few differences which should not make + * much difference in practice. For example, methods which would + * return a reference return a proxy object instead. Also @c value_type + * is used instead of @c const_reference; this is justified by the fact + * that the elements are always pointers. + * + * Note that algorithms which modify their range may not work + * correctly if the container owns its contents. Specializations + * that work properly for @c DataList are available for some algorithms. + * These include: + * - @c std::remove + * - @c std::remove_if + * - @c std::unique + * - @c std::reverse + * - @c std::rotate + * - @c std::partition + * - @c std::stable_partition + * + * There are a few other additions to the standard @c std::list interface. + * - The method @c stdcont may be used to get access to the underlying + * @c std::list representation. + * - The type @c PtrList is the type of the underlying @c std::List. + * @c BaseContainer is a synonym for this. + * - The method @c ownPolicy returns the ownership policy of the container. + * - An additional overload of @c clear() is provided that takes as + * an argument a new ownership policy for the container. This is + * the only way to change the ownership policy. + * + * Note that since @c DataList\<T> has an element type of @c T*, + * it is not possible to directly insert a <code>const T*</code>. + * If you want to do that, see @c ConstDataList. (In some cases, + * such as if the destination container is not being recorded in StoreGate, + * it may be more appropriate to simply use a + * <code>std::list<const T*></code>.) Don't just use a @c const_cast! + * + * Finally, @c DataList's may inherit from one another. + * If you have class @c D which derives from class @c B, you can set things + * up so that @c DataList\<D> derives from @c DataList\<B>. This allows + * you do to the same sort of conversions on the @c DataList's as on the + * element pointers themselves. The key to doing this is to add the + * declaration + * + *@code + * DATALIST_BASE (D, B); + @endcode + * + * before using @c DataList\<D>. A few caveats about doing this. + * The pointers are actually stored in the base @c DataList instance, + * and the type that @c stdcont returns will reflect this. + * For example, in the example given above, @c DataList<D>::stdcont() + * will return a reference to std::list\<B*>. Second, in order + * to preserve the invariant + * that a @c DataList\<D> contains only elements that actually derive + * from @c D, while at the same time not requiring that the contained + * objects be polymorphic, there is a restriction that you cannot + * insert into a @c DataList if you're not referring to it as the + * most derived type (even if such an insertion would not actually + * break the invariant). This is implemented as a runtime check. + * + * Example: + * + *@code + * DataList<D> ld; + * ld.push_back (new D); // This is ok. + * ld.push_back (new B); // This will give a compilation error + * (it would break the invariant). + * DataList<B>& lb = ld; + * lb.push_back (new B); // This will give a run-time error + * (it breaks the invariant). + * lb.push_back (new D); // This will also give a run-time error. + * (It's actually ok, but there's no good way + * to distinguish it from the previous case.) + @endcode + * + * Note also this (related to a common atlas idiom). If we have the above, + * and also: + * + *@code + * class B_List : public DataList<B> { ... }; + * class D_List : public DataList<D> { ... }; + @endcode + * + * Then a @c D_List will be convertible to a DataList\<B>, but _not_ + * to a @c B_List. + * + * Multiple and virtual inheritance are also supported. In this case, + * use <code>DATALIST_VIRTBASES</code><em>n</em> (where @e n is 1, 2, or 3) + * instead of @c DATALIST_BASE. Example: Given: + * + *@code + * class M { ... }; + * class N : virtual public M { ... }; + * class O : virtual public M { ... }; + * class P : virtual public N, virtual public O { ... }; + @endcode + * + * declare this with + * + *@code + * DATALIST_VIRTBASES1(N, M); + * DATALIST_VIRTBASES1(O, M); + * DATALIST_VIRTBASES2(P, N, O); + @endcode + * + * There is a restriction that there must be a unique base class that + * does not derive from anything else. For example, the diamond configuration + * above is ok, but this would not be: + * + *@code + * class L { ... }; + * class M { ... }; + * class N : virtual public M, virtual public L { ... }; + * class O : virtual public M { ... }; + * class P : virtual public N, virtual public O { ... }; + * + * DATALIST_VIRTBASES2(N, M, L); + * DATALIST_VIRTBASES1(O, M); + * DATALIST_VIRTBASES2(P, N, O); + @endcode + * + * Note, however, that you don't have to tell @c DataList about the complete + * hierarchy; leaving the @c L out of @c DATALIST_VIRTBASES would work + * (you just wouldn't be able to convert to @c DataList\<L> ). + * + * If you use @c DATALIST_VIRTBASES, there is an additional time penalty + * to retrieve elements from the collection. This does not apply + * for @c DATALIST_BASES. + * + * All applicable @c DATALIST_* macros must be visible at the point at which + * a @c DataList is instantiated. A confusing compilation error is + * likely to result otherwise. Note that this means that if you have + * the @c DATALIST_* macros within a container header file, then + * the header for the derived container must include the header + * for the base container. Be alert to this when converting existing + * code to use the inheritance scheme. For example, if class D2 derives + * from D which derives from B: + * + * BList.h: + *@code + * #include "B.h" + * #include "DataList.h" + * typedef DataList<B> BVec; + @endcode + * + * DList.h: + *@code + * #include "D.h" + * #include "DataList.h" + * DATALIST_BASE(D,B); + * typedef DataList<D> DVec; + @endcode + * + * D2List.h: + *@code + * #include "D2.h" + * #include "DataList.h" + * #include "DList.h" // This is required + * DATALIST_BASE(D2,D); + * typedef DataList<D2> DVec; + @endcode + * + * Using @c DATALIST_BASE will also set up the corresponding @c SG::BaseInfo + * definitions, both for the vectors themselves and for the contained objects. + */ + +#ifndef ATHCONTAINERS_DATALIST_H +#define ATHCONTAINERS_DATALIST_H + +// Make sure that this header is not used outside of Athena: +#ifdef XAOD_STANDALONE +#error "DataList is not supported outside of Athena!" +#endif // XAOD_STANDALONE + + +// For feature tests. +#define HAVE_CONSTDATAVECTOR + + +// STL includes +#include <list> +#include <typeinfo> +#include <functional> +#include <iostream> +#include <algorithm> // for std::swap, find, find_if +#include <iterator> +#include <type_traits> + +// Boost includes +#include <boost/static_assert.hpp> +#include <boost/type_traits.hpp> +#include <boost/iterator/iterator_adaptor.hpp> + +// Kernel and StoreGate includes +#include "SGTools/BaseInfo.h" +#include "SGTools/DataBucketTraitFwd.h" +#include "SGTools/ClassName.h" + +#include "AthContainers/DataVector.h" +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/DVLNoBase.h" +#include "AthContainers/tools/DVLInfo.h" +#include "AthContainers/tools/DVLDataBucket.h" +#include "AthContainers/tools/DVLCast.h" +#include "AthContainers/tools/DVLIterator.h" +#include "AthContainers/tools/DVL_iter_swap.h" +#include "AthContainers/tools/DVL_algorithms.h" +#include "AthContainers/tools/ElementProxy.h" +#include "AthContainers/tools/IsMostDerivedFlag.h" +#include "AthLinks/tools/selection_ns.h" + + +ENTER_ROOT_SELECTION_NS +template <class T, class BASE> class DataList; +EXIT_ROOT_SELECTION_NS + + +namespace DataList_detail { + + +// These are the intermediate classes from which @c DataList derives +// in the case of multiple or virtual derivation. The actual +// definitions are in the @c icc file. They have the following +// properties: +// - They derive from those of @c B1, @c B2, and @c B3 that are not +// @c NoBase. +// - They perform (static) checking to ensure that there's a unique +// base class in the hierarchy. +// - They make the following types available from the base classes: +// - @c PtrList +// - @c BaseContainer +// - @c size_type +// - @c difference_type +// - @c allocator_type +// - @c has_virtual is defined as @c true. +// - An override of @c dl_typeid is defined, to prevent ambiguities. +template <class B1, + class B2=DataModel_detail::NoBase, + class B3=DataModel_detail::NoBase> struct VirtBases; + +} // end namespace DataList_detail + +/** + * @brief Derivation information for @c DataList. + * + * Specializations of this class represent the derivation information that + * @c DataList needs. They have the property that + * <code>DataListBase<T>::Base</code> is either @c NoBase or it is the class + * from which @c DataList\<T> should derive. + */ +template <class T> +struct DataListBase +{ + typedef DataModel_detail::NoBase Base; +}; + +/** + * @brief Declare base class info to @c DataList. + * Single, non-virtual derivation. + * + * <code>DATALIST_BASE(D, B)</code> says that @c D derives + * non-virtually from @c B. + * + * This macro creates an appropriate specialization of @c DataListBase. + */ +#define DATALIST_BASE(T, BASE) \ +template <> struct DataListBase<T> \ +{ typedef DataList<BASE> Base; }; \ +SG_BASE(DataList<T>, DataList<BASE>); \ +template struct DataList_detail::DVLEltBaseInit<T> + + +/** + * @brief Declare base class info to @c DataList. + * Single, virtual derivation. + * + * <code>DATALIST_VIRTBASES(D, B1)</code> says that @c D derives + * virtually from @c B1. + * + * This macro creates an appropriate specialization of @c DataListBase. + */ +#define DATALIST_VIRTBASES1(T, B1) \ +template <> struct DataListBase<T> \ +{ typedef DataList_detail::VirtBases<B1> Base; }; \ +SG_BASES1(DataList<T>, SG_VIRTUAL(DataList<B1>)); \ +template struct DataList_detail::DVLEltBaseInit<T> + + + +/** + * @brief Declare base class info to @c DataList. + * Multiple derivation. + * + * <code>DATALIST_VIRTBASES(D, B1)</code> says that @c D derives + * from both @c B1 and @c B2. + * + * This macro creates an appropriate specialization of @c DataListBase. + */ +#define DATALIST_VIRTBASES2(T, B1, B2) \ +template <> struct DataListBase<T> \ +{ typedef DataList_detail::VirtBases<B1, B2> Base; }; \ +SG_BASES2(DataList<T>, SG_VIRTUAL(DataList<B1>), \ + SG_VIRTUAL(DataList<B2>)); \ +template struct DataList_detail::DVLEltBaseInit<T> + + +/** + * @brief Declare base class info to @c DataList. + * Multiple derivation. + * + * <code>DATALIST_VIRTBASES(D, B1)</code> says that @c D derives + * from all of @c B1, @c B2, and @c B3. + * + * This macro creates an appropriate specialization of @c DataListBase. + */ +#define DATALIST_VIRTBASES3(T, B1, B2, B3) \ +template <> struct DataListBase<T> \ +{ typedef DataList_detail::VirtBases<B1, B2, B3> Base; }; \ +SG_BASES3(DataList<T>, SG_VIRTUAL(DataList<B1>), \ + SG_VIRTUAL(DataList<B2>), \ + SG_VIRTUAL(DataList<B3>)); \ +template struct DataList_detail::DVLEltBaseInit<T> + + +template <class DL> class ConstDataList; +template <class DL> void test2_assignelement1(); + + +/** + * @brief Derived @c DataList\<T>. + * + * This is used for the case where @c T derives + * from other classes. The list of pointers is actually held + * in the (unique) base class of the hierarchy. + * + * See the file comments for full details. + */ +template <class T, class BASE = typename DataListBase<T>::Base> +class DataList : public BASE +{ +public: + typedef BASE DataList_BASE; + typedef BASE DVL_BASE; + + /// This is true for any @c DataList class if we need to use virtual + /// derivation to get to the base @c DataList class. + static const bool has_virtual = BASE::has_virtual; + + /// This is the type of the underlying @c std::list + /// (what @c stdcont returns). + typedef typename BASE::PtrList PtrList; + typedef typename BASE::PtrList BaseContainer; + + +public: + // Standard types required for the container interface. + typedef T*& reference; + typedef T* const & const_reference; + typedef typename BASE::size_type size_type; + typedef typename BASE::difference_type difference_type; + typedef T* value_type; + typedef typename BASE::allocator_type allocator_type; + typedef T** pointer; + typedef T* const * const_pointer; + + typedef const T* const_value_type; + + /// The @c T value used as the template parameter. + /// Note that this is different from @c value_type (that's @c T*). + typedef T base_value_type; + + /// This type is used to proxy lvalue accesses to @c DataList + /// elements, in order to handle ownership. + typedef DataModel_detail::ElementProxy<DataList> ElementProxy; + + + /// Standard @c const_iterator. + typedef typename DataModel_detail::const_iterator<DataList> + const_iterator; + + /// Standard @c iterator. Note that lvalue references here will yield + /// an @c ElementProxy, not a @c reference. + typedef typename DataModel_detail::iterator<DataList> iterator; + + + /// Standard @c const_reverse_iterator. + typedef typename std::reverse_iterator<const_iterator> + const_reverse_iterator; + + /// Standard @c reverse_iterator. Note that lvalue references here will + /// yield an @c ElementProxy, not a @c reference. + typedef typename std::reverse_iterator<iterator> + reverse_iterator; + + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataList( SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS ); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard list constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataList( size_type n, /* value_type pElem = 0,*/ + SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS ); + + + /** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ + // The copy constructor for derived classes is deliberately omitted, + // as otherwise we get warnings about not calling the copy constructors + // for base classes, which are problematic when we have virtual + // inheritance. Most of what needs doing is done in the base class anyway, + // except for setting @c m_isMostDerived. We arrange for these flags + // to all get set to false; they'll get set correctly when + // @c testInsert is called. + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + template <class InputIterator> + DataList( InputIterator first, InputIterator last, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS ); + + + /** + * @brief Assignment operator. + * @param rhs The DataList from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataList + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + DataList& operator=( const DataList& rhs ); + + + /** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataList's ownership policy determines whether it will take + * ownership of the new elements. + */ + template <class InputIterator> + void assign( InputIterator first, InputIterator last ); + + + // Destructor is inherited. + + + //@} + //======================================================================== + /** @name Size and capacity. */ + //@{ + + + /** + * @fn size_type size() const + * @brief Returns the number of elements in the collection. + */ + // This is inherited from the base class. + + + /** + * @fn size_type max_size() const + * @brief Returns the @c size() of the largest possible collection. + */ + // This is inherited from the base class. + + + /** + * @fn void resize(size_type sz) + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ + // This is inherited from the base class. + + + /** + * @fn bool empty() const + * @brief Returns @c true if the collection is empty. + */ + // This is inherited from the base class. + + + //@} + //======================================================================== + /** @name Element access. */ + //@{ + + /** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* front() const; + + + /** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* back() const; + + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy front (); + + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy back (); + + + //@} + //======================================================================== + /** @name Iterator creation. */ + //@{ + + + /** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator begin() const; + + + /** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator end() const; + + + /** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator begin(); + + + /** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator end(); + + + /** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rbegin() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rend() const; + + + /** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rbegin(); + + + /** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rend(); + + + //@} + //======================================================================== + /** @name Insertion operations. */ + //@{ + + + /** + * @brief Add an element at the beginning of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void push_front( value_type pElem ); + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void push_back( value_type pElem ); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + iterator insert( iterator position, value_type pElem ); + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + template <class InputIterator> + void insert( iterator position, InputIterator first, InputIterator last ); + + + //@} + //======================================================================== + /** @name Erasure operations. */ + //@{ + + + /** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ + iterator erase(iterator position); + + + /** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + iterator erase(iterator first, iterator last); + + + /** + * @fn void pop_back() + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ + // This is inherited from the base class. + + + /** + * @fn void pop_front() + * @brief Remove the first element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ + // This is inherited from the base class. + + + /** + * @fn void clear() + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + // This is inherited from the base class. + + + //@} + //======================================================================== + /** @name Swap and sort. */ + //@{ + + + /** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataList in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataList. + */ + void swap( DataList& rhs ); + + + /** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ + static void iter_swap (iterator a, iterator b); + + + /** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ + void sort(); + + + /** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + */ + template <class COMPARE> + void sort(COMPARE comp); + + + //@} + //======================================================================== + /** @name List operations. */ + //@{ + + + /** + * @brief Insert contents of another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * + * The elements of @a l are inserted in constant time in front of + * the element referenced by @a position. @a l becomes an empty + * list. + */ + void splice( iterator position, DataList& l ); + + /** + * @brief Insert element from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param i Iterator referencing the element to move. + * + * Removes the element in list @a l referenced by @a i and + * inserts it into the current list before @a position. + */ + void splice( iterator position, DataList& l, iterator i ); + + + /** + * @brief Insert range from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param first Iterator referencing the start of range in @a l. + * @param last Iterator referencing the end of range in @a l. + * + * Removes elements in the range [@a first, @a last ) and inserts them + * before @a position in constant time. + * + * Undefined if @a position is in [@a first, @a last ). + */ + void splice( iterator position, DataList& l, + iterator first, + iterator last ); + + + /** + * @brief Remove all elements equal to value. + * @param value The value to remove. + * + * Removes every element in the list equal to @a value. + * Remaining elements stay in list order. + */ + void remove( const value_type& value ); + + + /** + * @brief Remove all elements satisfying a predicate. + * @param p Unary predicate function or object. + * + * Removes every element in the list for which the predicate + * returns true. Remaining elements stay in list order. + */ + template<typename PREDICATE> + void remove_if( PREDICATE p ); + + + /** + * @brief Remove consecutive duplicate elements. + * + * For each consecutive set of elements with the same value, + * remove all but the first one. Remaining elements stay in + * list order. + */ + void unique(); + + + /** + * @brief Remove consecutive elements satisfying a predicate. + * @param p Binary predicate function or object. + * + * For each consecutive set of elements [first,last) that + * satisfy predicate(first,i) where i is an iterator in + * [first,last), remove all but the first one. Remaining + * elements stay in list order. + */ + template<typename BINARY_PREDICATE> + void unique( BINARY_PREDICATE p ); + + + /** + * @brief Merge sorted lists. + * @param l Sorted list to merge. + * + * Assumes that both @a l and this list are sorted according to + * operator<(). Merges elements of @a l into this list in + * sorted order, leaving @a l empty when complete. Elements in + * this list precede elements in @a l that are equal. + */ + void merge( DataList& l ); + + + /** + * @brief Merge sorted lists according to comparison function. + * @param l Sorted list to merge. + * @param predicate Comparison function defining a sort order (which + * must be strictly weak ordering). + * + * Assumes that both @a l and this @c DataList are sorted according to + * COMPARE predicate. Merges elements of @a l into this list + * in sorted order, leaving @a l empty when complete. Elements + * in this list precede elements in @a x that are equivalent + * according to StrictWeakOrdering(). + */ + template<typename COMPARE> + void merge( DataList& l, COMPARE predicate ); + + + /** + * @brief Reverse the elements in list. + * + * Reverse the order of elements in the list in linear time. + */ + void reverse(); + + + //@} + //======================================================================== + /** @name Non-standard operations. */ + //@{ + + +public: + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, value_type newElem, reference oldElem); + + + /** + * @fn const PtrList& stdcont() const + * @brief Return the underlying @c std::list of the container. + * @return Reference to the @c std::list actually holding the collection. + * + * Note that @c DataList<T>::stdcont does not necessarily return + * a @c std::list<T*> if @c DataList inheritance is being used. + */ + // This is inherited from the base class. + + + /** + * @fn SG::OwnershipPolicy ownPolicy() const + * @brief Return the ownership policy setting for this container. + */ + // This is inherited from the base class. + + + /** + * @fn void clear (SG::OwnershipPolicy ownPolicy) + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + // This is inherited from the base class. + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + static const DataModel_detail::DVLInfoBase& dvlinfo(); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const; + + + //@} + //======================================================================== + + + // Doxygen trick. We want DataList<T> to show the complete interface, + // including inherited methods. Normally, doxygen would do this. + // But it's not smart to figure out our inheritance relationships. + // We can add a function with `fn', but doxygen won't actually + // generate the documentation unless it also sees the declaration. + // So here are declarations which should be visible to doxygen + // but not to C++. +#ifndef __cplusplus + size_type size() const; + size_type max_size() const; + void resize(size_type sz); + bool empty() const; + void pop_back(); + void pop_front(); + void clear(); + const PtrList& stdcont() const; + SG::OwnershipPolicy ownPolicy() const; + void clear (SG::OwnershipPolicy ownPolicy); +#endif // not __cplusplus + + + /** @name Internal operations. */ + //@{ + + +public: + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c DataList. + */ + void resortAux (iterator beg, iterator end); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataList. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ + void testInsert (const char* op); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ + void testInsertOol (const char* op); + + +protected: + /** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ + void clearMostDerived(); + + + /** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ + virtual void setMostDerived(); + + +private: + friend class DataModel_detail::ElementProxy<DataList>; + friend class ConstDataList<DataList>; + friend void test2_assignelement1<DataList>(); + + + /** + * @brief Find the most-derived @c DataList class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * In order to properly type-check insertions, we need to be able to find + * the most-derived @c DataList class in the inheritance hierarchy. + * That's the purpose of this function. + * Every @c DataList defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataList + * gets run. + */ + virtual const std::type_info& dl_typeid() const; + + + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ + void assignElement (typename BaseContainer::iterator pos, value_type newElem); + + + /** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ + void assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem); + + + /** + * @brief Helper to shorten calls to @c DataList_detail::DVLCast. + * @param p The value to convert. + * @return The value as a @c const @c T*. + * + * The conversion will be done with @c static_cast if possible, + * with @c dynamic_cast otherwise. + */ + static + const T* do_cast (const typename PtrList::value_type p); + //@} + + + /// This flag is true if this DL instance is the most-derived one. + /// We set this to true in the top-level constructor; the constructor + /// then calls clearMostDerived on the base classes. + SG::IsMostDerivedFlag m_isMostDerived; + + + /// The DV/DL info struct for this class. + static DataModel_detail::DVLInfo<DataList<T> > s_info; + + + typedef typename + ROOT_SELECTION_NS::DataList<T, DataList_BASE>::self self; +}; + + +template <class T, class BASE> +const bool DataList<T, BASE>::has_virtual; + + +/** + * @brief Base specialization for @c DataList\<T>. + * + * This is used for the case where @c T does not derive + * from other classes. This is the class which actually holds + * the list of pointers. + * + * See the file comments for full details. + */ +template <class T> +class DataList<T, DataModel_detail::NoBase> +{ +public: + typedef DataModel_detail::NoBase DataList_BASE; + typedef DataModel_detail::NoBase DVL_BASE; + + /// Mark as a sequence, for DataLink / ElementLink. + typedef std::true_type isSequence; + + /// This is the type of the underlying @c std::list + /// (what @c stdcont returns). + typedef std::list<T*> PtrList; + typedef std::list<T*> BaseContainer; + + /// This is true for any @c DataList class if we need to use virtual + /// derivation to get to the base @c DataList class. + /// Since this @e is the base @c DataList class, set this + /// unconditionally to @c false. + static const bool has_virtual = false; + + // Standard types required for the container interface. + typedef T*& reference; + typedef T* const & const_reference; + typedef typename PtrList::size_type size_type; + typedef typename PtrList::difference_type difference_type; + typedef T* value_type; + typedef typename PtrList::allocator_type allocator_type; + typedef T** pointer; + typedef T* const * const_pointer; + + typedef const T* const_value_type; + + /// The @c T value used as the template parameter. + /// Note that this is different from @c value_type (that's @c T*). + typedef T base_value_type; + + /// This type is used to proxy lvalue accesses to @c DataList + /// elements, in order to handle ownership. + typedef DataModel_detail::ElementProxy<DataList> ElementProxy; + + + /// Standard @c const_iterator. + /// Here, we can just use the @c std::list iterator. + typedef typename PtrList::const_iterator const_iterator; + + /// Standard @c iterator. Note that lvalue references here will yield + /// an @c ElementProxy, not a @c reference. + typedef typename DataModel_detail::iterator<DataList> iterator; + + /// Standard @c const_reverse_iterator. + /// Note: we can't just use the underlying PtrList::const_reverse_iterator + /// here; otherwise, const_reverse_iterator won't be convertable to + /// reverse_iterator. + typedef typename std::reverse_iterator<const_iterator> + const_reverse_iterator; + + /// Standard @c reverse_iterator. Note that lvalue references here will + /// yield an @c ElementProxy, not a @c reference. + typedef typename std::reverse_iterator<iterator> + reverse_iterator; + + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataList( SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS ); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard list constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataList( size_type n, /* value_type pElem = 0,*/ + SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS ); + + + /** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ + DataList( const DataList& rhs ); + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + template <class InputIterator> + DataList( InputIterator first, InputIterator last, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS ); + + + /** + * @brief Assignment operator. + * @param rhs The @c DataList from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataList + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + DataList& operator=( const DataList& rhs ); + + + /** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The <code>DataList</code>'s ownership policy determines whether it will + * take ownership of the new elements. + */ + template <class InputIterator> + void assign( InputIterator first, InputIterator last ); + + + /** + * @brief Destructor. + * + * If this container owns its elements, the contained elements will + * be deleted as well. Before doing this, the destructor will scan + * for duplicate pointers (takes @f$ n\log n @f$ time); duplicates are only + * destroyed once. Duplicates should, however, be considered an error; + * don't rely on this behavior. + */ + virtual ~DataList(); + + + //@} + //======================================================================== + /** @name Size and capacity. */ + //@{ + + + /** + * @brief Returns the number of elements in the collection. + */ + size_type size() const; + + + /** + * @brief Returns the @c size() of the largest possible collection. + */ + size_type max_size() const; + + + /** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ + void resize( size_type sz ); + + + /** + * @brief Returns @c true if the collection is empty. + */ + bool empty() const; + + + //@} + //======================================================================== + /** @name Element access. */ + //@{ + + + /** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* front() const; + + + /** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* back() const; + + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy front(); + + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy back(); + + + //@} + //======================================================================== + /** @name Iterator creation. */ + //@{ + + + /** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator begin() const; + + + /** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator end() const; + + + /** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator begin(); + + + /** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator end(); + + + /** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rbegin() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rend() const; + + + /** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rbegin(); + + + /** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rend(); + + //@} + //======================================================================== + /** @name Insertion operations. */ + //@{ + + + /** + * @brief Add an element at the beginning of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void push_front( value_type pElem ); + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void push_back( value_type pElem ); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + iterator insert( iterator position, value_type pElem ); + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + template <class InputIterator> + void insert( iterator position, InputIterator first, InputIterator last ); + + + //@} + //======================================================================== + /** @name Erasure operations. */ + //@{ + + + /** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or <code>end()</code>). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ + iterator erase( iterator position ); + + + /** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or <code>end()</code>). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + iterator erase( iterator first, iterator last ); + + + /** + * @brief Remove the first element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ + void pop_front(); + + + /** + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ + void pop_back(); + + + /** + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear(); + + + //@} + //======================================================================== + /** @name Swap and sort. */ + //@{ + + + /** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataList in the hierarchy. The @a rhs must also be + * referenced using the most-derived <code>DataList</code>. + */ + void swap( DataList& rhs ); + + + /** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ + static void iter_swap (iterator a, iterator b); + + + /** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ + void sort(); + + + /** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + * + */ + template <class COMPARE> + void sort( COMPARE comp ); + + + //@} + //======================================================================== + /** @name List operations. */ + //@{ + + + /** + * @brief Insert contents of another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * + * The elements of @a l are inserted in constant time in front of + * the element referenced by @a position. @a l becomes an empty + * list. + */ + void splice( iterator position, DataList& l ); + + /** + * @brief Insert element from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param i Iterator referencing the element to move. + * + * Removes the element in list @a l referenced by @a i and + * inserts it into the current list before @a position. + */ + void splice( iterator position, DataList& l, iterator i ); + + + /** + * @brief Insert range from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param first Iterator referencing the start of range in @a l. + * @param last Iterator referencing the end of range in @a l. + * + * Removes elements in the range [@a first, @a last ) and inserts them + * before @a position in constant time. + * + * Undefined if @a position is in [@a first, @a last ). + */ + void splice( iterator position, DataList& l, + iterator first, + iterator last ); + + + /** + * @brief Remove all elements equal to value. + * @param value The value to remove. + * + * Removes every element in the list equal to @a value. + * Remaining elements stay in list order. Note that this + * function only erases the elements, and that if the elements + * themselves are pointers, the pointed-to memory is not + * touched in any way. Managing the pointer is the user's + * responsibility. + */ + void remove( const value_type& value ); + + + /** + * @brief Remove all elements satisfying a predicate. + * @param p Unary predicate function or object. + * + * Removes every element in the list for which the predicate + * returns true. Remaining elements stay in list order. Note + * that this function only erases the elements, and that if the + * elements themselves are pointers, the pointed-to memory is + * not touched in any way. Managing the pointer is the user's + * responsibility. + */ + template<typename PREDICATE> + void remove_if( PREDICATE p ); + + /** + * @brief Remove consecutive duplicate elements. + * + * For each consecutive set of elements with the same value, + * remove all but the first one. Remaining elements stay in + * list order. + */ + void unique(); + + /** + * @brief Remove consecutive elements satisfying a predicate. + * @param pred Binary predicate function or object. + * + * For each consecutive set of elements [first,last) that + * satisfy predicate(first,i) where i is an iterator in + * [first,last), remove all but the first one. Remaining + * elements stay in list order. + */ + template<typename BinaryPredicate> + void unique( BinaryPredicate pred ); + + /** + * @brief Merge sorted lists. + * @param l Sorted list to merge. + * + * Assumes that both @a l and this list are sorted according to + * operator<(). Merges elements of @a l into this list in + * sorted order, leaving @a l empty when complete. Elements in + * this list precede elements in @a l that are equal. + */ + void merge( DataList& l ); + + /** + * @brief Merge sorted lists according to comparison function. + * @param l Sorted list to merge. + * @param predicate Comparison function defining a sort order (which + * must be strictly weak ordering). + * + * Assumes that both @a l and this @c DataList are sorted according to + * COMPARE predicate. Merges elements of @a l into this list + * in sorted order, leaving @a l empty when complete. Elements + * in this list precede elements in @a x that are equivalent + * according to StrictWeakOrdering(). + */ + template<typename COMPARE> + void merge( DataList& l, COMPARE predicate ); + + /** + * @brief Reverse the elements in list. + * + * Reverse the order of elements in the list in linear time. + */ + void reverse(); + + + + //@} + //======================================================================== + /** @name Non-standard operations. */ + //@{ + + +public: + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, value_type newElem, reference oldElem); + + + /** + * @brief Return the underlying @c std::list of the container. + * @return Reference to the @c std::list actually holding the collection. + * + * Note that @c DataList<T>::stdcont does not necessarily return + * a @c std::list<T*> if @c DataList inheritance is being used. + */ + const PtrList& stdcont() const; + + + /** + * @brief Return the ownership policy setting for this container. + */ + SG::OwnershipPolicy ownPolicy() const; + + + /** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + static const DataModel_detail::DVLInfoBase& dvlinfo(); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const; + + + //@} + //======================================================================== + /** @name Internal operations. */ + //@{ + + +public: + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c DataList. + */ + void resortAux (iterator beg, iterator end); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataList. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ + void testInsert (const char* op); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ + void testInsertOol (const char* op); + + +private: + friend class DataModel_detail::ElementProxy<DataList>; + friend class ConstDataList<DataList>; + friend void test2_assignelement1<DataList>(); + + + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, value_type newElem); + + + /** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem); + + +protected: + /** + * @brief Helper for @c erase(). Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or <code>end()</code>). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataList classes. It deals with the + * @c std::list iterators directly. + */ + typename PtrList::iterator erase_base( typename PtrList::iterator position ); + + + /** + * @brief Helper for @c erase(). Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or <code> end()</code>). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataList classes. It deals with the + * @c std::list iterators directly. + */ + typename PtrList::iterator + erase_base( typename PtrList::iterator first, + typename PtrList::iterator last ); + + +protected: + /// The ownership policy of this container --- + /// either SG::OWNS_ELEMENTS or SG::VIEW_ELEMENTS. + SG::OwnershipPolicy m_ownPolicy; + + /// This actually holds the elements. + PtrList m_pCont; + + + /** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ + void clearMostDerived(); + + + /** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ + virtual void setMostDerived(); + + +private: + /** + * @brief Find the most-derived @c DataList class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * In order to properly type-check insertions, we need to be able to find + * the most-derived @c DataList class in the inheritance hierarchy. + * That's the purpose of this function. + * Every @c DataList defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataList + * gets run. + */ + virtual const std::type_info& dl_typeid() const; + //@} + + + /// This flag is true if this DL instance is the most-derived one. + /// We set this to true in the top-level constructor; the constructor + /// then calls clearMostDerived on the base classes. + SG::IsMostDerivedFlag m_isMostDerived; + + + /// The DV/DL info struct for this class. + static DataModel_detail::DVLInfo<DataList<T> > s_info; + + + typedef typename + ROOT_SELECTION_NS::DataList<T, DataList_BASE>::self self; +}; + +template <class T> +const bool DataList<T, DataModel_detail::NoBase>::has_virtual; + + +/** + * @brief List equality comparison. + * @param a A @c DataList. + * @param b A @c DataList of the same type as @a a. + * @return True if the size and elements of the lists are equal. + * + * This is an equivalence relation. It is linear in the size of the + * lists. Lists are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ +template <class T> +bool operator==( const DataList<T>& a, const DataList<T>& b ); + + +/// Based on operator== +template <class T> +bool operator!=( const DataList<T>& a, const DataList<T>& b ); + + +/** + * @brief List ordering relation. + * @param a A @c DataList. + * @param b A @c DataList of the same type as @a a. + * @return True if @a a is lexicographically less than @a b. + * + * This is a total ordering relation. It is linear in the size of the + * lists. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ +template <class T> +bool operator< ( const DataList<T>& a, const DataList<T>& b ); + + +/// Based on operator< +template <class T> +bool operator> ( const DataList<T>& a, const DataList<T>& b ); + + +/// Based on operator< +template <class T> +bool operator<=( const DataList<T>& a, const DataList<T>& b ); + + +/// Based on operator< +template <class T> +bool operator>=( const DataList<T>& a, const DataList<T>& b ); + + +/// See <code>DataList<T, BASE>::swap()</code>. +template <class T> +void swap( DataList<T>& a, DataList<T>& b ); + + +/** + * @brief Specialization of @c ClassName for @c DataList. + * + * This overrides the default implementation of @c ClassName + * to hide <code>DataList</code>'s second template parameter. + */ +template <class T> +class ClassName<DataList<T> > +{ +public: + static std::string name(); +}; + + +ENTER_ROOT_SELECTION_NS + +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + +template <class T, class BASE> +class DataList +{ +public: + typedef DataList<T, BASE> self; + + ROOT_SELECTION_NS::TEMPLATE_DEFAULTS< + ROOT_SELECTION_NS::NODEFAULT, + typename ::DataList<T>::DataList_BASE> dum1; + ROOT_SELECTION_NS::NO_SELF_AUTOSELECT dum2; + ROOT_SELECTION_NS::TRANSIENT m_isMostDerived; +}; + +#else + +template< class T, class BASE > +class DataList : KeepFirstTemplateArguments< 1 >, SelectNoInstance { + +public: + /// A helper typedef + typedef DataList< T, BASE > self; + + /// Declare the transient variable(s): + ROOT_SELECTION_NS::MemberAttributes< kTransient > m_isMostDerived; + +}; + +#endif // ROOT_VERSION + +EXIT_ROOT_SELECTION_NS + + +namespace SG { + + +/** + * @brief Metafunction to find the proper @c DataBucket class for @c T. + * + * Specialize this for @c DataVector. + * See SGTools/StorableConversions.h for an explanation. + */ +template <class T, class U> +struct DataBucketTrait<DataList<T>, U> +{ + typedef SG::DVLDataBucket<U> type; + static void init() { DataList<T>::dvlinfo(); } +}; + + +} // namespace SG +#include "AthContainers/DataList.icc" + + +#if 0 +//=================================================================== +// Code to try to make the DATALIST_BASES definitions automatically +// based on SG_BASES. Still have to use one macro, DATALIST_BASES_FROM_SG. +// Currently missing the part that would declare the DataList relations +// to SG. Not sure how useful this will be; don't bother trying to +// finish it now. +#include "boost/mpl/if.hpp" +#include "boost/mpl/and.hpp" +#include "boost/mpl/equal_to.hpp" +#define if_ boost::mpl::if_ +#define and_ boost::mpl::and_ +#define equal_to boost::mpl::equal_to +#define true_ boost::mpl::true_ +#define false_ boost::mpl::false_ +template <class U> struct not_virtual { typedef true_ type; }; +template <class U> struct not_virtual<SG::Virtual<U> > { typedef false_ type; }; +template <class U> struct clean_type { typedef U type; }; +template <> struct clean_type<SG::NoBase> +{ typedef DataModel_detail::NoBase type; }; +template <class U> struct clean_type<SG::Virtual<U> > +{ typedef typename clean_type<U>::type type; }; +template <class T> +struct bases_from_sg +{ + typedef typename + if_<equal_to<typename SG::Bases<T>::Base1, SG::NoBase>, + DataModel_detail::NoBase, + if_<and_<equal_to<typename SG::Bases<T>::Base1, SG::NoBase>, + not_virtual<typename SG::Bases<T>::Base2> >, + typename SG::Bases<T>::Base1, + DataList_detail::VirtBases + <clean_type<typename SG::Bases<T>::Base1>, + clean_type<typename SG::Bases<T>::Base2>, + clean_type<typename SG::Bases<T>::Base3> > + > >::type type; +}; +#undef if_ +#undef and_ +#undef equal_to +#undef true_ +#undef false_ + +#define DATALIST_BASES_FROM_SG(T) \ +template <> struct DataListBase<T> \ +{ typedef bases_from_sg<T>::type Base; }; +//=================================================================== +#endif + + + +#endif // ATHCONTAINERS_DATALIST_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/DataList.icc b/EDM/athena/Control/AthContainers/AthContainers/DataList.icc new file mode 100644 index 00000000..713eff7f --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/DataList.icc @@ -0,0 +1,2549 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file AthContainers/DataList.icc + * @author scott snyder, Paolo Calafiura, Sebastien Binet, etc + * @date February 2006; rewritten from earlier version. + * @brief An STL list of pointers that by default owns its pointed-to + * elements. + * Implementation file. + */ + + +#include "AthContainers/tools/CompareAndPrint.h" +#include "AthContainers/tools/ATHCONTAINERS_ASSERT.h" +#include <limits> + + +//**************************************************************************** +// VirtBases +// + +ENTER_ROOT_SELECTION_NS +namespace DataList_detail { +template <class B1, class B2, class B3> class VirtBases; +} +EXIT_ROOT_SELECTION_NS + + +namespace DataList_detail { + +/* #define DO_REMOVE_DUPLICATES to activate for debugging purposes (Slow) */ +// Note: this name should be distinct from the corresponding one in DataVector, +// even though they're in different namespaces. This due to an apparent +// Koenig lookup bug in gccxml 0.9.0. +template <class L> +void optimizeMeAway_DL(L&, bool){} + +/** + * @brief Remove duplicates from a @c DataList before deleting elements. + * @param b Start of range to scan. + * @param e One past end of range to scan. + * @param quiet If true, complain if duplicates are found. + * @return One past the last unique elements. + * + * The elements within the range are sorted, then duplicate elements + * are moved to the end. If duplicate elements are found and + * @a quiet is @c true, then a complaint will be printed. + */ +template <class LIST> +typename LIST::iterator remove_duplicates(LIST& l, bool quiet=false) +{ +#ifdef DO_REMOVE_DUPLICATES + l.sort(); + return std::unique(l.begin(), l.end(), DataModel_detail::CompareAndPrint(quiet)); +#else + optimizeMeAway_DL(l, quiet); + return l.end(); +#endif +} + + +/** + * @brief VirtBases for one class. + * + * @c DataList\<T> derives from this for the case of + * @c T deriving virtually from a single class. + * It in turn derives from @c B1. + */ +template <class B1> +struct VirtBases<B1, DataModel_detail::NoBase, DataModel_detail::NoBase> + : virtual public DataList<B1> +{ + // Make these types available to the derived @c DataList. + typedef typename DataList<B1>::PtrList PtrList; + typedef typename DataList<B1>::size_type size_type; + typedef typename DataList<B1>::difference_type difference_type; + typedef typename DataList<B1>::allocator_type allocator_type; + +#ifndef __REFLEX__ + // We're using virtual derivation. + static const bool has_virtual = true; +#endif + + +protected: + // Pass this down to base classes. + void clearMostDerived() + { + DataList<B1>::clearMostDerived(); + } + + // We need these here to prevent ambiguities, + // but they shouldn't actually be called. + virtual const std::type_info& dl_typeid() const + { + return typeid(VirtBases); + } + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const + { + return DataList<B1>::dvlinfo(); + } + virtual void setMostDerived() + { + std::abort(); + } + + +private: + typedef typename + ROOT_SELECTION_NS:: + DataList_detail::VirtBases<B1, + DataModel_detail::NoBase, + DataModel_detail::NoBase>::self self; +}; + + +/** + * @brief VirtBases for two classes. + * + * @c DataList\<T> derives from this for the case of + * @c T deriving from two classes. + * It in turn derives from @c B1 and @c B2. + */ +template <class B1, class B2> +struct VirtBases<B1, B2, DataModel_detail::NoBase> + : virtual public DataList<B1>, + virtual public DataList<B2> +{ + // Check to be sure that @c B1 and @c B2 have the same ultimate base type. + typedef ::boost::is_same<typename DataList<B1>::PtrList, + typename DataList<B2>::PtrList> check; + BOOST_STATIC_ASSERT (check::value); + + // Make these types available to the derived @c DataList. + typedef typename DataList<B1>::PtrList PtrList; + typedef typename DataList<B1>::size_type size_type; + typedef typename DataList<B1>::difference_type difference_type; + typedef typename DataList<B1>::allocator_type allocator_type; + +#ifndef __REFLEX__ + // We're using virtual derivation. + static const bool has_virtual = true; +#endif + + +protected: + // Pass this down to base classes. + void clearMostDerived() + { + DataList<B1>::clearMostDerived(); + DataList<B2>::clearMostDerived(); + } + + // We need these here to prevent ambiguities, + // but they shouldn't actually be called. + virtual const std::type_info& dl_typeid() const + { + return typeid(VirtBases); + } + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const + { + return DataList<B1>::dvlinfo(); + } + virtual void setMostDerived() + { + std::abort(); + } + + +private: + typedef typename + ROOT_SELECTION_NS:: + DataList_detail::VirtBases<B1, B2, + DataModel_detail::NoBase>::self self; +}; + + +/** + * @brief VirtBases for three classes. + * + * @c DataList\<T> derives from this for the case of + * @c T deriving from three classes. + * It in turn derives from @c B1, @c B2, and @c B3. + */ +template <class B1, class B2, class B3> +struct VirtBases + : virtual public DataList<B1>, + virtual public DataList<B2>, + virtual public DataList<B3> +{ + // Check to be sure that @c B1, @c B2, and @c B3 have the same + // ultimate base type. + typedef ::boost::is_same<typename DataList<B1>::PtrList, + typename DataList<B2>::PtrList> check1; + typedef ::boost::is_same<typename DataList<B1>::PtrList, + typename DataList<B3>::PtrList> check2; + BOOST_STATIC_ASSERT (check1::value); + BOOST_STATIC_ASSERT (check2::value); + + + // Make these types available to the derived @c DataList. + typedef typename DataList<B1>::PtrList PtrList; + typedef typename DataList<B1>::size_type size_type; + typedef typename DataList<B1>::difference_type difference_type; + typedef typename DataList<B1>::allocator_type allocator_type; + +#ifndef __REFLEX__ + // We're using virtual derivation. + static const bool has_virtual = true; +#endif + + +protected: + // Pass this down to base classes. + void clearMostDerived() + { + DataList<B1>::clearMostDerived(); + DataList<B2>::clearMostDerived(); + DataList<B3>::clearMostDerived(); + } + + // We need these here to prevent ambiguities, + // but they shouldn't actually be called. + virtual const std::type_info& dl_typeid() const + { + return typeid(VirtBases); + } + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const + { + return DataList<B1>::dvlinfo(); + } + virtual void setMostDerived() + { + std::abort(); + } + + +private: + typedef typename + ROOT_SELECTION_NS::DataList_detail::VirtBases<B1, B2, B3>::self + self; +}; + + +} // namespace DataList_detail + + +ENTER_ROOT_SELECTION_NS +namespace DataList_detail { + +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + +template <class B1, class B2, class B3> +class VirtBases +{ +public: + typedef DataList_detail::VirtBases<B1, B2, B3> self; + + ROOT_SELECTION_NS::TEMPLATE_DEFAULTS< + ROOT_SELECTION_NS::NODEFAULT, + ::DataModel_detail::NoBase, + ::DataModel_detail::NoBase> dum1; +}; + +#else + +template< class B1, class B2, class B3 > +class VirtBases : KeepFirstTemplateArguments< 1 > { + +public: + typedef DataList_detail::VirtBases< B1, B2, B3 > self; + +}; + +#endif // ROOT_VERSION + +} +EXIT_ROOT_SELECTION_NS + + +//**************************************************************************** +// Generic (derived) DataList implementation. +// + + +//=== Constructors, destructors, assignment. + + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataList + * class. + */ +template <class T, class BASE> +inline +DataList<T, BASE>::DataList + (SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/) +{ + this->m_ownPolicy = ownPolicy; + this->m_isMostDerived = true; + BASE::clearMostDerived(); +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard list constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataList + * class. + */ +template <class T, class BASE> +inline +DataList<T, BASE>::DataList + (size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/) +{ + this->m_ownPolicy = ownPolicy; + this->m_isMostDerived = true; + BASE::clearMostDerived(); + this->m_pCont.resize (n, (value_type)0); +} + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataList + * class. + */ +template <class T, class BASE> +template <class InputIterator> +inline +DataList<T, BASE>::DataList + (InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/) +{ + // Make sure that the input iterator can actually be converted + // to a T*. Lets us give a compilation error for this: + // DATALIST_BASE(D, B); + // B* bb[] = ... + // DataList<D> d (bb, bb+1); + // which would otherwise compile. + typedef typename std::iterator_traits<InputIterator>::value_type ittype; + BOOST_STATIC_ASSERT ((::boost::is_convertible<ittype, const T*>::value)); + + this->m_ownPolicy = ownPolicy; + this->m_isMostDerived = true; + BASE::clearMostDerived(); + this->m_pCont.assign (first, last); +} + + +/** + * @brief Assignment operator. + * @param rhs The DataList from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the DataList + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T, class BASE> +inline +DataList<T, BASE>& DataList<T, BASE>::operator= (const DataList& rhs) +{ + if (&rhs != this) { + // Ensure we're not being called via a base class. + testInsert ("assignment operator"); + this->clear(); // Release any currently-owned elements. + this->m_ownPolicy = SG::VIEW_ELEMENTS; + this->m_pCont = rhs.m_pCont; + } + return *this; +} + + +/** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataList's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T, class BASE> +template <class InputIterator> +void DataList<T, BASE>::assign(InputIterator first, InputIterator last) +{ + // Ensure we're not being called via a base class. + testInsert ("assign"); + this->clear(); // Release any currently-owned elements. + insert(begin(), first, last); +} + + +//=== Element access. + + +/** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T, class BASE> +inline +const T* DataList<T, BASE>::front() const +{ + return do_cast( this->m_pCont.front() ); +} + + +/** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T, class BASE> +inline +const T* DataList<T, BASE>::back() const +{ + return do_cast( this->m_pCont.back() ); +} + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::ElementProxy +DataList<T, BASE>::front() +{ + return ElementProxy( this->m_pCont.begin(), this ); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::ElementProxy +DataList<T, BASE>::back() +{ + return ElementProxy( --(this->m_pCont.end()), this ); +} + + +//=== Iterator creation. + + +/** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::const_iterator +DataList<T, BASE>::begin() const +{ + return const_iterator( this->m_pCont.begin() ); +} + + +/** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::const_iterator +DataList<T, BASE>::end() const +{ + return const_iterator( this->m_pCont.end() ); +} + + +/** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::iterator +DataList<T, BASE>::begin() +{ + return iterator( this->m_pCont.begin(), this ); +} + + +/** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::iterator +DataList<T, BASE>::end() +{ + return iterator( this->m_pCont.end(), this ); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::const_reverse_iterator +DataList<T, BASE>::rbegin() const +{ + return const_reverse_iterator( end() ); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::const_reverse_iterator +DataList<T, BASE>::rend() const +{ + return const_reverse_iterator( begin() ); +} + + +/** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::reverse_iterator +DataList<T, BASE>::rbegin() +{ + return reverse_iterator( iterator( this->m_pCont.end(), this )); +} + + +/** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataList<T, BASE>::reverse_iterator +DataList<T, BASE>::rend() +{ + return reverse_iterator( iterator( this->m_pCont.begin(), this )); +} + + +//=== Insertion operations. + + +/** + * @brief Add an element to the beginning of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::push_front( value_type pElem ) +{ + // Ensure we're not being called via a base class. + testInsert ("push_front"); + this->m_pCont.push_front( pElem ); +} + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::push_back( value_type pElem ) +{ + // Ensure we're not being called via a base class. + testInsert ("push_back"); + this->m_pCont.push_back( pElem ); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T, class BASE> +typename DataList<T, BASE>::iterator +DataList<T, BASE>::insert( iterator position, value_type pElem ) +{ + // Ensure we're not being called via a base class. + testInsert ("insert"); + return iterator( this->m_pCont.insert( position.base(), pElem ), this ); +} + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T, class BASE> +template <class InputIterator> +void DataList<T, BASE>::insert( iterator position, + InputIterator first, + InputIterator last ) +{ + // Make sure that the input iterator can actually be converted + // to a T*. Lets us give a compilation error for this: + // DATALIST_BASE(D, B); + // B* bb[] = ... + // DataList<D> d; + // d.insert (d.begin(), bb, bb+1); + // which would otherwise compile. + typedef typename std::iterator_traits<InputIterator>::value_type ittype; + BOOST_STATIC_ASSERT ((::boost::is_convertible<ittype, const T*>::value)); + + // Ensure we're not being called via a base class. + testInsert ("insert"); + this->m_pCont.insert(position.base(), first, last); +} + + +//=== Erasure operations. + + +/** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ +template <class T, class BASE> +typename DataList<T, BASE>::iterator +DataList<T, BASE>::erase(iterator position) +{ + return iterator( this->erase_base( position.base() ), this ); +} + + +/** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T, class BASE> +typename DataList<T, BASE>::iterator +DataList<T, BASE>::erase( iterator first, iterator last ) +{ + return iterator( this->erase_base( first.base(), last.base() ), this ); +} + +//=== Swap and sort. + + +/** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataList in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataList. + */ +template <class T, class BASE> +void DataList<T, BASE>::swap(DataList& rhs) +{ + testInsert ("swap"); + rhs.testInsert ("swap"); + std::swap(this->m_ownPolicy, rhs.m_ownPolicy); + this->m_pCont.swap(rhs.m_pCont); +} + + +/** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ +template <class T, class BASE> +void DataList<T, BASE>::iter_swap (iterator a, iterator b) +{ + ATHCONTAINERS_ASSERT (a.ownPolicy() == b.ownPolicy()); + a.testInsert ("iter_swap"); + b.testInsert ("iter_swap"); + std::iter_swap (a.base(), b.base()); +} + + +/** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ +template <class T, class BASE> +void DataList<T, BASE>::sort() +{ + typedef std::less<typename PtrList::value_type> less; + this->m_pCont.sort( DataModel_detail::Compwrapper<DataList, less>( less() ) ); +} + + +/** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + */ +template <class T, class BASE> +template <class COMPARE> +void DataList<T, BASE>::sort(COMPARE comp) +{ + this->m_pCont.sort( DataModel_detail::Compwrapper<DataList, COMPARE>( comp )); +} + +//=== List operations. + +/** + * @brief Insert contents of another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * + * The elements of @a l are inserted in constant time in front of + * the element referenced by @a position. @a l becomes an empty + * list. + */ +template <class T, class BASE> +void DataList<T, BASE>::splice( iterator position, DataList& l ) +{ + if ( this->m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("splice"); + this->m_pCont.splice( position.base(), l.m_pCont ); + } +} + +/** + * @brief Insert element from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param i Iterator referencing the element to move. + * + * Removes the element in list @a l referenced by @a i and + * inserts it into the current list before @a position. + */ +template <class T, class BASE> +void DataList<T, BASE>::splice( iterator position, DataList& l, iterator i ) +{ + //FIXME + if ( this->m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("splice"); + this->m_pCont.splice( position.base(), l.m_pCont, i.base() ); + } +} + + +/** + * @brief Insert range from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param first Iterator referencing the start of range in @a l. + * @param last Iterator referencing the end of range in @a l. + * + * Removes elements in the range [@a first, @a last ) and inserts them + * before @a position in constant time. + * + * Undefined if @a position is in [@a first, @a last ). + */ +template <class T, class BASE> +void DataList<T, BASE>::splice( iterator position, DataList& l, + iterator first, + iterator last ) +{ + //FIXME + if ( this->m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("splice"); + this->m_pCont.splice( position.base(), l.m_pCont, + first.base(), last.base() ); + } +} + +/** + * @brief Remove all elements equal to value. + * @param value The value to remove. + * + * Removes every element in the list equal to @a value. + * Remaining elements stay in list order. + */ +template <class T, class BASE> +void DataList<T, BASE>::remove( const value_type& value ) +{ + //FIXME + iterator i = begin(); + while ( end() != ( i = std::find( i, end(), value ) ) ) { + erase(i++); + } +} + +/** + * @brief Remove all elements satisfying a predicate. + * @param pred Unary predicate function or object. + * + * Removes every element in the list for which the predicate + * returns true. Remaining elements stay in list order. + */ +template <class T, class BASE> +template<typename PREDICATE> +void DataList<T, BASE>::remove_if( PREDICATE pred ) +{ + //FIXME + iterator i = begin(); + while ( end() != ( i = std::find_if( i, end(), pred ) ) ) { + erase(i++); + } +} + +/** + * @brief Remove consecutive duplicate elements. + * + * For each consecutive set of elements with the same value, + * remove all but the first one. Remaining elements stay in + * list order. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::unique() +{ + this->m_pCont.unique(); +} + +/** + * @brief Remove consecutive elements satisfying a predicate. + * @param BinaryPredicate Binary predicate function or object. + * + * For each consecutive set of elements [first,last) that + * satisfy predicate(first,i) where i is an iterator in + * [first,last), remove all but the first one. Remaining + * elements stay in list order. + */ +template <class T, class BASE> +template<typename BinaryPredicate> +inline +void DataList<T, BASE>::unique( BinaryPredicate p ) +{ + this->m_pCont.unique(DataModel_detail::Compwrapper<DataList, + BinaryPredicate>(p)); +} + +/** + * @brief Merge sorted lists. + * @param l Sorted list to merge. + * + * Assumes that both @a l and this list are sorted according to + * @c operator<(). Merges elements of @a l into this list in + * sorted order, leaving @a l empty when complete. Elements in + * this list precede elements in @a l that are equal. + */ +template <class T, class BASE> +void DataList<T, BASE>::merge( DataList& l ) +{ + //FIXME + if ( this->m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("merge"); + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DataList<T, BASE>::PtrList::value_type> less; + this->m_pCont.merge( l.m_pCont, + DataModel_detail::Compwrapper<DataList, less>( less() ) ); + } +} + +/** + * @brief Merge sorted lists according to comparison function. + * @param l Sorted list to merge. + * @param COMPARE Comparison function defining sort order (which + * must be strictly weak ordering). + * + * Assumes that both @a l and this @c DataList are sorted according to + * COMPARE predicate. Merges elements of @a l into this list + * in sorted order, leaving @a l empty when complete. Elements + * in this list precede elements in @a x that are equivalent + * according to StrictWeakOrdering(). + */ +template <class T, class BASE> +template<typename COMPARE> +void DataList<T, BASE>::merge( DataList& l, COMPARE predicate ) +{ + //FIXME + if ( this->m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("merge"); + this->m_pCont.merge( l.m_pCont, + DataModel_detail::Compwrapper<DataList<T, BASE>, + COMPARE>(predicate) ); + } +} + +/** + * @brief Reverse the elements in list. + * + * Reverse the order of elements in the list in linear time. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::reverse() +{ + //FIXME + this->m_pCont.reverse(); +} + + +//=== Non-standard operations. + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T, class BASE> +void DataList<T, BASE>::swapElement(iterator pos, + value_type newElem, + reference oldElem) +{ + testInsert ("swapElement"); + oldElem = + DataModel_detail::DVLCast<DataList>::cast(*pos.base()); + *pos.base() = newElem; +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T, class BASE> +const DataModel_detail::DVLInfoBase& DataList<T, BASE>::dvlinfo() +{ + return s_info; +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T, class BASE> +const DataModel_detail::DVLInfoBase& DataList<T, BASE>::dvlinfo_v() const +{ + return s_info; +} + + +//=== Internal operations. + + +/** + * @brief Find the most-derived @c DataList class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * In order to properly type-check insertions, we need to be able to find + * the most-derived @c DataList class in the inheritance hierarchy. + * That's the purpose of this function. + * Every @c DataList defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataList + * gets run. + */ +template <class T, class BASE> +const std::type_info& DataList<T, BASE>::dl_typeid() const +{ + return typeid(DataList); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c DataList. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::resortAux (iterator /*beg*/, iterator /*end*/) +{ +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataList. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::testInsert (const char* op) +{ + if (ATHCONTAINERS_LIKELY (m_isMostDerived)) + return; + this->testInsertOol (op); +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ +template <class T, class BASE> +void DataList<T, BASE>::testInsertOol (const char* op) +{ + this->setMostDerived(); + if (!m_isMostDerived) + throw SG::ExcInsertionInBaseClass (op, typeid(DataList), dl_typeid()); +} + + +/** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ +template <class T, class BASE> +inline +void DataList<T, BASE>::clearMostDerived() +{ + this->m_isMostDerived = false; + BASE::clearMostDerived(); +} + + +/** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ +template <class T, class BASE> +void DataList<T, BASE>::setMostDerived() +{ + m_isMostDerived = true; + BASE::clearMostDerived(); +} + + +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ +template <class T, class BASE> +void DataList<T, BASE>::assignElement (typename BaseContainer::iterator pos, + value_type newElem) +{ + testInsert ("assignElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + *pos = newElem; +} + + +/** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ +template <class T, class BASE> +void +DataList<T, BASE>::assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem) +{ + testInsert ("assignBaseElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + *pos = newElem; +} + + +/** + * @brief Helper to shorten calls to @c DataModel_detail::DVLCast. + * @param p The value to convert. + * @return The value as a @c const @c T*. + * + * The conversion will be done with @c static_cast if possible, + * with @c dynamic_cast otherwise. + */ +template <class T, class BASE> +inline +const T* +DataList<T, BASE>::do_cast (const typename PtrList::value_type p) +{ + return DataModel_detail::DVLCast<DataList>::cast (p); +} + + +/// The DV/DL info struct for this class. +template <class T, class BASE> +DataModel_detail::DVLInfo<DataList<T> > DataList<T, BASE>::s_info; + + +//**************************************************************************** +// Specialized (base) DataList implementation. +// + + +#ifndef __CINT__ // I don't think CINT will be able to read this. + +// An abbreviation for the DataList specialization to try to make +// things a little more readable. +#define DATALIST DataList<T, DataModel_detail::NoBase> + + +//=== Constructors, destructors, assignment. + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class T> +inline +DATALIST::DataList( SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/ ) + : m_ownPolicy(ownPolicy) +{ + this->m_isMostDerived = true; +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * + * Note that unlike the standard list constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataList will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class T> +inline +DATALIST::DataList( size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/ ) + : m_ownPolicy(ownPolicy), + m_pCont (n, (value_type)0) +{ + this->m_isMostDerived = true; +} + + +/** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ +template <class T> +inline +DATALIST::DataList(const DataList& rhs) + : m_ownPolicy(SG::VIEW_ELEMENTS), + m_pCont(rhs.m_pCont) +{ + // Leave m_isMostDerived false here, because we may be being called + // from a derived class implicit copy constructor. The flags will get + // set correctly when @c testInsert gets called. +} + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * + * By default, a @c DataList will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class T> +template <class InputIterator> +inline +DATALIST::DataList( InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/ ) + : m_ownPolicy(ownPolicy), + m_pCont(first, last) +{ + this->m_isMostDerived = true; +} + + +/** + * @brief Assignment operator. + * @param rhs The DataList from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataList + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T> +inline +DATALIST& DATALIST::operator= (const DataList& rhs) +{ + if (&rhs != this) { + // Ensure we're not being called via a base class. + testInsert ("assignment operator"); + clear(); // Release any currently-owned elements. + m_ownPolicy = SG::VIEW_ELEMENTS; + m_pCont = rhs.m_pCont; + } + return *this; +} + + +/** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataList's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T> +template <class InputIterator> +void DATALIST::assign( InputIterator first, + InputIterator last ) +{ + // Ensure we're not being called via a base class. + testInsert ("assign"); + clear(); // Release any currently-owned elements. + insert(begin(), first, last); +} + + +/** + * @brief Destructor. + * + * If this container owns its elements, the contained elements will + * be deleted as well. Before doing this, the destructor will scan + * for duplicate pointers (takes @f$n \log n@f$ time); duplicates are only + * destroyed once. Duplicates should, however, be considered an error; + * don't rely on this behavior. + */ +template <class T> +DATALIST::~DataList() +{ + if (m_ownPolicy == SG::OWN_ELEMENTS) { + typename PtrList::iterator new_end = + DataList_detail::remove_duplicates(m_pCont); + typename PtrList::iterator iter = m_pCont.begin(); + while (iter != new_end) + delete *(iter++); + } +} + + +//=== Size and capacity. + + +/** + * @brief Returns the number of elements in the collection. + */ +template <class T> +inline +typename DATALIST::size_type DATALIST::size() const +{ + return m_pCont.size(); +} + + +/** + * @brief Returns the @c size() of the largest possible collection. + */ +template <class T> +inline +typename DATALIST::size_type DATALIST::max_size() const +{ + return m_pCont.max_size(); +} + + +/** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ +template <class T> +void DATALIST::resize(size_type sz) +{ + if (sz < size()) { + iterator itr = begin(); + size_type length = 0; + for (; itr != end() && length < sz; ++itr, ++length) { + // we just want to point at the good element: + // the one which will be the new end of the list + ; + } + erase ( itr, end() ); + } else { + m_pCont.insert(m_pCont.end(), sz - m_pCont.size(), 0); + } +} + + +/** + * @brief Returns @c true if the collection is empty. + */ +template <class T> +inline +bool DATALIST::empty() const +{ + return m_pCont.empty(); +} + + +//=== Element access. + + +/** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T> +inline +const T* DATALIST::front() const +{ + return m_pCont.front(); +} + + +/** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T> +inline +const T* DATALIST::back() const +{ + return m_pCont.back(); +} + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T> +inline +typename DATALIST::ElementProxy DATALIST::front () +{ + return ElementProxy( m_pCont.begin(), this ); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T> +inline +typename DATALIST::ElementProxy DATALIST::back () +{ + return ElementProxy( --m_pCont.end(), this ); +} + + +//=== Iterator creation. + + +/** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATALIST::const_iterator DATALIST::begin() const +{ + return m_pCont.begin(); +} + + +/** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATALIST::const_iterator DATALIST::end() const +{ + return m_pCont.end(); +} + + +/** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATALIST::iterator DATALIST::begin() +{ + return iterator( m_pCont.begin(), this ); +} + + +/** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATALIST::iterator DATALIST::end() +{ + return iterator( m_pCont.end(), this ); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATALIST::const_reverse_iterator DATALIST::rbegin() const +{ + return const_reverse_iterator( m_pCont.end() ); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATALIST::const_reverse_iterator DATALIST::rend() const +{ + return const_reverse_iterator( const_iterator( m_pCont.begin() ) ); +} + + +/** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATALIST::reverse_iterator DATALIST::rbegin() +{ + return reverse_iterator( iterator( m_pCont.end(), this )); +} + + +/** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATALIST::reverse_iterator DATALIST::rend() +{ + return reverse_iterator( iterator( m_pCont.begin(), this )); +} + + +//=== Insertion operations. + + +/** + * @brief Add an element to the beginning of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T> +inline +void DATALIST::push_front(value_type pElem) +{ + // Ensure we're not being called via a base class. + testInsert ("push_front"); + m_pCont.push_front(pElem); +} + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T> +inline +void DATALIST::push_back(value_type pElem) +{ + // Ensure we're not being called via a base class. + testInsert ("push_back"); + m_pCont.push_back(pElem); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T> +inline +typename DATALIST::iterator +DATALIST::insert( iterator position, value_type pElem ) +{ + // Ensure we're not being called via a base class. + testInsert ("insert"); + return iterator( m_pCont.insert( position.base(), pElem ), this ); +} + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T> +template <class InputIterator> +inline +void +DATALIST::insert( iterator position, InputIterator first, InputIterator last ) +{ + // Ensure we're not being called via a base class. + testInsert ("insert"); + m_pCont.insert(position.base(), first, last); +} + + +//=== Erasure operations. + + +/** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ +template <class T> +inline +typename DATALIST::iterator DATALIST::erase( iterator position ) +{ + return iterator( this->erase_base( position.base() ), this ); +} + + +/** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +inline +typename DATALIST::iterator DATALIST::erase( iterator first, iterator last ) +{ + return iterator( this->erase_base( first.base(), last.base() ), this ); +} + + +/** + * @brief Remove the first element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ +template <class T> +void DATALIST::pop_front() +{ + if (!m_pCont.empty()) { + if (m_ownPolicy == SG::OWN_ELEMENTS) + delete m_pCont.front(); + m_pCont.pop_front(); + } +} + + +/** + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ +template <class T> +void DATALIST::pop_back() +{ + if (!m_pCont.empty()) { + if (m_ownPolicy == SG::OWN_ELEMENTS) + delete m_pCont.back(); + m_pCont.pop_back(); + } +} + + +/** + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +inline +void DATALIST::clear() +{ + erase( begin(), end() ); +} + + +//=== Swap and sort. + + +/** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataList in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataList. + */ +template <class T> +void DATALIST::swap( DataList& rhs ) +{ + testInsert ("swap"); + rhs.testInsert ("swap"); + std::swap( m_ownPolicy, rhs.m_ownPolicy ); + m_pCont.swap( rhs.m_pCont ); +} + + +/** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ +template <class T> +void DATALIST::iter_swap (iterator a, iterator b) +{ + ATHCONTAINERS_ASSERT (a.ownPolicy() == b.ownPolicy()); + a.testInsert ("iter_swap"); + b.testInsert ("iter_swap"); + std::iter_swap (a.base(), b.base()); +} + + +/** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ +template <class T> +void DATALIST::sort() +{ + m_pCont.sort(); +} + + +/** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + */ +template <class T> +template <class COMPARE> +void DATALIST::sort( COMPARE comp ) +{ + m_pCont.sort( comp ); +} + +//=== List operations. + +/** + * @brief Insert contents of another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * + * The elements of @a l are inserted in constant time in front of + * the element referenced by @a position. @a l becomes an empty + * list. + */ +template <class T> +void DATALIST::splice( iterator position, DataList& l ) +{ + if ( m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("splice"); + this->m_pCont.splice( position.base(), l.m_pCont ); + } +} + +/** + * @brief Insert element from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param i Iterator referencing the element to move. + * + * Removes the element in list @a l referenced by @a i and + * inserts it into the current list before @a position. + */ +template <class T> +void DATALIST::splice( iterator position, DataList& l, iterator i ) +{ + //FIXME + if ( m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("splice"); + this->m_pCont.splice( position.base(), l.m_pCont, i.base() ); + } +} + + +/** + * @brief Insert range from another list. + * @param position Iterator referencing the element to insert before. + * @param l Source list. + * @param first Iterator referencing the start of range in @a l. + * @param last Iterator referencing the end of range in @a l. + * + * Removes elements in the range [@a first, @a last ) and inserts them + * before @a position in constant time. + * + * Undefined if @a position is in [@a first, @a last ). + */ +template <class T> +void DATALIST::splice( iterator position, DataList& l, + iterator first, + iterator last ) +{ + //FIXME + if ( m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("splice"); + this->m_pCont.splice( position.base(), l.m_pCont, + first.base(), last.base() ); + } +} + +/** + * @brief Remove all elements equal to value. + * @param value The value to remove. + * + * Removes every element in the list equal to @a value. + * Remaining elements stay in list order. + */ +template <class T> +void DATALIST::remove( const value_type& value ) +{ + //FIXME + iterator i = begin(); + while ( end() != ( i = std::find( i, end(), value ) ) ) { + erase(i++); + } +} + +/** + * @brief Remove all elements satisfying a predicate. + * @param pred Unary predicate function or object. + * + * Removes every element in the list for which the predicate + * returns true. Remaining elements stay in list order. + */ +template <class T> +template<typename PREDICATE> +void DATALIST::remove_if( PREDICATE pred ) +{ + //FIXME + iterator i = begin(); + while ( end() != ( i = std::find_if( i, end(), pred ) ) ) { + erase(i++); + } +} + +/** + * @brief Remove consecutive duplicate elements. + * + * For each consecutive set of elements with the same value, + * remove all but the first one. Remaining elements stay in + * list order. + */ +template <class T> +inline +void DATALIST::unique() +{ + this->m_pCont.unique(); +} + +/** + * @brief Remove consecutive elements satisfying a predicate. + * @param BinaryPredicate Binary predicate function or object. + * + * For each consecutive set of elements [first,last) that + * satisfy predicate(first,i) where i is an iterator in + * [first,last), remove all but the first one. Remaining + * elements stay in list order. + */ +template <class T> +template<typename BinaryPredicate> +inline +void DATALIST::unique( BinaryPredicate p ) +{ + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + this->m_pCont.unique( DataModel_detail::Compwrapper<DATALIST, + BinaryPredicate>(p) ); +} + +/** + * @brief Merge sorted lists. + * @param l Sorted list to merge. + * + * Assumes that both @a l and this list are sorted according to + * @c operator<(). Merges elements of @a l into this list in + * sorted order, leaving @a l empty when complete. Elements in + * this list precede elements in @a l that are equal. + */ +template <class T> +void DATALIST::merge( DataList& l ) +{ + //FIXME + if ( m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("merge"); + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DATALIST::PtrList::value_type> less; + this->m_pCont.merge( l.m_pCont, + DataModel_detail::Compwrapper<DATALIST, + less>( less() ) ); + } +} + +/** + * @brief Merge sorted lists according to comparison function. + * @param l Sorted list to merge. + * @param COMPARE Comparison function defining sort order (which + * must be strictly weak ordering). + * + * Assumes that both @a l and this @c DataList are sorted according to + * COMPARE predicate. Merges elements of @a l into this list + * in sorted order, leaving @a l empty when complete. Elements + * in this list precede elements in @a x that are equivalent + * according to StrictWeakOrdering(). + */ +template <class T> +template<typename COMPARE> +void DATALIST::merge( DataList& l, COMPARE predicate ) +{ + //FIXME + if ( m_ownPolicy == l.m_ownPolicy ) { + // Ensure we're not being called via a base class. + testInsert ("merge"); + this->m_pCont.merge( l.m_pCont, + DataModel_detail::Compwrapper<DATALIST, + COMPARE>(predicate) ); + } +} + +/** + * @brief Reverse the elements in list. + * + * Reverse the order of elements in the list in linear time. + */ +template <class T> +inline +void DATALIST::reverse() +{ + //FIXME + this->m_pCont.reverse(); +} + + +//=== Non-standard operations. + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ +template <class T> +void DATALIST::swapElement(iterator pos, + value_type newElem, + reference oldElem) +{ + testInsert ("swapElement"); + oldElem = *pos.base(); + *pos.base() = newElem; +} + + +/** + * @brief Return the underlying @c std::list of the container. + * @return Reference to the @c std::list actually holding the collection. + * + * Note that @c DataList<T>::stdcont does not necessarily return + * a @c std::list<T*> if @c DataList inheritance is being used. + */ +template <class T> +inline +const typename DATALIST::PtrList& DATALIST::stdcont() const +{ + return m_pCont; +} + + +/** + * @brief Return the ownership policy setting for this container. + */ +template <class T> +inline +SG::OwnershipPolicy DATALIST::ownPolicy() const +{ + return m_ownPolicy; +} + + +/** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +void DATALIST::clear (SG::OwnershipPolicy ownPolicy) +{ + clear(); + m_ownPolicy = ownPolicy; +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T> +const DataModel_detail::DVLInfoBase& DATALIST::dvlinfo() +{ + return s_info; +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T> +const DataModel_detail::DVLInfoBase& DATALIST::dvlinfo_v() const +{ + return s_info; +} + + +//=== Internal operations. + + +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ +template <class T> +void DATALIST::assignElement (typename BaseContainer::iterator pos, + value_type newElem) +{ + testInsert ("assignElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + *pos = newElem; +} + + +/** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + */ +template <class T> +void DATALIST::assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem) +{ + testInsert ("assignBaseElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + *pos = newElem; +} + + +/** + * @brief Helper for @c erase(). Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataList classes. It deals with the + * @c std::list iterators directly. + */ +template <class T> +typename DATALIST::PtrList::iterator +DATALIST::erase_base( typename PtrList::iterator position ) +{ + if (m_ownPolicy == SG::OWN_ELEMENTS && position != m_pCont.end()) + delete *position; + return m_pCont.erase( position ); +} + + +/** + * @brief Helper for @c erase(). Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataList classes. It deals with the + * @c std::list iterators directly. + */ +template <class T> +typename DATALIST::PtrList::iterator +DATALIST::erase_base( typename PtrList::iterator first, + typename PtrList::iterator last ) +{ + if (first == last) return first; + if (m_ownPolicy == SG::OWN_ELEMENTS) { + typename PtrList::iterator iter = first; + while (iter != last) delete *(iter++); + } + return m_pCont.erase(first, last); +} + + +/** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ +template <class T> +inline +void DATALIST::clearMostDerived() +{ + this->m_isMostDerived = false; +} + + +/** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ +template <class T> +void DATALIST::setMostDerived() +{ + m_isMostDerived = true; +} + + +/** + * @brief Find the most-derived @c DataList class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * In order to properly type-check insertions, we need to be able to find + * the most-derived @c DataList class in the inheritance hierarchy. + * That's the purpose of this function. + * Every @c DataList defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataList + * gets run. + */ +template <class T> +const std::type_info& +DATALIST::dl_typeid() const +{ + return typeid( DataList ); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * This is a no-op for @c DataList. + */ +template <class T> +inline +void DATALIST::resortAux (iterator /*beg*/, iterator /*end*/) +{ +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataList. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ +template <class T> +inline +void DATALIST::testInsert (const char* op) +{ + if (ATHCONTAINERS_LIKELY (m_isMostDerived)) + return; + this->testInsertOol (op); +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ +template <class T> +void DATALIST::testInsertOol (const char* op) +{ + this->setMostDerived(); + if (!m_isMostDerived) + throw SG::ExcInsertionInBaseClass (op, typeid(DataList), dl_typeid()); +} + + +/// The DV/DL info struct for this class. +template <class T> +DataModel_detail::DVLInfo<DataList<T> > DATALIST::s_info; + + +#undef DATALIST +#endif // not __CINT__ + + +//**************************************************************************** +// Free function implementations. +// + + +/** + * @brief List equality comparison. + * @param a A @c DataList. + * @param b A @c DataList of the same type as @a x. + * @return True iff the size and elements of the lists are equal. + * + * This is an equivalence relation. It is linear in the size of the + * lists. Lists are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ +template <class T> +bool operator== (const DataList<T>& a, const DataList<T>& b) +{ + return a.stdcont() == b.stdcont(); +} + + +/// Based on operator== +template <class T> +bool operator!= (const DataList<T>& a, const DataList<T>& b) +{ + return a.stdcont() != b.stdcont(); +} + + +/** + * @brief List ordering relation. + * @param a A @c DataList. + * @param b A @c DataList of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * lists. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ +template <class T> +bool operator< (const DataList<T>& a, const DataList<T>& b) +{ + return a.stdcont() < b.stdcont(); +} + + +/// Based on operator< +template <class T> +bool operator> (const DataList<T>& a, const DataList<T>& b) +{ + return a.stdcont() > b.stdcont(); +} + + +/// Based on operator< +template <class T> +bool operator<= (const DataList<T>& a, const DataList<T>& b) +{ + return a.stdcont() <= b.stdcont(); +} + + +/// Based on operator< +template <class T> +bool operator>= (const DataList<T>& a, const DataList<T>& b) +{ + return a.stdcont() >= b.stdcont(); +} + + +/// See @c DataList<T, BASE>::swap(). +template <class T> +void swap( DataList<T>& a, DataList<T>& b ) +{ + a.swap (b); +} + + +/** + * @brief Specialization of @c ClassName for @c DataList. + * + * This overrides the default implementation of @c ClassName + * to hide @c DataList's second template parameter. + */ +template <class T> +std::string ClassName<DataList<T> >::name() +{ + std::string out = "DataList<"; + out += ClassName<T>::name(); + if (out[out.size()-1] == '>') + out += ' '; + out += '>'; + return out; +} + + +// Set up initialization of element type BaseInfo +namespace DataList_detail { +#define DVLTYPE DataList +#include "AthContainers/tools/DVLEltBaseInfo.icc" +#undef DVLTYPE +} // namespace DataList_detail + + +// We need to specialize the function that DVLInfo uses to create the container +// for DataVector. +/** + * @brief Construct a new container. + * @param nreserve Number of elements for which to reserve space. + * (Ignored if not appropriate.) + * @param cont[out] Pointer to the constructed container. + * (Returned via an argument to allow for template + * argument deduction.) + * + * Specialization for DataList. + */ +template <class T> +void dvl_makecontainer (size_t /*nreserve*/, DataList<T>*& cont) +{ + cont = new DataList<T> (SG::VIEW_ELEMENTS); +} diff --git a/EDM/athena/Control/AthContainers/AthContainers/DataVector.h b/EDM/athena/Control/AthContainers/AthContainers/DataVector.h new file mode 100644 index 00000000..a8a242ef --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/DataVector.h @@ -0,0 +1,3402 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataVector.h 800990 2017-03-19 23:15:21Z ssnyder $ + +/** + * @file AthContainers/DataVector.h + * @author scott snyder, Paolo Calafiura, etc + * @date May 2005; rewritten from earlier version. + * @brief An STL vector of pointers that by default owns its pointed-to + * elements. + * + * For further information, see + * <https://twiki.cern.ch/twiki/bin/viewauth/AtlasComputing/DataVector> + * + * Introduction + * ============ + * + * A @c DataVector<T> acts like a @c std::vector<T*>, except that it can + * optionally manage the memory that it contains. The constructors take + * an (optional) extra argument, which can be either @c SG::OWN_ELEMENTS + * or @c SG::VIEW_ELEMENTS (defaulting to @c SG::OWN_ELEMENTS, except for a + * copy constructor). This tells whether the @c DataVector owns + * its contained elements or not. + * + * Ownership issues + * ================ + * + * If a @c DataVector owns its elements, then they are deleted + * when the container itself is. Further, they are deleted by actions + * which erase elements from the container (i.e, @c erase(), @c pop_back()). + * A replacement (such as <code> v[0] = new T </code>) will result in the + * old element being deleted and the container taking ownership + * of the new element. It is an error to assign directly between + * two owning containers (<code>v1[0] = v2[0]</code>). + * To remove an element from a container and acquire ownership, + * use @c swapElement. + * + * Beware of ownership issues when you modify a @c DataVector. + * Obviously you should not delete explicitly a @c DataVector element. + * A @c DataVector should never have two elements pointing to the same object. + * This may seem obvious but certain std algorithms (e.g. @c remove_if) may + * leave a @c DataVector with two copies of the same element in the + * "left-over" range. To avoid a crash when clearing the vector (e.g. in the + * destructor we have introduced a @f$n\log n@f$ helper function that searches + * and removes duplicates in the @c DataVector. This is used by the destructor + * by @c clear() and by <code>erase(first, last)</code>. As this may change + * in the future to improve performance, do not rely on this functionality + * and do avoid introducing duplicated elements in a @c DataVector. + * + * All these cautions do not apply when a @c DataVector it is created with + * the flag @c SG::VIEW_ELEMENTS (see <code>enum OwnershipPolicy</code>) + * and hence does not own its elements. This is typically used + * to have @c DataVector elements allocated by @c DataPool. + * Otherwise consider the cleaner alternative of using a @c vector<T*>. + * + * The interface for @c DataVector should be mostly compatible with that + * of @c std::vector. There are a few differences which should not make + * much difference in practice. For example, methods which would + * return a reference return a proxy object instead. Also @c value_type + * is used instead of @c const_reference; this is justified by the fact + * that the elements are always pointers. + * + * Note that algorithms which modify their range may not work + * correctly if the container owns its contents. Specializations + * that work properly for @c DataVector are available for some algorithms. + * These include: + * - @c std::sort + * - @c std::stable_sort + * - @c std::partial_sort + * - @c std::remove + * - @c std::remove_if + * - @c std::unique + * - @c std::reverse + * - @c std::rotate + * - @c std::random_shuffle + * - @c std::partition + * - @c std::stable_partition + * + * Alternately, for @c sort(), the @c sort() methods defined in @c DataVector + * may be used. Or do the sorting in a view @c DataVector + * or a plain @c std::vector. + * + * There are a few other additions to the standard @c std::vector interface. + * - The method @c stdcont may be used to get access to the underlying + * @c std::vector representation. + * - The type @c PtrVector is the type of the underlying @c std::vector. + * @c BaseContainer is a synonym for this. + * - The method @c swapElement may be used to get ownership of an element + * back from a @c DataVector. + * - The method @c sort provides an interface + * to @c std::sort that works even if the container owns its contents. + * - The method @c ownPolicy returns the ownership policy of the container. + * - An additional overload of @c clear() is provided that takes as + * an argument a new ownership policy for the container. This is + * the only way to change the ownership policy, save for swapping + * or moving the container. + * + * Note that since @c DataVector\<T> has an element type of @c T*, + * it is not possible to directly insert a <code>const T*</code>. + * If you want to do that, see @c ConstDataVector. (In some cases, + * such as if the destination container is not being recorded in StoreGate, + * it may be more appropriate to simply use a + * <code>std::vector<const T*></code>.) Don't just use a @c const_cast! + * + * Inheritance + * =========== + * + * @c DataVector's may inherit from one another. + * If you have class @c D which derives from class @c B, you can set things + * up so that @c DataVector\<D> derives from @c DataVector\<B>. This allows + * you do to the same sort of conversions on the @c DataVector's as on the + * element pointers themselves. The key to doing this is to add the + * declaration + * + *@code + * DATAVECTOR_BASE (D, B); + @endcode + * + * before using @c DataVector\<D>. A few caveats about doing this. + * The pointers are actually stored in the base @c DataVector instance, + * and the type that @c stdcont returns will reflect this. + * For example, in the example given above, @c DataVector<D>::stdcont() + * will return a reference to std::vector\<B*>. Second, in order + * to preserve the invariant + * that a @c DataVector\<D> contains only elements that actually derive + * from @c D, while at the same time not requiring that the contained + * objects be polymorphic, there is a restriction that you cannot + * insert into a @c DataVector if you're not referring to it as the + * most derived type (even if such an insertion would not actually + * break the invariant). This is implemented as a runtime check. + * + * Example: + * + *@code + * DataVector<D> vd; + * vd.push_back (new D); // This is ok. + * vd.push_back (new B); // This will give a compilation error + * (it would break the invariant). + * DataVector<B>& vb = vd; + * vb.push_back (new B); // This will give a run-time error + * (it breaks the invariant). + * vb.push_back (new D); // This will also give a run-time error. + * (It's actually ok, but there's no good way + * to distinguish it from the previous case.) + @endcode + * + * Note also this (related to a common atlas idiom). If we have the above, + * and also: + * + *@code + * class B_Vector : public DataVector<B> { ... }; + * class D_Vector : public DataVector<D> { ... }; + @endcode + * + * Then a @c D_Vector will be convertible to a DataVector\<B>, but _not_ + * to a @c B_Vector. + * + * Multiple and virtual inheritance are also supported. In this case, + * use <code>DATAVECTOR_VIRTBASES</code><em>n</em> (where @e n is 1, 2, or 3) + * instead of @c DATAVECTOR_BASE. Example: Given: + * + *@code + * class M { ... }; + * class N : virtual public M { ... }; + * class O : virtual public M { ... }; + * class P : virtual public N, virtual public O { ... }; + @endcode + * + * declare this with + * + *@code + * DATAVECTOR_VIRTBASES1(N, M); + * DATAVECTOR_VIRTBASES1(O, M); + * DATAVECTOR_VIRTBASES2(P, N, O); + @endcode + * + * There is a restriction that there must be a unique base class that + * does not derive from anything else. For example, the diamond configuration + * above is ok, but this would not be: + * + *@code + * class L { ... }; + * class M { ... }; + * class N : virtual public M, virtual public L { ... }; + * class O : virtual public M { ... }; + * class P : virtual public N, virtual public O { ... }; + * + * DATAVECTOR_VIRTBASES2(N, M, L); + * DATAVECTOR_VIRTBASES1(O, M); + * DATAVECTOR_VIRTBASES2(P, N, O); + @endcode + * + * Note, however, that you don't have to tell @c DataVector about the complete + * hierarchy; leaving the @c L out of @c DATAVECTOR_VIRTBASES would work + * (you just wouldn't be able to convert to @c DataVector\<L>). + * + * If you use @c DATAVECTOR_VIRTBASES, there is an additional time penalty + * to retrieve elements from the collection. This does not apply + * for @c DATAVECTOR_BASES. + * + * All applicable @c DATAVECTOR_* macros must be visible at the point at which + * a @c DataVector is instantiated. A confusing compilation error is + * likely to result otherwise. Note that this means that if you have + * the @c DATAVECTOR_* macros within a container header file, then + * the header for the derived container must include the header + * for the base container. Be alert to this when converting existing + * code to use the inheritance scheme. For example, if class D2 derives + * from D which derives from B: + * + * BVec.h: + *@code + * #include "B.h" + * #include "DataVector.h" + * typedef DataVector<B> BVec; + @endcode + * + * DVec.h: + *@code + * #include "D.h" + * #include "DataVector.h" + * DATAVECTOR_BASE(D,B); + * typedef DataVector<D> DVec; + @endcode + * + * D2Vec.h: + *@code + * #include "D2.h" + * #include "DataVector.h" + * #include "DVec.h" // This is required + * DATAVECTOR_BASE(D2,D); + * typedef DataVector<D2> DVec; + @endcode + * + * Using @c DATAVECTOR_BASE will also set up the corresponding @c SG::BaseInfo + * definitions, both for the vectors themselves and for the contained objects. + * + * Auxiliary data + * ============== + * + * A @c DataVector may also have `auxiliary data' associated with it. + * This is a set of name/value pairs that can be attached to each element + * of the vector. These data are stored in vectors that exist parallel + * to the @c DataVector; the exact way in which this managed is hidden + * behind an abstract interface. + * + * We'll start with an example, and then go into more detail. + * + *@code + * + * class MyClass + * : public SG::AuxElement // Derive from AuxElement to allow for aux data + * { + * public: + * // A getter for an aux data item. + * float foo() const + * { const static ConstAccessor<float> acc ("foo"); return acc(*this); } + * + * // A setter for an aux data item. + * void foo(float x) + * { const static Accessor<float> acc ("foo"); acc(*this) = x; } + * }; + * + * ... + * + * // Create the vector and associate a store. + * DataVector<MyClass>* v = new DataVector<MyClass>; + * SG::AuxStoreInternal* store = new SG::AuxStoreInternal; + * v->setStore (store); + * + * // Add an item to the vector and set aux data on it. + * v->push_back (new MyClass); + * v[0]->foo() = 3; + * + * // Add a user-defined aux data item. + * MyClass::Accessor<int> x ("x"); + * x(*v[0]) = 10; + * + * // Add a standalone store to an object. + * MyClass* c = new MyClass; + * c->makePrivateStore(); + * c->foo() = 4; + * c->push_back (c); // Aux data will be transferred to the container. + @endcode + * + * In order to be able store auxiliary data in a container three things + * must hold. First, the container's payload type must derive from + * @c SG::AuxElement. Second, the container must have index tracking + * enabled. Third, the container must have an associated auxiliary + * data store. More about these below. + * + * SG::AuxElement + * -------------- + * + * A type which may have associated auxiliary data must derive from the base + * class @c SG::AuxElement. This does a several things. + * + * First, in order to be able to find auxiliary data from a pointer to + * a container element, the element must be able to know both the container + * that it's a member of and its index within that container. + * @c SG::AuxElement makes this information available with the @c container() + * and @c index() methods. This information is maintained as long as the + * container has index tracking enabled (see below). + * + * Second, it provides an interface for getting/setting auxiliary data. + * The recommended way of doing this is through the nested @c Accessor + * and @c ConstAccessor classes; these allows caching the translation + * from attribute names to the internal representation. The difference + * between these two is that @c ConstAccessor allows only const access + * to the element, while @c Accessor, which derives from it, + * allows non-const access as well. Create an @c Accessor + * or @c ConstAccessor object with the data type (which can be anything + * that can be used within a @c std::vector) and a name. For @c Accessor, + * the resulting object can then be used both as an rvalue and a lvalue; + * for @c ConstAccessor, it can be used only as an rvalue. + * + *@code + * MyClass* c = ...; + * MyClass::Accessor<double> y ("y"); + * y(*c) = 4; // assign attribute. + * return y(*c); // read attribute. + @endcode + * + * A given name must always be used with the same type, otherwise an exception + * will be thrown. In the case that you want to use the same name for + * different types in different classes, the name may be qualified with + * an optional class name: + * + *@code + * MyClass::ConstAccessor<double> y ("y", "MyClass"); + @endcode + * + * If you have some auxiliary data items that are to be regarded as members + * of a class, it is recommended to define a setter and getter as in the + * example above. + * + * If you need to operate on a particular auxiliary data item for all elements + * in a container, it will be more efficient to access the auxiliary data + * directly by index, rather than through the elements. This can be done like: + * + *@code + * DataVector<MyClass>* v = ...; + * MyClass::ConstAccesor<float> x ("x"); + * size_t sz = v->size(); + * for (size_t i = 0; i < sz; i++) + * do_something (x(*v, i)); + @endcode + * + * @c Accessor and @c ConstAccessor also have @c getDataArray methods + * to directly return a pointer to the start of the auxiliary data array. + * + * It is also possible to use the @c auxdata method to access auxiliary + * data directly. However, it is not recommended to do this inside a loop + * or anywhere where performance is important. + * + *@code + * c->auxdata<int> ("aux") = 5; // set + * return c->auxdata<int> ("aux"); // retrieve + @endcode + * + * Decorations + * ----------- + * + * In addition, sometimes one wants to add additional auxiliary data to + * an existing, const container; this is called `decorating' it. + * For example, you might want to retrieve a const container from StoreGate, + * run some algorithm on it, and attach additional data to the object + * that can be accessed by downstream algorithms or written to a file. + * To support this, there is a @c Decorator object analogous to @c Accessor + * and @c ConstAccessor. The difference is that @c Decorator can operate + * on a const object and return a non-const reference. + * + * To prevent modifying existing data, the contents of a container + * may be locked with the @c lock() call; this happens automatically + * when the container is made const with @c StoreGateSvc::setConst. + * Once a container is locked, @c Decorator will only succeed + * if either the variable does not yet exist (in which case it is + * created and marked as a decoration) or it is marked as a decoration. + * + * Calling @c clearDecorations will erase all variables marked as decorations, + * restoring the state back to where it was when @c lock was called. + * + * An @c auxdecor method is also available, analogous to @x auxdata. + * + * + * Index tracking + * -------------- + * + * Recall that a @c DataVector either owns its elements or not. + * By default, a @c DataVector that owns its elements will update + * the container and index fields of the elements that it contains, + * while a view @c DataVector will not. + * + * This rule does not always suffice, though. In particular, a @c DataVector + * that gets filled with elements from a @c DataPool does not own its + * elements but should track indices. For this reason, one can specify + * an index tracking policy separate from the ownership policy. Where + * @c DataVector takes an ownership policy, it can also take as the + * next argument an index tracking policy. This policy defaults to + * @c SG::DEFAULT_TRACK_INDICES, which means to set the indexing + * policy based on the ownership policy. But it can also be set to + * @c SG::ALWAYS_TRACK_INDICES or @c SG::NEVER_TRACK_INDICES + * to override this. + * + * The current state of index tracking for a @c DataVector is returned + * by the @c trackIndices method. Like the ownership policy, it may + * be changed with the @c clear method. + * + * Auxiliary store + * --------------- + * + * @c DataVector does not itself manage the storage for auxiliary data. + * Instead, this is done by a separate _auxiliary store_ object. + * This store object implements either the interface @c SG::IConstAuxStore + * or @c SG::IAuxStore (which derives from it). The first of these + * provides operations needed to read data from the store, while the + * second adds operations needed to add to and modify the data in the store. + * + * When you are create a @c DataVector object that is to have + * auxiliary data, you will also need to create the store object. + * A generic store object, which manages dynamic auxiliary data, + * is available, @c SG::AuxStoreInternal. There may also be specialized + * store implementations for particular data classes. Store implementations + * also exist that are specialized for use in root; in that case, the data + * are managed as part of a root tree, and the store object manages + * access to it. + * + *@code + * DataVector<MyClass>* v = new DataVector<MyClass>; + * CHECK( evtStore->record (v, "mykey") ); + * SG::AuxStoreInternal* store = new SG::AuxStoreInternal; + * CHECK( evtStore->record (store, "mykeyAux.") ); + * v->setStore (store); + @endcode + * + * You can only set a store if the container has index tracking enabled; + * otherwise, an exception will be thrown. + * + * You should not have to explicitly deal with the auxiliary store + * for objects that are read from a file. The I/O system is responsible + * for getting the store association correct in that case. + * + * Standalone objects + * ------------------ + * + * Normally, an element can only have associated auxiliary data if it is + * a member of a container; otherwise, there is no store in which to store + * the auxiliary data. However, it is possible to request that a store + * be created for an individual element not part of a container by calling + * the method @c makePrivateStore. You can then add auxiliary data to the + * object: + * + *@code + * MyClass* c = new MyClass; + * c->makePrivateStore(); + * MyClass::Accessor<int> x ("x"); + * x(*c) = 5; + @endcode + * + * If the element is then added to a container, the auxiliary data will be + * copied to the container's store, and the private store the was associated + * with the element will be released. The fact that there was a private store + * is remembered, however; if the element is later removed from the container + * (in a way that doesn't delete the element), the private store will be remade + * and the auxiliary data copied back from the container to the private store. + * + * @c makePrivateStore can also take an argument. If provided, auxiliary data + * will be copied from it. This can be used to properly implement copy + * constructors: + * + *@code + * class MyStandaloneClass + * : public SG::AuxElement + * { + * public: + * MyStandaloneClass() { this->makePrivateStore(); } + * + * MyStandaloneClass (const MyStandaloneClass& other) + * SG::AuxElement (other) + * { + * this->makePrivateStore (other); + * } + @endcode + * + * As a shorthand, one can use the wrapper class @c SG::AuxElementComplete. + * This will add constructors that automatically make a private store: + * + *@code + * typedef SG::AuxElementComplete<MyClass> MyStandaloneClass; + @endcode + * + * A standalone object also has @c setStore methods that can be used + * to associate an external store with a since object, in the same manner + * as for containers. + */ + + +#ifndef ATHCONTAINERS_DATAVECTOR_H +#define ATHCONTAINERS_DATAVECTOR_H + + +// For feature tests. +#define HAVE_CONSTDATAVECTOR + + +#include "AthContainers/exceptions.h" +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/IndexTrackingPolicy.h" +#include "AthContainers/AuxVectorBase.h" +#include "AthContainers/tools/DVLNoBase.h" +#include "AthContainers/tools/DVLInfo.h" +#include "AthContainers/tools/DVLCast.h" +#include "AthContainers/tools/DVLIterator.h" +#include "AthContainers/tools/DVL_iter_swap.h" +#include "AthContainers/tools/DVL_algorithms.h" +#include "AthContainers/tools/ElementProxy.h" +#include "AthContainers/tools/IsMostDerivedFlag.h" +#include "AthLinks/tools/selection_ns.h" +#include <boost/static_assert.hpp> +#include <boost/iterator/iterator_adaptor.hpp> +#include <type_traits> +#include <vector> +#include <typeinfo> +#include <functional> +#include <iostream> +#include <algorithm> +#include <stdexcept> +#include <iterator> +#include <initializer_list> + + + +#ifdef XAOD_STANDALONE +# ifndef SG_BASE +# define SG_BASE(A, B) class ATHCONTAINERS_DUMMY +# endif // not SG_BASE +# ifndef SG_BASES1 +# define SG_BASES1(A, B) class ATHCONTAINERS_DUMMY +# endif // not SG_BASES1 +# ifndef SG_BASES2 +# define SG_BASES2(A, B, C) class ATHCONTAINERS_DUMMY +# endif // not SG_BASES2 +# ifndef SG_BASES3 +# define SG_BASES3(A, B, C, D) class ATHCONTAINERS_DUMMY +# endif // not SG_BASES3 +# ifndef SG_VIRTUAL +# define SG_VIRTUAL(X) X +# endif // not SG_VIRTUAL +#else +# include "SGTools/BaseInfo.h" +#endif + + +// Forward declarations. +ENTER_ROOT_SELECTION_NS +template <class T, class BASE> class DataVector; +EXIT_ROOT_SELECTION_NS + + +namespace DataVector_detail { + + +// These are the intermediate classes from which @c DataVector derives +// in the case of multiple or virtual derivation. The actual +// definitions are in the @c icc file. They have the following +// properties: +// - They derive from those of @c B1, @c B2, and @c B3 that are not +// @c NoBase. +// - They perform (static) checking to ensure that there's a unique +// base class in the hierarchy. +// - They make the following types available from the base classes: +// - @c PtrVector +// - @c BaseContainer +// - @c size_type +// - @c difference_type +// - @c allocator_type +// - @c has_virtual is defined as @c true. +// - An override of @c dvlinfo_v is defined, to prevent ambiguities. +template <class B1, + class B2=DataModel_detail::NoBase, + class B3=DataModel_detail::NoBase> struct VirtBases; + + +} // namespace DataVector_detail + + + +/** + * @brief Derivation information for @c DataVector. + * + * Specializations of this class represent the derivation information + * that @c DataVector needs. They have the property that + * <code>DataVectorBase<T>::Base</code> is either @c NoBase or + * it is the class from which @c DataVector\<T> should derive. + */ +template <class T> +struct DataVectorBase +{ + typedef DataModel_detail::NoBase Base; +}; + + +/** + * @brief Declare base class info to @c DataVector. + * Single, non-virtual derivation. + * + * <code>DATAVECTOR_BASE(D, B)</code> says that @c D derives + * non-virtually from @c B. + * + * This macro creates an appropriate specialization of @c DataVectorBase. + */ +#define DATAVECTOR_BASE(T, BASE) \ +DATAVECTOR_BASE_FWD(T, BASE); \ +template struct DataVector_detail::DVLEltBaseInit<T> + + +/** + * @brief Version of @c DATAVECTOR_BASE that can be used + * in forward declarations. + */ +#define DATAVECTOR_BASE_FWD(T, BASE) \ +template <> struct DataVectorBase<T> \ +{ typedef DataVector<BASE> Base; }; \ +SG_BASE(DataVector<T>, DataVector<BASE>) + + +/** + * @brief Declare base class info to @c DataVector. + * Single, virtual derivation. + * + * <code>DATAVECTOR_VIRTBASES1(D, B1)</code> says that @c D derives + * virtually from @c B1. + * + * This macro creates an appropriate specialization of @c DataVectorBase. + */ +#define DATAVECTOR_VIRTBASES1(T, B1) \ +DATAVECTOR_VIRTBASES1_FWD(T, B1); \ +template struct DataVector_detail::DVLEltBaseInit<T> + + + +/** + * @brief Version of @c DATAVECTOR_VIRTBASES1 that can be used + * in forward declarations. + */ +#define DATAVECTOR_VIRTBASES1_FWD(T, B1) \ +template <> struct DataVectorBase<T> \ +{ typedef DataVector_detail::VirtBases<B1> Base; }; \ +SG_BASES1(DataVector<T>, SG_VIRTUAL(DataVector<B1>)) + + + +/** + * @brief Declare base class info to @c DataVector. + * Multiple derivation. + * + * <code>DATAVECTOR_VIRTBASES2(D, B1, B2)</code> says that @c D derives + * from both @c B1 and @c B2. + * + * This macro creates an appropriate specialization of @c DataVectorBase. + */ +#define DATAVECTOR_VIRTBASES2(T, B1, B2) \ +DATAVECTOR_VIRTBASES2_FWD(T, B1, B2); \ +template struct DataVector_detail::DVLEltBaseInit<T> + + +/** + * @brief Version of @c DATAVECTOR_VIRTBASES2 that can be used + * in forward declarations. + */ +#define DATAVECTOR_VIRTBASES2_FWD(T, B1, B2) \ +template <> struct DataVectorBase<T> \ +{ typedef DataVector_detail::VirtBases<B1, B2> Base; }; \ +SG_BASES2(DataVector<T>, SG_VIRTUAL(DataVector<B1>), \ + SG_VIRTUAL(DataVector<B2>)) + + +/** + * @brief Declare base class info to @c DataVector. + * Multiple derivation. + * + * <code>DATAVECTOR_VIRTBASES3(D, B1, B2, B3)</code> says that @c D derives + * from all of @c B1, @c B2, and @c B3. + * + * This macro creates an appropriate specialization of @c DataVectorBase. + */ +#define DATAVECTOR_VIRTBASES3(T, B1, B2, B3) \ +DATAVECTOR_VIRTBASES3_FWD(T, B1, B2, B3); \ +template struct DataVector_detail::DVLEltBaseInit<T> + + +/** + * @brief Version of @c DATAVECTOR_VIRTBASES3 that can be used + * in forward declarations. + */ +#define DATAVECTOR_VIRTBASES3_FWD(T, B1, B2, B3) \ +template <> struct DataVectorBase<T> \ +{ typedef DataVector_detail::VirtBases<B1, B2, B3> Base; }; \ +SG_BASES3(DataVector<T>, SG_VIRTUAL(DataVector<B1>), \ + SG_VIRTUAL(DataVector<B2>), \ + SG_VIRTUAL(DataVector<B3>)) + + +template <class DV> class ConstDataVector; +template <class DV> void test2_assignelement1(); +template <class DV> void test2_assignelement2(); + + +/** + * @brief Derived @c DataVector\<T>. + * + * This is used for the case where @c T derives + * from other classes. The vector of pointers is actually held + * in the (unique) base class of the hierarchy. + * + * See the file comments for full details. + */ +template <class T, class BASE = typename DataVectorBase<T>::Base> +class DataVector : public BASE +{ +public: + typedef BASE DataVector_BASE; + typedef BASE DVL_BASE; + + /// This is true for any @c DataVector class if we need to use virtual + /// derivation to get to the base @c DataVector class. + static const bool has_virtual = BASE::has_virtual; + + /// This is the type of the underlying @c std::vector + /// (what @c stdcont returns). + typedef typename BASE::PtrVector PtrVector; + typedef typename BASE::PtrVector BaseContainer; + + +public: + // Standard types required for the container interface. + typedef T*& reference; + typedef T* const & const_reference; + typedef typename BASE::size_type size_type; + typedef typename BASE::difference_type difference_type; + typedef T* value_type; + typedef typename BASE::allocator_type allocator_type; + typedef T** pointer; + typedef T* const * const_pointer; + + typedef const T* const_value_type; + + /// The @c T value used as the template parameter. + /// Note that this is different from @c value_type (that's @c T*). + typedef T base_value_type; + + /// This type is used to proxy lvalue accesses to @c DataVector + /// elements, in order to handle ownership. + typedef DataModel_detail::ElementProxy<DataVector> ElementProxy; + + + /// Standard @c const_iterator. + typedef typename DataModel_detail::const_iterator<DataVector> + const_iterator; + + /// Standard @c iterator. Note that lvalue references here will yield + /// an @c ElementProxy, not a @c reference. + typedef typename DataModel_detail::iterator<DataVector> iterator; + + + /// Standard @c const_reverse_iterator. + typedef typename std::reverse_iterator<const_iterator> + const_reverse_iterator; + + /// Standard @c reverse_iterator. Note that lvalue references here will + /// yield an @c ElementProxy, not a @c reference. + typedef typename std::reverse_iterator<iterator> + reverse_iterator; + + typedef DataVector base_data_vector; + + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataVector(SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = + SG::DEFAULT_TRACK_INDICES); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataVector(size_type n, /* value_type pElem = 0,*/ + SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = + SG::DEFAULT_TRACK_INDICES); + + + /** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ + // The copy constructor for derived classes is deliberately omitted, + // as otherwise we get warnings about not calling the copy constructors + // for base classes, which are problematic when we have virtual + // inheritance. Most of what needs doing is done in the base class anyway, + // except for setting @c m_isMostDerived. We arrange for these flags + // to all get set to false; they'll get set correctly when + // @c testInsert is called. +#if __cplusplus > 201100 + // Need this to get the default copy ctor defined when a move + // ctor is also present. + DataVector (const DataVector&) = default; +#endif + + +#if __cplusplus > 201100 + /** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + DataVector (DataVector&& rhs); +#endif + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * By default, a @c DataVector will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + template <class InputIterator> + DataVector(InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = SG::DEFAULT_TRACK_INDICES, + SG::IAuxStore* store = 0); + + +#if __cplusplus > 201100 + /** + * @brief Constructor from an initializer list. + * @param l An initializer list. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * A @c DataVector constructed this way will *not* own its elements + * by default. To change this, pass @c SG::OWN_ELEMENTS for @a ownPolicy. + */ + DataVector(std::initializer_list<value_type> l, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = SG::DEFAULT_TRACK_INDICES, + SG::IAuxStore* store = 0); +#endif + + + /** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + DataVector& operator= (const DataVector& rhs); + + +#if __cplusplus > 201100 + /** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + DataVector& operator= (DataVector&& rhs); + + + /** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + DataVector& operator= (std::initializer_list<value_type> l); +#endif + + + /** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + template <class InputIterator> + void assign(InputIterator first, InputIterator last); + + +#if __cplusplus > 201100 + /** + * @brief Assign from an initializer list. + * @param l An initializer list. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + void assign(std::initializer_list<value_type> l); +#endif + + + // Destructor is inherited. + + + //@} + //======================================================================== + /** @name Size and capacity. */ + //@{ + + + /** + * @fn size_type size() const + * @brief Returns the number of elements in the collection. + * + * Could in principle be inherited from the base class, + * but redeclared in the derived class to avoid root6 bugs. + */ + size_type size() const; + + + /** + * @fn size_type max_size() const + * @brief Returns the @c size() of the largest possible collection. + */ + // This is inherited from the base class. + + + /** + * @fn void resize(size_type sz) + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ + void resize(size_type sz); + + + /** + * @fn size_type capacity() const + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + */ + // This is inherited from the base class. + + + /** + * @fn bool empty() const + * @brief Returns @c true if the collection is empty. + */ + // This is inherited from the base class. + + + /** + * @fn void reserve (size_type n) + * @brief Attempt to preallocate enough memory for a specified number + * of elements. + * @param n Number of elements required. + */ + void reserve (size_type n); + + + /** + * @brief Change the vector capacity to match the current size. + * + * Note: this does not affect auxiliary data. + */ + // This is inherited from the base class. + + + //@} + //======================================================================== + /** @name Element access. */ + //@{ + + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * No bounds checking is done. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* operator[] (size_type n) const; + + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * This is a synonym for operator[] const, to be used when calling from root + * (where we can't readily call just the const version of a method). + */ + const T* get (size_type n) const; + + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy operator[] (size_type n); + + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* at (size_type n) const; + + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy at (size_type n); + + + /** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* front() const; + + + /** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* back() const; + + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy front (); + + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy back (); + + + //@} + //======================================================================== + /** @name Iterator creation. */ + //@{ + + + /** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator begin() const; + + + /** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator end() const; + + + /** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator begin(); + + + /** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator end(); + + + /** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rbegin() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rend() const; + + + /** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rbegin(); + + + /** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rend(); + + + /** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator cbegin() const; + + + /** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator cend() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator crbegin() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator crend() const; + + + //@} + //======================================================================== + /** @name Insertion operations. */ + //@{ + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void push_back(value_type pElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void push_back(std::unique_ptr<base_value_type> pElem); +#endif +#endif + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c push_back. + * It's included just for interface compatibility with `std::vector`. + */ + void emplace_back(value_type pElem); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + iterator insert(iterator position, value_type pElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + iterator insert(iterator position, std::unique_ptr<base_value_type> pElem); +#endif +#endif + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c insert. + * It's included just for interface compatibility with `std::vector`. + */ + iterator emplace(iterator position, value_type pElem); + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + template <class InputIterator> + void insert(iterator position, InputIterator first, InputIterator last); + + +#if __cplusplus > 201100 + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param l An initializer list. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void insert(iterator position, std::initializer_list<value_type> l); +#endif + + + /** + * @brief Insert the contents of another @c DataVector, + * with auxiliary data copied via move semantics. + * @param position Iterator before which the new elements will be added. + * @param other The vector to add. + * + * The ownership mode of this vector must be the same as @c other; + * otherwise, an exception will be thrown. + * + * If both vectors are view vectors, then this is the same + * as <code> insert (position, other.begin(), other.end()) </code>. + * + * Otherwise, the elements from @c other will be inserted into this vector. + * This vector will take ownership of the elements, and the ownership + * mode of @c other will be changed to @c VIEW_ELEMENTS. + * Auxiliary data for these elements will be transferred, + * using move semantics if possible. (Thus, the auxiliary store + * for @c other may be modified and must not be locked.) + * Finally, the auxiliary store pointer for @c other will be cleared + * (but the store itself will not be deleted since it's not owned + * by the vector). + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void insertMove (iterator position, DataVector& other); + + + //@} + //======================================================================== + /** @name Erasure operations. */ + //@{ + + + /** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ + iterator erase(iterator position); + + + /** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + iterator erase(iterator first, iterator last); + + + /** + * @fn void pop_back() + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ + void pop_back(); + + + /** + * @fn void clear() + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear(); + + + //@} + //======================================================================== + /** @name Swap and sort. */ + //@{ + + + /** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataVector in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataVector. + */ + void swap(DataVector& rhs); + + + /** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ + static void iter_swap (iterator a, iterator b); + + + /** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ + void sort(); + + + /** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + */ + template <class COMPARE> + void sort(COMPARE comp); + + + + //@} + //======================================================================== + /** @name Non-standard operations. */ + //@{ + + + /** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(size_type index, value_type newElem, reference oldElem); + + + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, value_type newElem, reference oldElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(size_type index, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem); + + + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataList in the hierarchy. + */ + void swapElement(iterator pos, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem); +#endif +#endif + + +public: + /** + * @fn const PtrVector& stdcont() const + * @brief Return the underlying @c std::vector of the container. + * @return Reference to the @c std::vector actually holding the collection. + * + * Note that @c DataVector<T>::stdcont does not necessarily return + * a @c std::vector<T*> if @c DataVector inheritance is being used. + */ + // This is inherited from the base class. + + + /** + * @fn SG::OwnershipPolicy ownPolicy() const + * @brief Return the ownership policy setting for this container. + */ + // This is inherited from the base class. + + + /** + * @fn void clear (SG::OwnershipPolicy ownPolicy) + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy); + + + /** + * @fn void clear + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + static const DataModel_detail::DVLInfoBase& dvlinfo(); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const; + + + /** + * @brief Return the offset of a base @c DataVector class. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + * This function is here due to limitations of root 6, which can't + * calculate these offsets correctly from the dictionary if + * virtual derivation is used. + */ + static + int baseOffset (const std::type_info& ti); + + + /** + * @brief Convert to @c AuxVectorBase. + * + * Needed to get @x AuxVectorBase from a @c ConstDataVector. + * Present in @c DataVector as well for consistency. + * We only really need it in the base class; however, root6 fails + * constructing a @c TMethodCall for this if there is virtual + * derivation. A workaround is to redeclare this in the derived + * classes too. + */ + const SG::AuxVectorBase& auxbase() const; + + + //@} + //======================================================================== + + + // Doxygen trick. We want DataVector<T> to show the complete interface, + // including inherited methods. Normally, doxygen would do this. + // But it's not smart enough to figure out our inheritance relationships. + // We can add a function with `fn', but doxygen won't actually + // generate the documentation unless it also sees the declaration. + // So here are declarations which should be visible to doxygen + // but not to C++. +#ifndef __cplusplus + size_type max_size() const; + void resize(size_type sz); + size_type capacity() const; + bool empty() const; + void shrink_to_fit(); + void pop_back(); + void clear(); + const PtrVector& stdcont() const; + SG::OwnershipPolicy ownPolicy() const; + void clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices = SG::DEFAULT_TRACK_INDICES); +#endif // not __cplusplus + + + /** @name Internal operations. */ + //@{ + + + /** + * @brief Helper for @c baseOffset. + * @param p Pointer to the start of the top-level object. + * @param dv Reference to the DataVector object. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + */ + static + int baseOffset1 (const char* p, const DataVector& dv, + const std::type_info& ti); + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + */ + void resortAux (iterator beg, iterator end); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataVector. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ + void testInsert (const char* op); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ + void testInsertOol (const char* op); + + +private: + friend class DataModel_detail::ElementProxy<DataVector>; + template <class DV> + friend class ConstDataVector; + friend void test2_assignelement1<DataVector>(); + friend void test2_assignelement2<DataVector>(); + + + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, value_type newElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The container must own its elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, + std::unique_ptr<base_value_type> newElem); +#endif +#endif + + + /** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem); + + + /** + * @brief Shift the auxiliary elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + void shift (size_t pos, ptrdiff_t offs); + + +public: + // Make this public so we can call it from DVCollectionProxy. + /** + * @brief Helper to shorten calls to @c DataModel_detail::DVLCast. + * @param p The value to convert. + * @return The value as a @c const @c T*. + * + * The conversion will be done with @c static_cast if possible, + * with @c dynamic_cast otherwise. + */ + static + const T* do_cast (const typename PtrVector::value_type p); + + +private: + /** + * @brief Find the most-derived @c DataVector class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * This is used to generate a nice error message when the most-derived + * check for insertions fails. + * Every @c DataVector defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataVector + * gets run. + */ + virtual const std::type_info& dv_typeid() const; + + +protected: + /** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ + void clearMostDerived(); + + + /** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ + virtual void setMostDerived(); + + +private: + //@} + + + /// This flag is true if this DV instance is the most-derived one. + /// We set this to true in the top-level constructor; the constructor + /// then calls @c clearMostDerived on the base classes. + SG::IsMostDerivedFlag m_isMostDerived; + + + /// The DV/DL info struct for this class. + static DataModel_detail::DVLInfo<DataVector<T> > s_info; + + + typedef typename + ROOT_SELECTION_NS::DataVector<T, DataVector_BASE>::self self; +}; + + +template <class T, class BASE> +const bool DataVector<T, BASE>::has_virtual; + +/** + * @brief Base specialization for @c DataVector\<T>. + * + * This is used for the case where @c T does not derive + * from other classes. This is the class which actually holds + * the vector of pointers. + * + * See the file comments for full details. + */ +template <class T> +class DataVector<T, DataModel_detail::NoBase> + : public SG::AuxVectorBase +{ +public: + typedef DataModel_detail::NoBase DataVector_BASE; + typedef DataModel_detail::NoBase DVL_BASE; + + /// Mark as a sequence, for DataLink / ElementLink. + typedef std::true_type isSequence; + + /// This is the type of the underlying @c std::vector + /// (what @c stdcont returns). + typedef std::vector<T*> PtrVector; + typedef std::vector<T*> BaseContainer; + + /// This is true for any @c DataVector class if we need to use virtual + /// derivation to get to the base @c DataVector class. + /// Since this @e is the base @c DataVector class, set this + /// unconditionally to @c false. + static const bool has_virtual = false; + + // Standard types required for the container interface. + typedef T*& reference; + typedef T* const & const_reference; + typedef typename PtrVector::size_type size_type; + typedef typename PtrVector::difference_type difference_type; + typedef T* value_type; + typedef typename PtrVector::allocator_type allocator_type; + typedef T** pointer; + typedef T* const * const_pointer; + + typedef const T* const_value_type; + + /// The @c T value used as the template parameter. + /// Note that this is different from @c value_type (that's @c T*). + typedef T base_value_type; + + /// This type is used to proxy lvalue accesses to @c DataVector + /// elements, in order to handle ownership. + typedef DataModel_detail::ElementProxy<DataVector> ElementProxy; + + + /// Standard @c const_iterator. + // Here, we can just use the @c std::vector iterator. + typedef typename PtrVector::const_iterator const_iterator; + + /// Standard @c iterator. Note that lvalue references here will yield + /// an @c ElementProxy, not a @c reference. + typedef typename DataModel_detail::iterator<DataVector> iterator; + + /// Standard @c const_reverse_iterator. + // Note: we can't just use the underlying PtrVector::const_reverse_iterator + // here; otherwise, const_reverse_iterator won't be convertable to + // reverse_iterator. + typedef typename std::reverse_iterator<const_iterator> + const_reverse_iterator; + + /// Standard @c reverse_iterator. Note that lvalue references here will + /// yield an @c ElementProxy, not a @c reference. + typedef typename std::reverse_iterator<iterator> + reverse_iterator; + + typedef DataVector base_data_vector; + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataVector(SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = + SG::DEFAULT_TRACK_INDICES); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + explicit DataVector + (size_type n, /* value_type pElem = 0,*/ + SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = SG::DEFAULT_TRACK_INDICES); + + + /** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ + DataVector(const DataVector& rhs); + + +#if __cplusplus > 201100 + /** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + DataVector(DataVector&& rhs); +#endif + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * By default, a @c DataVector will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ + template <class InputIterator> + DataVector(InputIterator first, InputIterator last, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = SG::DEFAULT_TRACK_INDICES, + SG::IAuxStore* store = 0); + + +#if __cplusplus > 201100 + /** + * @brief Constructor from iterators. + * @param l An initializer list. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * A @c DataVector constructed this way will *not* own its elements + * by default. To change this, pass @c SG::OWN_ELEMENTS for @a ownPolicy. + */ + DataVector(std::initializer_list<value_type> l, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS, + SG::IndexTrackingPolicy trackIndices = SG::DEFAULT_TRACK_INDICES, + SG::IAuxStore* store = 0); +#endif + + + /** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + DataVector& operator= (const DataVector& rhs); + + +#if __cplusplus > 201100 + /** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + DataVector& operator= (DataVector&& rhs); + + + /** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + DataVector& operator= (std::initializer_list<value_type> l); +#endif + + + /** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + template <class InputIterator> + void assign(InputIterator first, InputIterator last); + + +#if __cplusplus > 201100 + /** + * @brief Assign from an initializer list. + * @param l An initializer list. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ + void assign(std::initializer_list<value_type> l); +#endif + + + /** + * @brief Destructor. + * + * If this container owns its elements, the contained elements will + * be deleted as well. Before doing this, the destructor will scan + * for duplicate pointers (takes @f$n \log n@f$ time); duplicates are only + * destroyed once. Duplicates should, however, be considered an error; + * don't rely on this behavior. + */ + virtual ~DataVector(); + + + //@} + //======================================================================== + /** @name Size and capacity. */ + //@{ + + + /** + * @brief Returns the number of elements in the collection. + */ + size_type size() const; + + + /** + * @brief Returns the number of elements in the collection. + * + * This version is virtual, to be callable from the AuxData + * base class. + */ + virtual size_type size_v() const; + + + /** + * @brief Returns the @c size() of the largest possible collection. + */ + size_type max_size() const; + + + /** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ + void resize(size_type sz); + + + /** + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + */ + size_type capacity() const; + + + /** + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + * + * This version is virtual, to be callable from the AuxData + * base class. + */ + virtual size_type capacity_v() const; + + + /** + * @brief Returns @c true if the collection is empty. + */ + bool empty() const; + + + /** + * @brief Attempt to preallocate enough memory for a specified number + * of elements. + * @param n Number of elements required. + */ + void reserve (size_type n); + + +#if __cplusplus > 201100 + /** + * @brief Change the vector capacity to match the current size. + * + * Note: this does not affect auxiliary data. + */ + void shrink_to_fit(); +#endif + + + //@} + //======================================================================== + /** @name Element access. */ + //@{ + + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * No bounds checking is done. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* operator[] (size_type n) const; + + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * This is a synonym for operator[] const, to be used when calling from root + * (where we can't readily call just the const version of a method). + */ + const T* get (size_type n) const; + + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy operator[] (size_type n); + + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* at (size_type n) const; + + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy at (size_type n); + + + /** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* front() const; + + + /** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ + const T* back() const; + + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy front (); + + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ + ElementProxy back (); + + + //@} + //======================================================================== + /** @name Iterator creation. */ + //@{ + + + /** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator begin() const; + + + /** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator end() const; + + + /** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator begin(); + + + /** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + iterator end(); + + + /** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rbegin() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator rend() const; + + + /** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rbegin(); + + + /** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ + reverse_iterator rend(); + + /** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator cbegin() const; + + + /** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_iterator cend() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator crbegin() const; + + + /** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ + const_reverse_iterator crend() const; + + + //@} + //======================================================================== + /** @name Insertion operations. */ + //@{ + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void push_back(value_type pElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void push_back(std::unique_ptr<base_value_type> pElem); +#endif +#endif + + + /** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c push_back. + * It's included just for interface compatibility with `std::vector`. + */ + void emplace_back(value_type pElem); + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + iterator insert(iterator position, value_type pElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + iterator insert(iterator position, std::unique_ptr<base_value_type> pElem); +#endif +#endif + + + /** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c insert. + * It's included just for interface compatibility with `std::vector`. + */ + iterator emplace(iterator position, value_type pElem); + + + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + template <class InputIterator> + void insert(iterator position, InputIterator first, InputIterator last); + + +#if __cplusplus > 201100 + /** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param l An initializer list. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void insert(iterator position, std::initializer_list<value_type> l); +#endif + + + /** + * @brief Insert the contents of another @c DataVector, + * with auxiliary data copied via move semantics. + * @param position Iterator before which the new elements will be added. + * @param other The vector to add. + * + * The ownership mode of this vector must be the same as @c other; + * otherwise, an exception will be thrown. + * + * If both vectors are view vectors, then this is the same + * as <code> insert (position, other.begin(), other.end()) </code>. + * + * Otherwise, the elements from @c other will be inserted into this vector. + * This vector will take ownership of the elements, and the ownership + * mode of @c other will be changed to @c VIEW_ELEMENTS. + * Auxiliary data for these elements will be transferred, + * using move semantics if possible. (Thus, the auxiliary store + * for @c other may be modified and must not be locked.) + * Finally, the auxiliary store pointer for @c other will be cleared + * (but the store itself will not be deleted since it's not owned + * by the vector). + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void insertMove (iterator position, DataVector& other); + + + //@} + //======================================================================== + /** @name Erasure operations. */ + //@{ + + + /** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ + iterator erase(iterator position); + + + /** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + iterator erase(iterator first, iterator last); + + + /** + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ + void pop_back(); + + + /** + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear(); + + + //@} + //======================================================================== + /** @name Swap and sort. */ + //@{ + + + /** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataVector in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataVector. + */ + void swap(DataVector& rhs); + + + /** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ + static void iter_swap (iterator a, iterator b); + + + /** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ + void sort(); + + + /** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + * + */ + template <class COMPARE> + void sort(COMPARE comp); + + + //@} + //======================================================================== + /** @name Non-standard operations. */ + //@{ + + + /** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(size_type index, value_type newElem, reference oldElem); + + + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(iterator pos, value_type newElem, reference oldElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(size_type index, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem); + + + /** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + void swapElement(iterator pos, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem); +#endif +#endif + + +public: + /** + * @brief Return the underlying @c std::vector of the container. + * @return Reference to the @c std::vector actually holding the collection. + * + * Note that @c DataVector<T>::stdcont does not necessarily return + * a @c std::vector<T*> if @c DataVector inheritance is being used. + */ + const PtrVector& stdcont() const; + + + /** + * @brief Return the ownership policy setting for this container. + */ + SG::OwnershipPolicy ownPolicy() const; + + + /** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy); + + + /** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ + void clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + static const DataModel_detail::DVLInfoBase& dvlinfo(); + + + /** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const; + + + /** + * @brief Return the offset of a base @c DataVector class. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + * This function is here due to limitations of root 6, which can't + * calculate these offsets correctly from the dictionary if + * virtual derivation is used. + */ + static + int baseOffset (const std::type_info& ti); + + + /** + * @brief Convert to @c AuxVectorBase. + * + * Needed to get @x AuxVectorBase from a @c ConstDataVector. + * Present in @c DataVector as well for consistency. + */ + const SG::AuxVectorBase& auxbase() const; + + + //@} + //======================================================================== + /** @name Internal operations. */ + //@{ + + + /** + * @brief Helper for @c baseOffset. + * @param p Pointer to the start of the top-level object. + * @param dv Reference to the DataVector object. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + */ + static + int baseOffset1 (const char* p, const DataVector& dv, + const std::type_info& ti); + + + /** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + */ + void resortAux (iterator beg, iterator end); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataVector. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ + void testInsert (const char* op); + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ + void testInsertOol (const char* op); + + +private: + friend class DataModel_detail::ElementProxy<DataVector>; + template <class DV> + friend class ConstDataVector; + friend void test2_assignelement1<DataVector>(); + friend void test2_assignelement2<DataVector>(); + + + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, value_type newElem); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The container must own its elements. + * Auxiliary data are copied if appropriate. + */ + void assignElement (typename BaseContainer::iterator pos, + std::unique_ptr<base_value_type> newElem); +#endif +#endif + + + /** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ + void assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem); + + + /** + * @brief Shift the auxiliary elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + void shift (size_t pos, ptrdiff_t offs); + + +public: + // Make this public so we can call it from DVCollectionProxy. + /** + * @brief Helper to shorten calls to @c DataModel_detail::DVLCast. + * @param p The value to convert. + * @return The value as a @c const @c T*. + * + * This is a no-op for the base class. + */ + static + const T* do_cast (const typename PtrVector::value_type p); + + +private: + /** + * @brief Find the most-derived @c DataVector class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * This is used to generate a nice error message when the most-derived + * check for insertions fails. + * Every @c DataVector defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataVector + * gets run. + */ + virtual const std::type_info& dv_typeid() const; + + +protected: + /** + * @brief Helper for @c erase(). Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataVector classes. It deals with the + * @c std::vector iterators directly. + */ + typename PtrVector::iterator + erase_base(typename PtrVector::iterator position); + + + /** + * @brief Helper for @c erase(). Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataVector classes. It deals with the + * @c std::vector iterators directly. + */ + typename PtrVector::iterator + erase_base(typename PtrVector::iterator first, + typename PtrVector::iterator last); + + +protected: + /// The ownership policy of this container --- + /// either SG::OWNS_ELEMENTS or SG::VIEW_ELEMENTS. + SG::OwnershipPolicy m_ownPolicy; + + /// This actually holds the elements. + PtrVector m_pCont; + + + /** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ + void clearMostDerived(); + + + /** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ + virtual void setMostDerived(); + + +private: + //@} + + + /// This flag is true if this DV instance is the most-derived one. + /// We set this to true in the top-level constructor; the constructor + /// then calls clearMostDerived on the base classes. + SG::IsMostDerivedFlag m_isMostDerived; + + + /// The DV/DL info struct for this class. + static DataModel_detail::DVLInfo<DataVector<T> > s_info; + + + typedef typename + ROOT_SELECTION_NS::DataVector<T, DataVector_BASE>::self self; +}; + +template <class T> +const bool DataVector<T, DataModel_detail::NoBase>::has_virtual; + + +/** + * @brief Vector equality comparison. + * @param a A @c DataVector. + * @param b A @c DataVector of the same type as @a x. + * @return True iff the size and elements of the vectors are equal. + * + * This is an equivalence relation. It is linear in the size of the + * vectors. Vectors are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ +template <class T> +bool operator== (const DataVector<T>& a, const DataVector<T>& b); + + +/// Based on operator== +template <class T> +bool operator!= (const DataVector<T>& a, const DataVector<T>& b); + + +/** + * @brief Vector ordering relation. + * @param a A @c DataVector. + * @param b A @c DataVector of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * vectors. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ +template <class T> +bool operator< (const DataVector<T>& a, const DataVector<T>& b); + + +/// Based on operator< +template <class T> +bool operator> (const DataVector<T>& a, const DataVector<T>& b); + + +/// Based on operator< +template <class T> +bool operator<= (const DataVector<T>& a, const DataVector<T>& b); + + +/// Based on operator< +template <class T> +bool operator>= (const DataVector<T>& a, const DataVector<T>& b); + + +/// See @c DataVector<T, BASE>::swap(). +template <class T> +void swap (DataVector<T>& a, DataVector<T>& b); + + +ENTER_ROOT_SELECTION_NS + +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + +template <class T> +struct SelectVirtBases +{ + typedef int type; +}; + +template <class B1, class B2, class B3> +struct SelectVirtBases<DataVector_detail::VirtBases<B1, B2, B3> > +{ + typedef ROOT_SELECTION_NS::AUTOSELECT type; +}; + +template <class T, class BASE> +class DataVector +{ +public: + typedef DataVector<T, BASE> self; + + ROOT_SELECTION_NS::TEMPLATE_DEFAULTS< + ROOT_SELECTION_NS::NODEFAULT, + typename ::DataVector<T>::DataVector_BASE> dum1; + ROOT_SELECTION_NS::NO_SELF_AUTOSELECT dum2; + ROOT_SELECTION_NS::AUTOSELECT m_pCont; + ROOT_SELECTION_NS::TRANSIENT m_isMostDerived; + typename SelectVirtBases<BASE>::type __base1; +}; + +#else + +template< class T, class BASE > +class DataVector : KeepFirstTemplateArguments< 1 > +// The SelectNoInstance type was added after 6.00/02... +#if ROOT_VERSION_CODE > ROOT_VERSION( 6, 0, 2 ) + , SelectNoInstance +#endif // > v6.00/02 +{ + +public: + /// A helper typedef + typedef DataVector< T, BASE > self; +#ifndef XAOD_STANDALONE + /// Automatically generate dictionary for contained vector + //MN: this causes massive dictionary duplication. Disabling for now. + // ROOT_SELECTION_NS::MemberAttributes< kAutoSelected > m_pCont; +#endif + /// Declare the automatically created variable transient + ROOT_SELECTION_NS::MemberAttributes< kTransient > m_isMostDerived; + +}; + +#endif // ROOT_VERSION + +EXIT_ROOT_SELECTION_NS + + +#include "AthContainers/ClassName.h" + + +/** + * @brief Specialization of @c ClassName for @c DataVector. + * + * This overrides the default implementation of @c ClassName + * to hide @c DataVector's second template parameter. + */ +template <class T> +class ClassName<DataVector<T> > +{ +public: + static std::string name(); +}; + + +#ifndef XAOD_STANDALONE + + +#include "AthContainers/tools/DVLDataBucket.h" +#include "SGTools/DataBucketTraitFwd.h" + + +namespace SG { + + +/** + * @brief Metafunction to find the proper @c DataBucket class for @c T. + * + * Specialize this for @c DataVector. + * See SGTools/StorableConversions.h for an explanation. + */ +template <class T, class U> +struct DataBucketTrait<DataVector<T>, U> +{ + typedef SG::DVLDataBucket<U> type; + static void init() { DataVector<T>::dvlinfo(); } +}; + + +} // namespace SG + + +#endif + + +#include "AthContainers/DataVector.icc" + + +#if 0 +//=================================================================== +// Code to try to make the DATAVECTOR_BASES definitions automatically +// based on SG_BASES. Still have to use one macro, DATAVECTOR_BASES_FROM_SG. +// Currently missing the part that would declare the DataVector relations +// to SG. Not sure how useful this will be; don't bother trying to +// finish it now. +#include "boost/mpl/if.hpp" +#include "boost/mpl/and.hpp" +#include "boost/mpl/equal_to.hpp" +#define if_ boost::mpl::if_ +#define and_ boost::mpl::and_ +#define equal_to boost::mpl::equal_to +#define true_ boost::mpl::true_ +#define false_ boost::mpl::false_ +template <class U> struct not_virtual { typedef true_ type; }; +template <class U> struct not_virtual<SG::Virtual<U> > { typedef false_ type; }; +template <class U> struct clean_type { typedef U type; }; +template <> struct clean_type<SG::NoBase> +{ typedef DataModel_detail::NoBase type; }; +template <class U> struct clean_type<SG::Virtual<U> > +{ typedef typename clean_type<U>::type type; }; +template <class T> +struct bases_from_sg +{ + typedef typename + if_<equal_to<typename SG::Bases<T>::Base1, SG::NoBase>, + DataModel_detail::NoBase, + if_<and_<equal_to<typename SG::Bases<T>::Base1, SG::NoBase>, + not_virtual<typename SG::Bases<T>::Base2> >, + typename SG::Bases<T>::Base1, + DataVector_detail::VirtBases + <clean_type<typename SG::Bases<T>::Base1>, + clean_type<typename SG::Bases<T>::Base2>, + clean_type<typename SG::Bases<T>::Base3> > + > >::type type; +}; +#undef if_ +#undef and_ +#undef equal_to +#undef true_ +#undef false_ + +#define DATAVECTOR_BASES_FROM_SG(T) \ +template <> struct DataVectorBase<T> \ +{ typedef bases_from_sg<T>::type Base; }; +//=================================================================== +#endif + + +#endif // not ATHCONTAINERS_DATAVECTOR_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/DataVector.icc b/EDM/athena/Control/AthContainers/AthContainers/DataVector.icc new file mode 100644 index 00000000..2ee19d7d --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/DataVector.icc @@ -0,0 +1,3946 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataVector.icc 797205 2017-02-14 19:38:03Z ssnyder $ +/** + * @file AthContainers/DataVector.icc + * @author scott snyder, Paolo Calafiura, etc + * @date May 2005; rewritten from earlier version. + * @brief An STL vector of pointers that by default owns its pointed-to + * elements. + * Implementation file. + */ + + +#include "AthContainers/tools/CompareAndPrint.h" +#include "AthContainers/tools/ATHCONTAINERS_ASSERT.h" +#include <limits> +#include <functional> + + +//**************************************************************************** +// VirtBases +// + +ENTER_ROOT_SELECTION_NS +namespace DataVector_detail { +template <class B1, class B2, class B3> class VirtBases; +} +EXIT_ROOT_SELECTION_NS + + +namespace DataVector_detail { + +/* #define DO_REMOVE_DUPLICATES to activate for debugging purposes (Slow) */ +// Note: this name should be distinct from the corresponding one in DataList, +// even though they're in different namespaces. This due to an apparent +// Koenig lookup bug in gccxml 0.9.0. +template <class FI> +void optimizeMeAway_DV(FI, bool){} +/** + * @brief Remove duplicates from a @c DataVector before deleting elements. + * @param b Start of range to scan. + * @param e One past end of range to scan. + * @param quiet If true, complain if duplicates are found. + * @return One past the last unique elements. + * + * The elements within the range are sorted, then duplicate elements + * are moved to the end. If duplicate elements are found and + * @a quiet is @c true, then a complaint will be printed. + */ +template <class ForwIter> +ForwIter remove_duplicates(ForwIter b, ForwIter e, bool quiet=false) +{ +#ifdef DO_REMOVE_DUPLICATES + std::sort(b, e); + return std::unique(b, e, DataModel_detail::CompareAndPrint(quiet)); +#else + optimizeMeAway_DV(b, quiet); + return e; +#endif +} + +/** + * @brief VirtBases for one class. + * + * @c DataVector\<T> derives from this for the case of + * @c T deriving virtually from a single class. + * It in turn derives from @c B1. + */ +template <class B1> +struct VirtBases<B1, DataModel_detail::NoBase, DataModel_detail::NoBase> + : virtual public DataVector<B1> +{ + // Make these types available to the derived @c DataVector. + typedef typename DataVector<B1>::PtrVector PtrVector; + typedef typename DataVector<B1>::size_type size_type; + typedef typename DataVector<B1>::difference_type difference_type; + typedef typename DataVector<B1>::allocator_type allocator_type; + +#ifndef __GCCXML__ + // We're using virtual derivation. + static const bool has_virtual = true; +#endif + + +#if __cplusplus > 201100 + // We need to delete the move ctor; otherwise, we get warnings about + // a virtual base having a non-trivial move ctor. Then we also need + // to explicitly default the ordinary ctors so that they remain visible. + VirtBases () = default; + VirtBases (const VirtBases&) = default; + // default doesn't work here with gcc 4.7; it does with 4.9. + VirtBases& operator= (VirtBases&) { return *this; } + VirtBases& operator= (VirtBases&&) = delete; +#endif + + +protected: + // Pass this down to base classes. + void clearMostDerived() + { + DataVector<B1>::clearMostDerived(); + } + + // We need these here to prevent ambiguities, + // but they shouldn't actually be called. + virtual const std::type_info& dv_typeid() const + { + return typeid(VirtBases); + } + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const + { + return DataVector<B1>::dvlinfo(); + } + virtual void setMostDerived() + { + std::abort(); + } + + + static + int baseOffset1 (const char* p, const VirtBases& dv, + const std::type_info& ti) + { + return DataVector<B1>::baseOffset1 (p, dv, ti); + } + + +private: + typedef typename + ROOT_SELECTION_NS:: + DataVector_detail::VirtBases<B1, + DataModel_detail::NoBase, + DataModel_detail::NoBase>::self self; +}; + + +/** + * @brief VirtBases for two classes. + * + * @c DataVector\<T> derives from this for the case of + * @c T deriving from two classes. + * It in turn derives from @c B1 and @c B2. + */ +template <class B1, class B2> +struct VirtBases<B1, B2, DataModel_detail::NoBase> + : virtual public DataVector<B1>, + virtual public DataVector<B2> +{ + // Check to be sure that @c B1 and @c B2 have the same ultimate base type. + typedef ::boost::is_same<typename DataVector<B1>::PtrVector, + typename DataVector<B2>::PtrVector> check; + BOOST_STATIC_ASSERT (check::value); + + // Make these types available to the derived @c DataVector. + typedef typename DataVector<B1>::PtrVector PtrVector; + typedef typename DataVector<B1>::size_type size_type; + typedef typename DataVector<B1>::difference_type difference_type; + typedef typename DataVector<B1>::allocator_type allocator_type; + +#ifndef __GCCXML__ + // We're using virtual derivation. + static const bool has_virtual = true; +#endif + + +#if __cplusplus > 201100 + // We need to delete the move ctor; otherwise, we get warnings about + // a virtual base having a non-trivial move ctor. Then we also need + // to explicitly default the ordinary ctors so that they remain visible. + VirtBases () = default; + VirtBases (const VirtBases&) = default; + // default doesn't work here with gcc 4.7; it does with 4.9. + VirtBases& operator= (VirtBases&) { return *this; } + VirtBases& operator= (VirtBases&&) = delete; +#endif + + +protected: + // Pass this down to base classes. + void clearMostDerived() + { + DataVector<B1>::clearMostDerived(); + DataVector<B2>::clearMostDerived(); + } + + // We need these here to prevent ambiguities, + // but they shouldn't actually be called. + virtual const std::type_info& dv_typeid() const + { + return typeid(VirtBases); + } + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const + { + return DataVector<B1>::dvlinfo(); + } + virtual void setMostDerived() + { + std::abort(); + } + + + static + int baseOffset1 (const char* p, const VirtBases& dv, + const std::type_info& ti) + { + int ret = DataVector<B1>::baseOffset1 (p, dv, ti); + if (ret >= 0) + return ret; + return DataVector<B2>::baseOffset1 (p, dv, ti); + } + + +private: + typedef typename + ROOT_SELECTION_NS:: + DataVector_detail::VirtBases<B1, B2, + DataModel_detail::NoBase>::self self; +}; + + +/** + * @brief VirtBases for three classes. + * + * @c DataVector\<T> derives from this for the case of + * @c T deriving from three classes. + * It in turn derives from @c B1, @c B2, and @c B3. + */ +template <class B1, class B2, class B3> +struct VirtBases + : virtual public DataVector<B1>, + virtual public DataVector<B2>, + virtual public DataVector<B3> +{ + // Check to be sure that @c B1, @c B2, and @c B3 have the same + // ultimate base type. + typedef ::boost::is_same<typename DataVector<B1>::PtrVector, + typename DataVector<B2>::PtrVector> check1; + typedef ::boost::is_same<typename DataVector<B1>::PtrVector, + typename DataVector<B3>::PtrVector> check2; + BOOST_STATIC_ASSERT (check1::value); + BOOST_STATIC_ASSERT (check2::value); + + + // Make these types available to the derived @c DataVector. + typedef typename DataVector<B1>::PtrVector PtrVector; + typedef typename DataVector<B1>::size_type size_type; + typedef typename DataVector<B1>::difference_type difference_type; + typedef typename DataVector<B1>::allocator_type allocator_type; + +#ifndef __GCCXML__ + // We're using virtual derivation. + static const bool has_virtual = true; +#endif + + +#if __cplusplus > 201100 + // We need to delete the move ctor; otherwise, we get warnings about + // a virtual base having a non-trivial move ctor. Then we also need + // to explicitly default the ordinary ctors so that they remain visible. + VirtBases () = default; + VirtBases (const VirtBases&) = default; + // default doesn't work here with gcc 4.7; it does with 4.9. + VirtBases& operator= (VirtBases&) { return *this; } + VirtBases& operator= (VirtBases&&) = delete; +#endif + + +protected: + // Pass this down to base classes. + void clearMostDerived() + { + DataVector<B1>::clearMostDerived(); + DataVector<B2>::clearMostDerived(); + DataVector<B3>::clearMostDerived(); + } + + // We need these here to prevent ambiguities, + // but they shouldn't actually be called. + virtual const std::type_info& dv_typeid() const + { + return typeid(VirtBases); + } + virtual const DataModel_detail::DVLInfoBase& dvlinfo_v() const + { + return DataVector<B1>::dvlinfo(); + } + virtual void setMostDerived() + { + std::abort(); + } + + + static + int baseOffset1 (const char* p, const VirtBases& dv, + const std::type_info& ti) + { + int ret = DataVector<B1>::baseOffset1 (p, dv, ti); + if (ret >= 0) + return ret; + ret = DataVector<B2>::baseOffset1 (p, dv, ti); + if (ret >= 0) + return ret; + return DataVector<B3>::baseOffset1 (p, dv, ti); + } + + +private: + typedef typename + ROOT_SELECTION_NS::DataVector_detail::VirtBases<B1, B2, B3>::self + self; +}; + + +} // namespace DataVector_detail + + +ENTER_ROOT_SELECTION_NS +namespace DataVector_detail { + +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + +template <class B1, class B2, class B3> +class VirtBases +{ +public: + typedef DataVector_detail::VirtBases<B1, B2, B3> self; + + ROOT_SELECTION_NS::TEMPLATE_DEFAULTS< + ROOT_SELECTION_NS::NODEFAULT, + ::DataModel_detail::NoBase, + ::DataModel_detail::NoBase> dum1; + ROOT_SELECTION_NS::NO_SELF_AUTOSELECT dum2; +}; + +#else + +template< class B1, class B2, class B3 > +class VirtBases : KeepFirstTemplateArguments< 1 > +// The SelectNoInstance type was added after 6.00/02... +#if ROOT_VERSION_CODE > ROOT_VERSION( 6, 0, 2 ) + , SelectNoInstance +#endif // > v6.00/02 +{ + +public: + /// A helper typedef + typedef DataVector_detail::VirtBases< B1, B2, B3 > self; + +}; + +#endif // ROOT_VERSION + +} +EXIT_ROOT_SELECTION_NS + + +//**************************************************************************** +// Generic (derived) DataVector implementation. +// + + +//=== Constructors, destructors, assignment. + + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataVector + * class. + */ +template <class T, class BASE> +inline +DataVector<T, BASE>::DataVector + (SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*= SG::DEFAULT_TRACK_INDICES*/) +{ + this->m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); + this->m_isMostDerived = true; + BASE::clearMostDerived(); +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataVector + * class. + */ +template <class T, class BASE> +inline +DataVector<T, BASE>::DataVector + (size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*=SG::DEFAULT_TRACK_INDICES*/) +{ + this->m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); + this->m_isMostDerived = true; + BASE::clearMostDerived(); + this->m_pCont.resize (n); +} + + +#if __cplusplus > 201100 +/** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class T, class BASE> +DataVector<T, BASE>::DataVector (DataVector&& rhs) +{ + SG::AuxVectorBase::operator= (std::move (rhs)); + this->m_ownPolicy = rhs.m_ownPolicy; + this->m_pCont = std::move (rhs.m_pCont); + + // Need to reset the container pointer on elements. + this->setIndices (this->begin(), this->end()); + this->m_isMostDerived = true; +} +#endif + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * By default, a @c DataVector will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataVector + * class. + */ +template <class T, class BASE> +template <class InputIterator> +inline +DataVector<T, BASE>::DataVector + (InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*= SG::DEFAULT_INDEX_TRACKING*/, + SG::IAuxStore* store /*= 0*/) +{ + // Make sure that the input iterator can actually be converted + // to a T*. Lets us give a compilation error for this: + // DATAVECTOR_BASE(D, B); + // B* bb[] = ... + // DataVector<D> d (bb, bb+1); + // which would otherwise compile. + typedef typename std::iterator_traits<InputIterator>::value_type ittype; + BOOST_STATIC_ASSERT ((::boost::is_convertible<ittype, const T*>::value)); + + this->m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); + this->m_isMostDerived = true; + BASE::clearMostDerived(); + if (store) + this->setStore (store); + this->m_pCont.assign (first, last); + this->moveAux (0, first, last); +} + + +#if __cplusplus > 201100 +/** + * @brief Constructor from an initializer list. + * @param l An initializer list. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * + * A @c DataVector constructed this way will *not* own its elements + * by default. To change this, pass @c SG::OWN_ELEMENTS for @a ownPolicy. + * + * Note that we do the complete initialization here in the derived class, + * using the default constructors for the base classes. The reason + * for this is to be able to deal nicely with the virtual derivation + * case. We can arrange to call the proper base class from here to get + * things initialized in the virtual derivation case. But then anyone + * who derives from us must also know to explicitly reference that base + * class. Doing the initialization explicitly here means that other classes + * who derive from us need only know about the most derived DataVector + * class. + */ +template <class T, class BASE> +inline +DataVector<T, BASE>::DataVector + (std::initializer_list<value_type> l, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*= SG::DEFAULT_INDEX_TRACKING*/, + SG::IAuxStore* store /*= 0*/) + : DataVector (l.begin(), l.end(), ownPolicy, trackIndices, store) +{ +} +#endif + + +/** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +inline +DataVector<T, BASE>& DataVector<T, BASE>::operator= (const DataVector& rhs) +{ + if (&rhs != this) { + // Ensure we're not being called via a base class. + testInsert ("assignment operator"); + this->clear(); // Release any currently-owned elements. + this->m_ownPolicy = SG::VIEW_ELEMENTS; + this->setStore ((SG::IConstAuxStore*)0); + this->template initAuxVectorBase<DataVector>(this->m_ownPolicy, + SG::DEFAULT_TRACK_INDICES); + this->m_pCont = rhs.m_pCont; + } + return *this; +} + + +#if __cplusplus > 201100 +/** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class T, class BASE> +DataVector<T, BASE>& +DataVector<T, BASE>::operator= (DataVector<T, BASE>&& rhs) +{ + if (this != &rhs) { + // Ensure we're not being called via a base class. + testInsert ("assignment operator"); + + SG::AuxVectorBase::operator= (std::move (rhs)); + this->m_ownPolicy = rhs.m_ownPolicy; + this->m_pCont = std::move (rhs.m_pCont); + + // Need to reset the container pointer on elements. + this->setIndices (this->begin(), this->end()); + } + return *this; +} + + +/** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T, class BASE> +inline +DataVector<T, BASE>& +DataVector<T, BASE>::operator= (std::initializer_list<value_type> l) +{ + this->assign (l.begin(), l.end()); + return *this; +} +#endif + + +/** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T, class BASE> +template <class InputIterator> +void DataVector<T, BASE>::assign(InputIterator first, InputIterator last) +{ + // Ensure we're not being called via a base class. + testInsert ("assign"); + this->clear(); // Release any currently-owned elements. + insert(begin(), first, last); + this->moveAux (0, first, last); +} + + +#if __cplusplus > 201100 +/** + * @brief Assign from an initializer list. + * @param l An initializer list. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T, class BASE> +void DataVector<T, BASE>::assign(std::initializer_list<value_type> l) +{ + this->assign (l.begin(), l.end()); +} +#endif + + +//=== Size and capacity. + + +/** + * @fn size_type size() const + * @brief Returns the number of elements in the collection. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::size_type +DataVector<T, BASE>::size() const +{ + return this->m_pCont.size(); +} + + +/** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ +template <class T, class BASE> +void DataVector<T, BASE>::resize(size_type sz) +{ + if (sz < this->size()) { + this->erase (this->begin()+sz, this->end()); + } else { + this->m_pCont.insert(this->m_pCont.end(), sz - this->m_pCont.size(), 0); + } + // xxx ??? Is this redundant with the erase() above? + SG::AuxVectorBase::resize<DataVector> (sz); +} + + +/** + * @brief Attempt to preallocate enough memory for a specified number + * of elements. + * @param n Number of elements required. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::reserve (size_type n) +{ + this->m_pCont.reserve (n); + SG::AuxVectorBase::reserve<DataVector> (n); +} + + +//=== Element access. + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * No bounds checking is done. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T, class BASE> +inline +const T* DataVector<T, BASE>::operator[] (size_type n) const +{ + return do_cast(this->m_pCont[n]); +} + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * This is a synonym for operator[] const, to be used when calling from root + * (where we can't readily call just the const version of a method). + */ +template <class T, class BASE> +inline +const T* DataVector<T, BASE>::get (size_type n) const +{ + return do_cast(this->m_pCont[n]); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::ElementProxy +DataVector<T, BASE>::operator[] (size_type n) +{ + return ElementProxy (this->m_pCont.begin() + n, this); +} + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T, class BASE> +inline +const T* DataVector<T, BASE>::at (size_type n) const +{ + return do_cast(this->m_pCont.at(n)); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::ElementProxy +DataVector<T, BASE>::at (size_type n) +{ + // Can't use m_pCont's at here, because we need an iterator. + // So we have to do the bounds check ourselves. + if (n >= this->size()) + throw std::out_of_range ("DataVector::at range check"); + return ElementProxy (this->m_pCont.begin() + n, this); +} + + +/** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T, class BASE> +inline +const T* DataVector<T, BASE>::front() const +{ + return do_cast (this->m_pCont.front()); +} + + +/** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T, class BASE> +inline +const T* DataVector<T, BASE>::back() const +{ + return do_cast (this->m_pCont.back()); +} + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::ElementProxy +DataVector<T, BASE>::front () +{ + return ElementProxy (this->m_pCont.begin(), this); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::ElementProxy +DataVector<T, BASE>::back () +{ + return ElementProxy (this->m_pCont.end()-1, this); +} + + +//=== Iterator creation. + + +/** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_iterator +DataVector<T, BASE>::begin() const +{ + return const_iterator (this->m_pCont.begin()); +} + + +/** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_iterator +DataVector<T, BASE>::end() const +{ + return const_iterator (this->m_pCont.end()); +} + + +/** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::begin() +{ + return iterator (this->m_pCont.begin(), this); +} + + +/** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::end() +{ + return iterator (this->m_pCont.end(), this); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_reverse_iterator +DataVector<T, BASE>::rbegin() const +{ + return const_reverse_iterator (end()); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_reverse_iterator +DataVector<T, BASE>::rend() const +{ + return const_reverse_iterator (begin()); +} + + +/** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::reverse_iterator +DataVector<T, BASE>::rbegin() +{ + return reverse_iterator (iterator (this->m_pCont.end(), this)); +} + + +/** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::reverse_iterator +DataVector<T, BASE>::rend() +{ + return reverse_iterator (iterator (this->m_pCont.begin(), this)); +} + + +/** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_iterator +DataVector<T, BASE>::cbegin() const +{ + return const_iterator (this->m_pCont.begin()); +} + + +/** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_iterator +DataVector<T, BASE>::cend() const +{ + return const_iterator (this->m_pCont.end()); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_reverse_iterator +DataVector<T, BASE>::crbegin() const +{ + return const_reverse_iterator (cend()); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T, class BASE> +inline +typename DataVector<T, BASE>::const_reverse_iterator +DataVector<T, BASE>::crend() const +{ + return const_reverse_iterator (cbegin()); +} + + +//=== Insertion operations. + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::push_back(value_type pElem) +{ + // Ensure we're not being called via a base class. + testInsert ("push_back"); + this->m_pCont.push_back(static_cast<typename PtrVector::value_type>(pElem)); + SG::AuxVectorBase::resize<DataVector> (this->size()); + if (pElem) + this->moveAux (this->size()-1, pElem, false, true); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::push_back(std::unique_ptr<base_value_type> pElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + // Ensure we're not being called via a base class. + testInsert ("push_back"); + value_type ptr = pElem.release(); + this->m_pCont.push_back(ptr); + SG::AuxVectorBase::resize<DataVector> (this->size()); + if (ptr) + this->moveAux (this->size()-1, ptr, false, true); +} +#endif +#endif + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c push_back. + * It's included just for interface compatibility with `std::vector`. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::emplace_back(value_type pElem) +{ + this->push_back (pElem); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::insert(iterator position, value_type pElem) +{ + // Ensure we're not being called via a base class. + testInsert ("insert"); + iterator ret (this->m_pCont.insert(position.base(), pElem), this); + this->shift (ret - this->begin(), 1); + this->moveAux (ret-this->begin(), pElem); + return ret; +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::insert(iterator position, + std::unique_ptr<base_value_type> pElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + // Ensure we're not being called via a base class. + testInsert ("insert"); + value_type ptr = pElem.release(); + iterator ret (this->m_pCont.insert(position.base(), ptr), this); + this->shift (ret - this->begin(), 1); + this->moveAux (ret-this->begin(), ptr); + return ret; +} +#endif +#endif + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c insert. + * It's included just for interface compatibility with `std::vector`. + */ +template <class T, class BASE> +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::emplace(iterator position, value_type pElem) +{ + return this->insert (position, pElem); +} + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +template <class InputIterator> +void DataVector<T, BASE>::insert(iterator position, + InputIterator first, + InputIterator last) +{ + // Make sure that the input iterator can actually be converted + // to a T*. Lets us give a compilation error for this: + // DATAVECTOR_BASE(D, B); + // B* bb[] = ... + // DataVector<D> d; + // d.insert (d.begin(), bb, bb+1); + // which would otherwise compile. + typedef typename std::iterator_traits<InputIterator>::value_type ittype; + BOOST_STATIC_ASSERT ((::boost::is_convertible<ittype, const T*>::value)); + + // Ensure we're not being called via a base class. + testInsert ("insert"); + size_t idx = position - this->begin(); + size_t old_sz = this->m_pCont.size(); + this->m_pCont.insert(position.base(), first, last); + size_t n = this->m_pCont.size() - old_sz; + this->shift (idx, n); + this->moveAux (idx, first, last); +} + + +#if __cplusplus > 201100 +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param l An initializer list. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +void DataVector<T, BASE>::insert(iterator position, + std::initializer_list<value_type> l) +{ + insert (position, l.begin(), l.end()); +} +#endif + + +/** + * @brief Insert the contents of another @c DataVector, + * with auxiliary data copied via move semantics. + * @param position Iterator before which the new elements will be added. + * @param other The vector to add. + * + * The ownership mode of this vector must be the same as @c other; + * otherwise, an exception will be thrown. + * + * If both vectors are view vectors, then this is the same + * as <code> insert (position, other.begin(), other.end()) </code>. + * + * Otherwise, the elements from @c other will be inserted into this vector. + * This vector will take ownership of the elements, and the ownership + * mode of @c other will be changed to @c VIEW_ELEMENTS. + * Auxiliary data for these elements will be transferred, + * using move semantics if possible. (Thus, the auxiliary store + * for @c other may be modified and must not be locked.) + * Finally, the auxiliary store pointer for @c other will be cleared + * (but the store itself will not be deleted since it's not owned + * by the vector). + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +void +DataVector<T, BASE>::insertMove (iterator position, DataVector& other) +{ + if (this->m_ownPolicy != other.ownPolicy()) + throw SG::ExcInsertMoveOwnershipMismatch(); + + if (this->m_ownPolicy == SG::VIEW_ELEMENTS) { + this->insert (position, other.begin(), other.end()); + return; + } + + testInsert ("insertMove"); + size_t pos = position.base() - this->m_pCont.begin(); + this->m_pCont.insert (position.base(), other.begin(), other.end()); + this->setIndices (this->begin()+pos, this->end(), pos); + other.m_ownPolicy = SG::VIEW_ELEMENTS; + + SG::IAuxStore* otherStore = other.getStore(); + if (otherStore) { + SG::IAuxStore* store = this->getStore(); + if (store) { + if (!store->insertMove (pos, *otherStore)) + this->clearCache(); + } + else if (this->hasStore()) + throw SG::ExcConstAuxData ("insertMove"); + other.setStore (static_cast<SG::IAuxStore*>(nullptr)); + } + else if (other.hasStore()) + throw SG::ExcConstAuxData ("insertMove"); +} + + +//=== Erasure operations. + + +/** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ +template <class T, class BASE> +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::erase(iterator position) +{ + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + this->clearIndex (position); + iterator ret (this->erase_base (position.base()), this); + this->shift (ret - this->begin() + 1, -1); + return ret; +} + + +/** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T, class BASE> +typename DataVector<T, BASE>::iterator +DataVector<T, BASE>::erase(iterator first, iterator last) +{ + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + this->clearIndices (first, last); + iterator ret (this->erase_base (first.base(), last.base()), this); + this->shift (ret - this->begin() + (last-first), -(last-first)); + return ret; +} + + +/** + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ +template <class T, class BASE> +void DataVector<T, BASE>::pop_back() +{ + if (!this->m_pCont.empty()) { + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete this->m_pCont.back(); + else + this->clearIndex (iterator (this->m_pCont.end() - 1, this)); + this->m_pCont.pop_back(); + SG::AuxVectorBase::resize<DataVector> (this->m_pCont.size()); + } +} + + +/** + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::clear() +{ + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + this->clearIndices (begin(), end()); + this->erase_base (this->m_pCont.begin(), this->m_pCont.end()); + SG::AuxVectorBase::resize<DataVector> (0); +} + + +//=== Swap and sort. + + +/** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataVector in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataVector. + * + * Warning: If this container has auxiliary data, then this + * is an O(N) operation, not O(1). + */ +template <class T, class BASE> +void DataVector<T, BASE>::swap(DataVector& rhs) +{ + testInsert ("swap"); + rhs.testInsert ("swap"); + std::swap(this->m_ownPolicy, rhs.m_ownPolicy); + SG::AuxVectorBase::swap (rhs); + this->m_pCont.swap(rhs.m_pCont); + this->setIndices (this->begin(), this->end()); + rhs.setIndices (rhs.begin(), rhs.end()); +} + + +/** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ +template <class T, class BASE> +void DataVector<T, BASE>::iter_swap (iterator a, iterator b) +{ + ATHCONTAINERS_ASSERT (a.ownPolicy() == b.ownPolicy()); + a.testInsert ("iter_swap"); + b.testInsert ("iter_swap"); + std::iter_swap (a.base(), b.base()); + DataVector* acont = a.container(); + DataVector* bcont = b.container(); + if (typename SG::AuxStore_traits<DataVector>::flag()) + acont->swapElementsAux (a.base() - acont->stdcont().begin(), + b.base() - bcont->stdcont().begin(), + DataModel_detail::DVLCast<DataVector>::cast(*a.base()), + DataModel_detail::DVLCast<DataVector>::cast(*b.base()), + bcont); +} + + +/** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ +template <class T, class BASE> +void DataVector<T, BASE>::sort() +{ + typedef std::less<typename PtrVector::value_type> less; + std::sort (this->m_pCont.begin(), this->m_pCont.end(), + DataModel_detail::Compwrapper<DataVector, less> (less())); + this->resortAux (this->begin(), this->end()); +} + + +/** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + */ +template <class T, class BASE> +template <class COMPARE> +void DataVector<T, BASE>::sort(COMPARE comp) +{ + std::sort (this->m_pCont.begin(), this->m_pCont.end(), + DataModel_detail::Compwrapper<DataVector, COMPARE> (comp)); + this->resortAux (this->begin(), this->end()); +} + + +//=== Non-standard operations. + + +/** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElement New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +void DataVector<T, BASE>::swapElement(size_type index, + value_type newElem, + reference oldElem) +{ + testInsert ("swapElement"); + oldElem = + DataModel_detail::DVLCast<DataVector>::cast(this->m_pCont[index]); + this->clearIndex (iterator (this->m_pCont.begin() + index, this)); + this->m_pCont[index] = newElem; + this->moveAux (index, newElem); +} + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +void DataVector<T, BASE>::swapElement(iterator pos, + value_type newElem, + reference oldElem) +{ + testInsert ("swapElement"); + oldElem = + DataModel_detail::DVLCast<DataVector>::cast(*pos.base()); + this->clearIndex (pos); + *pos.base() = newElem; + this->moveAux (pos.base() - this->m_pCont.begin(), newElem); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElement New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +void DataVector<T, BASE>::swapElement(size_type index, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + testInsert ("swapElement"); + oldElem = std::unique_ptr<base_value_type> + (DataModel_detail::DVLCast<DataVector>::cast(this->m_pCont[index])); + this->clearIndex (iterator (this->m_pCont.begin() + index, this)); + value_type ptr = newElem.release(); + this->m_pCont[index] = ptr; + this->moveAux (index, ptr); +} + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T, class BASE> +void DataVector<T, BASE>::swapElement(iterator pos, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + testInsert ("swapElement"); + oldElem = std::unique_ptr<base_value_type> + (DataModel_detail::DVLCast<DataVector>::cast(*pos.base())); + this->clearIndex (pos); + value_type ptr = newElem.release(); + *pos.base() = ptr; + this->moveAux (pos.base() - this->m_pCont.begin(), ptr); +} +#endif +#endif + + +/** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T, class BASE> +void DataVector<T, BASE>::clear (SG::OwnershipPolicy ownPolicy) +{ + this->clear(); + this->m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, + SG::DEFAULT_TRACK_INDICES); +} + + +/** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T, class BASE> +void DataVector<T, BASE>::clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices) +{ + this->clear(); + this->m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T, class BASE> +const DataModel_detail::DVLInfoBase& DataVector<T, BASE>::dvlinfo() +{ + return s_info; +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T, class BASE> +const DataModel_detail::DVLInfoBase& DataVector<T, BASE>::dvlinfo_v() const +{ + return s_info; +} + + +/** + * @brief Return the offset of a base @c DataVector class. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + * This function is here due to limitations of root 6, which can't + * calculate these offsets correctly from the dictionary if + * virtual derivation is used. + */ +template <class T, class BASE> +int DataVector<T, BASE>::baseOffset (const std::type_info& ti) +{ + DataVector dv; + return baseOffset1 (reinterpret_cast<const char*>(&dv), dv, ti); +} + + +/** + * @brief Convert to @c AuxVectorBase. + * + * Needed to get @x AuxVectorBase from a @c ConstDataVector. + * Present in @c DataVector as well for consistency. + * We only really need it in the base class; however, root6 fails + * constructing a @c TMethodCall for this if there is virtual + * derivation. A workaround is to redeclare this in the derived + * classes too. + */ +template <class T, class BASE> +const SG::AuxVectorBase& DataVector<T, BASE>::auxbase() const +{ + return *this; +} + + +//=== Internal operations. + + +/** + * @brief Helper for @c baseOffset. + * @param p Pointer to the start of the top-level object. + * @param dv Reference to the DataVector object. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + */ +template <class T, class BASE> +int DataVector<T, BASE>::baseOffset1 (const char* p, const DataVector& dv, + const std::type_info& ti) +{ + if (typeid(DataVector) == ti) + return reinterpret_cast<const char*>(&dv) - p; + return BASE::baseOffset1 (p, dv, ti); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + */ +template <class T, class BASE> +void DataVector<T, BASE>::resortAux (iterator beg, iterator end) +{ + if (typename SG::AuxStore_traits<DataVector>::flag() && + beg >= this->begin() && end <= this->end()) + { + SG::AuxVectorBase::resortAux (beg-begin(), beg, end); + } +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataVector. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::testInsert (const char* op) +{ + if (ATHCONTAINERS_LIKELY (m_isMostDerived)) + return; + this->testInsertOol (op); +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ +template <class T, class BASE> +void DataVector<T, BASE>::testInsertOol (const char* op) +{ + this->setMostDerived(); + if (!m_isMostDerived) + throw SG::ExcInsertionInBaseClass (op, typeid(DataVector), dv_typeid()); +} + + +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class T, class BASE> +void DataVector<T, BASE>::assignElement (typename BaseContainer::iterator pos, + value_type newElem) +{ + testInsert ("assignElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + else + this->clearIndex (iterator (pos, this)); + *pos = newElem; + this->moveAux (pos - this->m_pCont.begin(), newElem); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The container must own its elements. + * Auxiliary data are copied if appropriate. + */ +template <class T, class BASE> +void +DataVector<T, BASE>::assignElement (typename BaseContainer::iterator pos, + std::unique_ptr<base_value_type> newElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + testInsert ("assignElement"); + delete *pos; + value_type ptr = newElem.release(); + *pos = ptr; + this->moveAux (pos - this->m_pCont.begin(), ptr); +} +#endif +#endif + + +/** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class T, class BASE> +void +DataVector<T, BASE>::assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem) +{ + testInsert ("assignBaseElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + else + this->clearIndex (iterator (pos, this)); + *pos = newElem; + if (typename SG::AuxStore_traits<DataVector>::flag()) + this->moveAux (pos - this->m_pCont.begin(), + DataModel_detail::DVLCast<DataVector>::cast(newElem)); +} + + +/** + * @brief Shift the auxiliary elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +template <class T, class BASE> +void DataVector<T, BASE>::shift (size_t pos, ptrdiff_t offs) +{ + SG::AuxVectorBase::shift (*this, pos, offs); +} + + +/** + * @brief Helper to shorten calls to @c DataVector_detail::DVLCast. + * @param p The value to convert. + * @return The value as a @c const @c T*. + * + * The conversion will be done with @c static_cast if possible, + * with @c dynamic_cast otherwise. + */ +template <class T, class BASE> +inline +const T* +DataVector<T, BASE>::do_cast (const typename PtrVector::value_type p) +{ + return DataModel_detail::DVLCast<DataVector>::cast (p); +} + + +/** + * @brief Find the most-derived @c DataVector class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * This is used to generate a nice error message when the most-derived + * check for insertions fails. + * Every @c DataVector defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataVector + * gets run. + */ +template <class T, class BASE> +const std::type_info& DataVector<T, BASE>::dv_typeid() const +{ + return typeid(DataVector); +} + + +/** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ +template <class T, class BASE> +inline +void DataVector<T, BASE>::clearMostDerived() +{ + this->m_isMostDerived = false; + BASE::clearMostDerived(); +} + + +/** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ +template <class T, class BASE> +void DataVector<T, BASE>::setMostDerived() +{ + m_isMostDerived = true; + BASE::clearMostDerived(); +} + + +/// The DV/DL info struct for this class. +template <class T, class BASE> +DataModel_detail::DVLInfo<DataVector<T> > DataVector<T, BASE>::s_info; + + +//**************************************************************************** +// Specialized (base) DataVector implementation. +// + + +#ifndef __CINT__ // I don't think CINT will be able to read this. + +// An abbreviation for the DataVector specialization to try to make +// things a little more readable. +#define DATAVECTOR DataVector<T, DataModel_detail::NoBase> + + +//=== Constructors, destructors, assignment. + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class T> +inline +DATAVECTOR::DataVector + (SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*=SG::DEFAULT_TRACK_INDICES*/) + : m_ownPolicy(ownPolicy) +{ + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); + this->m_isMostDerived = true; +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + * + * By default, a @c DataVector will own its elements. + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class T> +inline +DATAVECTOR::DataVector + (size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::OWN_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*= SG::DEFAULT_TRACK_INDICES*/) + : m_ownPolicy(ownPolicy), + m_pCont (n) +{ + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); + this->m_isMostDerived = true; +} + + +/** + * @brief Copy constructor. + * @param rhs The container from which to copy. + * + * This is a `shallow' copy; the new container will not own its elements. + */ +template <class T> +inline +DATAVECTOR::DataVector(const DataVector& rhs) + : AuxVectorBase(), + m_ownPolicy(SG::VIEW_ELEMENTS), + m_pCont(rhs.m_pCont) +{ + this->template initAuxVectorBase<DataVector> (m_ownPolicy, + SG::DEFAULT_TRACK_INDICES); + // Leave m_isMostDerived false here, because we may be being called + // from a derived class implicit copy constructor. The flags will get + // set correctly when @c testInsert gets called. +} + + +#if __cplusplus > 201100 +/** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class T> +inline +DATAVECTOR::DataVector(DataVector&& rhs) + : AuxVectorBase (std::move (rhs)), + m_ownPolicy(rhs.m_ownPolicy), + m_pCont(std::move (rhs.m_pCont)) +{ + // Need to reset the container pointer on elements. + this->setIndices (this->begin(), this->end()); + + // This doesn't get called from derived classes. + // Go ahead and set this flag now. + m_isMostDerived = true; +} +#endif + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * By default, a @c DataVector will own its elements (and take ownership + * of the pointers passed to this constructor). + * To avoid this, pass @c SG::VIEW_ELEMENTS for @a ownPolicy. + */ +template <class T> +template <class InputIterator> +inline +DATAVECTOR::DataVector + (InputIterator first, + InputIterator last, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*= SG::DEFAULT_TRACK_INDICES*/, + SG::IAuxStore* store /*= 0*/) + : m_ownPolicy(ownPolicy), + m_pCont(first, last) +{ + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); + this->m_isMostDerived = true; + if (store) + this->setStore (store); + this->moveAux (0, first, last); +} + + +#if __cplusplus > 201100 +/** + * @brief Constructor from an initializer list. + * @param l An initializer list. + * @param last The end of the range to put in the new container. + * @param ownPolicy The ownership mode for the container. + * @param trackIndices The index tracking policy. + * @param store An associated auxiliary data store. + * + * + * A @c DataVector constructed this way will *not* own its elements + * by default. To change this, pass @c SG::OWN_ELEMENTS for @a ownPolicy. + */ +template <class T> +inline +DATAVECTOR::DataVector + (std::initializer_list<value_type> l, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/, + SG::IndexTrackingPolicy trackIndices /*= SG::DEFAULT_TRACK_INDICES*/, + SG::IAuxStore* store /*= 0*/) + : DataVector (l.begin(), l.end(), ownPolicy, trackIndices, store) +{ +} +#endif + + +/** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the @c DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +inline +DATAVECTOR& DATAVECTOR::operator= (const DataVector& rhs) +{ + if (&rhs != this) { + // Ensure we're not being called via a base class. + testInsert ("assignment operator"); + clear(); // Release any currently-owned elements. + m_ownPolicy = SG::VIEW_ELEMENTS; + this->setStore ((SG::IConstAuxStore*)0); + this->template initAuxVectorBase<DataVector> (m_ownPolicy, + SG::DEFAULT_TRACK_INDICES); + m_pCont = rhs.m_pCont; + } + return *this; +} + + +#if __cplusplus > 201100 +/** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class T> +DATAVECTOR& DATAVECTOR::operator= (DATAVECTOR&& rhs) +{ + if (this != &rhs) { + // Ensure we're not being called via a base class. + testInsert ("assignment operator"); + + SG::AuxVectorBase::operator= (std::move (rhs)); + this->m_ownPolicy = rhs.m_ownPolicy; + this->m_pCont = std::move (rhs.m_pCont); + + // Need to reset the container pointer on elements. + this->setIndices (this->begin(), this->end()); + } + return *this; +} + + +/** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T> +inline +DATAVECTOR& DATAVECTOR::operator= (std::initializer_list<value_type> l) +{ + this->assign (l.begin(), l.end()); + return *this; +} +#endif + + +/** + * @brief Assign from iterators. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T> +template <class InputIterator> +void DATAVECTOR::assign (InputIterator first, + InputIterator last) +{ + // Ensure we're not being called via a base class. + testInsert ("assign"); + clear(); // Release any currently-owned elements. + insert(begin(), first, last); + this->moveAux (0, first, last); +} + + +#if __cplusplus > 201100 +/** + * @brief Assign from an initializer list. + * @param l An initializer list. + * + * Any existing owned elements will be released. + * The @c DataVector's ownership policy determines whether it will take + * ownership of the new elements. + */ +template <class T> +void DATAVECTOR::assign (std::initializer_list<value_type> l) +{ + this->assign (l.begin(), l.end()); +} +#endif + + +/** + * @brief Destructor. + * + * If this container owns its elements, the contained elements will + * be deleted as well. Before doing this, the destructor will scan + * for duplicate pointers (takes @f$n \log n@f$ time); duplicates are only + * destroyed once. Duplicates should, however, be considered an error; + * don't rely on this behavior. + */ +template <class T> +DATAVECTOR::~DataVector() +{ + if (m_ownPolicy == SG::OWN_ELEMENTS) { + typename PtrVector::iterator new_end = + DataVector_detail::remove_duplicates(m_pCont.begin(), m_pCont.end()); + typename PtrVector::iterator iter = m_pCont.begin(); + while (iter != new_end) + delete *(iter++); + } +} + + +//=== Size and capacity. + + +/** + * @brief Returns the number of elements in the collection. + */ +template <class T> +inline +typename DATAVECTOR::size_type DATAVECTOR::size() const +{ + return m_pCont.size(); +} + + +/** + * @brief Returns the number of elements in the collection. + * + * This version is virtual, to be callable from the AuxData + * base class. + */ +template <class T> +inline +typename DATAVECTOR::size_type DATAVECTOR::size_v() const +{ + return this->size(); +} + + +/** + * @brief Returns the @c size() of the largest possible collection. + */ +template <class T> +inline +typename DATAVECTOR::size_type DATAVECTOR::max_size() const +{ + return m_pCont.max_size(); +} + + +/** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * + * Note that this function differs from the standard in that it does + * not allow specifying the value of any inserted elements. + * They will always be 0. + * + * If the container is shrunk, elements will be deleted as with @c erase(). + */ +template <class T> +void DATAVECTOR::resize(size_type sz) +{ + if (sz < this->size()) { + this->erase (this->begin()+sz, this->end()); + } else { + this->m_pCont.insert(this->m_pCont.end(), sz - this->m_pCont.size(), 0); + } + // xxx ??? Is this redundant with the erase() above? + SG::AuxVectorBase::resize<DataVector> (sz); +} + + +/** + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + */ +template <class T> +inline +typename DATAVECTOR::size_type DATAVECTOR::capacity() const +{ + return m_pCont.capacity(); +} + + +/** + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + * + * This version is virtual, to be callable from the AuxData + * base class. + */ +template <class T> +inline +typename DATAVECTOR::size_type DATAVECTOR::capacity_v() const +{ + return capacity(); +} + + +/** + * @brief Returns @c true if the collection is empty. + */ +template <class T> +inline +bool DATAVECTOR::empty() const +{ + return m_pCont.empty(); +} + + +/** + * @brief Attempt to preallocate enough memory for a specified number + * of elements. + * @param n Number of elements required. + */ +template <class T> +inline +void DATAVECTOR::reserve (size_type n) +{ + m_pCont.reserve (n); + SG::AuxVectorBase::reserve<DataVector> (n); +} + + +#if __cplusplus > 201100 +/** + * @brief Change the vector capacity to match the current size. + * + * Note: this does not affect auxiliary data. + */ +template <class T> +inline +void DATAVECTOR::shrink_to_fit() +{ + m_pCont.shrink_to_fit(); +} +#endif + + +//=== Element access. + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * No bounds checking is done. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T> +inline +const T* DATAVECTOR::operator[] (size_type n) const +{ + return m_pCont[n]; +} + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * This is a synonym for operator[] const, to be used when calling from root + * (where we can't readily call just the const version of a method). + */ +template <class T> +inline +const T* DATAVECTOR::get (size_type n) const +{ + return do_cast(this->m_pCont[n]); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::ElementProxy DATAVECTOR::operator[] (size_type n) +{ + return ElementProxy (m_pCont.begin() + n, this); +} + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T> +inline +const T* DATAVECTOR::at (size_type n) const +{ + return m_pCont.at(n); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::ElementProxy DATAVECTOR::at (size_type n) +{ + // Can't use m_pCont's at here, because we need an iterator. + // So we have to do the bounds check ourselves. + if (n >= size()) + throw std::out_of_range ("DataVector::at range check"); + return ElementProxy (m_pCont.begin() + n, this); +} + + +/** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T> +inline +const T* DATAVECTOR::front() const +{ + return m_pCont.front(); +} + + +/** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c const @c T* rather than a reference. + */ +template <class T> +inline +const T* DATAVECTOR::back() const +{ + return m_pCont.back(); +} + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::ElementProxy DATAVECTOR::front () +{ + return ElementProxy (m_pCont.begin(), this); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference; + * the proxy will handle deleting an owned element if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::ElementProxy DATAVECTOR::back () +{ + return ElementProxy (m_pCont.end()-1, this); +} + + +//=== Iterator creation. + + +/** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_iterator DATAVECTOR::begin() const +{ + return m_pCont.begin(); +} + + +/** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_iterator DATAVECTOR::end() const +{ + return m_pCont.end(); +} + + +/** + * @brief Return an @c iterator pointing at the beginning + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::iterator DATAVECTOR::begin() +{ + return iterator (m_pCont.begin(), this); +} + + +/** + * @brief Return an @c iterator pointing past the end + * of the collection. + * @return An @c iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::iterator DATAVECTOR::end() +{ + return iterator (m_pCont.end(), this); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_reverse_iterator DATAVECTOR::rbegin() const +{ + return const_reverse_iterator (m_pCont.end()); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_reverse_iterator DATAVECTOR::rend() const +{ + return const_reverse_iterator (const_iterator (m_pCont.begin())); +} + + +/** + * @brief Return a @c reverse_iterator pointing past the end + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::reverse_iterator DATAVECTOR::rbegin() +{ + return reverse_iterator(iterator (m_pCont.end(), this)); +} + + +/** + * @brief Return a @c reverse_iterator pointing at the beginning + * of the collection. + * @return A @c reverse_iterator. + * + * Note that dereferencing the iterator will yield a proxy rather + * than a reference; the proxy will handle deleting an owned element + * if it's assigned to. + */ +template <class T> +inline +typename DATAVECTOR::reverse_iterator DATAVECTOR::rend() +{ + return reverse_iterator(iterator (m_pCont.begin(), this)); +} + + +/** + * @brief Return a @c const_iterator pointing at the beginning + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_iterator DATAVECTOR::cbegin() const +{ + return m_pCont.begin(); +} + + +/** + * @brief Return a @c const_iterator pointing past the end + * of the collection. + * @return A @c const_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_iterator DATAVECTOR::cend() const +{ + return m_pCont.end(); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing past the end + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_reverse_iterator DATAVECTOR::crbegin() const +{ + return const_reverse_iterator (m_pCont.end()); +} + + +/** + * @brief Return a @c const_reverse_iterator pointing at the beginning + * of the collection. + * @return A @c const_reverse_iterator. + * + * Note that dereferencing the iterator will yield a @c const @c T* rather + * than a reference. + */ +template <class T> +inline +typename DATAVECTOR::const_reverse_iterator DATAVECTOR::crend() const +{ + return const_reverse_iterator (const_iterator (m_pCont.begin())); +} + + +//=== Insertion operations. + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +inline +void DATAVECTOR::push_back(value_type pElem) +{ + // Ensure we're not being called via a base class. + testInsert ("push_back"); + m_pCont.push_back(pElem); + SG::AuxVectorBase::resize<DataVector> (this->size()); + if (pElem) + this->moveAux (this->size()-1, pElem, false, true); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +inline +void DATAVECTOR::push_back(std::unique_ptr<base_value_type> pElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + // Ensure we're not being called via a base class. + testInsert ("push_back"); + value_type ptr = pElem.release(); + m_pCont.push_back(ptr); + SG::AuxVectorBase::resize<DataVector> (this->size()); + if (ptr) + this->moveAux (this->size()-1, ptr, false, true); +} +#endif +#endif + + +/** + * @brief Add an element to the end of the collection. + * @param pElem The element to add to the collection. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c push_back. + * It's included just for interface compatibility with `std::vector`. + */ +template <class T> +inline +void DATAVECTOR::emplace_back(value_type pElem) +{ + this->push_back (pElem); +} + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +inline +typename DATAVECTOR::iterator +DATAVECTOR::insert(iterator position, value_type pElem) +{ + // Ensure we're not being called via a base class. + testInsert ("insert"); + iterator ret (m_pCont.insert(position.base(), pElem), this); + this->shift (ret - this->begin(), 1); + this->moveAux (ret-this->begin(), pElem); + return ret; +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container must be an owning container. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +inline +typename DATAVECTOR::iterator +DATAVECTOR::insert(iterator position, std::unique_ptr<base_value_type> pElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + // Ensure we're not being called via a base class. + testInsert ("insert"); + value_type ptr = pElem.release(); + iterator ret (m_pCont.insert(position.base(), ptr), this); + this->shift (ret - this->begin(), 1); + this->moveAux (ret-this->begin(), ptr); + return ret; +} +#endif +#endif + + +/** + * @brief Add a new element to the collection. + * @param position Iterator before which the element will be added. + * @param pElem The element to add to the collection. + * @return An iterator that points to the inserted data. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + * + * For @c DataVector, this is just the same as @c insert. + * It's included just for interface compatibility with `std::vector`. + */ +template <class T> +inline +typename DATAVECTOR::iterator +DATAVECTOR::emplace(iterator position, value_type pElem) +{ + return this->insert (position, pElem); +} + + +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param first The start of the range to put in the container. + * @param last The end of the range to put in the container. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +template <class InputIterator> +inline +void +DATAVECTOR::insert (iterator position, InputIterator first, InputIterator last) +{ + // Ensure we're not being called via a base class. + testInsert ("insert"); + size_t idx = position - this->begin(); + size_t old_sz = this->m_pCont.size(); + m_pCont.insert(position.base(), first, last); + size_t n = this->m_pCont.size() - old_sz; + this->shift (idx, n); + this->moveAux (idx, first, last); +} + + +#if __cplusplus > 201100 +/** + * @brief Add a group of new elements to the collection. + * @param position Iterator before which the element will be added. + * @param l An initializer list. + * + * The container's ownership policy will determine if it takes ownership + * of the new element. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +inline +void +DATAVECTOR::insert (iterator position, std::initializer_list<value_type> l) +{ + this->insert (position, l.begin(), l.end()); +} +#endif + + +/** + * @brief Insert the contents of another @c DataVector, + * with auxiliary data copied via move semantics. + * @param position Iterator before which the new elements will be added. + * @param other The vector to add. + * + * The ownership mode of this vector must be the same as @c other; + * otherwise, an exception will be thrown. + * + * If both vectors are view vectors, then this is the same + * as <code> insert (position, other.begin(), other.end()) </code>. + * + * Otherwise, the elements from @c other will be inserted into this vector. + * This vector will take ownership of the elements, and the ownership + * mode of @c other will be changed to @c VIEW_ELEMENTS. + * Auxiliary data for these elements will be transferred, + * using move semantics if possible. (Thus, the auxiliary store + * for @c other may be modified and must not be locked.) + * Finally, the auxiliary store pointer for @c other will be cleared + * (but the store itself will not be deleted since it's not owned + * by the vector). + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +void +DATAVECTOR::insertMove (iterator position, DataVector& other) +{ + if (this->m_ownPolicy != other.ownPolicy()) + throw SG::ExcInsertMoveOwnershipMismatch(); + + if (this->m_ownPolicy == SG::VIEW_ELEMENTS) { + this->insert (position, other.begin(), other.end()); + return; + } + + testInsert ("insertMove"); + size_t pos = position.base() - this->m_pCont.begin(); + this->m_pCont.insert (position.base(), other.begin(), other.end()); + this->setIndices (this->begin()+pos, this->end(), pos); + other.m_ownPolicy = SG::VIEW_ELEMENTS; + + SG::IAuxStore* otherStore = other.getStore(); + if (otherStore) { + SG::IAuxStore* store = this->getStore(); + if (store) { + if (!store->insertMove (pos, *otherStore)) + this->clearCache(); + } + else if (this->hasStore()) + throw SG::ExcConstAuxData ("insertMove"); + other.setStore (static_cast<SG::IAuxStore*>(nullptr)); + } + else if (other.hasStore()) + throw SG::ExcConstAuxData ("insertMove"); +} + + +//=== Erasure operations. + + +/** + * @brief Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * If the container owns its elements, then the pointed-to element + * will be deleted. + */ +template <class T> +inline +typename DATAVECTOR::iterator DATAVECTOR::erase(iterator position) +{ + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + this->clearIndex (position); + iterator ret (this->erase_base (position.base()), this); + this->shift (ret - this->begin() + 1, -1); + return ret; +} + + +/** + * @brief Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +inline +typename DATAVECTOR::iterator DATAVECTOR::erase(iterator first, iterator last) +{ + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + this->clearIndices (first, last); + iterator ret (this->erase_base (first.base(), last.base()), this); + this->shift (ret - this->begin() + (last-first), -(last-first)); + return ret; +} + + +/** + * @brief Remove the last element from the collection. + * + * If the container owns its elements, then the removed element + * will be deleted. + */ +template <class T> +void DATAVECTOR::pop_back() +{ + if (!m_pCont.empty()) { + if (m_ownPolicy == SG::OWN_ELEMENTS) + delete m_pCont.back(); + else + this->clearIndex (m_pCont.end() - 1); + m_pCont.pop_back(); + SG::AuxVectorBase::resize<DataVector> (this->m_pCont.size()); + } +} + + +/** + * @brief Erase all the elements in the collection. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +inline +void DATAVECTOR::clear() +{ + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + this->clearIndices (begin(), end()); + this->erase_base (m_pCont.begin(), m_pCont.end()); + SG::AuxVectorBase::resize<DataVector> (0); +} + + +//=== Swap and sort. + + +/** + * @brief Swap this collection with another. + * @param rhs The collection with which to swap. + * + * Ownership is swapped along with the collection content. + * + * Note: this method may only be called using the most-derived + * @c DataVector in the hierarchy. The @a rhs must also be + * referenced using the most-derived @c DataVector. + * + * Warning: If this container has auxiliary data, then this + * is an O(N) operation, not O(1). + */ +template <class T> +void DATAVECTOR::swap(DataVector& rhs) +{ + testInsert ("swap"); + rhs.testInsert ("swap"); + std::swap(m_ownPolicy, rhs.m_ownPolicy); + SG::AuxVectorBase::swap (rhs); + m_pCont.swap(rhs.m_pCont); + this->setIndices (this->begin(), this->end()); + rhs.setIndices (rhs.begin(), rhs.end()); +} + + +/** + * @brief Swap the referents of two @c DataVector iterators. + * @param a The first iterator for the swap. + * @param b The second iterator for the swap/ + */ +template <class T> +void DATAVECTOR::iter_swap (iterator a, iterator b) +{ + ATHCONTAINERS_ASSERT (a.ownPolicy() == b.ownPolicy()); + a.testInsert ("iter_swap"); + b.testInsert ("iter_swap"); + std::iter_swap (a.base(), b.base()); + DataVector* acont = a.container(); + DataVector* bcont = b.container(); + if (typename SG::AuxStore_traits<DataVector>::flag()) + acont->swapElementsAux (a.base() - acont->stdcont().begin(), + b.base() - bcont->stdcont().begin(), + *a.base(), + *b.base(), + bcont); +} + + +/** + * @brief Sort the container. + * + * This just sorts by pointer value, so it's probably not very useful. + */ +template <class T> +void DATAVECTOR::sort() +{ + std::sort(m_pCont.begin(), m_pCont.end()); + this->resortAux (this->begin(), this->end()); +} + + +/** + * @brief Sort the container with a user-specified comparison operator. + * @param comp Functional to compare two values. + */ +template <class T> +template <class COMPARE> +void DATAVECTOR::sort(COMPARE comp) +{ + std::sort(m_pCont.begin(), m_pCont.end(), comp); + this->resortAux (this->begin(), this->end()); +} + + +//=== Non-standard operations. + + +/** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElement New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +void +DATAVECTOR::swapElement (size_type index, + value_type newElem, + reference oldElem) +{ + testInsert ("swapElement"); + oldElem = m_pCont[index]; + this->clearIndex (iterator (m_pCont.begin() + index, this)); + m_pCont[index] = newElem; + this->moveAux (index, newElem); +} + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. If the collection owns its elements, then it will + * take ownership of @a newElem and release (without deleting) + * the element returned through @a oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +void +DATAVECTOR::swapElement (iterator pos, + value_type newElem, + reference oldElem) +{ + testInsert ("swapElement"); + oldElem = *pos.base(); + this->clearIndex (pos); + *pos.base() = newElem; + this->moveAux (pos.base() - this->m_pCont.begin(), newElem); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Swap one element out of the container. + * @param index Index of the element in the container to swap. + * @param newElement New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a index of the + * collection (no bounds checking). Then element @a index is set + * to @newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +void +DATAVECTOR::swapElement (size_type index, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + testInsert ("swapElement"); + oldElem = std::unique_ptr<base_value_type> (m_pCont[index]); + this->clearIndex (iterator (m_pCont.begin() + index, this)); + value_type ptr = newElem.release(); + m_pCont[index] = ptr; + this->moveAux (index, ptr); +} + + +/** + * @brief Swap one element out of the container. + * @param pos The element in the container to swap. + * @param newElem New element to put in the container. + * May be 0. + * @param oldElem Reference to receive the element removed from the + * container. + * + * Reference @a oldElem is initialized with element @a pos of the + * collection (no bounds checking). Then element @a index is set + * to @c newElem. + * + * The collection must own its elements to use its interface. + * The collection will take ownership of @c newElem and will return + * ownership of @c oldElem. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class T> +void +DATAVECTOR::swapElement (iterator pos, + std::unique_ptr<base_value_type> newElem, + std::unique_ptr<base_value_type>& oldElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + testInsert ("swapElement"); + oldElem = std::unique_ptr<base_value_type> (*pos.base()); + this->clearIndex (pos); + value_type ptr = newElem.release(); + *pos.base() = ptr; + this->moveAux (pos.base() - this->m_pCont.begin(), ptr); +} +#endif +#endif + + +/** + * @brief Return the underlying @c std::vector of the container. + * @return Reference to the @c std::vector actually holding the collection. + * + * Note that @c DataVector<T>::stdcont does not necessarily return + * a @c std::vector<T*> if @c DataVector inheritance is being used. + */ +template <class T> +inline +const typename DATAVECTOR::PtrVector& DATAVECTOR::stdcont() const +{ + return m_pCont; +} + + +/** + * @brief Return the ownership policy setting for this container. + */ +template <class T> +inline +SG::OwnershipPolicy DATAVECTOR::ownPolicy() const +{ + return m_ownPolicy; +} + + +/** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +void DATAVECTOR::clear (SG::OwnershipPolicy ownPolicy) +{ + clear(); + m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, + SG::DEFAULT_TRACK_INDICES); +} + + +/** + * @brief Erase all the elements in the collection, and reset + * the ownership mode. + * @param ownPolicy The new ownership policy of the container. + * @param trackIndices The index tracking policy. + * + * If the container owns its elements, then the removed elements + * will be deleted. Any duplicates will be removed in this process, + * but don't rely on this. + */ +template <class T> +void DATAVECTOR::clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices) +{ + clear(); + m_ownPolicy = ownPolicy; + this->template initAuxVectorBase<DataVector> (ownPolicy, trackIndices); +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T> +const DataModel_detail::DVLInfoBase& DATAVECTOR::dvlinfo() +{ + return s_info; +} + + +/** + * @brief Return the DV/DL info struct for this class. + * + * This can be used to make sure that it's instantiated. + */ +template <class T> +const DataModel_detail::DVLInfoBase& DATAVECTOR::dvlinfo_v() const +{ + return s_info; +} + + +/** + * @brief Return the offset of a base @c DataVector class. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + * This function is here due to limitations of root 6, which can't + * calculate these offsets correctly from the dictionary if + * virtual derivation is used. + */ +template <class T> +int DATAVECTOR::baseOffset (const std::type_info& ti) +{ + if (typeid(DataVector) == ti) + return 0; + return -1; +} + + +/** + * @brief Convert to @c AuxVectorBase. + * + * Needed to get @x AuxVectorBase from a @c ConstDataVector. + * Present in @c DataVector as well for consistency. + */ +template <class T> +inline +const SG::AuxVectorBase& DATAVECTOR::auxbase() const +{ + return *this; +} + + +//=== Internal operations. + + +/** + * @brief Helper for @c baseOffset. + * @param p Pointer to the start of the top-level object. + * @param dv Reference to the DataVector object. + * @param ti @c std::type_info of the desired class. + * + * If @c ti represents a @c DataVector base class of this one, + * then return the offset of that base class. Otherwise, return -1. + * + */ +template <class T> +int DATAVECTOR::baseOffset1 (const char* p, const DataVector& dv, + const std::type_info& ti) +{ + if (typeid(DataVector) == ti) + return reinterpret_cast<const char*>(&dv) - p; + return -1; +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + */ +template <class T> +void DATAVECTOR::resortAux (iterator beg, iterator end) +{ + if (typename SG::AuxStore_traits<DataVector>::flag() && + beg >= this->begin() && end <= this->end()) + { + SG::AuxVectorBase::resortAux (beg-begin(), beg, end); + } +} + + +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class T> +void DATAVECTOR::assignElement (typename BaseContainer::iterator pos, + value_type newElem) +{ + testInsert ("assignElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + else + this->clearIndex (iterator (pos, this)); + *pos = newElem; + this->moveAux (pos - this->m_pCont.begin(), newElem); +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Handle element assignment. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The container must own its elements. + * Auxiliary data are copied if appropriate. + */ +template <class T> +void +DATAVECTOR::assignElement (typename BaseContainer::iterator pos, + std::unique_ptr<base_value_type> newElem) +{ + // Container must own its elements. + if (this->m_ownPolicy != SG::OWN_ELEMENTS) + SG::throwExcNonowningContainer(); + + testInsert ("assignElement"); + delete *pos; + value_type ptr = newElem.release(); + *pos = ptr; + this->moveAux (pos - this->m_pCont.begin(), ptr); +} +#endif +#endif + + +/** + * @brief Handle element assignment from a base pointer. + * @param pos Position in the container to assign. + * @param newElem The new element to assign. + * + * The old element is freed if this container owns elements. + * Auxiliary data are copied if appropriate. + */ +template <class T> +void DATAVECTOR::assignBaseElement (typename BaseContainer::iterator pos, + typename BaseContainer::value_type newElem) +{ + testInsert ("assignBaseElement"); + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete *pos; + else + this->clearIndex (iterator (pos, this)); + *pos = newElem; + if (typename SG::AuxStore_traits<DataVector>::flag()) + this->moveAux (pos - this->m_pCont.begin(), newElem); +} + + +/** + * @brief Shift the auxiliary elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * The elements in the container should have already been shifted; + * this operation will then adjust the element indices and also shift + * the elements in the vectors for all aux data items. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +template <class T> +void DATAVECTOR::shift (size_t pos, ptrdiff_t offs) +{ + SG::AuxVectorBase::shift (*this, pos, offs); +} + + +/** + * @brief Helper to shorten calls to @c DataModel_detail::DVLCast. + * @param p The value to convert. + * @return The value as a @c const @c T*. + * + * This is a no-op for the base class. + */ +template <class T> +inline +const T* DATAVECTOR::do_cast (const typename PtrVector::value_type p) +{ + return p; +} + + +/** + * @brief Find the most-derived @c DataVector class in the hierarchy. + * @return The @c type_info for the class for which this method gets run. + * + * This is used to generate a nice error message when the most-derived + * check for insertions fails. + * Every @c DataVector defines this virtual method, so when it's + * called, the one corresponding to the most-derived @c DataVector + * gets run. + */ +template <class T> +const std::type_info& DATAVECTOR::dv_typeid() const +{ + return typeid(DataVector); +} + + +/** + * @brief Helper for @c erase(). Remove element at a given position. + * @param position Iterator pointing to the element to be removed. + * @return An iterator pointing to the next element (or @c end()). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataVector classes. It deals with the + * @c std::vector iterators directly. + */ +template <class T> +typename DATAVECTOR::PtrVector::iterator +DATAVECTOR::erase_base(typename PtrVector::iterator position) +{ + if (m_ownPolicy == SG::OWN_ELEMENTS && position != m_pCont.end()) + delete *position; + return m_pCont.erase(position); +} + + +/** + * @brief Helper for @c erase(). Remove a range of elements. + * @param first Iterator pointing to the first element to be removed. + * @param last Iterator pointing one past the last element to be removed. + * @return An iterator pointing to the element pointed to by @a last + * prior to erasing (or @c end()). + * + * This function factors out common code between @c erase() in the + * base and derived @c DataVector classes. It deals with the + * @c std::vector iterators directly. + */ +template <class T> +typename DATAVECTOR::PtrVector::iterator +DATAVECTOR::erase_base(typename PtrVector::iterator first, + typename PtrVector::iterator last) +{ + if (first == last) return first; + if (m_ownPolicy == SG::OWN_ELEMENTS) { + typename PtrVector::iterator new_end = + DataVector_detail::remove_duplicates(first, last); + typename PtrVector::iterator iter = first; + while (iter != new_end) delete *(iter++); + } + return m_pCont.erase(first, last); +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * In order to maintain type-safety, we can only allow insertions + * using the most-derived instance of @c DataVector. This checks + * this by testing the @c m_isMostDerived, which is set by the constructors + * to true only for the most-derived instance. + * If the test fails, we call to potentially out-of-line code to continue. + */ +template <class T> +inline +void DATAVECTOR::testInsert (const char* op) +{ + if (ATHCONTAINERS_LIKELY (m_isMostDerived)) + return; + this->testInsertOol (op); +} + + +/** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + * + * This continues the test of @c testInsert. There is one case + * where @c m_isMostDerived may not be set correctly. If this container + * was made via copy construction, then all the @c m_isMostDerived flags + * will be false. So we call @c setMostDerived to set the flags correctly + * and test again. If the test fails again, then we raise an exception. + */ +template <class T> +void DATAVECTOR::testInsertOol (const char* op) +{ + this->setMostDerived(); + if (!m_isMostDerived) + throw SG::ExcInsertionInBaseClass (op, typeid(DataVector), dv_typeid()); +} + + +/** + * @brief Clear @c m_isMostDerived for this instance and for all bases. + * + * Called from the constructor after setting @c m_isMostDerived. + */ +template <class T> +inline +void DATAVECTOR::clearMostDerived() +{ + this->m_isMostDerived = false; +} + + +/** + * @brief Set @c m_isMostDerived for this instance and clear it for all bases. + * + * Called from @c testInsert if the test fails. The flag may not have + * been set if this container was made via copy construction, so set + * it appropriately now so we can test again. + */ +template <class T> +void DATAVECTOR::setMostDerived() +{ + m_isMostDerived = true; +} + + +/// The DV/DL info struct for this class. +template <class T> +DataModel_detail::DVLInfo<DataVector<T> > DATAVECTOR::s_info; + + +#undef DATAVECTOR +#endif // not __CINT__ + + +//**************************************************************************** +// Free function implementations. +// + + +/** + * @brief Vector equality comparison. + * @param a A @c DataVector. + * @param b A @c DataVector of the same type as @a x. + * @return True iff the size and elements of the vectors are equal. + * + * This is an equivalence relation. It is linear in the size of the + * vectors. Vectors are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ +template <class T> +bool operator== (const DataVector<T>& a, const DataVector<T>& b) +{ + return a.stdcont() == b.stdcont(); +} + + +/// Based on operator== +template <class T> +bool operator!= (const DataVector<T>& a, const DataVector<T>& b) +{ + return a.stdcont() != b.stdcont(); +} + + +/** + * @brief Vector ordering relation. + * @param a A @c DataVector. + * @param b A @c DataVector of the same type as @a x. + * @return True iff @a x is lexicographically less than @a y. + * + * This is a total ordering relation. It is linear in the size of the + * vectors. Comparisons are done on the pointer values of the elements. + * + * See @c std::lexicographical_compare() for how the determination is made. + */ +template <class T> +bool operator< (const DataVector<T>& a, const DataVector<T>& b) +{ + return a.stdcont() < b.stdcont(); +} + + +/// Based on operator< +template <class T> +bool operator> (const DataVector<T>& a, const DataVector<T>& b) +{ + return a.stdcont() > b.stdcont(); +} + + +/// Based on operator< +template <class T> +bool operator<= (const DataVector<T>& a, const DataVector<T>& b) +{ + return a.stdcont() <= b.stdcont(); +} + + +/// Based on operator< +template <class T> +bool operator>= (const DataVector<T>& a, const DataVector<T>& b) +{ + return a.stdcont() >= b.stdcont(); +} + + +/// See @c DataVector<T, BASE>::swap(). +template <class T> +void swap (DataVector<T>& a, DataVector<T>& b) +{ + a.swap (b); +} + + +/** + * @brief Specialization of @c ClassName for @c DataVector. + * + * This overrides the default implementation of @c ClassName + * to hide @c DataVector's second template parameter. + */ +template <class T> +std::string ClassName<DataVector<T> >::name() +{ + std::string out = "DataVector<"; + out += ClassName<T>::name(); + if (out[out.size()-1] == '>') + out += ' '; + out += '>'; + return out; +} + + +#ifndef XAOD_STANDALONE + + +// Set up initialization of element type BaseInfo +namespace DataVector_detail { +#define DVLTYPE DataVector +#include "AthContainers/tools/DVLEltBaseInfo.icc" +#undef DVLTYPE +} // namespace DataVector_detail + + +#else + + +namespace DataVector_detail { +/// Dummy implementation for the DVLEltBaseInit structure +template< class T > +struct DVLEltBaseInit {}; +} // namespace DataVector_detail + + +#endif // not XAOD_STANDALONE + + + +// We need to specialize the function that DVLInfo uses to create the container +// for DataVector. +/** + * @brief Construct a new container. + * @param nreserve Number of elements for which to reserve space. + * (Ignored if not appropriate.) + * @param cont[out] Pointer to the constructed container. + * (Returned via an argument to allow for template + * argument deduction.) + * + * Specialization for DataVector. + */ +template <class T> +void dvl_makecontainer (size_t nreserve, DataVector<T>*& cont) +{ + cont = new DataVector<T> (SG::VIEW_ELEMENTS); + cont->reserve (nreserve); +} diff --git a/EDM/athena/Control/AthContainers/AthContainers/IndexTrackingPolicy.h b/EDM/athena/Control/AthContainers/AthContainers/IndexTrackingPolicy.h new file mode 100644 index 00000000..aaaa5724 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/IndexTrackingPolicy.h @@ -0,0 +1,53 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IndexTrackingPolicy.h 581165 2014-02-03 10:42:54Z krasznaa $ +/** + * @file IndexTrackingPolicy.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Describes the possible index tracking policies. + * + * If the payload of a container does not derive from @c SG::AuxElement, + * then the container does not track indices (and thus cannot have + * associated aux data). If it does, whether a container will track + * indices (and potentially have aux data) is governed by both + * the ownership policy and the index tracking policy. The default + * value for the index tracking policy is DEFAULT_TRACK_INDICES. In that + * case, we track indices if this container owns its elements + * (OWN_ELEMENTS) and we don't if the container does not down its + * elements (VIEW_ELEMENTS). This is the usual case. However, + * the index tracking policy may also be set to ALWAYS_TRACK_INDICES + * or NEVER_TRACK_INDICES to override this. (The major foreseen use case + * for this is to allow index tracking for a view container populated + * with objects allocated from a @c DataPool.) + */ + + +#ifndef ATHCONTAINERS_INDEXTRACKINGPOLICY_H +#define ATHCONTAINERS_INDEXTRACKINGPOLICY_H + + +namespace SG { + + +enum IndexTrackingPolicy { + /// Default value. Set index tracking based on the ownership policy. + /// If this container owns its elements, then track indices; otherwise do not. + DEFAULT_TRACK_INDICES, + + /// Always track indices, regardless of the setting of the ownership policy. + ALWAYS_TRACK_INDICES, + + /// Never track indices, regardless of the setting of the ownership policy. + NEVER_TRACK_INDICES +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERS_INDEXTRACKINGPOLICY_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/OwnershipPolicy.h b/EDM/athena/Control/AthContainers/AthContainers/OwnershipPolicy.h new file mode 100644 index 00000000..e55a9519 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/OwnershipPolicy.h @@ -0,0 +1,22 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHCONTAINERS_OWNERSHIPPOLICY_H +# define ATHCONTAINERS_OWNERSHIPPOLICY_H + +/** @enum OwnershipPolicy + * @brief describes the possible element ownership policies + * (see e.g. DataVector) + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + *$Id: OwnershipPolicy.h 581165 2014-02-03 10:42:54Z krasznaa $ + */ + +namespace SG { + enum OwnershipPolicy { + OWN_ELEMENTS, ///< this data object owns its elements + VIEW_ELEMENTS ///< this data object is a view, it does not own its elmts + }; +} + +#endif // ATHCONTAINERS_OWNERSHIPPOLICY_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/PackedContainer.h b/EDM/athena/Control/AthContainers/AthContainers/PackedContainer.h new file mode 100644 index 00000000..22a77324 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/PackedContainer.h @@ -0,0 +1,139 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedContainer.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2014 + * @brief Container to hold aux data to be stored in a packed form. + */ + + +#ifndef ATHCONTAINERS_PACKEDCONTAINER_H +#define ATHCONTAINERS_PACKEDCONTAINER_H + + +#include "AthContainersInterfaces/IAuxSetOption.h" +#include "AthContainers/PackedParameters.h" +#include "CxxUtils/override.h" +#include <vector> + + +namespace SG { + + +/** + * @brief Container to hold aux data to be stored in a packed form. + * + * This class acts as a @c std::vector<T> (in fact, it derives from + * that type). However, we set up a special ROOT streamer for this + * type so that when it is saved, it is written in a packed format. + * The details of the packing are given by the @c PackedParameters (which see) + * instance that we hold. + * + * User code should generally not interact with this class directly. + * + * @c PackedContainer may be used as a static auxiliary variable by + * using it instead of the corresponding vector class in the auxiliary + * store class. Packing parameters may then be set by calling @c setOption + * from the constructor for the aux store object. + * + * For dynamic auxiliary variables, the stored vector is automatically + * converted to a @c PackedContainer when @c setOption is called for the + * variable. + */ +template <class T> +class PackedContainer + : public std::vector<T>, public IAuxSetOption +{ +public: + /// We act like this type. + typedef std::vector<T> vector_type; + + + /** + * @brief Constructor. + * + * The packing parameters will be initialized to defaults appropriate + * for type @c T. (See @c PackedParameters.) + */ + PackedContainer(); + + + /** + * @brief Set a packing option. + * @param option The option to set. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ + virtual bool setOption (const AuxDataOption& option) ATH_OVERRIDE; + + + /** + * @brief Set a packing option. + * @param name The option name. + * @param val The option value. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ + bool setOption (const std::string& name, int val); + + + /** + * @brief Set a packing option. + * @param name The option name. + * @param val The option value. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ + bool setOption (const std::string& name, float val); + + + /** + * @brief Set a packing option. + * @param name The option name. + * @param val The option value. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ + bool setOption (const std::string& name, double val); + + + /** + * @brief Return the packing parameters for this container. + */ + const PackedParameters& parms() const; + + + /** + * @brief Set the packing parameters. + * @param parms The new packing parameters. + */ + void setParms (const PackedParameters& parms); + + +private: + /// The packing parameters. + PackedParameters m_parms; +}; + + +} // namespace SG + + +#include "AthContainers/PackedContainer.icc" + + +#endif // not ATHCONTAINERS_PACKEDCONTAINER_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/PackedContainer.icc b/EDM/athena/Control/AthContainers/AthContainers/PackedContainer.icc new file mode 100644 index 00000000..202a243e --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/PackedContainer.icc @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedContainer.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2014 + * @brief Container to hold aux data to be stored in a packed form. + */ + + +namespace SG { + + +/** + * @brief Metafunction to extract the innermost element type + * from a nested vector type. + * + * I.e., vector<vector<... <T> > should yield T. + */ +template <class T> +struct inner_type +{ + typedef T type; +}; +template <class T> +struct inner_type<std::vector<T> > +{ + typedef typename inner_type<T>::type type; +}; + + +/** + * @brief Constructor. + * + * The packing parameters will be initialized to defaults appropriate + * for type @c T. (See @c PackedParameters.) + */ +template <class T> +inline +PackedContainer<T>::PackedContainer() + : m_parms (static_cast<typename inner_type<T>::type>(0)) +{ +} + + +/** + * @brief Set a packing option. + * @param option The option to set. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ +template <class T> +inline +bool PackedContainer<T>::setOption (const AuxDataOption& option) +{ + return m_parms.setOption (option); +} + + +/** + * @brief Set a packing option. + * @param name The option name. + * @param val The option value. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ +template <class T> +inline +bool PackedContainer<T>::setOption (const std::string& name, int val) +{ + return this->setOption (SG::AuxDataOption (name, val)); +} + + +/** + * @brief Set a packing option. + * @param name The option name. + * @param val The option value. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ +template <class T> +inline +bool PackedContainer<T>::setOption (const std::string& name, float val) +{ + return this->setOption (SG::AuxDataOption (name, val)); +} + + +/** + * @brief Set a packing option. + * @param name The option name. + * @param val The option value. + * + * Returns true on success, false otherwise. + * + * See @c PackedParameters::setOptions for details. + */ +template <class T> +inline +bool PackedContainer<T>::setOption (const std::string& name, double val) +{ + return this->setOption (SG::AuxDataOption (name, val)); +} + + +/** + * @brief Return the packing parameters for this container. + */ +template <class T> +inline +const PackedParameters& PackedContainer<T>::parms() const +{ + return m_parms; +} + + +/** + * @brief Set the packing parameters. + * @param parms The new packing parameters. + */ +template <class T> +inline +void PackedContainer<T>::setParms (const PackedParameters& parms) +{ + m_parms = parms; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/PackedConverter.h b/EDM/athena/Control/AthContainers/AthContainers/PackedConverter.h new file mode 100644 index 00000000..a16a465b --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/PackedConverter.h @@ -0,0 +1,191 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedConverter.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper for packing/unpacking a @c PackedContainer to/from a stream. + */ + + +#ifndef ATHCONTAINERS_PACKEDCONVERTER_H +#define ATHCONTAINERS_PACKEDCONVERTER_H + + +#include "AthContainers/PackedParameters.h" +#include "CxxUtils/FloatPacker.h" +#include "CxxUtils/BitPacker.h" +#include "CxxUtils/BitUnpacker.h" +#include <vector> +#include <stdint.h> + + +namespace SG { + + +/** + * @brief Helper for packing/unpacking a @c PackedContainer to/from a stream. + * + * This object should be created with the packing parameters to use. + * After that, call the read or write methods. These are all templated + * methods taking a @c vector<U> as input; this should be the vector + * contained within the @c PackedContainer. Additional overloads + * are supplied taking @c vector<vector<U> >. These read/write the + * element count, then call read/write for each element of the vector. + * This should allow for arbitrary vector nesting. + * + * The methods are also templated on the input/output stream. + * This should support operator<< and operator>> for a uint32_t; + * a ROOT @c TBuffer will satisfy this. + */ +class PackedConverter +{ +public: + /** + * @brief Constructor. + * @param parms The parameters describing the packed data. + */ + PackedConverter (const PackedParameters& parms); + + + /** + * @brief Pack a vector to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ + template <class U, class STREAM> + void write (size_t nelt, + const std::vector<U>& vec, + STREAM& stream); + + + /** + * @brief Pack a nested vector to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ + template <class U, class STREAM> + void write (size_t nelt, + const std::vector<std::vector<U> >& vec, + STREAM& stream); + + + /** + * @brief Unpack a vector from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ + template <class U, class STREAM> + void read (size_t nelt, + std::vector<U>& vec, + STREAM& stream); + + + /** + * @brief Unpack a nested vector from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ + template <class U, class STREAM> + void read (size_t nelt, + std::vector<std::vector<U> >& vec, + STREAM& stream); + + +private: + /** + * @brief Pack a vector of unsigned values to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ + template <template<class> class PACKER, class U, class STREAM> + void writeUnsigned (size_t nelt, + const std::vector<U>& vec, + STREAM& stream); + + + /** + * @brief Pack a vector of signed values to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ + template <template<class> class PACKER, class U, class STREAM> + void writeSigned (size_t nelt, + const std::vector<U>& vec, + STREAM& stream); + + + /** + * @brief Pack a vector of float values to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ + template <template<class> class PACKER, class U, class STREAM> + void writeFloat (size_t nelt, + const std::vector<U>& vec, + STREAM& stream); + + + /** + * @brief Unpack a vector of unsigned values from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ + template <template<class> class UNPACKER, class U, class STREAM> + void readUnsigned (size_t nelt, + std::vector<U>& vec, + STREAM& stream); + + + /** + * @brief Unpack a vector of signed values from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ + template <template<class> class UNPACKER, class U, class STREAM> + void readSigned (size_t nelt, + std::vector<U>& vec, + STREAM& stream); + + + + /** + * @brief Unpack a vector of floating-point values from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ + template <template<class> class UNPACKER, class U, class STREAM> + void readFloat (size_t nelt, + std::vector<U>& vec, + STREAM& stream); + + /// The parameters to use for the packing. + PackedParameters m_parms; + + /// Object to pack/unpack floating-point values. + CxxUtils::FloatPacker m_packer; +}; + + +} // namespace SG + + +#include "AthContainers/PackedConverter.icc" + + +#endif // not ATHCONTAINERS_PACKEDCONVERTER_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/PackedConverter.icc b/EDM/athena/Control/AthContainers/AthContainers/PackedConverter.icc new file mode 100644 index 00000000..fbe5506c --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/PackedConverter.icc @@ -0,0 +1,278 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedConverter.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper for packing/unpacking a @c PackedContainer to/from a stream. + */ + + +namespace SG { + + +/** + * @brief Pack a vector to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ +template <class U, class STREAM> +inline +void PackedConverter::write (size_t nelt, + const std::vector<U>& vec, + STREAM& stream) +{ + // Dispatch on number of bits and on type. + switch (m_parms.nbits()) { + case 8: + if (m_parms.isFloat()) + writeFloat<CxxUtils::BitPacker8> (nelt, vec, stream); + else if (m_parms.isSigned()) + writeSigned<CxxUtils::BitPacker8> (nelt, vec, stream); + else + writeUnsigned<CxxUtils::BitPacker8> (nelt, vec, stream); + break; + + case 16: + if (m_parms.isFloat()) + writeFloat<CxxUtils::BitPacker16> (nelt, vec, stream); + else if (m_parms.isSigned()) + writeSigned<CxxUtils::BitPacker16> (nelt, vec, stream); + else + writeUnsigned<CxxUtils::BitPacker16> (nelt, vec, stream); + break; + + default: + if (m_parms.isFloat()) + writeFloat<CxxUtils::BitPacker> (nelt, vec, stream); + else if (m_parms.isSigned()) + writeSigned<CxxUtils::BitPacker> (nelt, vec, stream); + else + writeUnsigned<CxxUtils::BitPacker> (nelt, vec, stream); + break; + } +} + + +/** + * @brief Pack a nested vector to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ +template <class U, class STREAM> +inline +void PackedConverter::write (size_t nelt, + const std::vector<std::vector<U> >& vec, + STREAM& stream) +{ + for (size_t i = 0; i < nelt; i++) { + size_t n = vec[i].size(); + stream << static_cast<uint32_t>(n); + this->write (n, vec[i], stream); + } +} + + +/** + * @brief Unpack a vector from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ +template <class U, class STREAM> +inline +void PackedConverter::read (size_t nelt, + std::vector<U>& vec, + STREAM& stream) +{ + vec.clear(); + vec.reserve (nelt); + + // Dispatch on number of bits and on type. + switch (m_parms.nbits()) { + case 8: + if (m_parms.isFloat()) + readFloat<CxxUtils::BitUnpacker8> (nelt, vec, stream); + else if (m_parms.isSigned()) + readSigned<CxxUtils::BitUnpacker8> (nelt, vec, stream); + else + readUnsigned<CxxUtils::BitUnpacker8> (nelt, vec, stream); + break; + + case 16: + if (m_parms.isFloat()) + readFloat<CxxUtils::BitUnpacker16> (nelt, vec, stream); + else if (m_parms.isSigned()) + readSigned<CxxUtils::BitUnpacker16> (nelt, vec, stream); + else + readUnsigned<CxxUtils::BitUnpacker16> (nelt, vec, stream); + break; + + default: + if (m_parms.isFloat()) + readFloat<CxxUtils::BitUnpacker> (nelt, vec, stream); + else if (m_parms.isSigned()) + readSigned<CxxUtils::BitUnpacker> (nelt, vec, stream); + else + readUnsigned<CxxUtils::BitUnpacker> (nelt, vec, stream); + break; + } +} + + +/** + * @brief Unpack a nested vector from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ +template <class U, class STREAM> +inline +void PackedConverter::read (size_t nelt, + std::vector<std::vector<U> >& vec, + STREAM& stream) +{ + vec.resize (nelt); + for (size_t i = 0; i < nelt; i++) { + uint32_t n; + stream >> n; + this->read (n, vec[i], stream); + } +} + + +/** + * @brief Pack a vector of unsigned values to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ +template <template<class> class PACKER, class U, class STREAM> +inline +void PackedConverter::writeUnsigned (size_t nelt, + const std::vector<U>& vec, + STREAM& stream) +{ + uint8_t nbits = m_parms.nbits(); + PACKER<STREAM> packer (nbits, stream); + uint32_t mask = CxxUtils::ones<uint32_t> (nbits); + for (size_t i = 0; i < nelt; ++i) + packer.pack (static_cast<uint32_t>(vec[i]) & mask); +} + + +/** + * @brief Pack a vector of signed values to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ +template <template<class> class PACKER, class U, class STREAM> +inline +void PackedConverter::writeSigned (size_t nelt, + const std::vector<U>& vec, + STREAM& stream) +{ + uint8_t nbits = m_parms.nbits(); + PACKER<STREAM> packer (nbits, stream); + uint32_t mask = CxxUtils::ones<uint32_t> (nbits); + uint32_t sgnmask = ~ CxxUtils::ones<uint32_t> (nbits-1); + for (size_t i = 0; i < nelt; ++i) { + U val = vec[i]; + uint32_t uval = static_cast<uint32_t> (val); + uint32_t m = uval & sgnmask; + if (m == 0 || m == sgnmask) + packer.pack (uval & mask); + else if (val > 0) + packer.pack (~sgnmask); // Largest + number + else + packer.pack (sgnmask & mask); // Largest - number + } +} + + +/** + * @brief Pack a vector of float values to the stream. + * @param nelt Number of elements to pack. + * @param vec Vector of elements to pack. + * @param stream Destination stream. + */ +template <template<class> class PACKER, class U, class STREAM> +inline +void PackedConverter::writeFloat (size_t nelt, + const std::vector<U>& vec, + STREAM& stream) +{ + uint8_t nbits = m_parms.nbits(); + PACKER<STREAM> packer (nbits, stream); + for (size_t i = 0; i < nelt; ++i) + packer.pack (m_packer.pack (vec[i])); +} + + + +/** + * @brief Unpack a vector of unsigned values from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ +template <template<class> class UNPACKER, class U, class STREAM> +void PackedConverter::readUnsigned (size_t nelt, + std::vector<U>& vec, + STREAM& stream) +{ + uint8_t nbits = m_parms.nbits(); + UNPACKER<STREAM> unpacker (nbits, stream); + for (size_t i = 0; i < nelt; ++i) + vec.push_back (static_cast<U> (unpacker.unpack())); +} + + +/** + * @brief Unpack a vector of signed values from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ +template <template<class> class UNPACKER, class U, class STREAM> +void PackedConverter::readSigned (size_t nelt, + std::vector<U>& vec, + STREAM& stream) +{ + uint8_t nbits = m_parms.nbits(); + uint32_t sgnmask = ~ CxxUtils::ones<uint32_t> (nbits-1); + UNPACKER<STREAM> unpacker (nbits, stream); + for (size_t i = 0; i < nelt; ++i) { + uint32_t val = unpacker.unpack(); + if (val & sgnmask) + val |= sgnmask; // Sign-extend. + vec.push_back (static_cast<U> (val)); + } +} + + +/** + * @brief Unpack a vector of floating-point values from the stream. + * @param nelt Number of elements to unpack. + * @param vec Vector to receive the unpacked elements. + * @param stream Source stream. + */ +template <template<class> class UNPACKER, class U, class STREAM> +void PackedConverter::readFloat (size_t nelt, + std::vector<U>& vec, + STREAM& stream) +{ + uint8_t nbits = m_parms.nbits(); + UNPACKER<STREAM> unpacker (nbits, stream); + for (size_t i = 0; i < nelt; ++i) + vec.push_back (static_cast<U> (m_packer.unpack (unpacker.unpack()))); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/PackedParameters.h b/EDM/athena/Control/AthContainers/AthContainers/PackedParameters.h new file mode 100644 index 00000000..fe03b315 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/PackedParameters.h @@ -0,0 +1,297 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedParameters.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Describe how the contents of a @c PackedContainer are to be saved. + */ + + +#ifndef ATHCONTAINERS_PACKEDPARAMETERS_H +#define ATHCONTAINERS_PACKEDPARAMETERS_H + + +#include "AthContainersInterfaces/AuxDataOption.h" +#include <limits> +#include <stdint.h> + + +namespace SG { + + +/** + * @brief Describe how the contents of a @c PackedContainer are to be saved. + * + * When a @c PackedContainer is saved to a root file, the contents may + * be stored with reduced precision. How this packing is done is described + * by the parameters held in this structure. These include: + * + * - nbits: This is the overall number of bits used to hold one container + * element. May be in the range 1-32, inclusive. + * - isSigned: If true, then the elements are saved as signed numbers; + * otherwise as unsigned numbers. If this is set, then one + * bit is used for the sign; nbits must therefore be at least 2. + * - isFloat: If true, the elements are saved as floating-point numbers; + * otherwise as integers. It may occasionally be useful to + * save floating-point values as integers. The converse + * should also work, but is likely to be less useful. + * + * The remaining parameters are only used when elements are being + * saved as floating-point. + * + * - nmantissa: The number of bits to be used for the mantissa part + * of the representation. Does not include a sign bit. + * Any bits left out of nbits after removing nmantissa + * bits and (optionally) the sign bit are used as the exponent. + * If fewer than 2 bits are available for the exponent, + * then the number is saved using a fixed-point representation, + * with a range [0, 1). + * - scale: If set, then numbers will be divided by this value before + * being saved. This allows extending a fixed-point format + * to an arbitrary range. + * - rounding: If true, numbers will be rounded to the nearest value + * when written. Otherwise (the default), they will + * be truncated. + * + * User code will should usually not interact with this class directly. + * Use the @c setOption interfaces instead. + */ +class PackedParameters +{ +public: + /** + * @brief Default constructor. + * + * Set up to write unsigned integers with 32 bits. + */ + PackedParameters(); + + + /** + * @brief Constructor from nbits and flags. + * @param nbits The number of bits for each element. + * @param flags Extra flags describing the packing. + * + * Additionally nmantissa is set to correspond to a fixed-point + * representation and the scale is cleared. + * + * This is meant to be used by the read converter. + */ + PackedParameters (uint8_t nbits, uint8_t flags); + + + /** + * @brief Initialize with default packing parameters for type @c T. + * + * For integer types, the number of bits and signedness is set to match @c T. + * For floating types, nbits is set to 32, nmantissa to 23, isSigned to true, + * and the scale is cleared. + */ + template <class T> + PackedParameters(T); + + + /** + * @brief The number of bits used to store each element. + */ + uint8_t nbits() const; + + + /** + * @brief The number of bits used for the mantissa portion of a float-point + * representation, excluding a sign bit (if any). + * + * If there are at least two bits left over after accounting + * for the mantissa and sign bits, then numbers will be saved + * in a floating-point format; otherwise, fixed-point. + */ + uint8_t nmantissa() const; + + + /** + * @brief Additional flags describing the packing. + * + * (This should really only be used by converters.) + */ + uint8_t flags() const; + + + /** + * @brief Return the scale for floating-point numbers. + * + * If enabled, float-point numbers will be divided by this value + * before being saved. If not enabled, this may return 0. + */ + float scale() const; + + + /** + * @brief Are elements being written as signed numbers? + */ + bool isSigned() const; + + + /** + * @brief Are elements being written as floating-point numbers? + */ + bool isFloat() const; + + + /** + * @brief Should floats be rescaled before writing? + */ + bool hasScale() const; + + + /** + * @brief Should floats be rounded during writing? + */ + bool rounding() const; + + + /** + * @brief Set the number of bits to be used for each element. + * @brief nbits The desired number of bits. + * + * @c nbits must be in the range 1-32 for unsigned numbers, + * 2-32 for signed numbers. + * + * If necessary, @c nmantissa will be adjusted so that it still fits + * within the requested number of bits. + * + * Returns true if successful, false otherwise. + */ + bool setNbits (uint8_t nbits); + + + /** + * @brief Set the number of mantissa bits used in the packed representation. + * @brief nmantissa The desired number of mantissa bits. + * + * This has an effect only when saving floating-point types. + * + * @c nmantissa must fit within the requested number of bits. + * @c nmantissa does not include the sign bit. + * If there are at least two bits left over, then numbers will be + * saved in a floating-point format; otherwise, fixed point will be used. + * + * Returns true if successful, false otherwise. + */ + bool setNmantissa (uint8_t nmantissa); + + + /** + * @brief Set the scale to use when packing floating-point data. + * @param scale The new scale, or 0 to disable. + * + * This has an effect only when saving floating-point types. + * + * If set to something non-zero, then floating-point numbers + * will be divided by this value before being written. + * + * Returns true to indicate success. + */ + bool setScale (float scale); + + + /** + * @brief Set the signedness flag for the packed representation. + * @param flag Should elements be saved as signed numbers? + * + * If the flag is false (unsigned), this always succeeds. + * If the flag is true (signed), then this fails if @c nbits is 1. + * @c nmantissa will be adjusted if there are now insufficient + * bits for it. + * + * Returns true if successful, false otherwise. + */ + bool setSigned (bool flag); + + + /** + * @brief Set the rounding mode. + * @param flag Should numbers be rounded when being written? + * + * This has an effect only when saving floating-point types. + * + * Returns true to indicate success. + */ + bool setRounding (bool flag); + + + /** + * @brief Set the floating-point flag. + * @param flag Should numbers be written as floating-point? + * + * If true, numbers will be written in a floating/fixed point + * representation; otherwise, they will be written as integers. + * + * Returns true to indicate success. + */ + bool setFloat (bool flag); + + + /** + * @brief Test to see if @c option is a recognized packing option. + * @param option The option to test. + * + * Returns @c true if the name of @c option is recognized as a valid + * packing option; @c false otherwise. + */ + static bool isValidOption (const AuxDataOption& option); + + + /** + * @brief Set a packing option. + * @parameter option The option to set. + * + * Recognized options are `nbits', `nmantissa', `scale', `signed', + * `rounding', and `float'. See the setter functions above for details + * on their semantics. + * + * Returns true on success; false otherwise. + */ + bool setOption (const AuxDataOption& option); + + + /// Define bit assignments for the flags field. + /// Existing flag assignments should never be changed, as the persistent + /// format may depend on them. + enum { + FLAG_IS_SIGNED = (1<<0), + FLAG_IS_FLOAT = (1<<1), + FLAG_HAS_SCALE = (1<<2), + FLAG_ROUNDING = (1<<3), + }; + + +private: + /// The number of bits to use for each element. + uint8_t m_nbits; + + /// The number of bits for the mantissa of floating-point representations. + /// Does not include the sign bit. + uint8_t m_nmantissa; + + /// If nonzero, divide floating-point numbers by this before writing. + float m_scale; + + /// Additional flags. + uint8_t m_flags; +}; + + +} // namespace SG + + +#include "AthContainers/PackedParameters.icc" + + +#endif // not ATHCONTAINERS_PACKEDPARAMETERS_H + diff --git a/EDM/athena/Control/AthContainers/AthContainers/PackedParameters.icc b/EDM/athena/Control/AthContainers/AthContainers/PackedParameters.icc new file mode 100644 index 00000000..63c13967 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/PackedParameters.icc @@ -0,0 +1,131 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedParameters.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Describe how the contents of a @c PackedContainer are to be saved. + */ + + +namespace SG { + + +/** + * @brief Initialize with default packing parameters for type @c T. + * + * For integer types, the number of bits and signedness is set to match @c T. + * For floating types, nbits is set to 32, nmantissa to 23, isSigned to true, + * and the scale is cleared. + */ +template <class T> +PackedParameters::PackedParameters (T /*val*/) + : m_nbits(8 * sizeof(uint32_t)), + m_nmantissa(23), + m_scale(0), + m_flags(0) +{ + if (std::numeric_limits<T>::is_signed) + setSigned (true); + + if (std::numeric_limits<T>::is_integer) + setNbits (8*sizeof(T)); + else + setFloat (true); +} + + +/** + * @brief The number of bits used to store each element. + */ +inline +uint8_t PackedParameters::nbits() const +{ + return m_nbits; +} + + +/** + * @brief The number of bits used for the mantissa portion of a float-point + * representation, excluding a sign bit (if any). + * + * If there are at least two bits left over after accounting + * for the mantissa and sign bits, then numbers will be saved + * in a floating-point format; otherwise, fixed-point. + */ +inline +uint8_t PackedParameters::nmantissa() const +{ + return m_nmantissa; +} + + +/** + * @brief Additional flags describing the packing. + * + * (This should really only be used by converters.) + */ +inline +uint8_t PackedParameters::flags() const +{ + return m_flags; +} + + +/** + * @brief Return the scale for floating-point numbers. + * + * If enabled, float-point numbers will be divided by this value + * before being saved. If not enabled, this may return 0. + */ +inline +float PackedParameters::scale() const +{ + return m_scale; +} + + +/** + * @brief Are elements being written as signed numbers? + */ +inline +bool PackedParameters::isSigned() const +{ + return m_flags & FLAG_IS_SIGNED; +} + + +/** + * @brief Are elements being written as floating-point numbers? + */ +inline +bool PackedParameters::isFloat() const +{ + return m_flags & FLAG_IS_FLOAT; +} + + +/** + * @brief Should floats be rescaled before writing? + */ +inline +bool PackedParameters::hasScale() const +{ + return m_flags & FLAG_HAS_SCALE; +} + + +/** + * @brief Should floats be rounded during writing? + */ +inline +bool PackedParameters::rounding() const +{ + return m_flags & FLAG_ROUNDING; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/UserDataStore.h b/EDM/athena/Control/AthContainers/AthContainers/UserDataStore.h new file mode 100644 index 00000000..b40b92c2 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/UserDataStore.h @@ -0,0 +1,213 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//Dear emacs, this is -*-c++-*- +#ifndef ATHCONTAINERS_USERDATASTORE_H +#define ATHCONTAINERS_USERDATASTORE_H + +#ifdef XAOD_STANDALONE + +/** + * @short Placeholder class when using AthContainers in ROOT + * + * The xAOD format doesn't consider the UserDataStore at the + * moment, but it could change later on. For now, because the + * dictionary generation expects a class called UserDataStore + * to be available, we use a dummy class. + * + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + * + * $Revision: 764634 $ + * $Date: 2016-07-27 16:09:53 +0200 (Wed, 27 Jul 2016) $ + */ +class UserDataStore { + +public: + /// Default constructor + UserDataStore() {} + +}; // class UserDataStore; + +#else + +#include "GaudiKernel/StatusCode.h" +#include "AthenaKernel/IAthenaBarCode.h" +#include "GaudiKernel/MsgStream.h" +#include <string> +#include <map> + +//#include <ext/hash_map> +//#include <boost/unordered_map.hpp> + + +#include "AthContainers/tools/UDSLabelHashTable.h" +#include "SGTools/CLASS_DEF.h" + +#include "boost/any.hpp" + +/** @class UserDataStoreObj + * @brief User Data store for type T + */ + +class UserDataStore { + + friend class UserDataStoreCnv_p1; + +public: + + /// Default constructor + UserDataStore(); + + /** + * @brief Record method with template payload + * @param abc A data-object implementing the IAthenaBarCode interface + * @param label String label of the decoration + * @param value Decoration payload + */ + template<typename T> + StatusCode record(const IAthenaBarCode& obj, const std::string& label, const T& value); + + + /** + * @brief Retrieve method with template payload + * @param abc A data-object implementing the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] value Decoration payload + */ + template<typename T> + StatusCode retrieve(const IAthenaBarCode& obj, const std::string& label, T& value) const; + + + /** + * @brief Contains method for element decorations + * @param abc A data-object implementing the IAthenaBarCode interface + * @param label String label of the decoration + * @return True if the decoration exists + */ + bool contains(const IAthenaBarCode& obj, const std::string& label) const; + + + /** + * @brief Table-of-contents method + * @param barcode A data-object implementing the IAthenaBarCode interface + * @return A vector of labels existing for this object + */ + std::vector<const std::string*> getLabels(const AthenaBarCode_t& barcode) const; + + + + /** + * @brief Record method with boost::any as payload + * @param abc A data-object implementing the IAthenaBarCode interface + * @param label String label of the decoration + * @param value Decoration payload + */ + StatusCode recordAny(const IAthenaBarCode& obj, const std::string& label, const boost::any& value); + + + /** + * @brief Retrieve method with boost::any as payload + * @param abc A data-object implementing the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] value Decoration payload + */ + StatusCode retrieveAny(const IAthenaBarCode& obj, const std::string& label, const boost::any*& value) const; + + + /** + * @brief Method to set the AthenaBarCode of this event (called by UserDataSvc) + * @param eventABC The AthenaBarCode + */ + void setEventABC(const AthenaBarCode_t& eventABC); + + + + /** + * @brief Method to get the AthenaBarCode of this event (called by UserDataSvc) + * @return The AthenaBarCode + */ + AthenaBarCode_t getEventABC() const { return m_eventABC; } + + + enum NotFoundTypes { + ALLGOOD=0, + BARCODE, + LABEL + }; + +private: + + // For experimental use of hash-maps instead of std::map + // class abcHashFcn { + // public: + // size_t operator()(const AthenaBarCode_t abc) const { return ((abc & 0xFFFFFFFF)>>6); } //Extract the 26 counter-bits + // }; + + typedef boost::any payload_t; + + typedef UDSLabelHashTable::hash_t index_t; + + typedef std::map<AthenaBarCode_t,std::map<index_t, payload_t > > mapmap_t; + //typedef __gnu_cxx::hash_map<AthenaBarCode_t,std::map<index_t, payload_t >, abcHashFcn > mapmap_t; + //typedef boost::unordered_map<AthenaBarCode_t,std::map<index_t, payload_t >, abcHashFcn > mapmap_t; + + typedef std::map<index_t, payload_t >::iterator iterator; + typedef std::map<index_t, payload_t >::const_iterator const_iterator; + + mapmap_t m_data; + + //find a label (const version) + const_iterator find(const AthenaBarCode_t& barcode, const std::string& label) const; + + //Update the cached map-iterator m_lastIt; + //void updateIt(const AthenaBarCode_t& barcode); + + const_iterator m_notFoundIt; + const std::map<index_t, payload_t > m_defaultEntry; + + UDSLabelHashTable m_labelTable; + + ///Cache of last barcode/object (const) + mutable mapmap_t::const_iterator m_lastIt; + + ///Cache of last barcode/object (non-const) + mutable mapmap_t::iterator m_lastIt_nc; + + ///AthenaBarCode for this event + AthenaBarCode_t m_eventABC; + + ///Cached Message Stream + mutable MsgStream m_msg; + + mutable NotFoundTypes m_whyNotFound; + +}; + +CLASS_DEF( UserDataStore , 51567825 , 1 ) + +template<typename T> +StatusCode UserDataStore::retrieve(const IAthenaBarCode& obj, const std::string& label, T& value) const { + const boost::any* aValue=0; + StatusCode sc=this->retrieveAny(obj,label, aValue); + if (sc.isFailure()) return sc; + if (typeid(T) != aValue->type()) { + m_msg << MSG::ERROR << "Typeid mismatch while retrieving user data with label " << label << endmsg; + return StatusCode::FAILURE; + } + const T* decoPtr=boost::any_cast<T>(aValue); + value=*decoPtr; //Deep copy! + return StatusCode::SUCCESS; +} + + +template<typename T> +StatusCode UserDataStore::record(const IAthenaBarCode& obj, const std::string& label, const T& value) { + boost::any aValue(value); + return this->recordAny(obj,label, aValue); +} + +#endif // not XAOD_STANDALONE + + +#endif // not ATHCONTAINERS_USERDATASTORE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/ViewVector.h b/EDM/athena/Control/AthContainers/AthContainers/ViewVector.h new file mode 100644 index 00000000..c5bc1a6d --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ViewVector.h @@ -0,0 +1,367 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/ViewVector.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Identify view containers to be made persistent. + */ + + +#ifndef ATHCONTAINERS_VIEWVECTOR_H +#define ATHCONTAINERS_VIEWVECTOR_H + + +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/IndexTrackingPolicy.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/ViewVectorBase.h" +#include "AthLinks/ElementLink.h" +#include "CxxUtils/unused.h" +#include "boost/preprocessor/stringize.hpp" + + +/** + * @brief Identify view containers to be made persistent. + * + * This is a variant of @c DataVector that can only be constructed as a + * view vector. This class also holds the persistent representation + * of the view vector, which is logically equivalent to a + * @c std::vector<ElementLink<DV> > (but stored as vector of pairs + * of integers). + * + * The template parameter @c DV is the @c DataVector on which the view + * is based. @c ViewVector<DV> acts just like @c DV except that it will + * throw an exception if you try to construct it as an owning container. + * (The ownership mode arguments cannot really be removed from the methods + * completely, otherwise ConstDataVector<ViewVector<DV> > wouldn't compile.) + * + * To make a @c ViewVector<DV> object persistent: + * - Instead of using @c CLASS_DEF, to associate a CLID with the object, + * use @c VIEWVECTOR_CLASS_DEF. You can then record a @c ViewVector + * to StoreGate without the @c VIEWVECTOR_CLASS_DEF being present + * in the compilation unit doing the record. You can also record + * a @c ViewVector object using a pointer to the base @c DataVector. + * These behaviors can be useful when the @c ViewVector type + * is generated by templated code. + * (Currently, this will only work directly if the argument to the + * @c ViewVector class is a @c DataVector directly, rather than + * an intermediate class.) + * - In the AthenaPool package, declare the class in the requirements file, + * but do not implement it. The default generated converter will get + * specialized appropriately for the ViewVector. + * - Previous versions of @c ViewVector were saved directly + * as @c std::vector<ElementLink<DV> >. If you need to continue to read + * such data, then generate a dictionary for + * @c std::vector<ElementLink<DV> > along with a guid. + * (You can use the @c Pers_t typedef in @c ViewVector + * to help with this.) + * - In a standalone root application, you must explicitly call + * @c toPersistent() on the @c ViewVector object prior to calling + * @c Fill() on the tree. + */ +template <class DV> +class ViewVector + : public DV, public SG::ViewVectorBase +{ +public: + /// Basic types, forwarded from the base. + typedef typename DV::size_type size_type; + typedef typename DV::difference_type difference_type; + typedef typename DV::allocator_type allocator_type; + typedef typename DV::base_value_type base_value_type; + typedef typename DV::BaseContainer BaseContainer; + typedef typename DV::DVL_BASE DVL_BASE; + typedef typename DV::const_iterator const_iterator; + typedef typename DV::const_reverse_iterator const_reverse_iterator; + typedef typename DV::value_type value_type; + typedef typename DV::const_value_type const_value_type; + typedef typename DV::reference reference; + typedef typename DV::const_reference const_reference; + typedef typename DV::pointer pointer; + typedef typename DV::const_pointer const_pointer; + + /// The old persistent form of this class. + typedef std::vector<ElementLink<DV> > Pers_t; + + + //======================================================================== + /** @name Constructors, destructors, assignment. */ + //@{ + + + /** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * Must be @c SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + */ + explicit ViewVector(SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS); + + + /** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * Must be @c SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + */ + explicit ViewVector(size_type n, + SG::OwnershipPolicy ownPolicy = SG::VIEW_ELEMENTS); + + + /** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + */ + template <class InputIterator> + ViewVector(InputIterator first, InputIterator last); + + + /// Use the compiler-generated copy constructor. + ViewVector (const ViewVector&) = default; + + + /** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + ViewVector (ViewVector&& rhs); + + + /** + * @brief Constructor from base vector. + * @param rhs The container from which to copy. + */ + ViewVector (const DV& rhs); + + + /** + * @brief Move constructor from base vector. + * @param rhs The container from which to copy. Must be a view container. + * + * Any auxiliary data will be moved along with the container contents. + */ + ViewVector (DV&& rhs); + + + /** + * @brief Constructor from an initializer list. + * @param l An initializer list. + */ + ViewVector(std::initializer_list<value_type> l); + + + /// Can use compiler-generated assignment op. + ViewVector& operator= (const ViewVector& rhs) = default; + + + /** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ + ViewVector& operator= (const DV& rhs); + + + /** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ + ViewVector& operator= (ViewVector&& rhs); + + + /** + * @brief Move assignment from base vector. + * @param rhs The container from which to move. + * Must be a view vector. + * + * Any auxiliary data will be moved along with the container contents. + */ + ViewVector& operator= (DV&& rhs); + + + /** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + */ + ViewVector& operator= (std::initializer_list<value_type> l); + + + /// Get the standard clear() from the base class. + using DV::clear; + + + /** + * @fn void clear + * @brief Erase all the elements in the collection. + * @param ownPolicy The new ownership policy of the container. + * Must be SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + */ + void clear (SG::OwnershipPolicy ownPolicy); + + + /** + * @fn void clear + * @brief Erase all the elements in the collection. + * @param ownPolicy The new ownership policy of the container. + * Must be SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + * @param trackIndices The index tracking policy. + */ + void clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices); + + + /** + * @brief Convert the vector to persistent form. + */ + virtual void toPersistent() override; + + + /** + * @brief Convert the vector to transient form. + */ + virtual void toTransient() override; + + +private: + /// Helper to ensure that the inheritance information for this class + /// gets initialized. + void registerBaseInit(); +}; + + +#ifndef XAOD_STANDALONE +#include "SGTools/BaseInfo.h" +namespace SG { + + +/// Specialize to declare that ViewVector<DV> derives from DV. +template<class DV> +struct Bases<ViewVector<DV> > { + typedef DV Base1; + typedef NoBase Base2; + typedef NoBase Base3; +}; + + +} +#endif + + +#include "AthContainers/ViewVector.icc" + + +#ifndef XAOD_STANDALONE +/** + * @brief ClassID_traits specialization for @c ViewVector. + * + * We want to allow SG operations on a @c ViewVector even when the + * CLASS_DEF for the @c ViewVector isn't present in the compilation unit + * doing the record. For example, we may have some piece of code + * templated on a @c DataVector class @c DV that creates a @c ViewVector<DV> + * and records it. When this is used, the header defining @c should + * be included, but the one defining @c ViewVector<DV> may not be. + * But we'd like the record to work anyway. + * + * So, for @c ViewVector, we use this specialization of @c ClassID_traits. + * It stores the CLID and the name (which recall will usually be a typedef + * name, so we can't get it from the @c DV template argument) as static + * class members. We define a macro @c VIEWVECTOR_CLASS_DEF which then + * sets these class statics during global initialization. + */ +template <class DV> +struct ClassID_traits< ViewVector<DV> > +{ + static const bool s_isDataObject = false; + typedef std::integral_constant<bool, s_isDataObject> is_DataObject_tag; + typedef std::true_type has_classID_tag; + + static const CLID& ID() { + if (s_clid == CLID_NULL) + SG::throwExcMissingViewVectorCLID (typeid(ViewVector<DV>)); + return s_clid; + } + static const char* typeNameString() { + if (s_name == nullptr) + SG::throwExcMissingViewVectorCLID (typeid(ViewVector<DV>)); + return s_name; + } + static const std::string& typeName() { + static const std::string name = typeNameString(); return name; + } + static const std::type_info& typeInfo() { + return typeid (ViewVector<DV>); + } + static Athena::PackageInfo packageInfo() { + static Athena::PackageInfo pi( BOOST_PP_STRINGIZE(PACKAGE_VERSION_UQ) ); + return pi; + } + typedef std::false_type has_version_tag; + static const bool s_isConst = false; + + static bool init (CLID clid, const char* name) + { + if (s_clid == CLID_NULL) { + s_clid = clid; + s_name = name; + } + return true; + } +private: + static CLID s_clid; + static const char* s_name; +}; + +template <class DV> +CLID ClassID_traits< ViewVector<DV> >::s_clid = CLID_NULL; +template <class DV> +const char* ClassID_traits< ViewVector<DV> >::s_name = nullptr; +#endif // not XAOD_STANDALONE + + +#ifdef XAOD_STANDALONE + +// FIXME: xAOD has its own, incompatible, CLASS_DEF, but we don't want to use it +// due to dependency issues. Probably need to move things around +// a bit to resolve this. +#define VIEWVECTOR_CLASS_DEF(NAME, CID) + +#else + +/** + * @brief Use this macro to associate a CLID with a @c ViewVector class. + */ +#define VIEWVECTOR_CLASS_DEF(NAME, CID) \ + static const bool UNUSED(clidinit_##CID) = ClassID_traits<NAME>::init (CID, #NAME); \ + CLIDREGISTRY_ADDENTRY(CID, NAME) +#endif + + +#endif // not ATHCONTAINERS_VIEWVECTOR_H + diff --git a/EDM/athena/Control/AthContainers/AthContainers/ViewVector.icc b/EDM/athena/Control/AthContainers/AthContainers/ViewVector.icc new file mode 100644 index 00000000..5adb5ce3 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ViewVector.icc @@ -0,0 +1,268 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/ViewVector.icc + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Identify view containers to be made persistent. + */ + + +/** + * @brief Default constructor. + * @param ownPolicy The ownership mode for the container. + * Must be @c SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + */ +template <class DV> +inline +ViewVector<DV>::ViewVector(SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/) + : DV (SG::VIEW_ELEMENTS) +{ + if (ownPolicy != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + registerBaseInit(); +} + + +/** + * @brief Sized constructor. + * @param n The size of the container. + * @param ownPolicy The ownership mode for the container. + * Must be @c SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + * + * Note that unlike the standard vector constructor, you can't specify + * an initial value here. The container will be initialized with 0's. + */ +template <class DV> +inline +ViewVector<DV>::ViewVector(size_type n, + SG::OwnershipPolicy ownPolicy /*= SG::VIEW_ELEMENTS*/) + : DV (n, SG::VIEW_ELEMENTS) +{ + if (ownPolicy != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + registerBaseInit(); +} + + +/** + * @brief Constructor from iterators. + * @param first The start of the range to put in the new container. + * @param last The end of the range to put in the new container. + */ +template <class DV> +template <class InputIterator> +inline +ViewVector<DV>::ViewVector(InputIterator first, InputIterator last) + : DV (first, last, SG::VIEW_ELEMENTS) +{ + registerBaseInit(); +} + + +/** + * @brief Move constructor. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class DV> +inline +ViewVector<DV>::ViewVector (ViewVector&& rhs) +{ + // Redundant, but just to check for problems. + if (rhs.ownPolicy() != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + DV::operator= (std::move (rhs)); + registerBaseInit(); +} + + +/** + * @brief Constructor from base vector.. + * @param rhs The container from which to copy. + */ +template <class DV> +inline +ViewVector<DV>::ViewVector (const DV& rhs) + : DV(rhs) +{ + registerBaseInit(); +} + + +/** + * @brief Move constructor from base vector. + * @param rhs The container from which to copy. Must be a view container. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class DV> +inline +ViewVector<DV>::ViewVector (DV&& rhs) + : DV(std::move(rhs)) +{ + if (this->ownPolicy() != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + registerBaseInit(); +} + + +/** + * @brief Constructor from an initializer list. + * @param l An initializer list. + */ +template <class DV> +inline +ViewVector<DV>::ViewVector(std::initializer_list<value_type> l) + : DV (l, SG::VIEW_ELEMENTS) +{ + registerBaseInit(); +} + + +/** + * @brief Assignment operator. + * @param rhs The DataVector from which to assign. + * @return This object. + * + * This is a `shallow' copy; after the completion of this, the DataVector + * will not own its elements. Any elements it owned prior to this call + * will be released. + * + * Note: this method may only be called using the most derived + * @c DataVector in the hierarchy. + */ +template <class DV> +inline +ViewVector<DV>& ViewVector<DV>::operator= (const DV& rhs) +{ + if (this != &rhs) { + DV::operator= (rhs); + } + return *this; +} + + +/** + * @brief Move assignment. + * @param rhs The container from which to move. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class DV> +inline +ViewVector<DV>& ViewVector<DV>::operator= (ViewVector&& rhs) +{ + if (this != &rhs) { + // Redundant but good to check anyway. + if (this->ownPolicy() != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + DV::operator= (std::move (rhs)); + } + return *this; +} + + +/** + * @brief Move assignment from base vector. + * @param rhs The container from which to move. + * Must be a view vector. + * + * Any auxiliary data will be moved along with the container contents. + */ +template <class DV> +inline +ViewVector<DV>& ViewVector<DV>::operator= (DV&& rhs) +{ + if (this != &rhs) { + if (rhs.ownPolicy() != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + DV::operator= (std::move (rhs)); + } + return *this; +} + + +/** + * @brief Assignment operator, from an initializer list. + * @param l An initializer list. + * @return This object. + * + * This is equivalent to @c assign. + */ +template <class DV> +inline +ViewVector<DV>& ViewVector<DV>::operator= (std::initializer_list<value_type> l) +{ + DV::operator= (l); + return *this; +} + + +/** + * @fn void clear + * @brief Erase all the elements in the collection. + * @param ownPolicy The new ownership policy of the container. + * Must be SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + */ +template <class DV> +inline +void ViewVector<DV>::clear (SG::OwnershipPolicy ownPolicy) +{ + if (ownPolicy != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + DV::clear (SG::VIEW_ELEMENTS); +} + + +/** + * @brief Convert the vector to persistent form. + */ +template <class DV> +inline +void ViewVector<DV>::toPersistent() +{ + doToPersistent (*static_cast<DV*>(this)); +} + + +/** + * @brief Convert the vector to transient form. + */ +template <class DV> +inline +void ViewVector<DV>::toTransient() +{ + doToTransient (*static_cast<DV*>(this)); +} + + +/** + * @fn void clear + * @brief Erase all the elements in the collection. + * @param ownPolicy The new ownership policy of the container. + * Must be SG::VIEW_ELEMENTS. + * (Argument present only for interface compatibility.) + * @param trackIndices The index tracking policy. + */ +template <class DV> +inline +void ViewVector<DV>::clear (SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy trackIndices) +{ + if (ownPolicy != SG::VIEW_ELEMENTS) SG::throwExcViewVectorNotView(); + DV::clear (SG::VIEW_ELEMENTS, trackIndices); +} + + +/** + * @brief Helper to ensure that the inheritance information for this class + * gets initialized. + */ +template <class DV> +void ViewVector<DV>::registerBaseInit() +{ +#ifndef XAOD_STANDALONE + static const SG::RegisterBaseInit<ViewVector> rbi; +#endif +} diff --git a/EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.h b/EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.h new file mode 100644 index 00000000..1a48f56a --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.h @@ -0,0 +1,186 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file ViewVectorBase.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2016 + * @brief Hold the persistent representation for a ViewVector. + */ + + +#ifndef ATHCONTAINERS_VIEWVECTORBASE_H +#define ATHCONTAINERS_VIEWVECTORBASE_H + + +#include "AthContainers/dataVectorAsELV.h" +#include "AthContainers/tools/CurrentEventStore.h" +#include "AthLinks/ElementLinkBase.h" +#include <vector> + + +class ViewVectorBaseTest; + + +namespace SG { + + +/** + * @brief Hold the persistent representation for a ViewVector. + * + * Base class for @c ViewVector; not to be used directly. + */ +class ViewVectorBase +{ +public: + /// Destructor. + virtual ~ViewVectorBase(); + + + /** + * @brief Convert the vector to persistent form. + */ + virtual void toPersistent() = 0; + + + /** + * @brief Convert the vector to transient form. + */ + virtual void toTransient() = 0; + + + /** + * @brief Clear the persistent data. + */ + void clearPersistent(); + + + /** + * @brief Set a flag to declare that the vector should be cleared + * on the next call to toPersistent(). + * + * This would be used in the case where we make a copy of the + * object being written. + */ + void setClearOnPersistent(); + + +protected: + /** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * Called for classes that have a CLID. + */ + template <class DV> + void doToPersistent1 (DV& v, const std::true_type&); + + + /** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * Called for classes that do not have a CLID. + * This will simply abort. + */ + template <class DV> + void doToPersistent1 (DV&, const std::false_type&); + + + /** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * This will abort if called for a class with no CLID. + */ + template <class DV> + void doToPersistent (DV& v); + + + /** + * @brief Convert to transient form. + * @param v The vector to fill in. + * + * Called for classes that have a CLID if DV is not a ConstDataVector. + */ + template <class DV> + void doToTransient2 (DV& v, const std::true_type&); + + + /** + * @brief Convert to transient form. + * @param v The vector to fill in. + * + * Called for the case that DV is not a ConstDataVector. A no-op. + */ + template <class DV> + void doToTransient2 (DV&, const std::false_type&) {} + + + /** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * Class has a CLID; dispatch based on whether DV is a ConstDataVector. + */ + template <class DV> + void doToTransient1 (DV& v, const std::true_type&) + { + doToTransient2 (v, std::is_same<DV, typename DV::base_data_vector>()); + } + + + /** + * @brief Convert to transient form. + * @param v The vector to fill in. + * + * Called for the case that DV doesn't have a CLID. A no-op. + * + * This is also what will get called for the case of an older version + * of a schema-evolved vector. + */ + template <class DV> + void doToTransient1 (DV&, const std::false_type&) {} + + + /** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * Dispatch based on whether the class has a CLID. + */ + template <class DV> + void doToTransient (DV& v) + { +#ifdef XAOD_STANDALONE + doToTransient1 (v, std::true_type()); +#else + doToTransient1 (v, typename ClassID_traits<DV>::has_classID_tag()); +#endif + } + + +private: + // For unit testing. + friend class ::ViewVectorBaseTest; + + /// The persistent form. (sgkey, index) + std::vector<unsigned int> m_persKey; + std::vector<unsigned int> m_persIndex; + + /// If true, the vector should be cleared when doPersistent is called. + bool m_clearOnPersistent = false; +}; + + +} // namespace SG + + +#include "AthContainers/ViewVectorBase.icc" + + +#endif // not ATHCONTAINERS_VIEWVECTORBASE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.icc b/EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.icc new file mode 100644 index 00000000..2312e2fa --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/ViewVectorBase.icc @@ -0,0 +1,197 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file ViewVectorBase.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2016 + * @brief Hold the persistent representation for a ViewVector. + */ + + +#include "AthContainers/AuxElement.h" +#include <type_traits> + + +namespace { + + +template <class T> +inline +SG::AuxVectorData* getContainer1 (T* p, const std::true_type&) +{ + return p->container(); +} +template <class T> +inline +SG::AuxVectorData* getContainer1 (T*, const std::false_type&) +{ + return nullptr; +} + + +/** + * @brief Return the container for an element. + * + * Returns null if the element does not derive from AuxElement. + */ +template <class T> +inline +SG::AuxVectorData* getContainer (T* p) +{ + return getContainer1 (p, typename std::is_base_of<SG::AuxElement, T>::type()); +} + + +} // anonyous namespace + + +namespace SG { + + +/** + * @brief Destructor. + */ +inline +ViewVectorBase::~ViewVectorBase() +{ +} + + +/** + * @brief Clear the persistent data. + */ +inline +void ViewVectorBase::clearPersistent() +{ + m_persKey.clear(); + m_persIndex.clear(); +} + + +/** + * @brief Set a flag to declare that the vector should be cleared + * on the next call to toPersistent(). + * + * This would be used in the case where we make a copy of the + * object being written. + */ +inline +void ViewVectorBase::setClearOnPersistent() +{ + m_clearOnPersistent = true; +} + + +/** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * Called for classes that have a CLID. + */ +template <class DV> +void +ViewVectorBase::doToPersistent1 (DV& v, const std::true_type&) +{ + IProxyDict* store = SG::CurrentEventStore::store(); + std::vector<ElementLink<DV> > elv = SG::dataVectorAsELV (v, store); + m_persKey.clear(); + m_persIndex.clear(); + m_persKey.reserve (elv.size()); + m_persIndex.reserve (elv.size()); + for (ElementLinkBase& el : elv) { +#ifdef XAOD_STANDALONE + m_persKey.push_back (el.persKey()); + m_persIndex.push_back (el.persIndex()); +#else + el.thin(); + m_persKey.push_back (el.key()); + m_persIndex.push_back (el.index()); +#endif + } + if (m_clearOnPersistent) { + v.clear(); + m_clearOnPersistent = false; + } +} + + +/** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * Called for classes that do not have a CLID. + * This will simply abort. + */ +template <class DV> +inline +void ViewVectorBase::doToPersistent1 (DV&, const std::false_type&) +{ + std::abort(); +} + + +/** + * @brief Convert to persistent form. + * @param v The vector to convert. + * + * This will abort if called for a class with no CLID. + */ +template <class DV> +inline +void ViewVectorBase::doToPersistent (DV& v) +{ + // Dispatch depending on whether or not DV has a CLID. + doToPersistent1 (v, +#ifdef XAOD_STANDALONE + std::true_type() +#else + typename ClassID_traits<DV>::has_classID_tag() +#endif + ); +} + + +/** + * @brief Convert to transient form. + * @param v The vector to fill in. + * + * Called for classes that have a CLID if DV is not a ConstDataVector. + */ +template <class DV> +void ViewVectorBase::doToTransient2 (DV& v, const std::true_type&) +{ + // The custom DataVector collection proxy will have created elements here, + // so we need to delete them to avoid a memory leak. + // FIXME: It should be possible to avoid creating the elements + // in the first place, at least for the usual case xAOD where the elements + // themselves have no persistent data. + if (v.ownPolicy() == SG::VIEW_ELEMENTS) { + for (typename DV::value_type p : v) { + // Try to protect against deleting an unowned object in the case + // where this gets called multiple times on the same object. + // The dummy elements will have null container pointers, while + // those that we've retrieved through EL resolution below should + // have the container pointer set. Can only do this check, though, + // for types with aux data. + if (getContainer(p) == nullptr) + delete p; + } + } + v.clear (SG::VIEW_ELEMENTS); + IProxyDict* store = SG::CurrentEventStore::store(); + + assert (m_persKey.size() == m_persIndex.size()); + for (size_t i = 0; i < m_persKey.size(); i++) { + ElementLink<DV> el (m_persKey[i], m_persIndex[i], store); + // FIXME: const_cast + v.push_back (const_cast<typename DV::value_type> (*el)); + } +} + + +} // namespace SG + + diff --git a/EDM/athena/Control/AthContainers/AthContainers/dataVectorAsELV.h b/EDM/athena/Control/AthContainers/AthContainers/dataVectorAsELV.h new file mode 100644 index 00000000..cdd8b993 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/dataVectorAsELV.h @@ -0,0 +1,113 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/dataVectorAsELV.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Helper to make a vector<EL> from a DataVector. + */ + + +#ifndef ATHCONTAINERS_DATAVECTORASELV_H +#define ATHCONTAINERS_DATAVECTORASELV_H + + +#include "AthContainers/AuxVectorData.h" +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/CurrentEventStore.h" +#include "AthContainersInterfaces/AuxStore_traits.h" +#include "AthLinks/ElementLink.h" +#include <vector> + + +namespace SG { + + +/** + * @brief Helper for @c dataVectorViewAsELV. Don't call this directly. + * + * Handle the case of a view vector with elements deriving from AuxElement. + */ +template <class DV> +void dataVectorViewAsELV (const SG_STD_OR_BOOST::true_type&, + const DV& v, + std::vector<ElementLink<DV> >& ret, + IProxyDict* store) +{ + const DV* last_d = nullptr; + const SG::AuxVectorData* last_b = nullptr; + for (const typename DV::base_value_type* elt : v) { + const SG::AuxVectorData* cont_b = elt->container(); + if (cont_b != last_b) { + last_b = cont_b; + last_d = dynamic_cast<const DV*>(cont_b); + } + if (!last_d) + throw SG::ExcDVToELV ("Element not in a container"); + ret.emplace_back (*last_d, elt->index(), store); + } +} + + + +/** + * @brief Helper for @c dataVectorViewAsELV. Don't call this directly. + * + * Handle the case of a view vector with elements not deriving from AuxElement + * (just throw an exception). + */ +template <class DV> +void dataVectorViewAsELV (const SG_STD_OR_BOOST::false_type&, + const DV&, + std::vector<ElementLink<DV> >&, + IProxyDict*) +{ + throw SG::ExcDVToELV ("Element in view container does not derive from AuxElement."); +} + + + +/** + * @brief Helper to make a vector<EL> from a DataVector. + * + * Given a @c DataVector, return a vector of ElementLink objects that + * reference the @c DataVector's elements. We can always do this if the + * @c DataVector owns its elements. However, if it is a view container, + * then the elements must derive from @c SG::AuxElement and must be + * part of some other container. + */ +template <class DV> +std::vector<ElementLink<DV> > +dataVectorAsELV (const DV& v, IProxyDict* store = 0) +{ + std::vector<ElementLink<DV> > ret; + size_t sz = v.size(); + ret.reserve (sz); + + if (!store) store = SG::CurrentEventStore::store(); + + if (v.ownPolicy() == SG::OWN_ELEMENTS) { + // Could hoist the sgkey lookup. + // But this will probably not be a common case, so don't do that + // unless it's needed. + for (size_t i = 0; i < sz; i++) + ret.emplace_back (v, i, store); + } + else { + dataVectorViewAsELV (typename AuxStore_traits<DV>::flag(), v, ret, store); + } + + return ret; +} + + +} // namespace SG + + +#endif // not ATHCONTAINERS_DATAVECTORASELV_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/debug.h b/EDM/athena/Control/AthContainers/AthContainers/debug.h new file mode 100644 index 00000000..8e1863da --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/debug.h @@ -0,0 +1,186 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/debug.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2015 + * @brief Helper functions intended to be called from the debugger. + */ + + +#ifndef ATHCONTAINERS_DEBUG_H +#define ATHCONTAINERS_DEBUG_H + + +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxVectorData.h" + + +namespace SGdebug { + + +/** + * @brief Return the name corresponding to a given aux id. + * @param id The aux id to look up. + */ +std::string aux_var_name (SG::auxid_t id); + + +/** + * @brief Print the name corresponding to a given aux id. + * @param id The aux id to print. + */ +void print_aux_var_name (SG::auxid_t id); + + +/****************************************************************************** + * Print the list of aux variables given some object. + */ + + +/** + * @brief Print the list of aux variables in a set. + * @param auxids The set to print. + */ +void print_aux_vars (const SG::auxid_set_t& auxids); + + +/** + * @brief Print the list of aux variables handled by a store. + * @param store The store to dump. + */ +void print_aux_vars (const SG::IConstAuxStore& store); + + +/** + * @brief Print the list of aux variables handled by a store. + * @param store The store to dump. + */ +void print_aux_vars (const SG::IConstAuxStore* store); + + +/** + * @brief Print the list of aux variables associated with a container. + * @param vec The container to dump. + */ +void print_aux_vars (const SG::AuxVectorData& vec); + + +/** + * @brief Print the list of aux variables associated with a container. + * @param vec The container to dump. + */ +void print_aux_vars (const SG::AuxVectorData* vec); + + +/** + * @brief Print the list of aux variables associated with an element. + * @param elt The element to dump. + */ +void print_aux_vars (const SG::AuxElement& elt); + + +/** + * @brief Print the list of aux variables associated with an element. + * @param elt The element to dump. + */ +void print_aux_vars (const SG::AuxElement* elt); + + +/****************************************************************************** + * Dump out aux variables. + */ + + +/** + * @brief Convert an aux variable to a string. + * @param auxid The id of the variable. + * @param p Pointer to the location of the variable. + */ +std::string aux_var_as_string (SG::auxid_t auxid, const void* p); + + +/** + * @brief Dump aux variables from a store for a single element. + * @param store The store from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore& store, size_t i); + + +/** + * @brief Dump aux variables from a store for a single element. + * @param store The store from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore* store, size_t i); + + +/** + * @brief Dump aux variables from a store for all elements. + * @param store The store from which to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore& store); + + +/** + * @brief Dump aux variables from a store for all elements. + * @param store The store from which to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore* store); + + +/** + * @brief Dump aux variables from a vector for a single element. + * @param vec The vector from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::AuxVectorData& vec, size_t i); + + +/** + * @brief Dump aux variables from a vector for a single element. + * @param vec The vector from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::AuxVectorData* vec, size_t i); + + +/** + * @brief Dump aux variables from a vector for all elements. + * @param vec The vector from which to dump. + */ +void dump_aux_vars (const SG::AuxVectorData& vec); + + +/** + * @brief Dump aux variables from a vector for all elements. + * @param vec The vector from which to dump. + */ +void dump_aux_vars (const SG::AuxVectorData* vec); + + +/** + * @brief Dump aux variables for an element. + * @param elt The element from which to dump. + */ +void dump_aux_vars (const SG::AuxElement& elt); + + +/** + * @brief Dump aux variables for an element. + * @param elt The element from which to dump. + */ +void dump_aux_vars (const SG::AuxElement* elt); + + +} // namespace SGdebug + + +#endif // not ATHCONTAINERS_DEBUG_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/exceptions.h b/EDM/athena/Control/AthContainers/AthContainers/exceptions.h new file mode 100644 index 00000000..c3a9999e --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/exceptions.h @@ -0,0 +1,371 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: exceptions.h 797205 2017-02-14 19:38:03Z ssnyder $ +/** + * @file AthContainers/exceptions.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Exceptions that can be thrown from AthContainers. + */ + + +#ifndef ATHCONTAINERS_EXCEPTIONS_H +#define ATHCONTAINERS_EXCEPTIONS_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include <stdexcept> +#include <typeinfo> +#include <string> + + +namespace SG { + + +/** + * @brief Exception --- Aux data requested from object with no store. + * + * You attempted to retrieve auxiliary data from an object with no + * associated auxiliary data store. + */ +class ExcNoAuxStore + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param auxid The ID of the requested aux data item. + */ + ExcNoAuxStore (SG::auxid_t auxid); + + + /** + * @brief Constructor. + * @param op The attempted operation. + */ + ExcNoAuxStore (const char* op); +}; + + +/** + * @brief Exception --- Attempt to retrieve nonexistent aux data item. + * + * You attempted to retrieve auxiliary data from an object, but the + * requested item does not exist. + */ +class ExcBadAuxVar + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param auxid The ID of the requested aux data item. + */ + ExcBadAuxVar (SG::auxid_t auxid); +}; + + +/** + * @brief Exception --- Non-const operation performed on const aux data. + * + * You attempted to perform some non-const operation on an object + * with const auxiliary data. + */ +class ExcConstAuxData + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param op The attempted operation. + * @param auxid The ID of the requested aux data item, if any. + */ + ExcConstAuxData (const std::string& op, SG::auxid_t auxid = null_auxid); +}; + + +/** + * @brief Exception --- Attempt to set aux data store on container + * that doesn't track indices, or disable index tracking + * for a container with aux data. + */ +class ExcUntrackedSetStore + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + */ + ExcUntrackedSetStore(); +}; + + + +/** + * @brief Exception --- Bad use of private store. + * + * You called @c makePrivateStore when there was already one, + * or @c releasePrivateStore when there wasn't one. + */ +class ExcBadPrivateStore + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param op The attempted operation. + */ + ExcBadPrivateStore (const std::string& op); +}; + + + +/** + * @brief Exception --- Type mismatch for aux variable + * + * Thrown when there's a mismatch between the type requested for + * an aux data item and a type previously requested for the same item. + */ +class ExcAuxTypeMismatch + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param auxid ID of the requested aux data item. + * @param new_type New type requested for the item. + * @param old_type Previous type associated with the item. + */ + ExcAuxTypeMismatch (SG::auxid_t auxid, + const std::type_info& new_type, + const std::type_info& old_type); +}; + + + +/** + * @brief Exception --- Attempted to do OP on a BASE base class of COMPLETE; + * can only be done on the most-derived class. + * + * Thrown when there's a mismatch between the type requested for + * an aux data item and a type previously requested for the same item. + */ +class ExcInsertionInBaseClass + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param op The attempted operation. + * @param base_type The type on which the operation was attempted. + * @param complete_type The most-derived type of the object. + */ + ExcInsertionInBaseClass (const char* op, + const std::type_info& base_type, + const std::type_info& complete_type); +}; + + +/** + * @brief Exception --- Attempted to modify auxiliary data in a locked store. + * + * Thrown when there was an attempt to access a non-decorator auxiliary + * item in a locked store, or when some other operation that would + * change the store is attempted. + */ +class ExcStoreLocked + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param op The attempted operation. + */ + ExcStoreLocked (SG::auxid_t auxid); + + + /** + * @brief Constructor. + * @param op The attempted operation. + */ + ExcStoreLocked (const char* op); +}; + + +/** + * @brief Exception --- Attempted to insert a unique_ptr to a non-owning container. + * + * The @c unique_ptr interfaces can be used only on containers + * that own their elements. + */ +class ExcNonowningContainer + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + */ + ExcNonowningContainer(); +}; + + +/** + * @brief Throw a SG::ExcNonowningContainer exception. + */ +[[noreturn]] +void throwExcNonowningContainer(); + + +/** + * @brief Exception --- Unknown aux data item. + * + * This can be thrown by @c TypelessConstAccessor if the requested + * item is not known to the registry, or (if the @c type_info is supplied) + * we don't know how to make a vector factory for the given @c type_info. + */ +class ExcUnknownAuxItem + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param name Name of the aux data item. + * @param clsname Class name of the aux data item, or an empty string. + * @param typ Type of the item, if provided. + */ + ExcUnknownAuxItem (const std::string& name, + const std::string& clsname = "", + const std::type_info* typ = 0); +}; + + +/** + * @brief Throw a SG::ExcUnknownAuxItem exception. + * @param name Name of the aux data item. + * @param clsname Class name of the aux data item, or an empty string. + * @param typ Type of the item, if provided. + */ +[[noreturn]] +void throwExcUnknownAuxItem (const std::string& name, + const std::string& clsname = "", + const std::type_info* typ = 0); + + +/** + * @brief Exception --- Can't convert DataVector to vector of ElementLinks. + * + * Thrown by @c dataVectorAsELV when trying to convert a view vector + * and the contained objects either do not derive from @c AuxElement + * or are not part of a container. + */ +class ExcDVToELV + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param detail More information about the error. + */ + ExcDVToELV (const std::string& detail); +}; + + +/** + * @brief Exception --- ViewVector not in view mode. + * + * A ViewVector may only be created with an ownership mode of SG::VIEW_ELEMENTS. + */ +class ExcViewVectorNotView + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + */ + ExcViewVectorNotView(); +}; + + +/** + * @brief Throw a SG::ExcViewVectorNotView exception. + */ +[[noreturn]] +void throwExcViewVectorNotView(); + + +/** + * @brief Exception --- Missing CLID for @c ViewVector. + * + * A @c ViewVector was used in a context that requires a CLID, but no CLID + * was available. Make sure a VIEWVECTOR_CLASS_DEF declaration exists + * for the class in a library that has been loaded. + */ +class ExcMissingViewVectorCLID + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param ti @c type_info for the class with the missing CLID. + */ + ExcMissingViewVectorCLID (const std::type_info& ti); +}; + + +/** + * @brief Throw a SG::ExcMissingViewVectorCLID exception. + * @param ti @c type_info for the class with the missing CLID. + */ +[[noreturn]] +void throwExcMissingViewVectorCLID (const std::type_info& ti); + + +/** + * @brief Exception --- Missing BaseInfo. + * + * Can't find BaseInfo for CLASS. + */ +class ExcMissingBaseInfo + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param ti @c type_info for the class with the missing base info. + */ + ExcMissingBaseInfo (const std::type_info& ti); +}; + + +/** + * @brief Throw a SG::ExcMissingBaseInfo exception. + * @param ti @c type_info for the class with the missing base info. + */ +[[noreturn]] +void throwExcMissingBaseInfo (const std::type_info& ti); + + +/** + * @brief Exception --- Ownership mismatch for insertMove. + * + * For insertMove, both vectors must have the same ownership mode. + */ +class ExcInsertMoveOwnershipMismatch + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + */ + ExcInsertMoveOwnershipMismatch(); +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERS_EXCEPTIONS_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/normalizedTypeinfoName.h b/EDM/athena/Control/AthContainers/AthContainers/normalizedTypeinfoName.h new file mode 100644 index 00000000..6fc5235b --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/normalizedTypeinfoName.h @@ -0,0 +1,53 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/normalizedTypeinfoName.h + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Convert a @c type_info to a normalized string representation + * (matching the names used in the root dictionary). + */ + + +#ifndef ATHCONTAINERS_NORMALIZEDTYPEINFONAME_H +#define ATHCONTAINERS_NORMALIZEDTYPEINFONAME_H + + +#include <string> +#include <typeinfo> + + +namespace SG { + + +/** + * @brief Convert a @c type_info to a normalized string representation + * (matching the names used in the root dictionary). + * @param info The type to convert. + * + * The function `AthContainer_detail::typeinfoName` may be used to convert + * a C++ `type_info` to a string representing the name of the class; this + * handles platform-dependent details such as performing demangling. + * + * However, the name you get as a result of this does not necessarily match + * the name by which the class is known in the ROOT dictionary. + * In particular, defaulted template arguments for STL containers and + * @c DataVector are suppressed in the dictionary. So, for example, + * for a vector class @c typeinfoName may produce + * `std::vector<int, std::allocator<T> >`, while in the dictionary + * it is known as `std::vector<int>`. Using @c normalizedTypeinfoName + * instead will transform the names to match what's in the dictionary. + * This function will also cache the typeinfo -> string conversions. + */ +std::string normalizedTypeinfoName (const std::type_info& info); + + +} + + +#endif // not ATHCONTAINERS_NORMALIZEDTYPEINFONAME_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/selection.xml b/EDM/athena/Control/AthContainers/AthContainers/selection.xml new file mode 100644 index 00000000..8ee8fe7e --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/selection.xml @@ -0,0 +1,191 @@ +<lcgdict> + <class name="UserDataStore"/> + + <class name="SG::AuxTypeRegistry"/> + <class name="SG::AuxVectorBase"/> + <class name="SG::AuxVectorData"> + <field name="m_cache" transient="true"/> + <field name="m_constCache" transient="true"/> + <field name="m_decorCache" transient="true"/> + <field name="m_store" transient="true"/> + <field name="m_constStore" transient="true"/> + <field name="m_constStoreLink" transient="true"/> + <field name="m_mutex" transient="true"/> + </class> + <class name="SG::AuxElement"> + <field name="m_index" transient="true"/> + <field name="m_container" transient="true"/> + <field name="m_privateData" transient="true"/> + </class> + <class name="SG::IAuxElement"> + <field name="m_dummy" transient="true"/> + </class> + <class name="SG::IAuxStore"/> + <class name="SG::IConstAuxStore"/> + <class name="DataLink<SG::IConstAuxStore>" /> + <class name="SG::IAuxStoreIO"/> + <class name="SG::IAuxStoreHolder"/> + <class name="SG::IAuxTypeVectorFactory"/> + <class name="SG::AuxStoreInternal" id="77039D3D-4E24-46C1-B5D1-9AD5F17D3B09"> + <field name="m_vecs" transient="true"/> + <field name="m_isDecoration" transient="true"/> + <field name="m_auxids" transient="true"/> + <field name="m_tick" transient="true"/> + <field name="m_locked" transient="true"/> + <field name="m_mutex" transient="true"/> + <field name="m_tsAuxids" transient="true"/> + </class> + <class name="SG::auxid_set_t"/> + <!--<class pattern="SG::hashtable<unsigned *,unsigned *,std::allocator<unsigned *>,CxxUtils_Internal::identity<unsigned *>,std::equal_to<unsigned *>,SG::hash<unsigned *>,CxxUtils_Internal::mod_range_hashing,CxxUtils_Internal::default_ranged_hash,CxxUtils_Internal::prime_rehash_policy,false,true,true>"> + <field name="m_payload_allocator" transient="true"/> + </class>--> + <class pattern="SG::hashtable<unsigned *"/> + <!--<class pattern="SG::hashtable_const_iterator<unsigned *"/>--> + <!--<class pattern="SG::hashtable_iterator<unsigned *"/>--> + <!--<class pattern="std::pair<*hashtable<unsigned *"/>--> + <function proto_pattern="*operator!=*hashtable_iterator<unsigned *"/> + <function proto_pattern="*operator!=*hashtable_const_iterator<unsigned *"/> + <function proto_pattern="*operator==*hashtable_iterator<unsigned *"/> + <function proto_pattern="*operator==*hashtable_const_iterator<unsigned *"/> + <class name="CxxUtils_Internal::prime_rehash_policy"/> + + <class name="SG::ViewVectorBase"> + <field name="m_clearOnPersistent" transient="true"/> + </class> + <read sourceClass="SG::ViewVectorBase" version="[1-]" + targetClass="SG::ViewVectorBase" source="" + target="" + > + <![CDATA[ + // Let the object prepare for being used: + if (newObj) newObj->toTransient(); + ]]> + </read> + + <class name="SG::AuxElement::TypelessConstAccessor"/> + + <class name="SG::AuxElement::ConstAccessor<char>"/> + <class name="SG::AuxElement::ConstAccessor<unsigned char>"/> + <class name="SG::AuxElement::ConstAccessor<int>"/> + <class name="SG::AuxElement::ConstAccessor<short>"/> + <class name="SG::AuxElement::ConstAccessor<long>"/> + <class name="SG::AuxElement::ConstAccessor<unsigned int>"/> + <class name="SG::AuxElement::ConstAccessor<unsigned short>"/> + <class name="SG::AuxElement::ConstAccessor<unsigned long>"/> + <class name="SG::AuxElement::ConstAccessor<unsigned long long>"/> + <class name="SG::AuxElement::ConstAccessor<float>"/> + <class name="SG::AuxElement::ConstAccessor<double>"/> + <class name="SG::AuxElement::ConstAccessor<bool>"/> + <class name="SG::AuxElement::ConstAccessor<std::string>"/> + + <class name="SG::AuxElement::ConstAccessor<std::vector<char> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<unsigned char> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<int> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<short> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<long> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<unsigned int> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<unsigned short> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<unsigned long> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<unsigned long long> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<float> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<double> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<bool> >"/> + <class name="SG::AuxElement::ConstAccessor<std::vector<std::string> >"/> + + <class name="SG::AuxElement::Accessor<char>"/> + <class name="SG::AuxElement::Accessor<unsigned char>"/> + <class name="SG::AuxElement::Accessor<int>"/> + <class name="SG::AuxElement::Accessor<short>"/> + <class name="SG::AuxElement::Accessor<long>"/> + <class name="SG::AuxElement::Accessor<unsigned int>"/> + <class name="SG::AuxElement::Accessor<unsigned short>"/> + <class name="SG::AuxElement::Accessor<unsigned long>"/> + <class name="SG::AuxElement::Accessor<unsigned long long>"/> + <class name="SG::AuxElement::Accessor<float>"/> + <class name="SG::AuxElement::Accessor<double>"/> + <class name="SG::AuxElement::Accessor<bool>"/> + <class name="SG::AuxElement::Accessor<std::string>"/> + + <class name="SG::AuxElement::Accessor<std::vector<char> >"/> + <class name="SG::AuxElement::Accessor<std::vector<unsigned char> >"/> + <class name="SG::AuxElement::Accessor<std::vector<int> >"/> + <class name="SG::AuxElement::Accessor<std::vector<short> >"/> + <class name="SG::AuxElement::Accessor<std::vector<long> >"/> + <class name="SG::AuxElement::Accessor<std::vector<unsigned int> >"/> + <class name="SG::AuxElement::Accessor<std::vector<unsigned short> >"/> + <class name="SG::AuxElement::Accessor<std::vector<unsigned long> >"/> + <class name="SG::AuxElement::Accessor<std::vector<unsigned long long> >"/> + <class name="SG::AuxElement::Accessor<std::vector<float> >"/> + <class name="SG::AuxElement::Accessor<std::vector<double> >"/> + <class name="SG::AuxElement::Accessor<std::vector<bool> >"/> + <class name="SG::AuxElement::Accessor<std::vector<std::string> >"/> + + <class name="SG::AuxElement::Decorator<char>"/> + <class name="SG::AuxElement::Decorator<unsigned char>"/> + <class name="SG::AuxElement::Decorator<int>"/> + <class name="SG::AuxElement::Decorator<short>"/> + <class name="SG::AuxElement::Decorator<long>"/> + <class name="SG::AuxElement::Decorator<unsigned int>"/> + <class name="SG::AuxElement::Decorator<unsigned short>"/> + <class name="SG::AuxElement::Decorator<unsigned long>"/> + <class name="SG::AuxElement::Decorator<unsigned long long>"/> + <class name="SG::AuxElement::Decorator<float>"/> + <class name="SG::AuxElement::Decorator<double>"/> + <class name="SG::AuxElement::Decorator<bool>"/> + <class name="SG::AuxElement::Decorator<std::string>"/> + + <class name="SG::AuxElement::Decorator<std::vector<char> >"/> + <class name="SG::AuxElement::Decorator<std::vector<unsigned char> >"/> + <class name="SG::AuxElement::Decorator<std::vector<int> >"/> + <class name="SG::AuxElement::Decorator<std::vector<short> >"/> + <class name="SG::AuxElement::Decorator<std::vector<long> >"/> + <class name="SG::AuxElement::Decorator<std::vector<unsigned int> >"/> + <class name="SG::AuxElement::Decorator<std::vector<unsigned short> >"/> + <class name="SG::AuxElement::Decorator<std::vector<unsigned long> >"/> + <class name="SG::AuxElement::Decorator<std::vector<unsigned long long> >"/> + <class name="SG::AuxElement::Decorator<std::vector<float> >"/> + <class name="SG::AuxElement::Decorator<std::vector<double> >"/> + <class name="SG::AuxElement::Decorator<std::vector<bool> >"/> + <class name="SG::AuxElement::Decorator<std::vector<std::string> >"/> + + <class name="SG::PackedParameters"/> + + <enum name="SG::OwnershipPolicy"/> + + <class name="SG::IAuxSetOption"/> + <class name="SG::AuxDataOption"/> + + <class name="SG::PackedContainer<char>"/> + <class name="SG::PackedContainer<unsigned char>"/> + <class name="SG::PackedContainer<short>"/> + <class name="SG::PackedContainer<unsigned short>"/> + <class name="SG::PackedContainer<int>"/> + <class name="SG::PackedContainer<unsigned int>"/> + <class name="SG::PackedContainer<float>"/> + <class name="SG::PackedContainer<double>"/> + + <class name="SG::PackedContainer<std::vector<char> >"/> + <class name="SG::PackedContainer<std::vector<unsigned char> >"/> + <class name="SG::PackedContainer<std::vector<short> >"/> + <class name="SG::PackedContainer<std::vector<unsigned short> >"/> + <class name="SG::PackedContainer<std::vector<int> >"/> + <class name="SG::PackedContainer<std::vector<unsigned int> >"/> + <class name="SG::PackedContainer<std::vector<float> >"/> + <class name="SG::PackedContainer<std::vector<double> >"/> + + <class name="SG::PackedContainer<std::vector<std::vector<char> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<unsigned char> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<short> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<unsigned short> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<int> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<unsigned int> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<float> > >"/> + <class name="SG::PackedContainer<std::vector<std::vector<double> > >"/> + + <function name="SGdebug::aux_var_name"/> + <function name="SGdebug::print_aux_var_name"/> + <function name="SGdebug::aux_var_as_string"/> + <function name="SGdebug::print_aux_vars"/> + <function name="SGdebug::dump_aux_vars"/> + +</lcgdict> diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/ATHCONTAINERS_ASSERT.h b/EDM/athena/Control/AthContainers/AthContainers/tools/ATHCONTAINERS_ASSERT.h new file mode 100644 index 00000000..ae9bc8f4 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/ATHCONTAINERS_ASSERT.h @@ -0,0 +1,35 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/ATHCONTAINERS_ASSERT.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief An overridable variant of assert. + * + * For purposes of unit tests, it's sometimes useful to change the + * behavior of assert, so that, for example, it throws an exception + * rather than aborting. + * + * It turns out that it's not feasible to override what the standard + * assert macro does (because assert.h does not use an include guard). + * So we instead introduce our own assert macro. Normally, this is the + * same as assert, but unit test programs may redefine it. + */ + + +#ifndef ATHCONTAINERS_TOOLS_ATHCONTAINERS_ASSERT_H +#define ATHCONTAINERS_TOOLS_ATHCONTAINERS_ASSERT_H + + +#ifndef ATHCONTAINERS_ASSERT +# include <cassert> +# define ATHCONTAINERS_ASSERT(X) assert(X) +#endif + + +#endif // not ATHCONTAINERS_TOOLS_ATHCONTAINERS_ASSERT_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/AuxDataTraits.h b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxDataTraits.h new file mode 100644 index 00000000..cdffb898 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxDataTraits.h @@ -0,0 +1,113 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/AuxDataTraits.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2014 + * @brief Allow customizing how aux data types are treated. + */ + + +#ifndef ATHCONTAINERS_AUXDATATRAITS_H +#define ATHCONTAINERS_AUXDATATRAITS_H + + +#include <vector> +#include <cstdlib> + + +namespace SG { + + +/** + * @brief Allow customizing how aux data types are treated. + * + * @c T here is the type that the user requests, eg in the template + * argument of a decorator. + */ +template <class T> +class AuxDataTraits +{ +public: + /// The type the user sees. + typedef T element_type; + + /// Reference types returned by aux data accessors. + typedef T& reference_type; + typedef const T& const_reference_type; + + /// Container type used to store this variable. + typedef std::vector<T> vector_type; + + /// Pointers to the data within the container. + typedef typename vector_type::pointer container_pointer_type; + typedef typename vector_type::const_pointer const_container_pointer_type; + + /// Look up an element in the container by index. + /// ptr is a pointer to the start of the container's data. + static reference_type index (void* ptr, size_t ndx) + { + return reinterpret_cast<container_pointer_type>(ptr)[ndx]; + } + + /// Look up an element in the container by index. + /// ptr is a pointer to the start of the container's data. + static const_reference_type index (const void* ptr, size_t ndx) + { + return reinterpret_cast<const_container_pointer_type>(ptr)[ndx]; + } + +}; + + +/** + * @brief Allow customizing how aux data types are treated. + * + * Special case for bool variables. + * + * @c T here is the type that the user requests, eg in the template + * argument of a decorator. + */ +template <> +class AuxDataTraits<bool> +{ +public: + /// The type the user sees. + typedef bool element_type; + + /// Reference types returned by aux data accessors. + typedef bool& reference_type; + typedef const bool& const_reference_type; + + /// Container type used to store this variable. + typedef std::vector<char> vector_type; + + /// Pointers to the data within the container. + typedef vector_type::pointer container_pointer_type; + typedef vector_type::const_pointer const_container_pointer_type; + + /// Look up an element in the container by index. + /// ptr is a pointer to the start of the container's data. + static reference_type index (void* ptr, size_t ndx) + { + return reinterpret_cast<bool*>(ptr)[ndx]; + } + + /// Look up an element in the container by index. + /// ptr is a pointer to the start of the container's data. + static const_reference_type index (const void* ptr, size_t ndx) + { + return reinterpret_cast<const bool*>(ptr)[ndx]; + } +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERS_AUXDATATRAITS_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.h b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.h new file mode 100644 index 00000000..9c2779a6 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.h @@ -0,0 +1,388 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/AuxTypeVector.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Implementation of @c IAuxTypeVector for specific types. + */ + + +#ifndef ATHCONTAINERS_AUXTYPEVECTOR_H +#define ATHCONTAINERS_AUXTYPEVECTOR_H + + +#include "AthContainersInterfaces/IAuxTypeVector.h" +#include "AthContainersInterfaces/IAuxSetOption.h" +#include "AthContainers/tools/AuxDataTraits.h" +#include "AthContainers/PackedContainer.h" +#include "CxxUtils/override.h" +#include <typeinfo> +#include <vector> +#include <algorithm> +#include <stdint.h> + + +#if __cplusplus > 201100 +# include <type_traits> +namespace SG_STD_OR_BOOST = std; +#else +# include "boost/type_traits/is_base_of.hpp" +# include "boost/type_traits/is_arithmetic.hpp" +namespace SG_STD_OR_BOOST = boost; +#endif + + +namespace SG { + + +class AuxDataOption; + + +/** + * @brief Implementation of @c IAuxTypeVector for specific types. + * + * The auxiliary data for a container is stored in a set of STL vectors, + * one for each data item. However, we want to allow storing arbitrary + * types in these vectors. Thus, we define this abstract interface + * to operate on the vectors. This template class provides the + * concrete implementations of this interface. + * + * This class is initialized with a pointer to the actual vector. + * For a version that holds the vector internally, see the derived + * class @c AuxTypeVector. + */ +template <class T, class CONT = typename AuxDataTraits<T>::vector_type> +class AuxTypeVectorHolder + : public IAuxTypeVector +{ +public: + /// Type of the STL vector used for storage. + typedef CONT vector_type; + + /// Type that the user sees. + typedef typename AuxDataTraits<T>::element_type element_type; + + /// Vector element type. + typedef typename vector_type::value_type vector_value_type; + +protected: + /// 1 for the usual case of @c V being @c vector<T>. + /// If @c V is @c vector<char>, then this is @c sizeof(T). + static const int SCALE = sizeof(element_type) / sizeof(vector_value_type); + + +public: + /** + * @brief Constructor. + * @param vecPtr Pointer to the object (of type @c CONT). + * @param ownFlag If true, take ownership of the object. + */ + AuxTypeVectorHolder (vector_type* vecPtr, bool ownFlag); + + + /** + * @brief Destructor. + * If @c ownFlag was true, then delete the vector object. + */ + ~AuxTypeVectorHolder(); + + + /** + * @brief Copy constructor. + * @param other Object to copy. + */ + AuxTypeVectorHolder (const AuxTypeVectorHolder& other); + + + /** + * @brief Move constructor. + * @param other Object to move. + */ + AuxTypeVectorHolder (AuxTypeVectorHolder&& other); + + + /** + * @brief Assignment. + */ + AuxTypeVectorHolder& operator= (const AuxTypeVectorHolder& other); + + + /** + * @brief Move assignment. + */ + AuxTypeVectorHolder& operator= (AuxTypeVectorHolder&& other); + + + /** + * @brief Return a reference to the payload vector. + */ + vector_type& vec(); + + + /** + * @brief Make a copy of this vector. + */ + virtual IAuxTypeVector* clone() const ATH_OVERRIDE; + + + /** + * @brief Return a pointer to the start of the vector's data. + */ + virtual void* toPtr() ATH_OVERRIDE; + + + /** + * @brief Return a pointer to the STL vector itself. + */ + virtual void* toVector() ATH_OVERRIDE; + + + /** + * @brief Return the type of the payload object for this instance. + * + * May be different from what we get from the registry; if packing + * is used, for example. + */ + virtual const std::type_info* objType() const ATH_OVERRIDE; + + + /** + * @brief Return the size of the vector. + */ + virtual size_t size() const ATH_OVERRIDE; + + + /** + * @brief Change the size of the vector. + * @param sz The new vector size. + * Returns true if it is known that iterators have not been invalidated; + * false otherwise. + */ + virtual bool resize (size_t sz) ATH_OVERRIDE; + + + /** + * @brief Change the capacity of the vector. + * @param sz The new vector capacity. + */ + virtual void reserve (size_t sz) ATH_OVERRIDE; + + + /** + * @brief Make an option setting. + * @param option The option to set. + * + * The interpretation of the option depends on the concrete class. + * + * Returns true if the option setting was successful; false otherwise. + */ + virtual bool setOption (const AuxDataOption& option) ATH_OVERRIDE; + + + /** + * @brief Shift the elements of the vector. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + virtual void shift (size_t pos, ptrdiff_t offs) ATH_OVERRIDE; + + + /** + * @brief Insert elements into the vector via move semantics. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * @c beg and @c end define a range of container elements, with length + * @c len defined by the difference of the pointers divided by the + * element size. + * + * The size of the container will be increased by @c len, with the elements + * starting at @c pos copied to @c pos+len. + * + * The contents of the @c beg:end range will then be moved to our vector + * starting at @c pos. This will be done via move semantics if possible; + * otherwise, it will be done with a copy. + * + * Returns true if it is known that the vector's memory did not move, + * false otherwise. + */ + virtual bool insertMove (size_t pos, void* beg, void* end) override; + + + /** + * @brief Try to convert this aux vector to a @c PackedContainer. + * + * If successful, returns a newly-allocated @c IAuxTypeVector. + * In this case, the contents of the vector will have been moved + * to the new vector (and this object will be empty). + * + * Returns null on failure. + */ + virtual IAuxTypeVector* toPacked() ATH_OVERRIDE; + + + /** + * @brief Copy an element between vectors (static method). + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + static void copy (void* dst, size_t dst_index, + const void* src, size_t src_index); + + + /** + * @brief Swap an element between vectors (static method). + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ + static void swap (void* a, size_t aindex, + void* b, size_t bindex); + + + /** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ + static void clear (void* dst, size_t dst_index); + + +private: + /** + * @brief Helper for @c insertMove. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * This does the actual move for POD types. + */ + void insertMove1 (typename CONT::iterator pos, + element_type* beg, + element_type* end, + std::true_type); + + + /** + * @brief Helper for @c insertMove. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * This does the actual move for non-POD types. + */ + void insertMove1 (typename CONT::iterator pos, + element_type* beg, + element_type* end, + std::false_type); + + /// The contained vector. + vector_type* m_vecPtr; + + /// True if we need to delete the object. + bool m_ownFlag; +}; + + +//********************************************************************** + + +/** + * @brief Implementation of @c IAuxTypeVector holding a vector instance. + * + * This is a derived class of @c AuxTypeVectorHolder that holds the vector + * instance as a member variable (and thus manages memory internally). + */ +template <class T, class CONT = typename AuxDataTraits<T>::vector_type> +class AuxTypeVector + : public AuxTypeVectorHolder<T, CONT> +{ +public: + typedef AuxTypeVectorHolder<T, CONT> Base; + typedef typename Base::vector_type vector_type; + typedef typename Base::element_type element_type; + typedef typename Base::vector_value_type vector_value_type; + + /** + * @brief Constructor. Makes a new vector. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ + AuxTypeVector (size_t size, size_t capacity); + + + + /** + * @brief Copy constructor. + */ + AuxTypeVector (const AuxTypeVector& other); + + + /** + * @brief Move constructor. + */ + AuxTypeVector (AuxTypeVector&& other); + + + /** + * @brief Assignment. + */ + AuxTypeVector& operator= (const AuxTypeVector& other); + + + /** + * @brief Move assignment. + */ + AuxTypeVector& operator= (AuxTypeVector&& other); + + + /** + * @brief Make a copy of this vector. + */ + virtual IAuxTypeVector* clone() const override; + + +private: + /// The contained vector. + vector_type m_vec; +}; + + +} // namespace SG + + +#include "AthContainers/tools/AuxTypeVector.icc" + + +#endif // not ATHCONTAINERS_AUXTYPEVECTOR_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.icc new file mode 100644 index 00000000..5d603155 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVector.icc @@ -0,0 +1,598 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/AuxTypeVector.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Implementation of @c IAuxTypeVector for specific types. + */ + + +namespace SG { + + +/** + * @brief Constructor. + * @param vecPtr Pointer to the object (of type @c CONT). + * @param ownFlag If true, take ownership of the object. + */ +template <class T, class CONT> +inline +AuxTypeVectorHolder<T, CONT>::AuxTypeVectorHolder (vector_type* vecPtr, bool ownFlag) + : m_vecPtr (vecPtr), + m_ownFlag (ownFlag) +{ +} + + +/** + * @brief Destructor. + * If @c ownFlag was true, then delete the vector object. + */ +template <class T, class CONT> +inline +AuxTypeVectorHolder<T, CONT>::~AuxTypeVectorHolder() +{ + if (m_ownFlag) + delete m_vecPtr; +} + + +/** + * @brief Copy constructor. + * @param other Object to copy. + */ +template <class T, class CONT> +AuxTypeVectorHolder<T, CONT>::AuxTypeVectorHolder + (const AuxTypeVectorHolder& other) +{ + // If we own the payload, then make a copy, else just use the same pointer. + m_ownFlag = other.m_ownFlag; + if (other.m_ownFlag) + m_vecPtr = new vector_type (*other.m_vecPtr); + else + m_vecPtr = other.m_vecPtr; +} + + +/** + * @brief Move constructor. + * @param other Object to move. + */ +template <class T, class CONT> +AuxTypeVectorHolder<T, CONT>::AuxTypeVectorHolder (AuxTypeVectorHolder&& other) +{ + m_ownFlag = other.m_ownFlag; + m_vecPtr = other.m_vecPtr; + other.m_ownFlag = false; +} + + +/** + * @brief Assignment. + */ +template <class T, class CONT> +AuxTypeVectorHolder<T, CONT>& +AuxTypeVectorHolder<T, CONT>::operator= (const AuxTypeVectorHolder& other) +{ + if (this != &other) { + if (m_ownFlag) + delete m_vecPtr; + m_ownFlag = other.m_ownFlag; + if (other.m_ownFlag) + m_vecPtr = new vector_type (*other.m_vecPtr); + else + m_vecPtr = other.m_vecPtr; + } + return *this; +} + + +/** + * @brief Move assignment. + */ +template <class T, class CONT> +AuxTypeVectorHolder<T, CONT>& +AuxTypeVectorHolder<T, CONT>::operator= (AuxTypeVectorHolder&& other) +{ + if (this != &other) { + if (m_ownFlag) + delete m_vecPtr; + m_ownFlag = other.m_ownFlag; + m_vecPtr = other.m_vecPtr; + other.m_ownFlag = false; + } + return *this; +} + + +/** + * @brief Return a reference to the payload vector. + */ +template <class T, class CONT> +inline +typename AuxTypeVectorHolder<T, CONT>::vector_type& AuxTypeVectorHolder<T, CONT>::vec() +{ + return *m_vecPtr; +} + + +/** + * @brief Make a copy of this vector. + */ +template <class T, class CONT> +inline +IAuxTypeVector* AuxTypeVectorHolder<T, CONT>::clone() const +{ + if (m_ownFlag) { + vector_type* vecPtr = new vector_type (*m_vecPtr); + return new AuxTypeVectorHolder<T, CONT> (vecPtr, true); + } + return new AuxTypeVectorHolder<T, CONT> (m_vecPtr, false); +} + + +/** + * @brief Return a pointer to the start of the vector's data. + */ +template <class T, class CONT> +inline +void* AuxTypeVectorHolder<T, CONT>::toPtr () +{ + if (m_vecPtr->empty()) + return nullptr; + return m_vecPtr->data(); +} + + +/** + * @brief Return a pointer to the STL vector itself. + */ +template <class T, class CONT> +inline +void* AuxTypeVectorHolder<T, CONT>::toVector () +{ + return m_vecPtr; +} + + +/** + * @brief Return the type of the complete payload object. + * + * May be different from what we get from the registry; if packing + * is used, for example. + */ +template <class T, class CONT> +inline +const std::type_info* AuxTypeVectorHolder<T, CONT>::objType() const +{ + return &typeid(vector_type); +} + + +/** + * @brief Return the size of the vector. + */ +template <class T, class CONT> +inline +size_t AuxTypeVectorHolder<T, CONT>::size () const +{ + return m_vecPtr->size() / SCALE; +} + + +/** + * @brief Change the size of the vector. + * @param sz The new vector size. + * Returns true if it is known that iterators have not been invalidated; + * false otherwise. + */ +template <class T, class CONT> +inline +bool AuxTypeVectorHolder<T, CONT>::resize (size_t sz) +{ + const void* orig = m_vecPtr->data(); + m_vecPtr->resize (sz * SCALE); + return m_vecPtr->data() == orig; +} + + +/** + * @brief Change the capacity of the vector. + * @param sz The new vector capacity. + */ +template <class T, class CONT> +inline +void AuxTypeVectorHolder<T, CONT>::reserve (size_t sz) +{ + m_vecPtr->reserve (sz * SCALE); +} + + +} // namespace SG + + +namespace DataModel_detail { + + +/// Make an option setting. VEC derives from @c IAuxSetOption. +template <class VEC> +bool setOptionHelper (VEC* vec, const SG::AuxDataOption& option, SG_STD_OR_BOOST::true_type) +{ + SG::IAuxSetOption* setopt = static_cast<SG::IAuxSetOption*> (vec); + return setopt->setOption (option); +} + + +/// Make an option setting. VEC does not derive from @c IAuxSetOption, +/// so this just returns failure. +template <class VEC> +bool setOptionHelper (VEC* /*vec*/, const SG::AuxDataOption& /*option*/, SG_STD_OR_BOOST::false_type) +{ + return false; +} + + +} // namespace DataModel_detail + + +namespace SG { + + +/** + * @brief Make an option setting. + * @param option The option to set. + * + * The interpretation of the option depends on the concrete class. + * + * Returns true if the option setting was successful; false otherwise. + */ +template <class T, class CONT> +inline +bool AuxTypeVectorHolder<T, CONT>::setOption (const AuxDataOption& option) +{ + // Need to instantiate different functions depending on whether or not + // the payload implements @c SG::IAuxSetOption. + return DataModel_detail::setOptionHelper + (m_vecPtr, + option, + typename SG_STD_OR_BOOST::is_base_of<SG::IAuxSetOption,vector_type>::type()); +} + + +/** + * @brief Shift the elements of the vector. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +template <class T, class CONT> +void AuxTypeVectorHolder<T, CONT>::shift (size_t pos, ptrdiff_t offs) +{ + vector_type& vec = *m_vecPtr; + if (offs < 0) { + if (-offs > static_cast<ptrdiff_t>(pos)) offs = -pos; + std::copy (vec.begin() + pos*SCALE, + vec.end(), + vec.begin() + (pos+offs)*SCALE); + vec.resize (vec.size() + offs*SCALE); + } + else if (offs > 0) { + size_t oldsz = vec.size(); + vec.resize (vec.size() + offs*SCALE); + std::copy (vec.rbegin() + offs*SCALE, + vec.rbegin() + (offs+oldsz-pos)*SCALE, + vec.rbegin()); + std::fill (vec.begin() + pos*SCALE, + vec.begin() + (pos+offs)*SCALE, + typename AuxDataTraits<T>::element_type()); + } +} + + +/** + * @brief Helper for @c insertMove. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * This does the actual move for POD types. + */ +template <class T, class CONT> +void AuxTypeVectorHolder<T, CONT>::insertMove1 + (typename CONT::iterator pos, + element_type* beg, + element_type* end, + std::true_type) +{ + m_vecPtr->insert (pos, beg, end); +} + + +/** + * @brief Helper for @c insertMove. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * This does the actual move for non-POD types. + */ +template <class T, class CONT> +void AuxTypeVectorHolder<T, CONT>::insertMove1 + (typename CONT::iterator pos, + element_type* beg, + element_type* end, + std::false_type) +{ + // std::vector doesn't provide a way to insert a range via move. + // So first make space, then move. + typename CONT::iterator pos2= m_vecPtr->insert (pos, end-beg, element_type()); + std::move (beg, end, pos2); +} + + +/** + * @brief Insert elements into the vector via move semantics. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * @c beg and @c end define a range of container elements, with length + * @c len defined by the difference of the pointers divided by the + * element size. + * + * The size of the container will be increased by @c len, with the elements + * starting at @c pos copied to @c pos+len. + * + * The contents of the @c beg:end range will then be moved to our vector + * starting at @c pos. This will be done via move semantics if possible; + * otherwise, it will be done with a copy. + * + * Returns true if it is known that the vector's memory did not move, + * false otherwise. + */ +template <class T, class CONT> +bool AuxTypeVectorHolder<T, CONT>::insertMove (size_t pos, void* beg, void* end) +{ + const void* orig = m_vecPtr->data(); + insertMove1 (m_vecPtr->begin() + pos*SCALE, + reinterpret_cast<element_type*> (beg), + reinterpret_cast<element_type*> (end), + typename std::is_pod<element_type>::type()); + return m_vecPtr->data() == orig; +} + + +} // namespace SG + + +namespace DataModel_detail { + + +/// Specialization for the case of types that can be packed. +template <class T> +SG::IAuxTypeVector* makePacked (std::vector<T>& v, SG_STD_OR_BOOST::true_type) +{ + // Make the new container and move our contents. + SG::AuxTypeVector<T, SG::PackedContainer<T> >* iv = + new SG::AuxTypeVector<T, SG::PackedContainer<T> > (0, 0); + iv->vec().swap (v); + return iv; +} + + +/// Specialization for the case of types that cannot be packed. +template <class T, class FLAG> +SG::IAuxTypeVector* makePacked (T&, FLAG) +{ + return 0; +} + + +/// Metafunction to determine if a @c vector<T> can be packed. +/// Arithmetic types can be packed, as can arbitrarily-nested vectors +/// of them, except that integers larger than 32 bits and long double +/// cannot be packed. +template <class T> +struct can_pack +{ + typedef typename SG_STD_OR_BOOST::is_arithmetic<T>::type type; +}; +template <> +struct can_pack<uint64_t> +{ + typedef SG_STD_OR_BOOST::false_type type; +}; +template <> +struct can_pack<int64_t> +{ + typedef SG_STD_OR_BOOST::false_type type; +}; +template <> +struct can_pack<long double> +{ + typedef SG_STD_OR_BOOST::false_type type; +}; +template <class T> +struct can_pack<std::vector<T> > +{ + typedef typename can_pack<T>::type type; +}; + + +} // namespace DataModel_detail + + +namespace SG { + + +/** + * @brief Try to convert this aux vector to a @c PackedContainer. + * + * If successful, returns a newly-allocated @c IAuxTypeVector. + * In this case, the contents of the vector will have been moved + * to the new vector (and this object will be empty). + * + * Returns null on failure. + */ +template <class T, class CONT> +IAuxTypeVector* AuxTypeVectorHolder<T, CONT>::toPacked() +{ + /// Use the proper instantiation depending on whether or not + /// this type can be packed. + return DataModel_detail::makePacked + (*m_vecPtr, typename DataModel_detail::can_pack<T>::type()); +} + + +/** + * @brief Copy an element between vectors (static method). + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +template <class T, class CONT> +inline +void AuxTypeVectorHolder<T, CONT>::copy (void* dst, size_t dst_index, + const void* src, size_t src_index) +{ + (reinterpret_cast<vector_value_type*>(dst))[dst_index] = + (reinterpret_cast<const vector_value_type*>(src))[src_index]; +} + + +/** + * @brief Swap an element between vectors (static method). + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ +template <class T, class CONT> +inline +void AuxTypeVectorHolder<T, CONT>::swap (void* a, size_t aindex, + void* b, size_t bindex) +{ + std::swap ((reinterpret_cast<vector_value_type*>(a))[aindex], + (reinterpret_cast<vector_value_type*>(b))[bindex]); +} + + +/** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ +template <class T, class CONT> +inline +void AuxTypeVectorHolder<T, CONT>::clear (void* dst, size_t dst_index) +{ + (reinterpret_cast<vector_value_type*>(dst))[dst_index] = vector_value_type(); +} + + +//********************************************************************** + + +/** + * @brief Constructor. Makes a new vector. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ +template <class T, class CONT> +AuxTypeVector<T, CONT>::AuxTypeVector (size_t size, size_t capacity) + : Base (&m_vec, false) +{ + m_vec.reserve (capacity * Base::SCALE); + m_vec.resize (size * Base::SCALE); +} + + +/** + * @brief Copy constructor. + */ +template <class T, class CONT> +AuxTypeVector<T, CONT>::AuxTypeVector (const AuxTypeVector& other) + : Base (&m_vec, false), + m_vec (other.m_vec) +{ +} + + +/** + * @brief Move constructor. + */ +template <class T, class CONT> +AuxTypeVector<T, CONT>::AuxTypeVector (AuxTypeVector&& other) + : Base (&m_vec, false), + m_vec (std::move (other.m_vec)) +{ +} + + +/** + * @brief Assignment. + */ +template <class T, class CONT> +AuxTypeVector<T, CONT>& +AuxTypeVector<T, CONT>::operator= (const AuxTypeVector& other) +{ + if (this != &other) { + m_vec = other.m_vec; + } + return *this; +} + + +/** + * @brief Move assignment. + */ +template <class T, class CONT> +AuxTypeVector<T, CONT>& +AuxTypeVector<T, CONT>::operator= (AuxTypeVector&& other) +{ + if (this != &other) { + m_vec = std::move (other.m_vec); + } + return *this; +} + + + + +/** + * @brief Make a copy of this vector. + */ +template <class T, class CONT> +inline +IAuxTypeVector* AuxTypeVector<T, CONT>::clone() const +{ + return new AuxTypeVector<T, CONT> (*this); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.h b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.h new file mode 100644 index 00000000..c59d2924 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.h @@ -0,0 +1,138 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/AuxTypeVectorFactory.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Factory objects that creates vectors using @c AuxTypeVector. + */ + + +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" +#include "AthContainers/tools/AuxTypeVector.h" + + +#ifndef ATHCONTAINERS_AUXTYPEVECTORFACTORY_H +#define ATHCONTAINERS_AUXTYPEVECTORFACTORY_H + + +namespace SG { + + +/** + * @brief Factory objects that creates vectors using @c AuxTypeVector. + * + * This is an implementation of @c IAuxTypeVectorFactory that makes + * vectors using the @c AuxTypeVector implementation. + */ +template <class T> +class AuxTypeVectorFactory + : public IAuxTypeVectorFactory +{ +public: + /** + * @brief Create a vector object of this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + virtual IAuxTypeVector* create (size_t size, size_t capacity) const; + + + /** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * But if @c isPacked is @c true, then @c data + * should instead point at an object of type @c SG::PackedContainer<T>. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + virtual IAuxTypeVector* createFromData (void* data, + bool isPacked, + bool ownFlag) const; + + + /** + * @brief Copy an element between vectors. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + virtual void copy (void* dst, size_t dst_index, + const void* src, size_t src_index) const; + + + /** + * @brief Swap an element between vectors. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ + virtual void swap (void* a, size_t aindex, + void* b, size_t bindex) const; + + + /** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ + virtual void clear (void* dst, size_t dst_index) const; + + + /** + * @brief Return the size of an element of this vector type. + */ + virtual size_t getEltSize() const; + + + /** + * @brief Return the @c type_info of the vector. + */ + virtual const std::type_info* tiVec() const; + + + /** + * @brief True if the vectors created by this factory work by dynamic + * emulation (via @c TVirtualCollectionProxy or similar); false + * if the std::vector code is used directly. + */ + virtual bool isDynamic() const; + + +private: + /// Helpers for creating vector from a data blob, + IAuxTypeVector* createFromData (void* data, bool isPacked, bool ownFlag, + std::true_type) const; + IAuxTypeVector* createFromData (void* data, bool isPacked, bool ownFlag, + std::false_type) const; +}; + + +} // namespace SG + + +#include "AthContainers/tools/AuxTypeVectorFactory.icc" + + +#endif // not ATHCONTAINERS_AUXTYPEVECTORFACTORY_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.icc new file mode 100644 index 00000000..e4734408 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/AuxTypeVectorFactory.icc @@ -0,0 +1,187 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/AuxTypeVectorFactory.icc + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Factory objects that creates vectors using @c AuxTypeVector. + */ + + +namespace SG { + + +/** + * @brief Create a vector object of this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ +template <class T> +IAuxTypeVector* +AuxTypeVectorFactory<T>::create (size_t size, size_t capacity) const +{ + return new AuxTypeVector<T> (size, capacity); +} + + +/** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * This is for types which are packable. + */ +template <class T> +IAuxTypeVector* +AuxTypeVectorFactory<T>::createFromData (void* data, + bool isPacked, + bool ownFlag, + std::true_type) const +{ + if (isPacked) { + typedef typename SG::AuxDataTraits<T>::vector_type unpacked_vector_type; + typedef typename unpacked_vector_type::value_type element_type; + typedef SG::PackedContainer<element_type> vector_type; + return new AuxTypeVectorHolder<T, vector_type > + (reinterpret_cast<vector_type*>(data), ownFlag); + } + else { + typedef typename AuxTypeVectorHolder<T>::vector_type vector_type; + return new AuxTypeVectorHolder<T> (reinterpret_cast<vector_type*>(data), true); + } +} + + +/** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * This is for types which are not packable. + */ +template <class T> +IAuxTypeVector* +AuxTypeVectorFactory<T>::createFromData (void* data, + bool isPacked, + bool ownFlag, + std::false_type) const +{ + if (isPacked) std::abort(); + typedef typename AuxTypeVectorHolder<T>::vector_type vector_type; + return new AuxTypeVectorHolder<T> + (reinterpret_cast<vector_type*>(data), ownFlag); +} + + +/** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * But if @c isPacked is @c true, then @c data + * should instead point at an object of type @c SG::PackedContainer<T>. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ +template <class T> +IAuxTypeVector* +AuxTypeVectorFactory<T>::createFromData (void* data, + bool isPacked, + bool ownFlag) const +{ + return createFromData (data, isPacked, ownFlag, + typename DataModel_detail::can_pack<T>::type()); +} + + +/** + * @brief Copy an element between vectors. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +template <class T> +void AuxTypeVectorFactory<T>::copy (void* dst, size_t dst_index, + const void* src, size_t src_index) const +{ + return AuxTypeVector<T>::copy (dst, dst_index, src, src_index); +} + + +/** + * @brief Swap an element between vectors. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ +template <class T> +void AuxTypeVectorFactory<T>::swap (void* a, size_t aindex, + void* b, size_t bindex) const +{ + return AuxTypeVector<T>::swap (a, aindex, b, bindex); +} + + +/** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ +template <class T> +void AuxTypeVectorFactory<T>::clear (void* dst, size_t dst_index) const +{ + return AuxTypeVector<T>::clear (dst, dst_index); +} + + +/** + * @brief Return the size of an element of this vector type. + */ +template <class T> +size_t AuxTypeVectorFactory<T>::getEltSize() const +{ + return sizeof (typename AuxTypeVector<T>::vector_type::value_type); +} + + +/** + * @brief Return the @c type_info of the vector. + */ +template <class T> +const std::type_info* AuxTypeVectorFactory<T>::tiVec() const +{ + return &typeid (typename AuxTypeVector<T>::vector_type); +} + + +/** + * @brief True if the vectors created by this factory work by dynamic + * emulation (via @c TVirtualCollectionProxy or similar); false + * if the std::vector code is used directly. + */ +template <class T> +bool AuxTypeVectorFactory<T>::isDynamic() const +{ + return false; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/ClassID.h b/EDM/athena/Control/AthContainers/AthContainers/tools/ClassID.h new file mode 100644 index 00000000..f89d7c69 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/ClassID.h @@ -0,0 +1,35 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/ClassID.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Standalone helpers. + */ + + +#ifndef ATHCONTAINERS_CLASSID_H +#define ATHCONTAINERS_CLASSID_H + + +#ifdef XAOD_STANDALONE + +typedef unsigned int CLID; +static const CLID CLID_NULL = 0; + + +#else + + +#include "GaudiKernel/ClassID.h" + + +#endif + + +#endif // not ATHCONTAINERS_CLASSID_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/CompareAndPrint.h b/EDM/athena/Control/AthContainers/AthContainers/tools/CompareAndPrint.h new file mode 100644 index 00000000..041d7035 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/CompareAndPrint.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHCONTAINERS_TOOLS_COMPAREANDPRINT_H +#define ATHCONTAINERS_TOOLS_COMPAREANDPRINT_H 1 + +//**************************************************************************** +// Helpers for deleting @c DataVector/List elements. +// + +#include <algorithm> /*sort, unique */ +#include <typeinfo> + +namespace DataModel_detail { +/** + * @brief Helper for @c remove_duplicates. + * + * Functor to compare two pointers and optionally print a complaint + * if they're the same. + */ +class CompareAndPrint +{ +public: + /** + * @brief Constructor. + * @param quiet If @c false, then print a complaint if duplicate + * pointers are found. + */ + CompareAndPrint(bool quiet) + : m_quiet(quiet) {} + + + /** + * @brief Compare two pointers. + * Maybe print a complaint if we find a duplicate. + * @param f First pointer to compare. + * @param s Second pointer to compare. + * @return The result of the comparison. + */ + template <typename Element> + bool operator()(Element* f, Element* s) const + { + bool areEq = (f == s); + if (!m_quiet && areEq && f != 0) + warn (typeid (*f), f); + return areEq; + } + + + /** + * @brief Duplicate elements were found; print a warning + * @param ti @c type_info for the element. + * @param f The element pointer. + */ + // This is defined out-of-line in the cxx file. + void warn (const std::type_info& ti, const void* f) const; + + +private: + /// Quiet flag. + bool m_quiet; +}; +} // namespace DataModel_detail +#endif // not ATHCONTAINERS_TOOLS_COMPAREANDPRINT_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/CurrentEventStore.h b/EDM/athena/Control/AthContainers/AthContainers/tools/CurrentEventStore.h new file mode 100644 index 00000000..859dd582 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/CurrentEventStore.h @@ -0,0 +1,42 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/CurrentEventStore.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Wrapper for CurrentEventStore, to do the correct thing + * for both Athena and standalone builds. + */ + + +#ifndef ATHCONTAINERS_CURRENTEVENTSTORE_H +#define ATHCONTAINERS_CURRENTEVENTSTORE_H + + +#ifdef XAOD_STANDALONE +#include "xAODRootAccessInterfaces/TVirtualEvent.h" +#include "xAODRootAccessInterfaces/TActiveEvent.h" + +typedef xAOD::TVirtualEvent IProxyDict; +namespace SG { +class CurrentEventStore +{ +public: + static IProxyDict* store() + { + return xAOD::TActiveEvent::event(); + } +}; +} // namespace SG +#else +#include "SGTools/CurrentEventStore.h" +#include "AthenaKernel/IProxyDict.h" +#endif + + +#endif // not ATHCONTAINERS_CURRENTEVENTSTORE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLCast.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLCast.h new file mode 100644 index 00000000..ea7303a3 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLCast.h @@ -0,0 +1,159 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/DVLCast.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief casting operations for @c DataVector/@c DataList. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVLCAST_H +#define ATHCONTAINERS_TOOLS_DVLCAST_H + + +#include <limits> +#include <limits.h> +#include <typeinfo> +#include <cstdlib> +#include <cstddef> + + +namespace DataModel_detail { + + +#ifdef __GCCXML__ +// Dummy version for reflex. +template <class DVL> +struct DVLCast +{ + typedef typename DVL::base_value_type T; + template <class U> static T* cast (U* b); + template <class U> static const T* cast (const U* b); +}; +#else +/** + * @brief casting operations for @c DataVector/@c DataList. + * + * When inheritance is used with @c DataVector/List, we need to be able + * to cast from the pointers actually stored in the container to the + * @c T* pointers which the derived @c DataVector/List uses. We want + * this to use a @c static_cast if at all possible, and @c dynamic_cast + * otherwise. + * + * This is handled by this template. The operation + * + *@code + * DVLCast<DVL>::cast (p) + @endcode + * + * will cast the pointer @c p to @c DVL's T* type. This is done + * either by @c static_cast or @c dynamic_cast, depending on the value + * of @c DVL::has_virtual. + */ +template <class DVL, bool has_virtual=DVL::has_virtual> struct DVLCast {}; + + +/** + * @brief casting operations for @c DataVector/List, @c static_cast version. + */ +template <class DVL> +struct DVLCast<DVL, false> +{ + typedef typename DVL::base_value_type T; + + + /** + * @brief Cast @a b to a @c T*. + * @param b Pointer to cast. + */ + template <class U> + static T* cast (U* b) + { + return static_cast<T*> (b); + } + + + /** + * @brief Cast @a b to a @c const T*. + * @param b Pointer to cast. + */ + template <class U> + static const T* cast (const U* b) + { + return static_cast<const T*> (b); + } +}; + + +/** + * @brief casting operations for @c DataVector/List, @c dynamic_cast version. + */ +template <class DVL> +struct DVLCast<DVL, true> +{ + typedef typename DVL::base_value_type T; + + + /** + * @brief Cast @a b to a @c T*. + * @param b Pointer to cast. + */ + template <class U> + static T* cast (U* b) + { + // The common case will be for the dynamic type of b to be T. + // So test to avoid a dynamic_cast in that case. + // The extra test shouldn't add significant overhead + // to the case where we really need to run dynamic_cast. + if (!b) + return 0; + if (typeid(*b) == typeid(T)) { + static ptrdiff_t offs = LONG_MAX; + if (offs == LONG_MAX) { + T* ret = dynamic_cast<T*> (b); + offs = reinterpret_cast<char*>(ret) - reinterpret_cast<char*>(b); + return ret; + } + return reinterpret_cast<T*> (reinterpret_cast<char*>(b) + offs); + } + else + return dynamic_cast<T*> (b); + } + + + /** + * @brief Cast @a b to a @c const T*. + * @param b Pointer to cast. + */ + template <class U> + static const T* cast (const U* b) + { + // See above. + if (!b) + return 0; + if (typeid(*b) == typeid(T)) { + static ptrdiff_t offs = LONG_MAX; + if (offs == LONG_MAX) { + T* ret = dynamic_cast<const T*> (b); + offs = reinterpret_cast<char*>(ret) - reinterpret_cast<char*>(b); + return ret; + } + return reinterpret_cast<const T*> (reinterpret_cast<char*>(b) + offs); + } + else + return dynamic_cast<const T*> (b); + } +}; +#endif // not __GCCXML__ + + +} // namespace DataModel_detail + + +#endif // not ATHCONTAINERS_TOOLS_DVLCAST_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.h new file mode 100644 index 00000000..161db007 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.h @@ -0,0 +1,169 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLDataBucket.h,v 1.2 2008-06-17 00:44:17 ssnyder Exp $ + +/** + * @file AthContainers/tools/DVLDataBucket.h + * @author scott snyder + * @date Mar 2008 + * @brief A @c DataBucket specialized for @c DataVector/@c DataList. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVLDATABUCKET_H +#define ATHCONTAINERS_TOOLS_DVLDATABUCKET_H + +#include "AthContainers/ViewVector.h" +#include "SGTools/DataBucket.h" +#include "AthContainers/tools/DVLInfo.h" +#include <memory> + + + +namespace SG { + + +/** + * @brief A @c DataBucket specialized for @c DataVector/@c DataList. + * + * @c DataVector and @c DataList have some special conversion requirements. + * + * In particular, we may have a situation where we're asked to convert + * from @c DataVector\<D> to @c DataVector\<B>, where these two classes + * are not related by inheritance, but @c D derived from @B. + * (In practice, this arises when one has multiple inheritance, + * and can't mirror both arms with @c DataVector/@c DataList.) + * + * This @c DataBucket allows such conversions to happen by making + * a copy of the container (as a view container) and converting the contained + * pointers. The new instance remains owned by the @c DataBucket. + * + * We may also try to create a bucket for a @c ViewVector<DV> object + * given a pointer to its @c DV base class. In such a case, we detect + * that we actually have a @c ViewVector and adjust appropriately the + * CLID and type_info that we return. + */ +template <class T> +class DVLDataBucket + : public SG::DataBucket<T> +{ +public: + /** + * @brief Default constructor. + */ + DVLDataBucket() : + m_ti (nullptr), + m_clid (CLID_NULL) + {} + + + /** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ + DVLDataBucket (T* data); + + +#if __cplusplus > 201100 + /** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ + DVLDataBucket(std::unique_ptr<T> data); +#endif + + + /** + * @brief Copy constructor. + * @param other Bucket to copy. + */ + DVLDataBucket (const DVLDataBucket& other); + + + /** + * @brief Destructor. + */ + virtual ~DVLDataBucket() override; + + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a clid. Note that only + * derived->base conversions are allowed here. + * @param clid The class ID to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + virtual void* cast (CLID clid, IRegisterTransient* irt = 0, + bool isConst = true) const override; + + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a std::type_info. Note that only + * derived->base conversions are allowed here. + * @param clid The @a std::type_info of the type to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + virtual void* cast (const std::type_info& tinfo, + IRegisterTransient* irt = 0, + bool isConst = true) const override; + + + /** + * @brief Return a new @c DataBucket whose payload has been cloned from the + * original one. + */ + virtual DVLDataBucket* clone() const override; + + + /** + * @brief The CLID for the class of object we're holding. + * + * May be different from that of the base @c DataVector in the case + * of a @c ViewVector. + */ + virtual const CLID& clID() const override; + + + /** + * @brief The std::type_info for the class of object we're holding. + * + * May be different from that of the base @c DataVector in the case + * of a @c ViewVector. + */ + virtual const std::type_info& tinfo() const override; + + +private: + typedef std::pair<DataModel_detail::DVLInfoBase*, void*> ent_t; + typedef std::vector<ent_t> vec_t; + mutable vec_t m_copies; + + /// The std::type_info for the class of object we're holding. + /// May be different from that of the base @c DataVector in the case + /// of a @c ViewVector. + const std::type_info* m_ti; + + /// The CLID for the class of object we're holding. + /// May be different from that of the base @c DataVector in the case + /// of a @c ViewVector. + CLID m_clid; + + // Avoid coverity warning. + DVLDataBucket& operator= (const DVLDataBucket&); +}; + + +} // namespace SG + + +#include "AthContainers/tools/DVLDataBucket.icc" + + +#endif // not ATHCONTAINERS_TOOLS_DVLDATABUCKET_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.icc new file mode 100644 index 00000000..2dc3c9c7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLDataBucket.icc @@ -0,0 +1,274 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLDataBucket.icc,v 1.2 2008-06-17 00:44:17 ssnyder Exp $ +/** + * @file AthContainers/tools/DVLDataBucket.icc + * @author scott snyder + * @date Mar 2008 + * @brief A @c DataBucket specialized for @c DataVector/@c DataList. + * + * Template and inline implementations. + */ + + +#include "AthContainers/exceptions.h" +#include "SGTools/IRegisterTransient.h" + + +namespace SG { + + +/** + * @brief Is a @c DataVector we're trying to record actually a @c ViewVector? + * @param data Object being recorded. + * @param[out] clid If the object is a @c ViewVector, set to the CLID + * of that class. Otherwise unchanged. + * @returns The @c type_info for the object being recorded, either the + * @c DataVector or a @c ViewVector that derives from it. + */ +template <class T> +const std::type_info* testViewVector (const DataVector<T>& data, + CLID& clid) +{ + // If this is a view container, test for @c ViewVector. + if (data.ownPolicy() == SG::VIEW_ELEMENTS) { + // See if we actually have a @c ViewVector. + // FIXME: This doesn't work if @c ViewVector is templated on an intermediate + // class rather than @c DataVector directly. + if (dynamic_cast<const ViewVector<DataVector<T> >*> (&data)) { + const std::type_info& ti = typeid(ViewVector<DataVector<T> >); + const SG::BaseInfoBase* bib = SG::BaseInfoBase::find (ti); + if (bib) { + clid = bib->clid(); + if (clid == CLID_NULL) + SG::throwExcMissingViewVectorCLID (ti); + return &ti; + } + else { + SG::throwExcMissingBaseInfo (ti); + } + } + } + return &typeid(DataVector<T>); +} + + +/** + * @brief Is a @c DataVector we're trying to record actually a @c ViewVector? + * + * Handle the case where the object being recorded is not a @c DataVector. + */ +template <class T> +const std::type_info* testViewVector (const T& , + CLID& ) +{ + return &typeid(T); +} + + +/** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ +template <class T> +DVLDataBucket<T>::DVLDataBucket (T* data) + : DataBucket<T> (data) +{ + m_clid = DataBucket<T>::classID(); + m_ti = testViewVector (*this->ptr(), m_clid); +} + + +#if __cplusplus > 201100 +/** + * @brief Constructor from a payload object. + * @param data Object to hold in the bucket. + */ +template <class T> +DVLDataBucket<T>::DVLDataBucket (std::unique_ptr<T> data) + : DataBucket<T> (std::move (data)) +{ + m_clid = DataBucket<T>::classID(); + m_ti = testViewVector (*this->ptr(), m_clid); +} +#endif + + +/** + * @brief Copy constructor. + * @param other Bucket to copy. + */ +template <typename T> +DVLDataBucket<T>::DVLDataBucket (const DVLDataBucket& other) + : SG::DataBucket<T> (new T (*(T*)(other.cptr()))), + m_copies (other.m_copies), + m_ti (other.m_ti), + m_clid (other.m_clid) +{ + // Make a copy of each of the copies. + vec_t::iterator end = m_copies.end(); + for (vec_t::iterator it = m_copies.begin(); it != end; ++it) { + it->second = it->first->clone (it->second); + } +} + + +/** + * @brief Destructor. + */ +template <typename T> +DVLDataBucket<T>::~DVLDataBucket() +{ + // Delete any copies. + vec_t::iterator end = m_copies.end(); + for (vec_t::iterator it = m_copies.begin(); it != end; ++it) { + it->first->del (it->second); + } +} + + +/** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a clid. Note that only + * derived->base conversions are allowed here. + * @param clid The class ID to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ +template <typename T> +void* +DVLDataBucket<T>::cast (CLID clid, IRegisterTransient* irt /*= 0*/, + bool /*isConst = true*/) const +{ + const T* ptr = *((DataBucket<T>*)this); + + // Test for trivial conversion. + // FIXME: Assumes we can reinterpret_cast between DV* and ViewVector<DV>*. + if (clid == m_clid || clid == DataBucket<T>::classID()) + return const_cast<T*>(ptr); + + // Try looking for a true base conversion. + void* ret = SG::BaseInfo<T>::cast (const_cast<T*>(ptr), clid); + if (ret) + return ret; + + // See if we've already made an instance for this type. + // We don't expect to have more than a few, so no point in doing + // anything more complicated than a linear search. + vec_t::iterator end = m_copies.end(); + for (vec_t::iterator it = m_copies.begin(); it != end; ++it) { + if (clid == it->first->clid()) { + // Recopy the elements if the container size has changed. + if (it->first->size (it->second) != ptr->size()) { + dvl_update (*const_cast<T*> (ptr), it->second, it->first); + } + return it->second; + } + } + + // Try to do a copying conversion. + DataModel_detail::DVLInfoBase* info; + void* newcont = dvl_convert (*const_cast<T*> (ptr), clid, info); + if (newcont) { + m_copies.push_back (std::make_pair (info, newcont)); + irt->registerTransient (newcont); + } + + return newcont; +} + + +/** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a std::type_info. Note that only + * derived->base conversions are allowed here. + * @param clid The @a std::type_info of the type to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ +template <typename T> +void* +DVLDataBucket<T>::cast (const std::type_info& tinfo, + IRegisterTransient* irt /*= 0*/, + bool /*isConst = true*/) const +{ + const T* ptr = *((DataBucket<T>*)this); + + // Test for trivial conversion. + // FIXME: Assumes we can reinterpret_cast between DV* and ViewVector<DV>*. + if (&tinfo == m_ti || tinfo == DataBucket<T>::tinfo()) + return const_cast<T*>(ptr); + + // Try looking for a true base conversion. + void* ret = SG::BaseInfo<T>::cast (const_cast<T*>(ptr), tinfo); + if (ret) + return ret; + + // See if we've already made an instance for this type. + // We don't expect to have more than a few, so no point in doing + // anything more complicated than a linear search. + vec_t::iterator end = m_copies.end(); + for (vec_t::iterator it = m_copies.begin(); it != end; ++it) { + if (tinfo == it->first->tinfo()) { + // Recopy the elements if the container size has changed. + if (it->first->size (it->second) != ptr->size()) { + dvl_update (*const_cast<T*> (ptr), it->second, it->first); + } + return it->second; + } + } + + // Try to do a copying conversion. + DataModel_detail::DVLInfoBase* info; + void* newcont = dvl_convert (*const_cast<T*> (ptr), tinfo, info); + if (newcont) { + m_copies.push_back (std::make_pair (info, newcont)); + irt->registerTransient (newcont); + } + + return newcont; +} + + +/** + * @brief Return a new @c DataBucket whose payload has been cloned from the + * original one. + */ +template <typename T> +DVLDataBucket<T>* DVLDataBucket<T>::clone() const +{ + return new DVLDataBucket<T> (*this); +} + + +/** + * @brief The CLID for the class of object we're holding. + * + * May be different from that of the base @c DataVector in the case + * of a @c ViewVector. + */ +template <typename T> +const CLID& DVLDataBucket<T>::clID() const +{ + return m_clid; +} + + +/** + * @brief The std::type_info for the class of object we're holding. + * + * May be different from that of the base @c DataVector in the case + * of a @c ViewVector. + */ +template <typename T> +const std::type_info& DVLDataBucket<T>::tinfo() const +{ + return *m_ti; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLEltBaseInfo.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLEltBaseInfo.icc new file mode 100644 index 00000000..fa4f344a --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLEltBaseInfo.icc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/DVLEltBaseInfo.icc + * @author scott snyder + * @date Jul 2009 + * @brief Set up BaseInfo information for DataVector/DataList elements. + * + * When we have a @c DATAVECTOR_BASE(D,B) macro, we want to record + * the @c D, @c B inheritance relation in @c SG::BaseInfo. + * We can't just invoke @c SG_BASE for this from @c DATAVECTOR_BASE because + * there may be duplicates, and @c SG_BASE won't compile in that case. + * But @c BaseInfo has a deferred initialization mechanism, so we use that: + * we arrange for an appropriate initializer be added to the list. + * We also need to walk the DV/DL type information structures + * rather then the @c BaseInfo ones. + * + * This is common code to be used for both @c DataVector and @c DataList. + * It should be included inside of the appropriate detail namespace. + * In addition, the macro @c DVLTYPE should be defined as either + * @c DataVector or @c DataList. + * Then, the *_BASE macros should explicitly instantiate the template + * @c *_detail::DVLEltBaseInit<T>. + */ + + +// Set up for token pasting. +#define DVLPASTE1(y,x) y##x +#define DVLPASTE2(y,x) DVLPASTE1(y,x) +#define DVLPASTE(x) DVLPASTE2(DVLTYPE,x) + + +// +// The various specializations of DVLEltBase_init here walk the tree +// of the DataVector inheritance info classes and add information +// to the BaseInfo. +// +// In all of these, T is the type of the BaseInfo we're working on, +// and B is the base we're trying to add to that BaseInfo. +// +template <class B> +struct DVLEltBase_init +{ + template <class T> + static void init (SG::BaseInfoImpl<T>& c, bool is_virtual) + { + // Use this instead of calling add_base directly so that we pick + // up any base declarations that were added separately with SG_BASE. + SG::BaseInfo_init<B>::init (c, is_virtual); + + DVLEltBase_init<typename DVLPASTE(Base)<B>::Base>::init (c, is_virtual); + } +}; +template <> +struct DVLEltBase_init<DataModel_detail::NoBase> +{ + template <class T> + static void init (SG::BaseInfoImpl<T>& /*c*/, bool /*is_virtual*/) + { + } +}; +template <class B1, class B2, class B3> +struct DVLEltBase_init<VirtBases<B1,B2,B3> > +{ + template <class T> + static void init (SG::BaseInfoImpl<T>& c, bool /*is_virtual*/) + { + DVLEltBase_init<B1>::init (c, true); + DVLEltBase_init<B2>::init (c, true); + DVLEltBase_init<B3>::init (c, true); + } +}; +template <class B> +struct DVLEltBase_init<DVLTYPE<B> > +{ + template <class T> + static void init (SG::BaseInfoImpl<T>& c, bool is_virtual) + { + DVLEltBase_init<B>::init (c, is_virtual); + } +}; + + +// This class sets up the BaseInfo initialization. +// An instance of this class will be constructed during global initialization. +// At that time, it adds an initializer to the BaseInfo which runs doinit(). +template <class T> +struct RegisterDVLEltBaseInit +{ + RegisterDVLEltBaseInit(); + static const SG::BaseInfoBase& doinit(); +}; +#ifndef __REFLEX__ +template <class T> +RegisterDVLEltBaseInit<T>::RegisterDVLEltBaseInit() +{ + // Make sure the BaseInfo derived class has been instantiated. + SG::BaseInfo<T>::maybeInit(); + // Set up the init function. + SG::BaseInfoBase::addInit(&typeid(T), doinit); +} +#endif +template <class T> +const SG::BaseInfoBase& RegisterDVLEltBaseInit<T>::doinit() +{ + // Find the BaseInfo instance. + SG::BaseInfoBase* bib = + const_cast<SG::BaseInfoBase*> (SG::BaseInfoBase::find (typeid(T))); + if (bib) { + // Walk the base classes and add to it. + SG::BaseInfoImpl<T>& impl = *static_cast<SG::BaseInfoImpl<T>*> (bib); + DVLEltBase_init<T>::init (impl, false); + } + return *bib; +} + + +// +// This is what the _BASE macros instantiate. +// It arranges for an instance of RegisterDVLEltBaseInit to be created +// during global initialization. +// +template <class T> struct DVLEltBaseInit { + static RegisterDVLEltBaseInit<T> s_regbase; +}; +#ifndef __APPLE__ +template <class T> RegisterDVLEltBaseInit<T> DVLEltBaseInit<T>::s_regbase; +#endif + +#undef DVLPASTE +#undef DVLPASTE1 +#undef DVLPASTE2 diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.h new file mode 100644 index 00000000..59997138 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.h @@ -0,0 +1,405 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLInfo.h,v 1.2 2008-06-17 00:44:17 ssnyder Exp $ + +/** + * @file AthContainers/tools/DVLInfo.h + * @author scott snyder + * @date Mar, 2008 + * @brief Holder to implement conversion copies for @c DataVector/@c DataList. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVLINFO_H +#define ATHCONTAINERS_TOOLS_DVLINFO_H + + +#include "AthContainers/tools/ClassID.h" +#include "AthContainers/AuxVectorBase.h" +#include <typeinfo> +#include <cstddef> + + +#if __cplusplus > 201100 +# include <type_traits> +namespace SG_STD_OR_BOOST = std; +#else +# include "boost/type_traits/remove_const.hpp" +# include "boost/type_traits/is_pointer.hpp" +# include "boost/type_traits/is_base_of.hpp" +namespace SG_STD_OR_BOOST = boost; +#endif + + + +namespace DataModel_detail { + + +/** + * @brief Helper to iterate over a DV container. + */ +class DVLIteratorBase +{ +public: + /// Destructor. + virtual ~DVLIteratorBase() {} + + + /** + * @brief Return the next element from the container. + * + * This is the next pointer from the container (it's a pointer to the + * element itself, not a pointer to the pointer. It will be properly + * cast to the type described by elt_tinfo(). Null pointers are skipped; + * this function signals the end of iteration by returning 0. + */ + virtual const void* next() = 0; +}; + + +/* + * @brief Holder to implement conversion copies for @c DataVector/@c DataList. + * + * In some cases, we want to convert @c DataVector\<A> to @c DataVector\<B>, + * where the two @c DataVector classes are not related by inheritance, + * but where @c A and @c B are. In such a case, we can make a new view + * container for @c DataVector\<B> and fill it with the pointers + * from @c DataVector\<A> (suitably converted). In order for this + * to work with the conversion machinery in SGTools, we must be able + * to do this given only the @c type_info for @c DataVector\<B>. + * Thus, we build a registry of @c DVLInfo objects, indexed + * by the @c type_info; the @c DVLInfo objects have virtual methods + * to build the new container and to fill it. (Everything said here + * for @c DataVector also applies to @c DataList.) + * + * Note: these objects should only be allocated statically. + */ +class DVLInfoBase +{ +public: + /** + * @brief Constructor. + * @param tinfo Type info object for the container being described. + * @param elt_tinfo Type info object for the element type of the container + * being described (with pointer and const's stripped.) + * + * Note: these objects should only be allocated statically. + */ + DVLInfoBase (const std::type_info& tinfo, + const std::type_info& elt_tinfo); + + + /// Destructor. + virtual ~DVLInfoBase() {} + + + /** + * @brief Return the @c type_info for the container. + */ + const std::type_info& tinfo() const; + + + /** + * @brief Return the CLID for the container. + */ + CLID clid() const; + + + /** + * @brief Return the @c type_info for the container's element. + * (Pointer and const stripped.) + */ + const std::type_info& elt_tinfo() const; + + + /** + * @brief Construct a new container. + * @param nreserve Number of elements for which to reserve space. + * (Ignored if not appropriate.) + */ + virtual void* make (size_t nreserve) const = 0; + + + /** + * @brief Push a new pointer into the container. + * @param cont_p Pointer to the container. + * @param elt_p Pointer to the element to push. + * (Must match the container's declared element type.) + */ + virtual void push (void* cont_p, void* elt_p) const = 0; + + + /** + * @brief Return the size of the container. + * @param cont_p Pointer to the container. + */ + virtual size_t size (void* cont_p) const = 0; + + + /** + * @brief Erase the elements in the container. + * @param cont_p Pointer to the container. + */ + virtual void clear (void* cont_p) const = 0; + + + /** + * @brief Delete a container. + * @param cont_p Pointer to the container. + */ + virtual void del (void* cont_p) const = 0; + + + /** + * @brief Copy a container. + * @param cont_p Pointer to the container. + */ + virtual void* clone (void* cont_p) const = 0; + + + /** + * @brief Return a new iterator object. + * @param cont_p Pointer to the container. + */ + virtual DVLIteratorBase* iterator (const void* cont_p) const = 0; + + + /** + * @brief Return a pointer to the container base. + * @param cont_p Pointer to the container. + */ + virtual SG::AuxVectorBase* base (void* cont_p) const = 0; + + + /** + * @brief Find the @c DVLInfo for the container @a tinfo. + * @param tinfo @c type_info of the desired container. + * @returns Pointer to the @c DVLInfo, or 0 if not found. + */ + static DVLInfoBase* find (const std::type_info& tinfo); + + + /** + * @brief Find the @c DVLInfo for the container @a clid. + * @param clid @c CLID of the desired container. + * @returns Pointer to the @c DVLInfo, or 0 if not found. + */ + static DVLInfoBase* find (CLID clid); + + +private: + /// The @c type_info of the container. + const std::type_info& m_tinfo; + + /// The @c type_info of the container's element. + const std::type_info& m_elt_tinfo; +}; + + +/* + * @brief Per-container @c DVLInfo. + * + * One instance of this class is instantiated for each + * @c DataVector/@c DataList class. + */ +template <class T> +class DVLInfo + : public DVLInfoBase +{ +public: + /// Container type. + typedef T Container; + + /// The container's element type (with pointer and any const removed). + typedef typename + SG_STD_OR_BOOST::remove_const<typename Container::base_value_type>::type + Elt; + + + /** + * @brief Constructor. + * + * Note: these objects should only be allocated statically. + */ + DVLInfo(); + + + /** + * @brief Construct a new container. + * @param nreserve Number of elements for which to reserve space. + * (Ignored if not appropriate.) + */ + virtual void* make (size_t nreserve) const; + + + /** + * @brief Push a new pointer into the container. + * @param cont_p Pointer to the container. + * @param elt_p Pointer to the element to push. + * (Must match the container's declared element type.) + */ + virtual void push (void* cont_p, void* elt_p) const; + + + /** + * @brief Return the size of the container. + * @param cont_p Pointer to the container. + */ + virtual size_t size (void* cont_p) const; + + + /** + * @brief Erase the elements in the container. + * @param cont_p Pointer to the container. + */ + virtual void clear (void* cont_p) const; + + + /** + * @brief Delete a container. + * @param cont_p Pointer to the container. + */ + virtual void del (void* cont_p) const; + + + /** + * @brief Copy a container. + * @param cont_p Pointer to the container. + */ + virtual void* clone (void* cont_p) const; + + + /** + * @brief Return a new iterator object. + * @param cont_p Pointer to the container. + */ + virtual DVLIteratorBase* iterator (const void* cont_p) const; + + + /** + * @brief Return a pointer to the container base. + * @param cont_p Pointer to the container. + */ + virtual SG::AuxVectorBase* base (void* cont_p) const; + + + /** + * @brief Helper to create the @c DVLInfo static instance. + * + * Calling this will create the @c DVLInfo static instance. + * This can be called from, for example, an initializer for + * a class static variable. + */ + static const std::type_info* initHelper(); +}; + + +template <class T> +class DVLIterator + : public DVLIteratorBase +{ +public: + typedef typename T::const_iterator base_iterator; + + + /** + * @brief Constructor. + * @param beg Start of the container. + * @param end End of the container. + */ + DVLIterator (const base_iterator& beg, const base_iterator& end); + + + /** + * @brief Return the next element from the container. + * + * This is the next pointer from the container (it's a pointer to the + * element itself, not a pointer to the pointer). It will be properly + * cast to the type described by elt_tinfo(). Null pointers are skipped; + * this function signals the end of iteration by returning 0. + */ + virtual const void* next(); + + +private: + typename T::const_iterator m_it; + typename T::const_iterator m_end; +}; + + +/** + * @brief Perform @c DataVector/@c DataList conversion copying. + * @param src The source container. + * @param targ_info The @c DVLInfo for the target container type. + * @return The new container, or 0. + * + * If the elements of @a src can be converted to elements + * of a @a targ_tinfo container, then we make a new (view) + * container of that type and populate it with elements copied from @a src. + */ +template <class T> +void* dvl_convert (const T& src, + const DVLInfoBase& targ_info); + + +/** + * @brief Perform @c DataVector/@c DataList conversion copying. + * @param src The source container. + * @param targ_tinfo @c type_info for the desired container type. + * @param targ_info[out] The @c DVLInfo for the target container type. + * @return The new container, or 0. + * + * If the elements of @a src can be converted to elements + * of a @a targ_tinfo container, then we make a new (view) + * container of that type and populate it with elements copied from @a src. + */ +template <class T> +void* dvl_convert (const T& src, + const std::type_info& targ_tinfo, + DVLInfoBase*& targ_info); + + +/** + * @brief Perform @c DataVector/@c DataList conversion copying. + * @param src The source container. + * @param clid CLID for the desired container type. + * @param targ_info[out] The @c DVLInfo for the target container type. + * @return The new container, or 0. + * + * If the elements of @a src can be converted to elements + * of a @a targ_tinfo container, then we make a new (view) + * container of that type and populate it with elements copied from @a src. + */ +template <class T> +void* dvl_convert (const T& src, + CLID clid, + DVLInfoBase*& targ_info); + + +/** + * @brief Update the elements in the target container from the source. + * @param src The source container. + * @param target The target container. + * @param targ_info The @c DVLInfo for the target container type. + * + * The target container is cleared and then repopulated from the elements + * of the source container. + */ +template <class T> +void dvl_update (const T& src, + void* target, + const DVLInfoBase* targ_info); + + + +} // namespace DataModel_detail + + +#include "AthContainers/tools/DVLInfo.icc" + + +#endif // not ATHCONTAINERS_TOOLS_DVLINFO_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.icc new file mode 100644 index 00000000..a9e74da6 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLInfo.icc @@ -0,0 +1,500 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLInfo.icc,v 1.3 2008-12-15 15:14:29 ssnyder Exp $ +/** + * @file AthContainers/tools/DVLInfo.icc + * @author scott snyder + * @date Mar, 2008 + * @brief Holder to implement conversion copies for @c DataVector/@c DataList. + * + * Template and inline implementations. + */ + + +#include "AthContainers/OwnershipPolicy.h" +#include <vector> +#include <list> +#include <cassert> +#include <cstdlib> + + +#ifndef XAOD_STANDALONE +#include "SGTools/BaseInfo.h" +#endif + + +namespace DataModel_detail { + + +/** + * @brief Helper function to do @c push_back on a container. + * @param cont The container. + * @param elt The element to push + * + * This specialization is for the case when the container holds pointers. + */ +template <class CONTAINER, class ELT> +inline +void dvlPush (CONTAINER& cont, ELT* elt, const SG_STD_OR_BOOST::true_type&) +{ + cont.push_back (elt); +} + + +/** + * @brief Helper function to do @c push_back on a container. + * @param cont The container. + * @param elt The element to push + * + * This specialization is for the case when the container does not + * hold pointers. + */ +template <class CONTAINER, class ELT> +inline +void dvlPush (CONTAINER& cont, ELT* elt, const SG_STD_OR_BOOST::false_type&) +{ + cont.push_back (*elt); +} + + +/** + * @brief Helper function to return a pointer from an iterator. + * @param it The iterator. + * + * This specialization is for the case when the container holds pointers. + */ +template <class ITERATOR> +inline +const void* dvlGetPointer (ITERATOR& it, const SG_STD_OR_BOOST::true_type&) +{ + return *it; +} + + +/** + * @brief Helper function to return a pointer from an iterator. + * @param it The iterator. + * + * This specialization is for the case when the container does not + * hold pointers. + */ +template <class ITERATOR> +inline +const void* dvlGetPointer (ITERATOR& it, const SG_STD_OR_BOOST::false_type&) +{ + return &*it; +} + + +/** + * @brief Helper for converting a container to @x AuxVectorBase. + */ +template <class T> +SG::AuxVectorBase* dvlGetBase (T* p, const SG_STD_OR_BOOST::true_type&) +{ + return p; +} +template <class T> +SG::AuxVectorBase* dvlGetBase (T*, const SG_STD_OR_BOOST::false_type&) +{ + return 0; +} + + +/** + * @brief Return the @c type_info for the container. + */ +inline +const std::type_info& DVLInfoBase::tinfo() const +{ + return m_tinfo; +} + + +/** + * @brief Return the @c type_info for the container's element. + * (Pointer and const stripped.) + */ +inline +const std::type_info& DVLInfoBase::elt_tinfo() const +{ + return m_elt_tinfo; +} + + +/** + * @brief Constructor. + * + * Note: these objects should only be allocated statically. + */ +template <class T> +DVLInfo<T>::DVLInfo() + : DVLInfoBase (typeid (Container), typeid (Elt)) +{ +} + + +/** + * @brief Construct a new container. + * @param nreserve Number of elements for which to reserve space. + * (Ignored if not appropriate.) + */ +template <class T> +void* DVLInfo<T>::make (size_t nreserve) const +{ + T* cont = 0; + dvl_makecontainer (nreserve, cont); + return cont; +} + + +/** + * @brief Push a new pointer into the container. + * @param cont_p Pointer to the container. + * @param elt_p Pointer to the element to push. + * (Must match the container's declared element type.) + */ +template <class T> +void DVLInfo<T>::push (void* cont_p, void* elt_p) const +{ + Container* cont = reinterpret_cast<Container*> (cont_p); + Elt* elt = reinterpret_cast<Elt*> (elt_p); + dvlPush (*cont, elt, + typename SG_STD_OR_BOOST::is_pointer<typename Container::value_type>::type()); +} + + +/** + * @brief Return the size of the container. + * @param cont_p Pointer to the container. + */ +template <class T> +size_t DVLInfo<T>::size (void* cont_p) const +{ + Container* cont = reinterpret_cast<Container*> (cont_p); + return cont->size(); +} + + +/** + * @brief Erase the elements in the container. + * @param cont_p Pointer to the container. + */ +template <class T> +void DVLInfo<T>::clear (void* cont_p) const +{ + Container* cont = reinterpret_cast<Container*> (cont_p); + cont->clear(); +} + + +/** + * @brief Delete a container. + * @param cont_p Pointer to the container. + */ +template <class T> +void DVLInfo<T>::del (void* cont_p) const +{ + Container* cont = reinterpret_cast<Container*> (cont_p); + delete cont; +} + + +/** + * @brief Copy a container. + * @param cont_p Pointer to the container. + */ +template <class T> +void* DVLInfo<T>::clone (void* cont_p) const +{ + Container* cont = reinterpret_cast<Container*> (cont_p); + return new T (*cont); +} + + +/** + * @brief Helper to create the @c DVLInfo static instance. + * + * Calling this will create the @c DVLInfo static instance. + * This can be called from, for example, an initializer for + * a class static variable. + */ +template <class T> +const std::type_info* DVLInfo<T>::initHelper() +{ + static DVLInfo<T> inst; + return &inst.tinfo(); +} + + +/** + * @brief Return a new iterator object. + * @param cont_p Pointer to the container. + */ +template <class T> +DVLIteratorBase* DVLInfo<T>::iterator (const void* cont_p) const +{ + const Container* cont = reinterpret_cast<const Container*> (cont_p); + return new DVLIterator<T> (cont->begin(), cont->end()); +} + + +/** + * @brief Return a pointer to the container base. + * @param cont_p Pointer to the container. + */ +template <class T> +SG::AuxVectorBase* DVLInfo<T>::base (void* cont_p) const +{ + Container* cont = reinterpret_cast<Container*> (cont_p); + return DataModel_detail::dvlGetBase + (cont, + typename SG_STD_OR_BOOST::is_base_of<SG::AuxVectorBase,T>::type()); +} + + +/** + * @brief Constructor. + * @param beg Start of the container. + * @param end End of the container. + */ +template <class T> +DVLIterator<T>::DVLIterator (const base_iterator& beg, + const base_iterator& end) + : m_it (beg), + m_end (end) +{ +} + + +/** + * @brief Return the next element from the container. + * + * This is the next pointer from the container (it's a pointer to the + * element itself, not a pointer to the pointer). It will be properly + * cast to the type described by elt_tinfo(). Null pointers are skipped; + * this function signals the end of iteration by returning 0. + */ +template <class T> +const void* DVLIterator<T>::next() +{ + const void* ret = 0; + while (ret == 0) { + if (m_it == m_end) + return 0; + ret = dvlGetPointer (m_it, + typename SG_STD_OR_BOOST::is_pointer<typename T::value_type>::type()); + ++m_it; + } + return ret; +} + + +/** + * @brief Return container size in constant time, or 0. + * @param c The container. + * + * This will return the size of container @a c, if it is possible + * to do so in constant time. Otherwise, it returns 0. + */ +template <class T> +inline +size_t dvl_size_const (const T& c) +{ + return c.size(); +} + + +/** + * @brief Return container size in constant time, or 0. + * @param c The container. + * + * This is a specialization for @c list; here we just return 0. + */ +template <class T> +inline +size_t dvl_size_const (const std::list<T>& /*c*/) +{ + return 0; +} + + +#if defined(XAOD_STANDALONE) || defined(__GCCXML__) +template <class T> +void* dvl_convert (const T& , + const DVLInfoBase& ) +{ + // not implemented for standalone. + std::abort(); +} +#else +/** + * @brief Perform @c DataVector/@c DataList conversion copying. + * @param src The source container. + * @param targ_info The @c DVLInfo for the target container type. + * @return The new container, or 0. + * + * If the elements of @a src can be converted to elements + * of a @a targ_tinfo container, then we make a new (view) + * container of that type and populate it with elements copied from @a src. + */ +template <class T> +void* dvl_convert (const T& src, + const DVLInfoBase& targ_info) +{ + // @a src's element type, with pointer and const removed. + typedef + typename SG_STD_OR_BOOST::remove_const<typename T::base_value_type>::type + Elt; + + // Fetch the cast function. + SG::BaseInfoBase::castfn_t* castfn = + SG::BaseInfo<Elt>::castfn (targ_info.elt_tinfo()); + if (!castfn) + return 0; + + // Make the target container. + void* newcont = targ_info.make (dvl_size_const (src)); + + // Copy the contents of the source to the target container, + // converting as we go. + typename T::const_iterator it = src.begin(); + typename T::const_iterator end = src.end(); + for (; it != end; ++it) { + Elt* elt = const_cast<Elt*> (*it); + targ_info.push (newcont, castfn (elt)); + } + + return newcont; +} +#endif + + + +/** + * @brief Perform @c DataVector/@c DataList conversion copying. + * @param src The source container. + * @param targ_tinfo @c type_info for the desired container type. + * @param targ_info[out] The @c DVLInfo for the target container type. + * @return The new container, or 0. + * + * If the elements of @a src can be converted to elements + * of a @a targ_tinfo container, then we make a new (view) + * container of that type and populate it with elements copied from @a src. + */ +template <class T> +void* dvl_convert (const T& src, + const std::type_info& targ_tinfo, + DVLInfoBase*& targ_info) +{ + // Look up the info for the target container. + targ_info = DVLInfoBase::find (targ_tinfo); + if (!targ_info) + return 0; + + return dvl_convert (src, *targ_info); +} + + +/** + * @brief Perform @c DataVector/@c DataList conversion copying. + * @param src The source container. + * @param clid CLID for the desired container type. + * @param targ_info[out] The @c DVLInfo for the target container type. + * @return The new container, or 0. + * + * If the elements of @a src can be converted to elements + * of a @a targ_tinfo container, then we make a new (view) + * container of that type and populate it with elements copied from @a src. + */ +template <class T> +void* dvl_convert (const T& src, + CLID clid, + DVLInfoBase*& targ_info) +{ + // Look up the info for the target container. + targ_info = DVLInfoBase::find (clid); + if (!targ_info) + return 0; + + return dvl_convert (src, *targ_info); +} + + +#if defined(XAOD_STANDALONE) || defined(__GCCXML__) +template <class T> +void dvl_update (const T&, + void* , + const DVLInfoBase* ) +{ + // Not implemented for standalone. + std::abort(); +} +#else +/** + * @brief Update the elements in the target container from the source. + * @param src The source container. + * @param target The target container. + * @param targ_info The @c DVLInfo for the target container type. + * + * The target container is cleared and then repopulated from the elements + * of the source container. + */ +template <class T> +void dvl_update (const T& src, + void* target, + const DVLInfoBase* targ_info) +{ + // @a src's element type, with pointer and const removed. + typedef + typename SG_STD_OR_BOOST::remove_const<typename T::base_value_type>::type + Elt; + + // Clear the target container. + targ_info->clear (target); + + // Fetch the cast function. + SG::BaseInfoBase::castfn_t* castfn = + SG::BaseInfo<Elt>::castfn (targ_info->elt_tinfo()); + assert (castfn != 0); + + // Copy the contents of the source to the target container, + // converting as we go. + typename T::const_iterator it = src.begin(); + typename T::const_iterator end = src.end(); + for (; it != end; ++it) { + Elt* elt = const_cast<Elt*> (*it); + targ_info->push (target, castfn (elt)); + } +} +#endif + + +} // namespace DataModel_detail + + +/** + * @brief Construct a new container. + * @param nreserve Number of elements for which to reserve space. + * (Ignored if not appropriate.) + * @param cont[out] Pointer to the constructed container. + * (Returned via an argument to allow for template + * argument deduction.) + * + * This is broken out from the @c make method to allow specializing + * just this method. (Needs to be in the global namespace for proper + * resolution.) + */ +template <class CONTAINER> +void dvl_makecontainer (size_t /*nreserve*/, CONTAINER*& cont) +{ + cont = new CONTAINER; + std::abort(); +} + + + diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLIterator.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLIterator.h new file mode 100644 index 00000000..ab6a8790 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLIterator.h @@ -0,0 +1,393 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tests/DVLIterator.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Iterator classes for @c DataVector/@c DataList. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVLITERATOR_H +#define ATHCONTAINERS_TOOLS_DVLITERATOR_H + + +#include "AthContainers/OwnershipPolicy.h" +#include "AthContainers/tools/DVLCast.h" +#include "AthContainers/tools/ElementProxy.h" +#include <boost/iterator/iterator_adaptor.hpp> +#include <boost/version.hpp> +#include <iterator> +#include <cstdlib> + + +#if BOOST_VERSION < 105000 +namespace boost { namespace detail { + + +/** + * @brief Hack for dictionary generation. + * + * This is a hack to allow the operator->() defined by the boost base class + * of iterator to compile. It actually makes no sense to ever use operator->, + * since value_type is always a pointer. But if you try to generate + * dictionary information for one of these iterators, then you'll + * be trying to instantiate operator->, whether or not it makes sense. + * This should be sufficient to get things to compile; we'll just stick + * in abort in case anyone manages to actually call the thing. + */ +template <class T, class U> +struct operator_arrow_result<T*, + DataModel_detail::ElementProxy<U>, + T**> +{ +public: + typedef T* ValueType; + typedef DataModel_detail::ElementProxy<U> Reference; + typedef T** Pointer; + typedef Pointer type; + static type make (Reference /*x*/) { std::abort(); return 0; } +}; + + +}} +#endif + + +namespace DataModel_detail { + + +/** + * @brief Const iterator class for @c DataVector/@c DataList. + * + * We need to cast dereferences to the appropriate type. + * This could be done with a @c boost::transform_iterator, + * except that the iterator category for that will + * be one of boost's new-style iterator categories, which + * don't interoperate well with the standard C++ categories. + * In particular, the container concept checks didn't work. + * + * This is templated on the specific @c DataVector/List class. + * + * This used to be done using boost::iterator_adaptor, but that caused + * problems with root6. So now use just write out the iterator + * explicitly. + */ +template <class DVL> +class const_iterator +{ +public: + /// Standard iterator typedefs. + typedef typename DVL::const_value_type value_type; + typedef value_type reference; + typedef value_type* pointer; + typedef typename DVL::BaseContainer::const_iterator::difference_type difference_type; + typedef typename DVL::BaseContainer::const_iterator::iterator_category iterator_category; + + typedef DVL Container; + typedef typename DVL::BaseContainer BaseContainer; + + + /** + * @brief Default constructor. + */ + const_iterator() {} + + + /** + * @brief Constructor. + * @param it The underlying container iterator. + */ + const_iterator (typename BaseContainer::const_iterator it) + : m_it (it) + {} + + + /// Dereference. Operator-> doesn't make sense here. + reference operator*() const { return dereference(); } + reference operator[] (difference_type n) const + { const_iterator tmp = *this + n; return *tmp; } + + + /// Increment / decrement. + const_iterator& operator++() { ++m_it; return *this; } + const_iterator operator++(int) + { const_iterator tmp = *this; ++m_it; return tmp; } + const_iterator& operator--() { --m_it; return *this; } + const_iterator operator--(int) + { const_iterator tmp = *this; --m_it; return tmp; } + + + /// Arithmetic. + const_iterator& operator+= (difference_type n) { m_it += n; return *this; } + const_iterator& operator-= (difference_type n) { m_it -= n; return *this; } + const_iterator operator+ (difference_type n) const { const_iterator tmp = *this; tmp += n; return tmp; } + const_iterator operator- (difference_type n) const { const_iterator tmp = *this; tmp -= n; return tmp; } + difference_type operator- (const_iterator other) const { return m_it - other.m_it; } + + + /// Comparisons. + bool operator== (const const_iterator& other) const { return m_it == other.m_it; } + bool operator!= (const const_iterator& other) const { return m_it != other.m_it; } + bool operator< (const const_iterator& other) const { return m_it < other.m_it; } + bool operator> (const const_iterator& other) const { return m_it > other.m_it; } + bool operator<= (const const_iterator& other) const { return m_it <= other.m_it; } + bool operator>= (const const_iterator& other) const { return m_it >= other.m_it; } + + +private: + /// The wrapped iterator. + typename BaseContainer::const_iterator m_it; + + /** + * @brief Dereference the iterator. + * @return The pointed-to element. + */ + const typename DVL::value_type dereference() const + { + return DataModel_detail::DVLCast<DVL>::cast (*m_it); + } +}; + + +/** + * @brief (Non-const) Iterator class for @c DataVector/@c DataList. + * + * Except for dereferencing, we want this to be the same as the + * @c iterator of the underlying container type. So, we use + * @c boost::iterator_adaptor and override @c dereference. + * + * This should nearly meets underlying container's iterator requirements, except + * that the dereferencing operations return an @c ElementProxy + * instead of a @c reference. + * + * This is templated on the specific @c DataVector/List class. + */ +template <class DVL> +class iterator + : public boost::iterator_adaptor<iterator<DVL>, + typename DVL::BaseContainer::iterator, + typename DVL::value_type, // Value + // Note: Can't use boost::use_default here. + // Otherwise, we get boost's new-fangled + // iterator categories, which won't work + // with libstdc++'s implementation + // of sort(). + // CategoryOrTraversal + typename DVL::BaseContainer:: + const_iterator::iterator_category, + typename DVL::ElementProxy> // Reference +{ +private: + // Shorthand for the base class type. + typedef boost::iterator_adaptor<iterator, + typename DVL::BaseContainer::iterator, + typename DVL::value_type, // Value + // CategoryOrTraversal + typename DVL::BaseContainer:: + const_iterator::iterator_category, + typename DVL::ElementProxy> iterator_adaptor_; + + // Copy some other names + typedef typename DVL::ElementProxy ElementProxy; + typedef typename DVL::const_iterator const_iterator; + + +public: + typedef DVL Container; + typedef typename DVL::BaseContainer BaseContainer; + + + /** + * @brief Default constructor. + */ + iterator() : + m_container(0) + {} + + + /** + * @brief Constructor. + * @param it The underlying container iterator. + * @param container xxx + */ + iterator (typename BaseContainer::iterator it, + DVL* container) + : iterator_adaptor_ (it), + m_container (container) + {} + + + /** + * @brief Element access. + * @param n Index relative to the iterator of the element to access. + * @return Proxy for the element. + * + * We need to override this here in order to get the return type correct. + */ + ElementProxy operator[] (int n) const + { + return ElementProxy (this->base()+n, m_container); + } + + + /** + * @brief Convert to a @c const_iterator. + * + * This is needed to allow @c iterator to convert to @c const_iterator. + */ + operator const_iterator() const + { + return const_iterator (this->base()); + } + + + /** + * @brief Return the container holding the referenced element. + */ + DVL* container() const + { + return m_container; + } + + + /** + * @brief Return the ownership policy of the container from + * which this iterator was created. + */ + SG::OwnershipPolicy ownPolicy() const + { + return m_container->ownPolicy(); + } + + + /** + * @brief Test if we can insert; raise an exception if not. + * @param op Description of the attempted operation. + */ + void testInsert (const char* op) + { + m_container->testInsert (op); + } + + + // These are needed for iterator/const_iterator comparisons to work. + bool operator== (const iterator& i) const { return this->base() == i.base();} + bool operator!= (const iterator& i) const { return this->base() != i.base();} + bool operator< (const iterator& i) const { return this->base() < i.base();} + bool operator> (const iterator& i) const { return this->base() > i.base();} + bool operator<= (const iterator& i) const { return this->base() <= i.base();} + bool operator>= (const iterator& i) const { return this->base() >= i.base();} + + // These are needed for iterator/const_iterator comparisons to work. + bool operator== (const const_iterator& i) const + { return static_cast<const_iterator>(*this)==i; } + bool operator!= (const const_iterator& i) const + { return static_cast<const_iterator>(*this)!=i; } + bool operator< (const const_iterator& i) const + { return static_cast<const_iterator>(*this)<i; } + bool operator> (const const_iterator& i) const + { return static_cast<const_iterator>(*this)>i; } + bool operator<= (const const_iterator& i) const + { return static_cast<const_iterator>(*this)<=i; } + bool operator>= (const const_iterator& i) const + { return static_cast<const_iterator>(*this)>=i; } + + // These overloads are needed for iterator-const_iterator to work. + typename iterator_adaptor_::difference_type + operator- (const iterator& i) const + { return this->base() - i.base(); } + iterator operator- (typename iterator_adaptor_::difference_type i) const + { return iterator (this->base() - i, m_container); } + typename iterator_adaptor_::difference_type + operator- (const const_iterator& i) const + { return static_cast<const_iterator>(*this) - i; } + + +private: + typename DVL::pointer operator-> (); + + // Required for iterator_adaptor to work. + friend class boost::iterator_core_access; + + + /** + * @brief Dereference the iterator. + * @return A proxy to the pointed-to element. + */ + ElementProxy dereference() const + { + return ElementProxy (this->base(), m_container); + } + + + /// The referenced container. + DVL* m_container; +}; + + +} // namespace DataModel_detail + + +// We need to define these to allow comparisons of +// iterator and const_iterator. +template <class DVL> +inline +bool operator== (const typename DVL::const_iterator& i1, + const DataModel_detail::iterator<DVL>& i2) +{ + return i1 == typename DVL::const_iterator (i2); +} +template <class DVL> +inline +bool operator!= (typename DVL::const_iterator i1, + DataModel_detail::iterator<DVL> i2) +{ + return i1 != typename DVL::const_iterator (i2); +} +template <class DVL> +inline +bool operator< (typename DVL::const_iterator i1, + DataModel_detail::iterator<DVL> i2) +{ + return i1 < typename DVL::const_iterator (i2); +} +template <class DVL> +inline +bool operator> (typename DVL::const_iterator i1, + DataModel_detail::iterator<DVL> i2) +{ + return i1 > typename DVL::const_iterator (i2); +} +template <class DVL> +inline +bool operator<= (typename DVL::const_iterator i1, + DataModel_detail::iterator<DVL> i2) +{ + return i1 <= typename DVL::const_iterator (i2); +} +template <class DVL> +inline +bool operator>= (typename DVL::const_iterator i1, + DataModel_detail::iterator<DVL> i2) +{ + return i1 >= typename DVL::const_iterator (i2); +} + +// This overloads is needed for const_iterator-iterator to work. +template <class DVL> +inline +typename DVL::const_iterator::difference_type +operator- (typename DVL::const_iterator i1, + DataModel_detail::iterator<DVL> i2) +{ + return i1 - typename DVL::const_iterator (i2); +} + + +#endif // not ATHCONTAINERS_TOOLS_DVLITERATOR_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVLNoBase.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLNoBase.h new file mode 100644 index 00000000..cd27965c --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVLNoBase.h @@ -0,0 +1,39 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/DVLNoBase.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Marker for the base of the inheritance hierarchy. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVLNOBASE_H +#define ATHCONTAINERS_TOOLS_DVLNOBASE_H + + +namespace DataModel_detail { + + +/** + * @brief Marker for the base of the inheritance hierarchy. + * + * Normally, @c DataVectorBase<T>::Base is the class from which + * @c DataVector<T> should derive. + * If, however, @c T has not had a base declared to @c DataVector, + * then @c DataVectorBase<T>::Base will be @c NoBase. + * (And similarly for @c DataList.) + */ +struct NoBase {}; + + +} // namespace DataModel_detail + + + +#endif // not ATHCONTAINERS_TOOLS_DVLNOBASE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.h new file mode 100644 index 00000000..1dcc2e90 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.h @@ -0,0 +1,974 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/DVL_algorithms.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Specializations of STL algorithms to work with @c DataVector/List. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVL_ALGORITHMS_H +#define ATHCONTAINERS_TOOLS_DVL_ALGORITHMS_H + + +#include "AthContainers/tools/DVLIterator.h" +#include <iterator> +#include <algorithm> + + +#include "AthContainers/tools/DVL_algorithms.icc" + + + +//=========================================================================== +// Algorithms requiring @c ForwardIterator. +// Usable with @c DataVector and @c DataList. +// + +namespace std { + + +/** + * @brief Specialization of @c remove for @c DataVector/List. + * @param beg The start iterator for the remove. + * @param end The end iterator for the remove. + * @param value The value to remove. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the remove in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class T> +typename DataModel_detail::iterator<DVL> +remove (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + const T& value) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_remove (beg, end, value); +} + + +/** + * @brief Specialization of @c remove_if for @c DataVector/List. + * @param beg The start iterator for the remove. + * @param end The end iterator for the remove. + * @param pred The predicate for the removal. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the remove in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Predicate> +typename DataModel_detail::iterator<DVL> +remove_if (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + Predicate pred) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_remove_if (beg, end, pred); +} + + +/** + * @brief Specialization of @c remove for @c DataVector/List. + * @param beg The start reverse_iterator for the remove. + * @param end The end reverse_iterator for the remove. + * @param value The value to remove. + * + * @c beg and @c end should both be reverseIterators + * from the same @c DataVector/List. + * This performs the remove in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class T> +typename std::reverse_iterator<DataModel_detail::iterator<DVL> > +remove (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + const T& value) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_remove (beg, end, value); +} + + +/** + * @brief Specialization of @c remove_if for @c DataVector/List. + * @param beg The start reverse_iterator for the remove. + * @param end The end reverse_iterator for the remove. + * @param pred The predicate for the removal. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the remove in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Predicate> +typename std::reverse_iterator<DataModel_detail::iterator<DVL> > +remove_if (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + Predicate pred) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_remove_if (beg, end, pred); +} + + +/** + * @brief Specialization of @c unique for @c DataVector/List. + * @param beg The start iterator for the unique operation. + * @param end The end iterator for the unique operation. + * @param value The value to remove. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's object ownership rules. + */ +template <class DVL> +typename DataModel_detail::iterator<DVL> +unique (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_unique (beg, end); +} + + +/** + * @brief Specialization of @c unique for @c DataVector/List. + * @param beg The start iterator for the unique operation. + * @param end The end iterator for the unique operation. + * @param pred The predicate for the operation. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's object ownership rules. + */ +template <class DVL, class BinaryPredicate> +typename DataModel_detail::iterator<DVL> +unique (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + BinaryPredicate pred) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_unique (beg, end, pred); +} + + +/** + * @brief Specialization of @c unique for @c DataVector/List. + * @param beg The start reverse_iterator for the unique operation. + * @param end The end reverse_iterator for the unique operation. + * @param value The value to remove. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's object ownership rules. + */ +template <class DVL> +typename std::reverse_iterator<DataModel_detail::iterator<DVL> > +unique (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_unique (beg, end); +} + + +/** + * @brief Specialization of @c unique for @c DataVector/List. + * @param beg The start reverse_iterator for the unique operation. + * @param end The end reverse_iterator for the unique operation. + * @param pred The predicate for the operation. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class BinaryPredicate> +typename std::reverse_iterator<DataModel_detail::iterator<DVL> > +unique (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + BinaryPredicate pred) +{ + // Implemented with iter_swap, no extra index manipulation needed. + return DataModel_detail::dvl_unique (beg, end, pred); +} + + +/** + * @brief Specialization of @c rotate for @c DataVector/List. + * @param beg The start iterator for the rotate operation. + * @param mid The middle iterator for the rotate operation. + * @param end The end iterator for the rotate operation. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void rotate (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> mid, + typename DataModel_detail::iterator<DVL> end) +{ + std::rotate (beg.base(), mid.base(), end.base()); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c rotate for @c DataVector/List. + * @param beg The start reverse_iterator for the rotate operation. + * @param mid The middle reverse_iterator for the rotate operation. + * @param end The end reverse_iterator for the rotate operation. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void +rotate (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > mid, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::rotate (ri(beg.base().base()), + ri(mid.base().base()), + ri(end.base().base())); + DataModel_detail::resortAux (beg, end); +} + + +} // namespace std + + + +//=========================================================================== +// Algorithms requiring @c BidirectionalIterator. +// Usable with @c DataVector and @c DataList. +// + +namespace std { + + +/** + * @brief Specialization of @c reverse for @c DataVector/List. @param beg + * The start iterator for the reverse operation. @param end The end + * iterator for the reverse operation. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void reverse (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end) +{ + std::reverse (beg.base(), end.base()); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c reverse for @c DataVector/List. + * @param beg The start reverse_iterator for the reverse operation. + * @param end The end reverse_iterator for the reverse operation. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void +reverse (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::reverse (ri(beg.base().base()), ri(end.base().base())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c partition for @c DataVector/List. + * @param beg The start iterator for the partition operation. + * @param end The end iterator for the partition operation. + * @param pred The predicate for the partition. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Predicate> +typename DataModel_detail::iterator<DVL> +partition (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + Predicate pred) +{ + typename DataModel_detail::iterator<DVL> ret + (std::partition (beg.base(), end.base(), + DataModel_detail::Predwrapper<DVL, Predicate> (pred)), + beg.container()); + DataModel_detail::resortAux (beg, end); + return ret; +} + + +/** + * @brief Specialization of @c partition for @c DataVector/List. + * @param beg The start reverse_iterator for the partition operation. + * @param end The end reverse_iterator for the partition operation. + * @param pred The predicate for the partition. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Predicate> +typename std::reverse_iterator<DataModel_detail::iterator<DVL> > +partition (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + Predicate pred) +{ + typedef typename DataModel_detail::iterator<DVL> Iterator; + typedef typename DVL::BaseContainer::reverse_iterator ri; + typedef typename DataModel_detail::Predwrapper<DVL, Predicate> pwrap_t; + std::reverse_iterator<Iterator> ret + (Iterator (std::partition (ri(beg.base().base()), + ri(end.base().base()), + pwrap_t (pred)).base(), + beg.base().container())); + DataModel_detail::resortAux (beg, end); + return ret; +} + + +/** + * @brief Specialization of @c stable_partition for @c DataVector/List. + * @param beg The start iterator for the partition operation. + * @param end The end iterator for the partition operation. + * @param pred The predicate for the partition. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Predicate> +typename DataModel_detail::iterator<DVL> +stable_partition (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + Predicate pred) +{ + DataModel_detail::iterator<DVL> ret + (std::stable_partition (beg.base(), end.base(), + DataModel_detail::Predwrapper<DVL, Predicate> + (pred)), + beg.container()); + DataModel_detail::resortAux (beg, end); + return ret; +} + + +/** + * @brief Specialization of @c stable_partition for @c DataVector/List. + * @param beg The start reverse_iterator for the partition operation. + * @param end The end reverse_iterator for the partition operation. + * @param pred The predicate for the partition. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Predicate> +typename std::reverse_iterator<DataModel_detail::iterator<DVL> > +stable_partition + (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + Predicate pred) +{ + typedef typename DataModel_detail::iterator<DVL> Iterator; + typedef typename DVL::BaseContainer::reverse_iterator ri; + typedef typename DataModel_detail::Predwrapper<DVL, Predicate> pwrap_t; + std::reverse_iterator<Iterator> ret + (Iterator (std::stable_partition (ri(beg.base().base()), + ri(end.base().base()), + pwrap_t (pred)).base(), + beg.base().container())); + DataModel_detail::resortAux (beg, end); + return ret; +} + + +/** + * @brief Specialization of @c inplace_merge for @c DataVector/List. + * @param beg The start iterator for the merge operation. + * @param mid Divider between the two sequences to be merged. + * @param end The end iterator for the merge operation. + * + * @c beg, @c mid, and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void +inplace_merge (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> mid, + typename DataModel_detail::iterator<DVL> end) +{ + std::inplace_merge (beg.base(), mid.base(), end.base()); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c inplace_merge for @c DataVector/List. + * @param beg The start iterator for the merge operation. + * @param mid Divider between the two sequences to be merged. + * @param end The end iterator for the merge operation. + * @param comp The comparison object. + * + * @c beg, @c mid, and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Compare> +void +inplace_merge (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> mid, + typename DataModel_detail::iterator<DVL> end, + Compare comp) +{ + std::inplace_merge (beg.base(), mid.base(), end.base(), + typename DataModel_detail::Compwrapper<DVL, Compare>(comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c inplace_merge for @c DataVector/List. + * @param beg The start iterator for the merge operation. + * @param mid Divider between the two sequences to be merged. + * @param end The end iterator for the merge operation. + * + * @c beg, @c mid, and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void +inplace_merge (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > mid, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::inplace_merge (ri (beg.base().base()), + ri (mid.base().base()), + ri (end.base().base())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c inplace_merge for @c DataVector/List. + * @param beg The start iterator for the merge operation. + * @param mid Divider between the two sequences to be merged. + * @param end The end iterator for the merge operation. + * @param comp The comparison object. + * + * @c beg, @c mid, and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Compare> +void +inplace_merge (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > mid, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + Compare comp) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::inplace_merge (ri (beg.base().base()), + ri (mid.base().base()), + ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, Compare>(comp)); + DataModel_detail::resortAux (beg, end); +} + + +} // namespace std + + + +//=========================================================================== +// Algorithms requiring @c RandomAccessIterator. +// Usable with @c DataVector. +// + +namespace std { + + +/** + * @brief Specialization of @c sort for @c DataVector/List. + * @param beg The start iterator for the sort. + * @param end The end iterator for the sort. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL> +void sort (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end) +{ + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DVL::BaseContainer::value_type> less; + std::sort (beg.base(), end.base(), + typename DataModel_detail::Compwrapper<DVL, less> (less())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c sort for @c DataVector/List. + * @param beg The start iterator for the sort. + * @param end The end iterator for the sort. + * @param comp The comparison functional object. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Compare> +void sort (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + Compare comp) +{ + std::sort (beg.base(), end.base(), + typename DataModel_detail::Compwrapper<DVL, Compare> (comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c sort for @c DataVector/List. + * @param beg The start reverse_iterator for the sort. + * @param end The end reverse_iterator for the sort. + * + * @c beg and @c end should both be reverse iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL> +void sort (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DVL::BaseContainer::value_type> less; + std::sort (ri (beg.base().base()), ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, less> (less())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c sort for @c DataVector/List. + * @param beg The start reverse_iterator for the sort. + * @param end The end reverse_iterator for the sort. + * @param comp The comparison functional object. + * + * @c beg and @c end should both be reverse iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Compare> +void sort (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + const Compare& comp) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::sort (ri (beg.base().base()), ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, Compare> (comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c stable_sort for @c DataVector/List. + * @param beg The start iterator for the sort. + * @param end The end iterator for the sort. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL> +void stable_sort (DataModel_detail::iterator<DVL> beg, + DataModel_detail::iterator<DVL> end) +{ + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DVL::BaseContainer::value_type> less; + std::stable_sort (beg.base(), end.base(), + DataModel_detail::Compwrapper<DVL, less> (less())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c stable_sort for @c DataVector/List. + * @param beg The start iterator for the sort. + * @param end The end iterator for the sort. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Compare> +void stable_sort (DataModel_detail::iterator<DVL> beg, + DataModel_detail::iterator<DVL> end, + Compare comp) +{ + std::stable_sort (beg.base(), end.base(), + DataModel_detail::Compwrapper<DVL, Compare> (comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c stable_sort for @c DataVector/List. + * @param beg The start reverse_iterator for the sort. + * @param end The end reverse_iterator for the sort. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL> +void stable_sort (std::reverse_iterator<DataModel_detail::iterator <DVL> > beg, + std::reverse_iterator<DataModel_detail::iterator <DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DVL::BaseContainer::value_type> less; + std::stable_sort (ri (beg.base().base()), ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, less> (less())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c stable_sort for @c DataVector/List. + * @param beg The start reverse_iterator for the sort. + * @param end The end reverse_iterator for the sort. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Compare> +void stable_sort (std::reverse_iterator<DataModel_detail::iterator <DVL> > beg, + std::reverse_iterator<DataModel_detail::iterator <DVL> > end, + Compare comp) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::stable_sort (ri (beg.base().base()), ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, Compare>(comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c partial_sort for @c DataVector/List. + * @param beg The start iterator for the sort. + * @param mid The middle iterator for the sort. + * @param end The end iterator for the sort. + * + * @c beg, @c mid, and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL> +void partial_sort (DataModel_detail::iterator<DVL> beg, + DataModel_detail::iterator<DVL> mid, + DataModel_detail::iterator<DVL> end) +{ + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DVL::BaseContainer::value_type> less; + std::partial_sort (beg.base(), mid.base(), end.base(), + DataModel_detail::Compwrapper<DVL, less> (less())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c partial_sort for @c DataVector/List. + * @param beg The start iterator for the sort. + * @param mid The middle iterator for the sort. + * @param end The end iterator for the sort. + * + * @c beg, @c mid, and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Compare> +void partial_sort (DataModel_detail::iterator<DVL> beg, + DataModel_detail::iterator<DVL> mid, + DataModel_detail::iterator<DVL> end, + Compare comp) +{ + std::partial_sort (beg.base(), mid.base(), end.base(), + DataModel_detail::Compwrapper<DVL, Compare> (comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c partial_sort for @c DataVector/List. + * @param beg The start reverse_iterator for the sort. + * @param mid The middle reverse_iterator for the sort. + * @param end The end reverse_iterator for the sort. + * + * @c beg, @c mid, and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL> +void partial_sort (std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + std::reverse_iterator<DataModel_detail::iterator<DVL> > mid, + std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + // Wrap the default comparison object, + // in case someone's overridden operator< for pointers. + typedef std::less<typename DVL::BaseContainer::value_type> less; + std::partial_sort (ri (beg.base().base()), + ri (mid.base().base()), + ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, less> + (less())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c partial_sort for @c DataVector/List. + * @param beg The start reverse_iterator for the sort. + * @param mid The middle reverse_iterator for the sort. + * @param end The end reverse_iterator for the sort. + * + * @c beg, @c mid, and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the sort in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class DVL, class Compare> +void partial_sort (std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + std::reverse_iterator<DataModel_detail::iterator<DVL> > mid, + std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + Compare comp) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::partial_sort (ri (beg.base().base()), + ri (mid.base().base()), + ri (end.base().base()), + typename DataModel_detail::Compwrapper<DVL, Compare> + (comp)); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c random_shuffle for @c DataVector/List. + * @param beg The start iterator for the shuffle operation. + * @param end The end iterator for the shuffle operation. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void random_shuffle (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end) +{ + std::random_shuffle (beg.base(), end.base()); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c random_shuffle for @c DataVector/List. + * @param beg The start iterator for the shuffle operation. + * @param end The end iterator for the shuffle operation. + * @param rand The random generator. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Random> +void random_shuffle (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + Random& rand) +{ + std::random_shuffle (beg.base(), end.base(), rand); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c random_shuffle for @c DataVector/List. + * @param beg The start reverse_iterator for the shuffle operation. + * @param end The end reverse_iterator for the shuffle operation. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL> +void +random_shuffle + (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::random_shuffle (ri(beg.base().base()), + ri(end.base().base())); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c random_shuffle for @c DataVector/List. + * @param beg The start reverse_iterator for the shuffle operation. + * @param end The end reverse_iterator for the shuffle operation. + * @param rand The random generator. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class Random> +void +random_shuffle + (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + Random& rand) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::random_shuffle (ri(beg.base().base()), + ri(end.base().base()), + rand); + DataModel_detail::resortAux (beg, end); +} + + +#if __cplusplus > 201100 +/** + * @brief Specialization of @c shuffle for @c DataVector/List. + * @param beg The start iterator for the shuffle operation. + * @param end The end iterator for the shuffle operation. + * @param g The uniform random number generator. + * + * @c beg and @c end should both be iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class UniformRandom> +void shuffle (typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end, + UniformRandom& g) +{ + std::shuffle (beg.base(), end.base(), g); + DataModel_detail::resortAux (beg, end); +} + + +/** + * @brief Specialization of @c shuffle for @c DataVector/List. + * @param beg The start reverse_iterator for the shuffle operation. + * @param end The end reverse_iterator for the shuffle operation. + * @param g The uniform random number generator. + * + * @c beg and @c end should both be reverse_iterators + * from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class DVL, class UniformRandom> +void +shuffle + (typename std::reverse_iterator<DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<DataModel_detail::iterator<DVL> > end, + UniformRandom& g) +{ + typedef typename DVL::BaseContainer::reverse_iterator ri; + std::shuffle (ri(beg.base().base()), + ri(end.base().base()), + g); + DataModel_detail::resortAux (beg, end); +} +#endif + + +} // namespace std + + + +#endif // not ATHCONTAINERS_TOOLS_DVL_ALGORITHMS_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.icc new file mode 100644 index 00000000..f01cf16a --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_algorithms.icc @@ -0,0 +1,322 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/DVL_algorithms.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Helpers for STL algorithms for @c DataVector/List. + */ + + +#include "AthContainers/tools/DVLNoBase.h" +#include "AthContainers/tools/DVLCast.h" +#include "AthContainers/AuxElement.h" +#include "AthContainersInterfaces/AuxStore_traits.h" +#include <algorithm> + + +template <class DV> class ConstDataVector; + + +namespace DataModel_detail { + + +/** + * @brief Comparison helper for @c DataVector/List classes. + * + * When doing operations such as @c sort on a @c DataVector/List, + * we'd like to be able to give to sort the iterators of the underlying + * @c BaseContainer container, for the sake of efficiency. But we also + * have to make sure that the comparisons see the proper pointer types + * for derived @c DataVector/List classes. This can be done with the following + * functional wrapper. This wraps a comparison object, putting the + * arguments through @c DVLCast before calling the comparison. + * + * There is also a specialization for the case where no casting + * is required. + */ +template <class DVL, class Compare, class DVL_Base=typename DVL::DVL_BASE> +struct Compwrapper +{ + typedef typename DVL::BaseContainer::value_type inptr; + Compare m_comp; + Compwrapper (Compare comp) : m_comp (comp) {} + bool operator() (inptr x, inptr y) + { + return m_comp (DataModel_detail::DVLCast<DVL>::cast (x), + DataModel_detail::DVLCast<DVL>::cast (y)); + } +}; + + +/** + * @brief Comparison helper for @c DataVector/List classes (specialization). + * + * This is specialized for the case where we're dealing with + * a base @c DataVector/List, and thus no casting is required. + */ +template <class DVL, class Compare> +struct Compwrapper<DVL, Compare, DataModel_detail::NoBase> + : public Compare +{ + Compwrapper (Compare comp) : Compare (comp) {} +}; + + +/** + * @brief Predicate helper for @c DataVector/List classes. + * + * When doing operations such as @c partition on a @c DataVector/List, + * we'd like to be able to give the operation the iterators of the underlying + * @c BaseContainer container, for the sake of efficiency. But we also + * have to make sure that the predicate sees the proper pointer types + * for derived @c DataVector/List classes. This can be done with the following + * functional wrapper. This wraps a predicate object, putting the + * arguments through @c DVLCast before calling the predicate. + * + * There is also a specialization for the case where no casting + * is required. + */ +template <class DVL, class Predicate, class DVL_Base=typename DVL::DVL_BASE> +struct Predwrapper +{ + typedef typename DVL::BaseContainer::value_type inptr; + Predicate m_pred; + Predwrapper (Predicate pred) : m_pred (pred) {} + bool operator() (inptr x) + { + return m_pred (DataModel_detail::DVLCast<DVL>::cast (x)); + } +}; + + +/** + * @brief Predicate helper for @c DataVector/List classes (specialization). + * + * This is specialized for the case where we're dealing with + * a base @c DataVector/List, and thus no casting is required. + */ +template <class DV, class Predicate> +struct Predwrapper<DV, Predicate, DataModel_detail::NoBase> + : public Predicate +{ + Predwrapper (Predicate pred) : Predicate (pred) {} +}; + + +/** + * @brief Specialization of @c remove for @c DataVector/List. + * @param beg The start iterator for the remove. + * @param end The end iterator for the remove. + * @param value The value to remove. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the remove in a way that doesn't run afoul of + * @c DataVector/List's object ownership rules. + */ +template <class Iterator, class T> +Iterator +dvl_remove (Iterator beg, + Iterator end, + const T& value) +{ + beg = std::find (beg, end, value); + if (beg == end) + return end; + Iterator res = beg; + *beg = 0; + ++beg; + for (; beg != end; ++beg) { + if (!(*beg == value)) { + std::iter_swap (res, beg); + ++res; + } + else + *beg = 0; + } + return res; +} + + +/** + * @brief Specialization of @c remove_if for @c DataVector/List. + * @param beg The start iterator for the remove. + * @param end The end iterator for the remove. + * @param pred The predicate for the removal. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the remove in a way that doesn't run afoul + * of @c DataVector/List's object ownership rules. + */ +template <class Iterator, class Predicate> +Iterator +dvl_remove_if (Iterator beg, + Iterator end, + Predicate pred) +{ + beg = std::find_if (beg, end, pred); + if (beg == end) + return end; + Iterator res = beg; + *beg = 0; + ++beg; + for (; beg != end; ++beg) { + if (!bool(pred(*beg))) { + std::iter_swap (res, beg); + ++res; + } + else + *beg = 0; + } + return res; +} + + +/** + * @brief Specialization of @c unique for @c DataVector/List. + * @param beg The start iterator for the unique operation. + * @param end The end iterator for the unique operation. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's object ownership rules. + */ +template <class Iterator> +Iterator +dvl_unique (Iterator beg, + Iterator end) +{ + beg = std::adjacent_find (beg, end); + if (beg == end) + return end; + Iterator res = beg; + ++beg; + *beg = 0; + while (++beg != end) { + if (!(*res == *beg)) + std::iter_swap (++res, beg); + else + *beg = 0; + } + return ++res; +} + + +/** + * @brief Specialization of @c unique for @c DataVector/List. + * @param beg The start iterator for the unique operation. + * @param end The end iterator for the unique operation. + * @param pred The predicate for the operation. + * + * @c beg and @c end should both be iterators from the same @c DataVector/List. + * This performs the operation in a way + * that doesn't run afoul of @c DataVector/List's + * object ownership rules. + */ +template <class Iterator, class BinaryPredicate> +Iterator +dvl_unique (Iterator beg, + Iterator end, + BinaryPredicate pred) +{ + beg = std::adjacent_find (beg, end, pred); + if (beg == end) + return end; + Iterator res = beg; + ++beg; + *beg = 0; + while (++beg != end) { + if (!pred(*res, *beg)) + std::iter_swap (++res, beg); + else + *beg = 0; + } + return ++res; +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Call this after some operation that has permuted the elements in the + * container (such as sort). The index information in the elements + * will be used to permute all auxiliary data in the same way. + * Finally, all the indices will be reset in the correct order. + * + * @c ForwardIterator should be an iterator over the @c DataVector + * (not a base iterator). + */ +template <class ForwardIterator> +inline +void resortAux (ForwardIterator beg, + ForwardIterator end) +{ + // Forward to the appropriate specialization, depending on whether + // or not aux data is supported. + typedef typename std::iterator_traits<ForwardIterator>::value_type valtype; + resortAux1 (typename SG::AuxStore_traits<valtype>::flag(), beg, end); +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Aux data case. + */ +template <class DVL> +void resortAux1 (const SG_STD_OR_BOOST::true_type&, + typename DataModel_detail::iterator<DVL> beg, + typename DataModel_detail::iterator<DVL> end) +{ + if (beg != end) { + DVL* cont = dynamic_cast<DVL*> (beg.container()); + if (cont) + cont->resortAux (beg, end); + } +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * Aux data case with reverse iterators. + */ +template <class DVL> +void resortAux1 (const SG_STD_OR_BOOST::true_type&, + typename std::reverse_iterator<typename DataModel_detail::iterator<DVL> > beg, + typename std::reverse_iterator<typename DataModel_detail::iterator<DVL> > end) +{ + if (beg != end) { + DVL* cont = dynamic_cast<DVL*> (beg.base().container()); + if (cont) + cont->resortAux (end.base(), beg.base()); + } +} + + +/** + * @brief Reset indices / reorder aux data after elements have been permuted. + * @param beg Start of the range of elements to process. + * @param end End of the range of elements to process. + * + * No-auxdata case; just a no-op. + */ +template <class ForwardIterator> +inline +void resortAux1 (const SG_STD_OR_BOOST::false_type&, + ForwardIterator, + ForwardIterator) +{ +} + + +} // namespace DataModel_detail diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_iter_swap.h b/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_iter_swap.h new file mode 100644 index 00000000..e42c600e --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/DVL_iter_swap.h @@ -0,0 +1,110 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/DVL_iter_swap.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Specializations of @c iter_swap for @c DataVector/@c DataList. + */ + + +#ifndef ATHCONTAINERS_TOOLS_DVL_ITER_SWAP_H +#define ATHCONTAINERS_TOOLS_DVL_ITER_SWAP_H + + +#include "AthContainers/tools/DVLIterator.h" +#include "AthContainers/tools/ATHCONTAINERS_ASSERT.h" +#include <iterator> + + +namespace std { + + +/** + * @brief Specialization of @c iter_swap for @c DataVector/@c DataList. + * @param a First iterator for the swap. + * @param b Second iterator for the swap. + * + * Swaps @c *a with @c *b, respecting the @c DataVector/List ownership rules. + */ +template <class DV> +void iter_swap (typename DataModel_detail::iterator<DV> a, + typename DataModel_detail::iterator<DV> b) +{ + DV::iter_swap (a, b); +} + + +/** + * @brief Specialization of @c iter_swap for @c DataVector/@c DataList. + * @param a First reverse_iterator for the swap. + * @param b Second reverse_iterator for the swap. + * + * Swaps @c *a with @c *b, respecting the @c DataVector/List ownership rules. + */ +template <class DV> +void +iter_swap (typename std::reverse_iterator<DataModel_detail::iterator<DV> > a, + typename std::reverse_iterator<DataModel_detail::iterator<DV> > b) +{ + DataModel_detail::iterator<DV> ai = a.base(); + DataModel_detail::iterator<DV> bi = b.base(); + --ai; + --bi; + DV::iter_swap (ai, bi); +} + + +/** + * @brief Specialization of @c swap_ranges for @c DataVector/@c DataList. + * @param first1 Start of the first range. + * @param last End of the first range. + * @param first2 Start of the second range. + * + * Swap, element-by-element, the two ranges [first1, last) and + * [first2, first2+(last-first1)). + */ +template <class DV> +DataModel_detail::iterator<DV> +swap_ranges (DataModel_detail::iterator<DV> first1, + DataModel_detail::iterator<DV> last1, + DataModel_detail::iterator<DV> first2) +{ + + for (; first1 != last1; ++first1, ++first2) + std::iter_swap(first1, first2); + return first2; +} + + +/** + * @brief Specialization of @c swap_ranges for @c DataVector/@c DataList. + * @param first1 Start of the first range. + * @param last End of the first range. + * @param first2 Start of the second range. + * + * Swap, element-by-element, the two ranges [first1, last) and + * [first2, first2+(last-first1)). + */ +template <class DV> +std::reverse_iterator<DataModel_detail::iterator<DV> > +swap_ranges (std::reverse_iterator<DataModel_detail::iterator<DV> > first1, + std::reverse_iterator<DataModel_detail::iterator<DV> > last1, + std::reverse_iterator<DataModel_detail::iterator<DV> > first2) +{ + + for (; first1 != last1; ++first1, ++first2) + std::iter_swap(first1, first2); + return first2; +} + + +} // namespace std + + +#endif // not ATHCONTAINERS_TOOLS_DVL_ITER_SWAP_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.h b/EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.h new file mode 100644 index 00000000..85a2494b --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.h @@ -0,0 +1,191 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/ElementProxy.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Proxy for lvalue access to @c DataVector/@c DataList elements. + */ + + +#ifndef ATHCONTAINERS_TOOLS_ELEMENTPROXY_H +#define ATHCONTAINERS_TOOLS_ELEMENTPROXY_H + + +#include "AthContainers/OwnershipPolicy.h" +#include "AthLinks/tools/selection_ns.h" +#include <memory> + + +// Forward declarations. +ENTER_ROOT_SELECTION_NS +namespace DataModel_detail { +template <class DVL> class ElementProxy; +} +EXIT_ROOT_SELECTION_NS + + +namespace DataModel_detail { + + +/** + * @brief Proxy for lvalue access to @c DataVector/@c DataList elements. + * + * We need to be careful with lvalue references to @c DataVector/List elements. + * If the @c DataVector/List owns its elements, then if we write into the + * @c DataVector/List via an lvalue, the old element should be deleted + * (and the @c DataVector/List then takes ownership of the new value). + * We implement this by having the lvalue references return a proxy + * object rather than a raw reference. The proxy handles + * ownership issues. To do this, the proxy stores a pointer + * to the original container. + * + * When inheritance is used with @c DataVector/List, we have the additional + * restriction that we can only write into the @c DataVector/List using + * the most-derived @c DataVector/List class. We also need to enforce that + * in @c ElementProxy when there's an attempt to write via an lvalue. + * We can also get this information from the original container. + */ +template <class DVL> +class ElementProxy +{ +public: + /** + * @brief Constructor. + * @param i The underlying container iterator pointing at + * the element which we're proxying. + * @param container The container that the iterator references. + */ + ElementProxy (typename DVL::BaseContainer::iterator i, + DVL* container); + + + /** + * @brief Assignment operator, from an @c Element proxy. + * @param rhs The proxy from which we're assigning. + * + * If @a rhs is the same as the element we're proxying, then + * we don't need to do anything. Otherwise, @c can_insert must + * be true. If the parent @c DataVector/List owns its elements, + * we then need to delete the proxied object before making + * the assignment. We also disallow copying between two + * @c DataVector/List's, both of which own their elements. + */ + ElementProxy& operator= (const ElementProxy& rhs); + + + /** + * @brief Assignment operator, from a pointer. + * @param rhs The pointer from which we're assigning. + * + * If @a rhs is the same as the element we're proxying, then + * we don't need to do anything. Otherwise, @c can_insert must + * be true. If the parent @c DataVector/List owns its elements, + * we then need to delete the proxied object before making + * the assignment. + */ + ElementProxy& operator= (typename DVL::value_type rhs); + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ + /** + * @brief Assignment operator, from a pointer. + * @param rhs The pointer from which we're assigning. + * + * If @a rhs is the same as the element we're proxying, then + * we don't need to do anything. Otherwise, @c can_insert must + * be true. The container must own its elements in order + * to use this interface. + */ + ElementProxy& operator= (std::unique_ptr<typename DVL::base_value_type> rhs); +#endif +#endif + + + /** + * @brief Conversion to a (const) pointer. + * + * We just need to do a cast here. + */ + operator typename DVL::value_type const() const; + + + /** + * @brief Conversion to a (const) pointer. + * + * We just need to do a cast here. + */ + typename DVL::value_type const operator-> () const; + + + + /** + * @brief Return the container holding the element that this object proxies. + */ + DVL* container() const; + + + typedef typename + ROOT_SELECTION_NS::DataModel_detail::ElementProxy<DVL>::self + self; + + +private: + /// Iterator pointing at the proxied element. + typename DVL::BaseContainer::iterator m_proxied; + + /// The container that it references. + DVL* m_container; +}; + + +} // namespace DataModel_detail + + +ENTER_ROOT_SELECTION_NS + +namespace DataModel_detail { + +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + +template <class DVL> +class ElementProxy +{ +public: + typedef ElementProxy<DVL> self; + ROOT_SELECTION_NS::NO_SELF_AUTOSELECT dum2; + ROOT_SELECTION_NS::TRANSIENT m_proxied; + ROOT_SELECTION_NS::TRANSIENT m_container; +}; + +#else + +template <class DVL> +class ElementProxy +#if ROOT_VERSION_CODE > ROOT_VERSION( 6, 0, 2 ) + : public SelectNoInstance +#endif +{ +public: + typedef ElementProxy<DVL> self; + ROOT_SELECTION_NS::MemberAttributes< kTransient > m_proxied; + ROOT_SELECTION_NS::MemberAttributes< kTransient > m_container; +}; + +#endif // ROOT_VERSION + +} + +EXIT_ROOT_SELECTION_NS + + +#include "AthContainers/tools/ElementProxy.icc" + + +#endif // not ATHCONTAINERS_TOOLS_ELEMENTPROXY_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.icc new file mode 100644 index 00000000..77ce96d0 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/ElementProxy.icc @@ -0,0 +1,145 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/ElementProxy.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Proxy for lvalue access to @c DataVector/@c DataList elements. + */ + + +#include "AthContainers/tools/DVLCast.h" +#include "AthContainers/tools/ATHCONTAINERS_ASSERT.h" + + +namespace DataModel_detail { + + +#ifndef __GCCXML__ + + +/** + * @brief Constructor. + * @param i The underlying container iterator pointing at + * the element which we're proxying. + * @param container The container that the iterator references. + */ +template <class DVL> +inline +ElementProxy<DVL>::ElementProxy (typename DVL::BaseContainer::iterator i, + DVL* container) + : m_proxied (i), + m_container (container) +{ +} + + +/** + * @brief Assignment operator, from an @c Element proxy. + * @param rhs The proxy from which we're assigning. + * + * If @a rhs is the same as the element we're proxying, then + * we don't need to do anything. Otherwise, @c can_insert must + * be true. If the parent @c DataVector/List owns its elements, + * we then need to delete the proxied object before making + * the assignment. We also disallow copying between two + * @c DataVector/List's, both of which own their elements. + */ +template <class DVL> +ElementProxy<DVL>& ElementProxy<DVL>::operator= (const ElementProxy& rhs) +{ + if (*rhs.m_proxied != *m_proxied) { + ATHCONTAINERS_ASSERT (! (container()->ownPolicy() == SG::OWN_ELEMENTS && + rhs.container()->ownPolicy() == SG::OWN_ELEMENTS)); + container()->assignBaseElement (m_proxied, *rhs.m_proxied); + } + return *this; +} + + +/** + * @brief Assignment operator, from a pointer. + * @param rhs The pointer from which we're assigning. + * + * If @a rhs is the same as the element we're proxying, then + * we don't need to do anything. Otherwise, @c can_insert must + * be true. If the parent @c DataVector/List owns its elements, + * we then need to delete the proxied object before making + * the assignment. + */ +template <class DVL> +ElementProxy<DVL>& ElementProxy<DVL>::operator= (typename DVL::value_type rhs) +{ + if (rhs != *m_proxied) + m_container->assignElement(m_proxied, rhs); + return *this; +} + + +#if __cplusplus > 201100 +#ifndef __REFLEX__ +/** + * @brief Assignment operator, from a pointer. + * @param rhs The pointer from which we're assigning. + * + * If @a rhs is the same as the element we're proxying, then + * we don't need to do anything. Otherwise, @c can_insert must + * be true. The container must own its elements in order + * to use this interface. + */ +template <class DVL> +ElementProxy<DVL>& +ElementProxy<DVL>::operator= (std::unique_ptr<typename DVL::base_value_type> rhs) +{ + if (rhs.get() != *m_proxied) + m_container->assignElement(m_proxied, std::move(rhs)); + return *this; +} +#endif +#endif + + +/** + * @brief Conversion to a (const) pointer. + * + * We just need to do a cast here. + */ +template <class DVL> +inline +ElementProxy<DVL>::operator typename DVL::value_type const() const +{ + return DataModel_detail::DVLCast<DVL>::cast (*m_proxied); +} + + +/** + * @brief Conversion to a (const) pointer. + * + * We just need to do a cast here. + */ +template <class DVL> +inline +typename DVL::value_type const ElementProxy<DVL>::operator-> () const +{ + return DataModel_detail::DVLCast<DVL>::cast (*m_proxied); +} + + +/** + * @brief Return the container holding the element that this object proxies. + */ +template <class DVL> +inline +DVL* ElementProxy<DVL>::container() const +{ + return m_container; +} + + +#endif // not __GCCXML__ + + +} // namespace DataModel_detail diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/IsMostDerivedFlag.h b/EDM/athena/Control/AthContainers/AthContainers/tools/IsMostDerivedFlag.h new file mode 100644 index 00000000..afba730a --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/IsMostDerivedFlag.h @@ -0,0 +1,54 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/IsMostDerivedFlag.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Holder for the is-most-derived flag. + */ + + +#ifndef ATHCONTAINERS_ISMOSTDERIVEDFLAG_H +#define ATHCONTAINERS_ISMOSTDERIVEDFLAG_H + + +namespace SG { + + +/** + * @brief Holder for the is-most-derived flag. + * + * This acts like a bool, except that when the class containing it + * gets copied via a copy/move constructor, it is initialized to false. + * This allows us to maintain the flags when the containers have + * only implicit copy constructors for the derived classes. After + * copy construction, the flags will get set correctly by the + * first call to @c testInsert. + */ +class IsMostDerivedFlag +{ +public: + IsMostDerivedFlag() : m_flag(false) {} + IsMostDerivedFlag(bool flag) : m_flag(flag) {} + IsMostDerivedFlag(const IsMostDerivedFlag&) : m_flag(false) {} +#if __cplusplus > 201100 + IsMostDerivedFlag(IsMostDerivedFlag&&) : m_flag(false) {} +#endif + operator bool() const { return m_flag; } + IsMostDerivedFlag& operator= (const IsMostDerivedFlag&) { return *this; } + IsMostDerivedFlag& operator= (bool flag) { m_flag = flag; return *this;} + +private: + bool m_flag; +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERS_ISMOSTDERIVEDFLAG_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/UDSLabelHashTable.h b/EDM/athena/Control/AthContainers/AthContainers/tools/UDSLabelHashTable.h new file mode 100644 index 00000000..28ba8114 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/UDSLabelHashTable.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//Dear emacs, this is -*-c++-*- + + +#ifndef ATHCONTAINERS_UDSLABELHASHTABLE_H +#define ATHCONTAINERS_UDSLABELHASHTABLE_H + +// Don't use this header outside of Athena: +#ifdef XAOD_STANDALONE +#error "UDSLabelHashTable.h is not to be used outside of Athena!" +#endif // XAOD_STANDALONE + + +#include "SGTools/crc64.h" +#include <map> +#include <string> +#include "GaudiKernel/MsgStream.h" + +#include <stdint.h> + + +/** @class UDSLabelHashTable + * @brief Helper class for UserDataStore + * Provides the hash function and keeps a map<hash,label> + */ + +class UDSLabelHashTable { + + public: + typedef uint32_t hash_t; + + enum {INVALID=0}; + + hash_t hash(const std::string& label) const; + const std::string& getLabel(const hash_t number) const; + hash_t addLabel(const std::string& label); + void addLabel(const std::string& label, hash_t hash); + + std::vector<const std::string*> getAllLabels() const; + + size_t size() const {return m_hashLabels.size();} + + typedef std::map<hash_t, std::string>::const_iterator const_iterator; + const_iterator begin() const { return m_hashLabels.begin(); } + const_iterator end() const { return m_hashLabels.end(); } + + private: + std::map<hash_t, std::string> m_hashLabels; + std::string m_empty; + + +}; + +inline +UDSLabelHashTable::hash_t UDSLabelHashTable::hash(const std::string& label) const { + const uint64_t hash64=SG::crc64(label); + return (hash_t)(hash64 & 0xFFFFFFFF); +} + +#endif // not ATHCONTAINERS_UDSLABELHASHTABLE_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/assume.h b/EDM/athena/Control/AthContainers/AthContainers/tools/assume.h new file mode 100644 index 00000000..11325e41 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/assume.h @@ -0,0 +1,33 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/assume.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Macro to provide hints for optimization. + * + * ATHCONTAINERS_ASSUME(x) informs the compiler that it can assume + * that condition x is true. This can be used to let the compiler + * know about conditions that are guaranteed to hold but that it + * cannot deduce itself, such as postconditions for out-of-line + * function calls. + */ + + +#ifndef ATHCONTAINERS_ASSUME_H +#define ATHCONTAINERS_ASSUME_H + + +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define ATHCONTAINERS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while(0) +#else +# define ATHCONTAINERS_ASSUME(x) do { } while(0) +#endif + + +#endif // not ATHCONTAINERS_ASSUME_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/copyAuxStoreThinned.h b/EDM/athena/Control/AthContainers/AthContainers/tools/copyAuxStoreThinned.h new file mode 100644 index 00000000..38da8ea4 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/copyAuxStoreThinned.h @@ -0,0 +1,48 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/copyAuxStoreThinned.h + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Helper to copy an aux store while applying thinning. + */ + + +#ifndef ATHCONTAINERS_COPYAUXSTORETHINNED_H +#define ATHCONTAINERS_COPYAUXSTORETHINNED_H + + +class IThinningSvc; + + +namespace SG { + + +class IConstAuxStore; +class IAuxStore; + + +/** + * @brief Helper to copy an aux store while applying thinning. + * @param orig Source aux store from which to coy. + * @param copy Destination aux store to which to copy. + * @param svc The thinning service. + * + * @c orig and @c copy are both auxiliary store objects. + * The data from @c orig will be copied to @c copy, with individual + * elements removed according to thinning recorded for @c orig in @c svc. + */ +void copyAuxStoreThinned (const SG::IConstAuxStore& orig, + SG::IAuxStore& copy, + IThinningSvc* svc); + + +} // namespace SG + + +#endif // not ATHCONTAINERS_COPYAUXSTORETHINNED_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.h b/EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.h new file mode 100644 index 00000000..5d25ec7f --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.h @@ -0,0 +1,118 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/copyThinned.h + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Helper to copy an object while applying thinning. + * + * The code in this file handles thinning for @c DataVector and + * @c IAuxStore objects. Support for other types may be added by + * providing additional overloads for @c copyThinned1. + * + * In the signature of @c copyThinned1, the container is passed twice: + * once as a reference and once as a pointer. This allows one to use + * overload resolution on the pointer argument to select the proper + * overload, while still being able to get the derived type of the container + * via template binding to the first argument. See the declarations + * below for concrete examples. + */ + + +#ifndef ATHCONTAINERS_COPYTHINNED_H +#define ATHCONTAINERS_COPYTHINNED_H + + +#include "AthContainers/DataVector.h" +#include "AthContainers/ConstDataVector.h" +#include "AthContainers/tools/copyAuxStoreThinned.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthenaKernel/IThinningSvc.h" + + +class IThinningSvc; + + +namespace SG { + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param svc The thinning service. + * + * Returns a new copy of @c orig with elements removed according to the + * thinning defined in @c svc. Ownership of the new object is passed + * back to the caller. + * + * The code here handles @c DataVector and @c IAuxStore objects. + * Support for additional object types may be added by adding + * overloads for @c copyThinned1. + */ +template <class CONTAINER> +CONTAINER* +copyThinned (const CONTAINER& orig, + IThinningSvc* svc); + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param dummy Dummy argument for overload resolution. + * @param svc The thinning service. + * + * This is the generic version of @c copyThinned, which matches types + * for which there is not a more specific overload. It simply makes + * a copy of @c orig using the copy constructor. + */ +template <class CONTAINER> +CONTAINER* +copyThinned1 (const CONTAINER& orig, + const void* dummy, + IThinningSvc* svc); + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param dummy Dummy argument for overload resolution. + * @param svc The thinning service. + * + * This overload handles @c DataVector types. It returns a view container + * copy of @c orig, from which any thinned elements are removed. + */ +template <class CONTAINER> +CONTAINER* +copyThinned1 (const CONTAINER& orig, + const DataVector<typename CONTAINER::base_value_type>* dummy, + IThinningSvc* svc); + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param dummy Dummy argument for overload resolution. + * @param svc The thinning service. + * + * This overload handles @c IAuxStore types. It returns a new copy + * of the store, with any thinned elements removed. + */ +template <class CONTAINER> +CONTAINER* +copyThinned1 (const CONTAINER& orig, + const SG::IAuxStore* dummy, + IThinningSvc* svc); + + +} // namespace SG + + +#include "AthContainers/tools/copyThinned.icc" + + +#endif // not ATHCONTAINERS_COPYTHINNED_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.icc new file mode 100644 index 00000000..37402c9c --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/copyThinned.icc @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/copyThinned.icc + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Helper to copy an object while applying thinning. + */ + + +namespace SG { + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param dummy Dummy argument for overload resolution. + * @param svc The thinning service. + * + * This is the generic version of @c copyThinned, which matches types + * for which there is not a more specific overload. It simply makes + * a copy of @c orig using the copy constructor. + */ +template <class CONTAINER> +CONTAINER* +copyThinned1 (const CONTAINER& orig, + const void* /*dummy*/, + IThinningSvc* /*svc*/) +{ + return new CONTAINER (orig); +} + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param dummy Dummy argument for overload resolution. + * @param svc The thinning service. + * + * This overload handles @c DataVector types. It returns a view container + * copy of @c orig, from which any thinned elements are removed. + */ +template <class CONTAINER> +CONTAINER* +copyThinned1 (const CONTAINER& orig, + const DataVector<typename CONTAINER::base_value_type>* /*dummy*/, + IThinningSvc* svc) +{ + size_t size = orig.size(); + if (size > 0 && + svc && + svc->thinningOccurred (&orig)) + { + ConstDataVector<CONTAINER>* newcont = new ConstDataVector<CONTAINER>; + newcont->clear (SG::VIEW_ELEMENTS); + newcont->reserve (size); + + for (size_t i = 0; i < size; i++) { + if (!IThinningSvc::isThinned (svc->index (&orig, i))) { + newcont->push_back (orig[i]); + } + } + + // FIXME: This is a const-correctness violation, but it's too + // hard to actually fix the interfaces at this time. + // It's problematic to have @c createPersistent return + // a const pointer, because the converter code will then try + // to register the results of extending converters, requiring + // a non-const pointer. + return const_cast<CONTAINER*> (newcont->asDataVector()); + } + + return new CONTAINER (orig); +} + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param dummy Dummy argument for overload resolution. + * @param svc The thinning service. + * + * This overload handles @c IAuxStore types. It returns a new copy + * of the store, with any thinned elements removed. + */ +template <class CONTAINER> +CONTAINER* +copyThinned1 (const CONTAINER& orig, + const SG::IAuxStore* /*dummy*/, + IThinningSvc* svc) +{ + // T->P conversion is done from within copyAuxStoreThinned, + // so we need to call it regardless of whether or not + // thinning is actually done. Don't call it though if the + // container is empty. + if (orig.size() > 0) + { + CONTAINER* newcont = new CONTAINER; + copyAuxStoreThinned (orig, *newcont, svc); + return newcont; + } + + return new CONTAINER (orig); +} + + +/** + * @brief Helper to copy an object while applying thinning. + * @param orig The object to copy. + * @param svc The thinning service. + * + * Returns a new copy of @c orig with elements removed according to the + * thinning defined in @c svc. Ownership of the new object is passed + * back to the caller. + */ +template <class CONTAINER> +CONTAINER* copyThinned (const CONTAINER& orig, + IThinningSvc* svc) +{ + return copyThinned1 (orig, &orig, svc); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/error.h b/EDM/athena/Control/AthContainers/AthContainers/tools/error.h new file mode 100644 index 00000000..c19170d8 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/error.h @@ -0,0 +1,61 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/error.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Helper for emitting error messages. + * + * This defines the macro @c ATHCONTAINER_ERROR, which emits an error + * through the message service if we're built for Athena and prints + * it directly if we're built standalone. + * + * We also define @c AthContainers_detail::typeinfoName. + */ + + +#ifndef ATHCONTAINERS_ERROR_H +#define ATHCONTAINERS_ERROR_H + + +#ifdef XAOD_STANDALONE + +#include <iostream> +#include <string> +#include <typeinfo> + +#define ATHCONTAINERS_ERROR(ctx, msg) \ + std::cout << ctx << "ERROR " << __FILE__ << ":" << __LINE__ << " " \ + << __func__ << ": ERROR: " << msg << "\n" + + +namespace AthContainers_detail { + +std::string typeinfoName (const std::type_info& ti); + +} // namespace AthContainers_detail + + +#else + +#include "AthenaKernel/errorcheck.h" +#include "GaudiKernel/System.h" + +#define ATHCONTAINERS_ERROR(ctx, msg) \ + errorcheck::ReportMessage(MSG::ERROR, ERRORCHECK_ARGS, ctx).msgstream() << msg + +namespace AthContainers_detail { + +using System::typeinfoName; + +} // namespace AthContainers_detail + +#endif // not XAOD_STANDALONE + + +#endif // not ATHCONTAINERS_ERROR_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/foreach.h b/EDM/athena/Control/AthContainers/AthContainers/tools/foreach.h new file mode 100644 index 00000000..5aa9bb6e --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/foreach.h @@ -0,0 +1,31 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/foreach.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief foreach helper for standalone build. + * + * Define @c ATHCONTAINERS_FOREACH to use either @c BOOST_FOREACH + * for C++ directly, depending on whether or not we're using c++11. + */ + + +#ifndef ATHCONTAINERS_FOREACH_H +#define ATHCONTAINERS_FOREACH_H + + +#if __cplusplus < 201100 +# include "boost/foreach.hpp" +# define ATHCONTAINERS_FOREACH(A, B) BOOST_FOREACH(A, B) +#else +# define ATHCONTAINERS_FOREACH(A, B) for (A : B) +#endif + + +#endif // not ATHCONTAINERS_FOREACH_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.h b/EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.h new file mode 100644 index 00000000..e5dec7aa --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.h @@ -0,0 +1,77 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/getThinnedFlags.h + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Return vector of flags giving which container elements were thinned. + */ + + +#ifndef ATHCONTAINERS_GETTHINNEDFLAGS_H +#define ATHCONTAINERS_GETTHINNEDFLAGS_H + + +#include <vector> +#include <cstddef> + + +class IThinningSvc; + + +namespace SG { + + +/** + * @brief Return vector of flags giving which container elements were thinned. + * @param svc The thinning service (or 0). + * @param container The container for which to find thinning information. + * @param nremaining[out] The number of elements in the container not thinned. + * @param flags[out] Array telling which elements were thinned. + * + * If no thinning is done on @c CONTAINER, then return false with + * @c nremaining equal to `container.size()`. @c flags may be empty + * in this case. + * + * Otherwise, the container was thinned, and the function returns true. + * The size of @c flags will equal the container size; each element of + * @c flags is non-zero if the corresponding container element has been + * thinned. @c nremaining will be set to the count of elements + * that have _not_ been thinned. + */ +template <class CONTAINER> +bool getThinnedFlags (IThinningSvc* svc, + const CONTAINER& container, + size_t& nremaining, + std::vector<unsigned char>& flags); + + +/** + * @brief Return vector of flags giving which container elements were thinned. + * @param svc The thinning service (or 0). + * @param container The container for which to find thinning information. + * @param size Size of the container. + * @param nremaining[out] The number of elements in the container not thinned. + * @param flags[out] Array telling which elements were thinned. + * + * This is and out-of-line helper for @c getThinnedFlags. + */ +bool getThinnedFlags1 (IThinningSvc* svc, + const void* container, + size_t size, + size_t& nremaining, + std::vector<unsigned char>& flags); + + +} // namespace SG + + +#include "AthContainers/tools/getThinnedFlags.icc" + + +#endif // not ATHCONTAINERS_GETTHINNEDFLAGS_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.icc new file mode 100644 index 00000000..e7c70ae7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/getThinnedFlags.icc @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/getThinnedFlags.icc + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Return vector of flags giving which container elements were thinned. + */ + + +namespace SG { + + +/** + * @brief Return vector of flags giving which container elements were thinned. + * @param svc The thinning service (or 0). + * @param container The container for which to find thinning information. + * @param nremaining[out] The number of elements in the container not thinned. + * @param flags[out] Array telling which elements were thinned. + * + * If no thinning is done on @c CONTAINER, then return false with + * @c nremaining equal to `container.size()`. @c flags may be empty + * in this case. + * + * Otherwise, the container was thinned, and the function returns true. + * The size of @c flags will equal the container size; each element of + * @c flags is non-zero if the corresponding container element has been + * thinned. @c nremaining will be set to the count of elements + * that have _not_ been thinned. + */ +template <class CONTAINER> +bool getThinnedFlags (IThinningSvc* svc, + const CONTAINER& container, + size_t& nremaining, + std::vector<unsigned char>& flags) +{ + return getThinnedFlags1 (svc, &container, container.size(), + nremaining, flags); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/likely.h b/EDM/athena/Control/AthContainers/AthContainers/tools/likely.h new file mode 100644 index 00000000..dfc9f123 --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/likely.h @@ -0,0 +1,31 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/likely.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Define likely/unlikely macros for branch prediction. + * + * Duplicated here for standalone builds. + */ + + +#ifndef ATHCONTAINERS_LIKELY_H +#define ATHCONTAINERS_LIKELY_H + + +#if __GNUC__ >= 4 || defined(__clang__) +# define ATHCONTAINERS_LIKELY(x) __builtin_expect(!!(x), 1) +# define ATHCONTAINERS_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define ATHCONTAINERS_LIKELY(x) (x) +# define ATHCONTAINERS_UNLIKELY(x) (x) +#endif + + +#endif // not ATHCONTAINERS_LIKELY_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/threading.h b/EDM/athena/Control/AthContainers/AthContainers/tools/threading.h new file mode 100644 index 00000000..5857f55d --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/threading.h @@ -0,0 +1,266 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools/threading.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Threading definitions. + * + * In a standard build, we define the locking objects below. + * In a standalone build, or with ATHCONTAINERS_NO_THREADS defined, + * they're defined as no-ops. + */ + + +#ifndef ATHCONTAINERS_THREADING_H +#define ATHCONTAINERS_THREADING_H + + +#if defined(XAOD_STANDALONE) || defined(__GCCXML__) +# ifndef ATHCONTAINERS_NO_THREADS +# define ATHCONTAINERS_NO_THREADS +# endif +#endif + + +#ifdef ATHCONTAINERS_NO_THREADS + + +namespace AthContainers_detail { + + +/** + * @brief No-op definition of @c mutex. + */ +class mutex {}; + + +/** + * @brief No-op definition of @c lock_guard. + */ +template <class LOCKABLE> +class lock_guard +{ +public: + lock_guard() {} + lock_guard(LOCKABLE&) {} +}; + + +/** + * @brief No-op definition of @c upgrade_mutex. + */ +class upgrade_mutex +{ +public: + void lock() {} + void unlock() {} + void lock_shared() {} + void unlock_shared() {} + void lock_upgrade() {} + void unlock_upgrade() {} + void unlock_upgrade_and_lock() {} +private: + // Real upgrade_mutex is not assignable. Need this for proper + // dictionary generation. + upgrade_mutex& operator= (const upgrade_mutex&); +}; + + +/** + * @brief Single-thread version of thread_specific_ptr. + */ +template <class T> +class thread_specific_ptr +{ +public: + thread_specific_ptr() : m_ptr(0) {} + ~thread_specific_ptr() { delete m_ptr; } + T* get() const { return m_ptr; } + T* operator->() const { return m_ptr; } + T& operator*() const { return *m_ptr; } + void reset (T* new_value=0) { delete m_ptr; m_ptr = new_value; } + T* release() { T* ret = m_ptr; m_ptr = 0; return ret; } + +private: + T* m_ptr; +}; + + +/// No-op definitions of fences. +inline void fence_acq_rel() {} +inline void fence_seq_cst() {} + + +} // namespace AthContainers_detail + + +#else // not ATHCONTAINERS_NO_THREADS + +//the shared_mutex include generates annoying unused_variable warnings during compilations... silence this in athanalysisbase +#ifdef XAOD_ANALYSIS +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED 1 +#endif +#endif + +#include "boost/thread/shared_mutex.hpp" +#include "boost/thread/tss.hpp" +#if __cplusplus > 201100 +# include <atomic> +# include <mutex> +# include <thread> +namespace SG_STD_OR_BOOST = std; +#else +# include "boost/atomic.hpp" +# include "boost/thread/mutex.hpp" +# include "boost/thread/thread.hpp" +namespace SG_STD_OR_BOOST = boost; +#endif + + +namespace AthContainers_detail { + + +// Take these from boost. (Boost extensions not in C++.) +using boost::upgrade_mutex; +using boost::thread_specific_ptr; + +// Other mutex/lock types come from either boost or std. +using SG_STD_OR_BOOST::mutex; +using SG_STD_OR_BOOST::lock_guard; +using SG_STD_OR_BOOST::thread; + + +/** + * @brief An acquire/release fence. + */ +void fence_acq_rel(); + + +/** + * @brief A sequentially-consistent fence. + */ +void fence_seq_cst(); + + +} // namespace AthContainers_detail + + +#endif // not ATHCONTAINERS_NO_THREADS + + + +namespace AthContainers_detail { + + +/** + * @brief Lock object for taking out shared locks. + * + * This is like the boost @c strict_lock, except that it takes out a shared + * lock on the underlying object rather than an exclusive one. + */ +template <typename LOCKABLE> +class strict_shared_lock +{ +public: + /// The underlying object type. + typedef LOCKABLE lockable_type; + + + /** + * @brief Take out a shared lock on @c obj and remember it. + * @param obj The lockable object. + */ + explicit strict_shared_lock(lockable_type& obj); + + + /** + * @brief Take out a shared lock on @c obj and remember it. + * @param obj The lockable object. + */ + explicit strict_shared_lock(const lockable_type& obj); + + + /** + * @brief Release the held lock. + */ + ~strict_shared_lock(); + + +private: + // Disallow these. + strict_shared_lock(); + strict_shared_lock(strict_shared_lock const&); + strict_shared_lock& operator=(strict_shared_lock const&); + + +private: + /// The lock being held. + lockable_type& m_obj; +}; + + +/** + * @brief Lock object for taking out upgradable locks. + * + * The will first be taken out in upgrade mode. + * If @c upgrade() is called, then the lock will be upgraded to exclusive mode. + * When this object is destroyed, the object will be unlocked for either + * upgrade or exclusive mode, as appropriate. + */ +template <class LOCKABLE> +class upgrading_lock +{ +public: + /// The underlying object type. + typedef LOCKABLE lockable_type; + + + /** + * @brief Take out an upgrade lock on @c obj and remember it. + * @param obj The lockable object. + */ + explicit upgrading_lock (lockable_type& obj); + + + /** + * @brief Release the held lock. + */ + ~upgrading_lock(); + + + /** + * @brief Convert the lock from upgrade to exclusive. + */ + void upgrade(); + + +private: + // Disallow these. + upgrading_lock(); + upgrading_lock(upgrading_lock const&); + upgrading_lock& operator=(upgrading_lock const&); + + +private: + /// The lock being held. + lockable_type& m_obj; + + /// Has the lock been converted to exclusive? + bool m_exclusive; +}; + + +} // namespace AthContainers_detail + + +#include "AthContainers/tools/threading.icc" + + +#endif // not ATHCONTAINERS_THREADING_H diff --git a/EDM/athena/Control/AthContainers/AthContainers/tools/threading.icc b/EDM/athena/Control/AthContainers/AthContainers/tools/threading.icc new file mode 100644 index 00000000..e51cd3ee --- /dev/null +++ b/EDM/athena/Control/AthContainers/AthContainers/tools/threading.icc @@ -0,0 +1,123 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/tools.threading.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Threading definitions. + */ + + +namespace AthContainers_detail { + + +#ifndef ATHCONTAINERS_NO_THREADS + + +/** + * @brief An acquire/release fence. + */ +inline +void fence_acq_rel() +{ + SG_STD_OR_BOOST::atomic_thread_fence (SG_STD_OR_BOOST::memory_order_acq_rel); +} + + +/** + * @brief A sequentially-consistent fence. + */ +inline +void fence_seq_cst() +{ + SG_STD_OR_BOOST::atomic_thread_fence (SG_STD_OR_BOOST::memory_order_seq_cst); +} + + +#endif + + +/** + * @brief Take out a shared lock on @c obj and remember it. + * @param obj The lockable object. + */ +template <typename LOCKABLE> +inline +strict_shared_lock<LOCKABLE>::strict_shared_lock (lockable_type& obj) + : m_obj(obj) +{ + obj.lock_shared(); // locks on construction +} + + +/** + * @brief Take out a shared lock on @c obj and remember it. + * @param obj The lockable object. + */ +template <typename LOCKABLE> +inline +strict_shared_lock<LOCKABLE>::strict_shared_lock (const lockable_type& obj) + : m_obj(const_cast<lockable_type&>(obj)) +{ + obj.lock_shared(); // locks on construction +} + + +/** + * @brief Release the held lock. + */ +template <typename LOCKABLE> +inline +strict_shared_lock<LOCKABLE>::~strict_shared_lock() +{ + m_obj.unlock_shared(); // unlocks on destruction +} + + +/** + * @brief Take out an upgrade lock on @c obj and remember it. + * @param obj The lockable object. + */ +template <typename LOCKABLE> +inline +upgrading_lock<LOCKABLE>::upgrading_lock (lockable_type& obj) + : m_obj (obj) +{ + m_obj.lock_upgrade(); + m_exclusive = false; +} + + +/** + * @brief Release the held lock. + */ +template <typename LOCKABLE> +inline +upgrading_lock<LOCKABLE>::~upgrading_lock() +{ + if (m_exclusive) + m_obj.unlock(); + else + m_obj.unlock_upgrade(); +} + + +/** + * @brief Convert the lock from upgrade to exclusive. + */ +template <typename LOCKABLE> +inline +void upgrading_lock<LOCKABLE>::upgrade() +{ + if (!m_exclusive) { + m_obj.unlock_upgrade_and_lock(); + m_exclusive = true; + } +} + + + +} // namespace AthContainers_detail diff --git a/EDM/athena/Control/AthContainers/CMakeLists.txt b/EDM/athena/Control/AthContainers/CMakeLists.txt new file mode 100644 index 00000000..c24d815e --- /dev/null +++ b/EDM/athena/Control/AthContainers/CMakeLists.txt @@ -0,0 +1,104 @@ +# $Id: CMakeLists.txt 800990 2017-03-19 23:15:21Z ssnyder $ +################################################################################ +# Package: AthContainers +################################################################################ + +# Declare the package name: +atlas_subdir( AthContainers ) + +# Extra dependencies, based on the environment we are in: +if( NOT XAOD_STANDALONE ) + set( extra_deps Control/AthenaKernel Control/SGTools GaudiKernel ) + set( extra_libs AthenaKernel SGTools GaudiKernel ) + set( extra_sources src/*.cxx ) +endif() + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/AthContainersInterfaces + Control/AthLinks + Control/CxxUtils + ${extra_deps} + PRIVATE + AtlasTest/TestTools ) + +# External dependencies: +find_package( Boost COMPONENTS thread ) +find_package( ROOT COMPONENTS Core ) + +# Component(s) in the package: +atlas_add_library( AthContainers + AthContainers/*.h AthContainers/*.icc + AthContainers/tools/*.h AthContainers/tools/*.icc + Root/*.cxx ${extra_sources} + PUBLIC_HEADERS AthContainers + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} AthLinks CxxUtils ${extra_libs} ) + +atlas_add_dictionary( AthContainersDict + AthContainers/AthContainersDict.h + AthContainers/selection.xml + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers + EXTRA_FILES Root/dict/*.cxx ) + +# Helper function setting up the test(s) in the package: +function( _add_test name ) + cmake_parse_arguments( ARG "" "EXTRA_PATTERNS" "" ${ARGN} ) + if( ARG_EXTRA_PATTERNS ) + set( extra_arg EXTRA_PATTERNS ${ARG_EXTRA_PATTERNS} ) + endif() + atlas_add_test( ${name} + SOURCES test/${name}.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthLinks CxxUtils + TestTools AthContainers ${extra_libs} + ${extra_arg} ) +endfunction( _add_test ) + +# Test(s) in the package: +_add_test( removeDuplicates_test ) +_add_test( DataVector_test ) +_add_test( DataVector_a_test ) +_add_test( DataVector_b_test ) +_add_test( DataVector_c_test ) +_add_test( DataVector_d_test ) +_add_test( DataVector_e_test ) +_add_test( DataVector_f_test ) +_add_test( DataList_test ) +_add_test( DVLInfo_test ) +_add_test( DVLCast_test ) +_add_test( IsMostDerivedFlag_test ) +_add_test( ElementProxy_test ) +_add_test( DVLIterator_test ) +_add_test( DVL_iter_swap_test ) +_add_test( foreach_test ) +_add_test( AuxTypeVector_test ) +_add_test( AuxTypeVectorFactory_test ) +_add_test( AuxTypeRegistry_test EXTRA_PATTERNS "will use std::" ) +_add_test( AuxVectorBase_test EXTRA_PATTERNS "will use std::" ) +_add_test( AuxStoreInternal_test ) +_add_test( AuxStoreStandalone_test ) +_add_test( AuxElement_test ) +_add_test( AuxElementComplete_test ) +_add_test( error_test ) +_add_test( threading_test ) +_add_test( threading_nothreads_test ) +_add_test( exceptions_test ) +_add_test( normalizedTypeinfoName_test ) +_add_test( getThinnedFlags_test ) +_add_test( copyAuxStoreThinned_test ) +_add_test( copyThinned_test ) +_add_test( PackedParameters_test ) +_add_test( PackedConverter_test ) +_add_test( PackedContainer_test ) +_add_test( debug_test ) + +if( NOT XAOD_STANDALONE ) + _add_test( dataVectorAsELV_test ) + _add_test( ViewVector_test ) + _add_test( ViewVectorBase_test ) + _add_test( AuxVectorData_test EXTRA_PATTERNS "will use std::" ) + _add_test( DVLDataBucket_test ) +endif() diff --git a/EDM/athena/Control/AthContainers/Root/AuxElement.cxx b/EDM/athena/Control/AthContainers/Root/AuxElement.cxx new file mode 100644 index 00000000..6866ed00 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/AuxElement.cxx @@ -0,0 +1,497 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/Root/AuxElement.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Base class for elements of a container that can have aux data. + */ + + +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxStoreStandalone.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/foreach.h" + + + +namespace SG { + + +/** + * @brief Internal data container. + * + * If an object has a private or standalone data store, + * its container is set to point to an instance of this. + */ +class AuxElementData + : public AuxVectorData +{ +public: + virtual size_t size_v() const { return 1; } + virtual size_t capacity_v() const { return 1; } +}; + + +/** + * @brief Internal data container for private store. + * + * This is used when we have a private aux store. + * It contains an embedded store object. + */ +class AuxElementPrivateData + : public AuxElementData +{ +public: + AuxElementPrivateData () + { + this->setStore (&m_store); + } + + +private: + AuxStoreStandalone m_store; +}; + + +/** + * @brief Internal data container for standalone store. + * + * This is used when we have an external (`standalone') aux store. + */ +class AuxElementStandaloneData + : public AuxElementData +{ +public: + using AuxElementData::setStore; +}; + + +//************************************************************************ + + +/// Special value used to mark that an object had a private store, +/// but it was released because it was added to a container. +/// (And therefore we should recreate the private store if the +/// object is later removed.) +SG::AuxElementData* AuxElement::s_privatePlaceholder = + reinterpret_cast<SG::AuxElementData*>(1); + + +/** + * @brief Create a new (empty) private store for this object. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + */ +void AuxElement::makePrivateStore() +{ + if (m_privateData || m_container) { + throw SG::ExcBadPrivateStore ("store already exists"); + } + + m_privateData = new SG::AuxElementPrivateData; + m_index = 0; + m_container = m_privateData; +} + + +/** + * @brief Release and free any private store associated with this object. + * + * @c ExcBadPrivateStore will be thrown if this object does not + * have a private store. + */ +void AuxElement::releasePrivateStore() +{ + if (m_privateData == s_privatePlaceholder) { + // We had a private store, but it was released because this object + // was added to a container. Just forget about it. + m_privateData = 0; + return; + } + + if (!m_privateData || + (m_container && m_container != m_privateData) || + typeid(*m_privateData) != typeid(AuxElementPrivateData)) + { + throw SG::ExcBadPrivateStore ("no private store exists"); + } + + m_index = 0; + m_container = 0; + delete m_privateData; + m_privateData = 0; +} + + +/** + * @brief Set the store associated with this object. + * @param store The new store. + * + * If store is nonzero, this adds a standalone store to the object. + * The object must not be in a container and must not have a private store. + * If store is zero, this removes a standalone store. + */ +void AuxElement::setStore (const SG::IConstAuxStore* store) +{ + AuxElementStandaloneData* data = setStore1 (store); + if (store) + data->setStore (store); +} + + +/** + * @brief Set the store associated with this object. + * @param store The new store. + * + * If store is nonzero, this adds a standalone store to the object. + * The object must not be in a container and must not have a private store. + * If store is zero, this removes a standalone store. + */ +void AuxElement::setStore (SG::IAuxStore* store) +{ + AuxElementStandaloneData* data = setStore1 (store); + if (store) + data->setStore (store); +} + + +/** + * @brief Set the store associated with this object. + * @param store Link to the new store. + */ +void AuxElement::setStore (const DataLink< SG::IConstAuxStore >& store) +{ + AuxElementStandaloneData* data = setStore1 (store); + if (store) + data->setStore (store); +} + + +/** + * @brief Test to see if this object is currently using a private store. + */ +bool AuxElement::usingPrivateStore() const +{ + return privateDataValid() && + typeid(*m_privateData) == typeid(AuxElementPrivateData); +} + + +/** + * @brief Test to see if this object is currently using a private store. + */ +bool AuxElement::usingStandaloneStore() const +{ + return privateDataValid() && + typeid(*m_privateData) == typeid(AuxElementStandaloneData); +} + + +/** + * @brief Return the current store, as a const interface. + * + * This will be non-zero if either a const or non-const store + * is associated with this object. + * This will fetch either a private or standalone store. + */ +const SG::IConstAuxStore* AuxElement::getConstStore() const +{ + if (privateDataValid()) + return m_privateData->getConstStore(); + return 0; +} + + +/** + * @brief Return the current store, as a non-const interface. + * + * This will be non-zero if a non-const store is associated with this object. + * This will fetch either a private or standalone store. + */ +SG::IAuxStore* AuxElement::getStore() const +{ + if (privateDataValid()) + return m_privateData->getStore(); + return 0; +} + + +/** + * @brief Clear the cached aux data pointers. + * + * You should call this any time something changes in the aux store + * that could invalidate the vector pointers. + */ +void AuxElement::clearCache() +{ + if (m_container) + m_container->clearCache(); +} + + +/** + * @brief Return a set of identifiers for existing data items + * for this object. + * + * If this object has a private or standalone store, then information + * from that will be returned. Otherwise, if this element + * is part of a container, then information for the container + * will be returned. Otherwise, return an empty set. + */ +const SG::auxid_set_t& AuxElement::getAuxIDs() const +{ + if (privateDataValid()) + return m_privateData->getConstStore()->getAuxIDs(); + if (container()) + return container()->getAuxIDs(); + static SG::auxid_set_t null_set; + return null_set; +} + + +/** + * @brief Return true if this object has an associated store. + * + * This will be true for either a private or standalone store. + */ +bool AuxElement::hasStore() const +{ + if (privateDataValid()) + return m_privateData->hasStore(); + return false; +} + + +/** + * @brief Return true if this object has an associated non-const store. + * + * This will be true for either a private or standalone store. + */ +bool AuxElement::hasNonConstStore() const +{ + if (privateDataValid()) + return m_privateData->hasNonConstStore(); + return false; +} + + +/** + * @brief Clear all decorations. + * + * Erase all decorations from an associated store, restoring the state to when + * @c lock was called. + */ +void AuxElement::clearDecorations() const +{ + if (privateDataValid()) + m_privateData->clearDecorations(); +} + + +/** + * @brief Out-of-line portion of destructor. + * + * Delete a private store if we have one. + */ +void AuxElement::releasePrivateStoreForDtor() +{ + if (m_privateData != s_privatePlaceholder) + { + delete m_privateData; + } +} + + +/** + * @brief Set the store associated with this object. + * @param store The new store. + * + * Helper for @c setStore. Creates the @x AuxElementStandaloneData + * object if needed and returns it. + */ +AuxElementStandaloneData* +AuxElement::setStore1 (const SG::IConstAuxStore* store) +{ + if (store) { + // Want this object be standalone. + if (!m_container) { + // Not in a container (and no private store). Make a new object. + AuxElementStandaloneData* data = new AuxElementStandaloneData; + m_privateData = data; + m_container = data; + return data; + } + if (usingStandaloneStore()) { + // Standalone --- return existing object. + return static_cast<AuxElementStandaloneData*> (m_privateData); + } + // Otherwise, it's an error. + throw ExcBadPrivateStore ("Attempt to attach a standalone store to an " + "object in a container or with a private store."); + } + + else { + // Getting rid of a standalone store. + if (usingStandaloneStore()) { + delete m_privateData; + m_privateData = 0; + m_container = 0; + } + else if (m_container != 0) + throw ExcBadPrivateStore ("Attempt to remove a standalone store from an " + "object in a container or with a private store."); + return 0; + } +} + + +/** + * @brief Set the index/container for this element. + * @param index The index of this object within the container. + * @param container The container holding this object. + * May be null if this object is being removed + * from a container. + * + * This is called from @c setIndex when we have a private store to deal with. + */ +bool AuxElement::setIndexPrivate (size_t index, SG::AuxVectorData* container) +{ + // Precondition: m_privateData != 0. + + if (m_privateData == s_privatePlaceholder) { + // We had a private store, but it was released because we were added + // to a container. + + if (container == 0) { + // We're being moved out of the container. Make a new private + // store, copy the data, and switch to it. + m_privateData = new SG::AuxElementPrivateData; + AuxElement to (m_privateData, 0); + to.copyAux (*this); + m_index = 0; + m_container = m_privateData; + return true; + } + } + else if (typeid(*m_privateData) == typeid(AuxElementPrivateData)) { + // We currently have a private store. + + if (container != 0 && container != m_privateData) { + // We're being added to a container. + // Aux data has already been copied. + // Release private store. + delete m_privateData; + m_privateData = s_privatePlaceholder; + } + } + else { + // We have a standalone store. + throw SG::ExcBadPrivateStore ("Attempt to add/remove a standalone object " + "from a container."); + } + + m_index = index; + m_container = container; + return false; +} + + +/** + * @brief Create a new private store for this object and copy aux data. + * @param other The object from which aux data should be copied. + * + * @c ExcBadPrivateStore will be thrown if this object is already + * associated with a store. + * + * This overload handles the case where @c other does have aux data. + */ +void AuxElement::makePrivateStore1 (const AuxElement* other) +{ + makePrivateStore(); + if (other) + this->copyAux (*other); +} + + +/** + * @brief Clear all aux data associated with this element. + * + * If this object has no associated store, this does nothing. + * If the associated aux data is const, this throws @c ExcConstAuxData. + */ +void AuxElement::clearAux() +{ + if (!m_container) return; + if (!m_container->hasStore()) return; + if (!m_container->hasNonConstStore()) + throw SG::ExcConstAuxData ("clearAux", SG::null_auxid); + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::AuxTypeRegistry::lock_t lock (r); + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, m_container->getWritableAuxIDs()) { + void* dst = m_container->getDataArray (auxid); + r.clear (lock, auxid, dst, m_index); + } +} + + +/** + * @brief Copy aux data from another object. + * @param other The object from which to copy. + * + * If this object has no associated store, this does nothing. + * If the associated aux data is const, this throws @c ExcConstAuxData. + * + * All aux data items from @c other are copied to this object. + * Any aux data items associated with this object that are not present + * in @c other are cleared. (If @c other has no aux data, then all + * aux data items for this object are cleared.) + */ +void AuxElement::copyAux (const AuxElement& other) +{ + if (!m_container) return; + if (!m_container->hasStore()) return; + if (!m_container->hasNonConstStore()) + throw SG::ExcConstAuxData ("copyAux"); + + const SG::AuxVectorData* ocont = other.container(); + + if (!ocont || !ocont->hasStore()) { + this->clearAux(); + return; + } + + size_t oindex = other.index(); + const SG::auxid_set_t& other_ids = ocont->getAuxIDs(); + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, other_ids) { + const void* src = ocont->getDataArrayAllowMissing (auxid); + if (src) { + void* dst = m_container->getDataArray (auxid); + r.copy (auxid, dst, m_index, src, oindex); + } + else { + void* dst = m_container->getDataArray (auxid); + r.clear (auxid, dst, m_index); + } + } + + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, m_container->getWritableAuxIDs()) { + if (other_ids.find (auxid) == other_ids.end()) { + void* dst = m_container->getDataArray (auxid); + r.clear (auxid, dst, m_index); + } + } +} + + +} // namespace SG + + diff --git a/EDM/athena/Control/AthContainers/Root/AuxStoreInternal.cxx b/EDM/athena/Control/AthContainers/Root/AuxStoreInternal.cxx new file mode 100644 index 00000000..696c260d --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/AuxStoreInternal.cxx @@ -0,0 +1,677 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/src/AuxStoreInternal.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief An auxiliary data store that holds data internally. + */ + + +#include <iostream> +#include <sstream> + +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/PackedParameters.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/foreach.h" +#include "AthContainers/tools/error.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param standalone If true, then write this in standalone mode. + */ +AuxStoreInternal::AuxStoreInternal (bool standalone /*= false*/) + : m_standalone (standalone), + m_tick (0), + m_locked (false) +{ +} + + +/** + * @brief Destructor. + * + * All contained data will be deleted. + */ +AuxStoreInternal::~AuxStoreInternal() +{ + ATHCONTAINERS_FOREACH (IAuxTypeVector* p, m_vecs) + delete p; +} + + +/** + * @brief Copy constructor. + */ +AuxStoreInternal::AuxStoreInternal (const AuxStoreInternal& other) + : m_standalone (other.m_standalone), + m_isDecoration (other.m_isDecoration), + m_auxids (other.m_auxids), + m_tick (1), + m_locked (other.m_locked) +{ + size_t size = other.m_vecs.size(); + m_vecs.resize (size); + for (size_t i = 0; i < size; i++) { + if (other.m_vecs[i]) + m_vecs[i] = other.m_vecs[i]->clone(); + } +} + + +/** + * @brief Return the standalone flag. + */ +bool AuxStoreInternal::standalone() const +{ + return m_standalone; +} + + +/** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * This should return 0 if the item doesn't exist. + */ +const void* AuxStoreInternal::getData (auxid_t auxid) const +{ + guard_t guard (m_mutex); + if (auxid >= m_vecs.size() || !m_vecs[auxid]) { + // With the new behavior of SG::AuxElement::Accessor::isAvailable, + // we shouldn't print an error message here. Asking the store whether + // it has an element using this function is not necessarily an + // error condition by now. In any case, the DataVector code will + // complain itself in case of an error. + return 0; + } + return m_vecs[auxid]->toPtr(); +} + + +/** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + */ +void* AuxStoreInternal::getData (auxid_t auxid, size_t size, size_t capacity) +{ + return getDataInternal (auxid, size, capacity, false); +} + + +/** + * @brief Explicitly add a vector to the store. + * @param auxid The identifier of the aux data item being added. + * @param vec Vector data being added. + * @param isDecoration Should this variable be marked as a decoration? + * + * For internal use. The @c auxid must not already exist in the store. + */ +void +AuxStoreInternal::addVector (auxid_t auxid, + std::unique_ptr<IAuxTypeVector> vec, + bool isDecoration) +{ + guard_t guard (m_mutex); + if (m_locked) + throw ExcStoreLocked (auxid); + + // Resize the vectors if needed. + if (m_vecs.size() <= auxid) { + m_vecs.resize (auxid+1); + m_isDecoration.resize (auxid+1); + } + + // Give up if the variable is already present in the store. + if (m_vecs[auxid]) std::abort(); + + // Make sure the length is consistent with the rest of the store. + size_t sz = this->size_noLock(); + if (vec->size() < sz) + vec->resize (sz); + + // Add it to the store. + m_vecs[auxid] = vec.release(); + m_isDecoration[auxid] = isDecoration; + addAuxID (auxid); +} + + +/** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it then it will be created and initialized + * with default values. If the container is locked, then the new + * item will be marked as a decoration. @c size and @c capacity give + * the size for the new aux data item vector. + * + * If the data item already exists, then we return it if either the + * container is not locked or the item is marked as a decoration. + * Otherwise we throw an exception. + */ +void* +AuxStoreInternal::getDecoration (auxid_t auxid, size_t size, size_t capacity) +{ + guard_t guard (m_mutex); + if (m_vecs.size() <= auxid) { + m_vecs.resize (auxid+1); + m_isDecoration.resize (auxid+1); + } + if (m_vecs[auxid] == 0) { + m_vecs[auxid] = AuxTypeRegistry::instance().makeVector (auxid, size, capacity); + addAuxID (auxid); + if (m_locked) + m_isDecoration[auxid] = true; + } + if (m_locked && !m_isDecoration[auxid]) + throw ExcStoreLocked (auxid); + return m_vecs[auxid]->toPtr(); +} + + +/** + * @brief Change the size of all aux data vectors. + * @param sz The new size. + * + * This should be called when the size of the container changes. + * This should resize the vectors for all aux data items. + * + * If the size of the container grows, the new elements should + * be default-initialized; if it shrinks, destructors should + * be run as appropriate. + * + * Should return @c true if it is known that none of the data pointers + * changed (and thus the cache does not need to be cleared), false + * otherwise. + */ +bool AuxStoreInternal::resize (size_t sz) +{ + guard_t guard (m_mutex); + if (m_locked) + throw ExcStoreLocked ("resize"); + bool nomoves = true; + for (IAuxTypeVector* v : m_vecs) { + if (v) { + if (!v->resize (sz)) + nomoves = false; + } + } + return nomoves; +} + + +/** + * @brief Change the capacity of all aux data vectors. + * @param sz The new capacity. + * + * This should be called when the capacity of the container changes + * (by @c reserve). This should change the capacity for the vectors + * for all aux data items. + */ +void AuxStoreInternal::reserve (size_t sz) +{ + guard_t guard (m_mutex); + if (m_locked) + throw ExcStoreLocked ("reserve"); + ATHCONTAINERS_FOREACH (IAuxTypeVector* v, m_vecs) { + if (v) + v->reserve (sz); + } +} + + +/** + * @brief Shift the elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +void AuxStoreInternal::shift (size_t pos, ptrdiff_t offs) +{ + guard_t guard (m_mutex); + if (m_locked) + throw ExcStoreLocked ("shift"); + ATHCONTAINERS_FOREACH (IAuxTypeVector* v, m_vecs) { + if (v) + v->shift (pos, offs); + } +} + + +/** + * @brief Move all elements from @c other to this store. + * @param pos The starting index of the insertion. + * @param other Store from which to do the move. + * @param ignore Set of variables that should not be added to the store. + * + * Let @c len be the size of @c other. The store will be increased + * in size by @c len elements, with the elements at @c pos being + * copied to @c pos+len. Then, for each auxiliary variable, the + * entire contents of that variable for @c other will be moved to + * this store at index @c pos. This will be done via move semantics + * if possible; otherwise, it will be done with a copy. Variables + * present in this store but not in @c other will have the corresponding + * elements default-initialized. Variables in @c other but not in this + * store will be added unless they are in @c ignore. + * + * Returns true if it is known that none of the vectors' memory moved, + * false otherwise. + */ +bool AuxStoreInternal::insertMove (size_t pos, + IAuxStore& other, + const SG::auxid_set_t& ignore) +{ + guard_t guard (m_mutex); + const AuxTypeRegistry& r = AuxTypeRegistry::instance(); + + if (m_locked) + throw ExcStoreLocked ("insertMove"); + bool nomove = true; + size_t other_size = other.size(); + if (other_size == 0) + return true; + 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) { + 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; + } + } + } + + // Add any new variables not present in the original container. + for (SG::auxid_t id : other.getAuxIDs()) { + if (m_auxids.find(id) == m_auxids.end() && + ignore.find(id) == ignore.end()) + { + if (other.getData (id)) { + void* src_ptr = other.getData (id, other_size, other_size); + if (src_ptr) { + size_t sz = size_noLock(); + if (sz < other_size) sz = other_size + pos; + (void)getDataInternal_noLock (id, sz, sz, false); + m_vecs[id]->resize (sz - other_size); + m_vecs[id]->insertMove (pos, src_ptr, reinterpret_cast<char*>(src_ptr) + other_size*r.getEltSize(id)); + nomove = false; + } + } + } + } + + return nomove; +} + + +/** + * @brief Return a set of identifiers for existing data items + * in this store. + * + * This should include identifiers for all items, + * const and non-const. + */ +const SG::auxid_set_t& +AuxStoreInternal::getAuxIDs() const +{ + guard_t guard (m_mutex); + if (m_tsAuxids.get() == 0) { + m_tsAuxids.reset (new TSAuxidSet (m_tick, m_auxids)); + } + else if (m_tsAuxids->m_tick != m_tick) { + m_tsAuxids->m_set = m_auxids; // May need to optimize this! + m_tsAuxids->m_tick = m_tick; + } + return m_tsAuxids->m_set; +} + + +/** + * @brief Return a set of identifiers for writable data items + * in this store. + * + * This should include only non-const identifiers. + */ +const SG::auxid_set_t& +AuxStoreInternal::getWritableAuxIDs() const +{ + return getAuxIDs(); +} + + +/** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * @param quiet If true, then don't print an error on failure. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ +const void* AuxStoreInternal::getIODataInternal (auxid_t auxid, bool quiet) const +{ + guard_t guard (m_mutex); + if (auxid >= m_vecs.size() || !m_vecs[auxid]) { + if (!quiet) { + std::ostringstream ss; + ss << "Requested variable " + << SG::AuxTypeRegistry::instance().getName (auxid) + << " (" << auxid << ") doesn't exist"; + ATHCONTAINERS_ERROR("AuxStoreInternal::getIODataInternal", ss.str()); + } + return 0; + } + + if (m_standalone) + return m_vecs[auxid]->toPtr(); + return m_vecs[auxid]->toVector(); +} + + +/** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ +const void* AuxStoreInternal::getIOData (auxid_t auxid) const +{ + return getIODataInternal (auxid, false); +} + + +/** + * @brief Return the type of the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * For an aux data item of type @c T, this will usually be + * @c std::vector<T>. For standalone objects, however, it will + * usually be @c T; and @c std::vector<char> will be used instead + * of @c std::vector<bool>. + * + * Returns 0 if the requested aux data item does not exist. + */ +const std::type_info* AuxStoreInternal::getIOType (auxid_t auxid) const +{ + if (m_standalone) + return SG::AuxTypeRegistry::instance().getType (auxid); + guard_t guard (m_mutex); + if (auxid < m_vecs.size() && m_vecs[auxid]) { + const std::type_info* ret = m_vecs[auxid]->objType(); + if (ret) return ret; + } + return SG::AuxTypeRegistry::instance().getVecType (auxid); +} + + +/** + * @brief Get the list of all variables that need to be handled. + */ +const SG::auxid_set_t& +AuxStoreInternal::getDynamicAuxIDs() const +{ + return getAuxIDs(); +} + + +/** + * @brief Lock the container. + * + * After this, only decorations can be changed/modified. + * If the container is already locked, this is a no-op. + */ +void AuxStoreInternal::lock() +{ + guard_t guard (m_mutex); + m_locked = true; +} + + +/** + * @brief Clear all decorations. + * + * Erase all decorations from the store, restoring the state to when + * @c lock was called. Be sure to clear the cache of the referencing + * container! + */ +void AuxStoreInternal::clearDecorations() +{ + guard_t guard (m_mutex); + for (auxid_t id = 0; id < m_vecs.size(); id++) { + if (m_isDecoration[id]) { + m_isDecoration[id] = false; + delete m_vecs[id]; + m_vecs[id] = 0; + m_auxids.erase (id); + ++m_tick; + } + } +} + + +/** + * @brief Return the number of elements in the store. + * + * May return 0 for a store with no aux data. + */ +size_t AuxStoreInternal::size() const +{ + guard_t guard (m_mutex); + return size_noLock(); +} + + +/** + * @brief Return the number of elements in the store. (No locking.) + * + * May return 0 for a store with no aux data. + */ +size_t AuxStoreInternal::size_noLock() const +{ + for (SG::auxid_t id : m_auxids) { + if (id < m_vecs.size() && m_vecs[id] && m_vecs[id]->size() > 0) + return m_vecs[id]->size(); + } + return 0; +} + + +/** + * @brief Set an option for an auxiliary data variable. + * @param id The variable for which we want to set the option. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +bool AuxStoreInternal::setOption (auxid_t id, const AuxDataOption& option) +{ + // Does this variable exist in this store? + bool exists = false; + { + guard_t guard (m_mutex); + if (id < m_vecs.size() && m_vecs[id] != 0) + exists = true; + } + + // If not, and we have a packing parameter request, then create the variable. + if (!exists) { + if (!PackedParameters::isValidOption (option)) return false; + size_t sz = size(); + getDataInternal (id, sz, sz, true); + } + + // Try the option setting. + guard_t guard (m_mutex); + if (m_vecs[id]->setOption (option)) return true; + + // It didn't work. If this is a packing request, then try to convert + // the variable to packed form and retry. + if (!PackedParameters::isValidOption (option)) return false; + IAuxTypeVector* packed = m_vecs[id]->toPacked(); + if (packed) { + // Converted to packed form. Replace the object and retry. + delete m_vecs[id]; + m_vecs[id] = packed; + return packed->setOption (option); + } + + // Didn't work. + return false; +} + + +/** + * @brief Add a new auxid to the set of those being managed by this store. + * @param auxid The auxid to add. + */ +void AuxStoreInternal::addAuxID (auxid_t auxid) +{ + m_auxids.insert (auxid); + ++m_tick; +} + + +/// Implementation of getDataInternal; no locking. +void* AuxStoreInternal::getDataInternal_noLock (auxid_t auxid, + size_t size, + size_t capacity, + bool no_lock_check) +{ + if (m_vecs.size() <= auxid) { + m_vecs.resize (auxid+1); + m_isDecoration.resize (auxid+1); + } + if (m_vecs[auxid] == 0) { + if (m_locked && !no_lock_check) + throw ExcStoreLocked (auxid); + m_vecs[auxid] = AuxTypeRegistry::instance().makeVector (auxid, size, capacity); + addAuxID (auxid); + } + else { + // Make sure the vector has at least the requested size. + // One way in which it could be short: setOption was called and created + // a variable in a store that had no other variables. + if (m_vecs[auxid]->size() < size) { + m_vecs[auxid]->resize (size); + m_vecs[auxid]->reserve (capacity); + } + } + return m_vecs[auxid]->toPtr(); +} + + +/** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * @param no_lock_check If true, then skip the test for a locked container. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + */ +void* AuxStoreInternal::getDataInternal (auxid_t auxid, + size_t size, + size_t capacity, + bool no_lock_check) +{ + guard_t guard (m_mutex); + if (m_vecs.size() <= auxid) { + m_vecs.resize (auxid+1); + m_isDecoration.resize (auxid+1); + } + if (m_vecs[auxid] == 0) { + if (m_locked && !no_lock_check) + throw ExcStoreLocked (auxid); + m_vecs[auxid] = AuxTypeRegistry::instance().makeVector (auxid, size, capacity); + addAuxID (auxid); + } + else { + // Make sure the vector has at least the requested size. + // One way in which it could be short: setOption was called and created + // a variable in a store that had no other variables. + if (m_vecs[auxid]->size() < size) { + m_vecs[auxid]->resize (size); + m_vecs[auxid]->reserve (capacity); + } + } + return m_vecs[auxid]->toPtr(); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/AuxStoreStandalone.cxx b/EDM/athena/Control/AthContainers/Root/AuxStoreStandalone.cxx new file mode 100644 index 00000000..fc62577e --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/AuxStoreStandalone.cxx @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/src/AuxStoreStandalone.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Auxiliary data store for standalone objects. + */ + + +#include "AthContainers/AuxStoreStandalone.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/error.h" +#include <sstream> + + +namespace SG { + + +/** + * @brief Constructor. + */ +AuxStoreStandalone::AuxStoreStandalone() + : AuxStoreInternal (true) +{ +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/AuxTypeRegistry.cxx b/EDM/athena/Control/AthContainers/Root/AuxTypeRegistry.cxx new file mode 100644 index 00000000..01a6ffe7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/AuxTypeRegistry.cxx @@ -0,0 +1,823 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/AuxTypeRegistry.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Handle mappings between names and auxid_t. + */ + + +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/normalizedTypeinfoName.h" +#include "AthContainers/tools/foreach.h" +#include "AthLinks/ElementLinkBase.h" +#include <cassert> +#include <sstream> +#include <cstring> + + +namespace SG { + + +/** + * @brief Return the singleton registry instance. + */ +AuxTypeRegistry& AuxTypeRegistry::instance() +{ + static AuxTypeRegistry auxTypeRegistry; + return auxTypeRegistry; +} + + +/** + * @brief Look up a name -> @c auxid_t mapping. + * @param ti Type of the aux data item. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * + * The type of the item is given by @a ti. + * Return @c null_auxid if we don't know how to make vectors of @a ti. + * (Use @c addFactory to register additional types.) + * If an item with the same name was previously requested + * with a different type, then raise @c SG::ExcAuxTypeMismatch. + */ +SG::auxid_t AuxTypeRegistry::getAuxID (const std::type_info& ti, + const std::string& name, + const std::string& clsname /*= ""*/) +{ + return findAuxID (name, clsname, ti, &AuxTypeRegistry::makeFactoryNull); +} + + +/** + * @brief Look up a name -> @c auxid_t mapping. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * + * Will only find an existing @c auxid_t; unlike @c getAuxID, + * this won't make a new one. If the item isn't found, this + * returns @c null_auxid. + */ +SG::auxid_t +AuxTypeRegistry::findAuxID( const std::string& name, + const std::string& clsname ) const +{ + upgrading_lock_t lock (const_cast<mutex_t&>(m_mutex)); + key_t key (name, clsname); + id_map_t::const_iterator i = m_auxids.find (key); + if (i != m_auxids.end()) { + return i->second; + } + return null_auxid; +} + + +/** + * @brief Construct a new vector to hold an aux item. + * @param auxid The desired aux data item. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ +IAuxTypeVector* AuxTypeRegistry::makeVector (SG::auxid_t auxid, + size_t size, + size_t capacity) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + assert (factory != 0); + return factory->create (size, capacity); +} + + +/** + * @brief Construct a new vector to hold an aux item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ +IAuxTypeVector* AuxTypeRegistry::makeVector (lock_t& lock, + SG::auxid_t auxid, + size_t size, + size_t capacity) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + assert (factory != 0); + return factory->create (size, capacity); +} + + +/** + * @brief Construct an @c IAuxTypeVector object from a vector. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * But if @c isPacked is @c true, then @c data + * should instead point at an object of type @c SG::PackedContainer<T>. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ +IAuxTypeVector* AuxTypeRegistry::makeVectorFromData (SG::auxid_t auxid, + void* data, + bool isPacked, + bool ownMode) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + assert (factory != 0); + return factory->createFromData (data, isPacked, ownMode); +} + + + +/** + * @brief Return the name of an aux data item. + * @param auxid The desired aux data item. + */ +std::string AuxTypeRegistry::getName (SG::auxid_t auxid) const +{ + lock_t lock (*this); + return getName (lock, auxid); +} + + +/** + * @brief Return the name of an aux data item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ +std::string AuxTypeRegistry::getName (lock_t& /*lock*/, + SG::auxid_t auxid) const +{ + if (auxid >= m_types.size()) + return ""; + return m_types[auxid].m_name; +} + + +/** + * @brief Return the class name associated with an aux data item + * (may be blank). + * @param auxid The desired aux data item. + */ +std::string AuxTypeRegistry::getClassName (SG::auxid_t auxid) const +{ + lock_t lock(*this); + return getClassName (lock, auxid); +} + + +/** + * @brief Return the class name associated with an aux data item + * (may be blank). [external locking] + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ +std::string AuxTypeRegistry::getClassName (lock_t& /*lock*/, + SG::auxid_t auxid) const +{ + if (auxid >= m_types.size()) + return ""; + return m_types[auxid].m_clsname; +} + + +/** + * @brief Return the type of an aux data item. + * @param auxid The desired aux data item. + */ +const std::type_info* AuxTypeRegistry::getType (SG::auxid_t auxid) const +{ + lock_t lock (*this); + return getType (lock, auxid); +} + + +/** + * @brief Return the type of an aux data item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ +const std::type_info* AuxTypeRegistry::getType (lock_t& /*lock*/, + SG::auxid_t auxid) const +{ + if (auxid >= m_types.size()) + return 0; + return m_types[auxid].m_ti; +} + + +/** + * @brief Return the type name of an aux data item. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ +std::string AuxTypeRegistry::getTypeName (SG::auxid_t auxid) const +{ + lock_t lock (*this); + return getTypeName (lock, auxid); +} + + +/** + * @brief Return the type name of an aux data item (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ +std::string AuxTypeRegistry::getTypeName (lock_t& /*lock*/, + SG::auxid_t auxid) const +{ + if (auxid >= m_types.size()) + return ""; + return normalizedTypeinfoName (*m_types[auxid].m_ti); +} + + +/** + * @brief Return the type of the STL vector used to hold an aux data item. + * @param auxid The desired aux data item. + */ +const std::type_info* AuxTypeRegistry::getVecType (SG::auxid_t auxid) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) + return factory->tiVec(); + return 0; +} + + +/** + * @brief Return the type of the STL vector used to hold an aux data item. + * (external locking) + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ +const std::type_info* AuxTypeRegistry::getVecType (lock_t& lock, + SG::auxid_t auxid) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) + return factory->tiVec(); + return 0; +} + + +/** + * @brief Return the type name of the STL vector used to hold an aux data item. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ +std::string AuxTypeRegistry::getVecTypeName (SG::auxid_t auxid) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) + return normalizedTypeinfoName (*factory->tiVec()); + return ""; +} + + +/** + * @brief Return the type name of the STL vector used to hold an aux data item. + * (external locking) + * @param lock The registry lock. + * @param auxid The desired aux data item. + * + * Returns an empty string if the type is not known. + */ +std::string AuxTypeRegistry::getVecTypeName (lock_t& lock, + SG::auxid_t auxid) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) + return normalizedTypeinfoName (*factory->tiVec()); + return ""; +} + + +/** + * @brief Return size of an element in the STL vector. + * @param auxid The desired aux data item. + */ +size_t AuxTypeRegistry::getEltSize (SG::auxid_t auxid) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) + return factory->getEltSize(); + return 0; +} + + +/** + * @brief Return size of an element in the STL vector + * (external locking). + * @param lock The registry lock. + * @param auxid The desired aux data item. + */ +size_t AuxTypeRegistry::getEltSize (lock_t& lock, + SG::auxid_t auxid) const +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) + return factory->getEltSize(); + return 0; +} + + +/** + * @brief Copy an element between vectors. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +void AuxTypeRegistry::copy (SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) + factory->copy (dst, dst_index, src, src_index); +} + + +/** + * @brief Copy an element between vectors (external locking). + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +void AuxTypeRegistry::copy (lock_t& lock, + SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) + factory->copy (dst, dst_index, src, src_index); +} + + +/** + * @brief Copy an element between vectors. + * Apply any transformations needed for output. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +void AuxTypeRegistry::copyForOutput (SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) { + factory->copy (dst, dst_index, src, src_index); + + // It would be cleaner, safer, and more flexible to add a new factory + // interface for this. But that would require a full rebuild, + // which we want to avoid at this point. + upgrading_lock_t lock (m_mutex); + if (m_isEL[auxid]) applyELThinning (reinterpret_cast<char*>(dst) + dst_index * factory->getEltSize()); + if (m_isELVec[auxid]) applyELVecThinning (reinterpret_cast<char*>(dst) + dst_index * factory->getEltSize()); + } +} + + +/** + * @brief Copy an element between vectors (external locking). + * Apply any transformations needed for output. + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +void AuxTypeRegistry::copyForOutput (lock_t& lock, + SG::auxid_t auxid, + void* dst, size_t dst_index, + const void* src, size_t src_index) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) { + factory->copy (dst, dst_index, src, src_index); + + // It would be cleaner, safer, and more flexible to add a new factory + // interface for this. But that would require a full rebuild, + // which we want to avoid at this point. + if (m_isEL[auxid]) applyELThinning (reinterpret_cast<char*>(dst) + dst_index * factory->getEltSize()); + if (m_isELVec[auxid]) applyELVecThinning (reinterpret_cast<char*>(dst) + dst_index * factory->getEltSize()); + } +} + + +/** + * @brief Swap an element between vectors. + * @param auxid The aux data item being operated on. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ +void AuxTypeRegistry::swap (SG::auxid_t auxid, + void* a, size_t aindex, + void* b, size_t bindex) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) + factory->swap (a, aindex, b, bindex); +} + + +/** + * @brief Swap an element between vectors (external locking). + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ +void AuxTypeRegistry::swap (lock_t& lock, + SG::auxid_t auxid, + void* a, size_t aindex, + void* b, size_t bindex) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) + factory->swap (a, aindex, b, bindex); +} + + +/** + * @brief Clear an element within a vector. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ +void AuxTypeRegistry::clear (SG::auxid_t auxid, void* dst, size_t dst_index) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (auxid); + if (factory) + factory->clear (dst, dst_index); +} + + +/** + * @brief Clear an element within a vector (external locking). + * @param lock The registry lock. + * @param auxid The aux data item being operated on. + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ +void AuxTypeRegistry::clear (lock_t& lock, + SG::auxid_t auxid, void* dst, size_t dst_index) +{ + const SG::IAuxTypeVectorFactory* factory = getFactory (lock, auxid); + if (factory) + factory->clear (dst, dst_index); +} + + +/** + * @brief Return the vector factory for a given vector element type. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ +const IAuxTypeVectorFactory* +AuxTypeRegistry::getFactory (const std::type_info& ti) const +{ + lock_t lock (*this); + return getFactory (lock, ti); +} + + +/** + * @brief Return the vector factory for a given vector element type. + * (external locking) + * @param lock The registry lock. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ +const IAuxTypeVectorFactory* +AuxTypeRegistry::getFactory (lock_t& /*lock*/, + const std::type_info& ti) const +{ + return getFactoryLocked (ti); +} + + +/** + * @brief Return the vector factory for a given vector element type. + * (external locking) + * @param lock The registry lock. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ +const IAuxTypeVectorFactory* +AuxTypeRegistry::getFactory (upgrading_lock_t& /*lock*/, + const std::type_info& ti) const +{ + return getFactoryLocked (ti); +} + + +/** + * @brief Add a new type -> factory mapping. + * @param ti Type of the vector element. + * @param factory The factory instance. The registry will take ownership. + * + * This records that @c factory can be used to construct vectors with + * an element type of @c ti. If a mapping already exists, the new + * factory is discarded, unless the old one is a dynamic factory and + * the new one isn't, in which case the new replaces the old one. + */ +void AuxTypeRegistry::addFactory (const std::type_info& ti, + IAuxTypeVectorFactory* factory) +{ + upgrading_lock_t lock (m_mutex); + return addFactory (lock, ti, factory); +} + + +/** + * @brief Add a new type -> factory mapping. (external locking) + * @param lock The registry lock. + * @param ti Type of the vector element. + * @param factory The factory instance. The registry will take ownership. + * + * This records that @c factory can be used to construct vectors with + * an element type of @c ti. If a mapping already exists, the new + * factory is discarded, unless the old one is a dynamic factory and + * the new one isn't, in which case the new replaces the old one. + */ +void AuxTypeRegistry::addFactory (upgrading_lock_t& lock, + const std::type_info& ti, + IAuxTypeVectorFactory* factory) +{ + lock.upgrade(); + + ti_map_t::iterator it = m_factories.find (&ti); + if (it != m_factories.end()) { + if (it->second->isDynamic() && !factory->isDynamic()) { + // Replacing a dynamic factory with a non-dynamic one. + // But don't delete the old one, since it might still be referenced. + // Instead, push it on a vector to remember it so we can delete + // it later. + m_oldFactories.push_back (it->second); + it->second = factory; + } + else + delete factory; + } + else + m_factories[&ti] = factory; +} + + +/** + * @brief Constructor. + * + * Populates the type -> factory mappings for standard C++ types. + */ +AuxTypeRegistry::AuxTypeRegistry() +{ + // Make sure we have factories registered for common C++ types. +#define ADD_FACTORY(T) addFactory(typeid(T), new AuxTypeVectorFactory<T>) + ADD_FACTORY (bool); + ADD_FACTORY (char); + ADD_FACTORY (unsigned char); + ADD_FACTORY (short); + ADD_FACTORY (unsigned short); + ADD_FACTORY (int); + ADD_FACTORY (unsigned int); + ADD_FACTORY (long); + ADD_FACTORY (unsigned long); + ADD_FACTORY (long long); + ADD_FACTORY (unsigned long long); + ADD_FACTORY (float); + ADD_FACTORY (double); + ADD_FACTORY (std::string); + + ADD_FACTORY (std::vector<char>); + ADD_FACTORY (std::vector<unsigned char>); + ADD_FACTORY (std::vector<int>); + ADD_FACTORY (std::vector<unsigned int>); + ADD_FACTORY (std::vector<float>); + ADD_FACTORY (std::vector<double>); +#undef ADD_FACTORY +} + + +/** + * @brief Destructor. + * + * Delete factory instances. + */ +AuxTypeRegistry::~AuxTypeRegistry() +{ + ATHCONTAINERS_FOREACH (ti_map_t::value_type& p, m_factories) + delete p.second; + ATHCONTAINERS_FOREACH (const IAuxTypeVectorFactory* p, m_oldFactories) + delete p; +} + + +/** + * @brief Look up a name -> @c auxid_t mapping. + * @param name The name of the aux data item. + * @param clsname The name of its associated class. May be blank. + * @param ti The type of this aux data item. + * @param makeFactory Function to create a factory for this type, if needed. + * May return 0 if the type is unknown. + * + * + * If the aux data item already exists, check to see if the provided + * type matches the type that was used before. If so, then set + * return the auxid; otherwise, raise @c SG::ExcAuxTypeMismatch. + * + * If the aux data item does not already exist, then see if we + * have a factory registered for this @c type_info. If not, then + * call @c makeFactory and use what it returns. If that returns 0, + * then fail and return null_auxid. Otherwise, assign a new auxid + * and return it. + */ +SG::auxid_t +AuxTypeRegistry::findAuxID (const std::string& name, + const std::string& clsname, + const std::type_info& ti, + IAuxTypeVectorFactory* (AuxTypeRegistry::*makeFactory) () const) +{ + upgrading_lock_t lock (m_mutex); + key_t key (name, clsname); + id_map_t::iterator i = m_auxids.find (key); + if (i != m_auxids.end()) { + typeinfo_t& m = m_types[i->second]; + + // By all rights, these two tests should be redundant. + // However, there are cases where we see distinct @c type_info objects + // for the same type. This is usually associated with dictionaries + // being loaded `too early,' during python configuration processing. + // It's a C++ standard violation for this to ever happen, but it's + // not clear that it's feasible to actually eliminate the possibility + // of this happening. So if the @c type_info instances differ, + // we still accept the match as long as the names are the same. + if (&ti == m.m_ti || strcmp(ti.name(), m.m_ti->name()) == 0) { + // Try to upgrade a dynamic factory. + if (m.m_factory->isDynamic()) { + lock.upgrade(); + IAuxTypeVectorFactory* fac2 = (*this.*makeFactory)(); + if (fac2) { + addFactory (lock, ti, fac2); + m.m_factory = getFactory (lock, ti); + } + } + return i->second; + } + if( *m.m_ti != typeid(SG::AuxTypePlaceholder) ) { + throw SG::ExcAuxTypeMismatch (i->second, ti, *m.m_ti); + } + // fall through, get a new auxid and real type info + // new auxid needed so a new data vector is created in the AuxStore + } + lock.upgrade(); + const IAuxTypeVectorFactory* fac = getFactory (lock, ti); + if (!fac || fac->isDynamic()) { + IAuxTypeVectorFactory* fac2 = (*this.*makeFactory)(); + if (fac2) { + addFactory (lock, ti, fac2); + fac = getFactory (lock, ti); + } + } + if (!fac) return null_auxid; + SG::auxid_t auxid = m_types.size(); + m_types.resize (auxid+1); + m_auxids[key] = auxid; + typeinfo_t& t = m_types[auxid]; + t.m_name = name; + t.m_clsname = clsname; + t.m_ti = &ti; + t.m_factory = fac; + + setELFlags (lock, auxid); + return auxid; +} + + +/** + * @brief Return the vector factory for a given vector element type. + * The registry lock must be held. + * @param ti The type of the vector element. + * + * Returns 0 if the type is not known. + * (Use @c addFactory to add new mappings.) + */ +const IAuxTypeVectorFactory* +AuxTypeRegistry::getFactoryLocked (const std::type_info& ti) const +{ + ti_map_t::const_iterator it = m_factories.find (&ti); + if (it != m_factories.end()) + return it->second; + return 0; +} + + +/** + * @brief Initialize the m_isEL* flags for a given variable. + * @param auxid The variable for which the flags should be initialized. + * @param lock The registry lock (must be locked). + * + * ??? Should go away when we extend the factory interface. + */ +void AuxTypeRegistry::setELFlags (upgrading_lock_t& /*lock*/, auxid_t auxid) +{ + m_isEL.resize (auxid+1); + m_isELVec.resize (auxid+1); + std::string tname = normalizedTypeinfoName (*m_types[auxid].m_ti); + static std::string pat1 = "ElementLink<"; + static std::string pat2 = "std::vector<ElementLink<"; + if (tname.substr (0, pat1.size()) == pat1) + m_isEL[auxid] = true; + else if (tname.substr (0, pat2.size()) == pat2) + m_isELVec[auxid] = true; +} + + +/** + * @brief Apply @c ElementLink output transformations to a single element. + * @param dst Pointer to the element. + * + * ??? Should go away when we extend the factory interface. + */ +#ifdef XAOD_STANDALONE +void AuxTypeRegistry::applyELThinning (void*) +{ +} +#else +void AuxTypeRegistry::applyELThinning (void* dst) +{ + reinterpret_cast<ElementLinkBase*> (dst)->thin(); +} +#endif + + +/** + * @brief Apply @c ElementLink output transformations to a vector. + * @param dst Pointer to the vector. + * + * ??? Should go away when we extend the factory interface. + */ +#ifdef XAOD_STANDALONE +void AuxTypeRegistry::applyELVecThinning (void*) +{ +} +#else +void AuxTypeRegistry::applyELVecThinning (void* dst) +{ + std::vector<ElementLinkBase>& v = + *reinterpret_cast<std::vector<ElementLinkBase>* > (dst); + size_t sz = v.size(); + for (size_t i = 0; i < sz; i++) + v[i].thin(); +} +#endif + + +} // namespace SG + + diff --git a/EDM/athena/Control/AthContainers/Root/AuxVectorBase.cxx b/EDM/athena/Control/AthContainers/Root/AuxVectorBase.cxx new file mode 100644 index 00000000..e629ef44 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/AuxVectorBase.cxx @@ -0,0 +1,402 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/src/AuxVectorBase.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Manage index tracking and synchronization of auxiliary data. + */ + + +#include "AthContainers/AuxVectorBase.h" +#include "AthContainers/tools/foreach.h" + + +namespace SG { + + +/** + * @brief Default constructor. + * + * This will disable index tracking by default. + * The constructor should be followed by a call to @c initAuxVectorBase. + * (This is separated from the constructor because calling non-default + * constructors of @c DataVector base classes can be awkward in the case + * of virtual derivation.) + */ +AuxVectorBase::AuxVectorBase() + : m_trackIndices (false) +{ +} + + +#if __cplusplus > 201100 +/** + * @brief Move constructor. + * @param rhs The container from which to move. + */ +AuxVectorBase::AuxVectorBase (AuxVectorBase&& rhs) + : AuxVectorData (std::move (rhs)), + m_trackIndices (rhs.m_trackIndices) +{ +} + + +/** + * @brief Move assignment. + * @param rhs The container from which to move. + */ +AuxVectorBase& AuxVectorBase::operator= (AuxVectorBase&& rhs) +{ + if (this != &rhs) { + AuxVectorData::operator= (std::move (rhs)); + m_trackIndices = rhs.m_trackIndices; + } + return *this; +} +#endif + + +/** + * @brief Destructor. + */ +AuxVectorBase::~AuxVectorBase() +{ +} + + +/** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + * + * It is an error to set a store for a container for which index tracking + * is disabled. That will raise an @c ExcUntrackedSetStore exception. + */ +void AuxVectorBase::setStore (const SG::IConstAuxStore* store) +{ + if (store && !m_trackIndices) + throw SG::ExcUntrackedSetStore(); + SG::AuxVectorData::setStore (store); +} + + +/** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will set both the const and non-const store pointers, and also + * clear the cache. + * + * It is an error to set a store for a container for which index tracking + * is disabled. That will raise an @c ExcUntrackedSetStore exception. + */ +void AuxVectorBase::setStore (SG::IAuxStore* store) +{ + if (store && !m_trackIndices) + throw SG::ExcUntrackedSetStore(); + SG::AuxVectorData::setStore (store); +} + + +/** + * @brief Set the store associated with this object. + * @param store The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + * + * It is an error to set a store for a container for which index tracking + * is disabled. That will raise an @c ExcUntrackedSetStore exception. + */ +void AuxVectorBase::setStore (const DataLink<SG::IConstAuxStore>& store) +{ + if (!m_trackIndices) + throw SG::ExcUntrackedSetStore(); + SG::AuxVectorData::setStore (store); +} + + +/** + * @brief Initialize index tracking mode --- no-auxdata specialization. + * @param ownPolicy The container ownership policy. + * @param indexTrackingPolicy The requested index tracking policy. + * + * Since this is the no-auxdata case, it always sets index tracking to false. + * An exception is raised if the container has an associated store + * (but that should never actually happen). + */ +void +AuxVectorBase::initAuxVectorBase1 (const SG_STD_OR_BOOST::false_type&, + SG::OwnershipPolicy /*ownPolicy*/, + SG::IndexTrackingPolicy /*indexTrackingPolicy*/) +{ + m_trackIndices = false; + if (this->hasStore()) + throw SG::ExcUntrackedSetStore(); +} + + +/** + * @brief Initialize index tracking mode --- auxdata specialization. + * @param ownPolicy The container ownership policy. + * @param indexTrackingPolicy The requested index tracking policy. + * + * Sets index tracking based on the requested policies. + * An exception is raised if index tracking is disabled and the container + * has an associated store. + */ +void +AuxVectorBase::initAuxVectorBase1 (const SG_STD_OR_BOOST::true_type&, + SG::OwnershipPolicy ownPolicy, + SG::IndexTrackingPolicy indexTrackingPolicy) +{ + if (indexTrackingPolicy == SG::ALWAYS_TRACK_INDICES) + m_trackIndices = true; + else if (indexTrackingPolicy == SG::NEVER_TRACK_INDICES) + m_trackIndices = false; + else if (ownPolicy == SG::OWN_ELEMENTS) + m_trackIndices = true; + else + m_trackIndices = false; + + if (!m_trackIndices && this->hasStore()) + throw SG::ExcUntrackedSetStore(); +} + + +/** + * @brief Resize the aux data associated with this container. + * @param size The new container size. + * + * The auxdata case. + */ +void AuxVectorBase::resize1 (const SG_STD_OR_BOOST::true_type&, size_t size) +{ + if (this->hasNonConstStore()) { + if (!this->getStore()->resize (size)) { + // Only clear the cache if iterators have been invalidated. + clearCache(); + } + } + else if (this->hasStore()) + throw SG::ExcConstAuxData ("resize"); +} + + +/** + * @brief Change the capacity of the aux data associated with this container. + * @param size The new container size. + * + * The auxdata case. + */ +void AuxVectorBase::reserve1 (const SG_STD_OR_BOOST::true_type&, size_t size) +{ + if (this->hasNonConstStore()) { + this->getStore()->reserve (size); + clearCache(); + } + else if (this->hasStore()) + throw SG::ExcConstAuxData ("reserve"); +} + + +/** + * @brief Set index on an element and copy auxiliary data. + * @param index Container index at which the new element is being added. + * @param p The new element being added. + * @param clear If true, then any auxiliary data initially associated + * with @c p are cleared after being copied. + * @param skipDestClear Normally, if @c p does not have auxiliary data, + * then the variables of the destination are cleared. + * If this flag is true, then this clear is skipped. + * This can be appropriate as part of a push_back, + * where the destiniation is already known to be clear. + * + * Element @c p is being added to the container at @c index. + * If @c p has associated auxiliary data, copy it to the container + * at @c index. Then set the container / index on @c p. + */ +void +AuxVectorBase::moveAux (size_t index, SG::AuxElement* p, + bool clear /*= false*/, + bool skipDestClear /*= false*/) +{ + if (!m_trackIndices) + return; + + SG::AuxElement to (this, index); + if (!p) { + if (!skipDestClear) to.clearAux(); + return; + } + + if (p->hasStore() || !skipDestClear) + to.copyAux (*p); + if (clear) + p->clearAux(); + p->setIndex (index, this); +} + + +/** + * @brief Swap indices and auxiliary data between two elements. + * @param aindex Index of the first element, in this container. + * @param bindex Index of the second element, in @c bcont. + * @param a Pointer to the first element. + * @param b Pointer to the second element. + * @param bcont Container holding the second element. + * (May be the same as this, but doesn't have to be.) + * + * Elements @c a at @c aindex in @c this and @c b at @c bindex in @c bcont + * are being swapped. Swap the index / container references between the + * elements and also swap the auxiliary data if it exists. + */ +void AuxVectorBase::swapElementsAux (size_t aindex, + size_t bindex, + SG::AuxElement* a, + SG::AuxElement* b, + AuxVectorBase* bcont) +{ + AuxVectorBase* acont = this; + + // If one of the elements is null, then this is just a @c moveAux. + if (!b) { + if (!a) return; + acont->moveAux (aindex, a, true); + return; + } + if (!a) { + bcont->moveAux (bindex, b, true); + return; + } + + // Reset indices. + if (b && bcont->trackIndices()) + b->setIndex (bindex, bcont); + if (a && acont->trackIndices()) + a->setIndex (aindex, acont); + + // Check stores. + if (!this->hasNonConstStore()) { + if (this->hasStore()) { + throw SG::ExcConstAuxData ("swapElementsAux"); + } + return; + } + + // Swap aux data. + + const SG::auxid_set_t& a_ids = acont->getAuxIDs(); + const SG::auxid_set_t& b_ids = bcont->getAuxIDs(); + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::AuxTypeRegistry::lock_t lock (r); + + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, a_ids) { + void* aptr = acont->getDataArray (auxid); + void* bptr = bcont->getDataArray (auxid); + r.swap (lock, auxid, aptr, aindex, bptr, bindex); + } + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, b_ids) { + if (a_ids.find (auxid) == a_ids.end()) { + void* aptr = acont->getDataArray (auxid); + void* bptr = bcont->getDataArray (auxid); + r.swap (lock, auxid, aptr, aindex, bptr, bindex); + } + } +} + + +/** + * @brief Set up for resorting. + * @param sz The number of elements in the resort range. + * @param index The index of the first element in the range in the container. + * @param vec The containing vector. + */ +AuxVectorBase::ResortAuxHelper::ResortAuxHelper (size_t sz, + size_t index, + AuxVectorBase& vec) + : m_vec (vec), + m_index (index), + m_imap (sz), + m_rmap (sz), + m_lock (SG::AuxTypeRegistry::instance()) +{ + for (size_t i = 0; i < sz; i++) + m_imap[i] = m_rmap[i] = i; + + const SG::auxid_set_t& auxid_set = vec.getAuxIDs(); + size_t naux = auxid_set.size(); + m_auxdata.reserve (naux); + m_auxids.reserve (naux); + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, auxid_set) { + m_auxdata.push_back (vec.getDataArrayForResort (auxid)); + m_auxids.push_back (auxid); + } +} + + +/** + * @param Resort one element. + * @param idx The index of the element within the range. + * @param elt The element. + */ +void +AuxVectorBase::ResortAuxHelper::resortElement (size_t idx, SG::AuxElement* elt) +{ + // V + // x: 9 8 7 6 5 0 1 2 3 4 + // m_index: 0 1 2 3 4 0 1 2 3 4 + // imap 9 8 7 6 5 4 3 2 1 0 + // rmap 9 8 7 6 5 4 3 2 1 0 + // aux 19 18 17 16 15 14 13 12 11 10 + // + // imap[i] tells in which slot the auxdata originally in slot + // i is currently located. + // rmap[i] gives the original location of the auxdata + // currently in slot i. + // + // each time through the loop, looking at index i: + // -- look at the index that was set. + // we want to move the aux data originally at + // auxindex=v[i]->index() here. + // -- that data is currently at slot ii1 = imap[auxindex] + // -- swap auxdata between slots i and ii1 + // -- swap rmap between slots i and ii1 + // -- swap imap entries rmap[i] and rmap[ii1] + // -- set v[i]->index() to index. + // but need to remember to take into account any offset between + // the beginning of the range we're given and the beginning + // of the container (i.e., index was nonzero on entry). + // + // ??? can this be made more efficient? do we need so much + // working storage??? xxx + + size_t index = m_index; + size_t auxindex = elt->index(); + ATHCONTAINERS_ASSERT (auxindex-index < m_imap.size()); + size_t ii1 = m_imap[auxindex-index]; + if (ii1 != idx) { + ATHCONTAINERS_ASSERT (ii1 > idx); + // swap between auxdata slots dx+index, ii1+index + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + size_t naux = m_auxids.size(); + for (size_t iid = 0; iid < naux; iid++) { + void* ptr = m_auxdata[iid]; + r.swap (m_lock, m_auxids[iid], ptr, idx+index, ptr, ii1+index); + } + std::swap (m_rmap[idx], m_rmap[ii1]); + std::swap (m_imap[m_rmap[idx]], m_imap[m_rmap[ii1]]); + } + + m_vec.setIndexForResort (elt, index+idx); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/AuxVectorData.cxx b/EDM/athena/Control/AthContainers/Root/AuxVectorData.cxx new file mode 100644 index 00000000..b9f24a8a --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/AuxVectorData.cxx @@ -0,0 +1,598 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/src/AuxVectorData.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Manage lookup of vectors of auxiliary data. + */ + + +#include "AthContainers/AuxVectorData.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/error.h" +#include <sstream> + + +namespace SG { + + +/// Minimum length to use for the cache vector. +size_t AuxVectorData::s_minCacheLen = 1024; + + +/// Empty auxid set, used for a return value when we have no associated store. +SG::auxid_set_t AuxVectorData::s_emptySet; + + +/** + * @brief Constructor. + */ +AuxVectorData::AuxVectorData() + : m_store(0), + m_constStore( 0 ) +{ +} + + +#if __cplusplus > 201100 +/** + * @brief Move constructor. + * @param rhs The container from which to move. + */ +AuxVectorData::AuxVectorData (AuxVectorData&& rhs) + : m_cache (std::move (rhs.m_cache)), + m_constCache (std::move (rhs.m_constCache)), + m_decorCache (std::move (rhs.m_decorCache)), + m_store (rhs.m_store), + m_constStore (rhs.m_constStore), + m_constStoreLink (std::move (rhs.m_constStoreLink)) +{ + rhs.m_store = 0; + rhs.m_constStore = 0; + rhs.m_constStoreLink.clear(); +} + + +/** + * @brief Move assignment. + * @param rhs The container from which to move. + */ +AuxVectorData& AuxVectorData::operator= (AuxVectorData&& rhs) +{ + if (this != &rhs) { + m_cache = std::move (rhs.m_cache); + m_constCache = std::move (rhs.m_constCache); + m_decorCache = std::move (rhs.m_decorCache); + m_store = rhs.m_store; + m_constStore = rhs.m_constStore; + m_constStoreLink = rhs.m_constStoreLink; + + rhs.m_store = 0; + rhs.m_constStore = 0; + rhs.m_constStoreLink.clear(); + } + return *this; +} +#endif + + +/** + * @brief Destructor. + */ +AuxVectorData::~AuxVectorData() +{ +} + + +/** + * @brief Set the store associated with this object. + * @param The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + */ +void AuxVectorData::setStore (const SG::IConstAuxStore* store) +{ + m_store = 0; + m_constStore = store; + m_constStoreLink.clear(); + clearCache(); +} + + +/** + * @brief Set the store associated with this object. + * @param The new store. + * + * This will set both the const and non-const store pointers, and also + * clear the cache. + */ +void AuxVectorData::setStore (SG::IAuxStore* store) +{ + m_store = store; + m_constStore = store; + m_constStoreLink.clear(); + clearCache(); +} + + +/** + * @brief Set the store associated with this object. + * @param The new store. + * + * This will clear the non-const store pointer, and also + * clear the cache. + */ +void AuxVectorData::setStore (const DataLink< SG::IConstAuxStore >& store) +{ + m_store = 0; + m_constStore = 0; + m_constStoreLink = store; + clearCache(); +} + + +/** + * @brief Set an option for an auxiliary data variable. + * @param id The variable for which we want to set the option. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +bool AuxVectorData::setOption (auxid_t id, const AuxDataOption& option) +{ + if (id == null_auxid) return false; + SG::IAuxStore* store = getStore(); + if (!store) return false; + return store->setOption (id, option); +} + + +/** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +bool AuxVectorData::setOption (const std::string& name, + const AuxDataOption& option) +{ + auxid_t id = SG::AuxTypeRegistry::instance().findAuxID (name); + return setOption (id, option); +} + + +/** + * @brief Set an option for an auxiliary data variable. + * @param name The name of the variable. + * @param clsname The name of the associated class. May be blank. + * @param option The option setting to make. + * + * The interpretation of @c option depends on the associated auxiliary store. + * See PackedParameters.h for option settings for writing packed data. + * Returns @c true on success, @c false otherwise. + */ +bool AuxVectorData::setOption (const std::string& name, + const std::string& clsname, + const AuxDataOption& option) +{ + auxid_t id = SG::AuxTypeRegistry::instance().findAuxID (name, clsname); + return setOption (id, option); +} + + +/** + * @brief Return a set of identifiers for existing data items + * in store associated with this object. + * + * This will include identifiers for all items, + * const and non-const. If no store is associated + * with this object, this will return an empty set. + */ +const SG::auxid_set_t& AuxVectorData::getAuxIDs() const +{ + if (getConstStore()) + return getConstStore()->getAuxIDs(); + return s_emptySet; +} + + +/** + * @brief Return a set of identifiers for writable data items + * in this store. + * + * This will include only non-const identifiers. + * If no store is associated + * with this object, this will return an empty set. + */ +const SG::auxid_set_t& AuxVectorData::getWritableAuxIDs() const +{ + if (m_store) + return m_store->getWritableAuxIDs(); + return s_emptySet; +} + + +/** + * @brief Out-of-line portion of isAvailable. + * @param id The variable to test. + */ +bool AuxVectorData::isAvailableOol (auxid_t id) const +{ + const SG::IConstAuxStore* store = getConstStore(); + if (!store) return false; + + // Don't rely on getAuxIDs() --- the store can lie. + // Explicitly try to fetch the data. + const void* ptr = store->getData (id); + if (ptr) { + m_constCache.store (id, const_cast<void*> (ptr)); + return true; + } + return false; +} + + +/** + * @brief Out-of-line portion of isAvailableWritable. + * @param id The variable to test. + */ +bool AuxVectorData::isAvailableWritableOol (auxid_t id) const +{ + const SG::IAuxStore* store = getStore(); + if (!store) return false; + const SG::auxid_set_t& ids = store->getWritableAuxIDs(); + return ( ids.find (id) != ids.end() ); +} + + +/** + * @brief Out-of-line portion of isAvailableWritableAsDecoration. + * @param id The variable to test. + */ +bool AuxVectorData::isAvailableWritableAsDecorationOol (auxid_t id) const +{ + if (!isAvailableOol (id)) return false; + + // Not nice, but not sure we can do otherwise without changing interfaces. + // I think the case of a caught exception should be rare. + try { + this->getDecorationArray (id); + } + catch (const SG::ExcStoreLocked&) { + return false; + } + return true; +} + + +/** + * @brief Out-of-line portion of data access. + * @param auxid aux data item being accessed. + * @param allowMissing If true, then return nullptr if the variable + * is missing rather than throwing an exception. + * + * When this function returns, the cache entry @c m_cache[auxid] + * will be valid. That entry is also returned. If there's an error, + * the function will throw an exception rather than returning. + */ +void* AuxVectorData::getDataOol (SG::auxid_t auxid, bool allowMissing) +{ + guard_t guard (m_mutex); + + // Fetch the pointer from the store, or raise an exception if we don't + // have a non-const store. + void* ptr = 0; + if (m_store) + ptr = m_store->getData (auxid, this->size_v(), this->capacity_v()); + else if (getConstStore()) + throw SG::ExcConstAuxData ("fetch item", auxid); + else + throw SG::ExcNoAuxStore (auxid); + + // Check that we got a good pointer back, otherwise throw. + if (ptr) { + m_cache.store (auxid, ptr); + + // Set the same entry in the other caches as well. + m_constCache.store (auxid, ptr); + m_decorCache.store (auxid, ptr); + } + else if (!allowMissing) + throw SG::ExcBadAuxVar (auxid); + + return ptr; +} + + +/** + * @brief Out-of-line portion of data access (const version). + * @param auxid aux data item being accessed. + * @param allowMissing If true, then return nullptr if the variable + * is missing rather than throwing an exception. + * + * When this function returns, the cache entry @c m_constCache[auxid] + * will be valid. That entry is also returned. If there's an error, + * the function will throw an exception rather than returning. + */ +const void* AuxVectorData::getDataOol (SG::auxid_t auxid, + bool allowMissing) const +{ + guard_t guard (m_mutex); + + // Fetch the pointer from the store, or raise an exception if we don't + // have a const store. + const void* ptr = 0; + if (getConstStore()) + ptr = getConstStore()->getData (auxid); + else + throw SG::ExcNoAuxStore (auxid); + + // Check that we got a good pointer back, otherwise throw. + if (ptr) + m_constCache.store (auxid, const_cast<void*>(ptr)); + else if (!allowMissing) + throw SG::ExcBadAuxVar (auxid); + + return ptr; +} + + +/** + * @brief Out-of-line portion of data access (decorator version). + * @param auxid aux data item being accessed. + * + * When this function returns, the cache entry @c m_cache[auxid] + * will be valid. That entry is also returned. If there's an error, + * the function will throw an exception rather than returning. + * + * The difference between @c getDecorationOol and @c getDataOol is that + * @c getDecorationOol takes a const container as input, but returns + * a non-const pointer. This will only succeed if either the + * container is not locked or the item was first accessed + * as a decoration. + */ +void* AuxVectorData::getDecorationOol (SG::auxid_t auxid) const +{ + guard_t guard (m_mutex); + + // Fetch the pointer from the store, or raise an exception if we don't + // have a non-const store. + void* ptr = 0; + if (m_store) + ptr = m_store->getDecoration (auxid, this->size_v(), this->capacity_v()); + else if (getConstStore()) { + // The whole point of decorations is to allow adding information to + // something that's otherwise const. So we have the const_cast here. + // The store object is responsible for determining whether the + // modification is really allowed or not. + IConstAuxStore* store = const_cast<IConstAuxStore*> (getConstStore()); + ptr = store->getDecoration (auxid, this->size_v(), this->capacity_v()); + } + else + throw SG::ExcNoAuxStore (auxid); + + // Check that we got a good pointer back, otherwise throw. + if (!ptr) + throw SG::ExcBadAuxVar (auxid); + + m_decorCache.store (auxid, ptr); + + // Set the same entry in the const cache as well. + m_constCache.store (auxid, ptr); + + return ptr; +} + + +/** + * @brief Cache manager constructor. + */ +AuxVectorData::Cache::Cache() + : m_cache(), + m_cache_len(0) +{ +} + + +#if __cplusplus > 201100 +/** + * @brief Cache manager move constructor. + * @param rhs The cache from which to copy. + */ +AuxVectorData::Cache::Cache (Cache&& rhs) + : m_cache_len (rhs.m_cache_len), + m_allcache (std::move (rhs.m_allcache)) +{ + m_cache[0] = rhs.m_cache[0]; + m_cache[1] = rhs.m_cache[1]; + rhs.m_cache[0] = 0; + rhs.m_cache[1] = 0; + rhs.m_cache_len = 0; +} + + +/** + * @brief Cache manager move assignment. + * @param rhs The cache from which to copy. + */ +AuxVectorData::Cache& AuxVectorData::Cache::operator= (Cache&& rhs) +{ + if (this != &rhs) { + clear(); + m_cache_len = rhs.m_cache_len; + m_allcache = std::move (rhs.m_allcache); + + m_cache[0] = rhs.m_cache[0]; + m_cache[1] = rhs.m_cache[1]; + rhs.m_cache[0] = 0; + rhs.m_cache[1] = 0; + rhs.m_cache_len = 0; + } + return *this; +} +#endif + + +/** + * @brief Cache manager destructor. + */ +AuxVectorData::Cache::~Cache() +{ + for (size_t i=0; i < m_allcache.size(); i++) delete [] m_allcache[i]; +} + + +/** + * @brief Swap this cache object with another. + * @param other The cache object with which to swap. + */ +void AuxVectorData::Cache::swap (Cache& other) +{ + m_allcache.swap (other.m_allcache); + std::swap (m_cache, other.m_cache); + std::swap (m_cache_len, other.m_cache_len); +} + + +/** + * @brief Clear the cache (and free any old cache vectors). + */ +void AuxVectorData::Cache::clear() +{ + if (m_cache_len > 0) { + if (m_allcache.size() > 1) { + for (size_t i=0; i < m_allcache.size()-1; i++) + delete [] m_allcache[i]; + m_allcache[0] = m_allcache.back(); + m_allcache.resize(1); +} + std::fill (m_cache[0], m_cache[0] + m_cache_len, static_cast<void*>(0)); + } +} + + +/** + * @brief Store a pointer for @c auxid in the cache. + * @param auxid The aux data item being stored. + * @param ptr Pointer to the start of the aux vector for @c auxid. + */ +void AuxVectorData::Cache::store (SG::auxid_t auxid, void* ptr) +{ + // We must be holding the container lock m_mutex to call this. + + if (auxid >= m_cache_len) { + // We need to expand the cache vector. Allocate a new one. + size_t newlen = + std::max (static_cast<SG::auxid_t>(AuxVectorData::s_minCacheLen), + (auxid+1)*3/2); + void** newcache = new void*[newlen]; + m_allcache.push_back (newcache); + void** oldcache = m_cache[0]; + + // Copy old vector to the new one and clear the remainder. + std::copy (oldcache, oldcache + m_cache_len, newcache); + std::fill (newcache + m_cache_len, newcache + newlen, + static_cast<void*>(0)); + + // Store so that other threads can see it. + // The stores to m_cache must happen before the store to m_cache_len; + // we use a fence to ensure this. + m_cache[0] = newcache; + m_cache[1] = newcache; + AthContainers_detail::fence_seq_cst(); + m_cache_len = newlen; + } + + // We have room in the cache vector now. Store the pointer. + m_cache[0][auxid] = ptr; +} + + +/** + * @brief Lock the container. + * + * After this, only decorations can be changed/modified. + * If the container is already locked, this is a no-op. + */ +void AuxVectorData::lock() +{ + if (m_store) { + m_store->lock(); + clearCache(); + } + + // No error if no store or no writable store. +} + + +/** + * @brief Clear all decorations. + * + * Erase all decorations from the store, restoring the state to when + * @c lock was called. + */ +void AuxVectorData::clearDecorations() const +{ + if (m_store) { + m_store->clearDecorations(); + m_cache.clear(); + m_constCache.clear(); + m_decorCache.clear(); + } + else if (getConstStore()) { + // The whole point of decorations is to allow adding information to + // something that's otherwise const. So we have the const_cast here. + // The store object is responsible for determining whether the + // modification is really allowed or not. + IConstAuxStore* store = const_cast<IConstAuxStore*> (getConstStore()); + store->clearDecorations(); + } + else + throw SG::ExcNoAuxStore ("lock"); +} + + +} // namespace SG + + +#ifndef XAOD_STANDALONE + + +/** + * @brief Propagate thinning. Called after applying thinning to @c in. + * @param in The object that was thinned. + * @param svc The thinning service (for convenience). + * @param filter Lists the elements to be kept. + * @param op How to merge results: AND or OR. + * + * This will be called whenever a request is made to thin a @c DataVector. + * + * Otherwise, we pass the thinning request on to the aux store, provided + * that it exists and is in the event store. + */ +StatusCode thinningHook (const SG::AuxVectorData* in, + IThinningSvc* svc, + const IThinningSvc::Filter_t& filter, + const IThinningSvc::Operator::Type op ) +{ + const SG::IConstAuxStore* store = in->getConstStore(); + if (store && svc->proxy (store)) + return svc->typelessFilter (store, filter, op); + return StatusCode::SUCCESS; +} + + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/Root/CompareAndPrint.cxx b/EDM/athena/Control/AthContainers/Root/CompareAndPrint.cxx new file mode 100644 index 00000000..b9f8fbbc --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/CompareAndPrint.cxx @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: CompareAndPrint.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthContainers/src/CompareAndPrint.cxx + * @author scott snyder, Paolo Calafiura, etc + * @date May 2005; rewritten from earlier version. + * @brief helper class for remove_duplicates + * Out-of-line implementations. + */ + +#include "AthContainers/tools/CompareAndPrint.h" +#include "AthContainers/tools/error.h" +#include <iostream> + + +namespace DataModel_detail { + +/** + * @brief Duplicate elements were found; print a warning. + * @param ti @c type_info for the element. + * @param f The element pointer. + */ +void CompareAndPrint::warn (const std::type_info& ti, const void* f) const +{ + std::cout << "DataVector ERROR: duplicated pointer found in a DataVector of " + << AthContainers_detail::typeinfoName(ti) + << " owning its elements! " + << std::hex << f << std::dec << std::endl; +} + +} // namespace DataModel_detail diff --git a/EDM/athena/Control/AthContainers/Root/DVLInfo.cxx b/EDM/athena/Control/AthContainers/Root/DVLInfo.cxx new file mode 100644 index 00000000..33dfbda3 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/DVLInfo.cxx @@ -0,0 +1,125 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLInfo.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthContainers/src/DVLInfo.cxx + * @author scott snyder + * @date Mar, 2008 + * @brief Holder to implement conversion copies for @c DataVector/@c DataList. + * + * Out-of-line implementations. + */ + + +#include "AthContainers/tools/DVLInfo.h" +#ifndef XAOD_STANDALONE +#include "SGTools/CLIDRegistry.h" +#endif +#include <typeinfo> +#include <string> +#include <memory> + + +#if __cplusplus > 201100 +# include <unordered_map> +namespace SG_STD_OR_SG = std; +#else +# include "CxxUtils/unordered_map.h" +namespace SG_STD_OR_SG = SG; +#endif + + + +namespace DataModel_detail { + + +/// Maps from tinfo pointers and CLID to @c DVLInfo instances. +/// Note that we don't rely on static initialization here, +/// to avoid initialization ordering problems. +typedef SG_STD_OR_SG::unordered_map<const std::type_info*, DVLInfoBase*> + dvl_tinfo_map_t; +dvl_tinfo_map_t* s_dvl_tinfo_map = 0; + +struct dvlmapdel { + ~dvlmapdel() { delete s_dvl_tinfo_map; } +} s_dvlmapdel; + + + + +/** + * @brief Constructor. + * @param tinfo Type info object for the container being described. + * @param elt_tinfo Type info object for the element type of the container + * being described (with pointer and const's stripped.) + * + * Note: these objects should only be allocated statically. + */ +DVLInfoBase::DVLInfoBase (const std::type_info& tinfo, + const std::type_info& elt_tinfo) + : m_tinfo (tinfo), + m_elt_tinfo (elt_tinfo) +{ + if (s_dvl_tinfo_map == 0) + s_dvl_tinfo_map = new dvl_tinfo_map_t; + (*s_dvl_tinfo_map)[&tinfo] = this; +} + + +/** + * @brief Find the @c DVLInfo for the container @a tinfo. + * @param tinfo @c type_info of the desired container. + * @returns Pointer to the @c DVLInfo, or 0 if not found. + */ +DVLInfoBase* DVLInfoBase::find (const std::type_info& tinfo) +{ + if (!s_dvl_tinfo_map) + return 0; + dvl_tinfo_map_t::iterator i = s_dvl_tinfo_map->find (&tinfo); + if (i != s_dvl_tinfo_map->end()) + return i->second; + return 0; +} + + +#ifdef XAOD_STANDALONE +DVLInfoBase* DVLInfoBase::find (CLID /*clid*/) +{ + return 0; +} + +CLID DVLInfoBase::clid() const +{ + return CLID_NULL; +} +#else +/** + * @brief Find the @c DVLInfo for the container @a tinfo. + * @param clid @c CLID of the desired container. + * @param tinfo @c type_info of the desired container. + * @returns Pointer to the @c DVLInfo, or 0 if not found. + */ +DVLInfoBase* DVLInfoBase::find (CLID clid) +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return DVLInfoBase::find (*ti); + return 0; +} + + +/** + * @brief Return the CLID for the container. + */ +CLID DVLInfoBase::clid() const +{ + return CLIDRegistry::typeinfoToCLID (m_tinfo); +} +#endif + + +} // namespace DataModel_detail diff --git a/EDM/athena/Control/AthContainers/Root/PackedConverter.cxx b/EDM/athena/Control/AthContainers/Root/PackedConverter.cxx new file mode 100644 index 00000000..6dda03d1 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/PackedConverter.cxx @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedConverter.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper for packing/unpacking a @c PackedContainer to/from a stream. + */ + + +#include "AthContainers/PackedConverter.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param parms The parameters describing the packed data. + */ +PackedConverter::PackedConverter (const PackedParameters& parms) + : m_parms (parms), + m_packer (parms.nbits(), + parms.nmantissa() + (parms.isSigned()?1:0), + parms.scale(), + parms.isSigned(), + parms.rounding()) +{ +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/PackedParameters.cxx b/EDM/athena/Control/AthContainers/Root/PackedParameters.cxx new file mode 100644 index 00000000..9da1116e --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/PackedParameters.cxx @@ -0,0 +1,246 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/PackedParameters.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Describe how the contents of a @c PackedContainer are to be saved. + */ + + +#include "AthContainers/PackedParameters.h" + + +namespace SG { + + +/** + * @brief Default constructor. + * + * Set up to write unsigned integers with 32 bits. + */ +PackedParameters::PackedParameters() + : m_nbits(8 * sizeof(uint32_t)), + m_nmantissa(23), + m_scale(0), + m_flags(0) +{ +} + + +/** + * @brief Constructor from nbits and flags. + * @param nbits The number of bits for each element. + * @param flags Extra flags describing the packing. + * + * Additionally nmantissa is set to correspond to a fixed-point + * representation and the scale is cleared. + * + * This is meant to be used by the read converter. + */ +PackedParameters::PackedParameters (uint8_t nbits, uint8_t flags) + : m_nbits(nbits), + m_flags(flags) +{ + m_nmantissa = nbits; + if (isSigned() && m_nmantissa > 0) --m_nmantissa; + if (hasScale()) + m_scale = 1; + else + m_scale = 0; +} + + +/** + * @brief Set the number of bits to be used for each element. + * @brief nbits The desired number of bits. + * + * @c nbits must be in the range 1-32 for unsigned numbers, + * 2-32 for signed numbers. + * + * If necessary, @c nmantissa will be adjusted so that it still fits + * within the requested number of bits. + * + * Returns true if successful, false otherwise. + */ +bool PackedParameters::setNbits (uint8_t nbits) +{ + if (nbits <= 0 || nbits > 32) return false; + uint8_t navail = nbits; + if (isSigned()) --navail; + if (navail == 0) return false; + m_nbits = nbits; + if (m_nmantissa > navail) + m_nmantissa = navail; + return true; +} + + +/** + * @brief Set the number of mantissa bits used in the packed representation. + * @brief nmantissa The desired number of mantissa bits. + * + * This has an effect only when saving floating-point types. + * + * @c nmantissa must fit within the requested number of bits. + * @c nmantissa does not include the sign bit. + * If there are at least two bits left over, then numbers will be + * saved in a floating-point format; otherwise, fixed point will be used. + * + * Returns true if successful, false otherwise. + */ +bool PackedParameters::setNmantissa (uint8_t nmantissa) +{ + uint8_t navail = m_nbits; + if (isSigned()) --navail; + if (nmantissa <= 0 || nmantissa > navail) return false; + m_nmantissa = nmantissa; + return true; +} + + +/** + * @brief Set the scale to use when packing floating-point data. + * @param scale The new scale, or 0 to disable. + * + * This has an effect only when saving floating-point types. + * + * If set to something non-zero, then floating-point numbers + * will be divided by this value before being written. + * + * Returns true to indicate success. + */ +bool PackedParameters::setScale (float scale) +{ + m_scale = scale; + if (m_scale == 0 || m_scale == 1) + m_flags &= ~FLAG_HAS_SCALE; + else + m_flags |= FLAG_HAS_SCALE; + return true; +} + + +/** + * @brief Set the signedness flag for the packed representation. + * @param flag Should elements be saved as signed numbers? + * + * If the flag is false (unsigned), this always succeeds. + * If the flag is true (signed), then this fails if @c nbits is 1. + * @c nmantissa will be adjusted if there are now insufficient + * bits for it. + * + * Returns true if successful, false otherwise. + */ +bool PackedParameters::setSigned (bool flag) +{ + if (!flag) { + m_flags &= ~FLAG_IS_SIGNED; + return true; + } + + if (m_nbits == 1) return false; + if (m_nmantissa + 1 > m_nbits) + m_nmantissa = m_nbits - 1; + m_flags |= FLAG_IS_SIGNED; + return true; +} + + +/** + * @brief Set the rounding mode. + * @param flag Should numbers be rounded when being written? + * + * This has an effect only when saving floating-point types. + * + * Returns true to indicate success. + */ +bool PackedParameters::setRounding (bool flag) +{ + if (flag) + m_flags |= FLAG_ROUNDING; + else + m_flags &= ~FLAG_ROUNDING; + return true; +} + + +/** + * @brief Set the floating-point flag. + * @param flag Should numbers be written as floating-point? + * + * If true, numbers will be written in a floating/fixed point + * representation; otherwise, they will be written as integers. + * + * Returns true to indicate success. + */ +bool PackedParameters::setFloat (bool flag) +{ + if (flag) + m_flags |= FLAG_IS_FLOAT; + else + m_flags &= ~FLAG_IS_FLOAT; + return true; +} + + +/** + * @brief Test to see if @c option is a recognized packing option. + * @param option The option to test. + * + * Returns @c true if the name of @c option is recognized as a valid + * packing option; @c false otherwise. + */ +bool PackedParameters::isValidOption (const AuxDataOption& option) +{ + if (option.name() == "nbits" || + option.name() == "nmantissa" || + option.name() == "scale" || + option.name() == "signed" || + option.name() == "rounding" || + option.name() == "float") + { + return true; + } + return false; +} + + +/** + * @brief Set a packing option. + * @parameter option The option to set. + * + * Recognized options are `nbits', `nmantissa', `scale', `signed', + * `rounding', and `float'. See the setter functions above for details + * on their semantics. + * + * Returns true on success; false otherwise. + */ +bool PackedParameters::setOption (const AuxDataOption& option) +{ + if (option.name() == "nbits") + return setNbits (option.intVal()); + + else if (option.name() == "nmantissa") + return setNmantissa (option.intVal()); + + else if (option.name() == "scale") + return setScale (option.floatVal()); + + else if (option.name() == "signed") + return setSigned (option.intVal() != 0); + + else if (option.name() == "rounding") + return setRounding (option.intVal() != 0); + + else if (option.name() == "float") + return setFloat (option.intVal() != 0); + + return false; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/UDSLabelHashTable.cxx b/EDM/athena/Control/AthContainers/Root/UDSLabelHashTable.cxx new file mode 100644 index 00000000..cad5a1a9 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/UDSLabelHashTable.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef XAOD_STANDALONE + +#include "AthContainers/tools/UDSLabelHashTable.h" +#include "AthenaKernel/getMessageSvc.h" + +void UDSLabelHashTable::addLabel(const std::string& label, hash_t hash) +{ + hash_t h = addLabel (label); + if (h != hash) { + MsgStream logstr(Athena::getMessageSvc(), "UDSLabelHashTable"); + logstr << MSG::ERROR << "Hash mismatch for " << label + << ": " << hash << "/" << h << endmsg; + } +} + + +UDSLabelHashTable::hash_t UDSLabelHashTable::addLabel(const std::string& label) { + if (label.size()==0) { + MsgStream logstr(Athena::getMessageSvc(), "UDSLabelHashTable"); + logstr << MSG::ERROR << "Zero-length string given as Label!" << endmsg; + return INVALID; + } + hash_t h=this->hash(label); + if (h==INVALID) { + MsgStream logstr(Athena::getMessageSvc(), "UDSLabelHashTable"); + logstr << MSG::ERROR << "Label " << label << " yields an invalid hash. Please choose different name!" << endmsg; + return INVALID; + } + + std::map<hash_t, std::string>::const_iterator it=m_hashLabels.find(h); + if (it==m_hashLabels.end()) { + //new label, new hash + m_hashLabels[h]=label; + } + else { + //Hash exists already + if (it->second!=label) { //Same hash but different label -> hash-collision! + MsgStream logstr(Athena::getMessageSvc(), "UDSLabelHashTable"); + logstr << MSG::ERROR << "Hash collision between label " << label << " and label " << it->second << endmsg; + return INVALID; + } + } + return h; +} + + +const std::string& UDSLabelHashTable::getLabel(const hash_t number) const { + std::map<hash_t, std::string>::const_iterator it=m_hashLabels.find(number); + if (it==m_hashLabels.end()) + return m_empty; + else + return it->second; +} + + +std::vector<const std::string*> UDSLabelHashTable::getAllLabels() const { + + std::vector<const std::string*> allLabels; + allLabels.reserve(m_hashLabels.size()); + std::map<hash_t, std::string>::const_iterator it=m_hashLabels.begin(); + std::map<hash_t, std::string>::const_iterator it_e=m_hashLabels.end(); + for(;it!=it_e;++it) + allLabels.push_back(&(it->second)); + + return allLabels; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/Root/UserDataStore.cxx b/EDM/athena/Control/AthContainers/Root/UserDataStore.cxx new file mode 100644 index 00000000..bc0d9ecd --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/UserDataStore.cxx @@ -0,0 +1,118 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthContainers/UserDataStore.h" + +#ifndef XAOD_STANDALONE + +#include "AthenaKernel/getMessageSvc.h" + +UserDataStore::UserDataStore() : + m_data(), + m_lastIt(m_data.end()), + m_lastIt_nc(m_data.end()), + m_eventABC(IAthenaBarCode::UNDEFINEDBARCODE), + m_msg(Athena::getMessageSvc(),"UserDataStore"), + m_whyNotFound(ALLGOOD) + + {} + + + +UserDataStore::const_iterator +UserDataStore::find(const AthenaBarCode_t& barcode, const std::string& label) const { + m_whyNotFound=ALLGOOD; + if (m_lastIt==m_data.end() || m_lastIt->first!=barcode) + m_lastIt=m_data.find(barcode); + + if (m_lastIt==m_data.end()) { //No user data for this bar-code + m_whyNotFound=BARCODE; + return m_notFoundIt; + } + + const index_t idx=m_labelTable.hash(label); + const_iterator label_it=m_lastIt->second.find(idx); + if (label_it==m_lastIt->second.end()) { + //std::cout << "Did not find label " << label << "(hash=" << idx << ")" << std::endl; + m_whyNotFound=LABEL; + return m_notFoundIt; + } + else + return label_it; +} + +void UserDataStore::setEventABC(const AthenaBarCode_t& eventABC) { + if (m_eventABC==IAthenaBarCode::UNDEFINEDBARCODE) m_eventABC=eventABC; +} + + + +StatusCode UserDataStore::recordAny(const IAthenaBarCode& obj, const std::string& label, const boost::any& value) { + const AthenaBarCode_t& barcode=obj.getAthenaBarCode(); + + if (barcode==IAthenaBarCode::UNDEFINEDBARCODE) { + m_msg << MSG::ERROR << "Attempt to record UserData for an object with undefined AthenaBarCode. Label=" << label << endmsg; + return StatusCode::FAILURE; + } + + const index_t idx=m_labelTable.addLabel(label); + if (idx==UDSLabelHashTable::INVALID) { + m_msg << MSG::ERROR << "Failed to convert label '" << label << "' into a hash value" << endmsg; + return StatusCode::FAILURE; + } + else { + if (m_lastIt_nc==m_data.end() || m_lastIt_nc->first!=barcode) { + m_lastIt_nc=m_data.find(barcode); + } + if (m_lastIt_nc==m_data.end()) { + m_lastIt_nc=m_data.insert(std::make_pair(barcode,m_defaultEntry)).first; + } + (m_lastIt_nc->second)[idx]=value; + return StatusCode::SUCCESS; + } +} + + +StatusCode UserDataStore::retrieveAny(const IAthenaBarCode& obj, const std::string& label, const boost::any*& value) const { + const AthenaBarCode_t& barcode=obj.getAthenaBarCode(); + + const_iterator it=this->find(barcode,label); + if (it==m_notFoundIt) { + if (m_whyNotFound==BARCODE) + m_msg << MSG::ERROR << "No user data found for bar code " << barcode << endmsg; + if (m_whyNotFound==LABEL) + m_msg << MSG::ERROR << "No user data with label '" << label << "' found for this barcode" << endmsg; + return StatusCode::FAILURE; + } + else { + value=&(it->second); + return StatusCode::SUCCESS; + } +} + + +bool UserDataStore::contains(const IAthenaBarCode& obj, const std::string& label) const { + const AthenaBarCode_t& barcode=obj.getAthenaBarCode(); + const_iterator it=this->find(barcode,label); + return (it!=m_notFoundIt); +} + + +std::vector<const std::string*> UserDataStore::getLabels(const AthenaBarCode_t& barcode) const { + + std::vector<const std::string*> out; + mapmap_t::const_iterator abc_it=m_data.find(barcode); + if (abc_it!=m_data.end()) { + const std::map<index_t, boost::any>& labelMap=abc_it->second; + const_iterator it=labelMap.begin(); + const_iterator it_e=labelMap.end(); + for (;it!=it_e;++it) { + const std::string& sLabel=m_labelTable.getLabel(it->first); + out.push_back(&sLabel); + } + }// end if abc_it!=m_data.end() + return out; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/Root/debug.cxx b/EDM/athena/Control/AthContainers/Root/debug.cxx new file mode 100644 index 00000000..cdd52d53 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/debug.cxx @@ -0,0 +1,350 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/src/debug.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2015 + * @brief Helper functions intended to be called from the debugger. + */ + + +#include "AthContainers/debug.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/error.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "CxxUtils/StrFormat.h" +#include <vector> +#include <sstream> + + +namespace SGdebug { + + +/** + * @brief Return the name corresponding to a given aux id. + * @param id The aux id to look up. + */ +std::string aux_var_name (SG::auxid_t id) +{ + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + return reg.getClassName(id) + "::" + reg.getName(id); +} + + +/** + * @brief Print the name corresponding to a given aux id. + * @param id The aux id to print. + */ +void print_aux_var_name (SG::auxid_t id) +{ + std::cout << aux_var_name(id) << "\n"; +} + + +/****************************************************************************** + * Print the list of aux variables given some object. + */ + + +/** + * @brief Print the list of aux variables in a set. + * @param auxids The set to print. + */ +void print_aux_vars (const SG::auxid_set_t& auxids) +{ + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + std::vector<SG::auxid_t> ids (auxids.begin(), auxids.end()); + std::sort (ids.begin(), ids.end()); + + for (SG::auxid_t id : ids) { + std::cout << id << " " + << reg.getClassName(id) << "::" << reg.getName(id) << " " + << "[" << reg.getTypeName(id) << "]\n"; + } +} + + +/** + * @brief Print the list of aux variables handled by a store. + * @param store The store to dump. + */ +void print_aux_vars (const SG::IConstAuxStore& store) +{ + print_aux_vars (store.getAuxIDs()); +} + + +/** + * @brief Print the list of aux variables handled by a store. + * @param store The store to dump. + */ +void print_aux_vars (const SG::IConstAuxStore* store) +{ + print_aux_vars (*store); +} + + +/** + * @brief Print the list of aux variables associated with a container. + * @param vec The container to dump. + */ +void print_aux_vars (const SG::AuxVectorData& vec) +{ + print_aux_vars (vec.getAuxIDs()); +} + + +/** + * @brief Print the list of aux variables associated with a container. + * @param vec The container to dump. + */ +void print_aux_vars (const SG::AuxVectorData* vec) +{ + print_aux_vars (*vec); +} + + +/** + * @brief Print the list of aux variables associated with an element. + * @param elt The element to dump. + */ +void print_aux_vars (const SG::AuxElement& elt) +{ + print_aux_vars (elt.getAuxIDs()); +} + + +/** + * @brief Print the list of aux variables associated with an element. + * @param elt The element to dump. + */ +void print_aux_vars (const SG::AuxElement* elt) +{ + print_aux_vars (*elt); +} + + +/****************************************************************************** + * Dump out aux variables. + */ + + +namespace { + + +template <class T> +void convert (std::ostream& os, const T& x) +{ + os << x; +} + + +void convert (std::ostream& os, const float x) +{ + os << CxxUtils::strformat ("%.3f", x); +} + + +void convert (std::ostream& os, const double x) +{ + os << CxxUtils::strformat ("%.3f", x); +} + + +template <class T> +void convert (std::ostream& os, const std::vector<T>& x) +{ + os << "["; + bool first = true; + for (const T& elt : x) { + if (first) + first = false; + else + os << ", "; + convert (os, elt); + } + os << "]"; +} + + +struct AuxVarSort +{ + AuxVarSort (SG::auxid_t the_id) + : id(the_id), + name(aux_var_name(the_id)) + {} + + SG::auxid_t id; + std::string name; +}; + + +bool operator< (const AuxVarSort& a, const AuxVarSort& b ) +{ + return a.name < b.name; +} + + +} // anonymous namespace + + +/** + * @brief Convert an aux variable to a string. + * @param auxid The id of the variable. + * @param p Pointer to the location of the variable. + */ +std::string aux_var_as_string (SG::auxid_t auxid, const void* p) +{ + std::ostringstream os; + + const SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + const std::type_info* ti = r.getType(auxid); +#define CONVERT(T) if (ti == &typeid(T)) convert (os, *reinterpret_cast<const T*>(p)); else +#define CONVERT1(T) CONVERT(T) CONVERT(std::vector<T>) + CONVERT1 (int) + CONVERT1 (unsigned int) + CONVERT1 (short) + CONVERT1 (unsigned short) + CONVERT1 (char) + CONVERT1 (unsigned char) + CONVERT1 (long) + CONVERT1 (unsigned long) + CONVERT1 (long long) + CONVERT1 (unsigned long long) + CONVERT1 (float) + CONVERT1 (double) + CONVERT1 (bool) + //else + os << "<??? " << AthContainers_detail::typeinfoName(*ti) << ">"; + return os.str(); +} + + +/** + * @brief Dump aux variables from a store for a single element. + * @param store The store from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore& store, size_t i) +{ + if (i >= store.size()) return; + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + SG::auxid_set_t ids = store.getAuxIDs(); + std::vector<AuxVarSort> vars (ids.begin(), ids.end()); + std::sort (vars.begin(), vars.end()); + for (const AuxVarSort& v : vars) { + const void* pbeg = store.getData (v.id); + size_t eltsz = reg.getEltSize (v.id); + const char* p = reinterpret_cast<const char*>(pbeg) + eltsz*i; + std::cout << v.name << " " << aux_var_as_string (v.id, p) << "\n"; + } +} + + +/** + * @brief Dump aux variables from a store for a single element. + * @param store The store from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore* store, size_t i) +{ + dump_aux_vars (*store, i); +} + + +/** + * @brief Dump aux variables from a store for all elements. + * @param store The store from which to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore& store) +{ + size_t sz = store.size(); + for (size_t i = 0; i < sz; i++) { + std::cout << "=== Element " << i << "\n"; + dump_aux_vars (store, i); + } +} + + +/** + * @brief Dump aux variables from a store for all elements. + * @param store The store from which to dump. + */ +void dump_aux_vars (const SG::IConstAuxStore* store) +{ + dump_aux_vars (*store); +} + + +/** + * @brief Dump aux variables from a vector for a single element. + * @param vec The vector from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::AuxVectorData& vec, size_t i) +{ + const SG::IConstAuxStore* store = vec.getConstStore(); + if (store) + dump_aux_vars (*store, i); +} + + +/** + * @brief Dump aux variables from a vector for a single element. + * @param vec The vector from which to dump. + * @param i The index of the element to dump. + */ +void dump_aux_vars (const SG::AuxVectorData* vec, size_t i) +{ + dump_aux_vars (*vec, i); +} + + +/** + * @brief Dump aux variables from a vector for all elements. + * @param vec The vector from which to dump. + */ +void dump_aux_vars (const SG::AuxVectorData& vec) +{ + const SG::IConstAuxStore* store = vec.getConstStore(); + if (store) + dump_aux_vars (*store); +} + + +/** + * @brief Dump aux variables from a vector for all elements. + * @param vec The vector from which to dump. + */ +void dump_aux_vars (const SG::AuxVectorData* vec) +{ + dump_aux_vars (*vec); +} + + +/** + * @brief Dump aux variables for an element. + * @param elt The element from which to dump. + */ +void dump_aux_vars (const SG::AuxElement& elt) +{ + const SG::AuxVectorData* cont = elt.container(); + if (cont) + dump_aux_vars (*cont, elt.index()); +} + + +/** + * @brief Dump aux variables for an element. + * @param elt The element from which to dump. + */ +void dump_aux_vars (const SG::AuxElement* elt) +{ + dump_aux_vars (*elt); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/dict/PackedContainerStreamer.cxx b/EDM/athena/Control/AthContainers/Root/dict/PackedContainerStreamer.cxx new file mode 100644 index 00000000..f1480f00 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/dict/PackedContainerStreamer.cxx @@ -0,0 +1,200 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/Root/PackedContainerStreamer.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Streamer code for I/O with SG::PackedContainer. + */ + + +#include "AthContainers/PackedContainer.h" +#include "AthContainers/PackedConverter.h" +#include "AthContainers/ClassName.h" +#include "TClassStreamer.h" +#include "TMemberStreamer.h" +#include "TError.h" +#include "TROOT.h" +#include <cassert> + + +namespace SG { + + +/** + * @brief Write a set of packed parameters to a buffer. + * @param b Buffer to which to write. + * @param param Parameters to write. + */ +inline +void writePackedParameters( TBuffer& b, const SG::PackedParameters& parms ) { + b << parms.nbits(); + b << parms.flags(); + if (parms.isFloat()) { + b << parms.nmantissa(); + if (parms.hasScale()) + b << parms.scale(); + } +} + + +/** + * @brief Read a set of packed parameters from a buffer. + * @param b Buffer from which to write. + */ +inline +SG::PackedParameters readPackedParameters( TBuffer& b ) { + uint8_t nbits; + b >> nbits; + + uint8_t flags; + b >> flags; + + SG::PackedParameters parms (nbits, flags); + if (parms.isFloat()) { + uint8_t nmantissa; + b >> nmantissa; + parms.setNmantissa (nmantissa); + if (parms.hasScale()) { + float scale; + b >> scale; + parms.setScale (scale); + } + } + return parms; +} + + +/** + * @brief Streamer for reading/writing SG::PackedContainer instances. + */ +template <class T> +class PackedContainerStreamer + : public TClassStreamer +{ +public: + /** + * @brief Constructor. + */ + PackedContainerStreamer(); + + + /** + * @brief Run the streamer. + * @param b Buffer from/to which to read/write. + * @param objp Object instance. + */ + virtual void operator()(TBuffer &b, void *objp); + + +private: + /// Name of the class we read/write (for error messages). + std::string m_className; +}; + + +/** + * @brief constructor. + */ +template <class T> +PackedContainerStreamer<T>::PackedContainerStreamer() + : m_className( ClassName< SG::PackedContainer< T > >::name() ) +{ +} + + +/** + * @brief Run the streamer. + * @param b Buffer from/to which to read/write. + * @param objp Object instance. + */ +template <class T> +void PackedContainerStreamer<T>::operator() ( TBuffer& b, void* objp ) { + SG::PackedContainer<T>* cont = + reinterpret_cast<SG::PackedContainer<T>*> (objp); + + if (b.IsReading()) { + UInt_t R__s, R__c; + Version_t R__v = b.ReadVersion(&R__s, &R__c); + if (R__v != 1) { + Error ("PackedContainerStreamer", + "Bad version %d for object of type %s (expected 1)", + R__v, m_className.c_str()); + } + + cont->setParms (readPackedParameters (b)); + + uint32_t nelt; + b >> nelt; + + SG::PackedConverter cnv (cont->parms()); + cnv.read (nelt, *cont, b); + + b.CheckByteCount(R__s, R__c, m_className.c_str()); + } + else { + UInt_t R__c = b.Length(); + b.SetBufferOffset (R__c + sizeof(UInt_t)); + b << Version_t(1); + writePackedParameters (b, cont->parms()); + + uint32_t nelt = cont->size(); + b << nelt; + + SG::PackedConverter cnv (cont->parms()); + cnv.write (cont->size(), *cont, b); + + b.SetByteCount(R__c, kTRUE); + } +} + + +template <class T> +struct InstallPackedContainerStreamer; + + +} // namespace SG + + +#define STREAMER(TYPE) \ + namespace ROOT { TGenericClassInfo* GenerateInitInstance(const SG::PackedContainer<TYPE>*);} \ + namespace SG { \ + template <> struct InstallPackedContainerStreamer<TYPE> { \ + InstallPackedContainerStreamer() { \ + ROOT::GenerateInitInstance((SG::PackedContainer<TYPE>*)nullptr)->AdoptStreamer (new PackedContainerStreamer<TYPE>) ; \ + } }; \ + InstallPackedContainerStreamer<TYPE> _R__UNIQUE_(streamerInstance); \ + } class swallowSemicolon + + +STREAMER(char); +STREAMER(unsigned char); +STREAMER(short); +STREAMER(unsigned short); +STREAMER(int); +STREAMER(unsigned int); +STREAMER(float); +STREAMER(double); + +STREAMER(std::vector<char>); +STREAMER(std::vector<unsigned char>); +STREAMER(std::vector<short>); +STREAMER(std::vector<unsigned short>); +STREAMER(std::vector<int>); +STREAMER(std::vector<unsigned int>); +STREAMER(std::vector<float>); +STREAMER(std::vector<double>); + +STREAMER(std::vector<std::vector<char> >); +STREAMER(std::vector<std::vector<unsigned char> >); +STREAMER(std::vector<std::vector<short> >); +STREAMER(std::vector<std::vector<unsigned short> >); +STREAMER(std::vector<std::vector<int> >); +STREAMER(std::vector<std::vector<unsigned int> >); +STREAMER(std::vector<std::vector<float> >); +STREAMER(std::vector<std::vector<double> >); + +#undef STREAMER diff --git a/EDM/athena/Control/AthContainers/Root/dict/ViewVectorBaseStreamer.cxx b/EDM/athena/Control/AthContainers/Root/dict/ViewVectorBaseStreamer.cxx new file mode 100644 index 00000000..0f1a737c --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/dict/ViewVectorBaseStreamer.cxx @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/Root/ViewVectorBaseStreamer.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Streamer code for I/O with SG::ViewVectorBase. + * + * This sets up a custom streamer function to ensure that toPersistent() + * is called when ViewVectorBase is written. The toTransient() method + * is called from the root read rule (or from the pool/bytestream converter + * in the case of schema evolution). + */ + + +#include "AthContainers/ViewVectorBase.h" +#include "TClass.h" +#include "TBuffer.h" + + +namespace SG { + + +void ViewVectorBaseStreamerFunc (TBuffer& b, void* p) +{ + static TClass* const cl = TClass::GetClass ("SG::ViewVectorBase"); + if (b.IsReading()) { + cl->ReadBuffer (b, p); + } else { + SG::ViewVectorBase* vvb = reinterpret_cast<SG::ViewVectorBase*>(p); + vvb->toPersistent(); + cl->WriteBuffer(b, p); + } +} + + +} // namespace SG + + +namespace ROOT { +TGenericClassInfo* GenerateInitInstance(const SG::ViewVectorBase*); +} + +namespace SG { +struct InstallViewVectorBaseStreamer { + InstallViewVectorBaseStreamer() { + ROOT::GenerateInitInstance((SG::ViewVectorBase*)nullptr)->SetStreamerFunc (ViewVectorBaseStreamerFunc); + } +}; +InstallViewVectorBaseStreamer viewVectorBaseStreamerInstance; +} // namespace SG + diff --git a/EDM/athena/Control/AthContainers/Root/error.cxx b/EDM/athena/Control/AthContainers/Root/error.cxx new file mode 100644 index 00000000..d74de9cf --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/error.cxx @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/error.cxx + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch>, scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Helper for emitting error messages. + */ + + +#include "AthContainers/tools/error.h" +#ifdef __GXX_ABI_VERSION +# include <cstdlib> +# include <cxxabi.h> +#endif + + +#ifdef XAOD_STANDALONE + + +namespace AthContainers_detail { + + +/** + * This function does pretty much the same thing as Gaudi's + * <code>System::typeinfoName</code>. The only reason for having it + * is to make the compilation of the package easier outside of + * Athena. + * + * @param ti The type identifier of the class we're interested in + * @returns The string name of the type + */ +std::string typeinfoName (const std::type_info& ti) +{ + // In case the "translation" is not successful, the fallback is to + // keep the original, mangled name: + std::string result = ti.name(); + +#ifdef __GXX_ABI_VERSION + // Try to demangle the name: + int status; + char* typeName = abi::__cxa_demangle( ti.name(), 0, 0, &status ); + if (status == 0) { + // Take the demangled name, and free up the memory allocated in + // the process: + result = typeName; + ::free( typeName ); + } +#endif + + return result; +} + + +} // namespace AthContainers_detail + + +#endif // XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/Root/exceptions.cxx b/EDM/athena/Control/AthContainers/Root/exceptions.cxx new file mode 100644 index 00000000..3bcf9a91 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/exceptions.cxx @@ -0,0 +1,453 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/src/exceptions.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Exceptions that can be thrown from AthContainers. + */ + + +#include "AthContainers/exceptions.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/error.h" +#include <sstream> + + +namespace SG { + + +/// Helper: format an aux data item name. +std::string excFormatName (SG::auxid_t auxid) +{ + std::ostringstream os; + if (auxid != null_auxid) { + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + os << "`" << r.getClassName (auxid); + if (!os.str().empty()) + os << "::"; + os << r.getName (auxid); + os << "' (" << auxid << ")"; + } + return os.str(); +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excNoAuxStore_format (SG::auxid_t auxid) +{ + std::ostringstream os; + os << "SG::ExcNoAuxStore: " + << "Requested aux data item " + << excFormatName (auxid) + << " but there is no associated aux data store."; + return os.str(); +} + + +/// Helper: format exception error string. +std::string excNoAuxStore_format (const char* op) +{ + std::ostringstream os; + os << "SG::ExcNoAuxStore: " + << "Operation attempted on container with no associated aux data store: "; + os << op; + return os.str(); +} + + +/** + * @brief Constructor. + * @param auxid The ID of the requested aux data item. + */ +ExcNoAuxStore::ExcNoAuxStore (SG::auxid_t auxid) + : std::runtime_error (excNoAuxStore_format (auxid)) +{ +} + + +/** + * @brief Constructor. + * @param op The attempted operation. + */ +ExcNoAuxStore::ExcNoAuxStore (const char* op) + : std::runtime_error (excNoAuxStore_format (op)) +{ +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excBadAuxVar_format (SG::auxid_t auxid) +{ + std::ostringstream os; + os << "SG::ExcBadAuxVar: " + << "Attempt to retrieve nonexistent aux data item " + << excFormatName (auxid) + << "."; + return os.str(); +} + + +/** + * @brief Constructor. + * @param auxid The ID of the requested aux data item. + */ +ExcBadAuxVar::ExcBadAuxVar (SG::auxid_t auxid) + : std::runtime_error (excBadAuxVar_format (auxid)) +{ +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excConstAuxData_format (const std::string& op, SG::auxid_t auxid) +{ + std::ostringstream os; + os << "SG::ExcConstAuxData: " + << "Non-const operation `" << op << "' performed on const aux data " + << excFormatName (auxid) + << "."; + return os.str(); +} + + +/** + * @brief Constructor. + * @param op The attempted operation. + * @param auxid The ID of the requested aux data item, if any. + */ +ExcConstAuxData::ExcConstAuxData (const std::string& op, SG::auxid_t auxid) + : std::runtime_error (excConstAuxData_format (op, auxid)) +{ +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcUntrackedSetStore::ExcUntrackedSetStore() + : std::runtime_error + ("SG::ExcUntrackedSetStore: " + "Attempt to set aux data store on container that doesn't track indices, " + "or disable index tracking for a container with aux data.") +{ +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param op The attempted operation. + */ +ExcBadPrivateStore::ExcBadPrivateStore (const std::string& op) + : std::runtime_error ("SG::ExcBadPrivateStore: " + "Bad use of private store: " + op) +{ +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excAuxTypeMismatch_format (SG::auxid_t auxid, + const std::type_info& new_type, + const std::type_info& old_type) +{ + std::ostringstream os; + os << "SG::ExcAuxTypeMismatch: " + << "Type mismatch for aux variable " + << excFormatName (auxid) + << "; old type is " << AthContainers_detail::typeinfoName (old_type) + << " new type is " << AthContainers_detail::typeinfoName (new_type); + return os.str(); +} + + +/** + * @brief Constructor. + * @param auxid ID of the requested aux data item. + * @param new_type New type requested for the item. + * @param old_type Previous type associated with the item. + */ +ExcAuxTypeMismatch::ExcAuxTypeMismatch (SG::auxid_t auxid, + const std::type_info& new_type, + const std::type_info& old_type) + : std::runtime_error (excAuxTypeMismatch_format (auxid, + new_type, old_type)) +{ +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excInsertionInBaseClass_format (const char* op, + const std::type_info& base_type, + const std::type_info& complete_type) +{ + std::ostringstream os; + os << "SG::ExcInsertionInBaseClass: " + << "Attempted to do " << op + << " on a " << AthContainers_detail::typeinfoName (base_type) + << " base class of " << AthContainers_detail::typeinfoName (complete_type) + << "; can only be done on the most-derived class."; + return os.str(); +} + + +/** + * @brief Constructor. + * @param op The attempted operation. + * @param base_type The type on which the operation was attempted. + * @param complete_type The most-derived type of the object. + */ +ExcInsertionInBaseClass::ExcInsertionInBaseClass + (const char* op, + const std::type_info& base_type, + const std::type_info& complete_type) + : std::runtime_error (excInsertionInBaseClass_format (op, + base_type, + complete_type)) +{ +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excStoreLocked_format (SG::auxid_t auxid) +{ + std::ostringstream os; + os << "SG::ExcStoreLocked: " + << "Attempted to modify auxiliary data in a locked store: "; + os << excFormatName (auxid); + return os.str(); +} + + +/// Helper: format exception error string. +std::string excStoreLocked_format (const char* op) +{ + std::ostringstream os; + os << "SG::ExcStoreLocked: " + << "Attempted to modify auxiliary data in a locked store: "; + os << op; + return os.str(); +} + + +/** + * @brief Constructor. + * @param op The attempted operation. + */ +ExcStoreLocked::ExcStoreLocked (SG::auxid_t auxid) + : std::runtime_error (excStoreLocked_format (auxid)) +{ +} + + +/** + * @brief Constructor. + * @param op The attempted operation. + */ +ExcStoreLocked::ExcStoreLocked (const char* op) + : std::runtime_error (excStoreLocked_format (op)) +{ +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcNonowningContainer::ExcNonowningContainer() + : std::runtime_error ("SG::ExcNonowningContainer: Attempted to insert a unique_ptr to a non-owning container.") +{ +} + + +/** + * @brief Throw a SG::ExcNonowningContainer exception. + */ +void throwExcNonowningContainer() +{ + throw ExcNonowningContainer(); +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excUnknownAuxItem_format (const std::string& name, + const std::string& clsname, + const std::type_info* typ) +{ + std::ostringstream os; + os << "SG::ExcUnknownAuxItem: " + << "Unknown aux data item "; + if (!clsname.empty()) + os << clsname << "::"; + os << name; + if (typ) + os << " (of type " << AthContainers_detail::typeinfoName (*typ) << ")"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param name Name of the aux data item. + * @param clsname Class name of the aux data item, or an empty string. + * @param typ Type of the item, if provided. + */ +ExcUnknownAuxItem::ExcUnknownAuxItem (const std::string& name, + const std::string& clsname /*= ""*/, + const std::type_info* typ /*= 0*/) + : std::runtime_error (excUnknownAuxItem_format (name, clsname, typ)) +{ +} + + +/** + * @brief Throw a SG::ExcUnknownAuxItem exception. + * @param name Name of the aux data item. + * @param clsname Class name of the aux data item, or an empty string. + * @param typ Type of the item, if provided. + */ +void throwExcUnknownAuxItem (const std::string& name, + const std::string& clsname /*= ""*/, + const std::type_info* typ /*= 0*/) +{ + throw ExcUnknownAuxItem (name, clsname, typ); +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excDVToELV_format (const std::string& detail) +{ + std::ostringstream os; + os << "SG::ExcDVToELV: " + << "Can't convert DataVector to vector of ElementLinks: " + << detail; + return os.str(); +} + + +/** + * @brief Constructor. + * @param detail More information about the error. + */ +ExcDVToELV::ExcDVToELV (const std::string& detail) + : std::runtime_error (excDVToELV_format (detail)) +{ +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcViewVectorNotView::ExcViewVectorNotView() + : std::runtime_error ("ViewVector not in view mode.") +{ +} + + +/** + * @brief Throw a SG::ExcViewVectorNotView exception. + */ +void throwExcViewVectorNotView() +{ + throw ExcViewVectorNotView(); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcMissingViewVectorCLID::ExcMissingViewVectorCLID (const std::type_info& ti) + : std::runtime_error ("ViewVector " + AthContainers_detail::typeinfoName(ti) + + "was used in a context that requires a CLID, " + "but no CLID was available. Make sure a " + "VIEWVECTOR_CLASS_DEF declaration exists for the class " + "in a library that has been loaded.") +{ +} + + +/** + * @brief Throw a SG::ExcViewVectorCLID exception. + */ +void throwExcMissingViewVectorCLID (const std::type_info& ti) +{ + throw ExcMissingViewVectorCLID (ti); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcMissingBaseInfo::ExcMissingBaseInfo (const std::type_info& ti) + : std::runtime_error ("Missing BaseInfo for " + + AthContainers_detail::typeinfoName(ti)) +{ +} + + +/** + * @brief Throw a SG::ExcMissingBaseInfo exception. + */ +void throwExcMissingBaseInfo (const std::type_info& ti) +{ + throw ExcMissingBaseInfo (ti); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcInsertMoveOwnershipMismatch::ExcInsertMoveOwnershipMismatch() + : std::runtime_error ("Ownership mismatch for insertMove.") +{ +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/Root/normalizedTypeinfoName.cxx b/EDM/athena/Control/AthContainers/Root/normalizedTypeinfoName.cxx new file mode 100644 index 00000000..b52ddc54 --- /dev/null +++ b/EDM/athena/Control/AthContainers/Root/normalizedTypeinfoName.cxx @@ -0,0 +1,165 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/Root/normalizedTypeinfoName.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Convert a @c type_info to a normalized string representation + * (matching the names used in the root dictionary). + */ + + +#include "AthContainers/normalizedTypeinfoName.h" +#include "AthContainers/tools/threading.h" +#include "AthContainers/tools/error.h" +#include "CxxUtils/ClassName.h" + + +#if __cplusplus < 201100 +# include "CxxUtils/unordered_map.h" +namespace SG_STD_OR_SG = SG; +#else +# include <unordered_map> +# include <functional> +namespace SG_STD_OR_SG = std; +#endif + + +namespace { + + +typedef SG_STD_OR_SG::unordered_map<const std::type_info*, std::string> + typemap_t; + +typedef AthContainers_detail::upgrade_mutex mutex_t; +typedef AthContainers_detail::strict_shared_lock<mutex_t> lock_t; +typedef AthContainers_detail::upgrading_lock<mutex_t> upgrading_lock_t; + + +void initRules (CxxUtils::ClassName::Rules& rules) +{ + // STL container types that Reflex knows about. + rules.add ("std::deque<$T, std::allocator<$T> >", + "std::deque<$T>"); + rules.add ("std::list<$T, std::allocator<$T> >", + "std::list<$T>"); + rules.add ("std::vector<$T, std::allocator<$T> >", + "std::vector<$T>"); + rules.add ("std::map<$KEY, $T, std::less<$KEY>, std::allocator<std::pair<const $KEY, $T> > >", + "std::map<$KEY, $T>"); + rules.add ("std::multimapmap<$KEY, $T, std::less<$KEY>, std::allocator<std::pair<const $KEY, $T> > >", + "std::multimapmap<$KEY, $T>"); + rules.add ("std::set<$KEY, std::less<$KEY>, std::allocator<$KEY> >", + "std::set<$KEY>"); + rules.add ("std::multiset<$KEY, std::less<$KEY>, std::allocator<$KEY> >", + "std::multiset<$KEY>"); + rules.add ("std::unordered_map<$KEY, $T, std::hash<$KEY>, std::equal_to<$KEY>, std::allocator<std::pair<const $KEY, $T> > >", + "std::unordered_map<$KEY, $T>"); + rules.add ("std::unordered_multimap<$KEY, $T, std::hash<$KEY>, std::equal_to<$KEY>, std::allocator<std::pair<const $KEY, $T> > >", + "std::unordered_multimap<$KEY, $T>"); + rules.add ("std::unordered_set<$KEY, std::hash<$KEY>, std::equal_to<$KEY>, std::allocator<$KEY> >", + "std::unordered_set<$KEY>"); + rules.add ("std::unordered_multiset<$KEY, std::hash<$KEY>, std::equal_to<$KEY>, std::allocator<$KEY> >", + "std::unordered_multiset<$KEY>"); + rules.add ("std::queue<$T, std::deque<$T> >", + "std::queue<$T>"); + rules.add ("std::stack<$T, std::deque<$T> >", + "std::stack<$T>"); + + // These container types are also defined in the C++11 standard, + // but root5 reflex doesn't know about them. List them here anyway. + rules.add ("std::forward_list<$T, std::allocator<$T> >", + "std::forward_list<$T>"); + rules.add ("std::priority_queue<$T, std::vector<$T>, std::less<$T> >", + "std::priority_queue<$T>"); + + // Reflex also handles the non-standard containers hash_map, etc. + // Don't think atlas is using those anywhere, so skip that. + + // Reflex handles the basic_string template. + // I actually think that demangling will produce `std::string' rather + // than `std::basic_string' with default arguments; however, add it + // for completeness. + rules.add ("std::basic_string<$T, std::char_traits<$T>, std::allocator<$T> >", + "std::string"); + + // Atlas-specific mappings. + rules.add ("DataVector<$T, $U>", "DataVector<$T>"); + rules.add ("DataList<$T, $U>", "DataList<$T>"); + + // Handle gcc's C++11 ABI. + rules.add ("std::__cxx11", "std"); + + // Needed for macos? + rules.add ("std::__1", "std"); +} + + +} // anonymous namespace + + +namespace SG { + + +/** + * @brief Convert a @c type_info to a normalized string representation + * (matching the names used in the root dictionary). + * @param info The type to convert. + * + * The function `AthContainer_detail::typeinfoName` may be used to convert + * a C++ `type_info` to a string representing the name of the class; this + * handles platform-dependent details such as performing demangling. + * + * However, the name you get as a result of this does not necessarily match + * the name by which the class is known in the ROOT dictionary. + * In particular, defaulted template arguments for STL containers and + * @c DataVector are suppressed in the dictionary. So, for example, + * for a vector class @c typeinfoName may produce + * `std::vector<int, std::allocator<T> >`, while in the dictionary + * it is known as `std::vector<int>`. Using @c normalizedTypeinfoName + * instead will transform the names to match what's in the dictionary. + * This function will also cache the typeinfo -> string conversions. + */ +std::string normalizedTypeinfoName (const std::type_info& info) +{ + static typemap_t normalizedTypemap; + static mutex_t normalizedTypemapMutex; + + // First test to see if we already have this mapping. + // For this, use a read lock. + { + lock_t lock (normalizedTypemapMutex); + typemap_t::iterator it = normalizedTypemap.find (&info); + if (it != normalizedTypemap.end()) + return it->second; + } + + static CxxUtils::ClassName::Rules normalizeRules; + + // Didn't find it. Take out an upgrading lock. + { + upgrading_lock_t lock (normalizedTypemapMutex); + + // Need to check again to see if the mapping's there. + typemap_t::iterator it = normalizedTypemap.find (&info); + if (it != normalizedTypemap.end()) + return it->second; + + // Convert lock to exclusive. + lock.upgrade(); + + if (normalizeRules.size() == 0) + initRules (normalizeRules); + + std::string tiname = AthContainers_detail::typeinfoName (info); + std::string normalizedName = normalizeRules.apply (tiname); + normalizedTypemap[&info] = normalizedName; + return normalizedName; + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/cmt/Makefile.RootCore b/EDM/athena/Control/AthContainers/cmt/Makefile.RootCore new file mode 100644 index 00000000..e8cb703e --- /dev/null +++ b/EDM/athena/Control/AthContainers/cmt/Makefile.RootCore @@ -0,0 +1,24 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = AthContainers +PACKAGE_PRELOAD = +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = AthContainersInterfaces AthLinks TestTools CxxUtils +PACKAGE_TRYDEP = Asg_gccxml +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 1 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 0 +PACKAGE_REFLEX = 1 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/EDM/athena/Control/AthContainers/cmt/requirements b/EDM/athena/Control/AthContainers/cmt/requirements new file mode 100644 index 00000000..e0c8ff92 --- /dev/null +++ b/EDM/athena/Control/AthContainers/cmt/requirements @@ -0,0 +1,77 @@ +package AthContainers +# $Id: requirements 800990 2017-03-19 23:15:21Z ssnyder $ + +author Paolo Calafiura <Paolo.Calafiura@cern.ch> +author Hong Ma <hma@bnl.gov> +author Srini Rajagopalan <srinir@bnl.gov> +author scott snyder <snyder@bnl.gov> + +use AtlasPolicy AtlasPolicy-* +use AthenaKernel AthenaKernel-* Control +use SGTools SGTools-* Control +use CxxUtils CxxUtils-* Control +use AthContainersInterfaces AthContainersInterfaces-* Control +use AthLinks AthLinks-* Control +use AtlasBoost AtlasBoost-* External +use GaudiInterface GaudiInterface-* External + +private +use AtlasROOT AtlasROOT-* External +end_private + +apply_pattern installed_library +library AthContainers *.cxx ../Root/*.cxx + +private + +use TestTools TestTools-* AtlasTest +apply_pattern UnitTest_run unit_test=removeDuplicates +apply_pattern UnitTest_run unit_test=DataVector +apply_pattern UnitTest_run unit_test=DataVector_a +apply_pattern UnitTest_run unit_test=DataVector_b +apply_pattern UnitTest_run unit_test=DataVector_c +apply_pattern UnitTest_run unit_test=DataVector_d +apply_pattern UnitTest_run unit_test=DataVector_e +apply_pattern UnitTest_run unit_test=DataVector_f +apply_pattern UnitTest_run unit_test=DataList +apply_pattern UnitTest_run unit_test=DVLInfo +apply_pattern UnitTest_run unit_test=DVLDataBucket +apply_pattern UnitTest_run unit_test=DVLCast +apply_pattern UnitTest_run unit_test=IsMostDerivedFlag +apply_pattern UnitTest_run unit_test=ElementProxy +apply_pattern UnitTest_run unit_test=DVLIterator +apply_pattern UnitTest_run unit_test=DVL_iter_swap +apply_pattern UnitTest_run unit_test=foreach + +apply_pattern UnitTest_run unit_test=AuxTypeVector +apply_pattern UnitTest_run unit_test=AuxTypeVectorFactory +apply_pattern UnitTest_run unit_test=AuxTypeRegistry extrapatterns='will use std::' +apply_pattern UnitTest_run unit_test=AuxVectorData extrapatterns='will use std::' +apply_pattern UnitTest_run unit_test=AuxVectorBase extrapatterns='will use std::' +apply_pattern UnitTest_run unit_test=AuxStoreInternal +apply_pattern UnitTest_run unit_test=AuxStoreStandalone +apply_pattern UnitTest_run unit_test=AuxElement +apply_pattern UnitTest_run unit_test=AuxElementComplete +apply_pattern UnitTest_run unit_test=error +apply_pattern UnitTest_run unit_test=threading +apply_pattern UnitTest_run unit_test=threading_nothreads +apply_pattern UnitTest_run unit_test=exceptions +apply_pattern UnitTest_run unit_test=normalizedTypeinfoName +apply_pattern UnitTest_run unit_test=getThinnedFlags +apply_pattern UnitTest_run unit_test=copyAuxStoreThinned +apply_pattern UnitTest_run unit_test=copyThinned +apply_pattern UnitTest_run unit_test=PackedParameters +apply_pattern UnitTest_run unit_test=PackedConverter +apply_pattern UnitTest_run unit_test=PackedContainer +apply_pattern UnitTest_run unit_test=debug +apply_pattern UnitTest_run unit_test=dataVectorAsELV +apply_pattern UnitTest_run unit_test=ViewVector +apply_pattern UnitTest_run unit_test=ViewVectorBase + +macro_append DOXYGEN_INPUT " ../doc" + +private +use AtlasReflex AtlasReflex-* External +apply_pattern lcgdict dict=AthContainers selectionfile=selection.xml \ + headerfiles="../AthContainers/AthContainersDict.h" \ + extralibfiles=../Root/dict/*.cxx diff --git a/EDM/athena/Control/AthContainers/ispellwords b/EDM/athena/Control/AthContainers/ispellwords new file mode 100644 index 00000000..ad0b3134 --- /dev/null +++ b/EDM/athena/Control/AthContainers/ispellwords @@ -0,0 +1,1140 @@ +personal_ws-1.1 en 698 +assoPointer +persistency +IdentifiableContainer +multi +toContainedElement +GaudiKernel +situ +someone's +refcnt +GENERATEINDEXINGPOLICIES +elementShortRef +originalSize +unary +blk +arg +objectContainer +dataID +bkt +Amram +endif +typeid +fooB +ForwardIndexingPolicy +JetCollection +resized +constr +PackedArray +const's +RandomAccessIterator +CompareAndPrint +del +IProxyDict +deallocate +dep +DVLNoBase +cassert +creat +ASHSTLAllocator +ness +Resizes +autoselect +doinit +setElement +DataVector +theAsso +addHostDObj +gaudi +Dreizin +scott +theAssociatedObjects +cmt +objIndex +assocIndex +dir +ArenaAllocatorRegistry +allocator's +persistifiable +InhVectorIntLink +functor +nclear +crc +elmts +ssnyder +Predwrapper +MessageSvc +DNC +readback +binet +theTrack +DL's +DataPool +Faz +newAssoc +fdl +GenerateIndexingPolicy +ConstDataVector +AtlasReflex +fangled +fdv +LongRef +pCont's +gcc +Ilija +HistogramPersis +absFluff +liint +getAssociations +allo +isDefault +utest +ArenaCachingHandle +depcy +nctor +ELs +CVS +ClassName +destructor +tTrack +elt +hashtable's +PlainPtrElementLink +ELV +DList +DSO +resetWithKeyAndIndex +DataLinkVector +ElemLink +resetWithKey +typedef +pbad +dum +firstAssoc +cxx +theStore +BaseContainer +persistified +dvl +endAssociation +ispellwords +ILink +endHostDObjs +shortRefs +shortrefs +GenParticleIndexing +Elsing +DV's +BinaryPredicate +anOther +FooDequeLink +moveHostDObjs +theObjects +FooDeque +ArenaBase +AtlasSEAL +FNV +NoBase +icc +iCtr +NOGAUDI +swapElement +defaultHeader +objectPointer +src's +StoreGateSvc +hashtable +CopyConstructible +findProxy +BeginEvent +GNUC +toPersistentDL +iff +firstAssObject +bitsize +pCopyDerFluff +findAssociationObjects +DataVectorBase +fdvlcopy +line'll +func +ArenaHandleBaseAllocT +asDataList +CLID's +CLIDs +convertable +fdlcopy +hoc +DHAVE +functionalities +addArena +dataGet +namespaces +StoreGate +IOSTREAMS +oldElem +DataProxy +paolo +eltest +jobOs +AssociationLinks +DataLink +RVersion +pAssoc +hpp +TODO +valgrind +DataProxyStorageBase +srini +getObject +ASSCONT +cerr +proxying +ASSOCONT +DataListBase +AthenaPOOL +Calafiura +MapIndexingPolicy +param +AssociationVector +IProxyDictWithPool +persistify +changeState +canReclear +doxygen +setHashAndIndex +runtime +lcg +args +DataList +DataPtrs +rebinder +theAssociations +inserters +uint +ndtor +DVLCast +theAssociationObjects +assoStore +AssociationVectorCollection +isStreamable +irt +resetTo +AssociationVectorIterator +wronglmint +pairtype +pdata +RemoveDataPtr +theType +printf +setStorableObject +ArenaHeapSTLAllocator +iJet +doRemap +toPersistable +OBJCONT +deallocation +iTracks +getFirstAssociation +SGFolder +AssociationLinkCollection +objectIter +lhs +storeName +ArenaBlockAllocatorBase +rvalue +DerivedFluff +ElemLinkVector +ArenaHeaderGaudiClear +mem +hasher +dobjs +assoIter +Quarrie +hasAssociations +assoContainer +dereferencing +cinquanta +IdentContIndexingPolicy +DVLDataBucket +ElementLinkVector +vers +PDTR +nav +Hong +forwardContainer +cinq +eltSize +AtlasBoost +CINT +typeinfoName +reverseIterators +ArenaPoolAllocator +kwd +ndx +resize +indexingPolicy +tradeoff +ClusterContainer +oldInt +getDataSourcePointer +MacOSX +NavigationToken +asso +PlainPtrStorage +bool +shortref +shortRef +dieci +DataMap +Nir +OBJTYPE +asDataVector +ArenaHeapAllocator +DataLinks +gmake +mLink +castfn +AssociationBaseCollection +clid +deps +LWG +namespace +IOHandler +ArenaAllocatorCreatorInit +pdf +pAssocs +dflt +dfluff +pDL +reflextion +typename +typeName +DVLIterator +iTrack +getDataSource +initParams +LXR +DataBucket +pDV +pJets +refCount +snyder +ASSOBJECT +initGaudi +Srini's +multimap +pTransient +DataBucketTrait +dict +ElemLinkRefs +interoperate +nreserve +lastAssObject +theAssoc +TrackContainer +init +minRefCount +impl +OwnershipPolicy +otherElemLinkRefs +AssociativeIndexingPolicy +DataVector's +oper +IsSTLSequence +findProxyFromKey +newAss +mutators +addTrack +IncidentSvc +makeIndex +sgkey +StrictWeakOrdering +lastTrack +ClassID +classID +calaf +rbegin +containsAssociation +SetIndexingPolicy +ifndef +assocPointer +BaseConstReference +pos +PtrVector +ret +pre +params +BList +theAssocs +ArenaAllocatorBase +Dufus +GaudiClear +ppvInterface +reextracted +lookup +arghh +rhs +pointee +maxRefCount +config +toPersistentState +intL +Sep +hostDObjs +ClassIDSvc +ptr +BVec +intV +pvp +getDataSourcePointerFromGaudi +RNG +pTracks +Metafunction +ArenaHandleBase +shortIterFromLong +tCluster +successFlag +genreflex +DataProxyStorage +DataProxyStorageData +theJet +ElementType +ELVDEBUG +PtrList +AllocatorCreatorBase +asStorable +ArenaSharedHeapSTLAllocator +AthenaKernel +ChangeLog +getLastAssocation +nblock +dvlinfo +DVLInfo +PlainPtrDataLink +src +cout +IDtype +pcopy +jobO +Vec +resizePool +TestTools +dtors +DataPtr +tdefs +enums +ArenaSTLAllocator +findHostDObj +DataList's +toIndexedElement +stl +sizeof +svc +cptr +sss +checkreq +dobj +Vukotic +packageinfo +frexp +str +setData +MyObj +iter +DVLEltBase +AssociationType +clidsvc +CLIDSvc +backNavigation +toPersistent +theCluster +mustClear +storable +IInterface +AssociationObjectIterator +DefaultKey +TSS +inlined +Rajagopalan +makeFunc +savannah +ArenaBlock +multiset +GeneratorObjects +reverseLookup +DefaultState +Obreshkov +pred +malloc +myassert +AthExStoreGateExamples +DVLInfoBase +setOwner +txt +myCluster +FIXME +LIBSTDCXX +ArenaAllocatorCreator +Gemmeren +makeAllocator +JetTrackAssociation +IOVSvc +prev +newElement +beginAssociation +specializable +removeHostDObj +toAccessible +RefVector +EndEvent +PersistentState +tinfo +myassertion +elcnv +ctor +struct +vpvp +dereference +allocvec +getDataRef +ElementParameter +fdvl +AthenaROOTAccess +ControlTest +objectIndex +iHost +emacs +alloc +pElem +riid +accessor +setValid +DataObject +makeCurrent +dpint +symLink +decls +ElementLink +bb +anAss +DataSource +linkOffset +linkoffset +lookups +refVector's +DPSB +isValid +ibadlint +ForwardIterator +assoIndex +firstTrack +NDEBUG +NULLs +templated +endl +br +getDataPtr +venti +eg +dl +mainpage +VirtBases +DefaultIndexingPolicy +utests +reportStr +fd +FooDataVectorLink +CxxUtils +ivint +findInContainer +dv +DVLTYPE +RehashPolicy +ElementProxy +theObject +fn +JetTrackAssociationCollection +SGASSERTERROR +checkForRemap +iliint +toTransient +anotherString +ctors +AssociationLink +FolderItem +IdentContIndex +dereferences +iptrlint +intLF +DataModel +getLastAssociation +IP +indices +multithreaded +sstream +intLL +ld +destructors +Elts +ownPolicy +tryELRemap +li +rvalues +DeclareIndexingPolicy +Koenig +IndexingPolicies +nd +xyz +Austern +delArena +TrackParticleContainer +minSize +toAccessibleState +storagePolicy +NavFourMon +ArenaHandle +ConstDataList +ok +TrackParticle +ChronoStatSvc +ElemLinkRef +ns +findAssociation +Compwrapper +proxied +gccxml +RegisterDVLEltBaseInit +badI +DataPoolTest +os +stdcont +stdCont +initializer +lastAssoc +DVec +ri +BaseInfo +sg +ElemLinks +ElemLink's +targ +DirSearchPath +ELVRef +intVF +headp +BidirectionalIterator +cplusplus +Tavori +SGElvRef +dtor +enum +schaffer +intVL +vd +ForwardContainerConcept +InUse +sz +WG +ArenaPoolSTLAllocator +inline +typedefs +typedef's +Vo +getE +vp +sgname +sgName +rObj +SequenceIndexing +setStorable +trenta +AssociationMap +abc +thinning's +newElem +jobOptions +getAssociationObjects +myarena +lvalues +CategoryOrTraversal +PTAss +accessors +Mytype +raiseInvalidErrorBase +MyElement +rdata +adaptors +toPersistentNomap +DVL's +endcode +aFoo +ftemplate +ExtractKey +ArenaHandleBaseT +defaultDataSource +IdentifiedState +lvalue +ElementHolder +adaptor +preload +ifdef +AssociationBase +theContext +AssociationObject +ArenaHeader +ElementLinks +toIdentified +wrongvint +AssociationObjects +Baz +overridable +const +SGTools +NULLLINK +DefaultKeyState +getDataSourcePointerFunc +libstdc +persistable +SGgetDataSource +AthContainers +lexicographically +ve +wouldn +VIRTBASES2 +VIRTBASES1 +list2 +list1 +Sebastien +B3 +B2 +B1 +allocator +shouldn +unowned +D2Vec +v2 +v1 +preallocate +pCont +isConst +coverity +didn +doesn +AbsFluff +test1 +intL2 +intL2L +intL2F +resizing +dfluff5 +dfluff4 +isn +vd2 +vd1 +vb2 +vb1 +test2 +intV2 +intV2L +intV2F +intV3 +AthContainersInterfaces +auxid +clsname +getName +t's +AuxTypeMismatch +dst +bindex +aindex +getAuxID +Mutex +mutex +AUXTYPEREGISTRY +0's +'s +Krasznahorkay +UserDataStore +xAOD +UserDataStoreObj +IAthenaBarCode +barcode +eventABC +UserDataSvc +AthenaBarCode +abcHashFcn +0xFFFFFFFF +mapmap +lastIt +updateIt +IAuxTypeVector +AuxTypeVector +UDSLabelHashTable +ATHCONTAINER +upgradable +isSequence +IAuxStoreIO +IConstAuxStore +IAuxStore +AuxTypeRegistry +typeinfo +idx +UserData +Gaudi's +demangle +demangled +AuxBaseRegistry +aName +aCls +otherclass +anInt +aFloat +xclass +aBool +aPayload +context2 +vtable +setStore +releasePrivateStore +myint +makePrivateStore +acc +getters +auxdata +Myclass +myInt +vint1 +AuxElement +ExcBadPrivateStore +setIndex +AuxElementStandaloneData +ExcConstAuxData +privateData +privatePlaceholder +AUXELEMENTBASE +krasznaa +AuxStoreInternal +auxid's +getIOType +getIOData +AUXSTORESTANDALONE +clearCache +getData +getDataArray +AUXVECTORDATA +foreach +clearAux +copyAux +anotherInt +AuxStoreStandalone +AuxVectorData +anInt1 +anInt2 +someop +otherop +resortAux +swapElementsAux +moveAux +clearIndices +clearIndex +setIndices +trackIndices +initAuxVectorBase +ExcUntrackedSetStore +indexTrackingPolicy +bcont +AUXVECTORBASE +ResortAuxHelper +IndexTrackingPolicy +postconditions +vec +imap +rmap +auxindex +ii1 +dx +AuxVectorBase +cstore +anInt3 +first2 +first1 +isMostDerived +clearMostDerived +AuxData +DVLEltBaseInit +wscript +auxr +auxb +AAux +xint +xfloat +BAux +xint2 +CAux +v's +xinta +xintb +obj2 +mydata +MyClassComplete +MyClass +u1 +AUXELEMENTCOMPLETE +setMostDerived +testInsert +assignElement +assignBaseElement +ISMOSTDERIVEDFLAG +IsMostDerivedFlag +AuxElementComplete +MyStandaloneClass +mykeyAux +mykey +evtStore +getter +releasePrivateStoreForDtor +isAvailableWritable +isAvailable +AthLinks +wasn +hwafize +yml +hscript +xaod +mig14 +RootCore +SVN +AuxTypePlaceholder +findAuxID +Marcin +Obo +AuxStore +decl +unordered +VIRTBASES3 +kAutoSelected +AuxVectorData's +getEltSize +MacOS +Cintex +Asg +root6 +test3 +len +asm +CPUs +x86 +priori +RCU +optimizations +reallocations +auxdecor +auxids +getDecoration +getDecorationArray +constCache +getDataOol +getDecorationOol +clearDecorations +lxplus +test4 +D2 +'round +D2List + + + + +addFactory +makeFactory +AuxTypeVectorFactory +IAuxTypeVectorFactory +TVirtualCollectionProxy +extlock +aShort +aTest3 +aren +instantiations +ConstAccessor + + +normalizedTypeinfoName +demangling +auxdataConst +pyroot +getVecTypeName +getTypeName + + +root5 +macos +mapping's +anInt9 +ityp1 +FacTest3 +store2 +b1 +ExcNonowningContainer + + +emplace +cbegin + + +inplace +constStoreLink + + +typ +ExcUnknownAuxItem + + +adsasd +x2 +TypelessConstAccessor + + +excBadAuxVar +thinningHook +COPYAUXSTORETHINNED +copyThinned1 +copyThinned +nremaining +getThinnedFlags +TestThinningSvc +addRef +queryInterface +proxy2 +proxy3 +addToStore +sysInitialize +sysStart +sysStop +sysFinalize +sysReinitialize +sysRestart +FSMState +targetFSMState +setServiceManager +copyAuxStoreThinned +isAvailableWritableAsDecoration +BASES1 +BASES2 +BASES3 +SelectNoInstance +setOption +PackedContainer +PackedParameters +parms +TBuffer +uint32 +nelt +PACKEDCONVERTER +nmantissa +isFloat +isSigned +nbits +signedness +rescaled +createPersistent +athanalysisbase +xAODCore +getStore +AthAnalysisBase +Buttinger +decorCache +ut +PackedConverter +c2 +c1 +optname +AUXDATATRAITS +setoption +opt2 +xcls +opt3 +IAuxSetOption +instantiation +toPacked +objType +isEL +nullptr +allowMissing +redeclared +redeclare +TMethodCall +baseOffset +DVCollectionProxy +dataVectorAsELV +AthenaPool +Pers +guid +ViewVector +EL +dataVectorViewAsELV +SGdebug +decrement +Nowak +auxbase +copyForOutput +DataBucketVoid +baseOffset1 +tp +getDataArrayAllowMissing +isAvailableOol +CMake +Goetz +IStringPool +TestStore +CDV +ExcDVToELV +noreturn +NORETURN +ExcViewVectorNotView +ExcMissingBaseInfo +ExcMissingViewVectorCLID +getAuxIDs +TClassStreamer +TMemberStreamer +TError +TROOT +objp +PackedContainerStreamer +yetAnotherInt +aString +storelink +emptysort +DView +xvint +ushort +uchar +ulong +llong +ullong +intvec +uintvec +shortvec +ushortvec +chartvec +uchartvec +longvec +ulongvec +llongvec +ullongvec +floatvec +doublevec +boolvec +clearVector +ViewVectorBase +CurrentEventStore +xAODRootAccessInterfaces +ATEAM +endmsg +endreq +rootcore +CMakeLists +AtlasSTLAddReflexDict +3f +pInt +pFloat diff --git a/EDM/athena/Control/AthContainers/share/AuxElementComplete_test.ref b/EDM/athena/Control/AthContainers/share/AuxElementComplete_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxElementComplete_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/AuxElement_test.ref b/EDM/athena/Control/AthContainers/share/AuxElement_test.ref new file mode 100644 index 00000000..0d9ec6df --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxElement_test.ref @@ -0,0 +1,7 @@ +test1 +test2 +test_clear +test_copy +test_standalone +test_decoration +test_private_store diff --git a/EDM/athena/Control/AthContainers/share/AuxStoreInternal_test.ref b/EDM/athena/Control/AthContainers/share/AuxStoreInternal_test.ref new file mode 100644 index 00000000..4b991ef9 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxStoreInternal_test.ref @@ -0,0 +1,6 @@ +test1 +test2 +test3 +test4 +test5 +test_threading diff --git a/EDM/athena/Control/AthContainers/share/AuxStoreStandalone_test.ref b/EDM/athena/Control/AthContainers/share/AuxStoreStandalone_test.ref new file mode 100644 index 00000000..46696ef9 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxStoreStandalone_test.ref @@ -0,0 +1,3 @@ +test1 +Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout +AuxStoreInterna... ERROR FILE:LINE (const void*SG::AuxStoreInternal::getIODataInternal(unsigned long, bool) const): Requested variable aFloat (1) doesn't exist diff --git a/EDM/athena/Control/AthContainers/share/AuxTypeRegistry_test.ref b/EDM/athena/Control/AthContainers/share/AuxTypeRegistry_test.ref new file mode 100644 index 00000000..ad8d96b0 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxTypeRegistry_test.ref @@ -0,0 +1,5 @@ +test2 +test_placeholder +test_factories +test_get_by_ti +test_copyForOutput diff --git a/EDM/athena/Control/AthContainers/share/AuxTypeVectorFactory_test.ref b/EDM/athena/Control/AthContainers/share/AuxTypeVectorFactory_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxTypeVectorFactory_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/AuxTypeVector_test.ref b/EDM/athena/Control/AthContainers/share/AuxTypeVector_test.ref new file mode 100644 index 00000000..76983460 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxTypeVector_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/EDM/athena/Control/AthContainers/share/AuxVectorBase_test.ref b/EDM/athena/Control/AthContainers/share/AuxVectorBase_test.ref new file mode 100644 index 00000000..28c342a2 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxVectorBase_test.ref @@ -0,0 +1,12 @@ +test_set_store +test_set_store2 +test_get_data +test_reserve_resize +test_shift +test_get_types +test_copy_aux +test_copy_base_aux +test_clear_aux +test_swap_elements_aux +test_resort_aux +test_move diff --git a/EDM/athena/Control/AthContainers/share/AuxVectorData_test.ref b/EDM/athena/Control/AthContainers/share/AuxVectorData_test.ref new file mode 100644 index 00000000..7bc1a900 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/AuxVectorData_test.ref @@ -0,0 +1,8 @@ +test_get_data +test_swap +test_get_types +test_decoration +test_move +test_setoption +test_storelink +test_threading diff --git a/EDM/athena/Control/AthContainers/share/DVLCast_test.ref b/EDM/athena/Control/AthContainers/share/DVLCast_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthContainers/share/DVLDataBucket_test.ref b/EDM/athena/Control/AthContainers/share/DVLDataBucket_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthContainers/share/DVLInfo_test.ref b/EDM/athena/Control/AthContainers/share/DVLInfo_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthContainers/share/DVLIterator_test.ref b/EDM/athena/Control/AthContainers/share/DVLIterator_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthContainers/share/DVL_iter_swap_test.ref b/EDM/athena/Control/AthContainers/share/DVL_iter_swap_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthContainers/share/DataList_test.ref b/EDM/athena/Control/AthContainers/share/DataList_test.ref new file mode 100644 index 00000000..e146565e --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataList_test.ref @@ -0,0 +1,98 @@ +*** DataList_test test1 BEGIN *** +intL: 0x5fe290 0x5fe210 0x5fe250 +7 1 3 +intL2: 0x5fe2b0 0x5fe2f0 0x5fe330 0x5fe370 0x5fe3f0 +5 5 5 5 6 +dfluff: 0x5fe670 0x5fe720 + --> Now deleting copied list, but it should not delete elements as it does not own them. You should not see message of Element Destructor + <-- delete done + --> Now deleting list copied via iterator. You should NOT see the elements being deleted + <-- delete done + --> Now resizing DataList<DerivedFluff> + --> You should see one DerivedFluff object being deleted + ----> Destructor of AbsFluff called for 0x5fe720. After return, left alive 1 + <-- resize done + --> Now deleting DataList<DerivedFluff>. You should see all remaining DerivedFluff objects being deleted + ----> Destructor of AbsFluff called for 0x5fe670. After return, left alive 0 + <-- delete done + --> Now erasing one element of the DerivedFluff container. You should see one instance being deleted + ----> Destructor of AbsFluff called for 0x5fd600. After return, left alive 3 + <-- erase done + --> Now resizing view container. You should NOT see the elements being deleted + <-- resize done + --> Now deleting two DerivedFluff instances + ----> Destructor of AbsFluff called for 0x5fef00. After return, left alive 14 + ----> Destructor of AbsFluff called for 0x5fefb0. After return, left alive 13 + <-- delete done + ----> Destructor of AbsFluff called for 0x5ff410. After return, left alive 17 + ----> Destructor of AbsFluff called for 0x5ff360. After return, left alive 16 +--> We have purposedly duplicated an element of pBadFluff: 0x5ff410 0x5ff4c0 0x5ff410 +---> now we should see a warning message from ~DataList +WARNING: duplicated pointer found in a DataList of DerivedFluff owning its elements! 0x5ff410 + ----> Destructor of AbsFluff called for 0x5ff410. After return, left alive 17 + ----> Destructor of AbsFluff called for 0x5ff4c0. After return, left alive 16 +*** DataList_test test1 OK *** + ----> Destructor of AbsFluff called for 0x5feed0. After return, left alive 15 + ----> Destructor of AbsFluff called for 0x5fef00. After return, left alive 14 + ----> Destructor of AbsFluff called for 0x5fefb0. After return, left alive 13 + ----> Destructor of AbsFluff called for 0x5fd600. After return, left alive 12 + ----> Destructor of AbsFluff called for 0x5fe7d0. After return, left alive 11 + ----> Destructor of AbsFluff called for 0x5fe970. After return, left alive 10 + ----> Destructor of AbsFluff called for 0x5fe9e0. After return, left alive 9 + ----> Destructor of AbsFluff called for 0x5fea50. After return, left alive 8 + ----> Destructor of AbsFluff called for 0x5feac0. After return, left alive 7 + ----> Destructor of AbsFluff called for 0x5feb50. After return, left alive 6 + ----> Destructor of AbsFluff called for 0x5febe0. After return, left alive 5 + ----> Destructor of AbsFluff called for 0x5fec70. After return, left alive 4 + ----> Destructor of AbsFluff called for 0x5fed00. After return, left alive 3 + ----> Destructor of AbsFluff called for 0x5fe670. After return, left alive 2 + ----> Destructor of AbsFluff called for 0x5fe720. After return, left alive 1 + ----> Destructor of AbsFluff called for 0x5fe800. After return, left alive 0 +*** DataList_test [test2] BEGIN *** +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fe210 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fe330 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fe430 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fe370 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff4f0 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff4b0 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff670 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff790 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff7f0 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff970 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ffd30 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fff30 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5ff4f0 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x6000d0 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fea90 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fea50 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fec10 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fed30 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fed90 +WARNING: duplicated pointer found in a DataList of AA owning its elements! 0x5fef10 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x600550 +WARNING: duplicated pointer found in a DataList of P owning its elements! 0x600b08 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x5fec90 +WARNING: duplicated pointer found in a DataList of P owning its elements! 0x600908 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x5ff850 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x5ff0f0 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x5ff9d0 +WARNING: duplicated pointer found in a DataList of P owning its elements! 0x600768 +WARNING: duplicated pointer found in a DataList of P owning its elements! 0x600768 +WARNING: duplicated pointer found in a DataList of P owning its elements! 0x600768 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x601240 +WARNING: duplicated pointer found in a DataList of R owning its elements! 0x6005d8 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x600580 +WARNING: duplicated pointer found in a DataList of R owning its elements! 0x5fea88 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x5ffc90 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x5ffc50 +WARNING: duplicated pointer found in a DataList of M owning its elements! 0x600c70 +WARNING: duplicated pointer found in a DataList of R owning its elements! 0x601148 +WARNING: duplicated pointer found in a DataList of R owning its elements! 0x601148 +WARNING: duplicated pointer found in a DataList of R owning its elements! 0x601148 +name: DataList<AA> + clid, vers, is_do: 26fd 1 0 +name: DataList<BB> + clid, vers, is_do: 26fe 1 0 +name: DataList<CC> + clid, vers, is_do: 854e980 2 0 +*** DataList_test [test2] OK *** diff --git a/EDM/athena/Control/AthContainers/share/DataVector_a_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_a_test.ref new file mode 100644 index 00000000..f81f1fbe --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_a_test.ref @@ -0,0 +1 @@ +test2_a diff --git a/EDM/athena/Control/AthContainers/share/DataVector_b_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_b_test.ref new file mode 100644 index 00000000..13cf9aad --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_b_test.ref @@ -0,0 +1 @@ +test2_b diff --git a/EDM/athena/Control/AthContainers/share/DataVector_c_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_c_test.ref new file mode 100644 index 00000000..a668f6db --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_c_test.ref @@ -0,0 +1 @@ +test2_c diff --git a/EDM/athena/Control/AthContainers/share/DataVector_d_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_d_test.ref new file mode 100644 index 00000000..4819c2be --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_d_test.ref @@ -0,0 +1 @@ +test2_d diff --git a/EDM/athena/Control/AthContainers/share/DataVector_e_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_e_test.ref new file mode 100644 index 00000000..fbbdf285 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_e_test.ref @@ -0,0 +1 @@ +test2_e diff --git a/EDM/athena/Control/AthContainers/share/DataVector_f_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_f_test.ref new file mode 100644 index 00000000..588e8878 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_f_test.ref @@ -0,0 +1 @@ +test2_f diff --git a/EDM/athena/Control/AthContainers/share/DataVector_test.ref b/EDM/athena/Control/AthContainers/share/DataVector_test.ref new file mode 100644 index 00000000..c58f991b --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/DataVector_test.ref @@ -0,0 +1,55 @@ +*** DataVector_test test1 BEGIN *** +intV: 0x1052bf0 0x1052bb0 0x1052bd0 +7 1 3 +intV2: 0x1052b90 0x1052c40 0x1052c60 0x1052c80 0x104e890 +5 5 5 5 6 +dfluff: 0x10590b0 0x1059050 + --> Now deleting copied vector, but it should not delete elements as it does not own them. You should not see message of Element Destructor + <-- delete done + --> Now deleting vector copied via iterator. You should NOT see the elements being deleted + <-- delete done + --> Now resizing DataVector<DerivedFluff> + --> You should see one DerivedFluff object being deleted + ----> Destructor of AbsFluff called for 0x1059050. After return, left alive 1 + <-- resize done + --> Now deleting DataVector<DerivedFluff>. You should see all remaining DerivedFluff objects being deleted + ----> Destructor of AbsFluff called for 0x10590b0. After return, left alive 0 + <-- delete done + --> Now erasing one element of the DerivedFluff container. You should see one instance being deleted + ----> Destructor of AbsFluff called for 0x10590b0. After return, left alive 3 + <-- erase done + --> Now resizing view container. You should NOT see the elements being deleted + <-- resize done + --> Now deleting two DerivedFluff instances + ----> Destructor of AbsFluff called for 0x1059860. After return, left alive 14 + ----> Destructor of AbsFluff called for 0x1059bd0. After return, left alive 13 + <-- delete done + ----> Destructor of AbsFluff called for 0x1059d80. After return, left alive 17 + ----> Destructor of AbsFluff called for 0x1059cc0. After return, left alive 16 +*** DataVector_test OK *** + ----> Destructor of AbsFluff called for 0x1059860. After return, left alive 15 + ----> Destructor of AbsFluff called for 0x1059b40. After return, left alive 14 + ----> Destructor of AbsFluff called for 0x1059c00. After return, left alive 13 + ----> Destructor of AbsFluff called for 0x10590b0. After return, left alive 12 + ----> Destructor of AbsFluff called for 0x1059390. After return, left alive 11 + ----> Destructor of AbsFluff called for 0x1059420. After return, left alive 10 + ----> Destructor of AbsFluff called for 0x10594e0. After return, left alive 9 + ----> Destructor of AbsFluff called for 0x1059570. After return, left alive 8 + ----> Destructor of AbsFluff called for 0x1059650. After return, left alive 7 + ----> Destructor of AbsFluff called for 0x10596b0. After return, left alive 6 + ----> Destructor of AbsFluff called for 0x1059740. After return, left alive 5 + ----> Destructor of AbsFluff called for 0x10597d0. After return, left alive 4 + ----> Destructor of AbsFluff called for 0x10598f0. After return, left alive 3 + ----> Destructor of AbsFluff called for 0x1059050. After return, left alive 2 + ----> Destructor of AbsFluff called for 0x1059110. After return, left alive 1 + ----> Destructor of AbsFluff called for 0x10592a0. After return, left alive 0 +test2 +name: DataVector<AA> + clid, vers, is_do: 2699 1 0 +name: DataVector<BB> + clid, vers, is_do: 269a 1 0 +name: DataVector<CC> + clid, vers, is_do: aa4491f 2 0 +test_auxdata +test_emptysort +test_insertmove diff --git a/EDM/athena/Control/AthContainers/share/ElementProxy_test.ref b/EDM/athena/Control/AthContainers/share/ElementProxy_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthContainers/share/IsMostDerivedFlag_test.ref b/EDM/athena/Control/AthContainers/share/IsMostDerivedFlag_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/IsMostDerivedFlag_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/PackedContainer_test.ref b/EDM/athena/Control/AthContainers/share/PackedContainer_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/PackedContainer_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/PackedConverter_test.ref b/EDM/athena/Control/AthContainers/share/PackedConverter_test.ref new file mode 100644 index 00000000..fadbf1d8 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/PackedConverter_test.ref @@ -0,0 +1,4 @@ +test1 +test2 +test3 +test4 diff --git a/EDM/athena/Control/AthContainers/share/PackedParameters_test.ref b/EDM/athena/Control/AthContainers/share/PackedParameters_test.ref new file mode 100644 index 00000000..76983460 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/PackedParameters_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/EDM/athena/Control/AthContainers/share/ViewVectorBase_test.ref b/EDM/athena/Control/AthContainers/share/ViewVectorBase_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/ViewVectorBase_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/ViewVector_test.ref b/EDM/athena/Control/AthContainers/share/ViewVector_test.ref new file mode 100644 index 00000000..fadbf1d8 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/ViewVector_test.ref @@ -0,0 +1,4 @@ +test1 +test2 +test3 +test4 diff --git a/EDM/athena/Control/AthContainers/share/copyAuxStoreThinned_test.ref b/EDM/athena/Control/AthContainers/share/copyAuxStoreThinned_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/copyAuxStoreThinned_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/copyThinned_test.ref b/EDM/athena/Control/AthContainers/share/copyThinned_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/copyThinned_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/dataVectorAsELV_test.ref b/EDM/athena/Control/AthContainers/share/dataVectorAsELV_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/dataVectorAsELV_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/debug_test.ref b/EDM/athena/Control/AthContainers/share/debug_test.ref new file mode 100644 index 00000000..2bf7b6e7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/debug_test.ref @@ -0,0 +1,128 @@ +test1 +bar::foo +test2 +... set ... +2 ::xint [int] +3 ::xfloat [float] +... store ... +2 ::xint [int] +3 ::xfloat [float] +2 ::xint [int] +3 ::xfloat [float] +... vec ... +2 ::xint [int] +3 ::xfloat [float] +2 ::xint [int] +3 ::xfloat [float] +... elt ... +2 ::xint [int] +3 ::xfloat [float] +2 ::xint [int] +3 ::xfloat [float] +test3 +a_int -2 +a_uint 10 +a_short 10 +a_ushort 20 +a_char a +a_uchar b +a_long 50 +a_ulong 60 +a_llong 50 +a_ullong 60 +a_float 123.500 +a_double 223.500 +a_bool 1 +a_intvec [1, -2, 3] +a_uintvec [1, 2, 3] +a_shortvec [4, 5, 6] +a_ushortvec [7, 8, 9] +a_chartvec [a, b, c] +a_uchartvec [d, e, f] +a_longvec [10, 11, 12] +a_ulongvec [13, 14, 15] +a_llongvec [16, 17, 18] +a_ullongvec [19, 20, 21] +a_floatvec [1.100, 1.200, 1.300] +a_doublevec [2.100, 2.200, 2.300] +a_boolvec [1, 0, 1] +a_a <??? A> +test4 +... print elt 1 from store +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +... print elt 0 from store +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] + +... print entire store +=== Element 0 +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] +=== Element 1 +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +=== Element 2 +::xfloat 3.500 +::xint 3 +::xvint [16, 17, 18] +=== Element 0 +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] +=== Element 1 +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +=== Element 2 +::xfloat 3.500 +::xint 3 +::xvint [16, 17, 18] + +... print elt 1 from vec +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +... print elt 0 from vec +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] + +... print entire vec +=== Element 0 +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] +=== Element 1 +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +=== Element 2 +::xfloat 3.500 +::xint 3 +::xvint [16, 17, 18] +=== Element 0 +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] +=== Element 1 +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +=== Element 2 +::xfloat 3.500 +::xint 3 +::xvint [16, 17, 18] + +... print elt 1 +::xfloat 2.500 +::xint 2 +::xvint [13, 14, 15] +... print elt 0 +::xfloat 1.500 +::xint 1 +::xvint [10, 11, 12] diff --git a/EDM/athena/Control/AthContainers/share/error_test.ref b/EDM/athena/Control/AthContainers/share/error_test.ref new file mode 100644 index 00000000..953ef5fb --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/error_test.ref @@ -0,0 +1,4 @@ +Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout +context ERROR ../test/error_test.cxx:16 (void test1()): message +Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout +context2 ERROR ../test/error_test.cxx:18 (void test1()): int diff --git a/EDM/athena/Control/AthContainers/share/exceptions_test.ref b/EDM/athena/Control/AthContainers/share/exceptions_test.ref new file mode 100644 index 00000000..7e933c4d --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/exceptions_test.ref @@ -0,0 +1,23 @@ +test1 +SG::ExcNoAuxStore: Requested aux data item `::foo' (0) but there is no associated aux data store. +SG::ExcNoAuxStore: Requested aux data item `cl::bar' (1) but there is no associated aux data store. +SG::ExcNoAuxStore: Requested aux data item but there is no associated aux data store. +SG::ExcNoAuxStore: Operation attempted on container with no associated aux data store: op +SG::ExcBadAuxVar: Attempt to retrieve nonexistent aux data item `::foo' (0). +SG::ExcConstAuxData: Non-const operation `someop' performed on const aux data `::foo' (0). +SG::ExcConstAuxData: Non-const operation `otherop' performed on const aux data . +SG::ExcUntrackedSetStore: Attempt to set aux data store on container that doesn't track indices, or disable index tracking for a container with aux data. +SG::ExcBadPrivateStore: Bad use of private store: op +SG::ExcAuxTypeMismatch: Type mismatch for aux variable `::foo' (0); old type is float new type is int +SG::ExcAuxTypeMismatch: Type mismatch for aux variable `cl::bar' (1); old type is float new type is int +SG::ExcInsertionInBaseClass: Attempted to do op on a int base class of float; can only be done on the most-derived class. +SG::ExcStoreLocked: Attempted to modify auxiliary data in a locked store: `::foo' (0) +SG::ExcStoreLocked: Attempted to modify auxiliary data in a locked store: op +SG::ExcNonowningContainer: Attempted to insert a unique_ptr to a non-owning container. +SG::ExcUnknownAuxItem: Unknown aux data item foo +SG::ExcUnknownAuxItem: Unknown aux data item bar::foo +SG::ExcUnknownAuxItem: Unknown aux data item bar::foo (of type int) +SG::ExcDVToELV: Can't convert DataVector to vector of ElementLinks: why +ViewVector not in view mode. +ViewVector intwas used in a context that requires a CLID, but no CLID was available. Make sure a VIEWVECTOR_CLASS_DEF declaration exists for the class in a library that has been loaded. +Ownership mismatch for insertMove. diff --git a/EDM/athena/Control/AthContainers/share/foreach_test.ref b/EDM/athena/Control/AthContainers/share/foreach_test.ref new file mode 100644 index 00000000..3b6d9b5e --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/foreach_test.ref @@ -0,0 +1,2 @@ +test1 +10 11 12 13 14 15 16 17 18 19 diff --git a/EDM/athena/Control/AthContainers/share/getThinnedFlags_test.ref b/EDM/athena/Control/AthContainers/share/getThinnedFlags_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/getThinnedFlags_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/normalizedTypeinfoName_test.ref b/EDM/athena/Control/AthContainers/share/normalizedTypeinfoName_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/normalizedTypeinfoName_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainers/share/removeDuplicates_test.ref b/EDM/athena/Control/AthContainers/share/removeDuplicates_test.ref new file mode 100644 index 00000000..0f6618e5 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/removeDuplicates_test.ref @@ -0,0 +1,8 @@ +--> We have purposedly duplicated an element of pDV: 0x8317db0 0x8317dd0 0x8317db0 +---> now we should see a warning message from ~DataVector +DataVector ERROR: duplicated pointer found in a DataVector of int owning its elements! 0x8317db0 +<--- ~DataVector returns +--> We have purposedly duplicated an element of pDL: 0x8317dd0 0x8317de0 0x8317dd0 +---> now we should see a warning message from ~DataList +DataVector ERROR: duplicated pointer found in a DataVector of int owning its elements! 0x8317dd0 +<--- ~DataList returns diff --git a/EDM/athena/Control/AthContainers/share/threading_nothreads_test.ref b/EDM/athena/Control/AthContainers/share/threading_nothreads_test.ref new file mode 100644 index 00000000..7aa5a891 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/threading_nothreads_test.ref @@ -0,0 +1,17 @@ +test1 +lock_shared +unlock_shared +test2 +lock_upgrade +unlock_upgrade +lock_upgrade +unlock_upgrade_and_lock +unlock +lock_upgrade +unlock_upgrade_and_lock +unlock +test3 +test4 +ctor 1 +ctor 2 +dtor 2 diff --git a/EDM/athena/Control/AthContainers/share/threading_test.ref b/EDM/athena/Control/AthContainers/share/threading_test.ref new file mode 100644 index 00000000..7aa5a891 --- /dev/null +++ b/EDM/athena/Control/AthContainers/share/threading_test.ref @@ -0,0 +1,17 @@ +test1 +lock_shared +unlock_shared +test2 +lock_upgrade +unlock_upgrade +lock_upgrade +unlock_upgrade_and_lock +unlock +lock_upgrade +unlock_upgrade_and_lock +unlock +test3 +test4 +ctor 1 +ctor 2 +dtor 2 diff --git a/EDM/athena/Control/AthContainers/src/copyAuxStoreThinned.cxx b/EDM/athena/Control/AthContainers/src/copyAuxStoreThinned.cxx new file mode 100644 index 00000000..1112306e --- /dev/null +++ b/EDM/athena/Control/AthContainers/src/copyAuxStoreThinned.cxx @@ -0,0 +1,113 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/Root/copyAuxStoreThinned.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Helper to copy an aux store while applying thinning. + */ + + +#include "AthContainers/tools/copyAuxStoreThinned.h" +#include "AthContainers/tools/getThinnedFlags.h" +#include "AthContainers/tools/foreach.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IAuxStoreIO.h" +#include "AthenaKernel/IThinningSvc.h" +#include "CxxUtils/no_sanitize_undefined.h" +#include <vector> + + +namespace SG { + + +/** + * @brief Helper to copy an aux store while applying thinning. + * @param orig Source aux store from which to coy. + * @param copy Destination aux store to which to copy. + * @param svc The thinning service. + * + * @c orig and @c copy are both auxiliary store objects. + * The data from @c orig will be copied to @c copy, with individual + * elements removed according to thinning recorded for @c orig in @c svc. + */ +void copyAuxStoreThinned NO_SANITIZE_UNDEFINED + (const SG::IConstAuxStore& orig, + SG::IAuxStore& copy, + IThinningSvc* svc) +{ + copy.resize(0); + size_t size = orig.size(); + if (size == 0) return; + size_t nremaining = 0; + std::vector<unsigned char> flags; + bool thinned = getThinnedFlags (svc, orig, nremaining, flags); + + // Access the auxiliary type registry: + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + + // The auxiliary IDs that the original container has: + SG::auxid_set_t auxids = orig.getAuxIDs(); + + SG::auxid_set_t dyn_auxids; + SG::auxid_set_t sel_auxids; + if (const IAuxStoreIO* iio = dynamic_cast<const IAuxStoreIO*> (&orig)) { + dyn_auxids = iio->getDynamicAuxIDs(); + sel_auxids = iio->getSelectedAuxIDs(); + } + + copy.resize (nremaining); + + // Loop over all the variables of the original container: + ATHCONTAINERS_FOREACH (SG::auxid_t auxid, auxids) { + // Skip null auxids (happens if we don't have the dictionary) + if(auxid == SG::null_auxid) continue; + + // Skip non-selected dynamic variables. + if (dyn_auxids.count(auxid) > 0 && sel_auxids.count(auxid) == 0) + continue; + + // Access the source variable: + const void* src = orig.getData (auxid); + + if (!src) continue; + + // FIXME: Do this via proper interfaces. + if (const IAuxStoreIO* iio = dynamic_cast<const IAuxStoreIO*> (&orig)) + { + const std::type_info* typ = iio->getIOType (auxid); + if (strstr (typ->name(), "PackedContainer") != nullptr) { + // This cast gets a warning from the undefined behavior sanitizer + // in gcc6. Done like this deliberately for now, so suppress ubsan + // checking for this function. + const PackedParameters& parms = + reinterpret_cast<const PackedContainer<int>* > (iio->getIOData (auxid))->parms(); + copy.setOption (auxid, AuxDataOption ("nbits", parms.nbits())); + copy.setOption (auxid, AuxDataOption ("float", parms.isFloat())); + copy.setOption (auxid, AuxDataOption ("signed", parms.isSigned())); + copy.setOption (auxid, AuxDataOption ("rounding", parms.rounding())); + copy.setOption (auxid, AuxDataOption ("nmantissa", parms.nmantissa())); + copy.setOption (auxid, AuxDataOption ("scale", parms.scale())); + } + } + + // Create the target variable: + void* dst = copy.getData (auxid, nremaining, nremaining); + + // Copy over all elements, with thinning. + for (std::size_t isrc = 0, idst = 0; isrc < size; ++isrc) { + if (!thinned || !flags[isrc]) { + r.copyForOutput (auxid, dst, idst, src, isrc); + ++idst; + } + } + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/src/getThinnedFlags.cxx b/EDM/athena/Control/AthContainers/src/getThinnedFlags.cxx new file mode 100644 index 00000000..d979c88b --- /dev/null +++ b/EDM/athena/Control/AthContainers/src/getThinnedFlags.cxx @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/Root/getThinnedFlags.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Return vector of flags giving which container elements were thinned. + */ + + +#include "AthContainers/tools/getThinnedFlags.h" +#include "AthenaKernel/IThinningSvc.h" + + +namespace SG { + + +/** + * @brief Return vector of flags giving which container elements were thinned. + * @param svc The thinning service (or 0). + * @param container The container for which to find thinning information. + * @param size Size of the container. + * @param nremaining[out] The number of elements in the container not thinned. + * @param flags[out] Array telling which elements were thinned. + * + * This is and out-of-line helper for @c getThinnedFlags. + */ +bool getThinnedFlags1 (IThinningSvc* svc, + const void* container, + size_t size, + size_t& nremaining, + std::vector<unsigned char>& flags) +{ + nremaining = size; + flags.clear(); + if (!svc) return false; + if (size == 0) return false; + if (!svc->thinningOccurred (container)) return false; + + nremaining = 0; + flags.resize (size); + for (size_t i = 0; i < size; i++) { + flags[i] = IThinningSvc::isThinned (svc->index (container, i)); + if (!flags[i]) ++nremaining; + } + return true; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainers/test/AthContainers.xml b/EDM/athena/Control/AthContainers/test/AthContainers.xml new file mode 100644 index 00000000..ce4475e5 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AthContainers.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AthContainersTest" type="makecheck" suite="Examples"> + <package>Control/AthContainers</package> + <timelimit>40</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov, snyder@bnl.gov, binet@cern.ch</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/AthContainers/test/AuxElementComplete_test.cxx b/EDM/athena/Control/AthContainers/test/AuxElementComplete_test.cxx new file mode 100644 index 00000000..67d8908f --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxElementComplete_test.cxx @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxElementComplete_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Regression tests for AuxElementComplete + */ + + +#undef NDEBUG +#include "AthContainers/AuxElementComplete.h" +#include <iostream> +#include <cassert> + + +class Elt + : public SG::AuxElement +{ +public: + Elt() : x(0) {} + Elt(int the_x) : x(the_x) {} + Elt(const Elt& other) + : SG::AuxElement(other), + x(other.x) + {} + + Elt& operator= (const Elt&) = default; + + int& ityp1() + { + static Accessor<int> acc ("anInt"); + return acc (*this); + } + + int ityp1() const + { + static Accessor<int> acc ("anInt"); + return acc (*this); + } + + float& ftyp1() + { + static Accessor<float> acc ("aFloat"); + return acc (*this); + } + + float ftyp1() const + { + static Accessor<float> acc ("aFloat"); + return acc (*this); + } + + int x; +}; + + +typedef SG::AuxElementComplete<Elt> EltComplete; + + +void test1() +{ + std::cout << "test1\n"; + EltComplete elt; + assert (elt.x == 0); + + EltComplete elt2 (10); + assert (elt2.x == 10); + + Elt::Accessor<int> ityp2 ("anotherInt"); + + elt.ityp1() = 1; + ityp2(elt) = 2; + elt.ftyp1() = 1.5; + + assert (elt.ityp1() == 1); + assert (ityp2(elt) == 2); + assert (elt.ftyp1() == 1.5); + + elt.x = 20; + EltComplete elt3 (elt); + assert (elt3.x == 20); + assert (elt3.ityp1() == 1); + assert (ityp2(elt3) == 2); + assert (elt3.ftyp1() == 1.5); + assert (elt3.container() != elt.container()); + + elt.ityp1() = 31; + assert (elt3.ityp1() == 1); + elt3 = elt; + assert (elt3.ityp1() == 31); + assert (elt3.container() != elt.container()); + +#if __cplusplus > 201100 + elt.ityp1() = 41; + assert (elt3.ityp1() == 31); + elt3 = std::move(elt); + assert (elt3.ityp1() == 41); + assert (elt3.container() != elt.container()); + + EltComplete elt4 (std::move(elt)); + assert (elt4.x == 20); + assert (elt4.ityp1() == 41); + assert (ityp2(elt4) == 2); + assert (elt4.ftyp1() == 1.5); + assert (elt4.container() != elt.container()); +#endif + + elt3.ityp1() = 41; + elt.releasePrivateStore(); + assert (elt.container() == 0); + assert (elt3.x == 20); + assert (elt3.ityp1() == 41); + assert (ityp2(elt3) == 2); + assert (elt3.ftyp1() == 1.5); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/AuxElement_test.cxx b/EDM/athena/Control/AthContainers/test/AuxElement_test.cxx new file mode 100644 index 00000000..7bd7199f --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxElement_test.cxx @@ -0,0 +1,671 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxElement_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Regression tests for AuxElement + */ + +#undef NDEBUG +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/exceptions.h" +#include "TestTools/expect_exception.h" +#include "CxxUtils/make_unique.h" +#include <iostream> +#include <cassert> +#include <memory> +#include <vector> +#include <map> + + +#include "auxid_set_equal.icc" + + +namespace SG { + +class AuxVectorBase + : public SG::AuxVectorData +{ +public: + virtual size_t size_v() const { return 10; } + virtual size_t capacity_v() const { return 10; } + + using SG::AuxVectorData::setStore; + void set (SG::AuxElement& b, size_t index) + { + b.setIndex (index, this); + } + void clear (SG::AuxElement& b) + { + b.setIndex (0, 0); + } + + static + void clearAux (SG::AuxElement& b) + { + b.clearAux(); + } + + static + void copyAux (SG::AuxElement& a, const SG::AuxElement& b) + { + a.copyAux (b); + } + + static + void testAuxElementCtor (SG::AuxVectorData* container, + size_t index) + { + SG::AuxElement bx (container, index); + assert (bx.index() == index); + assert (bx.container() == container); + } +}; + + +} // namespace SG + + +class ConstAuxStoreTest + : public SG::IConstAuxStore +{ +public: + virtual const void* getData (SG::auxid_t auxid) const; + virtual const SG::auxid_set_t& getAuxIDs() const { return m_set; } + virtual void* getDecoration (SG::auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) { std::abort(); } + virtual void lock() { std::abort(); } + virtual void clearDecorations() { std::abort(); } + virtual size_t size() const { std::abort(); } + + void add (SG::auxid_t auxid, std::unique_ptr<std::vector<float> > vec); + + SG::auxid_set_t m_set; + typedef std::vector<float> vec_t; + typedef std::map<SG::auxid_t, std::unique_ptr<vec_t> > map_t; + map_t m_vecs; +}; + + +const void* ConstAuxStoreTest::getData (SG::auxid_t auxid) const +{ + map_t::const_iterator it = m_vecs.find (auxid); + if (it != m_vecs.end()) + return it->second->data(); + return 0; +} + +void ConstAuxStoreTest::add (SG::auxid_t auxid, + std::unique_ptr<std::vector<float> > vec) +{ + m_vecs[auxid] = std::move(vec); +} + + + +void test1() +{ + std::cout << "test1\n"; + + SG::AuxElement::ConstAccessor<int> ityp1_c ("anInt"); + SG::AuxElement::Accessor<int> ityp1 ("anInt"); + SG::AuxElement::Accessor<float> ftyp1 ("aFloat"); + + SG::AuxElement b; + assert (b.index() == 0); + assert (b.container() == 0); + assert (b.getAuxIDs().empty()); + + assert (!ityp1.isAvailable(b)); + assert (!ityp1_c.isAvailable(b)); + assert (!ityp1.isAvailableWritable(b)); + + SG::AuxVectorBase v; + v.set (b, 5); + assert (b.index() == 5); + assert (b.container() == &v); + + assert (!ityp1.isAvailable(b)); + assert (!ityp1.isAvailableWritable(b)); + + SG::AuxVectorBase::testAuxElementCtor (&v, 10); + + SG::AuxStoreInternal store; + v.setStore (&store); + + assert (!ityp1.isAvailable(b)); + assert (!ftyp1.isAvailable(b)); + assert (!ityp1.isAvailableWritable(b)); + assert (!ftyp1.isAvailableWritable(b)); + + ityp1(b) = 3; + ftyp1(b) = 1.5; + assert (ityp1(b) == 3); + assert (ityp1_c(b) == 3); + assert (ftyp1(b) == 1.5); + assert (b.auxdata<int>("anInt") == 3); + assert (b.auxdataConst<int>("anInt") == 3); + b.auxdata<int>("anInt") = 1; + assert (ityp1(b) == 1); + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t ityp1_id = r.getAuxID<int> ("anInt"); + SG::auxid_t ftyp1_id = r.getAuxID<float> ("aFloat"); + SG::auxid_set_t auxids; + auxids.insert (ityp1_id); + auxids.insert (ftyp1_id); + assert (b.getAuxIDs() == auxids); + + assert (ityp1_c.auxid() == ityp1_id); + assert (ityp1.auxid() == ityp1_id); + assert (ftyp1.auxid() == ftyp1_id); + + assert (ityp1(v, 5) == 1); + ityp1(v, 5) = 2; + assert (ityp1(v, 5) == 2); + assert (ityp1.getDataArray(v)[5] == 2); + ityp1.getDataArray(v)[5] = 1; + assert (ityp1.getDataArray(v)[5] == 1); + + assert (ityp1.isAvailable(b)); + assert (ftyp1.isAvailable(b)); + assert (ityp1.isAvailableWritable(b)); + assert (ftyp1.isAvailableWritable(b)); + + const SG::AuxElement& cb = b; + assert (ityp1(cb) == 1); + assert (ftyp1(cb) == 1.5); + + const SG::AuxVectorBase& cv = v; + assert (ityp1(cv, 5) == 1); + assert (ityp1.getDataArray(cv)[5] == 1); + + SG::AuxElement b2 = b; + assert (b2.index() == 0); + assert (b2.container() == 0); + + SG::AuxElement b3; + SG::AuxVectorBase v3; + v3.set (b3, 6); + SG::AuxStoreInternal store3; + v3.setStore (&store3); + assert (b3.index() == 6); + assert (b3.container() == &v3); + + b3 = b; + assert (b3.index() == 6); + assert (b3.container() == &v3); + assert (ityp1(b3) == 1); + assert (ftyp1(b3) == 1.5); + +#if __cplusplus > 201100 + ityp1(b) = 21; + b3 = std::move(b); + assert (b3.index() == 6); + assert (b3.container() == &v3); + assert (ityp1(b3) == 21); + assert (ftyp1(b3) == 1.5); + + SG::AuxElement b4 = std::move(b); + assert (b4.index() == 0); + assert (b4.container() == 0); +#endif + + ityp1.set (b3, 22); + assert (ityp1(b3) == 22); + + v.setStore ((SG::IConstAuxStore*)&store); + assert (ftyp1(cb) == 1.5); + + SG::AuxElement::TypelessConstAccessor ftyp1a ("aFloat"); + assert (ftyp1a.isAvailable (b3)); + assert (*reinterpret_cast<const float*>(ftyp1a (b3)) == 1.5); + assert (*reinterpret_cast<const float*>(ftyp1a (v3, 6)) == 1.5); + assert ((reinterpret_cast<const float*>(ftyp1a.getDataArray (v3)))[6] == 1.5); + + assert (ftyp1a.auxid() == ftyp1_id); + + EXPECT_EXCEPTION (SG::ExcUnknownAuxItem, + SG::AuxElement::TypelessConstAccessor ("adsasd")); + SG::AuxElement::TypelessConstAccessor x1 (typeid(int), "adsasd"); + EXPECT_EXCEPTION (SG::ExcUnknownAuxItem, + SG::AuxElement::TypelessConstAccessor (typeid(SG::AuxVectorBase), + "x2")); +} + + +class Elt + : public SG::AuxElement +{ +public: + Elt() : x(0) { makePrivateStore(); } + Elt(int the_x) : x(the_x) { makePrivateStore(); } + Elt(const Elt& other) + : SG::AuxElement(other), + x(other.x) + { + makePrivateStore(other); + } + + Elt(const Elt* other) + : SG::AuxElement(*other), + x(other->x) + { + makePrivateStore(other); + } + + Elt& operator= (const Elt&) = default; + + int& ityp1() + { + static Accessor<int> acc ("anInt"); + return acc (*this); + } + + int ityp1() const + { + static Accessor<int> acc ("anInt"); + return acc (*this); + } + + float& ftyp1() + { + static Accessor<float> acc ("aFloat"); + return acc (*this); + } + + float ftyp1() const + { + static Accessor<float> acc ("aFloat"); + return acc (*this); + } + + int x; +}; + + +void test2() +{ + std::cout << "test2\n"; + Elt elt; + assert (elt.x == 0); + assert (elt.usingPrivateStore()); + + Elt elt2 (10); + assert (elt2.x == 10); + + Elt::Accessor<int> ityp2 ("anotherInt"); + + elt.ityp1() = 1; + ityp2(elt) = 2; + elt.ftyp1() = 1.5; + + assert (elt.ityp1() == 1); + assert (ityp2(elt) == 2); + assert (elt.ftyp1() == 1.5); + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t ityp1_id = r.getAuxID<int> ("anInt"); + SG::auxid_t ftyp1_id = r.getAuxID<float> ("aFloat"); + SG::auxid_t ityp2_id = r.getAuxID<int> ("anotherInt"); + SG::auxid_set_t auxids; + auxids.insert (ityp1_id); + auxids.insert (ftyp1_id); + auxids.insert (ityp2_id); + assert (elt.getAuxIDs() == auxids); + + elt.x = 20; + Elt elt3 (elt); + assert (elt3.x == 20); + assert (elt3.ityp1() == 1); + assert (ityp2(elt3) == 2); + assert (elt3.ftyp1() == 1.5); + assert (elt3.container() != elt.container()); + + Elt elt3a (&elt); + assert (elt3a.x == 20); + assert (elt3a.ityp1() == 1); + assert (ityp2(elt3a) == 2); + assert (elt3a.ftyp1() == 1.5); + assert (elt3a.container() != elt.container()); + + elt.ityp1() = 31; + assert (elt3.ityp1() == 1); + elt3 = elt; + assert (elt3.ityp1() == 31); + assert (elt3.container() != elt.container()); + +#if __cplusplus > 201100 + elt.ityp1() = 41; + assert (elt3.ityp1() == 31); + elt3 = std::move(elt); + assert (elt3.ityp1() == 41); + assert (elt3.container() != elt.container()); + + Elt elt4 (std::move(elt)); + assert (elt4.x == 20); + assert (elt4.ityp1() == 41); + assert (ityp2(elt4) == 2); + assert (elt4.ftyp1() == 1.5); + assert (elt4.container() != elt.container()); +#endif + + elt3.ityp1() = 41; + elt.releasePrivateStore(); + assert (!elt.usingPrivateStore()); + assert (elt.container() == 0); + assert (elt3.x == 20); + assert (elt3.ityp1() == 41); + assert (ityp2(elt3) == 2); + assert (elt3.ftyp1() == 1.5); + + SG::AuxElement elt5; + elt5.makePrivateStore(); + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt5.makePrivateStore()); + + elt5.releasePrivateStore(); + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt5.releasePrivateStore()); +} + + +void test_clear() +{ + std::cout << "test_clear\n"; + Elt elt1; + assert (elt1.usingPrivateStore()); + elt1.ityp1() = 1; + elt1.ftyp1() = 1.5; + + assert (elt1.ityp1() == 1); + assert (elt1.ftyp1() == 1.5); + + SG::AuxVectorBase::clearAux (elt1); + assert (elt1.ityp1() == 0); + assert (elt1.ftyp1() == 0); + + elt1.releasePrivateStore(); + SG::AuxVectorBase::clearAux (elt1); + + SG::AuxVectorBase dv; + dv.set (elt1, 1); + ConstAuxStoreTest store; + dv.setStore (&store); + + EXPECT_EXCEPTION (SG::ExcConstAuxData, SG::AuxVectorBase::clearAux (elt1)); + + dv.setStore ((SG::IConstAuxStore*)0); + SG::AuxVectorBase::clearAux (elt1); +} + + +void test_copy() +{ + std::cout << "test_copy\n"; + + Elt::Accessor<int> ityp2 ("anotherInt"); + + Elt elt1; + Elt elt2; + SG::AuxVectorBase dv1; + dv1.set (elt1, 1); + dv1.set (elt2, 2); + SG::AuxStoreInternal store1; + dv1.setStore (&store1); + + elt1.ityp1() = 3; + elt1.ftyp1() = 3.5; + ityp2(elt1) = 4; + + elt2.ityp1() = 7; + elt2.ftyp1() = 7.5; + ityp2(elt2) = 5; + + Elt elt3; + SG::AuxVectorBase dv3; + dv3.set (elt3, 3); + SG::AuxStoreInternal store3; + dv3.setStore (&store3); + + elt3.ityp1() = 10; + elt3.ftyp1() = 10.5; + + SG::AuxVectorBase::copyAux (elt2, elt3); + assert (elt2.ityp1() == 10); + assert (elt2.ftyp1() == 10.5); + assert (ityp2(elt2) == 0); + + const Elt& celt2 = elt2; + Elt::Accessor<int> ityp3 ("yetAnotherInt"); + Elt elt5; + SG::AuxVectorBase dv5; + dv5.set (elt5, 1); + ConstAuxStoreTest store5; + dv5.setStore (&store5); + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t ityp1_id = r.getAuxID<int> ("anInt"); + SG::auxid_t ftyp1_id = r.getAuxID<float> ("aFloat"); + SG::auxid_t ityp3_id = ityp3.auxid(); + store5.m_set.insert (ityp1_id); + store5.m_set.insert (ityp3_id); + store5.m_set.insert (ftyp1_id); + auto vptr = CxxUtils::make_unique<std::vector<float> >(); + vptr->resize(5); + (*vptr)[1] = 3.5; + store5.add (ftyp1_id, std::move(vptr)); + EXPECT_EXCEPTION (SG::ExcBadAuxVar, ityp3(celt2)); + SG::AuxVectorBase::copyAux (elt2, elt5); + assert (elt2.ityp1() == 0); + assert (elt2.ftyp1() == 3.5); + assert (ityp3(celt2) == 0); + + Elt elt4; + elt4.releasePrivateStore(); + SG::AuxVectorBase::copyAux (elt1, elt4); + assert (elt1.ityp1() == 0); + assert (elt1.ftyp1() == 0); + assert (ityp2(elt1) == 0); + + ConstAuxStoreTest store; + dv1.setStore (&store); + + EXPECT_EXCEPTION(SG::ExcConstAuxData, SG::AuxVectorBase::copyAux(elt1, elt4)); + + dv1.setStore ((SG::IConstAuxStore*)0); + SG::AuxVectorBase::copyAux (elt1, elt4); + SG::AuxVectorBase::copyAux (elt4, elt1); +} + + +void test_standalone() +{ + std::cout << "test_standalone\n"; + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t ityp1 = r.getAuxID<int> ("anInt"); + SG::AuxElement::Accessor<int> int1 ("anInt"); + SG::AuxStoreInternal store1; + int* i1 = reinterpret_cast<int*> (store1.getData(ityp1, 1, 1)); + i1[0] = 11; + + SG::AuxVectorBase v; + + SG::AuxElement elt1; + elt1.clearCache(); + assert (!elt1.usingPrivateStore()); + assert (!elt1.usingStandaloneStore()); + assert (!elt1.hasStore()); + assert (!elt1.hasNonConstStore()); + assert (elt1.getStore() == 0); + assert (elt1.getConstStore() == 0); + + elt1.setStore (&store1); + elt1.clearCache(); + assert (!elt1.usingPrivateStore()); + assert (elt1.usingStandaloneStore()); + assert (elt1.hasStore()); + assert (elt1.hasNonConstStore()); + assert (elt1.getStore() == &store1); + assert (elt1.getConstStore() == &store1); + assert (int1(elt1) == 11); + int1(elt1) = 12; + + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt1.makePrivateStore()); + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, v.set(elt1, 2)); + + elt1.setStore ((SG::IAuxStore*)0); + assert (!elt1.usingPrivateStore()); + assert (!elt1.usingStandaloneStore()); + assert (!elt1.hasStore()); + assert (!elt1.hasNonConstStore()); + assert (elt1.getStore() == 0); + assert (elt1.getConstStore() == 0); + assert (i1[0] == 12); + + v.set (elt1, 1); + + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt1.setStore (&store1)); + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt1.setStore ((SG::IAuxStore*)0)); + + assert (!elt1.usingPrivateStore()); + assert (!elt1.usingStandaloneStore()); + assert (!elt1.hasStore()); + assert (!elt1.hasNonConstStore()); + assert (elt1.getStore() == 0); + assert (elt1.getConstStore() == 0); + + SG::AuxElement elt2; + elt2.makePrivateStore(); + + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt1.setStore (&store1)); + EXPECT_EXCEPTION (SG::ExcBadPrivateStore, elt1.setStore ((SG::IAuxStore*)0)); + + assert (elt2.usingPrivateStore()); + assert (!elt2.usingStandaloneStore()); + assert (elt2.hasStore()); + assert (elt2.hasNonConstStore()); + assert (elt2.getStore() != 0); + assert (elt2.getConstStore() != 0); + + elt2.releasePrivateStore(); + elt2.setNonConstStore (&store1); + assert (elt2.getStore() == &store1); + assert (elt2.getConstStore() == &store1); + elt2.setConstStore (&store1); + assert (elt2.getStore() == 0); + assert (elt2.getConstStore() == &store1); +} + + +void test_decoration() +{ + std::cout << "test_decoration\n"; + + SG::AuxElement b; + SG::AuxVectorBase v; + v.set (b, 5); + + SG::AuxStoreInternal store; + v.setStore (&store); + + SG::AuxElement::Accessor<int> ityp1 ("anInt1"); + SG::AuxElement::Decorator<int> ityp2 ("anInt2"); + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t ityp2_id = r.getAuxID<int> ("anInt2"); + assert (ityp2.auxid() == ityp2_id); + + ityp1(b) = 10; + ityp2(b) = 11; + + assert (10 == ityp1(b)); + assert (11 == ityp2(b)); + + v.lock(); + const SG::AuxElement& cb = b; + + SG::AuxElement::Decorator<int> ityp3 ("anInt3"); + ityp3(cb) = 12; + + assert (10 == ityp1(cb)); + assert (12 == ityp3(cb)); + + cb.auxdecor<int> ("anInt3") = 19; + assert (19 == ityp3(cb)); + + EXPECT_EXCEPTION (SG::ExcStoreLocked, ityp2(cb) = 14); + +#if 0 + assert (ityp3.isAvailable(cb)); + cb.clearDecorations(); + assert (ityp1.isAvailable(cb)); + assert (!ityp3.isAvailable(cb)); +#endif + + SG::AuxElement::Accessor<int> ityp4 ("anInt4"); + + SG::AuxElement b2; + b2.makePrivateStore(); + ityp1(b2) = 10; + + b2.getStore()->lock(); + EXPECT_EXCEPTION (SG::ExcStoreLocked, ityp4(b2) = 12); + assert (ityp1.isAvailable(b2)); + assert (!ityp4.isAvailable(b2)); + assert (ityp1.isAvailableWritable(b2)); + + const SG::AuxElement& cb2 = b2; + + ityp3(cb2) = 14; + assert (ityp3(cb2) == 14); + assert (ityp3.isAvailable(b2)); + + ityp3.set(cb2, 15); + assert (ityp3(cb2) == 15); + assert (ityp3.isAvailable(b2)); + + cb2.clearDecorations(); + assert (ityp1.isAvailable(b2)); + assert (!ityp3.isAvailable(b2)); +} + + +void test_private_store() +{ + std::cout << "test_private_store\n"; + Elt elt; + assert (elt.hasStore()); + assert (elt.hasNonConstStore()); + assert (elt.usingPrivateStore()); + assert (!elt.usingStandaloneStore()); + + SG::AuxVectorBase v; + v.set (elt, 1); + assert (!elt.hasStore()); + assert (!elt.hasNonConstStore()); + assert (!elt.usingPrivateStore()); + assert (!elt.usingStandaloneStore()); + + v.clear (elt); + assert (elt.hasStore()); + assert (elt.hasNonConstStore()); + assert (elt.usingPrivateStore()); + assert (!elt.usingStandaloneStore()); +} + + +int main() +{ + test1(); + test2(); + test_clear(); + test_copy(); + test_standalone(); + test_decoration(); + test_private_store(); + return 0; +} + +// LocalWords: anInt4 diff --git a/EDM/athena/Control/AthContainers/test/AuxStoreInternal_test.cxx b/EDM/athena/Control/AthContainers/test/AuxStoreInternal_test.cxx new file mode 100644 index 00000000..a281adae --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxStoreInternal_test.cxx @@ -0,0 +1,541 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxStoreInternal_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Regression tests for AuxStoreInternal + */ + + +#undef NDEBUG +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/AuxTypeVector.h" +#include "AthContainers/tools/threading.h" +#include "TestTools/expect_exception.h" +#ifndef ATHCONTAINERS_NO_THREADS +#include "boost/thread/shared_mutex.hpp" +#include "boost/thread/shared_lock_guard.hpp" +#endif +#include <iostream> +#include <sstream> +#include <cassert> + + +#include "auxid_set_equal.icc" + + +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(); } + + +class AuxStoreInternalTest + : public SG::AuxStoreInternal +{ +public: + using SG::AuxStoreInternal::addAuxID; + using SG::AuxStoreInternal::addVector; +}; + + +void test1() +{ + std::cout << "test1\n"; + AuxStoreInternalTest s; + assert (!s.standalone()); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + assert (s.getData (ityp1) == 0); + assert (s.size() == 0); + + int* i1 = reinterpret_cast<int*> (s.getData(ityp1, 10, 20)); + assert (s.size() == 10); + i1[0] = 1; + i1[1] = 2; + + const int* i1c = reinterpret_cast<const int*> (s.getData(ityp1)); + assert (i1c == i1); + assert (i1c[1] == 2); + + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anotherInt"); + assert (s.getData (ityp2) == 0); + int* i2 = reinterpret_cast<int*> (s.getData(ityp2, 10, 20)); + assert (i2 != i1); + assert (i2[0] == 0); + i2[0] = 11; + i2[1] = 12; + + const int* i2c = reinterpret_cast<const int*> (s.getData(ityp2)); + assert (i2c == i2); + assert (i2c[1] == 12); + + SG::auxid_t ftyp1 = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + assert (s.getData (ftyp1) == 0); + + float* f1 = reinterpret_cast<float*> (s.getData(ftyp1, 10, 20)); + f1[0] = 1.1; + f1[1] = 2.5; + + const float* f1c = reinterpret_cast<const float*> (s.getData(ftyp1)); + assert (f1c == f1); + assert (f1c[1] == 2.5); + + + assert (s.size() == 10); + + s.reserve(50); + assert (s.size() == 10); + i2c = reinterpret_cast<const int*> (s.getData(ityp2)); + f1c = reinterpret_cast<const float*> (s.getData(ftyp1)); + assert (s.resize(40) == true); + assert (s.size() == 40); + assert (i2c == reinterpret_cast<const int*> (s.getData(ityp2))); + assert (f1c == reinterpret_cast<const float*> (s.getData(ftyp1))); + + f1 = reinterpret_cast<float*> (s.getData(ftyp1, 40, 50)); + f1[39] = 5.5; + + s.shift (39, -37); + assert (s.size() == 3); + f1c = reinterpret_cast<const float*> (s.getData(ftyp1)); + assert (f1c[2] == 5.5); + s.shift (1, 1); + assert (s.size() == 4); + i2c = reinterpret_cast<const int*> (s.getData(ityp2)); + assert (i2c[0] == 11); + assert (i2c[1] == 0); + assert (i2c[2] == 12); + i1c = reinterpret_cast<const int*> (s.getData(ityp1)); + assert (i1c[0] == 1); + assert (i1c[1] == 0); + assert (i1c[2] == 2); + + const std::vector<int>* v1 = + reinterpret_cast<const std::vector<int>*> (s.getIOData(ityp1)); + assert (&*v1->begin() == i1c); + + const SG::auxid_set_t& ids = s.getAuxIDs(); + assert (ids.size() == 3); + assert (ids.find (ityp1) != ids.end()); + assert (ids.find (ityp2) != ids.end()); + assert (ids.find (ftyp1) != ids.end()); + + assert (s.getAuxIDs() == s.getWritableAuxIDs()); + + const SG::auxid_set_t& dids = s.getDynamicAuxIDs(); + std::vector<SG::auxid_t> vi1 (ids.begin(), ids.end()); + std::vector<SG::auxid_t> vi2 (dids.begin(), dids.end()); + std::sort (vi1.begin(), vi1.end()); + std::sort (vi2.begin(), vi2.end()); + assert (vi1 == vi2); + + assert (s.getIOType(ityp1) == &typeid(std::vector<int>)); + + SG::auxid_t btyp1 = SG::AuxTypeRegistry::instance().getAuxID<bool> ("aBool"); + s.getData(btyp1, 4, 50); + assert (s.getIOType(btyp1) == &typeid(std::vector<char>)); + + assert (s.getAuxIDs().size() == 4); + s.addAuxID (999); + const SG::auxid_set_t& ids2 = s.getAuxIDs(); + assert (ids2.size() == 5); + assert (ids2.find (ityp1) != ids2.end()); + assert (ids2.find (ityp2) != ids2.end()); + assert (ids2.find (ftyp1) != ids2.end()); + assert (ids2.find (btyp1) != ids2.end()); + assert (ids2.find (999) != ids2.end()); + + assert (s.size() == 4); + + SG::AuxStoreInternal s2 (s); + assert (s2.size() == 4); + + const SG::auxid_set_t& ids3 = s2.getAuxIDs(); + assert (ids3.size() == 5); + assert (ids3.find (ityp1) != ids2.end()); + assert (ids3.find (ityp2) != ids2.end()); + assert (ids3.find (ftyp1) != ids2.end()); + assert (ids3.find (btyp1) != ids2.end()); + assert (ids3.find (999) != ids2.end()); + + i2c = reinterpret_cast<const int*> (s2.getData(ityp2)); + assert (i2c[0] == 11); + assert (i2c[1] == 0); + assert (i2c[2] == 12); + i1c = reinterpret_cast<const int*> (s2.getData(ityp1)); + assert (i1c[0] == 1); + assert (i1c[1] == 0); + assert (i1c[2] == 2); + + assert (s.resize(1000) == false); + assert (s.resize(500) == true); + assert (s.resize(1000) == true); +} + + +// Test decorations / locking +void test2() +{ + std::cout << "test2\n"; + SG::AuxStoreInternal s; + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + SG::auxid_t ityp9 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt9"); + + int* i1 = reinterpret_cast<int*> (s.getData(ityp1, 10, 20)); + int* i2 = reinterpret_cast<int*> (s.getDecoration(ityp2, 10, 20)); + assert (i1 != 0); + assert (i2 != 0); + assert (i1 != i2); + + s.lock(); + + SG::auxid_set_t idset; + idset.insert (ityp1); + idset.insert (ityp2); + assert (s.getAuxIDs() == idset); + + assert (i1 == s.getData(ityp1)); + //EXPECT_EXCEPTION (SG::ExcStoreLocked, s.getData(ityp1, 10, 20)); + assert (i1 == reinterpret_cast<int*> (s.getData(ityp1, 10, 20))); + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.getData(ityp9, 10, 20)); + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.getDecoration(ityp1, 10, 20)); + + SG::auxid_t ityp3 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt3"); + int* i3 = reinterpret_cast<int*> (s.getDecoration(ityp3, 10, 20)); + assert (i3 != 0); + assert (i3 != i1); + assert (i3 != i2); + + assert (i3 == s.getDecoration (ityp3, 10, 20)); + + idset.insert (ityp3); + assert (idset.size() == 3); + assert (s.getAuxIDs() == idset); + + s.clearDecorations(); + idset.erase (ityp3); + assert (idset.size() == 2); + assert (s.getAuxIDs() == idset); + assert (s.getData(ityp3) == 0); + assert (s.getData(ityp1) == i1); + assert (s.getData(ityp2) == i2); + + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.resize(100)); + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.reserve(100)); + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.shift(1, 2)); +} + + +// Test setOption / getIOType +void test3() +{ + std::cout << "test3\n"; + SG::AuxStoreInternal s; + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + int* i1 = reinterpret_cast<int*> (s.getData(ityp1, 10, 20)); + i1[0] = 1; + i1[1] = 2; + + assert (!s.setOption (ityp2, SG::AuxDataOption ("opt", 1))); + assert (!s.setOption (ityp1, SG::AuxDataOption ("opt", 1))); + assert (s.getIOType (ityp1) == &typeid(std::vector<int>)); + assert (s.setOption (ityp1, SG::AuxDataOption ("nbits", 29))); + assert (s.getIOType (ityp1) == &typeid(SG::PackedContainer<int>)); + const SG::PackedContainer<int>* pvec = + reinterpret_cast<const SG::PackedContainer<int>*> (s.getIOData (ityp1)); + assert (typeid(*pvec) == typeid(SG::PackedContainer<int>)); + assert (pvec->parms().nbits() == 29); + assert (s.setOption (ityp1, SG::AuxDataOption ("nbits", 23))); + assert (pvec->parms().nbits() == 23); + + assert (s.getIOType (ityp2) == &typeid(std::vector<int>)); + assert (s.setOption (ityp2, SG::AuxDataOption ("nbits", 28))); + assert (s.getIOType (ityp2) == &typeid(SG::PackedContainer<int>)); + pvec = + reinterpret_cast<const SG::PackedContainer<int>*> (s.getIOData (ityp2)); + assert (typeid(*pvec) == typeid(SG::PackedContainer<int>)); + assert (pvec->parms().nbits() == 28); + assert (s.setOption (ityp2, SG::AuxDataOption ("nbits", 27))); + assert (pvec->parms().nbits() == 27); + + SG::auxid_t styp1 = SG::AuxTypeRegistry::instance().getAuxID<std::string> ("aString"); + s.getData(styp1, 10, 20); + assert (!s.setOption (styp1, SG::AuxDataOption ("nbits", 26))); +} + + +// Test insertMove +void test5() +{ + std::cout << "test5\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"); + SG::AuxStoreInternal s1; + s1.reserve(20); + 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; + ignore.insert (ityp4); + + assert (! s1.insertMove (3, s2, ignore)); // false due to added vbl + 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); + 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); + } + assert (s1.insertMove (10, s2, ignore)); + assert (s1.size() == 15); + 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])); + } +} + + +// Test addVector +void test4() +{ + std::cout << "test4\n"; + + AuxStoreInternalTest s; + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + SG::auxid_t ityp3 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt3"); + + assert (s.size() == 0); + auto vec1 = std::make_unique<SG::AuxTypeVector<int> > (10, 10); + SG::IAuxTypeVector* vec1ptr = vec1.get(); + s.addVector (ityp1, std::move(vec1), false); + assert (s.size() == 10); + assert (s.getIOData(ityp1) == vec1ptr->toVector()); + assert (s.getData(ityp1) == vec1ptr->toPtr()); + assert (vec1ptr->size() == 10); + + auto vec2 = std::make_unique<SG::AuxTypeVector<int> > (5, 5); + SG::IAuxTypeVector* vec2ptr = vec2.get(); + s.addVector (ityp2, std::move(vec2), true); + assert (s.size() == 10); + assert (vec2ptr->size() == 10); + assert (s.getIOData(ityp2) == vec2ptr->toVector()); + assert (s.getData(ityp2) == vec2ptr->toPtr()); + + s.lock(); + auto vec3 = std::make_unique<SG::AuxTypeVector<int> > (5, 5); + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.addVector (ityp3, std::move(vec3), false)); + EXPECT_EXCEPTION (SG::ExcStoreLocked, s.getDecoration (ityp1, 10, 10)); + s.getDecoration (ityp2, 10, 10); +} + + +class ThreadingTest +{ +public: + ThreadingTest(); + void worker(); + + void nonThreadedTest(); + void threadedTest(); + + struct testThread + { + testThread (ThreadingTest& test) + : m_test(test) {} + void operator()() + { +#ifndef ATHCONTAINERS_NO_THREADS + boost::shared_lock_guard<boost::shared_mutex> guard (m_test.m_sm); +#endif // not ATHCONTAINERS_NO_THREADS + m_test.worker(); + } + + ThreadingTest& m_test; + }; + +#ifndef ATHCONTAINERS_NO_THREADS + boost::shared_mutex m_sm; +#endif // not ATHCONTAINERS_NO_THREADS + std::vector<SG::auxid_t> m_ids; + SG::AuxStoreInternal m_store; + size_t m_nids; + size_t m_nelt; +}; + + +ThreadingTest::ThreadingTest() + : m_nids (10000), + m_nelt (1000) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + for (int i=0; i < 10000; i++) { + std::ostringstream ss; + ss << "xint" << i; + SG::auxid_t id = r.getAuxID<int> (ss.str()); + m_ids.push_back (id); + } +} + + +void ThreadingTest::worker() +{ + for (SG::auxid_t id : m_ids) { + int* data = reinterpret_cast<int*> (m_store.getData (id, m_nelt, m_nelt)); + assert (m_store.getData (id) == data); + data[0] = id; + assert (m_store.getAuxIDs().count (id) == 1); + } + + const SG::auxid_set_t& ids = m_store.getAuxIDs(); + assert (ids.size() == m_ids.size()); + for (SG::auxid_t id : m_ids) { + const int* data = reinterpret_cast<const int*> (m_store.getData (id)); + assert (data[0] == static_cast<int>(id)); + assert (ids.count (id) == 1); + } +} + + +void ThreadingTest::nonThreadedTest() +{ + worker(); +} + + +void ThreadingTest::threadedTest() +{ +#ifndef ATHCONTAINERS_NO_THREADS + int nthread = 10; + AthContainers_detail::thread threads[10]; + m_sm.lock(); + for (int i=0; i < nthread; i++) + threads[i] = AthContainers_detail::thread (testThread (*this)); + // Try to get the threads starting as much at the same time as possible. + m_sm.unlock(); + for (int i=0; i < nthread; i++) + threads[i].join(); +#endif +} + + +void test_threading() +{ + std::cout << "test_threading\n"; + + ThreadingTest test; + test.nonThreadedTest(); + for (int i=0; i < 100; i++) + test.threadedTest(); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test_threading(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/AuxStoreStandalone_test.cxx b/EDM/athena/Control/AthContainers/test/AuxStoreStandalone_test.cxx new file mode 100644 index 00000000..8500a417 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxStoreStandalone_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxStoreStandalone_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Regression tests for AuxStoreStandalone + */ + + +#undef NDEBUG +#include "AthContainers/AuxStoreStandalone.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/error.h" +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + SG::AuxStoreStandalone s; + assert (s.standalone()); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + int* i1 = reinterpret_cast<int*> (s.getData(ityp1, 10, 20)); + assert (s.getIOData (ityp1) == i1); + assert (s.getIOType (ityp1) == &typeid (int)); + + SG::auxid_t ftyp1 = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + assert (s.getIOData (ftyp1) == 0); +} + + +int main() +{ +#ifndef XAOD_STANDALONE + errorcheck::ReportMessage::hideErrorLocus(); +#endif + test1(); +} diff --git a/EDM/athena/Control/AthContainers/test/AuxTypeRegistry_test.cxx b/EDM/athena/Control/AthContainers/test/AuxTypeRegistry_test.cxx new file mode 100644 index 00000000..b2ed70fe --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxTypeRegistry_test.cxx @@ -0,0 +1,415 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxBaseRegistry_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Regression tests for AuxBaseRegistry + */ + + +#undef NDEBUG +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthLinks/ElementLink.h" +#include <iostream> +#include <cassert> + + +#ifndef XAOD_STANDALONE +#include "SGTools/TestStore.h" +#include "SGTools/CLASS_DEF.h" +CLASS_DEF (std::vector<int*>, 28374627, 0) +using namespace SGTest; +#endif + + +struct Payload +{ + Payload (int x = 0) : m_x (x) {} + Payload& operator= (const Payload&) = default; + int m_x; + bool operator== (const Payload& other) + { return m_x == other.m_x; } +}; + + +template <class T> +T makeT(int x=0) { return T(x); } + +bool makeT(int x=0) { return (x&1) != 0; } + + +template <class T> +void test_type(const std::string& typname, + const std::string& name, + const std::string& clsname = "") +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + assert (SG::null_auxid == r.findAuxID (name, clsname)); + SG::auxid_t auxid = r.getAuxID<T> (name, clsname); + assert (auxid == r.getAuxID<T> (name, clsname)); + assert (auxid == r.findAuxID (name, clsname)); + assert (auxid == r.getAuxID (typeid(T), name, clsname)); + + bool caught = false; + try { + r.getAuxID<char> (name, clsname); + } + catch (const SG::ExcAuxTypeMismatch& m) { + caught = true; + } + assert (caught); + + r.getAuxID<char> (name, "otherclass"); + + assert (r.getName (auxid) == name); + assert (r.getClassName (auxid) == clsname); + assert (r.getType (auxid) == &typeid(T)); + assert (r.getTypeName (auxid) == typname); + if (typeid(T) == typeid(bool)) { + assert (r.getVecType (auxid) == &typeid(std::vector<char>)); + assert (r.getVecTypeName (auxid) == "std::vector<char>"); + assert (r.getEltSize (auxid) == sizeof(char)); + } + else { + assert (r.getVecType (auxid) == &typeid(std::vector<T>)); + assert (r.getVecTypeName (auxid) == "std::vector<" + typname + ">"); + assert (r.getEltSize (auxid) == sizeof(T)); + } + + assert (r.getName (999) == ""); + assert (r.getType (999) == 0); + assert (r.getTypeName (999) == ""); + assert (r.getVecTypeName (999) == ""); + + SG::IAuxTypeVector* v = r.makeVector (auxid, 10, 20); + T* ptr = reinterpret_cast<T*> (v->toPtr()); + ptr[0] = makeT(0); + ptr[1] = makeT(1); + + v->reserve (50); + ptr = reinterpret_cast<T*> (v->toPtr()); + v->resize (40); + assert (ptr == reinterpret_cast<T*> (v->toPtr())); + ptr[49] = makeT(123); + + SG::IAuxTypeVector* v2 = r.makeVector (auxid, 10, 20); + T* ptr2 = reinterpret_cast<T*> (v2->toPtr()); + r.copy (auxid, ptr2, 0, ptr, 1); + r.copyForOutput (auxid, ptr2, 1, ptr, 0); + + assert (ptr2[0] == makeT(1)); + assert (ptr2[1] == makeT(0)); + + r.clear (auxid, ptr2, 0); + assert (ptr2[0] == makeT()); + assert (ptr2[1] == makeT(0)); + + ptr2[0] = makeT(10); + ptr2[1] = makeT(11); + r.swap (auxid, ptr, 0, ptr2, 1); + assert (ptr[0] == makeT(11)); + assert (ptr[1] == makeT(1)); + assert (ptr2[0] == makeT(10)); + assert (ptr2[1] == makeT(0)); + + SG::IAuxTypeVector* v3 = r.makeVector (auxid, 10, 10); + ptr = reinterpret_cast<T*> (v3->toPtr()); + for (int i=0; i<10; i++) + ptr[i] = makeT(i+1); + + v3->shift (5, 3); + // 1 2 3 4 5 0 0 0 6 7 8 9 10 + ptr = reinterpret_cast<T*> (v3->toPtr()); + for (int i=0; i<5; i++) + assert (ptr[i] == makeT(i+1)); + for (int i=5; i<8; i++) + assert (ptr[i] == makeT(0)); + for (int i=8; i<13; i++) + assert (ptr[i] == makeT(i-2)); + + v3->shift (3, -2); + // 1 4 5 0 0 0 6 7 8 9 10 + ptr = reinterpret_cast<T*> (v3->toPtr()); + assert (ptr[0] == makeT(1)); + for (int i=1; i<3; i++) + assert (ptr[i] == makeT(i+3)); + for (int i=3; i<6; i++) + assert (ptr[i] == makeT(0)); + for (int i=6; i<11; i++) + assert (ptr[i] == makeT(i)); + + delete v; + delete v2; + delete v3; +} + + +template <class T> +void test_type_extlock(const std::string& typname, + const std::string& name, + const std::string& clsname = "") +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::AuxTypeRegistry::lock_t lock (r); + + SG::auxid_t auxid = r.getAuxID<T> (name, clsname); + + assert (r.getName (lock, auxid) == name); + assert (r.getClassName (lock, auxid) == clsname); + assert (r.getType (lock, auxid) == &typeid(T)); + assert (r.getTypeName (lock, auxid) == typname); + if (typeid(T) == typeid(bool)) { + assert (r.getVecType (lock, auxid) == &typeid(std::vector<char>)); + assert (r.getVecTypeName (lock, auxid) == "std::vector<char>"); + } + else { + assert (r.getVecType (lock, auxid) == &typeid(std::vector<T>)); + assert (r.getVecTypeName (lock, auxid) == "std::vector<" + typname + ">"); + } + + assert (r.getName (lock, 999) == ""); + assert (r.getType (lock, 999) == 0); + assert (r.getTypeName (lock, 999) == ""); + assert (r.getVecTypeName (lock, 999) == ""); + + SG::IAuxTypeVector* v = r.makeVector (lock, auxid, 10, 20); + T* ptr = reinterpret_cast<T*> (v->toPtr()); + ptr[0] = makeT(0); + ptr[1] = makeT(1); + + v->reserve (50); + ptr = reinterpret_cast<T*> (v->toPtr()); + v->resize (40); + assert (ptr == reinterpret_cast<T*> (v->toPtr())); + ptr[49] = makeT(123); + + SG::IAuxTypeVector* v2 = r.makeVector (lock, auxid, 10, 20); + T* ptr2 = reinterpret_cast<T*> (v2->toPtr()); + r.copy (lock, auxid, ptr2, 0, ptr, 1); + r.copy (lock, auxid, ptr2, 1, ptr, 0); + r.copyForOutput (lock, auxid, ptr2, 1, ptr, 0); + + assert (ptr2[0] == makeT(1)); + assert (ptr2[1] == makeT(0)); + + r.clear (lock, auxid, ptr2, 0); + assert (ptr2[0] == makeT()); + assert (ptr2[1] == makeT(0)); + + ptr2[0] = makeT(10); + ptr2[1] = makeT(11); + r.swap (lock, auxid, ptr, 0, ptr2, 1); + assert (ptr[0] == makeT(11)); + assert (ptr[1] == makeT(1)); + assert (ptr2[0] == makeT(10)); + assert (ptr2[1] == makeT(0)); + + delete v; + delete v2; +} + + +template <class T> +void test_makeVector (const std::string& name) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t auxid = r.getAuxID<T> (name); + + typedef typename SG::AuxTypeVectorHolder<T>::vector_type vector_type; + vector_type* vec1 = new vector_type; + vec1->push_back (makeT(1)); + vec1->push_back (makeT(2)); + vec1->push_back (makeT(3)); + SG::IAuxTypeVector* v1 = r.makeVectorFromData (auxid, vec1, false, true); + assert (v1->size() == 3); + T* ptr1 = reinterpret_cast<T*> (v1->toPtr()); + assert (ptr1[0] == makeT(1)); + assert (ptr1[1] == makeT(2)); + assert (ptr1[2] == makeT(3)); + + SG::PackedContainer<T>* vec2 = new SG::PackedContainer<T>; + vec2->push_back (makeT(3)); + vec2->push_back (makeT(2)); + vec2->push_back (makeT(1)); + SG::IAuxTypeVector* v2 = r.makeVectorFromData (auxid, vec2, true, true); + assert (v2->size() == 3); + T* ptr2 = reinterpret_cast<T*> (v2->toPtr()); + assert (ptr2[0] == makeT(3)); + assert (ptr2[1] == makeT(2)); + assert (ptr2[2] == makeT(1)); + + delete v1; + delete v2; +} + + +void test2() +{ + std::cout << "test2\n"; + test_type<int> ("int", "anInt"); + test_type<float> ("float", "aFloat"); + test_type<double> ("double", "aFloat", "xclass"); + test_type<bool> ("bool", "aBool"); + test_type<Payload> ("Payload", "aPayload"); + test_makeVector<int> ("anInt"); + + test_type_extlock<int> ("int", "anInt"); +} + + +void test_placeholder() +{ + std::cout << "test_placeholder\n"; + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t auxid = r.getAuxID<SG::AuxTypePlaceholder> ("placeholder"); + assert (r.findAuxID("placeholder") == auxid); + assert (r.getType(auxid) == &typeid(SG::AuxTypePlaceholder)); + + auxid = r.getAuxID<int> ("placeholder"); + assert (r.getType(auxid) == &typeid(int)); +} + + +struct FacTest1 {}; +struct FacTest1DynFac + : public SG::AuxTypeVectorFactory<FacTest1> +{ +public: + virtual bool isDynamic() const { return true; } +}; + + +void test_factories() +{ + std::cout << "test_factories\n"; + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + const SG::IAuxTypeVectorFactory* fac = r.getFactory (typeid(char)); + assert (fac->getEltSize() == sizeof(char)); + assert (fac->tiVec() == &typeid(std::vector<char>)); + + assert (r.getFactory (typeid (FacTest1)) == 0); + + SG::IAuxTypeVectorFactory* fac1 = new FacTest1DynFac; + r.addFactory (typeid (FacTest1), fac1); + assert (r.getFactory (typeid (FacTest1)) == fac1); + SG::IAuxTypeVectorFactory* fac2 = new SG::AuxTypeVectorFactory<FacTest1>; + r.addFactory (typeid (FacTest1), fac2); + assert (r.getFactory (typeid (FacTest1)) == fac2); + SG::IAuxTypeVectorFactory* fac3 = new SG::AuxTypeVectorFactory<FacTest1>; + r.addFactory (typeid (FacTest1), fac3); + assert (r.getFactory (typeid (FacTest1)) == fac2); +} + + +struct FacTest2 {}; +struct FacTest2DynFac + : public SG::AuxTypeVectorFactory<FacTest2> +{ +public: + virtual bool isDynamic() const { return true; } +}; + + +void test_factories_extlock() +{ + std::cout << "test_factories_extlock\n"; + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + + { + SG::AuxTypeRegistry::lock_t lock (r); + + const SG::IAuxTypeVectorFactory* fac = r.getFactory (lock, typeid(char)); + assert (fac->getEltSize() == sizeof(char)); + assert (fac->tiVec() == &typeid(std::vector<char>)); + + assert (r.getFactory (lock, typeid (FacTest2)) == 0); + } +} + + +struct FacTest3 {}; + + +void test_get_by_ti() +{ + std::cout << "test_get_by_ti\n"; + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t auxid = r.getAuxID (typeid(short), "aShort"); + assert (auxid != SG::null_auxid); + assert (r.getType (auxid) == &typeid(short)); + assert (r.getTypeName (auxid) == "short"); + + assert (r.getAuxID (typeid(FacTest3), "aTest3") == SG::null_auxid); + r.addFactory (typeid(FacTest3), new SG::AuxTypeVectorFactory<FacTest3>); + auxid = r.getAuxID (typeid(FacTest3), "aTest3"); + assert (auxid != SG::null_auxid); + assert (r.getType (auxid) == &typeid(FacTest3)); + assert (r.getTypeName (auxid) == "FacTest3"); +} + + +void test_copyForOutput() +{ + std::cout << "test_copyForOutput\n"; + +#ifndef XAOD_STANDALONE + typedef ElementLink<std::vector<int*> > EL; + EL el1 (123, 10); + EL el2; + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t auxid = r.getAuxID<EL> ("EL"); + SG::auxid_t auxid_v = r.getAuxID<std::vector<EL> > ("ELV"); + + r.copyForOutput (auxid, &el2, 0, &el1, 0); + assert (el2.key() == 123); + assert (el2.index() == 10); + + std::vector<EL> v1; + v1.push_back (EL (123, 5)); + v1.push_back (EL (123, 6)); + std::vector<EL> v2; + r.copyForOutput (auxid_v, &v2, 0, &v1, 0); + assert (v2[0].key() == 123); + assert (v2[0].index() == 5); + assert (v2[1].key() == 123); + assert (v2[1].index() == 6); + + store.remap (123, 456, 10, 20); + + r.copyForOutput (auxid, &el2, 0, &el1, 0); + assert (el2.key() == 456); + assert (el2.index() == 20); + + store.remap (123, 456, 6, 12); + r.copyForOutput (auxid_v, &v2, 0, &v1, 0); + assert (v2[0].key() == 123); + assert (v2[0].index() == 5); + assert (v2[1].key() == 456); + assert (v2[1].index() == 12); +#endif +} + + +int main() +{ +#ifndef XAOD_STANDALONE + initTestStore(); +#endif + + test2(); + test_placeholder(); + test_factories(); + test_get_by_ti(); + test_copyForOutput(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/AuxTypeVectorFactory_test.cxx b/EDM/athena/Control/AthContainers/test/AuxTypeVectorFactory_test.cxx new file mode 100644 index 00000000..fc5e15ff --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxTypeVectorFactory_test.cxx @@ -0,0 +1,112 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxTypeVectorFactory_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Regression tests for AuxTypeVectorFactory. + */ + + +#undef NDEBUG + + +#include "AthContainers/tools/AuxTypeVectorFactory.h" +#include <iostream> +#include <cassert> + + +template <class T> +T makeT(int x=0) { return T(x); } + +bool makeT(int x=0) { return (x&1) != 0; } + + +template <class T> +void test_vector() +{ + SG::AuxTypeVectorFactory<T> fac; + assert (fac.getEltSize() == sizeof(T)); + assert (!fac.isDynamic()); + if (typeid(T) == typeid(bool)) + assert (fac.tiVec() == &typeid (std::vector<char>)); + else + assert (fac.tiVec() == &typeid (std::vector<T>)); + + SG::IAuxTypeVector* v = fac.create (10, 20); + T* ptr = reinterpret_cast<T*> (v->toPtr()); + ptr[0] = makeT(20); + ptr[1] = makeT(2); + + SG::IAuxTypeVector* v2 = fac.create (10, 20); + T* ptr2 = reinterpret_cast<T*> (v2->toPtr()); + fac.copy (ptr2, 0, ptr, 1); + fac.copy (ptr2, 1, ptr, 0); + assert (ptr2[0] == makeT(2)); + assert (ptr2[1] == makeT(20)); + + ptr2[0] = makeT(10); + ptr2[1] = makeT(11); + + fac.swap (ptr2, 0, ptr, 1); + assert (ptr[0] == makeT(20)); + assert (ptr[1] == makeT(10)); + assert (ptr2[0] == makeT(2)); + assert (ptr2[1] == makeT(11)); + + fac.clear (ptr2, 0); + assert (ptr2[0] == makeT()); + assert (ptr2[1] == makeT(11)); + + typedef typename SG::AuxTypeVectorHolder<T>::vector_type vector_type; + vector_type* vec3 = new vector_type; + vec3->push_back (makeT(3)); + vec3->push_back (makeT(2)); + vec3->push_back (makeT(1)); + SG::IAuxTypeVector* v3 = fac.createFromData (vec3, false, true); + assert (v3->size() == 3); + T* ptr3 = reinterpret_cast<T*> (v3->toPtr()); + assert (ptr3[0] == makeT(3)); + assert (ptr3[1] == makeT(2)); + assert (ptr3[2] == makeT(1)); +} + + +template <class T> +void test_vector2() +{ + SG::AuxTypeVectorFactory<T> fac; + SG::PackedContainer<T>* vec4 = new SG::PackedContainer<T>; + vec4->push_back (makeT(4)); + vec4->push_back (makeT(3)); + vec4->push_back (makeT(2)); + vec4->push_back (makeT(1)); + SG::IAuxTypeVector* v4 = fac.createFromData (vec4, true, true); + assert (v4->size() == 4); + T* ptr4 = reinterpret_cast<T*> (v4->toPtr()); + assert (ptr4[0] == makeT(4)); + assert (ptr4[1] == makeT(3)); + assert (ptr4[2] == makeT(2)); + assert (ptr4[3] == makeT(1)); +} + + +void test1() +{ + std::cout << "test1\n"; + test_vector<int>(); + test_vector2<int>(); + test_vector<bool>(); + test_vector<float>(); + test_vector2<float>(); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/AuxTypeVector_test.cxx b/EDM/athena/Control/AthContainers/test/AuxTypeVector_test.cxx new file mode 100644 index 00000000..6b4d7dfe --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxTypeVector_test.cxx @@ -0,0 +1,378 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxTypeVector_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for AuxTypeVector. + */ + + +#undef NDEBUG + + +#include "AthContainers/tools/AuxTypeVector.h" +#include <vector> +#include <iostream> +#include <cassert> +#include <memory> + + +template <class T> +T makeT1(int x, T*) { return T(x); } + +bool makeT1(int x, bool) { return (x&1) != 0; } + +template <class T> +T makeT(int x=0) { return makeT1(x, static_cast<T*>(nullptr)); } + + +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(); } +}; + + +template <class T> +bool wasMoved (const T&) { return true; } + +bool wasMoved (const MoveTest& x) { return x.m_v.empty(); } + + +template <class T> +void test_vector1() +{ + SG::AuxTypeVector<T>* vconcrete = new SG::AuxTypeVector<T> (10, 20); + SG::IAuxTypeVector* v = vconcrete; + T* ptr = reinterpret_cast<T*> (v->toPtr()); + ptr[0] = makeT<T>(1); + ptr[1] = makeT<T>(2); + assert (v->size() == 10); + + assert (vconcrete->vec()[0] == makeT<T>(1)); + assert (vconcrete->vec()[1] == makeT<T>(2)); + assert (&vconcrete->vec() == v->toVector()); + + v->reserve (50); + ptr = reinterpret_cast<T*> (v->toPtr()); + assert (v->resize (40) == true); + T* ptr2 = reinterpret_cast<T*> (v->toPtr()); + assert (ptr == ptr2); + assert (ptr[0] == makeT<T>(1)); + assert (ptr[1] == makeT<T>(2)); + assert (v->size() == 40); + + v->shift (1, 1); + assert (ptr[0] == makeT<T>(1)); + assert (ptr[1] == makeT<T>()); + assert (ptr[2] == makeT<T>(2)); + + ptr[1] = makeT<T>(20); + v->shift (1, -1); + assert (ptr[0] == makeT<T>(20)); + assert (ptr[1] == makeT<T>(2)); + + SG::IAuxTypeVector* v2 = new SG::AuxTypeVector<T> (10, 20); + ptr2 = reinterpret_cast<T*> (v2->toPtr()); + SG::AuxTypeVector<T>::copy (ptr2, 0, ptr, 1); + SG::AuxTypeVector<T>::copy (ptr2, 1, ptr, 0); + assert (ptr2[0] == makeT<T>(2)); + assert (ptr2[1] == makeT<T>(20)); + + ptr2[0] = makeT<T>(10); + ptr2[1] = makeT<T>(11); + + SG::AuxTypeVector<T>::swap (ptr2, 0, ptr, 1); + assert (ptr[0] == makeT<T>(20)); + assert (ptr[1] == makeT<T>(10)); + assert (ptr2[0] == makeT<T>(2)); + assert (ptr2[1] == makeT<T>(11)); + + SG::AuxTypeVector<T>::clear (ptr2, 0); + assert (ptr2[0] == makeT<T>()); + assert (ptr2[1] == makeT<T>(11)); + + SG::IAuxTypeVector* v3 = v->clone(); + assert (v3->size() == v->size()); + T* ptr3 = reinterpret_cast<T*> (v3->toPtr()); + for (size_t i = 0; i < v->size(); i++) + assert (ptr[i] == ptr3[i]); + + assert (v->resize (0) == true); + assert (v->toPtr() == 0); + + if (typeid(T) == typeid(bool)) + assert (v->objType() == &typeid(std::vector<char>)); + else + assert (v->objType() == &typeid(std::vector<T>)); + + assert (v->resize (1000) == false); + assert (v->resize (500) == true); + assert (v->resize (1000) == true); + + delete v; + delete v2; + delete v3; +} + + +template <class T> +void test_vector2() +{ + SG::AuxTypeVector<T> v1 (10, 10); + T* ptr1 = reinterpret_cast<T*> (v1.toPtr()); + ptr1[0] = makeT<T>(1); + ptr1[1] = makeT<T>(2); + + SG::AuxTypeVector<T> v2 (v1); + T* ptr2 = reinterpret_cast<T*> (v2.toPtr()); + assert (v1.size() == 10); + assert (v2.size() == 10); + assert (ptr1[0] == makeT<T>(1)); + assert (ptr1[1] == makeT<T>(2)); + assert (ptr2[0] == makeT<T>(1)); + assert (ptr2[1] == makeT<T>(2)); + + SG::AuxTypeVector<T> v3 (0, 0); + v3 = v1; + T* ptr3 = reinterpret_cast<T*> (v3.toPtr()); + assert (v1.size() == 10); + assert (v3.size() == 10); + assert (ptr1[0] == makeT<T>(1)); + assert (ptr1[1] == makeT<T>(2)); + assert (ptr3[0] == makeT<T>(1)); + assert (ptr3[1] == makeT<T>(2)); + + v3.resize (3); + ptr3[0] = makeT<T>(3); + ptr3[1] = makeT<T>(2); + ptr3[2] = makeT<T>(1); + + SG::AuxTypeVector<T> v4 (std::move (v3)); + T* ptr4 = reinterpret_cast<T*> (v4.toPtr()); + assert (v4.size() == 3); + assert (v3.size() == 0); + assert (ptr4[0] == makeT<T>(3)); + assert (ptr4[1] == makeT<T>(2)); + assert (ptr4[2] == makeT<T>(1)); + + v3 = std::move(v4); + assert (v3.size() == 3); + assert (v4.size() == 0); + assert (ptr3[0] == makeT<T>(3)); + assert (ptr3[1] == makeT<T>(2)); + assert (ptr3[2] == makeT<T>(1)); +} + + +template <class T> +void test_vector3() +{ + typedef typename SG::AuxTypeVectorHolder<T>::vector_type vector_type; + + vector_type* vptr1 = new vector_type; + vptr1->push_back (makeT<T>(1)); + vptr1->push_back (makeT<T>(2)); + vptr1->push_back (makeT<T>(3)); + + SG::AuxTypeVectorHolder<T> v1 (vptr1, true); + assert (v1.size() == 3); + T* ptr1 = reinterpret_cast<T*> (v1.toPtr()); + assert (ptr1[0] == makeT<T>(1)); + assert (ptr1[1] == makeT<T>(2)); + assert (ptr1[2] == makeT<T>(3)); + + SG::AuxTypeVectorHolder<T> v2 (v1); + assert (v1.size() == 3); + assert (v2.size() == 3); + T* ptr2 = reinterpret_cast<T*> (v2.toPtr()); + assert (ptr2[0] == makeT<T>(1)); + assert (ptr2[1] == makeT<T>(2)); + assert (ptr2[2] == makeT<T>(3)); + + v2.resize(2); + ptr2[0] = makeT<T>(2); + ptr2[1] = makeT<T>(1); + v1 = v2; + assert (v1.size() == 2); + assert (v2.size() == 2); + assert (ptr2[0] == makeT<T>(2)); + assert (ptr2[1] == makeT<T>(1)); + + SG::AuxTypeVectorHolder<T> v3 (std::move(v2)); + assert (v2.size() == 2); + assert (v3.size() == 2); + T* ptr3 = reinterpret_cast<T*> (v3.toPtr()); + assert (ptr3[0] == makeT<T>(2)); + assert (ptr3[1] == makeT<T>(1)); + + v1 = std::move(v3); + ptr1 = reinterpret_cast<T*> (v1.toPtr()); + assert (v1.size() == 2); + assert (v3.size() == 2); + assert (ptr1[0] == makeT<T>(2)); + assert (ptr1[1] == makeT<T>(1)); +} + + +// Testing insertMove +template <class T> +void test_vector4 (bool isPOD) +{ + SG::AuxTypeVector<T> v1 (10, 20); + T* ptr1 = reinterpret_cast<T*> (v1.toPtr()); + for (int i=0; i<10; i++) + ptr1[i] = makeT<T>(i); + + SG::AuxTypeVector<T> v2 (5, 5); + T* ptr2 = reinterpret_cast<T*> (v2.toPtr()); + for (int i=0; i<5; i++) + ptr2[i] = makeT<T>(i+10); + + assert (v1.insertMove (3, ptr2, ptr2+5)); + assert (v1.size() == 15); + for (int i=0; i<3; i++) + assert (ptr1[i] == makeT<T>(i)); + for (int i=0; i<5; i++) + assert (ptr1[3+i] == makeT<T>(10+i)); + for (int i=0; i<7; i++) + assert (ptr1[8+i] == makeT<T>(3+i)); + assert (v2.size() == 5); + for (int i=0; i<5; i++) + assert (wasMoved (ptr2[i])); + + for (int i=0; i<5; i++) + ptr2[i] = makeT<T>(i+20); + for (int i=0; i<5; i++) + assert (isPOD || !wasMoved (ptr2[i])); + + assert (v1.insertMove (15, ptr2, ptr2+5)); + assert (v1.size() == 20); + for (int i=0; i<3; i++) + assert (ptr1[i] == makeT<T>(i)); + for (int i=0; i<5; i++) + assert (ptr1[3+i] == makeT<T>(10+i)); + for (int i=0; i<7; i++) + assert (ptr1[8+i] == makeT<T>(3+i)); + for (int i=0; i<5; i++) + assert (ptr1[15+i] == makeT<T>(20+i)); + assert (v2.size() == 5); + for (int i=0; i<5; i++) + assert (wasMoved (ptr2[i])); + + SG::AuxTypeVector<T> v3 (1000, 1000); + T* ptr3 = reinterpret_cast<T*> (v3.toPtr()); + assert ( ! v1.insertMove (20, ptr3, ptr3 + v3.size()) ); +} + + +template <class T> +void test_vector() +{ + test_vector1<T>(); + test_vector2<T>(); + test_vector3<T>(); + test_vector4<T>(true); +} + + +void test1() +{ + std::cout << "test1\n"; + test_vector<int>(); + test_vector<bool>(); + test_vector<float>(); + test_vector4<MoveTest>(false); +} + + +class TestContainer + : public std::vector<int>, public SG::IAuxSetOption +{ +public: + virtual bool setOption (const SG::AuxDataOption& option) + { lastopt = option; return true; } + + static SG::AuxDataOption lastopt; +}; + + +SG::AuxDataOption TestContainer::lastopt ("", 0); + + +// test setOption +void test2() +{ + std::cout << "test2\n"; + + SG::AuxTypeVector<int> v1 (10, 20); + assert (!v1.setOption (SG::AuxDataOption ("opt", 1))); + + SG::AuxTypeVector<int, TestContainer> v2 (10, 20); + assert (v2.setOption (SG::AuxDataOption ("opt", 1))); + assert (TestContainer::lastopt.name() == "opt"); + assert (TestContainer::lastopt.intVal() == 1); +} + + +// test toPacked +void test3() +{ + std::cout << "test3\n"; + SG::AuxTypeVector<int> v1 (0, 0); + v1.vec().push_back(1); + v1.vec().push_back(2); + + assert (v1.objType() == &typeid(std::vector<int>)); + + void* ptr = v1.toPtr(); + int* iptr = reinterpret_cast<int*>(ptr); + assert (v1.size() == 2); + assert (iptr[0] == 1); + assert (iptr[1] == 2); + + SG::IAuxTypeVector* v2 = v1.toPacked(); + assert (v2 != 0); + assert (ptr == v2->toPtr()); + assert (v2->size() == 2); + assert (iptr[0] == 1); + assert (iptr[1] == 2); + assert (v1.size() == 0); + assert (v1.toPtr() == 0); + + assert (v2->objType() == &typeid(SG::PackedContainer<int>)); + SG::PackedContainer<int>* pptr = + reinterpret_cast<SG::PackedContainer<int>*> (v2->toVector()); + assert (typeid(*pptr) == typeid(SG::PackedContainer<int>)); + + SG::AuxTypeVector<std::string> v3 (0, 0); + v3.vec().push_back("1"); + v3.vec().push_back("2"); + + assert (v3.toPacked() == 0); + assert (v3.size() == 2); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/AuxVectorBase_test.cxx b/EDM/athena/Control/AthContainers/test/AuxVectorBase_test.cxx new file mode 100644 index 00000000..bf1a36ff --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxVectorBase_test.cxx @@ -0,0 +1,1008 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/AuxVectorBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2013 + * @brief Regression tests for AuxVectorBase + */ + +#undef NDEBUG +#include <exception> +#include <string> +#include <sstream> + + +//************************************************************************ + + +class dv_test_err + : public std::exception +{ +public: + explicit dv_test_err (const char* file, + int line, + const std::string& what); + virtual ~dv_test_err() throw() {} + virtual const char* what() const throw() { return m_what.c_str(); } +private: + std::string m_what; +}; + + +dv_test_err::dv_test_err (const char* file, + int line, + const std::string& what) +{ + std::ostringstream os; + os << file << ":" << line << " myassertion failure: " << what; + m_what = os.str(); +} + + +void throw_dv_test_err (const char* file, int line, const char* what) +{ + throw (dv_test_err (file, line, what)); +} + +#define myassert(X) do { \ + if (!(X)) { \ + throw_dv_test_err (__FILE__, __LINE__, #X); \ + } \ + } while (0) + + +#define ATHCONTAINERS_ASSERT(X) myassert(X) + + +//************************************************************************ + + +#include "AthContainers/AuxVectorBase.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/exceptions.h" +#include "TestTools/random.h" +#include <cassert> +#include <vector> +#include <iostream> + + +Athena_test::RNG stlrand; + + +//************************************************************************* + + +struct A +{ + int x; + A(int the_x=0) : x(the_x) {} +}; +struct B + : public SG::AuxElement +{ + int x; + B(int the_x=0) : x(the_x) {} +}; + +struct C + : public A, public SG::AuxElement +{ + C(int the_x=0) : A(the_x) {} +}; + +struct ACont +{ + static const bool has_virtual = false; + typedef std::vector<A*> BaseContainer; + typedef A base_value_type; + typedef A base_type; +}; +struct BCont +{ + static const bool has_virtual = false; + typedef std::vector<B*> BaseContainer; + typedef B base_value_type; + typedef B base_type; +}; +struct CCont +{ + static const bool has_virtual = false; + typedef std::vector<A*> BaseContainer; + typedef C base_value_type; + typedef A base_type; +}; + + +template <class BASE> +std::vector<BASE*> make_v() +{ + std::vector<BASE*> v; + for (int i=0; i < 10; i++) + v.push_back (new BASE(i)); + return v; +} + + +template <class BASE, class D> +std::vector<BASE*> make_v2() +{ + std::vector<BASE*> v; + for (int i=0; i < 10; i++) + v.push_back (new D(i)); + return v; +} + + +namespace SG { + + +class AuxVectorBase_test + : public AuxVectorBase +{ +public: + using AuxVectorBase::initAuxVectorBase; + using AuxVectorBase::setIndices; + using AuxVectorBase::clearIndex; + using AuxVectorBase::clearIndices; + using AuxVectorBase::reserve; + using AuxVectorBase::resize; + using AuxVectorBase::shift; + using AuxVectorBase::moveAux; + using AuxVectorBase::swapElementsAux; + using AuxVectorBase::resortAux; + using AuxVectorBase::swap; + + virtual size_t size_v() const { return 10; } + virtual size_t capacity_v() const { return 20; } + + template <class Iterator> + void check_ordered (Iterator beg, Iterator end, size_t index = 0) + { + while (beg < end) { + assert ((*beg)->index() == index); + assert ((*beg)->container() == this); + ++index; + ++beg; + } + } + + + template <class Cont> + void check_ordered (Cont& c, size_t index = 0) + { + check_ordered (c.begin(), c.end(), index); + } + + + template <class Iterator> + void check_clear (Iterator beg, Iterator end) + { + while (beg < end) { + assert ((*beg)->index() == 0); + assert ((*beg)->container() == 0); + ++beg; + } + } + + + template <class Container> + void check_clear (Container& c) + { + check_clear (c.begin(), c.end()); + } + + + template <class Iterator> + void order (Iterator beg, Iterator end, size_t index = 0) + { + initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + setIndices (beg, end, index); + } + + template <class Cont> + void order (Cont& c, size_t index = 0) + { + order (c.begin(), c.end(), index); + } + + static + void copyAux (SG::AuxElement& e1, const SG::AuxElement& e2) + { + e1.copyAux (e2); + } + + static + void clearAux (SG::AuxElement& e) + { + e.clearAux(); + } + + void setIndexTest (SG::AuxElement* p, size_t index) + { + p->setIndex (index, this); + } +}; + + +template <> +struct AuxStore_traits<std::vector<B*> > : public AuxStore_traits_AuxDefault {}; +template <> +struct AuxStore_traits<std::vector<C*> > : public AuxStore_traits_AuxDefault {}; + + + +class AuxStoreInternal_test + : public AuxStoreInternal +{ +public: + using AuxStoreInternal::AuxStoreInternal; + + virtual const void* getData (SG::auxid_t auxid) const override + { + m_gets.push_back (auxid); + return AuxStoreInternal::getData (auxid); + } + + virtual void* getData (SG::auxid_t auxid, size_t size, size_t capacity) + override + { + m_gets.push_back (auxid); + return AuxStoreInternal::getData (auxid, size, capacity); + } + + mutable std::vector<SG::auxid_t> m_gets; +}; + + +} // namespace SG + + +void test1() +{ + SG::AuxVectorBase_test b1; + assert (!b1.trackIndices()); + assert (b1.size_v() == 10); + assert (b1.capacity_v() == 20); +} + + +void test_init() +{ + SG::AuxVectorBase_test b1; + assert (!b1.trackIndices()); + b1.initAuxVectorBase<A> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + assert (!b1.trackIndices()); + + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + assert (b1.trackIndices()); + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::NEVER_TRACK_INDICES); + assert (!b1.trackIndices()); + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + assert (b1.trackIndices()); + + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + assert (!b1.trackIndices()); + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::NEVER_TRACK_INDICES); + assert (!b1.trackIndices()); + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + assert (b1.trackIndices()); + + SG::AuxVectorBase_test b2; + assert (!b2.trackIndices()); + b1.swap (b2); + assert (!b1.trackIndices()); + assert (b2.trackIndices()); + + SG::AuxStoreInternal store; + b2.setStore (&store); + b2.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + + bool caught = false; + try { + b2.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::NEVER_TRACK_INDICES); + } + catch (const SG::ExcUntrackedSetStore&) { + caught = true; + } + assert (caught); + + caught = false; + try { + b2.initAuxVectorBase<A> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + } + catch (const SG::ExcUntrackedSetStore&) { + caught = true; + } + assert (caught); +} + + +void test_set_store() +{ + std::cout << "test_set_store\n"; + SG::AuxVectorBase_test b; + SG::AuxStoreInternal store; + assert (!b.trackIndices()); + assert (!b.hasStore()); + assert (!b.hasNonConstStore()); + bool caught = false; + try { + b.setStore (&store); + } + catch (const SG::ExcUntrackedSetStore&) { + caught = true; + } + assert (caught); + + caught = false; + try { + b.setStore ((SG::IConstAuxStore*)&store); + } + catch (const SG::ExcUntrackedSetStore&) { + caught = true; + } + assert (caught); + + b.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b.setStore ((SG::IConstAuxStore*)&store); + assert (b.trackIndices()); + assert (b.hasStore()); + assert (!b.hasNonConstStore()); + b.setStore (&store); + assert (b.trackIndices()); + assert (b.hasStore()); + assert (b.hasNonConstStore()); +} + + +void test_set_store2() +{ + std::cout << "test_set_store2\n"; + SG::AuxVectorBase_test b; + SG::AuxStoreInternal store; + assert (!b.trackIndices()); + assert (!b.hasStore()); + assert (!b.hasNonConstStore()); + bool caught = false; + try { + b.setNonConstStore (&store); + } + catch (const SG::ExcUntrackedSetStore&) { + caught = true; + } + assert (caught); + + caught = false; + try { + b.setConstStore (&store); + } + catch (const SG::ExcUntrackedSetStore&) { + caught = true; + } + assert (caught); + + b.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b.setConstStore (&store); + assert (b.trackIndices()); + assert (b.hasStore()); + assert (!b.hasNonConstStore()); + b.setNonConstStore (&store); + assert (b.trackIndices()); + assert (b.hasStore()); + assert (b.hasNonConstStore()); +} + + +void test_set_indices() +{ + std::vector<A*> va = make_v<A>(); + std::vector<B*> vb = make_v<B>(); + + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<A> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setIndices (va.begin(), va.end(), 3); + + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setIndices (vb.begin(), vb.end(), 3); + b1.check_clear (vb); + + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setIndices (vb.begin(), vb.begin()+5, 3); + b1.check_ordered (vb.begin(), vb.begin()+5, 3); + b1.check_clear (vb.begin()+5, vb.end()); +} + + +void test_clear_index() +{ + std::vector<A*> va = make_v<A>(); + std::vector<B*> vb = make_v<B>(); + + SG::AuxVectorBase_test b1; + b1.order (vb); + b1.check_ordered (vb); + + b1.initAuxVectorBase<A> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.clearIndex (va.begin()); + + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.clearIndex (vb.begin()); + b1.check_ordered (vb); + + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.clearIndex (vb.begin()); + b1.check_clear (vb.begin(), vb.begin()+1); + b1.check_ordered (vb.begin()+1, vb.end(), 1); +} + + +void test_clear_indices() +{ + std::vector<A*> va = make_v<A>(); + std::vector<B*> vb = make_v<B>(); + + SG::AuxVectorBase_test b1; + b1.order (vb); + b1.check_ordered (vb); + + b1.initAuxVectorBase<A> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.clearIndices (va.begin(), va.begin()+5); + + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.clearIndices (vb.begin(), vb.begin()+5); + b1.check_ordered (vb); + + b1.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + assert (b1.trackIndices()); + b1.clearIndices (vb.begin(), vb.begin()+5); + b1.check_clear (vb.begin(), vb.begin()+5); + b1.check_ordered (vb.begin()+5, vb.end(), 5); +} + + +void test_get_data() +{ + std::cout << "test_get_data\n"; + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + const SG::AuxVectorBase& cb1 = b1; + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + bool caught = false; + try { + b1.getData<int> (ityp, 0); + } + catch (const SG::ExcNoAuxStore&) { + caught = true; + } + assert (caught); + + SG::AuxStoreInternal store; + SG::IConstAuxStore* cstore = &store; + + b1.setStore (cstore); + caught = false; + try { + assert (b1.getData<int> (ityp, 0) == 0); + } + catch (const SG::ExcConstAuxData&) { + caught = true; + } + assert (caught); + caught = false; + try { + assert (cb1.getData<int> (ityp, 0) == 0); + } + catch (const SG::ExcBadAuxVar&) { + caught = true; + } + assert (caught); + + b1.setStore (&store); + assert (b1.getData<int> (ityp, 0) == 0); + assert (b1.getData<int> (ityp, 1) == 0); + b1.getData<int> (ityp, 0) = 1; + b1.getData<int> (ityp, 1) = 2; + assert (b1.getData<int> (ityp, 0) == 1); + assert (b1.getData<int> (ityp, 1) == 2); + + b1.setStore (cstore); + assert (cb1.getData<int> (ityp, 0) == 1); + assert (cb1.getData<int> (ityp, 1) == 2); + + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + float* ff = reinterpret_cast<float*> (store.getData (ftyp, 10, 20)); + ff[0] = 1.5; + ff[1] = 2.5; + assert (cb1.getData<float> (ftyp, 0) == 1.5); + assert (cb1.getData<float> (ftyp, 1) == 2.5); +} + + +void test_reserve_resize() +{ + std::cout << "test_reserve_resize\n"; + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + SG::AuxStoreInternal_test store; + //SG::IConstAuxStore* cstore = &store; + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + b1.setStore (&store); + b1.getData<int> (ityp, 1) = 10; + + b1.reserve<BCont> (50); + int* ip = &b1.getData<int> (ityp, 1); + b1.resize<BCont> (40); + assert (ip == &b1.getData<int> (ityp, 1)); + assert (b1.getData<int> (ityp, 1) == 10); + + bool caught = false; + try { + b1.reserve<ACont> (1); + } + catch (dv_test_err&) { + caught = true; + } + assert (caught); + + caught = false; + try { + b1.resize<ACont> (1); + } + catch (dv_test_err&) { + caught = true; + } + assert (caught); + + SG::AuxVectorBase_test b2; + b2.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b2.reserve<ACont> (1); + b2.resize<ACont> (1); + + store.m_gets.clear(); + b1.getData<int> (ityp, 1) = 10; + assert (store.m_gets.empty()); + // Should not clear the cache. + b1.resize<BCont> (20); + b1.getData<int> (ityp, 1) = 10; + assert (store.m_gets.empty()); + // Should clear the cache. + b1.resize<BCont> (1000); + b1.getData<int> (ityp, 1) = 10; + assert (store.m_gets == std::vector<SG::auxid_t>{ityp}); + store.m_gets.clear(); + // Below should not clear the cache. + b1.resize<BCont> (500); + b1.getData<int> (ityp, 1) = 10; + assert (store.m_gets.empty()); + b1.resize<BCont> (1000); + b1.getData<int> (ityp, 1) = 10; + assert (store.m_gets.empty()); +} + + +void test_shift() +{ + std::cout << "test_shift\n"; + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + SG::AuxStoreInternal store; + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + b1.setStore (&store); + std::vector<B*> vb = make_v<B>(); + b1.order (vb); + for (int i=0; i < 10; i++) + b1.getData<int> (ityp, i) = i+1; + + for (int i=0; i < 3; i++) + vb.insert (vb.begin()+5, new B); + b1.shift (vb, 5, 3); + // 1 2 3 4 5 0 0 0 6 7 8 9 10 + for (int i=0; i<5; i++) + assert (b1.getData<int> (ityp, i) == i+1); + for (int i=5; i<8; i++) + assert (b1.getData<int> (ityp, i) == 0); + for (int i=8; i<13; i++) + assert (b1.getData<int> (ityp, i) == i-2); + + b1.check_ordered (vb.begin(), vb.begin()+5, 0); + b1.check_ordered (vb.begin()+8, vb.end(), 8); + b1.order (vb); + + for (int i=0; i < 2; i++) + vb.erase (vb.begin()+1); + b1.shift (vb, 3, -2); + // 1 4 5 0 0 0 6 7 8 9 10 + for (int i=1; i<3; i++) + assert (b1.getData<int> (ityp, i) == i+3); + for (int i=3; i<6; i++) + assert (b1.getData<int> (ityp, i) == 0); + for (int i=6; i<11; i++) + assert (b1.getData<int> (ityp, i) == i); + b1.check_ordered (vb); + + std::vector<A*> va = make_v<A>(); + bool caught = false; + try { + b1.shift (va, 1, 1); + } + catch (dv_test_err&) { + caught = true; + } + assert (caught); + + SG::AuxVectorBase_test b2; + b2.initAuxVectorBase<B> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b2.shift (va, 1, 1); +} + + +void test_get_types() +{ + std::cout << "test_get_types\n"; + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + + assert (b1.getAuxIDs().size() == 0); + + SG::AuxStoreInternal store; + b1.setStore (&store); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + b1.getData<int> (ityp1, 1) = 10; + b1.getData<int> (ityp2, 1) = 10; + + assert (b1.getAuxIDs().size() == 2); + assert (b1.getAuxIDs().find(ityp1) != b1.getAuxIDs().end()); + assert (b1.getAuxIDs().find(ityp2) != b1.getAuxIDs().end()); +} + + +void test_copy_aux() +{ + std::cout << "test_copy_aux\n"; + SG::AuxVectorBase_test b1; + SG::AuxStoreInternal store1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setStore (&store1); + + SG::AuxVectorBase_test b2; + b2.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + SG::AuxStoreInternal store2; + b2.setStore (&store2); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + SG::auxid_t ityp3 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt3"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + b1.getData<int> (ityp1, 1) = 10; + b1.getData<int> (ityp2, 1) = 20; + b1.getData<float> (ftyp, 1) = 1.5; + + SG::AuxElement elt; + b1.setIndexTest (&elt, 1); + assert (elt.index() == 1); + assert (elt.container() == &b1); + + b2.getData<int> (ityp1, 3) = 100; + b2.getData<int> (ityp3, 3) = 200; + b2.moveAux (3, &elt); + assert (b2.getData<int> (ityp1, 3) == 10); + assert (b2.getData<int> (ityp2, 3) == 20); + assert (b2.getData<int> (ityp3, 3) == 0); + assert (b2.getData<float> (ftyp, 3) == 1.5); + assert (elt.index() == 3); + assert (elt.container() == &b2); + + b2.moveAux (3, (SG::AuxElement*)0); + assert (b2.getData<int> (ityp1, 3) == 0); + assert (b2.getData<int> (ityp2, 3) == 0); + assert (b2.getData<int> (ityp3, 3) == 0); + assert (b2.getData<float> (ftyp, 3) == 0); + + b1.setIndexTest (&elt, 1); + assert (elt.index() == 1); + assert (elt.container() == &b1); + + SG::AuxElement elt2; + b2.setIndexTest (&elt2, 2); + + SG::AuxVectorBase_test::copyAux (elt2, elt); + assert (b2.getData<int> (ityp1, 2) == 10); + assert (b2.getData<int> (ityp2, 2) == 20); + assert (b2.getData<int> (ityp3, 2) == 0); + assert (b2.getData<float> (ftyp, 2) == 1.5); + assert (elt.index() == 1); + assert (elt.container() == &b1); + + b2.moveAux (2, &elt, true); + assert (b1.getData<int> (ityp1, 1) == 0); + + assert (b2.getData<int> (ityp1, 2) == 10); + assert (b2.getData<int> (ityp2, 2) == 20); + assert (b2.getData<int> (ityp3, 2) == 0); + assert (b2.getData<float> (ftyp, 2) == 1.5); + + SG::AuxElement elt3; + b2.moveAux (2, &elt3, false, true); + assert (b2.getData<int> (ityp1, 2) == 10); + assert (b2.getData<int> (ityp2, 2) == 20); + assert (b2.getData<int> (ityp3, 2) == 0); + assert (b2.getData<float> (ftyp, 2) == 1.5); + + SG::AuxElement elt4; + b2.moveAux (2, &elt4); + assert (b2.getData<int> (ityp1, 2) == 0); + assert (b2.getData<int> (ityp2, 2) == 0); + assert (b2.getData<int> (ityp3, 2) == 0); + assert (b2.getData<float> (ftyp, 2) == 0); +} + + +void test_copy_base_aux() +{ + std::cout << "test_copy_base_aux\n"; + SG::AuxVectorBase_test b1; + SG::AuxStoreInternal store1; + b1.initAuxVectorBase<C> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setStore (&store1); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + + C pc; + b1.setIndexTest (&pc, 0); + b1.getData<int> (ityp1, 0) = 10; + + SG::AuxVectorBase_test b2; + b2.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + SG::AuxStoreInternal store2; + b2.setStore (&store2); +} + + +void test_clear_aux() +{ + std::cout << "test_clear_aux\n"; + SG::AuxVectorBase_test b1; + SG::AuxStoreInternal store1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setStore (&store1); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + b1.getData<int> (ityp1, 1) = 10; + b1.getData<int> (ityp2, 1) = 20; + b1.getData<float> (ftyp, 1) = 1.5; + + SG::AuxElement elt; + b1.setIndexTest (&elt, 1); + assert (elt.index() == 1); + assert (elt.container() == &b1); + + SG::AuxVectorBase_test::clearAux (elt); + + assert (b1.getData<int> (ityp1, 3) == 0); + assert (b1.getData<int> (ityp2, 3) == 0); + assert (b1.getData<float> (ftyp, 3) == 0); +} + + +void test_swap_elements_aux() +{ + std::cout << "test_swap_elements_aux\n"; + + SG::AuxVectorBase_test b1; + SG::AuxStoreInternal store1; + b1.initAuxVectorBase<C> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setStore (&store1); + + SG::AuxVectorBase_test b2; + SG::AuxStoreInternal store2; + b2.initAuxVectorBase<C> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b2.setStore (&store2); + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + + C* pc1 = new C; + b1.setIndexTest (pc1, 1); + b1.getData<int> (ityp, 1) = 10; + b1.getData<float> (ftyp, 1) = 1.5; + + C* pc2 = new C; + b2.setIndexTest (pc2, 2); + b2.getData<int> (ityp, 2) = 20; + b2.getData<float> (ftyp, 2) = 2.5; + + b1.swapElementsAux(1, 2, pc2, pc1, &b2); + + assert (pc1->index() == 2); + assert (pc1->container() == &b2); + assert (b1.getData<int> (ityp, 1) == 20); + assert (b1.getData<float> (ftyp, 1) == 2.5); + + assert (pc2->index() == 1); + assert (pc2->container() == &b1); + assert (b2.getData<int> (ityp, 2) == 10); + assert (b2.getData<float> (ftyp, 2) == 1.5); + + b2.swapElementsAux(2, 1, 0, pc1, &b1); + + assert (pc1->index() == 1); + assert (pc1->container() == &b1); + assert (b1.getData<int> (ityp, 1) == 10); + assert (b1.getData<float> (ftyp, 1) == 1.5); + + assert (pc2->index() == 1); + assert (pc2->container() == &b1); + assert (b2.getData<int> (ityp, 2) == 0); + assert (b2.getData<float> (ftyp, 2) == 0); + + b1.setIndexTest (pc1, 1); + b1.getData<int> (ityp, 1) = 10; + b1.getData<float> (ftyp, 1) = 1.5; + b2.setIndexTest (pc2, 2); + b2.getData<int> (ityp, 2) = 20; + b2.getData<float> (ftyp, 2) = 2.5; + + b1.swapElementsAux(1, 2, pc2, 0, &b2); + + assert (pc1->index() == 1); + assert (pc1->container() == &b1); + assert (b1.getData<int> (ityp, 1) == 20); + assert (b1.getData<float> (ftyp, 1) == 2.5); + + assert (pc2->index() == 1); + assert (pc2->container() == &b1); + assert (b2.getData<int> (ityp, 2) == 0); + assert (b2.getData<float> (ftyp, 2) == 0); +} + + +template <class T, class BASE> +void test_resort_aux_check (SG::AuxVectorBase_test& b, + std::vector<BASE*>& v, + bool checkaux = true) +{ + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + + for (size_t i = 0; i < v.size(); i++) { + T* vv = static_cast<T*> (v[i]); + assert (vv->container() == &b); + assert (vv->index() == i); + if (checkaux) { + assert (b.getData<int>(ityp, i) == v[i]->x); + assert (b.getData<float>(ftyp, i) == v[i]->x+0.5); + } + } +} +template <class T, class CONT> +void test_resort_aux1() +{ + //typedef typename CONT::base_type BASE; + typedef T BASE; + stlrand.seed = 1; + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + + std::vector<BASE*> v = make_v2<BASE, T>(); + SG::AuxVectorBase_test b; + b.initAuxVectorBase<T> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + for (size_t i = 0; i < v.size(); i++) + b.setIndexTest (static_cast<T*>(v[i]), i); + test_resort_aux_check<T,BASE> (b, v, false); + SG::AuxStoreInternal store; + b.setStore (&store); + for (size_t i = 0; i < v.size(); i++) { + b.getData<int> (ityp, i) = v[i]->x; + b.getData<float> (ftyp, i) = v[i]->x + 0.5; + } + + for (int jj=0; jj<10; jj++) { + std::random_shuffle (v.begin(), v.end(), stlrand); + b.resortAux (0, v.begin(), v.end()); + test_resort_aux_check<T,BASE> (b, v); + } + for (int jj=0; jj<10; jj++) { + std::random_shuffle (v.begin()+2, v.end()-2, stlrand); + b.resortAux (2, v.begin()+2, v.end()-2); + test_resort_aux_check<T,BASE> (b, v); + } + + std::vector<BASE*> v2 = v; + SG::AuxVectorBase_test b2; + b2.initAuxVectorBase<T> (SG::VIEW_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + for (int jj=0; jj<10; jj++) { + std::random_shuffle (v2.begin(), v2.end(), stlrand); + b2.resortAux (0, v.begin(), v.end()); + test_resort_aux_check<T,BASE> (b, v); + } + + b.setStore((SG::IAuxStore*)0); + for (int jj=0; jj<10; jj++) { + std::random_shuffle (v.begin(), v.end(), stlrand); + b.resortAux (0, v.begin(), v.end()); + test_resort_aux_check<T,BASE> (b, v, false); + } +} +void test_resort_aux() +{ + std::cout << "test_resort_aux\n"; + + std::vector<A*> va = make_v<A>(); + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<A> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + b1.setIndices (va.begin(), va.end(), 0); + b1.resortAux (0, va.begin(), va.end()); + + test_resort_aux1<B, BCont>(); + test_resort_aux1<C, CCont>(); +} + + +void test_move() +{ + std::cout << "test_move\n"; + +#if __cplusplus > 201100 + SG::AuxVectorBase_test b1; + b1.initAuxVectorBase<B> (SG::OWN_ELEMENTS, SG::DEFAULT_TRACK_INDICES); + SG::AuxStoreInternal store; + b1.setStore (&store); + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + b1.getData<int> (ityp, 0) = 1; + b1.getData<int> (ityp, 1) = 2; + assert (b1.getData<int> (ityp, 0) == 1); + assert (b1.getData<int> (ityp, 1) == 2); + + SG::AuxVectorBase_test b2 (std::move (b1)); + assert (b1.getConstStore() == 0); + assert (b1.getStore() == 0); + assert (b2.getConstStore() == &store); + assert (b2.getStore() == &store); + assert (b2.getData<int> (ityp, 0) == 1); + assert (b2.getData<int> (ityp, 1) == 2); + + SG::AuxVectorBase_test b3; + b3 = std::move (b2); + assert (b2.getConstStore() == 0); + assert (b2.getStore() == 0); + assert (b3.getConstStore() == &store); + assert (b3.getStore() == &store); + assert (b3.getData<int> (ityp, 0) == 1); + assert (b3.getData<int> (ityp, 1) == 2); +#endif +} + + +int main() +{ + test1(); + test_init(); + test_set_store(); + test_set_store2(); + test_set_indices(); + test_clear_index(); + test_clear_indices(); + test_get_data(); + test_reserve_resize(); + test_shift(); + test_get_types(); + test_copy_aux(); + test_copy_base_aux(); + test_clear_aux(); + test_swap_elements_aux(); + test_resort_aux(); + test_move(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/AuxVectorData_test.cxx b/EDM/athena/Control/AthContainers/test/AuxVectorData_test.cxx new file mode 100644 index 00000000..289a8969 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/AuxVectorData_test.cxx @@ -0,0 +1,502 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file DataModel/test/AuxVectorData_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Regression tests for AuxVectorData + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include "AthContainers/AuxVectorData.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/foreach.h" +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" +#ifndef ATHCONTAINERS_NO_THREADS +#include "boost/thread/shared_mutex.hpp" +#include "boost/thread/shared_lock_guard.hpp" +#endif +#include <iostream> +#include <sstream> +#include <cassert> + + +#include "auxid_set_equal.icc" + + +namespace SG { + + +class AuxVectorData_test + : public AuxVectorData +{ +public: + using AuxVectorData::setStore; + using AuxVectorData::s_minCacheLen; + + virtual size_t size_v() const { return 10; } + virtual size_t capacity_v() const { return 20; } +}; + + +} // namespace SG + + + +using SG::AuxVectorData; +using SG::AuxVectorData_test; + + +void test_get_data() +{ + std::cout << "test_get_data\n"; + AuxVectorData_test b1; + const AuxVectorData& cb1 = b1; + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + EXPECT_EXCEPTION (SG::ExcNoAuxStore, b1.getData<int> (ityp, 0)); + EXPECT_EXCEPTION (SG::ExcNoAuxStore, cb1.getDataArray (ityp)); + EXPECT_EXCEPTION (SG::ExcNoAuxStore, cb1.getDataArrayAllowMissing (ityp)); + + SG::AuxStoreInternal store; + SG::IConstAuxStore* cstore = &store; + + assert (!b1.hasNonConstStore()); + assert (!b1.hasStore()); + assert (!b1.isAvailable (ityp)); + assert (!b1.isAvailableWritable (ityp)); + assert (!b1.isAvailableWritableAsDecoration (ityp)); + assert (!b1.isAvailable<int> ("anInt")); + assert (!b1.isAvailableWritable<int> ("anInt")); + assert (!b1.isAvailableWritableAsDecoration<int> ("anInt")); + assert (b1.getConstStore() == 0); + assert (b1.getStore() == 0); + b1.setStore (cstore); + assert (b1.getConstStore() == cstore); + assert (b1.getStore() == 0); + assert (!b1.hasNonConstStore()); + assert (b1.hasStore()); + assert (!b1.isAvailable (ityp)); + assert (!b1.isAvailableWritable (ityp)); + assert (!b1.isAvailableWritableAsDecoration (ityp)); + assert (!b1.isAvailable<int> ("anInt")); + assert (!b1.isAvailableWritable<int> ("anInt")); + assert (!b1.isAvailableWritableAsDecoration<int> ("anInt")); + EXPECT_EXCEPTION (SG::ExcConstAuxData, b1.getData<int> (ityp, 0)); + EXPECT_EXCEPTION (SG::ExcBadAuxVar, cb1.getData<int> (ityp, 0)); + EXPECT_EXCEPTION (SG::ExcBadAuxVar, cb1.getDataArray (ityp)); + assert (cb1.getDataArrayAllowMissing (ityp) == nullptr); + + b1.setStore (&store); + assert (b1.getConstStore() == &store); + assert (b1.getStore() == &store); + assert (b1.hasNonConstStore()); + assert (b1.hasStore()); + assert (b1.getData<int> (ityp, 0) == 0); + assert (b1.getData<int> (ityp, 1) == 0); + b1.getData<int> (ityp, 0) = 1; + b1.getData<int> (ityp, 1) = 2; + assert (b1.getData<int> (ityp, 0) == 1); + assert (b1.getData<int> (ityp, 1) == 2); + assert (b1.isAvailable (ityp)); + assert (b1.isAvailableWritable (ityp)); + assert (b1.isAvailableWritableAsDecoration (ityp)); + assert (b1.isAvailable<int> ("anInt")); + assert (b1.isAvailableWritable<int> ("anInt")); + assert (b1.isAvailableWritableAsDecoration<int> ("anInt")); + assert (reinterpret_cast<const int*>(cb1.getDataArray (ityp))[1] == 2); + assert (reinterpret_cast<const int*>(cb1.getDataArrayAllowMissing (ityp))[1] == 2); + + b1.setStore (cstore); + assert (!b1.hasNonConstStore()); + assert (cb1.getData<int> (ityp, 0) == 1); + assert (cb1.getData<int> (ityp, 1) == 2); + assert (b1.isAvailable (ityp)); + assert (!b1.isAvailableWritable (ityp)); + assert (b1.isAvailableWritableAsDecoration (ityp)); + assert (b1.isAvailable<int> ("anInt")); + assert (!b1.isAvailableWritable<int> ("anInt")); + assert (b1.isAvailableWritableAsDecoration<int> ("anInt")); + + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + float* ff = reinterpret_cast<float*> (store.getData (ftyp, 10, 20)); + ff[0] = 1.5; + ff[1] = 2.5; + assert (cb1.getData<float> (ftyp, 0) == 1.5); + assert (cb1.getData<float> (ftyp, 1) == 2.5); +} + + +void test_swap() +{ + std::cout << "test_swap\n"; + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + + AuxVectorData_test b1; + SG::AuxStoreInternal store1; + b1.setStore (&store1); + + AuxVectorData_test b2; + SG::AuxStoreInternal store2; + b2.setStore (&store2); + + b1.getData<int> (ityp, 0) = 1; + b2.getData<int> (ityp, 0) = 11; + b2.getData<int> (ityp, 1) = 12; + + b1.swap (b2); + assert (b1.getData<int> (ityp, 0) == 11); + assert (b1.getData<int> (ityp, 1) == 12); + assert (b2.getData<int> (ityp, 0) == 1); +} + + +void test_get_types() +{ + std::cout << "test_get_types\n"; + AuxVectorData_test b1; + + assert (b1.getAuxIDs().size() == 0); + + SG::AuxStoreInternal store; + b1.setStore (&store); + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + b1.getData<int> (ityp1, 1) = 10; + b1.getData<int> (ityp2, 1) = 10; + + assert (b1.getAuxIDs().size() == 2); + assert (b1.getAuxIDs().find(ityp1) != b1.getAuxIDs().end()); + assert (b1.getAuxIDs().find(ityp2) != b1.getAuxIDs().end()); + + assert (b1.getWritableAuxIDs() == b1.getAuxIDs()); +} + + +void test_decoration() +{ + std::cout << "test_decoration\n"; + + AuxVectorData_test b1; + const AuxVectorData& cb1 = b1; + SG::AuxStoreInternal store; + SG::IConstAuxStore* cstore = &store; + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt1"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt2"); + SG::auxid_t ityp3 = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt3"); + + EXPECT_EXCEPTION (SG::ExcNoAuxStore, b1.getDecoration<int> (ityp1, 0)); + b1.setStore (cstore); + //EXPECT_EXCEPTION (SG::ExcConstAuxData, b1.getDecoration<int> (ityp1, 0)); + b1.getDecoration<int> (ityp1, 0) = 9; + assert (cb1.getData<int> (ityp1, 0) == 9); + b1.setStore (&store); + + b1.getData<int> (ityp1, 0) = 10; + cb1.getDecoration<int> (ityp2, 0) = 11; + assert (cb1.getData<int> (ityp1, 0) == 10); + assert (cb1.getData<int> (ityp2, 0) == 11); + + b1.lock(); + + assert (cb1.getData<int> (ityp1, 0) == 10); + //EXPECT_EXCEPTION (SG::ExcStoreLocked, b1.getData<int> (ityp1, 0)); + EXPECT_EXCEPTION (SG::ExcStoreLocked, b1.getDecoration<int> (ityp1, 0)); + + cb1.getDecoration<int> (ityp3, 0) = 14; + assert (cb1.getData<int> (ityp1, 0) == 10); + assert (cb1.getData<int> (ityp2, 0) == 11); + assert (cb1.getData<int> (ityp3, 0) == 14); + assert (cb1.getDecoration<int> (ityp3, 0) == 14); + + b1.clearDecorations(); + assert (cb1.getData<int> (ityp1, 0) == 10); + assert (cb1.getData<int> (ityp2, 0) == 11); + EXPECT_EXCEPTION (SG::ExcBadAuxVar, cb1.getData<int> (ityp3, 0)); + cb1.getDecoration<int> (ityp3, 0) = 15; +} + + +void test_move() +{ + std::cout << "test_move\n"; + +#if __cplusplus > 201100 + AuxVectorData_test b1; + SG::AuxStoreInternal store; + b1.setStore (&store); + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + b1.getData<int> (ityp, 0) = 1; + b1.getData<int> (ityp, 1) = 2; + assert (b1.getData<int> (ityp, 0) == 1); + assert (b1.getData<int> (ityp, 1) == 2); + + AuxVectorData_test b2 (std::move (b1)); + assert (b1.getConstStore() == 0); + assert (b1.getStore() == 0); + assert (b2.getConstStore() == &store); + assert (b2.getStore() == &store); + assert (b2.getData<int> (ityp, 0) == 1); + assert (b2.getData<int> (ityp, 1) == 2); + + AuxVectorData_test b3; + b3 = std::move (b2); + assert (b2.getConstStore() == 0); + assert (b2.getStore() == 0); + assert (b3.getConstStore() == &store); + assert (b3.getStore() == &store); + assert (b3.getData<int> (ityp, 0) == 1); + assert (b3.getData<int> (ityp, 1) == 2); +#endif +} + + +class ThreadingTest +{ +public: + ThreadingTest(); + void worker (AuxVectorData& b, size_t istart); + void worker_c (const AuxVectorData& b, size_t istart); + + void nonThreadedTest(); + void threadedTest(); + + struct testThread + { + testThread (ThreadingTest& test, AuxVectorData& b, int iworker) + : m_test(test), m_b (b), m_iworker(iworker) {} + void operator()() + { +#ifndef ATHCONTAINERS_NO_THREADS + boost::shared_lock_guard<boost::shared_mutex> guard (m_test.m_sm); +#endif // not ATHCONTAINERS_NO_THREADS + size_t istart = (m_iworker * 10) % m_test.m_nelt; + if (m_iworker&1) + m_test.worker (m_b, istart); + else + m_test.worker_c (m_b, istart); + } + + ThreadingTest& m_test; + AuxVectorData& m_b; + int m_iworker; + }; + + size_t m_nelt; + SG::AuxStoreInternal m_store; + std::vector<SG::auxid_t> m_ids; +#ifndef ATHCONTAINERS_NO_THREADS + boost::shared_mutex m_sm; +#endif // not ATHCONTAINERS_NO_THREADS +}; + + +ThreadingTest::ThreadingTest() + : m_nelt (1000) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + for (int i=0; i < 10000; i++) { + std::ostringstream ss; + ss << "xint" << i; + SG::auxid_t id = r.getAuxID<int> (ss.str()); + m_ids.push_back (id); + int* data = reinterpret_cast<int*> (m_store.getData (id, m_nelt, m_nelt)); + for (size_t j = 0; j < m_nelt; j++) + data[j] = id*1234 + j; + } +} + + +void ThreadingTest::worker (AuxVectorData& b, size_t istart) +{ + ATHCONTAINERS_FOREACH (SG::auxid_t id, m_ids) { + assert (b.getData<int> (id, istart) == static_cast<int>(id*1234 + istart)); + ++istart; + if (istart >= m_nelt) istart = 0; + } +} + + +void ThreadingTest::worker_c (const AuxVectorData& b, size_t istart) +{ + ATHCONTAINERS_FOREACH (SG::auxid_t id, m_ids) { + assert (b.getData<int> (id, istart) == static_cast<int>(id*1234 + istart)); + ++istart; + if (istart >= m_nelt) istart = 0; + } +} + + +void ThreadingTest::nonThreadedTest() +{ + AuxVectorData_test b; + b.setStore (&m_store); + worker (b, 0); + worker_c (b, 10); +} + + +void ThreadingTest::threadedTest() +{ +#ifndef ATHCONTAINERS_NO_THREADS + AuxVectorData_test b; + b.setStore (&m_store); + + int nthread = 10; + AthContainers_detail::thread threads[10]; + m_sm.lock(); + for (int i=0; i < nthread; i++) + threads[i] = AthContainers_detail::thread (testThread (*this, b, i)); + // Try to get the threads starting as much at the same time as possible. + m_sm.unlock(); + for (int i=0; i < nthread; i++) + threads[i].join(); +#endif +} + + +class TestStore + : public SG::IAuxStore +{ +public: + TestStore() {} + virtual const void* getData (SG::auxid_t) const { std::abort(); } + virtual void* getDecoration (SG::auxid_t, size_t, size_t) { std::abort(); } + virtual const SG::auxid_set_t& getAuxIDs() const { std::abort(); } + virtual void lock() { std::abort(); } + virtual void clearDecorations() { std::abort(); } + virtual size_t size() const { std::abort(); } + virtual void* getData (SG::auxid_t, size_t, size_t) { std::abort(); } + virtual const SG::auxid_set_t& getWritableAuxIDs() const { std::abort(); } + virtual bool resize (size_t) { std::abort(); } + virtual void reserve (size_t) { std::abort(); } + virtual void shift (size_t, ptrdiff_t) { std::abort(); } + virtual bool insertMove (size_t, IAuxStore&, const SG::auxid_set_t&) { std::abort(); } + + virtual bool setOption (SG::auxid_t auxid, const SG::AuxDataOption& option) + { + lastid = auxid; + lastopt = option; + return true; + } + + static SG::auxid_t lastid; + static SG::AuxDataOption lastopt; +}; + + +SG::auxid_t TestStore::lastid = 0; +SG::AuxDataOption TestStore::lastopt ("", 0); + + +void test_setoption() +{ + std::cout << "test_setoption\n"; + AuxVectorData_test b; + assert (!b.setOption (SG::null_auxid, SG::AuxDataOption ("opt", 1))); + b.setStore (new TestStore); + assert (!b.setOption (SG::null_auxid, SG::AuxDataOption ("opt", 1))); + assert (b.setOption (1, SG::AuxDataOption ("opt", 1))); + assert (TestStore::lastid == 1); + assert (TestStore::lastopt.name() == "opt"); + assert (TestStore::lastopt.intVal() == 1); + + SG::auxid_t xtyp = SG::AuxTypeRegistry::instance().getAuxID<int> ("xint"); + assert (b.setOption ("xint", SG::AuxDataOption ("opt2", 2))); + assert (TestStore::lastid == xtyp); + assert (TestStore::lastopt.name() == "opt2"); + assert (TestStore::lastopt.intVal() == 2); + + SG::auxid_t xtyp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("xint2", + "xcls"); + assert (b.setOption ("xint2", "xcls", SG::AuxDataOption ("opt3", 2.5))); + assert (TestStore::lastid == xtyp2); + assert (TestStore::lastopt.name() == "opt3"); + assert (TestStore::lastopt.floatVal() == 2.5); + + assert (b.setOption (1, "opt", 1)); + assert (TestStore::lastid == 1); + assert (TestStore::lastopt.name() == "opt"); + assert (TestStore::lastopt.intVal() == 1); + + assert (b.setOption ("xint", "opt2", 2)); + assert (TestStore::lastid == xtyp); + assert (TestStore::lastopt.name() == "opt2"); + assert (TestStore::lastopt.intVal() == 2); + + assert (b.setOption ("xint2", "xcls", "opt3", 2.5)); + assert (TestStore::lastid == xtyp2); + assert (TestStore::lastopt.name() == "opt3"); + assert (TestStore::lastopt.floatVal() == 2.5); +} + + +void test_storelink() +{ + std::cout << "test_storelink\n"; + + AuxVectorData_test b1; + assert (!b1.hasStore()); + + b1.setStore (DataLink<SG::IConstAuxStore> ("foo")); + assert (b1.getConstStoreLink().dataID() == "foo"); +} + + +void test_threading() +{ + std::cout << "test_threading\n"; + + ThreadingTest test; + test.nonThreadedTest(); + for (int i=0; i < 1000; i++) + test.threadedTest(); +} + + +// These aren't called; present just to check generation of optimized code. +double test_code (SG::auxid_t auxid, AuxVectorData_test& b) +{ + return b.getData<double> (auxid, 0) + b.getData<double> (auxid, 1); +} +double test_code (SG::auxid_t auxid, const AuxVectorData_test& b) +{ + return b.getData<double> (auxid, 0) + b.getData<double> (auxid, 1); +} + + +int main() +{ + SGTest::initTestStore(); + + // Make reallocations more frequent (the better to exercise them). + AuxVectorData_test::s_minCacheLen = 1; + test_get_data(); + test_swap(); + test_get_types(); + test_decoration(); + test_move(); + test_setoption(); + test_storelink(); + test_threading(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DVLCast_test.cxx b/EDM/athena/Control/AthContainers/test/DVLCast_test.cxx new file mode 100644 index 00000000..5da6e0c3 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DVLCast_test.cxx @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLCast_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file DVLCast_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Regression tests for DVLCast. + */ + + +#undef NDEBUG +#include "AthContainers/tools/DVLCast.h" +#include <cassert> + + +struct X1 +{ + X1(int the_x) : x (the_x) {} + int x; +}; + +struct X2 : public X1 +{ + X2(int the_y) : X1(the_y+1), y(the_y) {} + int y; +}; + +struct X3 : public X2 +{ + X3(int the_z) : X2(the_z+1), z(the_z) {} + int z; +}; + + +struct Y1 +{ + Y1(int the_x) : x (the_x) {} + int x; +}; + +struct Y2 : virtual public Y1 +{ + Y2(int the_y) : Y1(the_y+1), y(the_y) {} + int y; +}; + +struct Y3 : virtual public Y2 +{ + Y3(int the_z) : Y1(the_z+2), Y2(the_z+1), z(the_z) {} + int z; +}; + + + +struct Test1 +{ + typedef ::X1 B; + typedef ::X2 D; + typedef ::X3 DD; + typedef D base_value_type; + static const bool has_virtual = false; +}; + + +struct Test2 +{ + typedef ::Y1 B; + typedef ::Y2 D; + typedef ::Y3 DD; + typedef D base_value_type; + static const bool has_virtual = true; +}; + + +template <class T> +void tester() +{ + typedef typename T::B B; + typedef typename T::D D; + typedef typename T::DD DD; + typedef typename DataModel_detail::DVLCast<T> Cast; + + D d(1); + DD dd(2); + B* b = &d; + assert (Cast::cast (b) == &d); + const B* cb = &d; + assert (Cast::cast (cb) == &d); + + b = ⅆ + D* dd2 = ⅆ + assert (Cast::cast (b) == dd2); + cb = ⅆ + assert (Cast::cast (cb) == dd2); +} + + +int main() +{ + tester<Test1>(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/DVLDataBucket_test.cxx b/EDM/athena/Control/AthContainers/test/DVLDataBucket_test.cxx new file mode 100644 index 00000000..9dcef97b --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DVLDataBucket_test.cxx @@ -0,0 +1,279 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLDataBucket_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthContainers/test/DVLDataBucket_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2008 + * @brief Regression tests for DVLDataBucket. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include "AthContainers/DataVector.h" +#include "AthContainers/tools/DVLDataBucket.h" +#include "AthContainers/tools/DVLInfo.h" +#include "AthContainers/DataVector.h" +#include "AthContainers/DataList.h" +#include "AthContainers/ConstDataVector.h" +#include "AthContainers/ConstDataList.h" +#include "SGTools/BaseInfo.h" +#include "SGTools/IRegisterTransient.h" +#include "SGTools/CLASS_DEF.h" +#include "TestTools/expect_exception.h" +#include "CxxUtils/make_unique.h" +#include <vector> +#include <cassert> + + +struct Reg + : public SG::IRegisterTransient +{ + virtual void registerTransient (void* p); + std::vector<void*> m_log; +}; + + +void Reg::registerTransient (void* p) +{ + m_log.push_back (p); +} + + +struct A +{ + A(int x) : aa(x) {} + virtual ~A() { log.push_back (aa); } + int aa; + static std::vector<int> log; +}; +std::vector<int> A::log; + + +struct B +{ + B(int x) : bb(x) {} + virtual ~B() {} + int bb; +}; + + +struct D + : virtual public B, public A +{ + D(int x) : B(x+10), A(x+20), dd(x) {} + int dd; +}; + +SG_BASES2 (D, SG_VIRTUAL(B), A); +DATAVECTOR_VIRTBASES1(D, B); +DATALIST_VIRTBASES1(D, B); + +CLASS_DEF( DataVector<A> , 178538882, 1 ) +CLASS_DEF( DataVector<B> , 178538883, 1 ) +CLASS_DEF( DataVector<D> , 178538884, 1 ) +CLASS_DEF( DataList<A> , 178538885, 1 ) +CLASS_DEF( DataList<B> , 178538886, 1 ) +CLASS_DEF( DataList<D> , 178538887, 1 ) + + +template <class CONTA, class CONTB, class CONTD, class CONSTCONT> +void test1t() +{ + static DataModel_detail::DVLInfo<CONTA> xinfoa; + static DataModel_detail::DVLInfo<CONTB> xinfob; + static DataModel_detail::DVLInfo<CONTD> xinfod; + + Reg reg; + + SG::DVLDataBucket<CONTD>* buck = new SG::DVLDataBucket<CONTD>; + assert (buck->object() == 0); + delete buck; + + CONTD* contd = new CONTD; + for (int i=0; i < 10; i++) + contd->push_back (new D (i)); + + buck = new SG::DVLDataBucket<CONTD> (contd); + + assert (buck->clID() == ClassID_traits<CONTD>::ID()); + assert (buck->tinfo() == typeid(CONTD)); + + void* cont_p = buck->cast (typeid (CONTB), ®); + CONTB* contb = reinterpret_cast<CONTB*> (cont_p); + assert (contb == contd); + assert (reg.m_log.empty()); + + cont_p = buck->cast (typeid (CONTA), ®); + CONTA* conta = reinterpret_cast<CONTA*> (cont_p); + assert (reg.m_log.size() == 1); + assert (reg.m_log[0] == conta); + assert (conta->size() == 10); + typename CONTA::iterator it = conta->begin(); + for (int i=0; i < 10; i++) { + assert ((*it)->aa == i+20); + ++it; + } + + assert (cont_p == buck->cast (typeid (CONTA), ®)); + + cont_p = buck->cast (ClassID_traits<CONTA>::ID(), ®); + conta = reinterpret_cast<CONTA*> (cont_p); + assert (reg.m_log.size() == 1); + assert (reg.m_log[0] == conta); + assert (conta->size() == 10); + it = conta->begin(); + for (int i=0; i < 10; i++) { + assert ((*it)->aa == i+20); + ++it; + } + + for (int i=10; i < 20; i++) + contd->push_back (new D (i)); + + assert (cont_p == buck->cast (ClassID_traits<CONTA>::ID(), ®)); + + cont_p = buck->cast (ClassID_traits<CONTA>::ID(), ®); + conta = reinterpret_cast<CONTA*> (cont_p); + assert (reg.m_log.size() == 1); + assert (reg.m_log[0] == conta); + assert (conta->size() == 20); + it = conta->begin(); + for (int i=0; i < 20; i++) { + assert ((*it)->aa == i+20); + ++it; + } + + for (int i=20; i < 30; i++) + contd->push_back (new D (i)); + + assert (cont_p == buck->cast (typeid (CONTA), ®)); + + cont_p = buck->cast (typeid (CONTA), ®); + conta = reinterpret_cast<CONTA*> (cont_p); + assert (reg.m_log.size() == 1); + assert (reg.m_log[0] == conta); + assert (conta->size() == 30); + it = conta->begin(); + for (int i=0; i < 30; i++) { + assert ((*it)->aa == i+20); + ++it; + } + + SG::DVLDataBucket<CONTD>* buck2 = buck->clone(); + delete buck; + delete buck2; + + { + A::log.clear(); + CONSTCONT* pp = new CONSTCONT; + pp->push_back (new A (21)); + typedef typename SG::DataBucketTrait<CONSTCONT>::type BUCKET; + BUCKET* buck3 = new BUCKET (pp); + assert (A::log.empty()); + delete buck3; + std::vector<int> exp21; + exp21.push_back(21); + assert (A::log == exp21); + } + +#if __cplusplus > 201100 + { + A::log.clear(); + std::unique_ptr<CONTA> pp = CxxUtils::make_unique<CONTA>(); + pp->push_back (new A(11)); + typedef typename SG::DataBucketTrait<CONTA>::type BUCKET; + { + std::unique_ptr<BUCKET> buck3 = + CxxUtils::make_unique<BUCKET>(std::move(pp)); + assert (A::log.empty()); + } + assert (A::log == std::vector<int>{11}); + } + + { + A::log.clear(); + std::unique_ptr<CONSTCONT> pp (new CONSTCONT); + pp->push_back (new A (31)); + typedef typename SG::DataBucketTrait<CONSTCONT>::type BUCKET; + { + std::unique_ptr<BUCKET> buck3 = + CxxUtils::make_unique<BUCKET>(std::move(pp)); + assert (A::log.empty()); + } + assert (A::log == std::vector<int>{31}); + } +#endif +} + + +void test1() +{ + test1t<DataVector<A>, DataVector<B>, DataVector<D>, ConstDataVector<DataVector<A> > >(); + test1t<DataList<A>, DataList<B>, DataList<D>, ConstDataList<DataList<A> > >(); +} + + +typedef ViewVector<DataVector<A> > AView; +VIEWVECTOR_CLASS_DEF (AView, 491783424) + +typedef ViewVector<DataVector<B> > BView; + + +void test2() +{ + Reg reg; + + auto a1 = CxxUtils::make_unique<AView>(); + void* vp = a1.get(); + auto buck = CxxUtils::make_unique<SG::DVLDataBucket<DataVector<A> > > (a1.release()); + + assert (buck->clID() == 491783424); + assert (buck->tinfo() == typeid(AView)); + + assert (buck->cast(491783424, ®) == vp); + assert (buck->cast(178538882, ®) == vp); + assert (buck->cast(2987492385, ®) == nullptr); + + assert (buck->cast(typeid(AView), ®) == vp); + assert (buck->cast(typeid(DataVector<A>), ®) == vp); + assert (buck->cast(typeid(int), ®) == nullptr); + + a1 = CxxUtils::make_unique<AView>(); + vp = a1.get(); + buck = CxxUtils::make_unique<SG::DVLDataBucket<DataVector<A> > > (std::move(a1)); + + assert (buck->clID() == 491783424); + assert (buck->tinfo() == typeid(AView)); + + assert (buck->cast(491783424, ®) == vp); + assert (buck->cast(178538882, ®) == vp); + assert (buck->cast(2987492385, ®) == nullptr); + + assert (buck->cast(typeid(AView), ®) == vp); + assert (buck->cast(typeid(DataVector<A>), ®) == vp); + assert (buck->cast(typeid(int), ®) == nullptr); + + auto b1 = CxxUtils::make_unique<BView>(); + EXPECT_EXCEPTION (SG::ExcMissingViewVectorCLID, + CxxUtils::make_unique<SG::DVLDataBucket<DataVector<B> > > (b1.release())); +} + + +#else + +void test1() {} +void test2() {} + +#endif // not XAOD_STANDALONE + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/DVLInfo_test.cxx b/EDM/athena/Control/AthContainers/test/DVLInfo_test.cxx new file mode 100644 index 00000000..f3fca335 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DVLInfo_test.cxx @@ -0,0 +1,359 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLInfo_test.cxx 508150 2012-06-29 10:25:42Z ssnyder $ +/** + * @file AthContainers/test/DVLInfo_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2008 + * @brief Regression tests for DVLInfo. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include "AthContainers/tools/DVLInfo.h" +#include "SGTools/BaseInfo.h" +#include "SGTools/CLASS_DEF.h" +#include "boost/type_traits/remove_pointer.hpp" +#include <vector> +#include <list> +#include <cassert> + + +class Foo{}; +CLASS_DEF(Foo, 1234, 1) + + +class DVLInfoTest + : public DataModel_detail::DVLInfoBase +{ +public: + DVLInfoTest() : DVLInfoBase (typeid(Foo), typeid(double)) {} + virtual void* make (size_t nreserve) const; + virtual void push (void* cont_p, void* elt_p) const; + virtual size_t size (void* cont_p) const; + virtual void clear (void* cont_p) const; + virtual void del (void* cont_p) const; + virtual void* clone (void* cont_p) const; + virtual DataModel_detail::DVLIteratorBase* + iterator (const void* cont_p) const; + SG::AuxVectorBase* base (void* /*cont_p*/) const { return 0; } +}; + + +void* DVLInfoTest::make (size_t nreserve) const +{ + std::vector<int*>* vec = new std::vector<int*>; + vec->reserve (nreserve); + return vec; +} + + +void DVLInfoTest::push (void* cont_p, void* elt_p) const +{ + reinterpret_cast<std::vector<int*>*>(cont_p) -> push_back ((int*)elt_p); +} + + +size_t DVLInfoTest::size (void* cont_p) const +{ + return reinterpret_cast<std::vector<int*>*>(cont_p) -> size(); +} + + +void DVLInfoTest::clear (void* cont_p) const +{ + reinterpret_cast<std::vector<int*>*>(cont_p) -> clear(); +} + + +void DVLInfoTest::del (void* cont_p) const +{ + delete reinterpret_cast<std::vector<int*>*>(cont_p); +} + + +void* DVLInfoTest::clone (void* cont_p) const +{ + return new std::vector<int*> (*reinterpret_cast<std::vector<int*>*>(cont_p)); +} + + +DataModel_detail::DVLIteratorBase* +DVLInfoTest::iterator (const void* /*cont_p*/) const +{ + return 0; +} + + +void test_DVLInfoBase() +{ + static DVLInfoTest info; + assert (DataModel_detail::DVLInfoBase::find (typeid (float)) == 0); + DataModel_detail::DVLInfoBase* info2 = + DataModel_detail::DVLInfoBase::find (typeid (Foo)); + assert (info2 == &info); + assert (info2->tinfo() == typeid (Foo)); + assert (info2->clid() == 1234); + assert (info2->elt_tinfo() == typeid (double)); + info2 = DataModel_detail::DVLInfoBase::find (1234); + assert (info2 == &info); + + void* cont_p = info2->make (5); + info2->push (cont_p, new int(1)); + info2->push (cont_p, new int(2)); + assert (info2->base(cont_p) == 0); + + std::vector<int*>* vec = reinterpret_cast<std::vector<int*>*> (cont_p); + assert (vec->capacity() == 5); + assert (vec->size() == 2); + assert (*(*vec)[0] == 1); + assert (*(*vec)[1] == 2); + assert (info2->size (cont_p) == 2); + + std::vector<int*>* vec2 = + reinterpret_cast<std::vector<int*>*> (info2->clone (cont_p)); + assert (vec2 != vec); + assert (vec2->size() == 2); + assert (*(*vec2)[0] == 1); + assert (*(*vec2)[1] == 2); + assert (info2->size (vec2) == 2); + info2->clear (vec2); + assert (info2->size (vec2) == 0); + assert (vec2->size() == 0); + + info2->del (vec); + + assert (info2->iterator (vec2) == 0); +} + + +template <class T> +class mycont + : public T +{ +public: + typedef typename boost::remove_pointer<typename T::value_type>::type + base_value_type; + mycont (SG::OwnershipPolicy pol) : m_pol (pol) {} + T& stdcont() { return *this; } + + SG::OwnershipPolicy m_pol; +}; + + +typedef mycont<std::vector<int*> > myvec; +typedef mycont<std::list<int*> > mylist; + + +class myvec2 + : public myvec, public SG::AuxVectorBase +{ +public: + myvec2 (SG::OwnershipPolicy pol = SG::VIEW_ELEMENTS) : myvec (pol) {} + myvec2 (const myvec2&) : myvec (SG::VIEW_ELEMENTS), SG::AuxVectorBase() {} + myvec2& operator= (const myvec2&) = delete; + virtual size_t capacity_v() const { return 0; } + virtual size_t size_v() const { return 0; } +}; + + + +template <class T> +void dvl_makecontainer (size_t nreserve, mycont<std::vector<T> >*& cont) +{ + cont = new mycont<std::vector<T> > (SG::VIEW_ELEMENTS); + cont->reserve (nreserve); +} + + +template <class T> +void dvl_makecontainer (size_t /*nreserve*/, mycont<std::list<T> >*& cont) +{ + cont = new mycont<std::list<T> > (SG::VIEW_ELEMENTS); +} + + + +CLASS_DEF (myvec, 7428347, 1) +CLASS_DEF (mylist, 7428348, 1) + + +template <class CONT> +CONT* test_DVLInfo1 () +{ + static DataModel_detail::DVLInfo<CONT> info; + assert (DataModel_detail::DVLInfoBase::find (typeid (float)) == 0); + DataModel_detail::DVLInfoBase* info2 = + DataModel_detail::DVLInfoBase::find (typeid (CONT)); + assert (info2 == &info); + info2 = DataModel_detail::DVLInfoBase::find (ClassID_traits<CONT>::ID()); + assert (info2 == &info); + + assert (info2->tinfo() == typeid (CONT)); + assert (info2->clid() == ClassID_traits<CONT>::ID()); + assert (info2->elt_tinfo() == typeid (int)); + + void* cont_p = info2->make (5); + info2->push (cont_p, new int(1)); + info2->push (cont_p, new int(2)); + + CONT* cont = (CONT*)cont_p; + assert (cont->m_pol == SG::VIEW_ELEMENTS); + assert (cont->size() == 2); + typename CONT::iterator it = cont->begin(); + assert (**it == 1); + ++it; + assert (**it == 2); + assert (info2->size (cont_p) == 2); + + CONT* cont2 = reinterpret_cast<CONT*> (info2->clone (cont_p)); + assert (cont2 != cont); + assert (cont2->m_pol == SG::VIEW_ELEMENTS); + assert (cont2->size() == 2); + it = cont2->begin(); + assert (**it == 1); + ++it; + assert (**it == 2); + + assert (info2->size (cont2) == 2); + info2->clear(cont2); + assert (info2->size (cont2) == 0); + assert (cont2->size() == 0); + + info2->del (cont2); + + CONT cont3 (SG::VIEW_ELEMENTS); + for (int i = 0; i < 10; i++) { + cont3.push_back (new int (i)); + cont3.push_back ((int*)0); + } + DataModel_detail::DVLIteratorBase* iit = info2->iterator (&cont3); + int ii = 0; + while (const void* p = iit->next()) { + const int* pp = reinterpret_cast<const int*> (p); + assert (*pp == ii); + ++ii; + } + + return cont; +} + + + +void test_DVLInfo() +{ + myvec* vec = test_DVLInfo1<myvec>(); + assert (vec->capacity() == 5); + test_DVLInfo1<mylist> (); + + static DataModel_detail::DVLInfo<myvec> info; + assert (info.base(vec) == 0); + + myvec2 vec2 (SG::VIEW_ELEMENTS); + static DataModel_detail::DVLInfo<myvec2> info2; + assert (info2.base(&vec2) == &vec2); +} + + +struct B +{ + B(int x) : bb(x) {} + virtual ~B() {} + int bb; +}; + + +struct D + : virtual public B +{ + D(int x) : B(x+10), dd(x) {} + int dd; +}; + +SG_BASE (D, SG_VIRTUAL(B)); + + +typedef mycont<std::vector<B*> > myvecb; +typedef mycont<std::vector<D*> > myvecd; +typedef mycont<std::list<B*> > mylistb; +typedef mycont<std::list<D*> > mylistd; + +CLASS_DEF (myvecb, 7428349, 1) +CLASS_DEF (myvecd, 7428350, 1) +CLASS_DEF (mylistb, 7428351, 1) +CLASS_DEF (mylistd, 7428352, 1) + + +template <class CONTB, class CONTD, class CONTI> +void test_dvl_convert1() +{ + static DataModel_detail::DVLInfo<CONTB> info; + + CONTD contd (SG::VIEW_ELEMENTS); + for (int i=0; i < 10; i++) + contd.push_back (new D(i)); + + DataModel_detail::DVLInfoBase* info2; + void* newp = DataModel_detail::dvl_convert (contd, typeid (CONTI), info2); + assert (newp == 0); + newp = DataModel_detail::dvl_convert (contd, typeid (CONTB), info2); + assert (info2->tinfo() == info.tinfo()); + CONTB* contb = reinterpret_cast<CONTB*> (newp); + assert (contb->size() == 10); + typename CONTB::iterator it = contb->begin(); + for (int i=0; i < 10; i++) { + assert ((*it)->bb = i+10); + ++it; + } + + newp = DataModel_detail::dvl_convert (contd, + ClassID_traits<CONTB>::ID(), info2); + assert (info2->tinfo() == info.tinfo()); + contb = reinterpret_cast<CONTB*> (newp); + assert (contb->size() == 10); + it = contb->begin(); + for (int i=0; i < 10; i++) { + assert ((*it)->bb = i+10); + ++it; + } + + CONTD contd2 (SG::VIEW_ELEMENTS); + for (int i=9; i >= 0; i--) + contd.push_back (new D(i)); + DataModel_detail::dvl_update (contd2, newp, info2); + it = contb->begin(); + for (int i=9; i >= 0; i--) { + assert ((*it)->bb = i+10); + ++it; + } +} + + +void test_dvl_convert() +{ + D* d1 = new D(1); + B* b1 = d1; + assert ((void*)b1 != (void*)d1); + test_dvl_convert1<myvecb, myvecd, myvec>(); +} + + +int main() +{ + test_DVLInfoBase(); + test_DVLInfo(); + test_dvl_convert(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DVLIterator_test.cxx b/EDM/athena/Control/AthContainers/test/DVLIterator_test.cxx new file mode 100644 index 00000000..173b778a --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DVLIterator_test.cxx @@ -0,0 +1,313 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLIterator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file DVLIterator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Regression tests for DVLIterator. + */ + + +#undef NDEBUG + + +#include "AthContainers/tools/DVLIterator.h" +#include "AthContainers/exceptions.h" +#include <vector> +#include <list> +#include <cassert> + + +struct X1 +{ + X1(int the_x) : x(the_x) {} + virtual ~X1() {} + int x; +}; +struct X2 : virtual public X1 +{ + X2(int the_x) : X1(the_x) {} +}; + +struct Cont1 +{ + typedef Cont1 Cont; + typedef X1 base_value_type; + typedef std::vector<X1*> BaseContainer; + static const bool has_virtual = false; + + typedef base_value_type* value_type; + typedef const base_value_type* const_value_type; + typedef base_value_type** pointer; + typedef DataModel_detail::ElementProxy<Cont> ElementProxy; + typedef DataModel_detail::const_iterator<Cont> const_iterator; + + Cont1 (SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + bool can_insert = true) + : m_ownPolicy (ownPolicy), + m_can_insert (can_insert) + {} + + SG::OwnershipPolicy ownPolicy() const { return m_ownPolicy; } + void testInsert (const char* op) + { + if (!m_can_insert) + throw SG::ExcInsertionInBaseClass (op, typeid(int), typeid(int)); + } + + SG::OwnershipPolicy m_ownPolicy; + bool m_can_insert; +}; + + +struct Cont2 +{ + typedef Cont2 Cont; + typedef X2 base_value_type; + typedef std::vector<X1*> BaseContainer; + static const bool has_virtual = true; + + typedef base_value_type* value_type; + typedef const base_value_type* const_value_type; + typedef base_value_type** pointer; + typedef DataModel_detail::ElementProxy<Cont> ElementProxy; + typedef DataModel_detail::const_iterator<Cont> const_iterator; + + Cont2 (SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + bool can_insert = true) + : m_ownPolicy (ownPolicy), + m_can_insert (can_insert) + {} + + SG::OwnershipPolicy ownPolicy() const { return m_ownPolicy; } + void testInsert (const char* op) + { + if (!m_can_insert) + throw SG::ExcInsertionInBaseClass (op, typeid(int), typeid(int)); + } + + SG::OwnershipPolicy m_ownPolicy; + bool m_can_insert; +}; + + +struct Cont3 +{ + typedef Cont3 Cont; + typedef X1 base_value_type; + typedef std::list<X1*> BaseContainer; + static const bool has_virtual = false; + + typedef base_value_type* value_type; + typedef const base_value_type* const_value_type; + typedef base_value_type** pointer; + typedef DataModel_detail::ElementProxy<Cont> ElementProxy; + typedef DataModel_detail::const_iterator<Cont> const_iterator; + + Cont3 (SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + bool can_insert = true) + : m_ownPolicy (ownPolicy), + m_can_insert (can_insert) + {} + + SG::OwnershipPolicy ownPolicy() const { return m_ownPolicy; } + void testInsert (const char* op) + { + if (!m_can_insert) + throw SG::ExcInsertionInBaseClass (op, typeid(int), typeid(int)); + } + + SG::OwnershipPolicy m_ownPolicy; + bool m_can_insert; +}; + + +struct Cont4 +{ + typedef Cont4 Cont; + typedef X2 base_value_type; + typedef std::list<X1*> BaseContainer; + static const bool has_virtual = true; + + typedef base_value_type* value_type; + typedef const base_value_type* const_value_type; + typedef base_value_type** pointer; + typedef DataModel_detail::ElementProxy<Cont> ElementProxy; + typedef DataModel_detail::const_iterator<Cont> const_iterator; + + Cont4 (SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + bool can_insert = true) + : m_ownPolicy (ownPolicy), + m_can_insert (can_insert) + {} + + SG::OwnershipPolicy ownPolicy() const { return m_ownPolicy; } + void testInsert (const char* op) + { + if (!m_can_insert) + throw SG::ExcInsertionInBaseClass (op, typeid(int), typeid(int)); + } + + SG::OwnershipPolicy m_ownPolicy; + bool m_can_insert; +}; + + +template <class CONT, class CAT> +void test1_extra (CAT /*cat*/) +{ +} +template <class CONT> +void test1_extra (std::random_access_iterator_tag /*cat*/) +{ + typedef DataModel_detail::const_iterator<CONT> const_iterator; + typedef DataModel_detail::iterator<CONT> iterator; + + typename CONT::BaseContainer v; + typedef typename CONT::base_value_type T; + CONT cont; + T* t1 = new T(1); + T* t2 = new T(2); + T* t3 = new T(3); + v.push_back (t1); + v.push_back (t2); + v.push_back (t3); + + const_iterator c1 (v.begin()); + const_iterator c2 (v.begin()+2); + + iterator i1 (v.begin(), &cont); + iterator i2 (v.begin()+2, &cont); + + assert (c1 < c2); + assert (!(c2 < c1)); + assert (!(c1 < c1)); + assert (c1 <= c2); + assert (c1 <= c1); + assert (!(c2 <= c1)); + assert (c2 > c1); + assert (!(c1 > c2)); + assert (!(c1 > c1)); + assert (c2 >= c1); + assert (!(c1 >= c2)); + assert (c1 >= c1); + + assert (i1 < i2); + assert (!(i2 < i1)); + assert (!(i1 < i1)); + assert (i1 <= i2); + assert (i1 <= i1); + assert (!(i2 <= i1)); + assert (i2 > i1); + assert (!(i1 > i2)); + assert (!(i1 > i1)); + assert (i2 >= i1); + assert (!(i1 >= i2)); + assert (i1 >= i1); + + assert (c1 < i2); + assert (!(i2 < c1)); + assert (!(c1 < c1)); + assert (c1 <= i2); + assert (c1 <= c1); + assert (!(i2 <= c1)); + assert (i2 > c1); + assert (!(c1 > i2)); + assert (!(c1 > c1)); + assert (i2 >= c1); + assert (!(c1 >= i2)); + assert (c1 >= c1); + + assert (i1 < c2); + assert (!(c2 < i1)); + assert (!(i1 < i1)); + assert (i1 <= c2); + assert (i1 <= i1); + assert (!(c2 <= i1)); + assert (c2 > i1); + assert (!(i1 > c2)); + assert (!(i1 > i1)); + assert (c2 >= i1); + assert (!(i1 >= c2)); + assert (i1 >= i1); + + assert (c2 - c1 == 2); + assert (i2 - i1 == 2); + assert (c2 - i1 == 2); + assert (i2 - c1 == 2); + + assert (i1[0]->x == 1); + assert (i1[1]->x == 2); + assert (i1[2]->x == 3); +} +template <class CONT> +void test1_cont() +{ + typedef DataModel_detail::const_iterator<CONT> const_iterator; + typedef DataModel_detail::iterator<CONT> iterator; + + typename CONT::BaseContainer v; + typedef typename CONT::base_value_type T; + CONT cont; + T* t1 = new T(1); + T* t2 = new T(2); + T* t3 = new T(3); + v.push_back (t1); + v.push_back (t2); + v.push_back (t3); + + const_iterator c1; + const_iterator c2 (v.begin()); + assert (*c2 == t1); + + CONT cont3 (SG::OWN_ELEMENTS, false); + iterator i1; + iterator i2 (v.begin(), &cont3); + assert (i2.ownPolicy() == SG::OWN_ELEMENTS); + bool caught = false; + try { + i2.testInsert("foo"); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + assert (caught); + + assert (*i2 == t1); + assert (i1.container() == 0); + assert (i2.container() == &cont3); + + CONT cont2 (SG::VIEW_ELEMENTS); + iterator i3 (v.begin(), &cont2); + assert (i3.ownPolicy() == SG::VIEW_ELEMENTS); + i3.testInsert("foo"); + + assert (c2 == c2); + assert (c1 != c2); + assert (i2 == i2); + assert (i1 != i2); + + assert (i2 == c2); + assert (c2 == i2); + assert (i1 != c2); + assert (c1 != i2); + + test1_extra<CONT> (typename iterator::iterator_category()); +} +void test1() +{ + test1_cont<Cont1>(); + test1_cont<Cont2>(); + test1_cont<Cont3>(); + test1_cont<Cont4>(); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/DVL_iter_swap_test.cxx b/EDM/athena/Control/AthContainers/test/DVL_iter_swap_test.cxx new file mode 100644 index 00000000..85e6fca7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DVL_iter_swap_test.cxx @@ -0,0 +1,234 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVL_iter_swap_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file DVL_iter_swap_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Regression tests for DVL_iter_swap. + */ + + +#undef NDEBUG + + +//*************************************************************************** +// Change assertions failures to exceptions, so we can catch them. +// + +#include <string> +#include <stdexcept> +#include <sstream> + +class test_err + : public std::exception +{ +public: + explicit test_err (const char* file, + int line, + const char* what); + virtual ~test_err() throw() {} + virtual const char* what() const throw() { return m_what.c_str(); } +private: + std::string m_what; +}; + + +test_err::test_err (const char* file, + int line, + const char* what) +{ + std::ostringstream os; + os << file << ":" << line << " assertion failure: " << what; + m_what = os.str(); +} + + +void throw_test_err (const char* file, int line, const char* what) +{ + throw (test_err (file, line, what)); +} + +#define ATHCONTAINERS_ASSERT(X) do { \ + if (!(X)) { \ + throw_test_err (__FILE__, __LINE__, #X); \ + } \ + } while (0) + +//*************************************************************************** + + +#include "AthContainers/tools/DVL_iter_swap.h" +#include "AthContainers/tools/DVLIterator.h" +#include "AthContainers/exceptions.h" +#include <vector> +#include <cassert> + + +struct X1 +{ + X1(int the_x) : x(the_x) {} + virtual ~X1() {} + int x; +}; + + +struct Cont1 +{ + typedef Cont1 Cont; + typedef X1 base_value_type; + typedef std::vector<X1*> BaseContainer; + static const bool has_virtual = false; + + typedef base_value_type* value_type; + typedef const base_value_type* const_value_type; + typedef base_value_type** pointer; + typedef DataModel_detail::ElementProxy<Cont> ElementProxy; + typedef DataModel_detail::const_iterator<Cont> const_iterator; + typedef DataModel_detail::iterator<Cont> iterator; + + Cont1 (SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + bool can_insert = true) + : m_ownPolicy (ownPolicy), + m_can_insert (can_insert) + {} + + SG::OwnershipPolicy ownPolicy() const { return m_ownPolicy; } + void testInsert (const char* op) + { + if (!m_can_insert) + throw SG::ExcInsertionInBaseClass (op, typeid(int), typeid(int)); + } + + static void + iter_swap (iterator a, iterator b) + { + ATHCONTAINERS_ASSERT (a.ownPolicy() == b.ownPolicy()); + a.testInsert("iter_swap"); + b.testInsert("iter_swap"); + std::iter_swap (a.base(), b.base()); + m_x1 = *a; + m_x2 = *b; + } + + SG::OwnershipPolicy m_ownPolicy; + bool m_can_insert; + static X1* m_x1; + static X1* m_x2; +}; + + +X1* Cont1::m_x1 = 0; +X1* Cont1::m_x2 = 0; + + +void test1() +{ + typedef DataModel_detail::iterator<Cont1> iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + Cont1 cont; + + std::vector<X1*> v; + v.push_back (new X1(1)); + v.push_back (new X1(2)); + + iterator i1 (v.begin(), &cont); + iterator i2 (v.begin()+1, &cont); + assert ((*i1)->x == 1); + assert ((*i2)->x == 2); + std::iter_swap (i1, i2); + assert ((*i2)->x == 1); + assert ((*i1)->x == 2); + assert (cont.m_x1->x == 2); + assert (cont.m_x2->x == 1); + + Cont1 cont3 (SG::OWN_ELEMENTS, false); + iterator i3 (v.begin()+1, &cont3); + bool caught = false; + try { + std::iter_swap (i1, i3); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + assert (caught); + + caught = false; + try { + std::iter_swap (i3, i1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + assert (caught); + + Cont1 cont2 (SG::VIEW_ELEMENTS); + iterator i4 (v.begin()+1, &cont2); + caught = false; + try { + std::iter_swap (i1, i4); + } + catch (test_err&) { + caught = true; + } + assert (caught); + + iterator i5 (v.begin(), &cont2); + std::iter_swap (i4, i5); + assert ((*i1)->x == 1); + assert ((*i2)->x == 2); + + //************************************************* + + reverse_iterator ri1 (iterator (v.begin()+1, &cont)); + reverse_iterator ri2 (iterator (v.begin()+2, &cont)); + assert ((*ri1)->x == 1); + assert ((*ri2)->x == 2); + std::iter_swap (ri1, ri2); + assert ((*ri2)->x == 1); + assert ((*ri1)->x == 2); + + reverse_iterator ri3 (iterator (v.begin()+2, &cont3)); + caught = false; + try { + std::iter_swap (ri1, ri3); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + assert (caught); + + caught = false; + try { + std::iter_swap (ri3, ri1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + assert (caught); + + reverse_iterator ri4 (iterator (v.begin()+2, &cont2)); + caught = false; + try { + std::iter_swap (ri1, ri4); + } + catch (test_err&) { + caught = true; + } + assert (caught); + + reverse_iterator ri5 (iterator (v.begin()+1, &cont2)); + std::iter_swap (ri4, ri5); + assert ((*ri1)->x == 1); + assert ((*ri2)->x == 2); +} + + +int main() +{ + test1(); + return 0; +} + diff --git a/EDM/athena/Control/AthContainers/test/DataList_test.cxx b/EDM/athena/Control/AthContainers/test/DataList_test.cxx new file mode 100644 index 00000000..69e5d5ed --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataList_test.cxx @@ -0,0 +1,3484 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include <cassert> +#include <stdexcept> +#include <string> +#include <sstream> +#include <iomanip> +#include <iostream> +#include <vector> +#include <boost/iterator_adaptors.hpp> +#include <boost/iterator/indirect_iterator.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/concept_check.hpp> +#include "SGTools/CLASS_DEF.h" +#include "CxxUtils/unused.h" + + +class dl_test_err + : public std::exception +{ +public: + explicit dl_test_err (const char* file, + int line, + const char* what); + virtual ~dl_test_err() throw() {} + virtual const char* what() const throw() { return m_what.c_str(); } +private: + std::string m_what; +}; + + +dl_test_err::dl_test_err (const char* file, + int line, + const char* what) +{ + std::ostringstream os; + os << file << ":" << line << " myassertion failure: " << what; + m_what = os.str(); +} + + +void throw_dl_test_err (const char* file, int line, const char* what) +{ + throw (dl_test_err (file, line, what)); +} + +#define myassert(X) do { \ + if (!(X)) { \ + throw_dl_test_err (__FILE__, __LINE__, #X); \ + } \ + } while (0) + + +#define ATHCONTAINERS_ASSERT(X) myassert(X) + +#include "AthContainers/DataList.h" +#include "AthContainers/ConstDataList.h" +#include "AthContainers/exceptions.h" +#include "TestTools/random.h" + + +Athena_test::RNG stlrand; + + +using boost::assign::list_of; + + +//************************************************************************ + +struct AbsFluff { + static int s_alive; + AbsFluff() { ++s_alive; } + virtual ~AbsFluff() { + std::cout << " ----> Destructor of AbsFluff called for " << this + << ". After return, left alive " << --s_alive << std::endl; + } + virtual void foo() = 0; + virtual void cfoo() const = 0; +}; + +int AbsFluff::s_alive = 0; + +struct DerivedFluff : public AbsFluff { + int m_int; + float m_float; + std::string m_string; + virtual ~DerivedFluff() + { + // std::cout << " ----> Destructor of DerivedFluff called for " << this << std::endl; + } + std::string m_anotherString; + DerivedFluff() : AbsFluff(), m_int(1), m_float(-379.456f), + m_string("this is the Fluff struct"), + m_anotherString("this is the DerivedFluff struct") { } + DerivedFluff(const DerivedFluff& rhs) : + AbsFluff(), + m_int(rhs.m_int), m_float(-379.456f), + m_string("this is the Fluff struct") { } + DerivedFluff& operator= (const DerivedFluff&) = delete; + + virtual void foo() { /* std::cout << "foo called" << std::endl; */ } + virtual void cfoo() const { /* std::cout << "foo called" << std::endl; */ } +}; + +class FluffList : public DataList<DerivedFluff> +{ +public: + FluffList() : DataList<DerivedFluff>() { }; + virtual ~FluffList() {} +}; + + +void test1 () +{ + std::cout << "*** DataList_test test1 BEGIN ***" << std::endl; + typedef DataList<int> IntList; + IntList intL; + myassert(intL.empty()); + + unsigned int i; + const unsigned int IFILL(3); + for (i=0; i<IFILL; ++i) intL.push_back(new int(i)); + myassert (IFILL == intL.size()); + myassert(std::distance(intL.begin(), intL.end()) == (int)IFILL); + myassert( *(intL.front()) == 0); + myassert(2 == *(intL.back())); + intL.front() = new int(7); + myassert(7 == *(intL.front())); + *(intL.back()) = 3; + myassert(3 == *(intL.back())); + { + std::ostream_iterator<int*> os(std::cout, " "); + std::cout << "intL: " << std::hex; + std::copy(intL.begin(), intL.end(), os); + std::cout << std::dec <<std::endl; + std::ostream_iterator<int> intos(std::cout, " "); + /*1.30 boost::indirect_iterator_generator<DataList<int>::iterator, int>::type + intLF(intL.begin()), intLL(intL.end()); */ + boost::indirect_iterator<DataList<int>::iterator, int> intLF(intL.begin()); + boost::indirect_iterator<DataList<int>::iterator, int> intLL(intL.end()); + copy(intLF, intLL, intos); + std::cout <<std::endl; + } + + //FIXME does not work DataList<int> intL2(5, new int(5)); + DataList<int> intL2; + for (unsigned int i=0; i<5; ++i) intL2.push_back( new int(5) ); + myassert (5 == intL2.size()); + { + DataList<int>::const_iterator itrList = intL2.begin(); + myassert (5 == **itrList); + ++itrList; myassert(5 == **itrList); + ++itrList; myassert(5 == **itrList); + ++itrList; myassert(5 == **itrList); + ++itrList; myassert(5 == **itrList); + } + + { + DataList<int>::iterator itrList = intL2.begin(); + std::advance( itrList, 4 ); + (*itrList) = new int(6); + itrList = intL2.begin(); + std::advance( itrList, 4 ); + myassert (6 == **itrList); + } + { + std::ostream_iterator<int*> os(std::cout, " "); + std::cout << "intL2: " << std::hex; + std::copy(intL2.begin(), intL2.end(), os); + std::cout << std::dec <<std::endl; + std::ostream_iterator<int> intos(std::cout, " "); + /*1.30 boost::indirect_iterator_generator<DataList<int>::iterator, int>::type + intL2F(intL2.begin()), intL2L(intL2.end()); */ + boost::indirect_iterator<DataList<int>::iterator, int> intL2F(intL2.begin()); + boost::indirect_iterator<DataList<int>::iterator, int> intL2L(intL2.end()); + copy(intL2F, intL2L, intos); + std::cout <<std::endl; + } + + + DataList<int>* pintLZeros(new DataList<int>(10)); + delete pintLZeros; pintLZeros=0; + + DataList<int> testConst; + testConst.push_back(new int(-1)); + testConst.push_back(new int(-2)); + DataList<int>::const_iterator ci(testConst.begin()), ce(testConst.end()); + while (ci != ce) { + const int* UNUSED(cp) = *ci; + cp = 0; //remove warning + //this is bad but unfortunately correct: a DataList<int> is like a + //list<int*>. list<int*>::const_iterator has type (int* const)* + //and not (const int*)*. It is hence legal to do + int* p = *ci; //assign a int* const to a int* + *p = 77; //OUCH! + ++ci; + } + + + DataList<int> intL3(intL2.begin(), intL2.end()); + myassert (5 == intL3.size()); + { + DataList<int>::const_iterator itrList = intL3.begin(); + std::advance( itrList, 3 ); + myassert (5 == **itrList ); + std::advance( itrList, 1 ); + myassert (6 == **itrList ); + } + + + DataList<DerivedFluff>* dfluff = new DataList<DerivedFluff>(); + dfluff->push_back(new DerivedFluff()); + dfluff->push_back(new DerivedFluff()); + int count(AbsFluff::s_alive); + { + std::ostream_iterator<DerivedFluff*> os(std::cout, " "); + std::cout << "dfluff: " << std::hex; + std::copy(dfluff->begin(), dfluff->end(), os); + std::cout << std::dec <<std::endl; + } + + myassert(2 == dfluff->size()); + + + DataList<DerivedFluff>::iterator iter = dfluff->begin(); + int n = 0; + for (; iter != dfluff->end(); iter++) { + (*iter)->foo(); + n++; + } + myassert (2 == n); + + (dfluff->front())->cfoo(); + + (*(dfluff->back())).foo(); + //FIXME dfluff->back()->foo(); DNC: side effect of ElementProxy + + // copy: + + DataList<DerivedFluff>* fluff2 = new DataList<DerivedFluff>(*dfluff); + myassert(2 == fluff2->size()); + myassert(count == AbsFluff::s_alive); + + // copy using iterators: + DataList<DerivedFluff>* fluff3 = new DataList<DerivedFluff>(dfluff->begin(), dfluff->end()); + myassert(2 == fluff3->size()); + myassert(count == AbsFluff::s_alive); + + // delete copy: + std::cout << " --> Now deleting copied list, but it should not delete elements as it does not own them. You should not see message of Element Destructor" << std::endl; + delete fluff2; fluff2=0; + std::cout << " <-- delete done" << std::endl; + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now deleting list copied via iterator. You should NOT see the elements being deleted" << std::endl; + count = AbsFluff::s_alive; + delete fluff3; fluff3=0; + std::cout << " <-- delete done" << std::endl; + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now resizing DataList<DerivedFluff>" << std::endl; + std::cout << " --> You should see one DerivedFluff object being deleted" << std::endl; + count = AbsFluff::s_alive - 1; + const int dfluffNewSize = dfluff->size()-1; + dfluff->resize(dfluffNewSize); //reduce dfluff by one + std::cout << " <-- resize done" << std::endl; + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now deleting DataList<DerivedFluff>. You should see all remaining DerivedFluff objects being deleted" << std::endl; + count = AbsFluff::s_alive - dfluff->size(); + delete dfluff; dfluff=0; + std::cout << " <-- delete done" << std::endl; + myassert(count == AbsFluff::s_alive); + + // std::cout << " Working with a subclass of DataList " << std::endl; + FluffList fc; + { + DerivedFluff* f1 = new DerivedFluff(); + DerivedFluff* f2 = new DerivedFluff(); + DerivedFluff* f3 = new DerivedFluff(); + DerivedFluff* f4 = new DerivedFluff(); + + fc.push_back(f1); + fc.push_back(f2); + fc.push_back(f3); + fc.push_back(f4); + } + count = AbsFluff::s_alive; + std::cout << " --> Now erasing one element of the DerivedFluff container. You should see one instance being deleted" << std::endl; + fc.erase(fc.begin(), ++fc.begin()); + std::cout << " <-- erase done" << std::endl; + myassert(fc.size() == 3); + myassert(count - 1 == AbsFluff::s_alive); + + FluffList copyFluff, *pcopy; + count = AbsFluff::s_alive; + copyFluff = fc; + myassert(count == AbsFluff::s_alive); //op = makes pcopy a view + count = AbsFluff::s_alive; + pcopy = new FluffList(fc); + myassert(count == AbsFluff::s_alive); //copy constr makes pcopy a view + delete pcopy; pcopy=0; + myassert(count == AbsFluff::s_alive); //copy constr makes pcopy a view + + // DataList with ownership: + DataList<DerivedFluff> dfluff5; + DerivedFluff *pdf( new DerivedFluff()); + count = AbsFluff::s_alive + 9; + // dfluff5.assign(10, pdf); + dfluff5.push_back(pdf); //take ownership + for(unsigned int i=1; i<10; ++i) dfluff5.push_back(new DerivedFluff(*pdf)); + + myassert(dfluff5.size() == 10); + myassert(count == AbsFluff::s_alive); + // dfluff5.insert(dfluff5.begin(), 10, (DerivedFluff*)0); + DataList<DerivedFluff>::iterator it5(dfluff5.begin()); + for(unsigned int i=0; i<10; ++i) it5 = dfluff5.insert(it5, 0); + myassert(count == AbsFluff::s_alive); + myassert(dfluff5.size() == 20); + + // DataList without ownership: + DataList<DerivedFluff>* dfluff4 = + new DataList<DerivedFluff>(SG::VIEW_ELEMENTS); + DerivedFluff *p1(new DerivedFluff()), *p2(new DerivedFluff()); + dfluff4->push_back(p1); + dfluff4->push_back(p2); + count = AbsFluff::s_alive; + std::cout << " --> Now resizing view container. You should NOT see the elements being deleted" << std::endl; + dfluff4->resize(0); //empties dfluff4; + std::cout << " <-- resize done" << std::endl; + myassert(0 == dfluff4->size()); + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now deleting two DerivedFluff instances" << std::endl; + delete p1; + delete p2; + std::cout << " <-- delete done" << std::endl; + + + count = AbsFluff::s_alive; + // dfluff4->assign(10, pdf); + //whatever this means... + for(unsigned int i=0; i<10; ++i) dfluff4->push_back(pdf); + myassert(dfluff4->size() == 10); + myassert(count == AbsFluff::s_alive); + // dfluff4->insert(dfluff4->begin(), 10, (DerivedFluff*)0); + DataList<DerivedFluff>::iterator it(dfluff4->begin()); + for(unsigned int i=0; i<10; ++i) it = dfluff4->insert(it, 0); + myassert(count == AbsFluff::s_alive); + myassert(dfluff4->size() == 20); + + delete dfluff4; dfluff4=0; + + //FIXME what is the right thing to do? Put in 5 NULLs or give a compilation + // error? + count = AbsFluff::s_alive; + DataList<AbsFluff> absFluff(5); + myassert(count == AbsFluff::s_alive); + + absFluff.resize(10); + myassert(count == AbsFluff::s_alive); + + count = AbsFluff::s_alive + 5; + // absFluff.resize(15, new DerivedFluff); + absFluff.resize(15); + for(unsigned int i=10; i<15; ++i) absFluff.push_back( new DerivedFluff ); + myassert(count == AbsFluff::s_alive); + + count = AbsFluff::s_alive - 2; + size_t dsize(absFluff.size() - 2); + absFluff.pop_back(); + absFluff.pop_back(); + myassert(count == AbsFluff::s_alive); + myassert(absFluff.size() == dsize); + + std::cout << "*** DataList_test test1 OK ***" <<std::endl; +} + + +//************************************************************************ + +std::list<int> dtor_log; +std::list<int> get_dtor_log() +{ + std::list<int> out; + out.swap (dtor_log); + // the order of element deletion within a container is unpredictable, + // due to the sort() in remove_duplicates(). + out.sort(); + return out; +} +void clear_dtor_log() +{ + dtor_log.clear(); +} +void check_dtor_log(int a=-1,int b=-1,int c=-1,int d=-1, int e=-1, int f=-1) +{ + std::list<int> v; + if (a != -1) v.push_back(a); + if (b != -1) v.push_back(b); + if (c != -1) v.push_back(c); + if (d != -1) v.push_back(d); + if (e != -1) v.push_back(e); + if (f != -1) v.push_back(f); + v.sort(); + myassert (get_dtor_log() == v); +} + +template <class ITERATOR> +ITERATOR next (ITERATOR it, size_t n=1) +{ + std::advance (it, n); + return it; +} +template <class ITERATOR> +ITERATOR prev (ITERATOR it, size_t n=1) +{ + std::advance (it, -n); + return it; +} +template <class CONT> +typename CONT::const_value_type nth (const CONT& cont, size_t n) +{ + return *::next(cont.begin(), n); +} + +struct AA +{ + AA (int the_x=0): x(the_x) {} + ~AA() { dtor_log.push_back (x); } + int x; + bool operator< (const AA& other) const { return x < other.x; } +}; +struct BB : public AA +{ + BB (int the_x=0) : AA(the_x) {} +}; +struct CC : public BB +{ + CC (int the_x=0) : BB(the_x) {} +}; + +DATALIST_BASE(BB, AA); +DATALIST_BASE(CC, BB); + +CLASS_DEF( DataList<AA> , 9981 , 1 ) +CLASS_DEF( DataList<BB> , 9982 , 1 ) +CLASS_DEF( DataList<CC> , 139782528 , 2 ) + +struct MM +{ + MM (int the_x=0) : mm(the_x) {} + virtual ~MM() {} + int mm; +}; +struct M +{ + M (int the_x=0) : x(the_x) {} + virtual ~M() { dtor_log.push_back (x); } + int x; + bool operator< (const M& other) const { return x < other.x; } +}; +struct N : virtual public M, public MM +{ + N (int the_x=0) : M(the_x), MM(the_x+100) {} +}; +struct O : virtual public M +{ + O (int the_x=0) : M(the_x) {} +}; +struct P : virtual public N, virtual public O +{ + P (int the_x=0) : M(the_x), N(the_x) {} +}; + +DATALIST_VIRTBASES1 (N, M); +DATALIST_VIRTBASES1 (O, M); +DATALIST_VIRTBASES2 (P, N, O); + +SG_BASES2 (N, SG_VIRTUAL(M), MM); +SG_BASE (O, SG_VIRTUAL(M)); +SG_BASES2 (P, SG_VIRTUAL(N), SG_VIRTUAL(O)); + +struct Q : virtual public M +{ + Q (int the_x=0) : M(the_x) {} +}; +struct R : virtual public N, virtual public O, virtual public Q +{ + R (int the_x=0) : M(the_x) {} +}; + +DATALIST_VIRTBASES1 (Q, M); +DATALIST_VIRTBASES3 (R, N, O, Q); + +CLASS_DEF( DataList<R> , 9983 , 1 ) +CLASS_DEF( DataList<N> , 9984 , 1 ) +CLASS_DEF( DataList<O> , 9985 , 1 ) +CLASS_DEF( DataList<Q> , 9986 , 1 ) +CLASS_DEF( DataList<M> , 9987 , 1 ) + + +// Make sure myassert is working. +void test2_myassert() +{ + bool caught = false; + try { + myassert (false); + } + catch (dl_test_err&) { + caught = true; + } + if (!caught) abort(); +} + +// Initial tests. +template <class B, class D> +void test2_initial() +{ + DataList<D> vd; + vd.push_back (new D(1)); + DataList<B>& vb = vd; + const B* b = vb.front(); + const D* d = vd.front(); + myassert (b->x == 1); + myassert (d->x == 1); + + DataList<D> d2 (10); + myassert (d2.size() == 10); + DataList<D> d3 (d2); + myassert (d3.size() == 10); +} + + +// Test default ctor +template <class DL> +void test2_default_ctor1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1; + v1.push_back (new T(1)); + myassert (v1.ownPolicy() == SG::OWN_ELEMENTS); + DL v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(2)); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + } + check_dtor_log (1); +} +template <class B, class D> +void test2_default_ctor() +{ + test2_default_ctor1<DataList<B> > (); + test2_default_ctor1<DataList<D> > (); +} + + +// Test sized ctor +template <class DL> +void test2_sized_ctor1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1 (10); + myassert (v1.size() == 10); + myassert (v1.front() == 0); + v1.push_back (new T(1)); + DL v2 (10, SG::VIEW_ELEMENTS); + myassert (v2.size() == 10); + myassert (v2.front() == 0); + v2.push_back (new T(2)); + } + check_dtor_log (1); +} +template <class B, class D> +void test2_sized_ctor() +{ + test2_sized_ctor1<DataList<B> > (); + test2_sized_ctor1<DataList<D> > (); + test2_sized_ctor1<ConstDataList<DataList<D> > > (); +} + + +// Test insertion ctor +template <class DL> +void test2_insertion_ctor1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + std::list<T*> tt; + tt.push_back (new T(1)); + tt.push_back (new T(2)); + DL v1 (tt.begin(), tt.end()); + DL v2 (tt.begin(), tt.end(), SG::OWN_ELEMENTS); + myassert (v1.size() == 2); + myassert (v2.size() == 2); + { + typename DL::const_iterator itrV1 = v1.begin(); + typename std::list<T*>::const_iterator itrTT = tt.begin(); + myassert( *itrV1 == *itrTT ); + ++itrV1; + ++itrTT; + myassert( *itrV1 == *itrTT ); + } + { + typename DL::const_iterator itrV2 = v2.begin(); + typename std::list<T*>::const_iterator itrTT = tt.begin(); + myassert( *itrV2 == *itrTT ); + ++itrV2; + ++itrTT; + myassert( *itrV2 == *itrTT ); + } + } + check_dtor_log (1, 2); +} +template <class B, class D> +void test2_insertion_ctor() +{ + test2_insertion_ctor1<DataList<B> > (); + test2_insertion_ctor1<DataList<D> > (); + test2_insertion_ctor1<ConstDataList<DataList<D> > > (); + { + // We can put D pointers into a B container. + std::list<D*> dd; + dd.push_back (new D(1)); + dd.push_back (new D(2)); + DataList<B> v1 (dd.begin(), dd.end()); + myassert (v1.size() == 2); + { + typename DataList<B>::const_iterator itrV1 = v1.begin(); + typename std::list<D*>::const_iterator itrDD = dd.begin(); + myassert( *itrV1 == *itrDD ); + ++itrV1; + ++itrDD; + myassert( *itrV1 == *itrDD ); + } + } +#ifdef COMPILE_ERROR + { + // But not the other way 'round. + std::list<B*> dd; + dd.push_back (new B(1)); + dd.push_back (new B(2)); + DataList<D> v1 (dd.begin(), dd.end()); + { + typename std::list<B>::const_iterator itrV1 = v1.begin(); + typename DataList<D*>::const_iterator itrDD = dd.begin(); + myassert( *itrV1 == *itrDD ); + ++itrV1; + ++itrDD; + myassert( *itrV1 == *itrDD ); + } + } +#endif +} + + +// Test copy ctor +template <class DL> +void test2_copy_ctor1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2 (v1); + myassert (v2.size() == 2); + { + typename DL::const_iterator itrV1 = v1.begin(); + typename DL::const_iterator itrV2 = v2.begin(); + myassert( *itrV1 == *itrV2 ); + ++itrV1; + ++itrV2; + myassert( *itrV1 == *itrV2 ); + } + } + check_dtor_log (1, 2); +} +template <class B, class D> +void test2_copy_ctor() +{ + test2_copy_ctor1<DataList<B> >(); + test2_copy_ctor1<DataList<D> >(); + test2_copy_ctor1<ConstDataList<DataList<D> > >(); + { + // Can copy derived list to base list. + DataList<D> v1; + v1.push_back (new D(1)); + v1.push_back (new D(2)); + DataList<B> v2 (v1); + myassert (v2.size() == 2); + { + typename DataList<D>::const_iterator itrV1 = v1.begin(); + typename DataList<B>::const_iterator itrV2 = v2.begin(); + myassert( *itrV1 == *itrV2 ); + ++itrV1; + ++itrV2; + myassert( *itrV1 == *itrV2 ); + } + } + check_dtor_log (1, 2); +#ifdef COMPILE_ERROR + { + // But not the other way 'round. + DataList<B> v1; + v1.push_back (new B(1)); + v1.push_back (new B(2)); + DataList<D> v2 (v1); + myassert (v2.size() == 2); + { + typename DataList<B>::const_iterator itrV1 = v1.begin(); + typename DataList<D>::const_iterator itrV2 = v2.begin(); + myassert( *itrV1 == *itrV2 ); + ++itrV1; + ++itrV2; + myassert( *itrV1 == *itrV2 ); + } + } + check_dtor_log (1, 2); +#endif +} + + + +// Test destructor. +template <class DL> +void test2_dtor1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + } + check_dtor_log (1, 2); + { + DL v1 (SG::VIEW_ELEMENTS); + v1.push_back (new T(1)); + v1.push_back (new T(2)); + } + check_dtor_log (); +#ifdef DO_REMOVE_DUPLICATES + { + DL v1; + T* t = new T(1); + v1.push_back (t); + v1.push_back (t); + } + check_dtor_log (1); +#endif +} +template <class B, class D> +void test2_dtor() +{ + test2_dtor1<DataList<B> > (); + test2_dtor1<DataList<D> > (); + test2_dtor1<ConstDataList<DataList<D> > > (); +} + + +// Test push_front +template <class B, class D> +void test2_push_front() +{ + DataList<B> vb; + vb.push_front (new B(1)); + vb.push_front (new D(2)); + myassert (vb.size() == 2); + { + typename DataList<B>::const_iterator itrVB = vb.begin(); + myassert( (*itrVB)->x == 2 ); + ++itrVB; + myassert( (*itrVB)->x == 1 ); + } + + DataList<D> vd; + vd.push_front (new D(3)); + myassert (vd.size() == 1); + myassert (vd.front()->x == 3); + + ConstDataList<DataList<D> > cvd; + cvd.push_front (new D(3)); + cvd.push_front (new D(4)); + myassert (cvd.size() == 2); + myassert (cvd.front()->x == 4); + myassert (cvd.back()->x == 3); + + // This isn't allowed. + DataList<B>& vd2 = vd; + bool caught = false; + try { + vd2.push_front (new B(4)); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test push_back +template <class B, class D> +void test2_push_back() +{ + DataList<B> vb; + vb.push_back (new B(1)); + vb.push_back (new D(2)); + myassert (vb.size() == 2); + { + typename DataList<B>::const_iterator itrVB = vb.begin(); + myassert( (*itrVB)->x == 1 ); + ++itrVB; + myassert( (*itrVB)->x == 2 ); + } + + DataList<D> vd; + vd.push_back (new D(3)); + myassert (vd.size() == 1); + myassert (vd.front()->x == 3); + + ConstDataList<DataList<D> > cvd; + cvd.push_back (new D(3)); + cvd.push_back (new D(4)); + myassert (cvd.size() == 2); + myassert (cvd.front()->x == 3); + myassert (cvd.back()->x == 4); + + // This isn't allowed. + DataList<B>& vd2 = vd; + bool caught = false; + try { + vd2.push_back (new B(4)); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test size +template <class DL, class B, class D> +void test2_size1() +{ + DL vb; + myassert (vb.size() == 0); + vb.push_back (new B(1)); + vb.push_back (new D(2)); + myassert (vb.size() == 2); +} +template <class B, class D> +void test2_size() +{ + test2_size1<DataList<B>, B, D>(); + test2_size1<ConstDataList<DataList<B> >, B, D>(); +} + + +// Test stdcont +template <class B, class D> +void test2_stdcont() +{ + DataList<B> vb; + vb.push_back (new B(1)); + vb.push_back (new D(2)); + const typename DataList<B>::PtrList& vv = vb.stdcont(); + myassert (vv.size() == 2); + myassert (vv.front()->x == 1); +} + + +// Test empty +template <class DL> +void test2_empty1() +{ + typedef typename DL::base_value_type T; + DL vb; + myassert (vb.empty()); + vb.push_back (new T(1)); + myassert (!vb.empty()); +} +template <class B, class D> +void test2_empty() +{ + test2_empty1<DataList<B> >(); + test2_empty1<ConstDataList<DataList<B> > >(); +} + + +// Test max_size +template <class B, class D> +void test2_max_size() +{ + DataList<B> vb; + myassert (vb.max_size() == std::list<void*>().max_size()); + ConstDataList<DataList<B> > cvb; + myassert (cvb.max_size() == std::list<void*>().max_size()); +} + + +// Test front const, back const +template <class DL, class B, class D> +void test2_front_back_const1() +{ + DL vd; + vd.push_back (new B(1)); + vd.push_back (new D(2)); + const DL& cvd = vd; + const B* dd = cvd.front(); + myassert (dd->x == 1); + dd = cvd.back(); + myassert (dd->x == 2); +} +template <class B, class D> +void test2_front_back_const() +{ + test2_front_back_const1<DataList<B>, B, D>(); + test2_front_back_const1<DataList<D>, D, D>(); + test2_front_back_const1<ConstDataList<DataList<D> >, D, D>(); +} + + +// Test begin const, end const +template <class DL> +void test2_begin_end_const1() +{ + typedef typename DL::base_value_type T; + DL v; + v.push_back (new T(1)); + v.push_back (new T(2)); + const DL& cv = v; + myassert ( std::distance( cv.begin(), cv.end() ) == 2); + typename DL::const_iterator i = cv.begin(); + myassert (i != cv.end()); + const T* tt = *i; + myassert (tt->x == 1); + ++i; + myassert (i != cv.end()); + myassert ((*i)->x == 2); + i++; + myassert (i == cv.end()); + i--; + myassert ((*i)->x == 2); + --i; + myassert ((*i)->x == 1); + myassert (i == cv.begin()); +} +template <class B, class D> +void test2_begin_end_const() +{ + test2_begin_end_const1<DataList<B> > (); + test2_begin_end_const1<DataList<D> > (); + test2_begin_end_const1<ConstDataList<DataList<D> > > (); +} + + +// Test rbegin const, rend const +template <class DL> +void test2_rbegin_rend_const1() +{ + typedef typename DL::base_value_type T; + DL v; + v.push_back (new T(1)); + v.push_back (new T(2)); + const DL& cv = v; + myassert ( std::distance( cv.rbegin(), cv.rend() ) == 2); + typename DL::const_reverse_iterator i = cv.rbegin(); + myassert (i != cv.rend()); + const T* tt = *i; + myassert (tt->x == 2); + ++i; + myassert (i != cv.rend()); + myassert ((*i)->x == 1); + i++; + myassert (i == cv.rend()); + i--; + myassert ((*i)->x == 1); + --i; + myassert ((*i)->x == 2); + myassert (i == cv.rbegin()); +} +template <class B, class D> +void test2_rbegin_rend_const() +{ + test2_rbegin_rend_const1<DataList<B> > (); + test2_rbegin_rend_const1<DataList<D> > (); + test2_rbegin_rend_const1<ConstDataList<DataList<D> > > (); +} + + +// Test ElementProxy operations. +template <class B, class D> +void test2_elementproxy() +{ + clear_dtor_log(); + + { + DataList<B> vb1; + vb1.push_back (new B(1)); + vb1.push_back (new D(2)); + + DataList<B> vb2 (SG::VIEW_ELEMENTS); + vb2.push_back (new B(3)); + vb2.push_back (new D(4)); + + DataList<D> vd1; + vd1.push_back (new D(5)); + vd1.push_back (new D(6)); + + DataList<D> vd2 (SG::VIEW_ELEMENTS); + vd2.push_back (new D(7)); + vd2.push_back (new D(8)); + + { + typename DataList<B>::const_iterator itrVB1 = vb1.begin(); + myassert( (*itrVB1)->x == 1 ); + ++itrVB1; + myassert( (**itrVB1).x == 2 ); + } + + D* dd = vd1.front(); + myassert (dd->x == 5); + { + typename DataList<D>::const_iterator itrVD1 = vd1.begin(); + ++itrVD1; + myassert( (*itrVD1)->x == 6); + } + + // vb1: (1,2) vb2: (3,4) vd1: (5,6) vd2: (7,8) + // Test ownership transfer. + // VIEW->VIEW doesn't delete anything. + vb2.front() = *(++vb2.begin()); + vd2.front() = *(++vd2.begin()); + check_dtor_log(); + + // vb1: (1,2) vb2: (4,4) vd1: (5,6) vd2: (8,8) + // OWN->VIEW doesn't delete anything. + vb2.front() = vb1.front(); + vd2.front() = vd1.front(); + check_dtor_log(); + + // vb1: (1,2) vb2: (1,4) vd1: (5,6) vd2: (5,8) + // VIEW->OWN deletes old val, takes ownership. + *(++vb1.begin()) = *(++vb2.begin()); + *(++vd1.begin()) = *(++vd2.begin()); + check_dtor_log (2, 6); + + // vb1: (1,4) vb2: (1,4) vd1: (5,8) vd2: (5,8) + // OWN->OWN not allowed. + bool caught = false; + try { + vb1.front() = *(++vb1.begin()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + vd1.front() = *(++vd1.begin()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + // Unless it's the same element. + vb1.front() = vb1.front(); + B* bb = vb1.front(); + vb1.front() = bb; + + // Check that we can't manage to put a B into a D container + // using ElementProxy. + DataList<B>& vd2_b = vd2; + caught = false; + try { + vd2_b.front() = vb2.front(); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + // On the other hand, we can put a D in a B container. + vb2.front() = vd2_b.front(); + + // vb1: (1,4) vb2: (5,4) vd1: (5,8) vd2: (5,8) + + // Test assignment from explicit pointers. + vb1.front() = new B(9); + check_dtor_log (1); + vb2.front() = new B(10); + check_dtor_log (); + // vb1: (9,4) vb2: (10,4) vd1: (5,8) vd2: (5,8) + vd2.front() = new D(11); + check_dtor_log (); + vd1.front() = new D(12); + check_dtor_log (5); + // vb1: (9,4) vb2: (10,4) vd1: (12,8) vd2: (11,8) + } + check_dtor_log (12, 8, 9, 4); +} + + +// Test front, back +template <class DL> +void test2_front_back1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v; + v.push_back (new T(1)); + v.push_back (new T(2)); + myassert (v.front()->x == 1); + myassert (v.back()->x == 2); + v.front() = new T(3); + check_dtor_log (1); + myassert (v.front()->x == 3); +} +// Test front, back +template <class B, class D> +void test2_front_back() +{ + test2_front_back1<DataList<B> > (); + test2_front_back1<DataList<D> > (); + test2_front_back1<ConstDataList<DataList<D> > > (); +} + + +// Test swapElement with iterator +template <class B, class D> +void test2_swapelement_iter() +{ + clear_dtor_log(); + { + DataList<B> vb; + vb.push_back (new B(1)); + vb.push_back (new B(2)); + + B* bold; + vb.swapElement (::next(vb.begin()), new B(3), bold); + myassert (nth(vb, 1)->x == 3); + myassert (bold->x == 2); + delete bold; + check_dtor_log (2); + + DataList<D> vd; + vd.push_back (new D(4)); + vd.push_back (new D(5)); + + D* dold; + vd.swapElement (::next(vd.begin()), new D(6), dold); + myassert (nth(vd,1)->x == 6); + myassert (dold->x == 5); + delete dold; + check_dtor_log (5); + + DataList<B>& vd_b = vd; + bool caught = false; + try { + vd_b.swapElement (::next(vd_b.begin()), new B(10), bold); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + ConstDataList<DataList<D> > cvd; + cvd.push_back (new D(7)); + cvd.push_back (new D(8)); + + const D* cdold; + cvd.swapElement (::next(cvd.begin()), new D(9), cdold); + myassert (nth(cvd,1)->x == 9); + myassert (cdold->x == 8); + delete cdold; + check_dtor_log (8); + } + + check_dtor_log (4, 6, 1, 3, 7, 9); +} + + +// Test resize +template <class DL> +void test2_resize1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2 (v1); + myassert (v2.size() == 2); + v2.resize (1); + check_dtor_log(); + myassert (v2.size() == 1); + myassert (v2.front()->x == 1); + myassert (v1.size() == 2); + v1.resize (1); + check_dtor_log(2); + myassert (v1.size() == 1); + myassert (v1.front()->x == 1); + v1.resize (3); + myassert (v1.size() == 3); + myassert (v1.front()->x == 1); + { + typename DL::const_iterator itrV1 = v1.begin(); + ++itrV1; + myassert( *itrV1 == 0 ); + ++itrV1; + myassert( *itrV1 == 0 ); + } +} +template <class B, class D> +void test2_resize() +{ + test2_resize1<DataList<B> >(); + test2_resize1<DataList<D> >(); + test2_resize1<ConstDataList<DataList<D> > >(); +} + + +// Test pop_front +template <class DL> +void test2_pop_front1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2 (v1); + myassert (v2.size() == 2); + v2.pop_front(); + myassert (v2.size() == 1); + check_dtor_log(); + myassert (v1.size() == 2); + v1.pop_front(); + myassert (v1.size() == 1); + myassert( v1.front()->x == 2 ); + check_dtor_log(1); +} +template <class B, class D> +void test2_pop_front() +{ + test2_pop_front1<DataList<B> > (); + test2_pop_front1<DataList<D> > (); + test2_pop_front1<ConstDataList<DataList<D> > > (); +} + +// Test pop_back +template <class DL> +void test2_pop_back1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2 (v1); + myassert (v2.size() == 2); + v2.pop_back(); + myassert (v2.size() == 1); + check_dtor_log(); + myassert (v1.size() == 2); + v1.pop_back(); + myassert (v1.size() == 1); + check_dtor_log(2); +} +template <class B, class D> +void test2_pop_back() +{ + test2_pop_back1<DataList<B> > (); + test2_pop_back1<DataList<D> > (); + test2_pop_back1<ConstDataList<DataList<D> > > (); +} + + +// Test begin, end +template <class DL> +void test2_begin_end1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + myassert ( std::distance( v1.begin(), v1.end() ) == 2); + typename DL::value_type tt = *v1.begin(); + myassert (tt->x == 1); + { + typename DL::const_iterator itrV1 = v1.begin(); + ++itrV1; + myassert( (*itrV1)->x == 2); + } + *v1.begin() = new T(3); + check_dtor_log(1); + myassert (v1.front()->x == 3); + + DL v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(4)); + v2.push_back (new T(5)); + *v2.begin() = *v1.begin(); + check_dtor_log(); + myassert (v2.front()->x == 3); + + // (3,2) (3,5) + *(--v1.end()) = *(--v2.end()); + check_dtor_log(2); + { + typename DL::const_iterator itrV1 = v1.begin(); + ++itrV1; + myassert( (*itrV1)->x == 5); + } + + // (3,5) (3,5) + *v2.begin() = *(++v2.begin()); + check_dtor_log(); + myassert (v2.front()->x == 5); + + bool caught = false; + try { + *v1.begin() = *(++v1.begin()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + // Check creating a const_iterator from an iterator. + typename DL::const_iterator ci = v2.begin(); + myassert ((*ci)->x == 5); + + // Check comparing iterators and const_iterators. + typename DL::iterator i = v2.begin(); + myassert (i == ci); + myassert (ci == i); + myassert (! (i != ci)); + myassert (! (ci != i)); + + v2.sort(); +} +template <class B, class D> +void test2_begin_end() +{ + test2_begin_end1<DataList<B> > (); + test2_begin_end1<DataList<D> > (); + test2_begin_end1<ConstDataList<DataList<D> > > (); + + DataList<D> vd (1); + DataList<B>& vb = vd; + bool caught = false; + try { + *vb.begin() = new B(1); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test rbegin, rend +template <class DL> +void test2_rbegin_rend1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + myassert ( std::distance( v1.rbegin(), v1.rend() ) == 2); + typename DL::value_type tt = *v1.rbegin(); + myassert (tt->x == 2); + { + typename DL::const_reverse_iterator ritrV1 = v1.rbegin(); + ++ritrV1; + myassert( (*ritrV1)->x == 1 ); + } + *v1.rbegin() = new T(3); + check_dtor_log(2); + { + typename DL::const_iterator itrV1 = v1.begin(); + ++itrV1; + myassert( (*itrV1)->x == 3 ); + } + + DL v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(4)); + v2.push_back (new T(5)); + // (1,3) (4,5) + *v2.rbegin() = *v1.rbegin(); + check_dtor_log(); + { + typename DL::const_iterator itrV2 = v2.begin(); + ++itrV2; + myassert( (*itrV2)->x == 3 ); + } + + // (1,3) (4,3) + *(--v1.rend()) = *(--v2.rend()); + check_dtor_log(1); + myassert (v1.front()->x == 4); + + // (4,3) (4,3) + (*v2.rbegin()) = *(++v2.rbegin()); + check_dtor_log(); + { + typename DL::const_iterator itrV2 = v2.begin(); + ++itrV2; + myassert( (*itrV2)->x == 4 ); + } + // (4,3) (4,4) + + bool caught = false; + try { + *v1.rbegin() = *(++v1.rbegin()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + // Check creating a const_iterator from an iterator. + typename DL::const_reverse_iterator ci = v2.rbegin(); + myassert ((*ci)->x == 4); + + v2.sort(); +} +template <class B, class D> +void test2_rbegin_rend() +{ + test2_rbegin_rend1<DataList<B> > (); + test2_rbegin_rend1<DataList<D> > (); + test2_rbegin_rend1<ConstDataList<DataList<D> > > (); + + DataList<D> vd (1); + DataList<B>& vb = vd; + bool caught = false; + try { + *vb.rbegin() = new B(1); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test erase(it, it) +template <class DL> +void test2_erase_range1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v; + for (int i=0; i < 10; i++) + v.push_back (new T(i)); + myassert (v.size() == 10); + + typename DL::iterator i1; + { + typename DL::iterator vItrAtPlus3 = v.begin(); + std::advance( vItrAtPlus3, 3 ); + typename DL::iterator vItrAtMinus3 = v.end(); + std::advance( vItrAtMinus3, -3 ); + i1 = v.erase( vItrAtPlus3, vItrAtMinus3 ); + } + myassert ((*i1)->x == 7); + myassert (v.size() == 6); + check_dtor_log (3, 4, 5, 6); + { + typename DL::const_iterator itrV = v.begin(); + std::advance( itrV, 2 ); + myassert( (*itrV)->x == 2 ); + ++itrV; + myassert( (*itrV)->x == 7 ); + } + + DL v2 (v); + myassert (v2.size() == 6); + typename DL::iterator i2; + { + typename DL::iterator itrV2AtPlus2 = v2.begin(); + std::advance( itrV2AtPlus2, 2 ); + typename DL::iterator itrV2AtMinus2 = v2.end(); + std::advance( itrV2AtMinus2, -2 ); + i2 = v2.erase( itrV2AtPlus2, itrV2AtMinus2 ); + } + myassert ((*i2)->x == 8); + myassert (v2.size() == 4); + check_dtor_log (); + { + typename DL::const_iterator itrV2 = v2.begin(); + ++itrV2; + myassert( (*itrV2)->x == 1 ); + ++itrV2; + myassert( (*itrV2)->x == 8 ); + } + +#ifdef DO_REMOVE_DUPLICATES + { + DL v3; + T* t = new T(1); + v3.push_back (t); + v3.push_back (t); + v3.push_back (new T(2)); + v3.erase( v3.begin(), ++(++v3.begin()) ); + check_dtor_log (1); + } + check_dtor_log(2); +#endif +} +template <class B, class D> +void test2_erase_range() +{ + test2_erase_range1<DataList<B> > (); + test2_erase_range1<DataList<D> > (); + test2_erase_range1<ConstDataList<DataList<D> > > (); +} + +// Test erase(it) +template <class DL> +void test2_erase_single1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.erase (v1.begin()); + myassert (v1.size() == 1); + myassert (v1.front()->x == 2); + check_dtor_log (1); + + DL v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(1)); + v2.push_back (new T(2)); + v2.erase (v2.begin()); + myassert (v2.size() == 1); + myassert (v2.front()->x == 2); + check_dtor_log (); +} +template <class B, class D> +void test2_erase_single() +{ + test2_erase_single1<DataList<B> > (); + test2_erase_single1<DataList<D> > (); + test2_erase_single1<ConstDataList<DataList<D> > > (); +} + + +// Test operator= +template <class DL> +void test2_operator_assign1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + { + DL v2; + v2 = v1; + myassert (v2.size() == 2); + myassert (v2.front()->x == 1); + { + typename DL::const_iterator itrV2 = v2.begin(); + ++itrV2; + myassert( (*itrV2)->x == 2 ); + } + } + check_dtor_log(); + + v1 = v1; + check_dtor_log(); + + { + DL v2; + v1 = v2; + myassert (v1.size() == 0); + } + check_dtor_log (1, 2); + } + check_dtor_log (); +} +template <class B, class D> +void test2_operator_assign() +{ + test2_operator_assign1<DataList<B> > (); + test2_operator_assign1<DataList<D> > (); + test2_operator_assign1<ConstDataList<DataList<D> > > (); + + DataList<D> vd1; + vd1.push_back (new D(1)); + DataList<B> vb1; + vb1 = vd1; + myassert (vb1.size() == 1); + myassert (vb1.front()->x == 1); + + DataList<B>& vd1_b = vd1; + bool caught = false; + try { + vd1_b = vb1; + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test insert(it, val) +template <class DL> +void test2_insert_value1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + typename DL::iterator i1 = v1.insert( ++v1.begin(), new T(3)); + myassert (v1.size() == 3); + myassert ((*i1)->x == 3); + { + typename DL::const_iterator itrV1 = v1.begin(); + myassert( (*itrV1)->x == 1 ); + ++itrV1; + myassert( (*itrV1)->x == 3 ); + ++itrV1; + myassert( (*itrV1)->x == 2 ); + } + + DL v2 (v1); + typename DL::iterator i2 = v2.insert( ++v2.begin(), new T(4)); + myassert (v2.size() == 4); + myassert ((*i2)->x == 4); + } + check_dtor_log (1, 3, 2); +} +template <class B, class D> +void test2_insert_value() +{ + test2_insert_value1<DataList<B> > (); + test2_insert_value1<DataList<D> > (); + test2_insert_value1<ConstDataList<DataList<D> > > (); + + DataList<D> vd; + DataList<B>& vb = vd; + bool caught = false; + try { + vb.insert (vb.begin(), new D(1)); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + vd.insert (vd.begin(), new D(1)); +} + + +// Test insert(it, It, It) +template <class DL> +void test2_insert_range1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + T* tt[] = {new T(1), new T(2)}; + DL v; + v.insert (v.begin(), tt, tt+2); + myassert (v.size() == 2); + { + typename DL::const_iterator itrV = v.begin(); + myassert( (*itrV)->x == 1 ); + ++itrV; + myassert( (*itrV)->x == 2 ); + } + } + check_dtor_log (1, 2); + + { + T* tt[] = {new T(1), new T(2)}; + DL v (SG::VIEW_ELEMENTS); + v.insert (v.begin(), tt, tt+2); + myassert (v.size() == 2); + { + typename DL::const_iterator itrV = v.begin(); + myassert( (*itrV)->x == 1 ); + ++itrV; + myassert( (*itrV)->x == 2 ); + } + } + check_dtor_log (); +} +template <class B, class D> +void test2_insert_range() +{ + test2_insert_range1<DataList<B> > (); + test2_insert_range1<DataList<D> > (); + test2_insert_range1<ConstDataList<DataList<D> > > (); + + DataList<D> vd; + DataList<B>& vb = vd; + bool caught = false; + D* tt[] = {new D(1), new D(2)}; + try { + vb.insert (vb.begin(), tt, tt+2); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + vd.insert (vd.begin(), tt, tt+2); +} + + +// Test clear() +template <class DL> +void test2_clear1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.clear(); + check_dtor_log (1, 2); + DL v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(1)); + v2.push_back (new T(2)); + v2.clear(); + check_dtor_log (); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + v2.clear(SG::OWN_ELEMENTS); + myassert (v2.ownPolicy() == SG::OWN_ELEMENTS); + v2.push_back (new T(1)); + v2.push_back (new T(2)); + v2.clear(SG::VIEW_ELEMENTS); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + check_dtor_log (1, 2); +} +template <class B, class D> +void test2_clear() +{ + test2_clear1<DataList<B> > (); + test2_clear1<DataList<D> > (); + test2_clear1<ConstDataList<DataList<D> > > (); +} + + +// Test swap() +template <class DL> +void test2_swap1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2; + v1.swap (v2); + myassert (v1.size() == 0); + myassert (v2.size() == 2); + { + typename DL::const_iterator itrV2 = v2.begin(); + myassert( (*itrV2)->x == 1 ); + ++itrV2; + myassert( (*itrV2)->x == 2 ); + } + check_dtor_log(); + } + check_dtor_log(1,2); + { + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2; + swap (v1, v2); + myassert (v1.size() == 0); + myassert (v2.size() == 2); + { + typename DL::const_iterator itrV2 = v2.begin(); + myassert( (*itrV2)->x == 1 ); + ++itrV2; + myassert( (*itrV2)->x == 2 ); + } + check_dtor_log(); + } + check_dtor_log(1,2); +} +template <class B, class D> +void test2_swap() +{ + test2_swap1<DataList<B> > (); + test2_swap1<DataList<D> > (); + test2_swap1<ConstDataList<DataList<D> > > (); + + DataList<D> vd; + DataList<B>& vb = vd; + DataList<B> vb2; + + bool caught = false; + try { + vb.swap(vb2); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + vb2.swap(vb); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + swap (vb, vb2); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + swap (vb2, vb); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +template <class DL> +void test2_assign1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + { + DL v; + v.push_back (new T(0)); + T* t[] = {new T(1), new T(2)}; + v.assign (t, t+2); + check_dtor_log(0); + } + check_dtor_log(1,2); + + { + DL v (SG::VIEW_ELEMENTS); + v.push_back (new T(0)); + T* t[] = {new T(1), new T(2)}; + v.assign (t, t+2); + } + check_dtor_log(); +} +template <class B, class D> +void test2_assign() +{ + test2_assign1<DataList<B> > (); + test2_assign1<DataList<D> > (); + test2_assign1<ConstDataList<DataList<D> > > (); + + DataList<D> vd; + DataList<B>& vb = vd; + B* t[] = {new B(1), new B(2)}; + bool caught = false; + try { + vb.assign (t, t+2); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +template <class DL> +void test2_relops1() +{ + typedef typename DL::base_value_type T; + DL v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DL v2 (v1); + DL v3 (v1); + v3.push_back (new T(3)); + + myassert (v1 == v2); + myassert (!(v1 == v3)); + myassert (v1 != v3); + myassert (!(v1 != v2)); + + myassert (v1 < v3); + myassert (!(v1 < v2)); + myassert (v3 > v1); + myassert (!(v2 > v1)); + + myassert (v1 <= v3); + myassert (v1 <= v2); + myassert (!(v3 <= v1)); + + myassert (v3 >= v1); + myassert (v2 >= v1); + myassert (!(v1 >= v3)); +} +template <class B, class D> +void test2_relops() +{ + test2_relops1<DataList<B> > (); + test2_relops1<DataList<D> > (); + test2_relops1<ConstDataList<DataList<D> > > (); +} + + +template <class T> +struct Comp +{ + bool operator() (const T* a, const T* b) const + { return *b < *a; } +}; + +template <class T> +struct PredX +{ + bool operator() ( const T* elem ) const + { return elem->x > m_cut; } + int m_cut; +}; + +template <class T> +struct LessX +{ + bool operator() (const T* a, const T* b) const + {return a->x < b->x; } +}; + +template <class T> +struct GreatX +{ + bool operator() (const T* a, const T* b) const + {return a->x > b->x; } +}; + +template <class DL, int N> +void test2_sort1_prepare1 (DL& v) +{ + typedef typename DL::base_value_type T; + T* tmp[N]; + for (int i=0; i<N; ++i) + tmp[i] = new T(i); + std::sort (tmp, tmp+N); + for (int i=0; i<N; ++i) + tmp[i]->x = i; + for (int i=0; i<N; ++i) + v.push_back (tmp[N-1-i]); +} +template <class DL> +void test2_sort1() +{ + typedef typename DL::base_value_type T; + const int N=10; + { + DL v; + test2_sort1_prepare1<DL, N> (v); + v.sort(); + typename DL::const_iterator itrV = v.begin(); + for (int i=0; i<N; ++i, ++itrV) + myassert ( (*itrV)->x == i); + } + + { + DL v; + for (int i=0; i<N; ++i ) + v.push_back (new T(i)); + v.sort(Comp<T>()); + typename DL::const_iterator itrV = v.begin(); + for (int i=0; i<N; ++i, ++itrV) + myassert ( (*itrV)->x == N-1-i); + } + + clear_dtor_log(); +} +template <class B, class D> +void test2_sort() +{ + test2_sort1<DataList<B> > (); + test2_sort1<DataList<D> > (); + test2_sort1<ConstDataList<DataList<D> > > (); +} + +template <class DL> +void test2_prepare1( const unsigned int N, + const unsigned int ratio, + DL& l ) +{ + typedef typename DL::base_value_type T; + for ( unsigned int i = 0; i != N; ++i ) { + l.push_back( new T( ratio * i ) ); + } +} + +template <class DL> +void test2_splice1() +{ + //typedef typename DL::base_value_type T; + const unsigned int N = 6; + + // test splice( iterator, DataList ) + { + DL l1; + DL l2; + test2_prepare1( N, 1, l1 ); + test2_prepare1( N, 2, l2 ); + myassert( l1.size() == N ); + myassert( l2.size() == N ); + + // Check VIEW_ELEMENTS + DL view1 = l1; + DL view2 = l2; + myassert( view1.size() == N ); + myassert( view2.size() == N ); + + typename DL::iterator itrL1 = view1.begin(); + std::advance( itrL1, N/2 ); + view1.splice( itrL1, view2 ); + + myassert( view1.size() == 2*N ); + myassert( view2.empty() ); + + // check content of OWN_ELEMENTS containers + typename DL::const_iterator itr1 = l1.begin(); + typename DL::const_iterator itr2 = l2.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr1, ++itr2 ) { + myassert( (*itr1)->x == static_cast<int>(i) ); + myassert( (*itr2)->x == static_cast<int>(i*2) ); + } + + // check OWN_ELEMENTS + itrL1 = l1.begin(); + std::advance( itrL1, N/2 ); + l1.splice( itrL1, l2 ); + + myassert( l1.size() == 2*N ); + myassert( l2.empty() ); + } + + // test splice( iterator, DataList, iterator ) + { + DL l1; + DL l2; + test2_prepare1( N, 1, l1 ); + test2_prepare1( N, 2, l2 ); + + // Check VIEW_ELEMENTS + DL view1 = l1; + DL view2 = l2; + myassert( view1.size() == N ); + myassert( view2.size() == N ); + + typename DL::iterator itrL1 = view1.begin(); + std::advance( itrL1, N/2 ); + view1.splice( itrL1, view2, view2.begin() ); + + myassert( view1.size() == N+1 ); + myassert( view2.size() == N-1 ); + + // check content of OWN_ELEMENTS containers + typename DL::const_iterator itr1 = l1.begin(); + typename DL::const_iterator itr2 = l2.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr1, ++itr2 ) { + myassert( (*itr1)->x == static_cast<int>(i) ); + myassert( (*itr2)->x == static_cast<int>(i*2) ); + } + + // check OWN_ELEMENTS + itrL1 = l1.begin(); + std::advance( itrL1, N/2 ); + l1.splice( itrL1, l2, l2.begin() ); + + myassert( l1.size() == N+1 ); + myassert( l2.size() == N-1 ); + + itrL1 = l1.begin(); + std::advance( itrL1, N/2 ); + myassert( (*itrL1)->x == 0 ); + ++itrL1; + myassert( (*itrL1)->x == N/2 ); + } + + // test splice( position, DataList, first, last ) + { + DL l1; + DL l2; + + test2_prepare1( N, 1, l1 ); + test2_prepare1( N, 2, l2 ); + + // Check VIEW_ELEMENTS + DL view1 = l1; + DL view2 = l2; + myassert( view1.size() == N ); + myassert( view2.size() == N ); + + typename DL::iterator itrL1 = view1.begin(); + std::advance( itrL1, N/2 ); + typename DL::iterator first2 = view2.begin(); + ++first2; + typename DL::iterator last2 = view2.end(); + --last2; + view1.splice( itrL1, view2, first2, last2 ); + + myassert( view1.size() == N+(N-2) ); + myassert( view2.size() == 2 ); + + // check content of OWN_ELEMENTS containers + typename DL::const_iterator itr1 = l1.begin(); + typename DL::const_iterator itr2 = l2.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr1, ++itr2 ) { + myassert( (*itr1)->x == static_cast<int>(i) ); + myassert( (*itr2)->x == static_cast<int>(i*2) ); + } + + // check OWN_ELEMENTS + itrL1 = l1.begin(); + std::advance( itrL1, N/2 ); + first2 = l2.begin(); + ++first2; + last2 = l2.end(); + --last2; + + l1.splice( itrL1, l2, first2, last2 ); + + myassert( l1.size() == N+(N-2) ); + myassert( l2.size() == 2 ); + + itrL1 = l1.begin(); + std::advance( itrL1, N/2 ); + myassert( (*itrL1)->x == 2 ); + ++itrL1; + myassert( (*itrL1)->x == 4 ); + itrL1 = l1.begin(); + std::advance( itrL1, N/2 + (N-2) ); + myassert( (*itrL1)->x == N/2 ); + } + clear_dtor_log(); +} + +template< class B, class D > +void test2_splice2() +{ + DataList<B> b1; + DataList<D> d2; + + const unsigned int N = 6; + test2_prepare1( N, 1, b1 ); + test2_prepare1( N, 1, d2 ); + + { + DataList<B>& b2 = d2; + bool caught = false; + try { + // check we can't splice a DataList<D> via a DataList<B> + typename DataList<B>::iterator itrB = b2.begin(); + std::advance( itrB, N/2 ); + b2.splice( itrB, b1 ); + + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert( caught ); + } + { + DataList<B>& b2 = d2; + bool caught = false; + try { + // check we can't splice a DataList<D> via a DataList<B> + typename DataList<B>::iterator itrB = b2.begin(); + std::advance( itrB, N/2 ); + b2.splice( itrB, b1, b1.begin() ); + + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert( caught ); + } + { + DataList<B>& b2 = d2; + bool caught = false; + try { + // check we can't splice a DataList<D> via a DataList<B> + typename DataList<B>::iterator itrB = b2.begin(); + std::advance( itrB, N/2 ); + b2.splice( itrB, b1, b1.begin(), b1.end() ); + + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert( caught ); + } +} + +template< class B, class D > +void test2_splice() +{ + test2_splice1<DataList<B> >(); + test2_splice1<DataList<D> >(); + test2_splice1<ConstDataList<DataList<D> > >(); + test2_splice2<B,D>(); +} + +template< class DL > +void test2_remove1() +{ + typedef typename DL::base_value_type T; + const unsigned int N = 6; + { + DL l; + test2_prepare1( N, 1, l ); + myassert( l.size() == N ); + + typename DL::iterator itr = l.begin(); + std::advance( itr, N/2 ); + l.remove( *itr ); + + myassert( l.size() == N-1 ); + itr = l.begin(); + std::advance( itr, N/2 ); + myassert( (*itr)->x == static_cast<int>(N/2 + 1) ); + } + { + DL l; + test2_prepare1( N, 1, l ); + myassert( l.size() == N ); + + PredX<T> predicate; + predicate.m_cut = N/2; + l.remove_if( predicate ); + myassert( l.size() == N/2 + 1); + } +} + +template< class B, class D > +void test2_remove() +{ + test2_remove1<DataList<B> >(); + test2_remove1<DataList<D> >(); + test2_remove1<ConstDataList<DataList<D> > >(); +} + +template <class DL> +void test2_merge1() +{ + typedef typename DL::base_value_type T; + const unsigned int N = 6; + + { + DL l1; + DL l2; + test2_prepare1( N, 1, l1 ); + test2_prepare1( N, 2, l2 ); + + myassert( l1.size() == N ); + myassert( l2.size() == N ); + + // test VIEW_ELEMENTS + DL view1 = l1; + DL view2 = l2; + + view1.merge( view2 ); + myassert( view1.size() == 2*N ); + myassert( view2.empty() ); + + // check content of OWN_ELEMENTS containers + typename DL::const_iterator itr1 = l1.begin(); + typename DL::const_iterator itr2 = l2.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr1, ++itr2 ) { + myassert( (*itr1)->x == static_cast<int>(i) ); + myassert( (*itr2)->x == static_cast<int>(i*2) ); + } + + // test OWN_ELEMENTS + l1.merge( l2 ); + myassert( l1.size() == 2*N ); + myassert( l2.empty() ); + } + { + DL l1; + DL l2; + test2_prepare1( N, 1, l1 ); + test2_prepare1( N, 2, l2 ); + + myassert( l1.size() == N ); + myassert( l2.size() == N ); + + // test VIEW_ELEMENTS + DL view1 = l1; + DL view2 = l2; + + view1.merge( view2, LessX<T>() ); + myassert( view1.size() == 2*N ); + myassert( view2.empty() ); + + // check content of OWN_ELEMENTS containers + typename DL::const_iterator itr1 = l1.begin(); + typename DL::const_iterator itr2 = l2.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr1, ++itr2 ) { + myassert( (*itr1)->x == static_cast<int>(i) ); + myassert( (*itr2)->x == static_cast<int>(i*2) ); + } + + // test OWN_ELEMENTS + l1.merge( l2, LessX<T>() ); + myassert( l1.size() == 2*N ); + myassert( l2.empty() ); + + itr1 = l1.begin(); + myassert( (*itr1)->x == 0 ); + ++itr1; + myassert( (*itr1)->x == 0 ); + itr1 = --l1.end(); + myassert( (*itr1)->x == static_cast<int>( (N-1)*2 ) ); + } +} + +template< class B, class D> +void test2_merge2() +{ + DataList<B> b1; + DataList<D> d2; + + const unsigned int N = 6; + test2_prepare1( N, 1, b1 ); + test2_prepare1( N, 1, d2 ); + + { + DataList<B>& b2 = d2; + bool caught = false; + try { + // check we can't merge a DataList<D> via a DataList<B> + b2.merge( b1 ); + + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert( caught ); + } + { + DataList<B>& b2 = d2; + bool caught = false; + try { + // check we can't merge a DataList<D> via a DataList<B> + b2.merge( b1, LessX<B>() ); + + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert( caught ); + } +} + +template< class B, class D > +void test2_merge() +{ + test2_merge1<DataList<B> >(); + test2_merge1<DataList<D> >(); + test2_merge1<ConstDataList<DataList<D> > >(); + test2_merge2<B, D>(); +} + +template< class DL > +void test2_unique1() +{ + typedef typename DL::base_value_type T; + const unsigned int N = 6; + { + DL l; + test2_prepare1( N, 1, l ); + const T * elem = l.front(); + l.push_front( const_cast<T*>(elem) ); + myassert( l.size() == N+1 ); + + // [0, 0, 1, 2, 3, 4, 5] => [0, 1, 2, 3, 4, 5] + l.unique(); + myassert( l.size() == N ); + + typename DL::const_iterator itr = l.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + } + { + DL l; + test2_prepare1( N, 1, l ); + const T * elem = l.front(); + l.push_front( const_cast<T*>(elem) ); + myassert( l.size() == N+1 ); + + // [0, 0, 1, 2, 3, 4, 5] => [0, 0] + l.unique( LessX<T>() ); + myassert( l.size() == 2 ); + + typename DL::const_iterator itr = l.begin(); + myassert( (*itr)->x == static_cast<int>(0) ); + ++itr; + myassert( (*itr)->x == static_cast<int>(0) ); + + // Prevent crash when l is deleted. + l.unique(); + } + // testing VIEW_ELEMENTS + { + DL l; + test2_prepare1( N, 1, l ); + const T * elem = l.front(); + l.push_front( const_cast<T*>(elem) ); + myassert( l.size() == N+1 ); + + DL view = l; + // [0, 0, 1, 2, 3, 4, 5] => [0, 1, 2, 3, 4, 5] + view.unique(); + myassert( view.size() == N ); + myassert( l.size() == N+1 ); + typename DL::const_iterator itr = l.begin(); + myassert( (*itr)->x == 0 ); + ++itr; + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + + // Prevent crash when l is deleted. + l.unique(); + } + // testing VIEW_ELEMENTS + { + DL l; + test2_prepare1( N, 1, l ); + const T * elem = l.front(); + l.push_front( const_cast<T*>(elem) ); + myassert( l.size() == N+1 ); + + DL view = l; + // [0, 0, 1, 2, 3, 4, 5] => [0, 0] + view.unique( LessX<T>() ); + myassert( view.size() == 2 ); + myassert( l.size() == N+1 ); + typename DL::const_iterator itr = l.begin(); + myassert( (*itr)->x == 0 ); + ++itr; + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + + // Prevent crash when l is deleted. + l.unique(); + } +} + +template< class B, class D > +void test2_unique2() +{ + const unsigned int N = 6; + { + DataList<D> d1; + test2_prepare1( N, 1, d1 ); + const D * elem = d1.front(); + d1.push_front( const_cast<D*>(elem) ); + myassert( d1.size() == N+1 ); + + // test we can @c unique a derived container from its base container + DataList<B>& b1 = d1; + // [0, 0, 1, 2, 3, 4, 5] => [0, 1, 2, 3, 4, 5] + b1.unique(); + myassert( b1.size() == N ); + myassert( d1.size() == N ); + + { + typename DataList<B>::const_iterator itr = b1.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + } + { + typename DataList<D>::const_iterator itr = d1.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + } + } +} + +template< class B, class D > +void test2_unique() +{ + test2_unique1<DataList<B> >(); + test2_unique1<DataList<D> >(); + test2_unique1<ConstDataList<DataList<D> > >(); + test2_unique2<B,D>(); +} + +template< class DL > +void test2_reverse1() +{ + //typedef typename DL::base_value_type T; + const unsigned int N = 6; + { + DL l; + test2_prepare1( N, 1, l ); + myassert( l.size() == N ); + + { + typename DL::const_iterator itr = l.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + } + + l.reverse(); + { + typename DL::const_iterator itr = l.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(N-1-i) ); + } + } + + } +} + +template< class B, class D > +void test2_reverse2() +{ + const unsigned int N = 6; + { + DataList<D> d1; + test2_prepare1( N, 1, d1 ); + myassert( d1.size() == N ); + + { + typename DataList<D>::const_iterator itr = d1.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(i) ); + } + } + + // Check one can reverse a derived container through its base container + DataList<B>& b1 = d1; + b1.reverse(); + { + typename DataList<B>::const_iterator itr = b1.begin(); + for ( unsigned int i = 0; i != N; ++i, ++itr ) { + myassert( (*itr)->x == static_cast<int>(N-1-i) ); + } + } + } +} + +template< class B, class D > +void test2_reverse() +{ + test2_reverse1<DataList<B> >(); + test2_reverse1<DataList<D> >(); + test2_reverse1<ConstDataList<DataList<D> > >(); + test2_reverse2<B, D>(); +} + +template <class DL, class It> +void test2_iter_swap_memb2 (DL& v, It beg, It end) +{ + int a = v.front()->x; + int b = v.back()->x; + myassert (a != b); + myassert( a == v.front()->x ); + myassert( b == v.back()->x ); + DL::iter_swap (beg, end); + myassert (a == v.back()->x); + myassert (b == v.front()->x); +} +template <class DL> +void test2_iter_swap_memb1() +{ + typedef typename DL::base_value_type T; + DL v; + for (int i=0; i<10; ++i ) + v.push_back (new T(i)); + test2_iter_swap_memb2 (v, v.begin(), --v.end()); + + DL v2 (v); + bool caught = false; + try { + test2_iter_swap_memb2 (v, v.begin(), --v2.end()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} +template <class B, class D> +void test2_iter_swap_memb() +{ + test2_iter_swap_memb1<DataList<B> > (); + test2_iter_swap_memb1<DataList<D> > (); + test2_iter_swap_memb1<ConstDataList<DataList<D> > > (); + + DataList<D> v; + for (int i=0; i<10; ++i) + v.push_back (new D(i)); + DataList<B>& b = v; + test2_iter_swap_memb2 (v, v.begin(), --v.end() ); + bool caught = false; + try { + test2_iter_swap_memb2 (b, b.begin(), --b.end() ); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +template <class DL, class It> +void test2_iter_swap2 (DL& v, It beg, It end) +{ + int a = v.front()->x; + int b = v.back()->x; + myassert (a != b); + myassert( a == v.front()->x ); + myassert( b == v.back()->x ); + std::iter_swap (beg, end); + myassert (a == v.back()->x); + myassert (b == v.front()->x); +} +template <class DL> +void test2_iter_swap1() +{ + typedef typename DL::base_value_type T; + DL v; + for (int i=0; i<10; ++i ) + v.push_back (new T(i)); + test2_iter_swap2 (v, v.begin(), --v.end()); + test2_iter_swap2 (v, v.rbegin(), --v.rend()); + + DL v2 (v); + bool caught = false; + try { + test2_iter_swap2 (v, v.begin(), --v2.end()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + caught = false; + try { + test2_iter_swap2 (v, v.rbegin(), --v2.rend()); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} +template <class B, class D> +void test2_iter_swap() +{ + test2_iter_swap1<DataList<B> > (); + test2_iter_swap1<DataList<D> > (); + test2_iter_swap1<ConstDataList<DataList<D> > > (); + + DataList<D> v; + for (int i=0; i<10; ++i) + v.push_back (new D(i)); + DataList<B>& b = v; + test2_iter_swap2 (v, v.begin(), --v.end() ); + bool caught = false; + try { + test2_iter_swap2 (b, b.begin(), --b.end() ); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + caught = false; + try { + test2_iter_swap2 (b, b.rbegin(), --b.rend() ); + } + catch (dl_test_err&) { + caught = true; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +template <class T> +struct Pred +{ + Pred (int the_v) : v (the_v) {} + bool operator() (const T* a) const + { return a->x == v; } + int v; +}; +template <class DL> +void test2_removealg1() +{ + typedef typename DL::base_value_type T; + const int N=10; + + { + clear_dtor_log(); + DL v; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + typename DL::iterator it = + std::remove (v.begin(), v.end(), nth (v, 5)); + myassert (std::distance (v.begin(), it) == N-1); + int j=0; + for (int i=0; i<N-1; i++, j++) { + if (j == 5) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth (v, N-1) == 0); + check_dtor_log (5); + + it = std::remove (v.begin(), ::prev(v.end()), nth(v,8)); + myassert (std::distance (v.begin(), it) == N-2); + j=0; + for (int i=0; i<N-2; i++, j++) { + if (j == 5) ++j; + if (j == 9) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,N-2) == 0); + myassert (nth(v,N-1) == 0); + check_dtor_log (9); + } + + { + clear_dtor_log(); + DL v; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + typename DL::iterator it = + std::remove_if (v.begin(), v.end(), Pred<T>(5)); + myassert (std::distance (v.begin(), it) == N-1); + int j=0; + for (int i=0; i<N-1; i++, j++) { + if (j == 5) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,N-1) == 0); + check_dtor_log (5); + + it = std::remove_if (v.begin(), ::prev(v.end()), Pred<T>(9)); + myassert (std::distance (v.begin(), it) == N-2); + j=0; + for (int i=0; i<N-2; i++, j++) { + if (j == 5) ++j; + if (j == 9) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,N-2) == 0); + myassert (nth(v,N-1) == 0); + check_dtor_log (9); + } + + { + clear_dtor_log(); + DL v; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + typename DL::reverse_iterator it = + std::remove (v.rbegin(), v.rend(), nth(v,5)); + myassert (std::distance (v.rbegin(), it) == N-1); + int j=0; + for (int i=1; i<N; i++, j++) { + if (j == 5) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,0) == 0); + check_dtor_log (5); + + it = std::remove (v.rbegin(), ::prev(v.rend()), nth(v,8)); + myassert (std::distance (v.rbegin(), it) == N-2); + j=0; + for (int i=2; i<N; i++, j++) { + if (j == 5) ++j; + if (j == 8) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,0) == 0); + myassert (nth(v,1) == 0); + check_dtor_log (8); + } + + { + clear_dtor_log(); + DL v; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + typename DL::reverse_iterator it = + std::remove_if (v.rbegin(), v.rend(), Pred<T>(5)); + myassert (std::distance (v.rbegin(), it) == N-1); + int j=0; + for (int i=1; i<N; i++, j++) { + if (j == 5) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,0) == 0); + check_dtor_log (5); + + it = std::remove_if (v.rbegin(), ::prev(v.rend()), Pred<T>(8)); + myassert (std::distance (v.rbegin(), it) == N-2); + j=0; + for (int i=2; i<N; i++, j++) { + if (j == 5) ++j; + if (j == 8) ++j; + myassert (nth(v,i)->x == j); + } + myassert (nth(v,0) == 0); + myassert (nth(v,1) == 0); + check_dtor_log (8); + } + +} +template <class B, class D> +void test2_removealg() +{ + test2_removealg1<DataList<B> > (); + test2_removealg1<DataList<D> > (); + + test2_removealg1<ConstDataList<DataList<D> > > (); +} + +template <class T> +struct BPred +{ + bool operator() (const T* a, const T* b) const + { return a->x == b->x; } +}; +template <class DL> +void test2_uniquealg1() +{ + typedef typename DL::base_value_type T; + { + DL v (SG::VIEW_ELEMENTS); + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (v.back()); + v.push_back (new T(2)); + typename DL::iterator it = std::unique (v.begin(), v.end()); + myassert (std::distance (v.begin(), it) == 3); + for (int i = 0; i < 3; i++) + myassert (nth(v,i)->x == i); + myassert (nth(v,3) == 0); + } + + { + clear_dtor_log(); + DL v; + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v.push_back (new T(3)); + typename DL::iterator it = + std::unique (v.begin(), v.end(), BPred<T>()); + myassert (std::distance (v.begin(), it) == 4); + for (int i = 0; i < 4; i++) + myassert (nth(v,i)->x == i); + myassert (nth(v,4) == 0); + myassert (nth(v,5) == 0); + check_dtor_log (1, 3); + } + + { + DL v (SG::VIEW_ELEMENTS); + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (v.back()); + v.push_back (new T(2)); + typename DL::reverse_iterator it = + std::unique (v.rbegin(), v.rend()); + myassert (std::distance (v.rbegin(), it) == 3); + for (int i = 1; i < 3; i++) + myassert (nth(v,i)->x == i-1); + myassert (nth(v,0) == 0); + } + + { + clear_dtor_log(); + DL v; + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v.push_back (new T(3)); + typename DL::reverse_iterator it = + std::unique (v.rbegin(), v.rend(), BPred<T>()); + myassert (std::distance (v.rbegin(), it) == 4); + for (int i = 2; i < 6; i++) + myassert (nth(v,i)->x == i-2); + myassert (nth(v,0) == 0); + myassert (nth(v,1) == 0); + check_dtor_log (1, 3); + } +} +template <class B, class D> +void test2_uniquealg() +{ + test2_uniquealg1<DataList<B> > (); + test2_uniquealg1<DataList<D> > (); + test2_uniquealg1<ConstDataList<DataList<D> > > (); +} + +template <class DL> +void test2_reversealg1() +{ + typedef typename DL::base_value_type T; + int N=5; + { + clear_dtor_log(); + DL v; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + std::reverse (v.begin(), v.end()); + for (int i=0; i<N; i++) + myassert (nth(v,i)->x == N-1-i); + std::reverse (v.rbegin(), v.rend()); + for (int i=0; i<N; i++) + myassert (nth(v,i)->x == i); + check_dtor_log (); + } +} +template <class B, class D> +void test2_reversealg() +{ + test2_reversealg1<DataList<B> > (); + test2_reversealg1<DataList<D> > (); + test2_reversealg1<ConstDataList<DataList<D> > > (); +} + +template <class DL> +void test2_rotatealg1() +{ + typedef typename DL::base_value_type T; + const int N=5; + { + clear_dtor_log(); + DL v; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + std::rotate (v.begin(), ::next(v.begin(),2), v.end()); + for (int i=0; i<N; i++) + myassert (nth(v,i)->x == (i+2)%5); + std::rotate (v.rbegin(), ::next(v.rbegin(),2), v.rend()); + for (int i=0; i<N; i++) + myassert (nth(v,i)->x == i); + check_dtor_log(); + } +} +template <class B, class D> +void test2_rotatealg() +{ + test2_rotatealg1<DataList<B> > (); + test2_rotatealg1<DataList<D> > (); + test2_rotatealg1<ConstDataList<DataList<D> > > (); +} + +template <class T> +struct PPred +{ + PPred (int the_v) : v (the_v) {} + bool operator() (const T* a) const + { return a->x < v; } + int v; +}; +template <class DL> +void random_list (DL& l, int n) +{ + typedef typename DL::base_value_type T; + std::vector<T*> v; + for (int i=0; i < n; i++) + v.push_back (new T(i)); + std::random_shuffle (v.begin(), v.end(), stlrand); + l.assign (v.begin(), v.end()); + clear_dtor_log(); +} +template <class DL> +void test2_partitionalg1() +{ + typedef typename DL::base_value_type T; + const int N=10; + { + stlrand.seed = 2; + clear_dtor_log(); + DL v; + random_list (v, N); + typename DL::iterator it = + std::partition (v.begin(), v.end(), PPred<T>(5)); + typename DL::iterator ii = v.begin(); + while (ii != it) + myassert ((*ii++)->x < 5); + while (ii != v.end()) + myassert ((*ii++)->x >= 5); + check_dtor_log(); + + random_list (v, N); + typename DL::reverse_iterator rit = + std::partition (v.rbegin(), v.rend(), PPred<T>(5)); + typename DL::reverse_iterator jj = v.rbegin(); + while (jj != rit) + myassert ((*jj++)->x < 5); + while (jj != v.rend()) + myassert ((*jj++)->x >= 5); + check_dtor_log(); + } + + { + stlrand.seed = 3; + clear_dtor_log(); + DL v; + random_list (v, N); + typename DL::iterator it = + std::stable_partition (v.begin(), v.end(), PPred<T>(5)); + typename DL::iterator ii = v.begin(); + while (ii != it) + myassert ((*ii++)->x < 5); + while (ii != v.end()) + myassert ((*ii++)->x >= 5); + check_dtor_log(); + + random_list (v, N); + typename DL::reverse_iterator rit = + std::stable_partition (v.rbegin(), v.rend(), PPred<T>(5)); + typename DL::reverse_iterator jj = v.rbegin(); + while (jj != rit) + myassert ((*jj++)->x < 5); + while (jj != v.rend()) + myassert ((*jj++)->x >= 5); + check_dtor_log(); + } +} +template <class B, class D> +void test2_partitionalg() +{ + test2_partitionalg1<DataList<B> > (); + test2_partitionalg1<DataList<D> > (); + test2_partitionalg1<ConstDataList<DataList<D> > > (); +} + +template <class D> +void test2_asdatalist() +{ + ConstDataList<DataList<D> > cv; + cv.push_back (new D(1)); + const DataList<D>* dv = cv.asDataList(); + myassert (dv->size() == 1); +} + +template <class DL> +void test2_assignelement1() +{ + typedef typename DL::base_value_type T; + clear_dtor_log(); + DL v; + v.push_back (new T(1)); + v.push_back (new T(2)); + v.assignElement ((v.begin()).base(), new T(3)); + check_dtor_log (1); + v.assignElement ((v.begin()).base(), new T(4)); + check_dtor_log (3); +} +template <class B, class D> +void test2_assignelement() +{ + test2_assignelement1<DataList<B> > (); + test2_assignelement1<DataList<D> > (); + test2_assignelement1<ConstDataList<DataList<D> > > (); +} + + +template <class DL> +void test2_swapranges() +{ + clear_dtor_log(); + + typedef typename DL::base_value_type T; + DL l1; + DL l2; + for (int i = 0; i < 10; i++) { + l1.push_back (new T(i)); + l2.push_back (new T(i+10)); + } + std::swap_ranges (::next(l1.begin(),3), ::next(l1.begin(),6), + ::next(l2.begin(),4)); + std::swap_ranges (::next(l1.rbegin(),3), ::next(l1.rbegin(),6), + ::next(l2.rbegin(),4)); + + check_dtor_log(); +} +template <class B, class D> +void test2_swapranges() +{ + test2_swapranges<DataList<B> > (); + test2_swapranges<DataList<D> > (); + test2_swapranges<ConstDataList<DataList<D> > > (); +} + +template <class B, class D> +void do_test2() +{ + boost::function_requires<boost::ForwardContainerConcept<DataList<B> > >(); + boost::function_requires<boost::ForwardContainerConcept<DataList<D> > >(); + + test2_initial<B,D> (); + test2_default_ctor<B,D> (); + test2_sized_ctor<B,D> (); + test2_insertion_ctor<B,D> (); + test2_copy_ctor<B,D> (); + test2_dtor<B,D> (); + test2_push_front<B,D> (); + test2_push_back<B,D> (); + test2_size<B,D> (); + test2_stdcont<B,D> (); + test2_empty<B,D> (); + test2_max_size<B,D> (); + test2_front_back_const<B,D> (); + test2_front_back<B,D> (); + test2_begin_end_const<B,D> (); + test2_rbegin_rend_const<B,D> (); + test2_elementproxy<B,D> (); + test2_swapelement_iter<B,D> (); + test2_resize<B,D> (); + test2_pop_front<B,D> (); + test2_pop_back<B,D> (); + test2_begin_end<B,D> (); + test2_rbegin_rend<B,D> (); + test2_erase_range<B,D> (); + test2_erase_single<B,D> (); + test2_operator_assign<B,D> (); + test2_insert_value<B,D> (); + test2_insert_range<B,D> (); + test2_clear<B,D> (); + test2_swap<B,D> (); + test2_assign<B,D> (); + test2_relops<B,D> (); + test2_sort<B,D> (); + test2_splice<B,D>(); + test2_merge<B,D>(); + test2_remove<B,D>(); + test2_unique<B,D>(); + test2_reverse<B,D>(); + test2_iter_swap_memb<B,D> (); + test2_iter_swap<B,D> (); + test2_removealg<B,D> (); + test2_uniquealg<B,D> (); + test2_reversealg<B,D> (); + test2_rotatealg<B,D> (); + test2_partitionalg<B,D> (); + test2_asdatalist<D> (); + test2_assignelement<B,D> (); + test2_swapranges<B,D> (); +} + + +template <class T> +void dump_classid() +{ + typedef ClassID_traits<DataList<T> > traits; + std::cout << "name: " << traits::typeName() << "\n"; + std::cout << " clid, vers, is_do: " + << std::hex << traits::ID() << std::dec << " " + << traits::s_version << " " + << traits::s_isDataObject << "\n"; +} + + +void test2() +{ + std::cout << "*** DataList_test [test2] BEGIN ***" << std::endl; + test2_myassert(); + do_test2<AA, BB> (); + do_test2<BB, CC> (); + do_test2<M, P> (); + do_test2<M, R> (); + myassert (ClassName<DataList<AA> >::name() == "DataList<AA>"); + myassert (ClassName<DataList<BB> >::name() == "DataList<BB>"); + myassert (ClassName<DataList<CC> >::name() == "DataList<CC>"); + myassert (ClassName<DataList<M> >::name() == "DataList<M>"); + myassert (ClassName<DataList<P> >::name() == "DataList<P>"); + myassert (ClassName<DataList<R> >::name() == "DataList<R>"); + dump_classid<AA> (); + dump_classid<BB> (); + dump_classid<CC> (); +#if 0 + std::ostringstream os; + os << ClassID_traits<DataList<AA> >::packageInfo(); + myassert ( os.str().substr(0,7) == "$Name: " || + os.str() == "Package-00-00-00" ); + os.str (""); + os << ClassID_traits<DataList<CC> >::packageInfo(); + myassert (os.str() == "Package-00-00-00"); +#endif + + std::cout << "*** DataList_test [test2] OK ***" << std::endl; +} + + +void test_baseinfo() +{ + std::vector<CLID> clids; + clids = SG::BaseInfo<DataList<CC> >::get_bases(); + std::vector<CLID> exp1 = list_of + (ClassID_traits<DataList<AA> >::ID()) + (ClassID_traits<DataList<BB> >::ID()) + (ClassID_traits<DataList<CC> >::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp1.begin(), exp1.end()); + myassert (clids == exp1); + + clids = SG::BaseInfo<DataList<R> >::get_bases(); + std::vector<CLID> exp2 = list_of + (ClassID_traits<DataList<R> >::ID()) + (ClassID_traits<DataList<N> >::ID()) + (ClassID_traits<DataList<O> >::ID()) + (ClassID_traits<DataList<Q> >::ID()) + (ClassID_traits<DataList<M> >::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp2.begin(), exp2.end()); + myassert (clids == exp2); + + myassert (SG::BaseInfo<DataList<CC> >::is_base + (ClassID_traits<DataList<BB> >::ID())); + myassert (! SG::BaseInfo<DataList<CC> >::is_virtual + (ClassID_traits<DataList<BB> >::ID())); + myassert (SG::BaseInfo<DataList<R> >::is_base + (ClassID_traits<DataList<M> >::ID())); + myassert (SG::BaseInfo<DataList<R> >::is_virtual + (ClassID_traits<DataList<M> >::ID())); +} + + +void test_eltbaseinfo() +{ + std::vector<const std::type_info*> tinfos; + tinfos = SG::BaseInfo<CC>::get_ti_bases(); + std::vector<const std::type_info*> exp1 = list_of + (&typeid(AA)) + (&typeid(BB)) + (&typeid(CC)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp1.begin(), exp1.end()); + myassert (tinfos == exp1); + + tinfos = SG::BaseInfo<R>::get_ti_bases(); + std::vector<const std::type_info*> exp2 = list_of + (&typeid(R)) + (&typeid(N)) + (&typeid(O)) + (&typeid(Q)) + (&typeid(M)) + (&typeid(MM)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp2.begin(), exp2.end()); + myassert (tinfos == exp2); + + myassert (SG::BaseInfo<CC>::is_base (typeid(BB))); + myassert (! SG::BaseInfo<CC>::is_virtual (typeid(BB))); + myassert (SG::BaseInfo<R>::is_base (typeid(M))); + myassert (SG::BaseInfo<R>::is_virtual (typeid(M))); +} + + +void test_copyconvert() +{ + DataList<P> lst; + for (int i=0; i<10; i++) + lst.push_back (new P(i)); + + assert (SG::BaseInfo<DataList<P> >::is_base (typeid (DataList<M>))); + assert (! SG::BaseInfo<DataList<P> >::is_base (typeid (DataList<MM>))); + + DataModel_detail::DVLInfoBase* info; + void* contp = DataModel_detail::dvl_convert (lst, + typeid (DataList<AA>), info); + assert (contp == 0); + DataList<MM>::dvlinfo(); + contp = DataModel_detail::dvl_convert (lst, typeid (DataList<MM>), info); + DataList<MM>& mmlst = *(DataList<MM>*)contp; + assert (mmlst.ownPolicy() == SG::VIEW_ELEMENTS); + assert (mmlst.size() == 10); + DataList<MM>::iterator it = mmlst.begin(); + for (int i=0; i<10; i++) { + MM* mm = *it; + assert (mm->mm == i + 100); + P* pp = dynamic_cast<P*> (mm); + if (!pp) std::abort(); + assert (pp->x == i); + ++it; + } + + for (int i=10; i<20; i++) + lst.push_back (new P(i)); + DataModel_detail::dvl_update (lst, contp, info); + assert (mmlst.ownPolicy() == SG::VIEW_ELEMENTS); + assert (mmlst.size() == 20); + it = mmlst.begin(); + for (int i=0; i<20; i++) { + MM* mm = *it; + assert (mm->mm == i + 100); + P* pp = dynamic_cast<P*> (mm); + if (!pp) std::abort(); + assert (pp->x == i); + ++it; + } +} + + +void test_iterate() +{ + DataList<P> vp; + for (int i=0; i < 10; i++) { + vp.push_back (new P(i)); + vp.push_back (0); + } + + const DataModel_detail::DVLInfoBase& info1 = DataList<P>::dvlinfo(); + DataModel_detail::DVLIteratorBase* iterator = info1.iterator (&vp); + int ii = 0; + while (const void* p = iterator->next()) { + const P* pp = reinterpret_cast<const P*> (p); + assert (pp->x == ii); + ++ii; + } + delete iterator; + + DataList<M>& vm = vp; + const DataModel_detail::DVLInfoBase& info2 = DataList<M>::dvlinfo(); + iterator = info2.iterator (&vm); + ii = 0; + while (const void* p = iterator->next()) { + const M* pp = reinterpret_cast<const M*> (p); + assert (pp->x == ii++); + } + delete iterator; +} + + +int main() +{ + test1(); + test2(); + test_baseinfo(); + test_eltbaseinfo(); + test_copyconvert(); + test_iterate(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE + +// asDataList diff --git a/EDM/athena/Control/AthContainers/test/DataVector_a_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_a_test.cxx new file mode 100644 index 00000000..0976fada --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_a_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_a_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG + + +#include "DataVector_test.icc" + + +void test2_a() +{ + std::cout << "test2_a\n"; + do_test2<AA, BB> (); +} + + +int main() +{ + test2_a(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DataVector_b_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_b_test.cxx new file mode 100644 index 00000000..aa63117b --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_b_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_b_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG + + +#include "DataVector_test.icc" + + +void test2_b() +{ + std::cout << "test2_b\n"; + do_test2<BB, CC> (); +} + + +int main() +{ + test2_b(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DataVector_c_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_c_test.cxx new file mode 100644 index 00000000..694b4f80 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_c_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_c_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG + + +#include "DataVector_test.icc" + + +void test2_c() +{ + std::cout << "test2_c\n"; + do_test2<M, P> (); +} + + +int main() +{ + test2_c(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DataVector_d_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_d_test.cxx new file mode 100644 index 00000000..3a6ea1bb --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_d_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_d_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG + + +#include "DataVector_test.icc" + + +void test2_d() +{ + std::cout << "test2_d\n"; + do_test2<M, R> (); +} + + +int main() +{ + test2_d(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DataVector_e_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_e_test.cxx new file mode 100644 index 00000000..61a22ca3 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_e_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_e_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG + + +#include "DataVector_test.icc" + + +void test2_e() +{ + std::cout << "test2_e\n"; + do_test2<AAux, BAux> (); +} + + +int main() +{ + test2_e(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DataVector_f_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_f_test.cxx new file mode 100644 index 00000000..0d530396 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_f_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_f_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG + + +#include "DataVector_test.icc" + + +void test2_f() +{ + std::cout << "test2_f\n"; + do_test2<AA, CAux> (); +} + + +int main() +{ + test2_f(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/DataVector_test.cxx b/EDM/athena/Control/AthContainers/test/DataVector_test.cxx new file mode 100644 index 00000000..20ebcdc5 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_test.cxx @@ -0,0 +1,894 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include <cassert> +#include <stdexcept> +#include <string> +#include <sstream> +#include <iomanip> +#include <iostream> +#include <vector> +#include <math.h> +#include <boost/iterator_adaptors.hpp> +#include <boost/iterator/indirect_iterator.hpp> +#include <boost/assign/list_of.hpp> +#include "SGTools/CLASS_DEF.h" +#include "SGTools/ClassName.h" + + +#include "DataVector_test.icc" + +//************************************************************************* + + +using boost::assign::list_of; + +#include "AthContainers/DataVector.h" +#include "AthContainers/ConstDataVector.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxElementComplete.h" + + +//************************************************************************ + +struct AbsFluff { + static int s_alive; + AbsFluff() { ++s_alive; } + virtual ~AbsFluff() { + std::cout << " ----> Destructor of AbsFluff called for " << this + << ". After return, left alive " << --s_alive << std::endl; + } + virtual void foo() = 0; + virtual void cfoo() const = 0; +}; + +int AbsFluff::s_alive = 0; + +struct DerivedFluff : public AbsFluff { + int m_int; + float m_float; + std::string m_string; + virtual ~DerivedFluff() + { + // cout << " ----> Destructor of DerivedFluff called for " << this << std::endl; + } + std::string m_anotherString; + DerivedFluff() : AbsFluff(), m_int(1), m_float(-379.456f), + m_string("this is the Fluff struct"), + m_anotherString("this is the DerivedFluff struct") { } + DerivedFluff(const DerivedFluff& rhs) : + AbsFluff(), + m_int(rhs.m_int), m_float(-379.456f), + m_string("this is the Fluff struct") { } + DerivedFluff& operator= (const DerivedFluff&) = delete; + + virtual void foo() { /* cout << "foo called" << std::endl; */ } + virtual void cfoo() const { /* cout << "foo called" << std::endl; */ } +}; + +class FluffContainer : public DataVector<DerivedFluff> +{ +public: + FluffContainer() : DataVector<DerivedFluff>() { }; + virtual ~FluffContainer() {} +}; + + +void test1 () +{ + std::cout << "*** DataVector_test test1 BEGIN ***" << std::endl; + typedef DataVector<int> IntVector; + IntVector intV; + myassert(intV.empty()); + intV.reserve(10); + myassert(intV.capacity() == 10); + myassert(intV.capacity_v() == 10); + + unsigned int i; + const unsigned int IFILL(3); + for (i=0; i<IFILL; ++i) intV.push_back(new int(i)); + myassert (IFILL == intV.size()); + myassert (IFILL == intV.size_v()); + myassert(std::distance(intV.begin(), intV.end()) == (int)IFILL); + myassert(*(intV.front()) == 0); + myassert(2 == *(intV.back())); + intV.front() = new int(7); + myassert(7 == *(intV.front())); + *(intV.back()) = 3; + myassert(3 == *(intV.back())); + { + std::ostream_iterator<int*> os(std::cout, " "); + std::cout << "intV: " << std::hex; + std::copy(intV.begin(), intV.end(), os); + std::cout << std::dec <<std::endl; + std::ostream_iterator<int> intos(std::cout, " "); + /*1.30 boost::indirect_iterator_generator<DataVector<int>::iterator, int>::type + intVF(intV.begin()), intVL(intV.end()); */ + boost::indirect_iterator<DataVector<int>::iterator, int> intVF(intV.begin()); + boost::indirect_iterator<DataVector<int>::iterator, int> intVL(intV.end()); + std::copy(intVF, intVL, intos); + std::cout <<std::endl; + } + + //FIXME does not work DataVector<int> intV2(5, new int(5)); + DataVector<int> intV2(5); + for (unsigned int i=0; i<5; ++i) intV2[i]=new int(5); + myassert (5 == intV2.size()); + myassert (5 == *intV2[3]); + + intV2[4] = new int(6); + myassert (6 == *intV2[4]); + { + std::ostream_iterator<int*> os(std::cout, " "); + std::cout << "intV2: " << std::hex; + std::copy(intV2.begin(), intV2.end(), os); + std::cout << std::dec <<std::endl; + std::ostream_iterator<int> intos(std::cout, " "); + /*1.30 boost::indirect_iterator_generator<DataVector<int>::iterator, int>::type + intV2F(intV2.begin()), intV2L(intV2.end()); */ + boost::indirect_iterator<DataVector<int>::iterator, int> intV2F(intV2.begin()); + boost::indirect_iterator<DataVector<int>::iterator, int> intV2L(intV2.end()); + std::copy(intV2F, intV2L, intos); + std::cout <<std::endl; + } + + + DataVector<int>* pintVZeros(new DataVector<int>(10)); + delete pintVZeros; pintVZeros=0; + + DataVector<int> testConst; + testConst.push_back(new int(-1)); + testConst.push_back(new int(-2)); + DataVector<int>::const_iterator ci(testConst.begin()), ce(testConst.end()); + while (ci != ce) { + const int* UNUSED(cp) = *ci; +#if 0 + //this is bad but unfortunately correct: a DataVector<int> is like a + //vector<int*>. vector<int*>::const_iterator has type (int* const)* + //and not (const int*)*. It is hence legal to do + int* p = *ci; //assign a int* const to a int* + *p = 77; //OUCH! +#endif + ++ci; + } + + + DataVector<int> intV3(intV2.begin(), intV2.end()); + myassert (5 == intV3.size()); + myassert (5 == *intV3[3]); + myassert (6 == *intV3[4]); + + int *oldInt(0), *newInt(new int(345)); + intV3.swapElement(3, newInt, oldInt); + + myassert(*oldInt == 5); + myassert(345 == *intV3[3]); + // can't do this --- we don't own it, since intV3 is a view container. + // oldInt is still owned by intV2. + //delete oldInt; + + + DataVector<DerivedFluff>* dfluff = new DataVector<DerivedFluff>(); + dfluff->push_back(new DerivedFluff()); + dfluff->push_back(new DerivedFluff()); + int count(AbsFluff::s_alive); + { + std::ostream_iterator<DerivedFluff*> os(std::cout, " "); + std::cout << "dfluff: " << std::hex; + std::copy(dfluff->begin(), dfluff->end(), os); + std::cout << std::dec <<std::endl; + } + + myassert(2 == dfluff->size()); + + + DataVector<DerivedFluff>::iterator iter = dfluff->begin(); + int n = 0; + for (; iter != dfluff->end(); iter++) { + (*iter)->foo(); + n++; + } + myassert (2 == n); + + ((*dfluff)[0])->cfoo(); + + (*dfluff->back()).foo(); + //FIXME dfluff->back()->foo(); DNC: side effect of ElementProxy + + // copy: + + DataVector<DerivedFluff>* fluff2 = new DataVector<DerivedFluff>(*dfluff); + myassert(2 == fluff2->size()); + myassert(count == AbsFluff::s_alive); + + // copy using iterators: + DataVector<DerivedFluff>* fluff3 = new DataVector<DerivedFluff>(dfluff->begin(), dfluff->end()); + myassert(2 == fluff3->size()); + myassert(count == AbsFluff::s_alive); + + // delete copy: + std::cout << " --> Now deleting copied vector, but it should not delete elements as it does not own them. You should not see message of Element Destructor" << std::endl; + delete fluff2; fluff2=0; + std::cout << " <-- delete done" << std::endl; + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now deleting vector copied via iterator. You should NOT see the elements being deleted" << std::endl; + count = AbsFluff::s_alive; + delete fluff3; fluff3=0; + std::cout << " <-- delete done" << std::endl; + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now resizing DataVector<DerivedFluff>" << std::endl; + std::cout << " --> You should see one DerivedFluff object being deleted" << std::endl; + count = AbsFluff::s_alive - 1; + dfluff->resize(dfluff->size()-1); //reduce dfluff by one + std::cout << " <-- resize done" << std::endl; + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now deleting DataVector<DerivedFluff>. You should see all remaining DerivedFluff objects being deleted" << std::endl; + count = AbsFluff::s_alive - dfluff->size(); + delete dfluff; dfluff=0; + std::cout << " <-- delete done" << std::endl; + myassert(count == AbsFluff::s_alive); + + // std::cout << " Working with a subclass of DataVector " << std::endl; + FluffContainer fc; + DerivedFluff* f1 = new DerivedFluff(); + DerivedFluff* f2 = new DerivedFluff(); + DerivedFluff* f3 = new DerivedFluff(); + DerivedFluff* f4 = new DerivedFluff(); + fc.push_back(f1); + fc.push_back(f2); + fc.push_back(f3); + fc.push_back(f4); + + count = AbsFluff::s_alive; + std::cout << " --> Now erasing one element of the DerivedFluff container. You should see one instance being deleted" << std::endl; + fc.erase(fc.begin(), fc.begin()+1); + std::cout << " <-- erase done" << std::endl; + myassert(fc.size() == 3); + myassert(count - 1 == AbsFluff::s_alive); + + FluffContainer copyFluff, *pcopy; + count = AbsFluff::s_alive; + copyFluff = fc; + myassert(count == AbsFluff::s_alive); //op = makes pcopy a view + count = AbsFluff::s_alive; + pcopy = new FluffContainer(fc); + myassert(count == AbsFluff::s_alive); //copy constr makes pcopy a view + delete pcopy; pcopy=0; + myassert(count == AbsFluff::s_alive); //copy constr makes pcopy a view + + // DataVector with ownership: + DataVector<DerivedFluff> dfluff5; + DerivedFluff *pdf( new DerivedFluff()); + count = AbsFluff::s_alive + 9; + // dfluff5.assign(10, pdf); + dfluff5.push_back(pdf); //take ownership + for(unsigned int i=1; i<10; ++i) dfluff5.push_back(new DerivedFluff(*pdf)); + + myassert(dfluff5.size() == 10); + myassert(count == AbsFluff::s_alive); + // dfluff5.insert(dfluff5.begin(), 10, (DerivedFluff*)0); + DataVector<DerivedFluff>::iterator it5(dfluff5.begin()); + for(unsigned int i=0; i<10; ++i) it5 = dfluff5.insert(it5, 0); + myassert(count == AbsFluff::s_alive); + myassert(dfluff5.size() == 20); + + // DataVector without ownership: + DataVector<DerivedFluff>* dfluff4 = + new DataVector<DerivedFluff>(SG::VIEW_ELEMENTS); + DerivedFluff *p1(new DerivedFluff()), *p2(new DerivedFluff()); + dfluff4->push_back(p1); + dfluff4->push_back(p2); + count = AbsFluff::s_alive; + std::cout << " --> Now resizing view container. You should NOT see the elements being deleted" << std::endl; + dfluff4->resize(0); //empties dfluff4; + std::cout << " <-- resize done" << std::endl; + myassert(0 == dfluff4->size()); + myassert(count == AbsFluff::s_alive); + + std::cout << " --> Now deleting two DerivedFluff instances" << std::endl; + delete p1; + delete p2; + std::cout << " <-- delete done" << std::endl; + + + count = AbsFluff::s_alive; + // dfluff4->assign(10, pdf); + //whatever this means... + for(unsigned int i=0; i<10; ++i) dfluff4->push_back(pdf); + myassert(dfluff4->size() == 10); + myassert(count == AbsFluff::s_alive); + // dfluff4->insert(dfluff4->begin(), 10, (DerivedFluff*)0); + DataVector<DerivedFluff>::iterator it(dfluff4->begin()); + for(unsigned int i=0; i<10; ++i) it = dfluff4->insert(it, 0); + myassert(count == AbsFluff::s_alive); + myassert(dfluff4->size() == 20); + + delete dfluff4; dfluff4=0; + + //FIXME what is the right thing to do? Put in 5 NULLs or give a compilation + // error? + count = AbsFluff::s_alive; + DataVector<AbsFluff> absFluff(5); + myassert(count == AbsFluff::s_alive); + + absFluff.resize(10); + myassert(count == AbsFluff::s_alive); + + count = AbsFluff::s_alive + 5; + // absFluff.resize(15, new DerivedFluff); + absFluff.resize(15); + for(unsigned int i=10; i<15; ++i) absFluff[i]=new DerivedFluff; + myassert(count == AbsFluff::s_alive); + + count = AbsFluff::s_alive - 2; + size_t dsize(absFluff.size() - 2); + absFluff.pop_back(); + absFluff.pop_back(); + myassert(count == AbsFluff::s_alive); + myassert(absFluff.size() == dsize); + + std::cout << "*** DataVector_test OK ***" <<std::endl; +} + + +//************************************************************************ + + + +// Make sure myassert is working. +void test2_myassert() +{ + bool caught = false; + try { + myassert (false); + } + catch (dv_test_err&) { + caught = true; + } + if (!caught) abort(); +} + + +// Test check_indices +void test2_check_indices() +{ + DataVector<BB> vbb; + typename DataVector<BB>::PtrVector& pbb = + const_cast<typename DataVector<BB>::PtrVector&> (vbb.stdcont()); + pbb.push_back (new BB(1)); + pbb.push_back (new BB(2)); + CHECK_INDICES(vbb); + + DataVector<BAux> vba; + typename DataVector<BAux>::PtrVector& pba = + const_cast<typename DataVector<BAux>::PtrVector&> (vba.stdcont()); + pba.push_back (new BAux(1)); + pba.push_back (new BAux(2)); + bool caught = false; + try { + CHECK_INDICES(vba); + } + catch (const dv_test_err&) { + caught = true; + } + myassert (caught); + vba.clear(); + vba.push_back (new BAux(1)); + vba.push_back (new BAux(2)); + CHECK_INDICES(vba); + + BB* b1 = new BB(1); + BAux* b2 = new BAux(2); + CHECK_INDEX_CLEAR(b1); + CHECK_INDEX_CLEAR(b2); + vbb.push_back (b1); + vba.push_back (b2); + CHECK_INDEX_CLEAR(b1); + caught = false; + try { + CHECK_INDEX_CLEAR(b2); + } + catch (const dv_test_err&) { + caught = true; + } + //myassert (caught); //xxx + + vba.clear (SG::VIEW_ELEMENTS); + vbb.clear (SG::VIEW_ELEMENTS); + b1 = new BB(1); + b2 = new BAux(2); + CHECK_INDEX_CLEAR(b1); + CHECK_INDEX_CLEAR(b2); + vbb.push_back (b1); + vba.push_back (b2); + CHECK_INDEX_CLEAR(b1); + CHECK_INDEX_CLEAR(b2); + delete b1; + delete b2; +} + + +void test2() +{ + std::cout << "test2\n"; + test2_myassert(); + test2_check_indices(); + // Calls to do_test2 for specific classes are split out into separate + // unit tests DataVector_X_test, in order to keep the amount of memory + // needed for compilation down to something reasonable. + myassert (ClassName<DataVector<AA> >::name() == "DataVector<AA>"); + myassert (ClassName<DataVector<BB> >::name() == "DataVector<BB>"); + myassert (ClassName<DataVector<CC> >::name() == "DataVector<CC>"); + myassert (ClassName<DataVector<M> >::name() == "DataVector<M>"); + myassert (ClassName<DataVector<P> >::name() == "DataVector<P>"); + myassert (ClassName<DataVector<R> >::name() == "DataVector<R>"); + dump_classid<AA> (); + dump_classid<BB> (); + dump_classid<CC> (); +#if 0 + std::ostringstream os; + os << ClassID_traits<DataVector<AA> >::packageInfo(); + myassert (os.str().substr(0,7) == "$Name: " || os.str() == "Package-00-00-00"); + os.str (""); + os << ClassID_traits<DataVector<CC> >::packageInfo(); + myassert (os.str() == "Package-00-00-00"); +#endif +} + + +void test_baseinfo() +{ + std::vector<CLID> clids; + clids = SG::BaseInfo<DataVector<CC> >::get_bases(); + std::vector<CLID> exp1 = list_of + (ClassID_traits<DataVector<AA> >::ID()) + (ClassID_traits<DataVector<BB> >::ID()) + (ClassID_traits<DataVector<CC> >::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp1.begin(), exp1.end()); + myassert (clids == exp1); + + clids = SG::BaseInfo<DataVector<R> >::get_bases(); + std::vector<CLID> exp2 = list_of + (ClassID_traits<DataVector<R> >::ID()) + (ClassID_traits<DataVector<N> >::ID()) + (ClassID_traits<DataVector<O> >::ID()) + (ClassID_traits<DataVector<Q> >::ID()) + (ClassID_traits<DataVector<M> >::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp2.begin(), exp2.end()); + myassert (clids == exp2); + + myassert (SG::BaseInfo<DataVector<CC> >::is_base + (ClassID_traits<DataVector<BB> >::ID())); + myassert (! SG::BaseInfo<DataVector<CC> >::is_virtual + (ClassID_traits<DataVector<BB> >::ID())); + myassert (SG::BaseInfo<DataVector<R> >::is_base + (ClassID_traits<DataVector<M> >::ID())); + myassert (SG::BaseInfo<DataVector<R> >::is_virtual + (ClassID_traits<DataVector<M> >::ID())); +} + + +void test_eltbaseinfo() +{ + std::vector<const std::type_info*> tinfos; + tinfos = SG::BaseInfo<CC>::get_ti_bases(); + std::vector<const std::type_info*> exp1 = list_of + (&typeid(AA)) + (&typeid(BB)) + (&typeid(CC)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp1.begin(), exp1.end()); + myassert (tinfos == exp1); + + tinfos = SG::BaseInfo<R>::get_ti_bases(); + std::vector<const std::type_info*> exp2 = list_of + (&typeid(R)) + (&typeid(N)) + (&typeid(O)) + (&typeid(Q)) + (&typeid(M)) + (&typeid(MM)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp2.begin(), exp2.end()); + myassert (tinfos == exp2); + + myassert (SG::BaseInfo<CC>::is_base (typeid(BB))); + myassert (! SG::BaseInfo<CC>::is_virtual (typeid(BB))); + myassert (SG::BaseInfo<R>::is_base (typeid(M))); + myassert (SG::BaseInfo<R>::is_virtual (typeid(M))); +} + + +void test_copyconvert() +{ + DataVector<P> vec; + for (int i=0; i<10; i++) + vec.push_back (new P(i)); + + myassert (SG::BaseInfo<DataVector<P> >::is_base (typeid (DataVector<M>))); + myassert (! SG::BaseInfo<DataVector<P> >::is_base (typeid (DataVector<MM>))); + + DataModel_detail::DVLInfoBase* info; + void* contp = DataModel_detail::dvl_convert (vec, + typeid (DataVector<AA>), info); + myassert (contp == 0); + DataVector<MM>::dvlinfo(); + contp = DataModel_detail::dvl_convert (vec, typeid (DataVector<MM>), info); + DataVector<MM>& mmvec = *(DataVector<MM>*)contp; + myassert (mmvec.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (mmvec.size() == 10); + for (int i=0; i<10; i++) { + myassert (mmvec[i]->mm == i + 100); + MM* mm = mmvec[i]; + P* pp = dynamic_cast<P*> (mm); + if (!pp) std::abort(); + myassert (pp->x == i); + } + + for (int i=10; i<20; i++) + vec.push_back (new P(i)); + DataModel_detail::dvl_update (vec, contp, info); + myassert (mmvec.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (mmvec.size() == 20); + for (int i=0; i<20; i++) { + myassert (mmvec[i]->mm == i + 100); + MM* mm = mmvec[i]; + P* pp = dynamic_cast<P*> (mm); + myassert (pp != nullptr); + myassert (pp->x == i); + } +} + + +void test_iterate() +{ + DataVector<P> vp; + for (int i=0; i < 10; i++) { + vp.push_back (new P(i)); + vp.push_back (0); + } + + const DataModel_detail::DVLInfoBase& info1 = DataVector<P>::dvlinfo(); + DataModel_detail::DVLIteratorBase* iterator = info1.iterator (&vp); + int ii = 0; + while (const void* p = iterator->next()) { + const P* pp = reinterpret_cast<const P*> (p); + myassert (pp->x == ii); + ++ii; + } + delete iterator; + + DataVector<M>& vm = vp; + const DataModel_detail::DVLInfoBase& info2 = DataVector<M>::dvlinfo(); + iterator = info2.iterator (&vm); + ii = 0; + while (const void* p = iterator->next()) { + const M* pp = reinterpret_cast<const M*> (p); + myassert (pp->x == ii++); + } + delete iterator; +} + + +bool cmpfloat (float x1, float x2) +{ + float den = std::abs(x1) + std::abs(x2); + if (den == 0) den = 1; + return std::abs(x1-x2)/den < 1e-6; +} + + +struct AuxR +{ + float x; + float y; + float r() const { return hypot (x, y); } +}; + + +template <class T> +void test_auxdata1() +{ + DataVector<T> v; + SG::AuxStoreInternal store; + v.setStore (&store); + + typename T::template Accessor<AuxR> auxr ("auxr"); + typename T::template Accessor<bool> auxb ("auxb"); + + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v[0]->setaux(); + v[1]->setaux(); + v[2]->setaux(); + + checkaux (v); + + auxr(*v[2]).x = 3; + auxr(*v[2]).y = 4; + assert (cmpfloat (auxr(*v[2]).r(), 5)); + + auxb(*v[0]) = true; + auxb(*v[2]) = false; + assert (auxb(*v[0]) == true); + assert (auxb(*v[1]) == false); + assert (auxb(*v[2]) == false); + + typedef SG::AuxElementComplete<T> Tcomp; + Tcomp* t4 = new Tcomp(4); + t4->setaux(); + auxr(*t4).x = 3; + auxr(*t4).y = 4; + + v.push_back (t4); + + v[3]->checkaux(); + assert (cmpfloat (auxr(*v[3]).r(), 5)); + + t4->releasePrivateStore(); + v[3]->checkaux(); + assert (cmpfloat (auxr(*v[3]).r(), 5)); + + v.erase (v.begin() + 1); + assert (v.size() == 3); + checkaux (v); + assert (v[0]->x == 1); + assert (v[1]->x == 3); + assert (v[2]->x == 4); + v.push_back (new T(5)); + v[3]->setaux(); + v.push_back (new T(6)); + v[4]->setaux(); + // 1 3 4 5 6 + v.erase (v.begin()+2, v.begin()+4); + assert (v.size() == 3); + checkaux (v); + assert (v[0]->x == 1); + assert (v[1]->x == 3); + assert (v[2]->x == 6); + + DataVector<T> v2; + SG::AuxStoreInternal store2; + v2.setStore (&store2); + v2.push_back (new T(7)); + v2[0]->setaux(); + + v2.swap (v); + assert (v2.size() == 3); + assert (v.size() == 1); + checkaux (v2); + assert (v2[0]->x == 1); + assert (v2[1]->x == 3); + assert (v2[2]->x == 6); + checkaux (v); + assert (v[0]->x == 7); + + Tcomp* t8 = new Tcomp(8); + t8->setaux(); + v2.insert (v2.begin()+1, t8); + t8->releasePrivateStore(); + checkaux (v2); + + Tcomp* tmp[2] = { new Tcomp(9), new Tcomp(10) }; + tmp[0]->setaux(); + tmp[1]->setaux(); + v2.insert (v2.begin()+1, tmp, tmp+2); + tmp[0]->releasePrivateStore(); + tmp[1]->releasePrivateStore(); + assert (v2.size() == 6); + checkaux (v2); + assert (v2[0]->x == 1); + assert (v2[1]->x == 9); + assert (v2[2]->x == 10); + assert (v2[3]->x == 8); + assert (v2[4]->x == 3); + assert (v2[5]->x == 6); + + v.reserve(6); + v.resize(6); + assert (v.size() == 6); + v.pop_back(); + assert (v.size() == 5); + v.clear(); + assert (v.size() == 0); + + //************************** + + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v[0]->setaux(); + v[1]->setaux(); + v[2]->setaux(); + checkaux(v); + + std::vector<Tcomp> vc; + for (int i=0; i < 3; i++) + vc.push_back (Tcomp (*v[i])); + std::reverse (vc.begin(), vc.end()); + for (int i=0; i < 3; i++) + *v[i] = vc[i]; + assert (v[0]->x == 3); + assert (v[1]->x == 2); + assert (v[2]->x == 1); + checkaux(v); + CHECK_INDICES(v); + + Tcomp* t9 = new Tcomp (9); + t9->setaux(); + checkaux(t9); + v.push_back(t9); + checkaux(t9); + checkaux(v); + assert (!t9->usingPrivateStore()); + T* t10 = 0; + v.swapElement (3, 0, t10); + assert (t9 == t10); + assert (t10->usingPrivateStore()); + checkaux(t10); +} + + +void test_auxdata() +{ + std::cout << "test_auxdata\n"; + test_auxdata1<AAux>(); + test_auxdata1<BAux>(); + test_auxdata1<CAux>(); +} + + +// If the xAOD base classes are used, they will always report that the static +// auxids are present. But if the container is empty, they are not actually +// retrievable. We need to work around that. +class TestEmptyStore + : public SG::IAuxStore +{ +public: + virtual const void* getData (SG::auxid_t) const { return 0;} + virtual void* getDecoration (SG::auxid_t, size_t, size_t) { return 0; } + virtual const SG::auxid_set_t& getAuxIDs() const { return m_auxids; } + virtual void lock() { } + virtual void clearDecorations() { } + virtual size_t size() const { return 0; } + virtual void* getData (SG::auxid_t, size_t, size_t) { return 0; } + virtual const SG::auxid_set_t& getWritableAuxIDs() const { return m_auxids; } + virtual bool resize (size_t) { return false; } + virtual void reserve (size_t) { } + virtual void shift (size_t, ptrdiff_t) { } + virtual bool insertMove (size_t, IAuxStore&, const SG::auxid_set_t&) { return false; } + + SG::auxid_set_t m_auxids; +}; +void test_emptysort() +{ + std::cout << "test_emptysort\n"; + DataVector<AAux> v; + TestEmptyStore store; + v.setStore (&store); + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("xint"); + store.m_auxids.insert (ityp); + v.sort(); +} + + +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(); } +}; + + +template <class T> +bool wasMoved (const T&) { return true; } + +bool wasMoved (const MoveTest& x) { return x.m_v.empty(); } + + +template <class T> +void test_insertmove1() +{ + typename T::template Accessor<MoveTest> auxm ("auxm"); + + DataVector<T> v; + SG::AuxStoreInternal store; + v.setStore (&store); + + for (int i=0; i < 5; i++) + v.push_back (new T(i)); + for (int i=0; i < 5; i++) { + v[i]->setaux(); + auxm(*v[i]) = MoveTest(i); + } + + DataVector<T> v2; + SG::AuxStoreInternal store2; + v2.setStore (&store2); + + for (int i=0; i < 5; i++) + v2.push_back (new T(i+10)); + for (int i=0; i < 5; i++) { + v2[i]->setaux(); + auxm(*v2[i]) = MoveTest(i+10); + } + + v.insertMove (v.begin()+3, v2); + assert (v.size() == 10); + checkaux (v); + CHECK_INDICES (v); + for (int i=0; i < 3; i++) { + assert (v[i]->x == i); + assert (auxm(*v[i]) == MoveTest(i)); + } + for (int i=0; i < 5; i++) { + assert (v[3+i]->x == i+10); + assert (auxm(*v[3+i]) == MoveTest(i+10)); + } + for (int i=3; i < 5; i++) { + assert (v[5+i]->x == i); + assert (auxm(*v[5+i]) == MoveTest(i)); + } + assert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + assert (v2.size() == 5); + for (int i=0; i < 5; i++) { + assert (v2[i]->x == i+10); + } +} + + +void test_insertmove() +{ + std::cout << "test_insertmove\n"; + test_insertmove1<AAux>(); + test_insertmove1<BAux>(); + test_insertmove1<CAux>(); +} + + +int main() +{ + test1(); + test2(); + test_baseinfo(); + test_eltbaseinfo(); + test_copyconvert(); + test_iterate(); + test_auxdata(); + test_emptysort(); + test_insertmove(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE + +// xxx +// per-object flagging of aux data presence? diff --git a/EDM/athena/Control/AthContainers/test/DataVector_test.icc b/EDM/athena/Control/AthContainers/test/DataVector_test.icc new file mode 100644 index 00000000..65c2ba8e --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/DataVector_test.icc @@ -0,0 +1,6162 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/DataVector_test.icc + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for DataVector + * + * The @c DataVector regression tests are split into several pieces, + * in order to reduce the memory required for compilation. + * + * This file contains the code common between these pieces. + */ + + +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/foreach.h" +#include "TestTools/expect_exception.h" +#include "SGTools/TestStore.h" +#include <stdexcept> +#include <string> +#include <sstream> + + +//************************************************************************ + + +class dv_test_err + : public std::exception +{ +public: + explicit dv_test_err (const char* file, + int line, + const std::string& what); + virtual ~dv_test_err() throw() {} + virtual const char* what() const throw() { return m_what.c_str(); } +private: + std::string m_what; +}; + + +dv_test_err::dv_test_err (const char* file, + int line, + const std::string& what) +{ + std::ostringstream os; + os << file << ":" << line << " myassertion failure: " << what; + m_what = os.str(); +} + + +void throw_dv_test_err (const char* file, int line, const char* what) +{ + throw (dv_test_err (file, line, what)); +} + +#define myassert(X) do { \ + if (!(X)) { \ + throw_dv_test_err (__FILE__, __LINE__, #X); \ + } \ + } while (0) + + +#define ATHCONTAINERS_ASSERT(X) myassert(X) + + +//************************************************************************ + + +#include "AthContainers/DataVector.h" +#include "AthContainers/ConstDataVector.h" +#include "AthContainers/AuxStoreInternal.h" +#include "CxxUtils/unused.h" +#include "CxxUtils/make_unique.h" +#include "TestTools/random.h" + + + +Athena_test::RNG stlrand; +Athena_test::RNG stlrand2; +Athena_test::URNG stlurand; +Athena_test::URNG stlurand2; + + +//************************************************************************ + + +std::vector<int> dtor_log; +std::vector<int> get_dtor_log() +{ + std::vector<int> out; + out.swap (dtor_log); + // the order of element deletion within a container is unpredictable, + // due to the sort() in remove_duplicates(). + std::sort (out.begin(), out.end()); + return out; +} +void clear_dtor_log() +{ + dtor_log.clear(); +} +void check_dtor_log(int a=-1,int b=-1,int c=-1,int d=-1, int e=-1, int f=-1) +{ + std::vector<int> v; + if (a != -1) v.push_back(a); + if (b != -1) v.push_back(b); + if (c != -1) v.push_back(c); + if (d != -1) v.push_back(d); + if (e != -1) v.push_back(e); + if (f != -1) v.push_back(f); + std::sort (v.begin(), v.end()); + std::vector<int> vv = get_dtor_log(); + myassert (vv == v); +} + + +//************************************************************************ + + +struct AA +{ + AA (int the_x=0): x(the_x) {} + ~AA() { dtor_log.push_back (x); } + int x; + bool operator< (const AA& other) const { return x < other.x; } +}; +struct BB : public AA +{ + BB (int the_x=0) : AA(the_x) {} +}; +struct CC : public BB +{ + CC (int the_x=0) : BB(the_x) {} +}; + +DATAVECTOR_BASE(BB, AA); +DATAVECTOR_BASE(CC, BB); + +CLASS_DEF( DataVector<AA> , 9881 , 1 ) +CLASS_DEF( DataVector<BB> , 9882 , 1 ) +CLASS_DEF( DataVector<CC> , 178538783 , 2 ) + + +struct MM +{ + MM (int the_x=0) : mm(the_x) {} + virtual ~MM() {} + int mm; +}; +struct M +{ + M (int the_x=0) : x(the_x) {} + virtual ~M() { dtor_log.push_back (x); } + int x; + bool operator< (const M& other) const { return x < other.x; } +}; +struct N : virtual public M, public MM +{ + N (int the_x=0) : M(the_x), MM(the_x+100) {} +}; +struct O : virtual public M +{ + O (int the_x=0) : M(the_x) {} +}; +struct P : virtual public N, virtual public O +{ + P (int the_x=0) : M(the_x), N(the_x) {} +}; + +DATAVECTOR_VIRTBASES1 (N, M); +DATAVECTOR_VIRTBASES1 (O, M); +DATAVECTOR_VIRTBASES2 (P, N, O); + +SG_BASES2 (N, SG_VIRTUAL(M), MM); +SG_BASE (O, SG_VIRTUAL(M)); +SG_BASES2 (P, SG_VIRTUAL(N), SG_VIRTUAL(O)); + +CLASS_DEF( DataVector<N> , 9884 , 1 ) +CLASS_DEF( DataVector<O> , 9885 , 1 ) +CLASS_DEF( DataVector<M> , 9887 , 1 ) +CLASS_DEF( DataVector<P> , 9888 , 1 ) + + +struct Q : virtual public M +{ + Q (int the_x=0) : M(the_x) {} +}; +struct R : virtual public N, virtual public O, virtual public Q +{ + R (int the_x=0) : M(the_x) {} +}; + +DATAVECTOR_VIRTBASES1 (Q, M); +DATAVECTOR_VIRTBASES3 (R, N, O, Q); + +CLASS_DEF( DataVector<R> , 9883 , 1 ) +CLASS_DEF( DataVector<Q> , 9886 , 1 ) + + + +struct AAux : public SG::AuxElement +{ + AAux (int the_x=0) : x(the_x) { } + //AAux (const AAux& other) : SG::AuxElement(other), x(other.x) {} + virtual ~AAux() { dtor_log.push_back (x); } + int x; + bool operator< (const AAux& other) const { return x < other.x; } + + int& xint() + { static Accessor<int> acc ("xint"); return acc(*this); } + int xint() const + { static Accessor<int> acc ("xint"); return acc(*this); } + bool xintAvailable() const + { static Accessor<int> acc ("xint"); return acc.isAvailable(*this); } + + float& xfloat() + { static Accessor<float> acc ("xfloat"); return acc(*this); } + float xfloat() const + { static Accessor<float> acc ("xfloat"); return acc(*this); } + bool xfloatAvailable() const + { static Accessor<float> acc ("xfloat"); return acc.isAvailable(*this); } + + void setaux() + { + xint() = x+10; + xfloat() = x+11.5; + } + + void checkaux() const + { + assert (xint() == x+10); + assert (xfloat() == x+11.5); + } + + void checkauxZero() const + { + assert (!xintAvailable() || xint() == 0); + assert (!xfloatAvailable() || xfloat() == 0); + } +}; +struct BAux : public AAux +{ + BAux (int the_x=0) : AAux(the_x) {} + //BAux (const BAux& other) : AAux(other) {} + + int& xint2() + { static Accessor<int> acc ("xint2"); return acc(*this); } + int xint2() const + { static Accessor<int> acc ("xint2"); return acc(*this); } + bool xint2Available() const + { static Accessor<int> acc ("xint2"); return acc.isAvailable(*this); } + + + void setaux() + { + AAux::setaux(); + xint2() = x+20; + } + + void checkaux() const + { + AAux::checkaux(); + assert (xint2() == x+20); + } + + void checkauxZero() const + { + AAux::checkauxZero(); + assert (!xint2Available() || xint2() == 0); + } +}; +struct CAux : public AA, public SG::AuxElement +{ + CAux (int the_x=0) : AA(the_x) {} + //CAux (const CAux& other) : AA(other), SG::AuxElement(other) {} + + int& xint() + { static Accessor<int> acc ("xint"); return acc(*this); } + int xint() const + { static Accessor<int> acc ("xint"); return acc(*this); } + bool xintAvailable() const + { static Accessor<int> acc ("xint"); return acc.isAvailable(*this); } + + float& xfloat() + { static Accessor<float> acc ("xfloat"); return acc(*this); } + float xfloat() const + { static Accessor<float> acc ("xfloat"); return acc(*this); } + bool xfloatAvailable() const + { static Accessor<float> acc ("xfloat"); return acc.isAvailable(*this); } + + void setaux() + { + xint() = x+10; + xfloat() = x+11.5; + } + + void checkaux() const + { + assert (xint() == x+10); + assert (xfloat() == x+11.5); + } + + void checkauxZero() const + { + assert (!xintAvailable() || xint() == 0); + assert (!xfloatAvailable() || xfloat() == 0); + } +}; + +DATAVECTOR_BASE(BAux, AAux); +DATAVECTOR_BASE(CAux, AA); +CLASS_DEF( DataVector<AAux>, 9891, 1 ) +CLASS_DEF( DataVector<BAux>, 9892, 1 ) +CLASS_DEF( DataVector<CAux>, 9893, 1 ) + + +//************************************************************************ + + +template <class DV> +void check_indices1 (const DV& v, + const char* file, + int line, + const SG::AuxElement*) +{ + if (!v.trackIndices()) return; + for (size_t i = 0; i < v.size(); i++) { + //if (v[i]) + // printf ("%d %d %p\n", i, v[i]->index(), v[i]->container()); + //else + // printf ("%d null\n", i); + if (v[i] && (v[i]->container() != &v.auxbase() || v[i]->index() != i)) { + throw (dv_test_err (file, line, + std::string ("check_indices ") + + ClassName<DV>::name())); + } + } +} + + +template <class DV> +void check_indices1 (const DV&, + const char*, + int, + const void*) +{ +} + + +template <class DV> +void check_indices (const DV& v, + const char* file, + int line) +{ + check_indices1 (v, file, line, typename DV::value_type()); +} + + +#define CHECK_INDICES(V) do { \ + check_indices(V, __FILE__, __LINE__); \ +} while(false) + + +#define CHECK_INDICES_FAIL(V) do { \ + bool caught = false; \ + try { \ + check_indices(V, __FILE__, __LINE__); \ + } catch (const dv_test_err&) { caught = true; } \ + myassert (caught || !v.trackIndices()); \ +} while(false) + + +template <class T> +void check_index_clear (const SG::AuxElement* p, + const char* file, + int line, + const T*) +{ + if (p->usingPrivateStore()) + return; + + if (p->container() != 0 || p->index() != 0) { + throw (dv_test_err (file, line, + std::string ("check_index_clear ") + + ClassName<T>::name())); + } +} + + +template <class T> +void check_index_clear (const void*, + const char*, + int, + const T*) +{ +} + + +#if __cplusplus > 201100 +template <class T> +void check_index_clear (const std::unique_ptr<T>& p, + const char* file, + int line, + const std::unique_ptr<T>&) +{ + check_index_clear (p.get(), file, line, static_cast<T*>(nullptr)); +} +#endif + + +#define CHECK_INDEX_CLEAR(P) do { \ + check_index_clear (P, __FILE__, __LINE__, P); \ +} while(false) + + +template <class T> +void checkaux1 (const DataVector<T>& v, const SG::AuxElement*) +{ + if (!v.hasNonConstStore()) return; + ATHCONTAINERS_FOREACH (const typename DataVector<T>::base_value_type* p, v) { + if (p) + p->checkaux(); + } +} + + +template <class T> +void checkaux1 (const DataVector<T>&, const void*) +{ +} + + +template <class T> +void checkaux (const DataVector<T>& v) +{ + checkaux1 (v, typename DataVector<T>::value_type()); +} + + +template <class T> +void checkaux (const ConstDataVector<T>&) +{ +} + + +template <class T> +void checkaux1 (T* p, const SG::AuxElement*) +{ + p->checkaux(); +} + +template <class T> +void checkaux1 (T*, const void*) +{ +} + +template <class T> +void checkaux (T* p) +{ + checkaux1 (p, p); +} + + +template <class DV> +void setaux1 (DV& v, SG::IAuxStore& store, const SG::AuxElement*) +{ + if (!v.hasNonConstStore()) + v.setStore (&store); + ATHCONTAINERS_FOREACH (typename DV::value_type p, v) { + if (p) + p->setaux(); + } +} + + +template <class DV> +void setaux1 (DV&, SG::IAuxStore&, const void*) +{ +} + + +template <class T> +void setaux (DataVector<T>& v, SG::IAuxStore& store) +{ + setaux1 (v, store, typename DataVector<T>::value_type()); +} + + +template <class T> +void setaux (ConstDataVector<T>&, SG::IAuxStore&) +{ +} + + +template <class T> +T* make_comp1 (int x, bool setaux, const SG::AuxElement*) +{ + T* t = new T(x); + t->makePrivateStore(); + if (setaux) + t->setaux(); + return t; +} + +template <class T> +T* make_comp1 (int x, bool, const void*) +{ + return new T(x); +} + +template <class T> +T* make_comp (int x, bool setaux=true) +{ + typedef T* ptr; + return make_comp1<T> (x, setaux, ptr()); +} + + +#if __cplusplus > 201100 +template <class T> +std::unique_ptr<T> make_comp_unique (int x, bool setaux=true) +{ + typedef T* ptr; + return std::unique_ptr<T> (make_comp1<T> (x, setaux, ptr())); +} +#endif + + +template <class T> +void releasePrivateStore1 (T* p, const SG::AuxElement*) +{ + p->releasePrivateStore(); +} + +template <class T> +void releasePrivateStore1 (T*, const void*) +{ +} + +template <class T> +void releasePrivateStore (T* p) +{ + releasePrivateStore1 (p, p); +} + + +template <class T> +void checkauxZero1 (T* p, const SG::AuxElement*) +{ + p->checkauxZero(); +} + +template <class T> +void checkauxZero1 (T*, const void*) +{ +} + +template <class T> +void checkauxZero (T* p) +{ + checkauxZero1 (p, p); +} + + + +void checkauxZero (const SG::AuxVectorBase& v, size_t index) +{ + if (!v.hasNonConstStore()) return; + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("xint"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("xfloat"); + assert (v.getData<int> (ityp, index) == 0); + assert (v.getData<float> (ftyp, index) == 0); +} + + +template <class T, class hasaux> +struct test2_maybeconst1 +{ + typedef const T type; +}; + + +template <class T> +struct test2_maybeconst1<T, SG_STD_OR_BOOST::true_type> +{ + typedef T type; +}; + + +// Gives `T' if T has auxdata; otherwise `const T'. +template <class T> +struct test2_maybeconst +{ + typedef typename test2_maybeconst1<T, typename SG::AuxStore_traits<T>::flag>::type type; +}; + + +// Initial tests. +template <class B, class D> +void test2_initial() +{ + DataVector<D> vd; + vd.push_back (new D(1)); + DataVector<B>& vb = vd; + const B* b = vb[0]; + const D* d = vd[0]; + myassert (b->x == 1); + myassert (d->x == 1); + + DataVector<D> d2 (10); + myassert (d2.size() == 10); + DataVector<D> d3 (d2); + myassert (d3.size() == 10); + CHECK_INDICES(vd); + CHECK_INDICES(d2); + CHECK_INDICES(d3); +} + + +// Test default ctor +template <class DV> +void test2_default_ctor1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1; + v1.push_back (new T(1)); + myassert (v1.ownPolicy() == SG::OWN_ELEMENTS); + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(2)); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + } + check_dtor_log (1); +} +template <class DV> +void test2_default_ctor2() +{ + test2_default_ctor1<DV>(); + + typedef typename DV::base_value_type T; + bool auxdata = typename SG::AuxStore_traits<T>::flag(); + clear_dtor_log(); + { + DV v1; + v1.push_back (new T(1)); + myassert (v1.ownPolicy() == SG::OWN_ELEMENTS); + myassert (!auxdata || v1.trackIndices()); + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(2)); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (!auxdata || !v2.trackIndices()); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + myassert (v3.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (!auxdata || v3.trackIndices()); + + DV v4 (SG::OWN_ELEMENTS, SG::NEVER_TRACK_INDICES); + myassert (v4.ownPolicy() == SG::OWN_ELEMENTS); + myassert (!auxdata || !v4.trackIndices()); + } + check_dtor_log (1); +} +template <class B, class D> +void test2_default_ctor() +{ + test2_default_ctor2<DataVector<B> > (); + test2_default_ctor2<DataVector<D> > (); + test2_default_ctor1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_default_ctor1<ConstDataVector<DataVector<D> > > (); +} + + +// Test sized ctor +template <class DV> +void test2_sized_ctor1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1 (10); + myassert (v1.size() == 10); + myassert (v1[0] == 0); + v1.push_back (new T(1)); + CHECK_INDICES (v1); + DV v2 (10, SG::VIEW_ELEMENTS); + myassert (v2.size() == 10); + myassert (v2[0] == 0); + v2.push_back (new T(2)); + CHECK_INDICES (v2); + } + check_dtor_log (1); +} +template <class DV> +void test2_sized_ctor2() +{ + test2_sized_ctor1<DV>(); + + typedef typename DV::base_value_type T; + bool auxdata = typename SG::AuxStore_traits<T>::flag(); + clear_dtor_log(); + { + DV v1 (10, SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store1; + setaux (v1, store1); + myassert (v1.size() == 10); + myassert (v1.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (!auxdata || v1.trackIndices()); + v1[0] = make_comp<T> (10, false); + releasePrivateStore(&*v1[0]); + checkauxZero (&*v1[0]); + delete v1[0]; + } +} +template <class B, class D> +void test2_sized_ctor() +{ + test2_sized_ctor2<DataVector<B> > (); + test2_sized_ctor2<DataVector<D> > (); + test2_sized_ctor1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_sized_ctor1<ConstDataVector<DataVector<D> > > (); +} + + +// Test insertion ctor +template <class DV> +void test2_insertion_ctor1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + std::vector<typename DV::value_type> tt; + tt.push_back (new T(1)); + tt.push_back (new T(2)); + DV v1 (tt.begin(), tt.end()); + DV v2 (tt.begin(), tt.end(), SG::OWN_ELEMENTS); + myassert (v1.size() == 2); + myassert (v2.size() == 2); + myassert (v1[0] == tt[0]); + myassert (v1[1] == tt[1]); + myassert (v2[0] == tt[0]); + myassert (v2[1] == tt[1]); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + } + check_dtor_log (1, 2); + +#if __cplusplus > 201100 + { + std::vector<typename DV::value_type> tt; + tt.push_back (new T(1)); + tt.push_back (new T(2)); + DV v1 ({tt[0], tt[1]}); + DV v2 ({tt[0], tt[1]}, SG::OWN_ELEMENTS); + myassert (v1.size() == 2); + myassert (v2.size() == 2); + myassert (v1[0] == tt[0]); + myassert (v1[1] == tt[1]); + myassert (v2[0] == tt[0]); + myassert (v2[1] == tt[1]); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + } + check_dtor_log (1, 2); +#endif +} +template <class DV> +void test2_insertion_ctor2() +{ + test2_insertion_ctor1<DV>(); + + typedef typename DV::base_value_type T; + const bool auxdata = typename SG::AuxStore_traits<T>::flag(); + clear_dtor_log(); + { + std::vector<typename DV::value_type> tt; + tt.push_back (make_comp<T>(1)); + tt.push_back (make_comp<T>(2)); + + SG::AuxStoreInternal store; + DV v1 (tt.begin(), tt.end(), SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES, + auxdata ? &store : 0); + myassert (v1.size() == 2); + myassert (v1.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (!auxdata || v1.trackIndices()); + checkaux (v1); + delete tt[0]; + delete tt[1]; + } +} +template <class B, class D> +void test2_insertion_ctor() +{ + test2_insertion_ctor2<DataVector<B> > (); + test2_insertion_ctor2<DataVector<D> > (); + test2_insertion_ctor1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_insertion_ctor1<ConstDataVector<DataVector<D> > > (); + { + // We can put D pointers into a B container. + std::vector<D*> dd; + dd.push_back (new D(1)); + dd.push_back (new D(2)); + DataVector<B> v1 (dd.begin(), dd.end()); + myassert (v1.size() == 2); + myassert (v1[0] == dd[0]); + myassert (v1[1] == dd[1]); + } +#ifdef COMPILE_ERROR + { + // But not the other way 'round. + std::vector<B*> dd; + dd.push_back (new B(1)); + dd.push_back (new B(2)); + DataVector<D> v1 (dd.begin(), dd.end()); + myassert (v1.size() == 2); + myassert (v1[0] == dd[0]); + myassert (v1[1] == dd[1]); + } +#endif +} + + +// Test copy ctor +template <class DV> +void test2_copy_ctor1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DV v2 (v1); + myassert (v2.size() == 2); + myassert (v2[0] == v1[0]); + myassert (v2[1] == v1[1]); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + } + check_dtor_log (1, 2); +} +template <class DV> +void test2_copy_ctor2() +{ + typedef typename DV::base_value_type T; + test2_copy_ctor1<DV>(); + + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + setaux(v1, store1); + checkaux(v1); + + DV v2 (v1); + checkaux(v2); + assert (!v2.hasStore()); +} +template <class B, class D> +void test2_copy_ctor() +{ + test2_copy_ctor2<DataVector<B> >(); + test2_copy_ctor2<DataVector<D> >(); + test2_copy_ctor1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_copy_ctor1<ConstDataVector<DataVector<D> > >(); + { + // Can copy derived vector to base vector. + DataVector<D> v1; + v1.push_back (new D(1)); + v1.push_back (new D(2)); + DataVector<B> v2 (v1); + myassert (v2.size() == 2); + myassert (v2[0] == v1[0]); + myassert (v2[1] == v1[1]); + DataVector<B> v3 = v2; + myassert (v3.size() == 2); + myassert (v3[0] == v1[0]); + myassert (v3[1] == v1[1]); + } + check_dtor_log (1, 2); +#ifdef COMPILE_ERROR + { + // But not the other way 'round. + DataVector<B> v1; + v1.push_back (new B(1)); + v1.push_back (new B(2)); + DataVector<D> v2 (v1); + myassert (v2.size() == 2); + myassert (v2[0] == v1[0]); + myassert (v2[1] == v1[1]); + } + check_dtor_log (1, 2); +#endif +} + + + +// Test destructor. +template <class DV> +void test2_dtor1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + } + check_dtor_log (1, 2); + { + DV v1 (SG::VIEW_ELEMENTS); + v1.push_back (new T(1)); + v1.push_back (new T(2)); + } + check_dtor_log (); +#ifdef DO_REMOVE_DUPLICATES + { + DV v1; + T* t = new T(1); + v1.push_back (t); + v1.push_back (t); + } + check_dtor_log (1); +#endif +} +template <class B, class D> +void test2_dtor() +{ + test2_dtor1<DataVector<B> > (); + test2_dtor1<DataVector<D> > (); + test2_dtor1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_dtor1<ConstDataVector<DataVector<D> > > (); +} + + +// Test push_back +template <class B, class D> +void test2_push_back() +{ + DataVector<B> vb; + SG::AuxStoreInternal storeb; + setaux (vb, storeb); + vb.push_back (make_comp<B>(1)); + vb.push_back (make_comp<D>(2)); + vb.emplace_back (make_comp<D>(12)); + myassert (vb.size() == 3); + myassert (vb[0]->x == 1); + myassert (vb[1]->x == 2); + myassert (vb[2]->x == 12); + CHECK_INDICES(vb); + checkaux(vb); + DataVector<B> vb2 (SG::VIEW_ELEMENTS); + vb2.push_back (vb[1]); + CHECK_INDICES(vb); + DataVector<B> vb3; + vb3.push_back (new B(3)); + vb3.emplace_back (new B(4)); + CHECK_INDICES(vb3); + + DataVector<D> vd; + SG::AuxStoreInternal stored; + setaux (vd, stored); + vd.push_back (make_comp<D>(3)); + vd.push_back (make_comp<D>(4)); + releasePrivateStore (&*vd[0]); + myassert (vd.size() == 2); + myassert (vd[0]->x == 3); + CHECK_INDICES(vd); + checkaux(vd); + DataVector<D> vd2 (SG::VIEW_ELEMENTS); + vd2.push_back (vd[1]); + CHECK_INDICES(vd); + DataVector<D> vd3; + vd3.push_back (new D(3)); + vd3.push_back (new D(4)); + CHECK_INDICES(vb3); + + ConstDataVector<DataVector<D> > cvd; + cvd.push_back (new D(3)); + myassert (cvd.size() == 1); + myassert (cvd[0]->x == 3); + CHECK_INDICES(cvd); + + typedef typename test2_maybeconst<D>::type Dconst; + DataVector<Dconst> vcd; + vcd.push_back (new D(3)); + myassert (vcd.size() == 1); + myassert (vcd[0]->x == 3); + CHECK_INDICES(vcd); + + // This isn't allowed. + DataVector<B>& vd4 = vd; + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, vd4.push_back (new B(4))); + + bool auxdata_b = typename SG::AuxStore_traits<B>::flag(); + bool auxdata_d = typename SG::AuxStore_traits<D>::flag(); + + vd.setStore (vd.getConstStore()); + bool caught = false; + try { + vd.push_back (new D(10)); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + assert (caught || !auxdata_d); + + vb.setStore (vb.getConstStore()); + caught = false; + try { + vb.push_back (new B(10)); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + assert (caught || !auxdata_b); + +#if __cplusplus > 201100 + { + clear_dtor_log(); + DataVector<B> vb_u; + SG::AuxStoreInternal storeb_u; + setaux (vb_u, storeb_u); + vb_u.push_back (make_comp_unique<B>(20)); + vb_u.push_back (make_comp_unique<D>(21)); + CHECK_INDICES(vb_u); + checkaux(vb_u); + check_dtor_log(); + + DataVector<B> vb2_u (SG::VIEW_ELEMENTS); + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vb2_u.push_back (CxxUtils::make_unique<B>(22))); + } + check_dtor_log(22, 20, 21); + + { + clear_dtor_log(); + DataVector<D> vd_u; + SG::AuxStoreInternal stored_u; + setaux (vd_u, stored_u); + vd_u.push_back (make_comp_unique<D>(23)); + vd_u.push_back (make_comp_unique<D>(24)); + CHECK_INDICES(vd_u); + checkaux(vd_u); + check_dtor_log(); + + DataVector<B>& vd4_u = vd_u; + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, + vd4_u.push_back (CxxUtils::make_unique<D>(26))); + + DataVector<B> vd2_u (SG::VIEW_ELEMENTS); + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vd2_u.push_back (CxxUtils::make_unique<D>(25))); + } + check_dtor_log(26, 25, 23, 24); +#endif +} + + +// Test operator[] const +template <class B, class D> +void test2_operator_index_const() +{ + { + DataVector<B> vb; + vb.push_back (new B(1)); + vb.push_back (new D(2)); + const DataVector<B>& cvb = vb; + myassert (cvb[0]->x == 1); + myassert (cvb[1]->x == 2); + myassert (cvb.get(1)->x == 2); + } + + { + DataVector<D> vd; + vd.push_back (new D(3)); + const DataVector<D>& cvd = vd; + const D* dd = cvd[0]; + myassert (dd->x == 3); + } + + { + ConstDataVector<DataVector<D> > vd; + vd.push_back (new D(3)); + const ConstDataVector<DataVector<D> >& cvd = vd; + const D* dd = cvd[0]; + myassert (dd->x == 3); + } + + { + typedef typename test2_maybeconst<D>::type Dconst; + DataVector<Dconst> vcd; + vcd.push_back (new D(3)); + const DataVector<Dconst>& cvcd = vcd; + const D* dd = cvcd[0]; + myassert (dd->x == 3); + } +} + + +// Test at const +template <class DV, class B, class D> +void test2_at_const1() +{ + DV vb; + vb.push_back (new B(1)); + vb.push_back (new D(2)); + const DV& cvb = vb; + myassert (cvb.at(0)->x == 1); + myassert (cvb.at(1)->x == 2); + CHECK_INDICES(vb); + + bool caught = false; + try { + vb.at(10); + } + catch (std::out_of_range&) { + caught = true; + } + myassert (caught); +} +template <class B, class D> +void test2_at_const() +{ + test2_at_const1<DataVector<B>, B, D>(); + test2_at_const1<DataVector<D>, D, D>(); + typedef typename test2_maybeconst<D>::type Dconst; + test2_at_const1<DataVector<Dconst>, Dconst, Dconst>(); + test2_at_const1<ConstDataVector<DataVector<D> >, D, D>(); +} + + +// Test size +template <class DV, class B, class D> +void test2_size1() +{ + DV vb; + myassert (vb.size() == 0); + vb.push_back (new B(1)); + vb.push_back (new D(2)); + myassert (vb.size() == 2); +} +template <class B, class D> +void test2_size() +{ + test2_size1<DataVector<B>, B, D>(); + test2_size1<ConstDataVector<DataVector<B> >, B, D>(); + + typedef typename test2_maybeconst<D>::type Dconst; + test2_size1<DataVector<Dconst>, Dconst, Dconst>(); +} + + +// Test stdcont +template <class B, class D> +void test2_stdcont() +{ + DataVector<B> vb; + vb.push_back (new B(1)); + vb.push_back (new D(2)); + const typename DataVector<B>::PtrVector& vv = vb.stdcont(); + myassert (vv.size() == 2); + myassert (vv[0]->x == 1); +} + + +// Test empty +template <class DV> +void test2_empty1() +{ + typedef typename DV::base_value_type T; + DV vb; + myassert (vb.empty()); + vb.push_back (new T(1)); + myassert (!vb.empty()); +} +template <class B, class D> +void test2_empty() +{ + test2_empty1<DataVector<B> >(); + test2_empty1<DataVector<typename test2_maybeconst<B>::type> > (); + test2_empty1<ConstDataVector<DataVector<B> > >(); +} + + +// Test reserve and capacity +template <class DV> +void test2_reserve_capacity1() +{ + DV vb; + myassert (vb.capacity() == 0); + vb.reserve (10); + myassert (vb.capacity() == 10); + +#if __cplusplus > 201100 + vb.resize (5); + vb.shrink_to_fit(); + myassert (vb.capacity() == 5); +#endif +} +template <class B, class D> +void test2_reserve_capacity() +{ + test2_reserve_capacity1<DataVector<B> >(); + test2_reserve_capacity1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_reserve_capacity1<ConstDataVector<DataVector<B> > >(); +} + + +// Test max_size +template <class B, class D> +void test2_max_size() +{ + DataVector<B> vb; + myassert (vb.max_size() == std::vector<void*>().max_size()); + ConstDataVector<DataVector<B> > cvb; + myassert (cvb.max_size() == std::vector<void*>().max_size()); + + typedef typename test2_maybeconst<B>::type Bconst; + DataVector<Bconst> vcb; + myassert (vcb.max_size() == std::vector<void*>().max_size()); +} + + +// Test front const, back const +template <class DV, class B, class D> +void test2_front_back_const1() +{ + DV vd; + vd.push_back (new B(1)); + vd.push_back (new D(2)); + const DV& cvd = vd; + const B* dd = cvd.front(); + myassert (dd->x == 1); + dd = cvd.back(); + myassert (dd->x == 2); +} +template <class B, class D> +void test2_front_back_const() +{ + test2_front_back_const1<DataVector<B>, B, D>(); + test2_front_back_const1<DataVector<D>, D, D>(); + typedef typename test2_maybeconst<D>::type Dconst; + test2_front_back_const1<DataVector<Dconst>, Dconst, Dconst>(); + test2_front_back_const1<ConstDataVector<DataVector<D> >, D, D>(); +} + + +// Test begin const, end const +template <class DV> +void test2_begin_end_const1() +{ + typedef typename DV::base_value_type T; + DV v; + v.push_back (new T(1)); + v.push_back (new T(2)); + const DV& cv = v; + myassert (cv.end() - cv.begin() == 2); + myassert (cv.cend() - cv.cbegin() == 2); + typename DV::const_iterator i = cv.begin(); + myassert (i != cv.end()); + const T* tt = *i; + myassert (tt->x == 1); + ++i; + myassert (i != cv.end()); + myassert (i != cv.cend()); + myassert ((*i)->x == 2); + i++; + myassert (i == cv.end()); + i--; + myassert ((*i)->x == 2); + --i; + myassert ((*i)->x == 1); + myassert (i == cv.begin()); + myassert (i == cv.cbegin()); +} +template <class B, class D> +void test2_begin_end_const() +{ + test2_begin_end_const1<DataVector<B> > (); + test2_begin_end_const1<DataVector<D> > (); + test2_begin_end_const1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_begin_end_const1<ConstDataVector<DataVector<D> > > (); +} + + +// Test rbegin const, rend const +template <class DV> +void test2_rbegin_rend_const1() +{ + typedef typename DV::base_value_type T; + DV v; + v.push_back (new T(1)); + v.push_back (new T(2)); + const DV& cv = v; + myassert (cv.rend() - cv.rbegin() == 2); + myassert (cv.crend() - cv.crbegin() == 2); + typename DV::const_reverse_iterator i = cv.rbegin(); + myassert (i != cv.rend()); + myassert (i != cv.crend()); + const T* tt = *i; + myassert (tt->x == 2); + ++i; + myassert (i != cv.rend()); + myassert (i != cv.crend()); + myassert ((*i)->x == 1); + i++; + myassert (i == cv.rend()); + myassert (i == cv.crend()); + i--; + myassert ((*i)->x == 1); + --i; + myassert ((*i)->x == 2); + myassert (i == cv.rbegin()); + myassert (i == cv.crbegin()); +} +template <class B, class D> +void test2_rbegin_rend_const() +{ + test2_rbegin_rend_const1<DataVector<B> > (); + test2_rbegin_rend_const1<DataVector<D> > (); + test2_rbegin_rend_const1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_rbegin_rend_const1<ConstDataVector<DataVector<D> > > (); +} + + +// Test ElementProxy operations. +template <class B, class D> +void test2_elementproxy() +{ + clear_dtor_log(); + + { + DataVector<B> vb1; + SG::AuxStoreInternal store_b; + vb1.push_back (new B(1)); + vb1.push_back (new D(2)); + setaux (vb1, store_b); + + DataVector<B> vb2 (SG::VIEW_ELEMENTS); + vb2.push_back (new B(3)); + vb2.push_back (new D(4)); + + DataVector<D> vd1; + SG::AuxStoreInternal store_d; + vd1.push_back (new D(5)); + vd1.push_back (new D(6)); + setaux (vd1, store_d); + + DataVector<D> vd2 (SG::VIEW_ELEMENTS); + vd2.push_back (new D(7)); + vd2.push_back (new D(8)); + + CHECK_INDICES (vb1); + CHECK_INDICES (vd1); + CHECK_INDICES (vb2); + CHECK_INDICES (vd2); + checkaux(vb1); + checkaux(vd1); + + myassert (vb1[0]->x == 1); + myassert ((*vb1[1]).x == 2); + + D* dd = vd1[0]; + myassert (dd->x == 5); + myassert (vd1[1]->x == 6); + + // vb1: (1,2) vb2: (3,4) vd1: (5,6) vd2: (7,8) + // Test ownership transfer. + // VIEW->VIEW doesn't delete anything. + vb2[0] = vb2[1]; + vd2[0] = vd2[1]; + check_dtor_log(); + + CHECK_INDICES (vb2); + CHECK_INDICES (vd2); + + // vb1: (1,2) vb2: (4,4) vd1: (5,6) vd2: (8,8) + // OWN->VIEW doesn't delete anything. + vb2[0] = vb1[0]; + vd2[0] = vd1[0]; + check_dtor_log(); + + CHECK_INDICES (vb2); + CHECK_INDICES (vd2); + checkaux (&*vb2[0]); + checkaux (&*vd2[0]); + + // vb1: (1,2) vb2: (1,4) vd1: (5,6) vd2: (5,8) + // VIEW->OWN deletes old val, takes ownership. + vb1[1] = vb2[1]; + vd1[1] = vd2[1]; + check_dtor_log (2, 6); + + CHECK_INDICES (vb1); + CHECK_INDICES (vd1); + checkauxZero (&*vb1[1]); + checkauxZero (&*vd1[1]); + + // vb1: (1,4) vb2: (1,4) vd1: (5,8) vd2: (5,8) + // OWN->OWN not allowed. + bool caught = false; + try { + vb1[0] = vb1[1]; + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + vd1[0] = vd1[1]; + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + + CHECK_INDICES (vb1); + CHECK_INDICES (vd1); + + // Unless it's the same element. + vb1[0] = vb1[0]; + B* bb = vb1[0]; + vb1[0] = bb; + + CHECK_INDICES (vb1); + CHECK_INDICES (vd1); + checkaux (&*vb1[0]); + checkaux (&*vd1[0]); + + // Check that we can't manage to put a B into a D container + // using ElementProxy. + DataVector<B>& vd2_b = vd2; + caught = false; + try { + vd2_b[0] = vb2[0]; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + // On the other hand, we can put a D in a B container. + vb2[0] = vd2_b[0]; + + // vb1: (1,4) vb2: (5,4) vd1: (5,8) vd2: (5,8) + + // Test assignment from explicit pointers. + vb1[0] = new B(9); + check_dtor_log (1); + vb2[0] = new B(10); + check_dtor_log (); + // vb1: (9,4) vb2: (10,4) vd1: (5,8) vd2: (5,8) + vd2[0] = new D(11); + check_dtor_log (); + D* dd2 = make_comp<D>(12); + vd1[0] = dd2; + releasePrivateStore (dd2); + check_dtor_log (5); + // vb1: (9,4) vb2: (10,4) vd1: (12,8) vd2: (11,8) + + CHECK_INDICES (vb1); + CHECK_INDICES (vd1); + CHECK_INDICES (vb2); + CHECK_INDICES (vd2); + checkauxZero (&*vb1[0]); + checkaux (&*vd1[0]); + +#if __cplusplus > 201100 + // Test assignment from unique_ptr. + vb1[0] = CxxUtils::make_unique<B>(21); + check_dtor_log (9); + vb1[0] = CxxUtils::make_unique<B>(9); + check_dtor_log (21); + + vd1[0] = CxxUtils::make_unique<D>(22); + check_dtor_log (12); + vd1[0] = CxxUtils::make_unique<D>(12); + check_dtor_log (22); + + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vb2[0] = CxxUtils::make_unique<B>(50)); + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vd2[0] = CxxUtils::make_unique<D>(51)); + check_dtor_log(50, 51); +#endif + + DataVector<D> vd3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + D* d1 = make_comp<D>(11); + D* d2 = make_comp<D>(12); + vd3.push_back (d1); + vd3.push_back (d2); + releasePrivateStore (d1); + releasePrivateStore (d2); + CHECK_INDICES (vd3); + checkaux(vd3); + vd3[0] = 0; + CHECK_INDICES (vd3); + CHECK_INDEX_CLEAR (d1); + checkaux(vd3); + } + check_dtor_log (12, 8, 9, 4); + + { + bool auxdata_b = typename SG::AuxStore_traits<B>::flag(); + bool auxdata_d = typename SG::AuxStore_traits<D>::flag(); + + DataVector<B> vb1; + SG::AuxStoreInternal store_b; + vb1.push_back (new B(1)); + setaux (vb1, store_b); + vb1.setStore (vb1.getConstStore()); + bool caught = false; + try { + vb1[0] = new B(2); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !auxdata_b); + caught = false; + try { + vb1[0] = 0; + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !auxdata_b); + + DataVector<D> vd1; + SG::AuxStoreInternal store_d; + vd1.push_back (new D(1)); + setaux (vd1, store_d); + vd1.setStore (vd1.getConstStore()); + caught = false; + try { + vd1[0] = new D(2); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !auxdata_d); + caught = false; + try { + vd1[0] = 0; + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !auxdata_d); + } + + { + DataVector<B> vb1; + vb1.push_back (new B(1)); + vb1.push_back (new B(2)); + CHECK_INDICES (vb1); + DataVector<B> vb2 (SG::VIEW_ELEMENTS); + vb2.resize(2); + vb2[0] = vb1[1]; + vb2[1] = vb1[0]; + CHECK_INDICES (vb1); + + DataVector<D> vd1; + vd1.push_back (new D(1)); + vd1.push_back (new D(2)); + CHECK_INDICES (vd1); + DataVector<D> vd2 (SG::VIEW_ELEMENTS); + vd2.resize(2); + vd2[0] = vd1[1]; + vd2[1] = vd1[0]; + CHECK_INDICES (vd1); + } +} + + +// Test operator[] +template <class DV> +void test2_operator_index1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v (2); + v[0] = new T(1); + v[1] = new T(2); + myassert (v[0]->x == 1); + myassert (v[1]->x == 2); + CHECK_INDICES(v); + v[0] = new T(3); + myassert (v[0]->x == 3); + check_dtor_log (1); + CHECK_INDICES(v); +} +template <class DV> +void test2_operator_index2() +{ + typedef typename DV::base_value_type T; + test2_operator_index1<DV>(); + + DV v2 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store2; + v2.resize(2); + T* t1 = new T(1); + T* t2 = new T(2); + v2[0] = t1; + v2[1] = t2; + setaux (v2, store2); + CHECK_INDICES(v2); + checkaux (v2); + v2[1] = 0; + CHECK_INDICES(v2); + CHECK_INDEX_CLEAR(t2); + v2.clear(); + delete t1; + delete t2; + + v2.resize(2); + t1 = make_comp<T>(3); + t2 = make_comp<T>(4); + v2[0] = t1; + v2[1] = t2; + CHECK_INDICES(v2); + checkaux(v2); + + DV v3 (SG::VIEW_ELEMENTS); + v3.resize(1); + v3[0] = v2[1]; + CHECK_INDICES(v2); + checkaux(v2); + + v2.setStore (v2.getConstStore()); + bool caught = false; + T* t3 = make_comp<T>(5); + try { + v2[0] = t3; + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + caught = false; + try { + v2[0] = 0; + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; + delete t3; +} +template <class B, class D> +void test2_operator_index() +{ + test2_operator_index2<DataVector<B> > (); + test2_operator_index2<DataVector<D> > (); + test2_operator_index1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_operator_index1<ConstDataVector<DataVector<D> > > (); +} + + +// Test at +template <class DV> +void test2_at1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v (2); + v.at(0) = new T(1); + v.at(1) = new T(2); + myassert (v.at(0)->x == 1); + myassert (v.at(1)->x == 2); + CHECK_INDICES(v); + v.at(0) = new T(3); + myassert (v.at(0)->x == 3); + check_dtor_log (1); + CHECK_INDICES(v); + + bool caught = false; + try { + v.at(10); + } + catch (std::out_of_range&) { + caught = true; + } + myassert (caught); + CHECK_INDICES(v); +} +template <class DV> +void test2_at2() +{ + typedef typename DV::base_value_type T; + test2_at1<DV>(); + + DV v2 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store2; + v2.resize(2); + T* t1 = new T(1); + T* t2 = new T(2); + v2.at(0) = t1; + v2.at(1) = t2; + setaux (v2, store2); + CHECK_INDICES(v2); + checkaux (v2); + v2.at(1) = 0; + CHECK_INDICES(v2); + CHECK_INDEX_CLEAR(t2); + v2.clear(); + delete t1; + delete t2; + + v2.resize(2); + t1 = make_comp<T>(3); + t2 = make_comp<T>(4); + v2.at(0) = t1; + v2.at(1) = t2; + releasePrivateStore(t1); + releasePrivateStore(t2); + CHECK_INDICES(v2); + checkaux(v2); + + DV v3 (SG::VIEW_ELEMENTS); + v3.resize(1); + v3.at(0) = v2.at(1); + CHECK_INDICES(v2); + checkaux(v2); + + v2.setStore (v2.getConstStore()); + bool caught = false; + T* t3 = make_comp<T>(5); + try { + v2.at(0) = t3; + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + caught = false; + try { + v2.at(0) = 0; + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; + delete t3; +} +template <class B, class D> +void test2_at() +{ + test2_at2<DataVector<B> > (); + test2_at2<DataVector<D> > (); + test2_at1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_at1<ConstDataVector<DataVector<D> > > (); +} + + +// Test swapElement +template <class B, class D> +void test2_swapelement() +{ + clear_dtor_log(); + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (new B(1)); + vb.push_back (new B(2)); + setaux (vb, store_b); + + B* bold; + B* bnew = make_comp<B>(3); + vb.swapElement (1, bnew, bold); + myassert (vb[1]->x == 3); + myassert (bold->x == 2); + CHECK_INDEX_CLEAR (bold); + delete bold; + check_dtor_log (2); + CHECK_INDICES(vb); + checkaux(vb); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (new D(4)); + vd.push_back (new D(5)); + setaux (vd, store_d); + + D* dold; + D* dnew = make_comp<D>(6); + vd.swapElement (1, dnew, dold); + releasePrivateStore(dnew); + myassert (vd[1]->x == 6); + myassert (dold->x == 5); + CHECK_INDEX_CLEAR (dold); + delete dold; + check_dtor_log (5); + CHECK_INDICES(vd); + checkaux(vd); + + DataVector<B>& vd_b = vd; + bool caught = false; + try { + vd_b.swapElement (1, new B(10), bold); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + ConstDataVector<DataVector<D> > cvd; + cvd.push_back (new D(7)); + cvd.push_back (new D(8)); + + const D* cdold; + cvd.swapElement (1, new D(9), cdold); + myassert (cvd[1]->x == 9); + myassert (cdold->x == 8); + delete cdold; + check_dtor_log (8); + CHECK_INDICES(cvd); + + { + typedef typename test2_maybeconst<D>::type Dconst; + ConstDataVector<DataVector<Dconst> > vcd; + vcd.push_back (new D(7)); + vcd.push_back (new D(8)); + + vcd.swapElement (1, new D(9), cdold); + myassert (vcd[1]->x == 9); + myassert (cdold->x == 8); + delete cdold; + check_dtor_log (8); + CHECK_INDICES(vcd); + } + check_dtor_log (7, 9); + + } + + check_dtor_log (4, 6, 1, 3, 7, 9); + + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (new B(1)); + setaux (vb, store_b); + vb.setStore (vb.getConstStore()); + B* bold; + B* bnew = make_comp<B>(3); + bool caught = false; + try { + vb.swapElement (0, bnew, bold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<B>::flag()); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (new D(1)); + setaux (vd, store_d); + vd.setStore (vd.getConstStore()); + D* dold; + D* dnew = make_comp<D>(3); + caught = false; + try { + vd.swapElement (0, dnew, dold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<D>::flag()); + } + + { + DataVector<B> vb1; + vb1.push_back (new B(1)); + vb1.push_back (new B(2)); + CHECK_INDICES(vb1); + B* bold; + B* bnew = new B(3); + vb1.swapElement (0, bnew, bold); + CHECK_INDICES(vb1); + DataVector<B> vb2 = vb1; + bnew = new B(4); + vb2.swapElement (0, bnew, bold); + CHECK_INDICES(vb1); + + DataVector<D> vd1; + vd1.push_back (new D(1)); + vd1.push_back (new D(2)); + CHECK_INDICES(vd1); + D* dold; + D* dnew = new D(3); + vd1.swapElement (0, dnew, dold); + CHECK_INDICES(vd1); + DataVector<D> vd2 = vd1; + dnew = new D(4); + vd2.swapElement (0, dnew, dold); + CHECK_INDICES(vd1); + } +} + + +// Test swapElement with unique_ptr +template <class B, class D> +void test2_swapelement_unique() +{ +#if __cplusplus > 201100 + clear_dtor_log(); + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (CxxUtils::make_unique<B>(1)); + vb.push_back (CxxUtils::make_unique<B>(2)); + setaux (vb, store_b); + + { + std::unique_ptr<B> bold; + vb.swapElement (1, make_comp_unique<B>(3), bold); + myassert (vb[1]->x == 3); + myassert (bold->x == 2); + CHECK_INDEX_CLEAR (bold); + } + check_dtor_log (2); + CHECK_INDICES(vb); + checkaux(vb); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (CxxUtils::make_unique<D>(4)); + vd.push_back (CxxUtils::make_unique<D>(5)); + setaux (vd, store_d); + + { + std::unique_ptr<D> dold; + vd.swapElement (1, make_comp_unique<D>(6), dold); + releasePrivateStore(static_cast<D*>(vd[1])); + myassert (vd[1]->x == 6); + myassert (dold->x == 5); + CHECK_INDEX_CLEAR (dold); + } + check_dtor_log (5); + CHECK_INDICES(vd); + checkaux(vd); + + DataVector<B>& vd_b = vd; + { + std::unique_ptr<B> bold; + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, + vd_b.swapElement (1, CxxUtils::make_unique<B>(10), bold)); + } + + clear_dtor_log(); + ConstDataVector<DataVector<D> > cvd; + cvd.push_back (CxxUtils::make_unique<D>(7)); + cvd.push_back (CxxUtils::make_unique<D>(8)); + + { + std::unique_ptr<const D> cdold; + cvd.swapElement (1, CxxUtils::make_unique<const D>(9), cdold); + myassert (cvd[1]->x == 9); + myassert (cdold->x == 8); + } + + check_dtor_log (8); + CHECK_INDICES(cvd); + + { + typedef typename test2_maybeconst<D>::type Dconst; + ConstDataVector<DataVector<Dconst> > vcd; + vcd.push_back (CxxUtils::make_unique<D>(7)); + vcd.push_back (CxxUtils::make_unique<D>(8)); + + { + std::unique_ptr<const D> cdold; + vcd.swapElement (1, CxxUtils::make_unique<const D>(9), cdold); + myassert (vcd[1]->x == 9); + myassert (cdold->x == 8); + } + check_dtor_log (8); + CHECK_INDICES(vcd); + } + check_dtor_log (7, 9); + + } + + check_dtor_log (4, 6, 1, 3, 7, 9); + + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (CxxUtils::make_unique<B>(1)); + setaux (vb, store_b); + vb.setStore (vb.getConstStore()); + std::unique_ptr<B> bold; + bool caught = false; + try { + vb.swapElement (0, make_comp_unique<B>(3), bold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<B>::flag()); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (CxxUtils::make_unique<D>(1)); + setaux (vd, store_d); + vd.setStore (vd.getConstStore()); + std::unique_ptr<D> dold; + caught = false; + try { + vd.swapElement (0, make_comp_unique<D>(3), dold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<D>::flag()); + } + + { + DataVector<B> vb1; + vb1.push_back (CxxUtils::make_unique<B>(1)); + vb1.push_back (CxxUtils::make_unique<B>(2)); + CHECK_INDICES(vb1); + std::unique_ptr<B> bold; + vb1.swapElement (0, CxxUtils::make_unique<B>(3), bold); + CHECK_INDICES(vb1); + DataVector<B> vb2 = vb1; + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vb2.swapElement (0, CxxUtils::make_unique<B>(4), bold)); + + DataVector<D> vd1; + vd1.push_back (CxxUtils::make_unique<D>(1)); + vd1.push_back (CxxUtils::make_unique<D>(2)); + CHECK_INDICES(vd1); + std::unique_ptr<D> dold; + vd1.swapElement (0, CxxUtils::make_unique<D>(3), dold); + CHECK_INDICES(vd1); + DataVector<D> vd2 = vd1; + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vd2.swapElement (0, CxxUtils::make_unique<D>(4), dold)); + } +#endif +} + + +// Test swapElement with iterator +template <class B, class D> +void test2_swapelement_iter() +{ + clear_dtor_log(); + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (new B(1)); + vb.push_back (new B(2)); + setaux (vb, store_b); + + B* bold; + B* bnew = make_comp<B>(3); + vb.swapElement (vb.begin()+1, bnew, bold); + releasePrivateStore(bnew); + myassert (vb[1]->x == 3); + myassert (bold->x == 2); + CHECK_INDEX_CLEAR (bold); + delete bold; + check_dtor_log (2); + CHECK_INDICES(vb); + checkaux(vb); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (new D(4)); + vd.push_back (new D(5)); + setaux (vd, store_d); + + D* dold; + D* dnew = make_comp<D>(6); + vd.swapElement (vd.begin()+1, dnew, dold); + releasePrivateStore(dnew); + myassert (vd[1]->x == 6); + myassert (dold->x == 5); + CHECK_INDEX_CLEAR (dold); + delete dold; + check_dtor_log (5); + CHECK_INDICES(vd); + checkaux(vd); + + DataVector<B>& vd_b = vd; + bool caught = false; + try { + vd_b.swapElement (vd_b.begin()+1, new B(10), bold); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + ConstDataVector<DataVector<D> > cvd; + cvd.push_back (new D(7)); + cvd.push_back (new D(8)); + + const D* cdold; + cvd.swapElement (cvd.begin()+1, new D(9), cdold); + myassert (cvd[1]->x == 9); + myassert (cdold->x == 8); + delete cdold; + check_dtor_log (8); + CHECK_INDICES(cvd); + + { + typedef typename test2_maybeconst<D>::type Dconst; + ConstDataVector<DataVector<Dconst> > vcd; + vcd.push_back (new D(7)); + vcd.push_back (new D(8)); + + vcd.swapElement (vcd.begin()+1, new D(9), cdold); + myassert (vcd[1]->x == 9); + myassert (cdold->x == 8); + delete cdold; + check_dtor_log (8); + CHECK_INDICES(vcd); + } + check_dtor_log (7, 9); + } + + check_dtor_log (4, 6, 1, 3, 7, 9); + + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (new B(1)); + setaux (vb, store_b); + vb.setStore (vb.getConstStore()); + B* bold; + B* bnew = make_comp<B>(3); + bool caught = false; + try { + vb.swapElement (vb.begin(), bnew, bold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<B>::flag()); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (new D(1)); + setaux (vd, store_d); + vd.setStore (vd.getConstStore()); + D* dold; + D* dnew = make_comp<D>(3); + caught = false; + try { + vd.swapElement (vd.begin(), dnew, dold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<D>::flag()); + } + + { + DataVector<B> vb1; + vb1.push_back (new B(1)); + vb1.push_back (new B(2)); + CHECK_INDICES(vb1); + B* bold; + B* bnew = new B(3); + vb1.swapElement (vb1.begin(), bnew, bold); + CHECK_INDICES(vb1); + DataVector<B> vb2 = vb1; + bnew = new B(4); + vb2.swapElement (vb2.begin(), bnew, bold); + CHECK_INDICES(vb1); + + DataVector<D> vd1; + vd1.push_back (new D(1)); + vd1.push_back (new D(2)); + CHECK_INDICES(vd1); + D* dold; + D* dnew = new D(3); + vd1.swapElement (vd1.begin(), dnew, dold); + CHECK_INDICES(vd1); + DataVector<D> vd2 = vd1; + dnew = new D(4); + vd2.swapElement (vd2.begin(), dnew, dold); + CHECK_INDICES(vd1); + } +} + + +// Test swapElement with iterator and unique_ptr +template <class B, class D> +void test2_swapelement_iter_unique() +{ +#if __cplusplus > 201100 + clear_dtor_log(); + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (CxxUtils::make_unique<B>(1)); + vb.push_back (CxxUtils::make_unique<B>(2)); + setaux (vb, store_b); + + { + std::unique_ptr<B> bold; + vb.swapElement (vb.begin()+1, make_comp_unique<B>(3), bold); + releasePrivateStore (static_cast<B*>(vb[1])); + myassert (vb[1]->x == 3); + myassert (bold->x == 2); + CHECK_INDEX_CLEAR (bold); + } + check_dtor_log (2); + CHECK_INDICES(vb); + checkaux(vb); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (CxxUtils::make_unique<D>(4)); + vd.push_back (CxxUtils::make_unique<D>(5)); + setaux (vd, store_d); + + { + std::unique_ptr<D> dold; + vd.swapElement (vd.begin()+1, make_comp_unique<D>(6), dold); + releasePrivateStore (static_cast<D*> (vd[1])); + myassert (vd[1]->x == 6); + myassert (dold->x == 5); + CHECK_INDEX_CLEAR (dold); + } + check_dtor_log (5); + CHECK_INDICES(vd); + checkaux(vd); + + { + DataVector<B>& vd_b = vd; + std::unique_ptr<B> bold; + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, + vd_b.swapElement (vd_b.begin()+1, + CxxUtils::make_unique<B>(10), bold)); + } + check_dtor_log (10); + + ConstDataVector<DataVector<D> > cvd; + cvd.push_back (CxxUtils::make_unique<D>(7)); + cvd.push_back (CxxUtils::make_unique<D>(8)); + + { + std::unique_ptr<const D> cdold; + cvd.swapElement (cvd.begin()+1, CxxUtils::make_unique<const D>(9), cdold); + myassert (cvd[1]->x == 9); + myassert (cdold->x == 8); + } + check_dtor_log (8); + CHECK_INDICES(cvd); + + { + typedef typename test2_maybeconst<D>::type Dconst; + ConstDataVector<DataVector<Dconst> > vcd; + vcd.push_back (CxxUtils::make_unique<D>(7)); + vcd.push_back (CxxUtils::make_unique<D>(8)); + + { + std::unique_ptr<const D> cdold; + vcd.swapElement (vcd.begin()+1, CxxUtils::make_unique<const D>(9), cdold); + myassert (vcd[1]->x == 9); + myassert (cdold->x == 8); + } + check_dtor_log (8); + CHECK_INDICES(vcd); + } + check_dtor_log (7, 9); + } + + check_dtor_log (4, 6, 1, 3, 7, 9); + + { + DataVector<B> vb; + SG::AuxStoreInternal store_b; + vb.push_back (CxxUtils::make_unique<B>(1)); + setaux (vb, store_b); + vb.setStore (vb.getConstStore()); + std::unique_ptr<B> bold; + bool caught = false; + try { + vb.swapElement (vb.begin(), make_comp_unique<B>(3), bold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<B>::flag()); + + DataVector<D> vd; + SG::AuxStoreInternal store_d; + vd.push_back (CxxUtils::make_unique<D>(1)); + setaux (vd, store_d); + vd.setStore (vd.getConstStore()); + std::unique_ptr<D> dold; + caught = false; + try { + vd.swapElement (vd.begin(), make_comp_unique<D>(3), dold); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<D>::flag()); + } + + { + DataVector<B> vb1; + vb1.push_back (CxxUtils::make_unique<B>(1)); + vb1.push_back (CxxUtils::make_unique<B>(2)); + CHECK_INDICES(vb1); + std::unique_ptr<B> bold; + vb1.swapElement (vb1.begin(), CxxUtils::make_unique<B>(3), bold); + CHECK_INDICES(vb1); + DataVector<B> vb2 = vb1; + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vb2.swapElement (vb2.begin(), CxxUtils::make_unique<B>(4), bold)); + + DataVector<D> vd1; + vd1.push_back (CxxUtils::make_unique<D>(1)); + vd1.push_back (CxxUtils::make_unique<D>(2)); + CHECK_INDICES(vd1); + std::unique_ptr<D> dold; + vd1.swapElement (vd1.begin(), CxxUtils::make_unique<D>(3), dold); + CHECK_INDICES(vd1); + DataVector<D> vd2 = vd1; + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + vd2.swapElement (vd2.begin(), CxxUtils::make_unique<D>(4), dold)); + } +#endif +} + + +// Test resize +template <class DV> +void test2_resize1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DV v2 (v1); + myassert (v2.size() == 2); + v2.resize (1); + CHECK_INDICES(v2); + check_dtor_log(); + myassert (v2.size() == 1); + myassert (v2[0]->x == 1); + myassert (v1.size() == 2); + v1.resize (1); + CHECK_INDICES(v1); + check_dtor_log(2); + myassert (v1.size() == 1); + myassert (v1[0]->x == 1); + v1.resize (3); + myassert (v1.size() == 3); + myassert (v1[0]->x == 1); + myassert (v1[1] == 0); + myassert (v1[2] == 0); + CHECK_INDICES(v1); +} +template <class DV> +void test2_resize2() +{ + typedef typename DV::base_value_type T; + test2_resize1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back (t1); + v3.push_back (t2); + setaux(v3, store3); + CHECK_INDICES(v3); + v3.resize(1); + myassert (v3.size() == 1); + myassert (v3[0]->x == 1); + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t2); + checkaux(v3); + + DV v4 = v3; + v4.resize(0); + CHECK_INDICES(v3); + checkaux(v3); + + T* t3 = new T(3); + v3.push_back(t3); + checkauxZero (&*v3.back()); + + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + v3.resize (100); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + caught = false; + try { + v3.resize (0); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; + delete t3; +} +template <class B, class D> +void test2_resize() +{ + test2_resize2<DataVector<B> >(); + test2_resize2<DataVector<D> >(); + test2_resize1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_resize1<ConstDataVector<DataVector<D> > >(); +} + + +// Test pop_back +template <class DV> +void test2_pop_back1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DV v2 (v1); + myassert (v2.size() == 2); + v2.pop_back(); + myassert (v2.size() == 1); + check_dtor_log(); + myassert (v1.size() == 2); + v1.pop_back(); + myassert (v1.size() == 1); + check_dtor_log(2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); +} +template <class DV> +void test2_pop_back2() +{ + typedef typename DV::base_value_type T; + test2_pop_back1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back (t1); + v3.push_back (t2); + CHECK_INDICES(v3); + setaux (v3, store3); + v3.pop_back(); + myassert (v3.size() == 1); + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t2); + checkaux(v3); + + DV v4 = v3; + v4.pop_back(); + CHECK_INDICES(v3); + checkaux(v3); + + v3.pop_back(); + myassert (v3.size() == 0); + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t1); + checkaux(v3); + delete t1; + delete t2; + + t1 = new T(3); + v3.push_back(t1); + CHECK_INDICES(v3); + assert (v3.size() == 1); + checkauxZero (&*v3[0]); + + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + v3.pop_back(); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); +} +template <class B, class D> +void test2_pop_back() +{ + test2_pop_back2<DataVector<B> > (); + test2_pop_back2<DataVector<D> > (); + test2_pop_back1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_pop_back1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + D* d = new D(1); + vd.push_back (d); + CHECK_INDICES(vd); + DataVector<B>& vb = vd; + bool caught = false; + try { + vb.pop_back(); + } + catch (dv_test_err&) { + caught = true; + } + + if (typename SG::AuxStore_traits<D>::flag() && + ! typename SG::AuxStore_traits<B>::flag()) + myassert (caught); + else + CHECK_INDEX_CLEAR(d); +} + + +// Test begin, end +template <class DV> +void test2_begin_end1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + myassert (v1.end() - v1.begin() == 2); + typename DV::value_type tt = *v1.begin(); + myassert (tt->x == 1); + myassert (v1.begin()[1]->x == 2); + *v1.begin() = new T(3); + check_dtor_log(1); + myassert (v1[0]->x == 3); + CHECK_INDICES(v1); + + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(4)); + v2.push_back (new T(5)); + *v2.begin() = *v1.begin(); + CHECK_INDICES(v2); + check_dtor_log(); + myassert (v2[0]->x == 3); + // (3,2) (3,5) + *(v1.end()-1) = v2.end()[-1]; + check_dtor_log(2); + myassert (v1[1]->x == 5); + CHECK_INDICES(v2); + // (3,5) (3,5) + v2.begin()[0] = v2.begin()[1]; + check_dtor_log(); + myassert (v2[0]->x == 5); + CHECK_INDICES(v2); + + bool caught = false; + try { + v1.begin()[0] = v1.begin()[1]; + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + CHECK_INDICES(v1); + + // Check creating a const_iterator from an iterator. + typename DV::const_iterator ci = v2.begin(); + myassert ((*ci)->x == 5); + + // Check comparing iterators and const_iterators. + typename DV::iterator i = v2.begin(); + myassert (i == ci); + myassert (ci == i); + myassert (! (i != ci)); + myassert (! (ci != i)); + myassert (! (i < ci)); + myassert (! (ci < i)); + myassert (! (i > ci)); + myassert (! (ci > i)); + myassert (i <= ci); + myassert (ci <= i); + myassert (i >= ci); + myassert (ci >= i); + + myassert (ci - i == 0); + myassert (i - ci == 0); + + std::sort (v2.begin(), v2.end()); + CHECK_INDICES(v2); +} +template <class DV> +void test2_begin_end2() +{ + typedef typename DV::base_value_type T; + test2_begin_end1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back(t1); + v3.push_back(t2); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux (v3); + *v3.begin() = 0; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t1); + *(v3.end()-1) = 0; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t2); + delete t1; + delete t2; + + t1 = make_comp<T>(3); + t2 = make_comp<T>(4); + *v3.begin() = t1; + *(v3.end()-1) = t2; + CHECK_INDICES(v3); + checkaux(v3); + + DV v4 (SG::VIEW_ELEMENTS); + v4.resize(2); + *v4.begin() = *(v3.end()-1); + *(v4.end()-1) = *(v3.begin()); + CHECK_INDICES(v3); + checkaux(v3); + + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + *v3.begin() = make_comp<T>(5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + caught = false; + try { + *(v3.end()-1) = make_comp<T>(5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; +} +template <class B, class D> +void test2_begin_end() +{ + test2_begin_end2<DataVector<B> > (); + test2_begin_end2<DataVector<D> > (); + test2_begin_end1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_begin_end1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd (1); + DataVector<B>& vb = vd; + bool caught = false; + try { + *vb.begin() = new B(1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test front, back +template <class DV> +void test2_front_back1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + typename DV::value_type tt = v1.front(); + myassert (tt->x == 1); + myassert (v1.back()->x == 2); + v1.front() = new T(3); + check_dtor_log(1); + myassert (v1[0]->x == 3); + CHECK_INDICES(v1); + + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(4)); + v2.push_back (new T(5)); + v2.front() = v1.front(); + CHECK_INDICES(v2); + check_dtor_log(); + myassert (v2[0]->x == 3); + // (3,2) (3,5) + v1.back() = v2.back(); + check_dtor_log(2); + myassert (v1[1]->x == 5); + CHECK_INDICES(v2); + // (3,5) (3,5) + v2.front() = v2.back(); + check_dtor_log(); + myassert (v2[0]->x == 5); + CHECK_INDICES(v2); + + bool caught = false; + try { + v1.front() = v1.back(); + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + CHECK_INDICES(v1); +} +template <class DV> +void test2_front_back2() +{ + typedef typename DV::base_value_type T; + test2_front_back1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back(t1); + v3.push_back(t2); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux (v3); + v3.front() = 0; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t1); + v3.back() = 0; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t2); + delete t1; + delete t2; + + t1 = make_comp<T>(3); + t2 = make_comp<T>(4); + v3.front() = t1; + v3.back() = t2; + checkaux(v3); + + DV v4 (SG::VIEW_ELEMENTS); + v4.resize(2); + v4.front() = v3.back(); + v4.back() = v3.front(); + CHECK_INDICES(v3); + checkaux(v3); + + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + v3.front() = make_comp<T>(5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + caught = false; + try { + v3.back() = make_comp<T>(5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; +} +template <class B, class D> +void test2_front_back() +{ + test2_front_back2<DataVector<B> > (); + test2_front_back2<DataVector<D> > (); + test2_front_back1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_front_back1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd (1); + DataVector<B>& vb = vd; + bool caught = false; + try { + vb.front() = new B(1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test rbegin, rend +template <class DV> +void test2_rbegin_rend1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + myassert (v1.rend() - v1.rbegin() == 2); + typename DV::value_type tt = *v1.rbegin(); + myassert (tt->x == 2); + myassert (v1.rbegin()[1]->x == 1); + *v1.rbegin() = new T(3); + check_dtor_log(2); + myassert (v1[1]->x == 3); + CHECK_INDICES(v1); + + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(4)); + v2.push_back (new T(5)); + // (1,3) (4,5) + *v2.rbegin() = *v1.rbegin(); + check_dtor_log(); + myassert (v2[1]->x == 3); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + // (1,3) (4,3) + *(v1.rend()-1) = v2.rend()[-1]; + check_dtor_log(1); + myassert (v1[0]->x == 4); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + // (4,3) (4,3) + v2.rbegin()[0] = v2.rbegin()[1]; + check_dtor_log(); + myassert (v2[1]->x == 4); + // (4,3) (4,4) + CHECK_INDICES(v1); + CHECK_INDICES(v2); + + bool caught = false; + try { + v1.rbegin()[0] = v1.rbegin()[1]; + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + CHECK_INDICES(v1); + + // Check creating a const_iterator from an iterator. + typename DV::const_reverse_iterator ci = v2.rbegin(); + myassert ((*ci)->x == 4); + + std::sort (v2.begin(), v2.end()); + CHECK_INDICES(v2); +} +template <class DV> +void test2_rbegin_rend2() +{ + typedef typename DV::base_value_type T; + test2_rbegin_rend1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back(t1); + v3.push_back(t2); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux (v3); + *v3.rbegin() = 0; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t2); + *(v3.rend()-1) = 0; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t1); + delete t1; + delete t2; + + t1 = make_comp<T>(3); + t2 = make_comp<T>(4); + *v3.rbegin() = t1; + *(v3.rend()-1) = t2; + CHECK_INDICES(v3); + checkaux(v3); + + DV v4 (SG::VIEW_ELEMENTS); + v4.resize(2); + *v4.rbegin() = *(v3.rend()-1); + *(v4.rend()-1) = *(v3.rbegin()); + CHECK_INDICES(v3); + checkaux(v3); + + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + *v3.rbegin() = make_comp<T>(5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + caught = false; + try { + *(v3.rend()-1) = make_comp<T>(5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; +} +template <class B, class D> +void test2_rbegin_rend() +{ + test2_rbegin_rend2<DataVector<B> > (); + test2_rbegin_rend2<DataVector<D> > (); + test2_rbegin_rend1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_rbegin_rend1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd (1); + DataVector<B>& vb = vd; + bool caught = false; + try { + *vb.rbegin() = new B(1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test erase(it, it) +template <class DV> +void test2_erase_range1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v; + for (int i=0; i < 10; i++) + v.push_back (new T(i)); + myassert (v.size() == 10); + typename DV::iterator i1 = v.erase (v.begin()+3, v.end()-3); + myassert ((*i1)->x == 7); + myassert (v.size() == 6); + check_dtor_log (3, 4, 5, 6); + myassert (v[2]->x == 2); + myassert (v[3]->x == 7); + CHECK_INDICES(v); + + DV v2 (v); + myassert (v2.size() == 6); + typename DV::iterator i2 = v2.erase (v2.begin()+2, v2.end()-2); + myassert ((*i2)->x == 8); + myassert (v2.size() == 4); + check_dtor_log (); + myassert (v2[1]->x == 1); + myassert (v2[2]->x == 8); + CHECK_INDICES(v2); + +#ifdef DO_REMOVE_DUPLICATES + { + DV v3; + T* t = new T(1); + v3.push_back (t); + v3.push_back (t); + v3.push_back (new T(2)); + v3.erase (v3.begin(), v3.begin()+2); + check_dtor_log (1); + CHECK_INDICES(v3); + } + check_dtor_log(2); +#endif +} +template <class DV> +void test2_erase_range2() +{ + typedef typename DV::base_value_type T; + test2_erase_range1<DV>(); + + clear_dtor_log(); + std::vector<T*> vv4; + DV v4 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store4; + for (int i=0; i < 10; i++) { + vv4.push_back (new T(i)); + v4.push_back (vv4.back()); + } + setaux(v4, store4); + CHECK_INDICES(v4); + checkaux(v4); + v4.erase (v4.begin()+3, v4.end()-3); + check_dtor_log(); + CHECK_INDICES(v4); + checkaux(v4); + for (int i=3; i<7; i++) + CHECK_INDEX_CLEAR(vv4[i]); + + DV v5 = v4; + v5.erase (v5.begin()+1, v5.end()-1); + CHECK_INDICES(v4); + checkaux(v4); + + v4.setStore (v4.getConstStore()); + bool caught = false; + try { + v4.erase (v4.begin()+1, v4.end()-1); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + for (size_t i=0; i < vv4.size(); ++i) + delete vv4[i]; +} +template <class B, class D> +void test2_erase_range() +{ + test2_erase_range2<DataVector<B> > (); + test2_erase_range2<DataVector<D> > (); + test2_erase_range1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_erase_range1<ConstDataVector<DataVector<D> > > (); +} + + +// Test erase(it) +template <class DV> +void test2_erase_single1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.erase (v1.begin()); + myassert (v1.size() == 1); + myassert (v1[0]->x == 2); + check_dtor_log (1); + CHECK_INDICES(v1); + + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(1)); + v2.push_back (new T(2)); + v2.erase (v2.begin()); + myassert (v2.size() == 1); + myassert (v2[0]->x == 2); + check_dtor_log (); + CHECK_INDICES(v2); +} +template <class DV> +void test2_erase_single2() +{ + typedef typename DV::base_value_type T; + test2_erase_single1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back (t1); + v3.push_back (t2); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux (v3); + v3.erase (v3.begin()); + myassert (v3.size() == 1); + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR(t1); + checkaux (v3); + + DV v5 = v3; + v5.erase (v5.begin()); + CHECK_INDICES(v3); + checkaux(v3); + + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + v3.erase (v3.begin()); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t1; + delete t2; +} +template <class B, class D> +void test2_erase_single() +{ + test2_erase_single2<DataVector<B> > (); + test2_erase_single2<DataVector<D> > (); + test2_erase_single1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_erase_single1<ConstDataVector<DataVector<D> > > (); +} + + +// Test operator= +template <class DV> +void test2_operator_assign1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + { + DV v2; + v2 = v1; + myassert (v2.size() == 2); + myassert (v2[0]->x == 1); + myassert (v2[1]->x == 2); + CHECK_INDICES(v2); + } + check_dtor_log(); + + v1 = v1; + check_dtor_log(); + CHECK_INDICES(v1); + + { + DV v2; + v1 = v2; + myassert (v1.size() == 0); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + } + check_dtor_log (1, 2); + } + check_dtor_log (); +} +template <class DV> +void test2_operator_assign2() +{ + typedef typename DV::base_value_type T; + test2_operator_assign1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back (t1); + v3.push_back (t2); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux(v3); + DV v4; + SG::AuxStoreInternal store4; + setaux (v4, store4); + v3 = v4; + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR (t1); + CHECK_INDEX_CLEAR (t2); + bool auxdata = typename SG::AuxStore_traits<T>::flag(); + myassert (!v3.hasStore()); + if (auxdata) myassert (v4.hasStore()); + delete t1; + delete t2; +} +template <class B, class D> +void test2_operator_assign() +{ + test2_operator_assign2<DataVector<B> > (); + test2_operator_assign2<DataVector<D> > (); + test2_operator_assign1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_operator_assign1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd1; + vd1.push_back (new D(1)); + DataVector<B> vb1; + vb1 = vd1; + myassert (vb1.size() == 1); + myassert (vb1[0]->x == 1); + + DataVector<B>& vd1_b = vd1; + bool caught = false; + try { + vd1_b = vb1; + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +// Test insert(it, val) +template <class DV> +void test2_insert_value1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + typename DV::iterator i1 = v1.insert (v1.begin()+1, new T(3)); + myassert (v1.size() == 3); + myassert ((*i1)->x == 3); + myassert (v1[0]->x == 1); + myassert (v1[1]->x == 3); + myassert (v1[2]->x == 2); + CHECK_INDICES(v1); + + DV v2 (v1); + typename DV::iterator i2 = v2.emplace (v2.begin()+1, new T(4)); + myassert (v2.size() == 4); + myassert ((*i2)->x == 4); + CHECK_INDICES(v2); + } + check_dtor_log (1, 3, 2); + +#if __cplusplus > 201100 + { + DV v3; + v3.push_back (CxxUtils::make_unique<T>(11)); + v3.push_back (CxxUtils::make_unique<T>(12)); + typename DV::iterator i3 = v3.insert (v3.begin()+1, CxxUtils::make_unique<T>(13)); + myassert (v3.size() == 3); + myassert ((*i3)->x == 13); + myassert (v3[0]->x == 11); + myassert (v3[1]->x == 13); + myassert (v3[2]->x == 12); + CHECK_INDICES(v3); + } + check_dtor_log (11, 13, 12); + + { + DV v4 (SG::VIEW_ELEMENTS); + v4.push_back (new T(21)); + v4.push_back (new T(22)); + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + v4.insert (v4.begin()+1, CxxUtils::make_unique<T>(23))); + } + check_dtor_log (23); +#endif +} +template <class DV> +void test2_insert_value2() +{ + test2_insert_value1<DV>(); + + typedef typename DV::base_value_type T; + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + setaux (v1, store1); + CHECK_INDICES(v1); + checkaux(v1); + + v1.insert (v1.begin()+1, make_comp<T>(3)); + assert (v1.size() == 3); + CHECK_INDICES(v1); + checkaux(v1); + + DV v2 = v1; + v2.insert (v2.begin()+1, make_comp<T>(5)); + CHECK_INDICES(v1); + checkaux(v1); + + v1.setStore (v1.getConstStore()); + bool caught = false; + try { + v1.insert (v1.begin()+1, make_comp<T>(4)); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + +#if __cplusplus > 201100 + { + DV v3; + SG::AuxStoreInternal store3; + v3.push_back (CxxUtils::make_unique<T>(41)); + v3.push_back (CxxUtils::make_unique<T>(42)); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux(v3); + + v3.insert (v3.begin()+1, make_comp_unique<T>(43)); + assert (v3.size() == 3); + CHECK_INDICES(v3); + checkaux(v3); + } +#endif +} +template <class B, class D> +void test2_insert_value() +{ + test2_insert_value2<DataVector<B> > (); + test2_insert_value2<DataVector<D> > (); + test2_insert_value1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_insert_value1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd; + DataVector<B>& vb = vd; + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, + vb.insert (vb.begin(), new D(1))); +#if __cplusplus > 201100 + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, + vb.insert (vb.begin(), CxxUtils::make_unique<D>(1))); +#endif + vd.insert (vd.begin(), new D(1)); +} + + +// Test insert(it, It, It) +template <class DV> +void test2_insert_range1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + T* tt[] = {new T(1), new T(2)}; + DV v; + v.insert (v.begin(), tt, tt+2); + myassert (v.size() == 2); + myassert (v[0]->x == 1); + myassert (v[1]->x == 2); + CHECK_INDICES(v); + } + check_dtor_log (1, 2); + + { + T* tt[] = {new T(1), new T(2)}; + DV v (SG::VIEW_ELEMENTS); + v.insert (v.begin(), tt, tt+2); + myassert (v.size() == 2); + myassert (v[0]->x == 1); + myassert (v[1]->x == 2); + CHECK_INDICES(v); + } + check_dtor_log (); + +#if __cplusplus > 201100 + { + DV v; + v.insert (v.begin(), {new T(1), new T(2)}); + myassert (v.size() == 2); + myassert (v[0]->x == 1); + myassert (v[1]->x == 2); + CHECK_INDICES(v); + } + check_dtor_log (1, 2); +#endif +} +template <class B, class D> +void test2_insert_range() +{ + test2_insert_range1<DataVector<B> > (); + test2_insert_range1<DataVector<D> > (); + test2_insert_range1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_insert_range1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd; + SG::AuxStoreInternal store; + setaux (vd, store); + DataVector<B>& vb = vd; + bool caught = false; + D* tt[] = {make_comp<D>(1), make_comp<D>(2)}; + try { + vb.insert (vb.begin(), tt, tt+2); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + vd.insert (vd.begin(), tt, tt+2); + checkaux(vd); + + DataVector<D> vd2 = vd; + vd2.insert (vd2.begin()+1, make_comp<D>(5)); + CHECK_INDICES(vd); + checkaux(vd); + + DataVector<B> vb2 = vb; + vb2.insert (vb2.begin()+1, make_comp<B>(5)); + CHECK_INDICES(vb); + checkaux(vb); + + D* tt2[] = {make_comp<D>(3), make_comp<D>(4)}; + vd.setStore (vd.getConstStore()); + caught = false; + try { + vd.insert (vd.begin(), tt2, tt2+2); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<D>::flag()); +} + + +// Test insertMove +template <class DV> +void test2_insertMove1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v; + v.push_back (new T(3)); + v.push_back (new T(4)); + DV v2 ({new T(1), new T(2)}, SG::OWN_ELEMENTS); + v.insertMove (v.begin()+1, v2); + myassert (v.size() == 4); + myassert (v[0]->x == 3); + myassert (v[1]->x == 1); + myassert (v[2]->x == 2); + myassert (v[3]->x == 4); + CHECK_INDICES(v); + + myassert (v2.size() == 2); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (v2[0]->x == 1); + myassert (v2[1]->x == 2); + } + check_dtor_log (3, 1, 2, 4); + + { + DV v (SG::VIEW_ELEMENTS); + v.push_back (new T(3)); + v.push_back (new T(4)); + DV v2 ({new T(1), new T(2)}, SG::VIEW_ELEMENTS); + v.insertMove (v.end(), v2); + myassert (v.size() == 4); + myassert (v[0]->x == 3); + myassert (v[1]->x == 4); + myassert (v[2]->x == 1); + myassert (v[3]->x == 2); + CHECK_INDICES(v); + + myassert (v2.size() == 2); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + myassert (v2[0]->x == 1); + myassert (v2[1]->x == 2); + } + check_dtor_log(); + + { + DV v; + v.push_back (new T(3)); + v.push_back (new T(4)); + DV v2 ({new T(1), new T(2)}, SG::VIEW_ELEMENTS); + EXPECT_EXCEPTION (SG::ExcInsertMoveOwnershipMismatch, + v.insertMove (v.begin()+1, v2)); + } + + clear_dtor_log(); +} +template <class B, class D> +void test2_insertMove() +{ + test2_insertMove1<DataVector<B> > (); + test2_insertMove1<DataVector<D> > (); + test2_insertMove1<DataVector<typename test2_maybeconst<D>::type> > (); + //test2_insertMove1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd; + SG::AuxStoreInternal store; + setaux (vd, store); + vd.push_back (make_comp<D>(3)); + vd.push_back (make_comp<D>(4)); + DataVector<B>& vb = vd; + + DataVector<D> vd2; + SG::AuxStoreInternal store2; + setaux (vd2, store2); + vd2.push_back (make_comp<D>(1)); + vd2.push_back (make_comp<D>(2)); + EXPECT_EXCEPTION (SG::ExcInsertionInBaseClass, + vb.insertMove (vb.begin()+1, vd2)); + + vd.insertMove (vd.begin()+1, vd2); + checkaux(vd); + + DataVector<D> vd3; + SG::AuxStoreInternal store3; + setaux (vd3, store3); + vd3.push_back (make_comp<D>(5)); + vd3.push_back (make_comp<D>(6)); + + vd.setStore (vd.getConstStore()); + bool caught = false; + try { + vd.insertMove (vd.begin(), vd3); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<D>::flag()); +} + + +// Test clear() +template <class DV> +void test2_clear1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.clear(); + check_dtor_log (1, 2); + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(1)); + v2.push_back (new T(2)); + v2.clear(); + check_dtor_log (); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + v2.clear(SG::OWN_ELEMENTS); + myassert (v2.ownPolicy() == SG::OWN_ELEMENTS); + v2.push_back (new T(1)); + v2.push_back (new T(2)); + v2.clear(SG::VIEW_ELEMENTS); + myassert (v2.ownPolicy() == SG::VIEW_ELEMENTS); + check_dtor_log (1, 2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); +} +template <class DV> +void test2_clear2() +{ + typedef typename DV::base_value_type T; + test2_clear1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back (t1); + v3.push_back (t2); + setaux (v3, store3); + CHECK_INDICES(v3); + checkaux (v3); + + DV v5 = v3; + v5.clear(); + CHECK_INDICES(v3); + checkaux (v3); + + v3.clear(); + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR (t1); + CHECK_INDEX_CLEAR (t2); + checkaux(v3); + delete t1; + delete t2; + + t1 = new T(3); + v3.push_back(t1); + checkauxZero (t1); + + bool auxdata = typename SG::AuxStore_traits<T>::flag(); + v3.setStore((SG::IConstAuxStore*)0); + myassert (!auxdata || v3.trackIndices()); + v3.clear (SG::VIEW_ELEMENTS); + myassert (!auxdata || !v3.trackIndices()); + v3.clear (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + myassert (!auxdata || v3.trackIndices()); + v3.clear (SG::VIEW_ELEMENTS, SG::NEVER_TRACK_INDICES); + myassert (!auxdata || !v3.trackIndices()); + + delete t1; + + DV v4 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store4; + setaux (v4, store4); + v4.setStore (v4.getConstStore()); + bool caught = false; + try { + v4.clear(); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + ConstDataVector<DV> cdv; + cdv.clear (SG::VIEW_ELEMENTS, SG::NEVER_TRACK_INDICES); +} +template <class B, class D> +void test2_clear() +{ + test2_clear2<DataVector<B> > (); + test2_clear2<DataVector<D> > (); + test2_clear1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_clear1<ConstDataVector<DataVector<D> > > (); +} + + +// Test swap() +template <class DV> +void test2_swap1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + setaux(v1, store1); + DV v2; + SG::AuxStoreInternal store2; + setaux(v2, store2); + v1.swap (v2); + myassert (v1.size() == 0); + myassert (v2.size() == 2); + myassert (v2[0]->x == 1); + myassert (v2[1]->x == 2); + check_dtor_log(); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + checkaux (v1); + checkaux (v2); + } + check_dtor_log(1,2); + { + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + setaux(v1, store1); + DV v2; + SG::AuxStoreInternal store2; + setaux(v2, store2); + swap (v1, v2); + myassert (v1.size() == 0); + myassert (v2.size() == 2); + myassert (v2[0]->x == 1); + myassert (v2[1]->x == 2); + check_dtor_log(); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + checkaux (v1); + checkaux (v2); + } + check_dtor_log(1,2); +} +template <class B, class D> +void test2_swap() +{ + test2_swap1<DataVector<B> > (); + test2_swap1<DataVector<D> > (); + + DataVector<D> vd; + DataVector<B>& vb = vd; + DataVector<B> vb2; + + bool caught = false; + try { + vb.swap(vb2); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + vb2.swap(vb); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + swap (vb, vb2); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + + caught = false; + try { + swap (vb2, vb); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +template <class DV> +void test2_assign1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + { + DV v; + v.push_back (new T(0)); + T* t[] = {new T(1), new T(2)}; + v.assign (t, t+2); + assert (v.size() == 2); + assert (v[0]->x == 1); + assert (v[1]->x == 2); + check_dtor_log(0); + CHECK_INDICES(v); + } + check_dtor_log(1,2); + + { + DV v (SG::VIEW_ELEMENTS); + v.push_back (new T(0)); + T* t[] = {new T(1), new T(2)}; + v.assign (t, t+2); + CHECK_INDICES(v); + } + +#if __cplusplus > 201100 + { + DV v; + v.push_back (new T(0)); + v.assign ({new T(1), new T(2)}); + check_dtor_log(0); + assert (v.size() == 2); + assert (v[0]->x == 1); + assert (v[1]->x == 2); + CHECK_INDICES(v); + } + check_dtor_log(1,2); + + { + DV v; + v.push_back (new T(10)); + v = {new T(11), new T(12)}; + check_dtor_log(10); + assert (v.size() == 2); + assert (v[0]->x == 11); + assert (v[1]->x == 12); + CHECK_INDICES(v); + } + check_dtor_log(11, 12); +#endif + + check_dtor_log(); +} +template <class DV> +void test2_assign2() +{ + typedef typename DV::base_value_type T; + test2_assign1<DV>(); + + DV v3 (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store3; + T* t1 = new T(1); + T* t2 = new T(2); + v3.push_back (t1); + v3.push_back (t2); + setaux(v3, store3); + CHECK_INDICES(v3); + checkaux(v3); + DV v4; + v3.assign (v4.begin(), v4.end()); + CHECK_INDICES(v3); + CHECK_INDEX_CLEAR (t1); + CHECK_INDEX_CLEAR (t2); + checkaux(v3); + assert (v3.size() == 0); + delete t1; + delete t2; + check_dtor_log(1, 2); + + T* vv[2] = {make_comp<T>(3), make_comp<T>(4)}; + v3.assign (vv, vv+2); + assert (v3.size() == 2); + CHECK_INDICES(v3); + checkaux(v3); + + T* vv2[2] = {make_comp<T>(5), make_comp<T>(6)}; + v3.setStore (v3.getConstStore()); + bool caught = false; + try { + v3.assign (vv2, vv2+2); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete vv[0]; + delete vv[1]; +} +template <class B, class D> +void test2_assign() +{ + test2_assign2<DataVector<B> > (); + test2_assign2<DataVector<D> > (); + test2_assign1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_assign1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> vd; + DataVector<B>& vb = vd; + B* t[] = {new B(1), new B(2)}; + bool caught = false; + try { + vb.assign (t, t+2); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + + +template <class DV> +void test2_relops1() +{ + typedef typename DV::base_value_type T; + DV v1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + DV v2 (v1); + DV v3 (v1); + v3.push_back (new T(3)); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + CHECK_INDICES(v3); + + myassert (v1 == v2); + myassert (!(v1 == v3)); + myassert (v1 != v3); + myassert (!(v1 != v2)); + + myassert (v1 < v3); + myassert (!(v1 < v2)); + myassert (v3 > v1); + myassert (!(v2 > v1)); + + myassert (v1 <= v3); + myassert (v1 <= v2); + myassert (!(v3 <= v1)); + + myassert (v3 >= v1); + myassert (v2 >= v1); + myassert (!(v1 >= v3)); +} +template <class B, class D> +void test2_relops() +{ + test2_relops1<DataVector<B> > (); + test2_relops1<DataVector<D> > (); + test2_relops1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_relops1<ConstDataVector<DataVector<D> > > (); +} + + +template <class T> +struct Comp +{ + bool operator() (const T* a, const T* b) const + { return *b < *a; } +}; + +template <class DV, int N> +void test2_sort1_prepare1 (DV& v) +{ + typedef typename + boost::remove_const<typename DV::base_value_type>::type T; + T* tmp[N]; + for (int i=0; i<N; i++) + tmp[i] = new T(i); + std::sort (tmp, tmp+N); + for (int i=0; i<N; i++) + tmp[i]->x = i; + for (int i=0; i<N; i++) + v.push_back (tmp[N-1-i]); +} +template <class DV> +void test2_sort1() +{ + typedef typename DV::base_value_type T; + const int N=10; + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + v2.sort(); // Check that this doesn't affect v's auxdata. + checkaux(v); + v.sort(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + v3.sort(); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + std::sort (v2.begin(), v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::sort (v.begin(), v.end()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + std::sort (v3.begin(), v3.end()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + std::sort (v2.rbegin(), v2.rend()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::sort (v.rbegin(), v.rend()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + std::sort (v3.rbegin(), v3.rend()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + std::stable_sort (v2.begin(), v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::stable_sort (v.begin(), v.end()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + std::stable_sort (v3.begin(), v3.end()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + std::stable_sort (v2.rbegin(), v2.rend()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::stable_sort (v.rbegin(), v.rend()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + std::stable_sort (v3.rbegin(), v3.rend()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + std::partial_sort (v2.begin(), v2.begin()+N/2, v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::partial_sort (v.begin(), v.begin()+N/2, v.end()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + std::partial_sort (v3.begin(), v3.begin()+N/2, v3.end()); + CHECK_INDICES(v3); + + for (int i=0; i<N/2; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + std::partial_sort (v2.rbegin(), v2.rend()-N/2, v2.rend()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::partial_sort (v.rbegin(), v.rend()-N/2, v.rend()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + std::partial_sort (v3.rbegin(), v3.rend()-N/2, v3.rend()); + CHECK_INDICES(v3); + + for (int i=N/2; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + v2.sort(Comp<T>());; // Check that this doesn't affect v's auxdata. + checkaux(v); + v.sort(Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + v3.sort(Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::sort (v2.begin(), v2.end(), Comp<T>()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::sort (v.begin(), v.end(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::sort (v3.begin(), v3.end(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::sort (v2.rbegin(), v2.rend(), Comp<T>()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::sort (v.rbegin(), v.rend(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::sort (v3.rbegin(), v3.rend(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::stable_sort (v2.begin(), v2.end(), Comp<T>()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::stable_sort (v.begin(), v.end(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::stable_sort (v3.begin(), v3.end(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::stable_sort (v2.rbegin(), v2.rend(), Comp<T>()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::stable_sort (v.rbegin(), v.rend(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::stable_sort (v3.rbegin(), v3.rend(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::partial_sort (v2.begin(), v2.begin()+N/2, v2.end(), Comp<T>()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::partial_sort (v.begin(), v.begin()+N/2, v.end(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::partial_sort (v3.begin(), v3.begin()+N/2, v3.end(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N/2; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::partial_sort (v2.rbegin(), v2.rend()-N/2, v2.rend(), Comp<T>()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::partial_sort (v.rbegin(), v.rend()-N/2, v.rend(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::partial_sort (v3.rbegin(), v3.rend()-N/2, v3.rend(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=N/2; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + v.setStore (v.getConstStore()); + bool caught = false; + try { + v.sort(); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } + + clear_dtor_log(); +} +template <class B, class D> +void test2_sort() +{ + test2_sort1<DataVector<B> > (); + test2_sort1<DataVector<D> > (); + test2_sort1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_sort1<ConstDataVector<DataVector<D> > > (); +} + +template <class Iterator> +void test2_call_inplace_merge (Iterator beg, Iterator end) +{ + std::sort (beg, beg+4); + std::sort (beg+4, end); + std::inplace_merge (beg, beg+4, end); +} +template <class Iterator, class Compare> +void test2_call_inplace_merge (Iterator beg, Iterator end, Compare comp) +{ + std::sort (beg, beg+4, comp); + std::sort (beg+4, end, comp); + std::inplace_merge (beg, beg+4, end, comp); +} +template <class DV> +void test2_inplace_merge1() +{ + typedef typename DV::base_value_type T; + const int N=10; + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + test2_call_inplace_merge (v2.begin(), v2.end()); + checkaux(v); + test2_call_inplace_merge (v.begin(), v.end()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + test2_call_inplace_merge (v3.begin(), v3.end()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + DV v2(v); + test2_call_inplace_merge (v2.rbegin(), v2.rend()); + checkaux(v); + test2_call_inplace_merge (v.rbegin(), v.rend()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + test2_sort1_prepare1<DV, N> (v3); + test2_call_inplace_merge (v3.rbegin(), v3.rend()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + test2_call_inplace_merge (v2.begin(), v2.end(), Comp<T>()); + checkaux(v); + test2_call_inplace_merge (v.begin(), v.end(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + test2_call_inplace_merge (v3.begin(), v3.end(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == N-1-i); + myassert (v2[i]->x == N-1-i); + myassert (v3[i]->x == N-1-i); + } + } + { + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + test2_call_inplace_merge (v2.rbegin(), v2.rend(), Comp<T>()); + checkaux(v); + test2_call_inplace_merge (v.rbegin(), v.rend(), Comp<T>()); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + test2_call_inplace_merge (v3.rbegin(), v3.rend(), Comp<T>()); + CHECK_INDICES(v3); + + for (int i=0; i<N; i++) { + myassert (v[i]->x == i); + myassert (v2[i]->x == i); + myassert (v3[i]->x == i); + } + } + + { + DV v; + SG::AuxStoreInternal store; + test2_sort1_prepare1<DV, N> (v); + setaux(v, store); + v.setStore (v.getConstStore()); + bool caught = false; + try { + test2_call_inplace_merge (v.begin(), v.end()); + v.sort(); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } + + clear_dtor_log(); +} +template <class B, class D> +void test2_inplace_merge() +{ + test2_inplace_merge1<DataVector<B> > (); + test2_inplace_merge1<DataVector<D> > (); + test2_inplace_merge1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_inplace_merge1<ConstDataVector<DataVector<D> > > (); +} + + +template <class DV, class It> +void test2_iter_swap_memb2 (DV& v, It beg, It end) +{ + int a = v.front()->x; + int b = v.back()->x; + myassert (a != b); + DV::iter_swap (beg, end); + myassert (a == v.back()->x); + myassert (b == v.front()->x); + CHECK_INDICES(v); +} +template <class DV> +void test2_iter_swap_memb1() +{ + typedef typename DV::base_value_type T; + DV v; + for (int i=0; i<10; i++) + v.push_back (new T(i)); + test2_iter_swap_memb2 (v, v.begin(), v.end()-1); + test2_iter_swap_memb2 (v, v.begin(), v.end()-1); + + DV v2 (v); + bool caught = false; + try { + test2_iter_swap_memb2 (v, v.begin(), v2.end()-1); + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + caught = false; + try { + test2_iter_swap_memb2 (v, v.begin(), v2.end()-1); + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + + DV v3; + v3.push_back (new T(100)); + DV::iter_swap (v.begin()+1, v3.begin()); + CHECK_INDICES(v); + CHECK_INDICES(v3); + assert (v[1]->x == 100); + assert (v3.front()->x == 1); +} +template <class DV> +void test2_iter_swap_memb4(void*) +{ +} +template <class DV> +void test2_iter_swap_memb4(SG::AuxElement*) +{ + typedef typename DV::base_value_type T; + + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.push_back (new T(3)); + setaux (v1, store1); + checkaux (v1); + CHECK_INDICES (v1); + // v1: 1 2 3 + + DV v2; + SG::AuxStoreInternal store2; + v2.push_back (new T(11)); + v2.push_back (new T(12)); + setaux (v2, store2); + checkaux (v2); + CHECK_INDICES (v2); + // v2: 11 12 + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("xint"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("xfloat"); + + v1[1] = 0; + checkaux (v1); + CHECK_INDICES(v1); + DV::iter_swap (v1.begin()+1, v2.begin()+1); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + assert (v2.template getData<int> (ityp, 1) == 0); + assert (v2.template getData<float> (ftyp, 1) == 0); + assert (v1[1]->x == 12); + assert (v2[1] == 0); + // v1: 1 12 3 + // v2: 11 x + + DV::iter_swap (v1.begin()+0, v2.begin()+1); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + assert (v1.template getData<int> (ityp, 0) == 0); + assert (v1.template getData<float> (ftyp, 0) == 0); + assert (v1[0] == 0); + assert (v2[1]->x == 1); + // v1: x 12 3 + // v2: 11 1 + + typename T::template Accessor<int> xinta ("xinta"); + typename T::template Accessor<int> xintb ("xintb"); + + xinta(*v1[1]) = 10; + DV::iter_swap (v1.begin()+1, v2.begin()+1); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + assert (v1[1]->x == 1); + assert (v2[1]->x == 12); + assert (xinta(*v1[1]) == 0); + assert (xinta(*v2[1]) == 10); + // v1: x 1 3 + // v2: 11 12 + + xintb(*v2[1]) = 20; + DV::iter_swap (v1.begin()+1, v2.begin()+1); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + assert (v1[1]->x == 12); + assert (v2[1]->x == 1); + assert (xinta(*v1[1]) == 10); + assert (xinta(*v2[1]) == 0); + assert (xintb(*v1[1]) == 20); + assert (xintb(*v2[1]) == 0); + // v1: x 12 3 + // v2: 11 1 + + DV v3 = v1; + DV::iter_swap (v3.begin()+1, v3.begin()+2); + CHECK_INDICES(v1); + checkaux(v1); + + v1.setStore (v1.getConstStore()); + bool caught = false; + try { + DV::iter_swap (v1.begin(), v1.begin()+1); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); +} +template <class DV> +void test2_iter_swap_memb3() +{ + typedef typename DV::base_value_type T; + + test2_iter_swap_memb1<DV>(); + test2_iter_swap_memb4<DV>((T*)0); + + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.push_back (new T(3)); + setaux (v1, store1); + checkaux (v1); + CHECK_INDICES (v1); + // v1: 1 2 3 + + DV::iter_swap (v1.begin(), v1.begin()+2); + assert (v1[0]->x == 3); + assert (v1[2]->x == 1); + checkaux (v1); + CHECK_INDICES(v1); + // v1: 3 2 1 + + DV::iter_swap (v1.begin(), v1.end()-1); + assert (v1[0]->x == 1); + assert (v1[2]->x == 3); + checkaux (v1); + CHECK_INDICES(v1); + // v1: 1 2 3 + + DV v2; + SG::AuxStoreInternal store2; + v2.push_back (new T(11)); + v2.push_back (new T(12)); + setaux (v2, store2); + checkaux (v2); + CHECK_INDICES (v2); + // v2: 11 12 + + DV::iter_swap (v1.begin(), v2.begin()); + assert (v1[0]->x == 11); + assert (v2[0]->x == 1); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + // v1: 11 2 3 + // v2: 1 12 + + DV::iter_swap (v1.end()-1, v2.end()-1); + assert (v1[2]->x == 12); + assert (v2[1]->x == 3); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + // v1: 11 2 12 + // v2: 1 3 +} +template <class B, class D> +void test2_iter_swap_memb() +{ + test2_iter_swap_memb3<DataVector<B> > (); + test2_iter_swap_memb3<DataVector<D> > (); + test2_iter_swap_memb1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_iter_swap_memb1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> v; + for (int i=0; i<10; i++) + v.push_back (new D(i)); + DataVector<B>& b = v; + test2_iter_swap_memb2 (v, v.begin(), v.end()-1); + bool caught = false; + try { + test2_iter_swap_memb2 (b, b.begin(), b.end()-1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + +template <class DV, class It> +void test2_iter_swap2 (DV& v, It beg, It end) +{ + int a = v.front()->x; + int b = v.back()->x; + myassert (a != b); + std::iter_swap (beg, end); + myassert (a == v.back()->x); + myassert (b == v.front()->x); + CHECK_INDICES(v); +} +template <class DV> +void test2_iter_swap1() +{ + typedef typename DV::base_value_type T; + DV v; + for (int i=0; i<10; i++) + v.push_back (new T(i)); + test2_iter_swap2 (v, v.begin(), v.end()-1); + test2_iter_swap2 (v, v.rbegin(), v.rend()-1); + + DV v2 (v); + bool caught = false; + try { + test2_iter_swap2 (v, v.begin(), v2.end()-1); + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + caught = false; + try { + test2_iter_swap2 (v, v.rbegin(), v2.rend()-1); + } + catch (dv_test_err&) { + caught = true; + } + myassert (caught); + + DV v3; + v3.push_back (new T(100)); + std::iter_swap (v.begin()+1, v3.begin()); + CHECK_INDICES(v); + CHECK_INDICES(v3); + assert (v[1]->x == 100); + assert (v3.front()->x == 1); +} +template <class DV> +void test2_iter_swap3() +{ + test2_iter_swap1<DV>(); + + typedef typename DV::base_value_type T; + + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (new T(1)); + v1.push_back (new T(2)); + v1.push_back (new T(3)); + setaux (v1, store1); + checkaux (v1); + CHECK_INDICES (v1); + + std::iter_swap (v1.begin(), v1.begin()+2); + assert (v1[0]->x == 3); + assert (v1[2]->x == 1); + checkaux (v1); + CHECK_INDICES(v1); + + std::iter_swap (v1.rbegin(), v1.rend()-1); + assert (v1[0]->x == 1); + assert (v1[2]->x == 3); + checkaux (v1); + CHECK_INDICES(v1); + + DV v2; + SG::AuxStoreInternal store2; + v2.push_back (new T(11)); + v2.push_back (new T(12)); + setaux (v2, store2); + checkaux (v2); + CHECK_INDICES (v2); + + std::iter_swap (v1.begin(), v2.begin()); + assert (v1[0]->x == 11); + assert (v2[0]->x == 1); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + + std::iter_swap (v1.rbegin(), v2.rbegin()); + assert (v1[2]->x == 12); + assert (v2[1]->x == 3); + checkaux (v1); + checkaux (v2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + + DV v3 = v1; + DV::iter_swap (v3.begin(), v3.begin()+1); + CHECK_INDICES(v1); + checkaux(v1); + + v1.setStore (v1.getConstStore()); + bool caught = false; + try { + std::iter_swap (v1.begin(), v1.begin()+1); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); +} +template <class B, class D> +void test2_iter_swap() +{ + test2_iter_swap3<DataVector<B> > (); + test2_iter_swap3<DataVector<D> > (); + test2_iter_swap1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_iter_swap1<ConstDataVector<DataVector<D> > > (); + + DataVector<D> v; + for (int i=0; i<10; i++) + v.push_back (new D(i)); + DataVector<B>& b = v; + test2_iter_swap2 (v, v.begin(), v.end()-1); + bool caught = false; + try { + test2_iter_swap2 (b, b.begin(), b.end()-1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); + caught = false; + try { + test2_iter_swap2 (b, b.rbegin(), b.rend()-1); + } + catch (SG::ExcInsertionInBaseClass&) { + caught = true; + } + myassert (caught); +} + +template <class T> +struct Pred +{ + Pred (int the_v) : v (the_v) {} + bool operator() (const T* a) const + { return a->x == v; } + int v; +}; +template <class DV> +void test2_set_ownership (DV& v, bool testClearIndex) +{ + if (testClearIndex) + v.clear (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); +} +template <class DV> +void test2_set_ownership (ConstDataVector<DV>& v, bool testClearIndex) +{ + if (testClearIndex) + v.clear (SG::VIEW_ELEMENTS); +} +template <class DV> +void test2_remove1 (bool testClearIndex) +{ + typedef typename DV::base_value_type T; + const int N=10; + + { + clear_dtor_log(); + DV v; + test2_set_ownership (v, testClearIndex); + for (int i=0; i<N; i++) + v.push_back (new T(i)); + std::vector<const T*> v2 (v.begin(), v.end()); + typename DV::iterator it = + std::remove (v.begin(), v.end(), v[5]); + myassert (it - v.begin() == N-1); + int j=0; + for (int i=0; i<N-1; i++, j++) { + if (j == 5) ++j; + myassert (v[i]->x == j); + } + myassert (v[N-1] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[5]); + } + else { + check_dtor_log (5); + } + + it = std::remove (v.begin(), v.end()-1, v[8]); + myassert (it - v.begin() == N-2); + j=0; + for (int i=0; i<N-2; i++, j++) { + if (j == 5) ++j; + if (j == 9) ++j; + myassert (v[i]->x == j); + } + myassert (v[N-2] == 0); + myassert (v[N-1] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[9]); + for (size_t i = 0; i < v2.size(); i++) delete v2[i]; + } + else { + check_dtor_log (9); + } + } + + { + clear_dtor_log(); + DV v; + test2_set_ownership (v, testClearIndex); + for (int i=0; i<N; i++) + v.push_back (new T(i)); + std::vector<const T*> v2 (v.begin(), v.end()); + typename DV::iterator it = + std::remove_if (v.begin(), v.end(), Pred<T>(5)); + myassert (it - v.begin() == N-1); + int j=0; + for (int i=0; i<N-1; i++, j++) { + if (j == 5) ++j; + myassert (v[i]->x == j); + } + myassert (v[N-1] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[5]); + } + else { + check_dtor_log (5); + } + + it = std::remove_if (v.begin(), v.end()-1, Pred<T>(9)); + myassert (it - v.begin() == N-2); + j=0; + for (int i=0; i<N-2; i++, j++) { + if (j == 5) ++j; + if (j == 9) ++j; + myassert (v[i]->x == j); + } + myassert (v[N-2] == 0); + myassert (v[N-1] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[9]); + for (size_t i = 0; i < v2.size(); i++) delete v2[i]; + } + else { + check_dtor_log (9); + } + } + + { + clear_dtor_log(); + DV v; + test2_set_ownership (v, testClearIndex); + for (int i=0; i<N; i++) + v.push_back (new T(i)); + std::vector<const T*> v2 (v.begin(), v.end()); + typename DV::reverse_iterator it = + std::remove (v.rbegin(), v.rend(), v[5]); + myassert (it - v.rbegin() == N-1); + int j=0; + for (int i=1; i<N; i++, j++) { + if (j == 5) ++j; + myassert (v[i]->x == j); + } + myassert (v[0] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[5]); + } + else { + check_dtor_log (5); + } + + it = std::remove (v.rbegin(), v.rend()-1, v[8]); + myassert (it - v.rbegin() == N-2); + j=0; + for (int i=2; i<N; i++, j++) { + if (j == 5) ++j; + if (j == 8) ++j; + myassert (v[i]->x == j); + } + myassert (v[0] == 0); + myassert (v[1] == 0); + CHECK_INDICES(v); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[8]); + for (size_t i = 0; i < v2.size(); i++) delete v2[i]; + } + else { + check_dtor_log (8); + } + } + + { + clear_dtor_log(); + DV v; + test2_set_ownership (v, testClearIndex); + for (int i=0; i<N; i++) + v.push_back (new T(i)); + std::vector<const T*> v2 (v.begin(), v.end()); + typename DV::reverse_iterator it = + std::remove_if (v.rbegin(), v.rend(), Pred<T>(5)); + myassert (it - v.rbegin() == N-1); + int j=0; + for (int i=1; i<N; i++, j++) { + if (j == 5) ++j; + myassert (v[i]->x == j); + } + myassert (v[0] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[5]); + } + else { + check_dtor_log (5); + } + + it = std::remove_if (v.rbegin(), v.rend()-1, Pred<T>(8)); + myassert (it - v.rbegin() == N-2); + j=0; + for (int i=2; i<N; i++, j++) { + if (j == 5) ++j; + if (j == 8) ++j; + myassert (v[i]->x == j); + } + myassert (v[0] == 0); + myassert (v[1] == 0); + CHECK_INDICES(v); + if (testClearIndex) { + CHECK_INDEX_CLEAR(v2[8]); + for (size_t i = 0; i < v2.size(); i++) delete v2[i]; + } + else { + check_dtor_log (8); + } + } +} +template <class DV> +void test2_remove2 (bool testClearIndex) +{ + const int N=10; + typedef typename DV::base_value_type T; + test2_remove1<DV> (testClearIndex); + DV v1; + SG::AuxStoreInternal store1; + for (int i=0; i<N; i++) + v1.push_back (new T(i)); + setaux (v1, store1); + checkaux(v1); + CHECK_INDICES(v1); + + DV v2 = v1; + std::remove (v2.begin(), v2.end(), v2[5]); + checkaux(v1); + CHECK_INDICES(v1); + + std::remove (v1.begin(), v1.end(), v1[5]); + checkaux(v1); + CHECK_INDICES(v1); + for (int i=0, j=0; i < N-1; i++, j++) { + if (j == 5) ++j; + assert (v1[i]->x == j); + } + assert (v1[N-1] == 0); + checkauxZero (v1, N-1); + + v2 = v1; + std::remove_if (v2.begin(), v2.end()-1, Pred<T>(3)); + checkaux(v1); + CHECK_INDICES(v1); + + std::remove_if (v1.begin(), v1.end()-1, Pred<T>(3)); + checkaux(v1); + CHECK_INDICES(v1); + for (int i=0, j=0; i < N-2; i++, j++) { + if (j == 3) ++j; + if (j == 5) ++j; + assert (v1[i]->x == j); + } + assert (v1[N-2] == 0); + assert (v1[N-1] == 0); + checkauxZero (v1, N-2); + checkauxZero (v1, N-1); + // 0 1 2 4 6 7 8 9 x x + + v2 = v1; + std::remove (v2.rbegin()+2, v2.rend(), v2[4]); + checkaux(v1); + CHECK_INDICES(v1); + + std::remove (v1.rbegin()+2, v1.rend(), v1[4]); + checkaux(v1); + CHECK_INDICES(v1); + for (int i=1, j=0; i < N-2; i++, j++) { + if (j == 3) ++j; + if (j == 5) ++j; + if (j == 6) ++j; + assert (v1[i]->x == j); + } + assert (v1[0] == 0); + assert (v1[N-2] == 0); + assert (v1[N-1] == 0); + checkauxZero (v1, 0); + checkauxZero (v1, N-2); + checkauxZero (v1, N-1); + // x 0 1 2 4 7 8 9 x x + + v2 = v1; + std::remove_if (v2.rbegin()+2, v2.rend()-1, Pred<T>(7)); + checkaux(v1); + CHECK_INDICES(v1); + + std::remove_if (v1.rbegin()+2, v1.rend()-1, Pred<T>(7)); + checkaux(v1); + CHECK_INDICES(v1); + for (int i=2, j=0; i < N-2; i++, j++) { + if (j == 3) ++j; + if (j == 5) ++j; + if (j == 6) ++j; + if (j == 7) ++j; + assert (v1[i]->x == j); + } + assert (v1[0] == 0); + assert (v1[1] == 0); + assert (v1[N-2] == 0); + assert (v1[N-1] == 0); + checkauxZero (v1, 1); + checkauxZero (v1, N-2); + checkauxZero (v1, N-1); + // x x 0 1 2 4 8 9 x x + + v1.setStore (v1.getConstStore()); + bool caught = false; + try { + std::remove (v1.begin(), v1.end(), v1[2]); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); +} +template <class B, class D> +void test2_remove() +{ + test2_remove2<DataVector<B> > (false); + test2_remove2<DataVector<D> > (false); + test2_remove2<DataVector<B> > (true); + test2_remove2<DataVector<D> > (true); + test2_remove1<DataVector<typename test2_maybeconst<D>::type> > (false); + test2_remove1<ConstDataVector<DataVector<D> > > (false); +} + +template <class T> +struct BPred +{ + bool operator() (const T* a, const T* b) const + { return a->x == b->x; } +}; +template <class DV> +void test2_unique1() +{ + typedef typename DV::base_value_type T; + { + DV v (SG::VIEW_ELEMENTS); + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (v.back()); + v.push_back (new T(2)); + typename DV::iterator it = std::unique (v.begin(), v.end()); + myassert (it - v.begin() == 3); + for (int i = 0; i < 3; i++) + myassert (v[i]->x == i); + myassert (v[3] == 0); + CHECK_INDICES(v); + } + + { + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v.push_back (new T(3)); + setaux (v, store); + checkaux(v); + CHECK_INDICES(v); + + DV v2 = v; + std::unique (v2.begin(), v2.end(), BPred<T>()); + checkaux(v); + CHECK_INDICES(v); + + typename DV::iterator it = + std::unique (v.begin(), v.end(), BPred<T>()); + myassert (it - v.begin() == 4); + for (int i = 0; i < 4; i++) + myassert (v[i]->x == i); + myassert (v[4] == 0); + myassert (v[5] == 0); + checkauxZero (v, 4); + checkauxZero (v, 5); + check_dtor_log (1, 3); + checkaux(v); + CHECK_INDICES(v); + } + + { + clear_dtor_log(); + DV v (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store; + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v.push_back (new T(3)); + setaux (v, store); + checkaux(v); + CHECK_INDICES(v); + + std::vector<T*> v2 (v.begin(), v.end()); + typename DV::iterator it = + std::unique (v.begin(), v.end(), BPred<T>()); + myassert (it - v.begin() == 4); + for (int i = 0; i < 4; i++) + myassert (v[i]->x == i); + myassert (v[4] == 0); + myassert (v[5] == 0); + checkauxZero (v, 4); + checkauxZero (v, 5); + check_dtor_log (); + checkaux(v); + CHECK_INDICES(v); + CHECK_INDEX_CLEAR (v2[2]); + CHECK_INDEX_CLEAR (v2[5]); + for (size_t i = 0; i < v2.size(); i++) delete v2[i]; + clear_dtor_log(); + } + + { + DV v (SG::VIEW_ELEMENTS); + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (v.back()); + v.push_back (new T(2)); + CHECK_INDICES(v); + + typename DV::reverse_iterator it = + std::unique (v.rbegin(), v.rend()); + myassert (it - v.rbegin() == 3); + for (int i = 1; i < 3; i++) + myassert (v[i]->x == i-1); + myassert (v[0] == 0); + CHECK_INDICES(v); + } + + { + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v.push_back (new T(3)); + setaux (v, store); + checkaux(v); + CHECK_INDICES(v); + + typename DV::reverse_iterator it = + std::unique (v.rbegin(), v.rend(), BPred<T>()); + myassert (it - v.rbegin() == 4); + for (int i = 2; i < 6; i++) + myassert (v[i]->x == i-2); + myassert (v[0] == 0); + myassert (v[1] == 0); + checkauxZero (v, 0); + checkauxZero (v, 1); + check_dtor_log (1, 3); + checkaux(v); + CHECK_INDICES(v); + } + + { + clear_dtor_log(); + DV v (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store; + v.push_back (new T(0)); + v.push_back (new T(1)); + v.push_back (new T(1)); + v.push_back (new T(2)); + v.push_back (new T(3)); + v.push_back (new T(3)); + setaux (v, store); + checkaux(v); + CHECK_INDICES(v); + std::vector<T*> v2 (v.begin(), v.end()); + + typename DV::reverse_iterator it = + std::unique (v.rbegin(), v.rend(), BPred<T>()); + myassert (it - v.rbegin() == 4); + for (int i = 2; i < 6; i++) + myassert (v[i]->x == i-2); + myassert (v[0] == 0); + myassert (v[1] == 0); + check_dtor_log (); + checkauxZero (v, 0); + checkauxZero (v, 1); + checkaux(v); + CHECK_INDICES(v); + CHECK_INDEX_CLEAR (v2[1]); + CHECK_INDEX_CLEAR (v2[4]); + for (size_t i = 0; i < v2.size(); i++) delete v2[i]; + clear_dtor_log(); + } + + { + DV v (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store; + v.push_back (new T(1)); + v.push_back (new T(1)); + setaux (v, store); + v.setStore (v.getConstStore()); + bool caught = false; + try { + std::unique (v.begin(), v.end(), BPred<T>()); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + } +} +template <class DV> +void test2_unique2() +{ + test2_unique1<DV>(); +} +template <class B, class D> +void test2_unique() +{ + test2_unique2<DataVector<B> > (); + test2_unique2<DataVector<D> > (); +} + +template <class DV> +void test2_reverse() +{ + typedef typename DV::base_value_type T; + int N=5; + { + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::reverse (v2.begin(), v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::reverse (v.begin(), v.end()); + for (int i=0; i<N; i++) + myassert (v[i]->x == N-1-i); + CHECK_INDICES(v); + checkaux(v); + + std::reverse (v2.rbegin(), v2.rend()); // Check that this doesn't affect v's auxdata. + checkaux(v); + + std::reverse (v.rbegin(), v.rend()); + for (int i=0; i<N; i++) + myassert (v[i]->x == i); + check_dtor_log (); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::reverse (v3.begin(), v3.end()); + CHECK_INDICES(v3); + std::reverse (v3.rbegin(), v3.rend()); + CHECK_INDICES(v3); + + v.setStore (v.getConstStore()); + bool caught = false; + try { + std::reverse (v.begin(), v.end()); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } +} +template <class B, class D> +void test2_reverse() +{ + test2_reverse<DataVector<B> > (); + test2_reverse<DataVector<D> > (); + test2_reverse<DataVector<typename test2_maybeconst<D>::type> > (); + test2_reverse<ConstDataVector<DataVector<D> > > (); +} + + +template <class DV> +void test2_rotate() +{ + typedef typename DV::base_value_type T; + const int N=5; + { + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::rotate (v2.begin(), v2.begin()+2, v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::rotate (v.begin(), v.begin()+2, v.end()); + for (int i=0; i<N; i++) + myassert (v[i]->x == (i+2)%5); + CHECK_INDICES(v); + checkaux(v); + + std::rotate (v2.rbegin(), v2.rbegin()+2, v2.rend()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::rotate (v.rbegin(), v.rbegin()+2, v.rend()); + for (int i=0; i<N; i++) + myassert (v[i]->x == i); + check_dtor_log(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::rotate (v3.begin(), v3.begin()+2, v3.end()); + CHECK_INDICES(v3); + std::rotate (v3.rbegin(), v3.rbegin()+2, v3.rend()); + CHECK_INDICES(v3); + + v.setStore (v.getConstStore()); + bool caught = false; + try { + std::rotate (v.begin(), v.begin()+2, v.end()); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } +} +template <class B, class D> +void test2_rotate() +{ + test2_rotate<DataVector<B> > (); + test2_rotate<DataVector<D> > (); + test2_rotate<DataVector<typename test2_maybeconst<D>::type> > (); + test2_rotate<ConstDataVector<DataVector<D> > > (); +} + + +template <class DV> +void test2_random_shuffle() +{ + typedef typename DV::base_value_type T; + const int N=5; + { + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::random_shuffle (v2.begin(), v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::random_shuffle (v.begin(), v.end()); + CHECK_INDICES(v); + checkaux(v); + std::random_shuffle (v2.begin(), v2.end()); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::random_shuffle (v.rbegin(), v.rend()); + check_dtor_log(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::random_shuffle (v3.begin(), v3.end()); + CHECK_INDICES(v3); + std::random_shuffle (v3.rbegin(), v3.rend()); + CHECK_INDICES(v3); + } + + { + int exp1[N] = {1,2,3,4,0}; + int exp2[N] = {0,2,1,3,4}; + + stlrand.seed = 1; + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + DV v2(v); + std::random_shuffle (v2.begin(), v2.end(), stlrand2); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::random_shuffle (v.begin(), v.end(), stlrand); + for (int i=0; i<N; i++) + myassert (v[i]->x == exp1[i]); + CHECK_INDICES(v); + checkaux(v); + + std::random_shuffle (v2.rbegin(), v2.rend(), stlrand2); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::random_shuffle (v.rbegin(), v.rend(), stlrand); + for (int i=0; i<N; i++) + myassert (v[i]->x == exp2[i]); + check_dtor_log(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::random_shuffle (v3.begin(), v3.end(), stlrand); + CHECK_INDICES(v3); + std::random_shuffle (v3.rbegin(), v3.rend(), stlrand); + CHECK_INDICES(v3); + + v.setStore (v.getConstStore()); + bool caught = false; + try { + std::random_shuffle (v.begin(), v.end(), stlrand); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } + +#if __cplusplus > 201100 + { + int exp1[N] = {1,2,3,4,0}; + int exp2[N] = {0,2,1,3,4}; + + stlurand.seed = 1; + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (CxxUtils::make_unique<T>(i)); + setaux(v, store); + DV v2(v); + std::shuffle (v2.begin(), v2.end(), stlurand2); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::shuffle (v.begin(), v.end(), stlurand); + for (int i=0; i<N; i++) + myassert (v[i]->x == exp1[i]); + CHECK_INDICES(v); + checkaux(v); + + std::shuffle (v2.rbegin(), v2.rend(), stlurand2); // Check that this doesn't affect v's auxdata. + checkaux(v); + std::shuffle (v.rbegin(), v.rend(), stlurand); + for (int i=0; i<N; i++) + myassert (v[i]->x == exp2[i]); + check_dtor_log(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (CxxUtils::make_unique<T>(i)); + std::shuffle (v3.begin(), v3.end(), stlurand); + CHECK_INDICES(v3); + std::shuffle (v3.rbegin(), v3.rend(), stlurand); + CHECK_INDICES(v3); + + v.setStore (v.getConstStore()); + bool caught = false; + try { + std::shuffle (v.begin(), v.end(), stlurand); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } +#endif +} +template <class B, class D> +void test2_random_shuffle() +{ + test2_random_shuffle<DataVector<B> > (); + test2_random_shuffle<DataVector<D> > (); + test2_random_shuffle<DataVector<typename test2_maybeconst<D>::type> > (); + test2_random_shuffle<ConstDataVector<DataVector<D> > > (); +} + + +template <class T> +struct PPred +{ + PPred (int the_v) : v (the_v) {} + bool operator() (const T* a) const + { return a->x < v; } + int v; +}; +template <class DV> +void test2_partition() +{ + typedef typename DV::base_value_type T; + const int N=10; + { + stlrand.seed = 2; + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + std::random_shuffle (v.begin(), v.end(), stlrand); + CHECK_INDICES(v); + checkaux(v); + DV v2(v); + std::partition (v2.begin(), v2.end(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + checkaux(v); + typename DV::iterator it = + std::partition (v.begin(), v.end(), PPred<T>(5)); + for (int i=0; i < it-v.begin(); i++) + myassert (v[i]->x < 5); + for (int i=it-v.begin(); i<N; i++) + myassert (v[i]->x >= 5); + CHECK_INDICES(v); + checkaux(v); + + std::random_shuffle (v.begin(), v.end(), stlrand); + CHECK_INDICES(v); + std::random_shuffle (v2.begin(), v2.end(), stlrand2); + std::partition (v2.rbegin(), v2.rend(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + checkaux(v); + typename DV::reverse_iterator rit = + std::partition (v.rbegin(), v.rend(), PPred<T>(5)); + for (int i=0; i < rit-v.rbegin(); i++) + myassert (v[N-1-i]->x < 5); + for (int i=rit-v.rbegin(); i<N; i++) + myassert (v[N-1-i]->x >= 5); + check_dtor_log(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::random_shuffle (v3.begin(), v3.end(), stlrand2); + std::partition (v3.begin(), v3.end(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + CHECK_INDICES(v3); + std::random_shuffle (v3.begin(), v3.end(), stlrand2); + std::partition (v3.rbegin(), v3.rend(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + CHECK_INDICES(v3); + + v.setStore (v.getConstStore()); + bool caught = false; + try { + std::partition (v.begin(), v.end(), PPred<T>(5)); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + } + + { + stlrand.seed = 3; + clear_dtor_log(); + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + std::random_shuffle (v.begin(), v.end(), stlrand); + CHECK_INDICES(v); + checkaux(v); + DV v2(v); + std::stable_partition (v2.begin(), v2.end(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + checkaux(v); + typename DV::iterator it = + std::stable_partition (v.begin(), v.end(), PPred<T>(5)); + for (int i=0; i < it-v.begin(); i++) + myassert (v[i]->x < 5); + for (int i=it-v.begin(); i<N; i++) + myassert (v[i]->x >= 5); + CHECK_INDICES(v); + checkaux(v); + + std::random_shuffle (v.begin(), v.end(), stlrand); + CHECK_INDICES(v); + std::random_shuffle (v2.begin(), v2.end(), stlrand2); + std::stable_partition (v2.rbegin(), v2.rend(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + checkaux(v); + typename DV::reverse_iterator rit = + std::stable_partition (v.rbegin(), v.rend(), PPred<T>(5)); + for (int i=0; i < rit-v.rbegin(); i++) + myassert (v[N-1-i]->x < 5); + for (int i=rit-v.rbegin(); i<N; i++) + myassert (v[N-1-i]->x >= 5); + check_dtor_log(); + CHECK_INDICES(v); + checkaux(v); + + DV v3; + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + std::random_shuffle (v3.begin(), v3.end(), stlrand2); + std::stable_partition (v3.begin(), v3.end(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + CHECK_INDICES(v3); + std::random_shuffle (v3.begin(), v3.end(), stlrand2); + std::stable_partition (v3.rbegin(), v3.rend(), PPred<T>(5)); // Check that this doesn't affect v's auxdata. + CHECK_INDICES(v3); + } +} +template <class B, class D> +void test2_partition() +{ + test2_partition<DataVector<B> > (); + test2_partition<DataVector<D> > (); + test2_partition<DataVector<typename test2_maybeconst<D>::type> > (); + test2_partition<ConstDataVector<DataVector<D> > > (); +} + + +template <class D> +void test2_asdatavector() +{ + ConstDataVector<DataVector<D> > cv; + cv.push_back (new D(1)); + const DataVector<D>* dv = cv.asDataVector(); + myassert (dv->size() == 1); +} + + +template <class DV> +void test2_assignelement1() +{ + typedef typename DV::base_value_type T; + clear_dtor_log(); + DV v; + v.push_back (new T(1)); + v.push_back (new T(2)); + CHECK_INDICES(v); + v.assignElement ((v.begin()+1).base(), new T(3)); + check_dtor_log (2); + CHECK_INDICES(v); + v.assignElement ((v.begin()+1).base(), new T(4)); + check_dtor_log (3); + CHECK_INDICES(v); +#if __cplusplus > 201100 + v.assignElement ((v.begin()+1).base(), CxxUtils::make_unique<T>(5)); + check_dtor_log (4); + CHECK_INDICES(v); + + DV v2 (SG::VIEW_ELEMENTS); + v2.push_back (new T(11)); + v2.push_back (new T(12)); + EXPECT_EXCEPTION (SG::ExcNonowningContainer, + v2.assignElement ((v2.begin()+1).base(), CxxUtils::make_unique<T>(15))); +#endif +} +template <class DV> +void test2_assignelement2() +{ + test2_assignelement1<DV>(); + typedef typename DV::base_value_type T; + + clear_dtor_log(); + DV v (SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES); + SG::AuxStoreInternal store; + v.push_back (new T(1)); + v.push_back (new T(2)); + setaux (v, store); + CHECK_INDICES(v); + checkaux (v); + T* t1 = v[1]; + T* t3 = make_comp<T>(3); + v.assignElement ((v.begin()+1).base(), t3); + check_dtor_log (); + releasePrivateStore(t3); + CHECK_INDICES(v); + checkaux (v); + CHECK_INDEX_CLEAR (t1); + T* t4 = make_comp<T>(4); + v.assignElement ((v.begin()+1).base(), t4); + check_dtor_log (); + CHECK_INDICES(v); + checkaux(v); + CHECK_INDEX_CLEAR (t3); + + v.assignElement ((v.begin()+1).base(), 0); + CHECK_INDICES(v); + checkaux(v); + checkauxZero (v, 1); + CHECK_INDEX_CLEAR (t4); + + T* t5 = make_comp<T>(5); + v.setStore (v.getConstStore()); + bool caught = false; + try { + v.assignElement ((v.begin()+1).base(), t5); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || !typename SG::AuxStore_traits<T>::flag()); + + delete t3; + delete t4; + delete t5; +} +template <class B, class D> +void test2_assignelement() +{ + test2_assignelement2<DataVector<B> > (); + test2_assignelement2<DataVector<D> > (); + test2_assignelement1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_assignelement1<ConstDataVector<DataVector<D> > > (); +} + +template <class DV> +void test2_swapranges() +{ + clear_dtor_log(); + + typedef typename DV::base_value_type T; + DV v1; + DV v2; + SG::AuxStoreInternal store1; + SG::AuxStoreInternal store2; + for (int i = 0; i < 10; i++) { + v1.push_back (new T(i)); + v2.push_back (new T(i+10)); + } + setaux(v1, store1); + setaux(v2, store2); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + checkaux(v1); + checkaux(v2); + + std::swap_ranges (v1.begin()+3, v1.begin()+6, v2.begin()+4); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + checkaux(v1); + checkaux(v2); + + std::swap_ranges (v1.rbegin()+3, v1.rbegin()+6, v2.rbegin()+4); + CHECK_INDICES(v1); + CHECK_INDICES(v2); + checkaux(v1); + checkaux(v2); + + DV v3 = v1; + std::swap_ranges (v3.begin(), v3.begin()+2, v3.begin()+4); + CHECK_INDICES(v1); + checkaux(v1); + + v1.setStore (v1.getConstStore()); + bool caught = false; + try { + std::swap_ranges (v1.begin()+3, v1.begin()+6, v2.begin()+4); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v1.trackIndices()); + + check_dtor_log(); +} +template <class B, class D> +void test2_swapranges() +{ + test2_swapranges<DataVector<B> > (); + test2_swapranges<DataVector<D> > (); + test2_swapranges<DataVector<typename test2_maybeconst<D>::type> > (); + test2_swapranges<ConstDataVector<DataVector<D> > > (); +} + +template <class DV> +typename DV::BaseContainer& test2_resortaux_ptrvector (DV& v) +{ + return const_cast<typename DV::BaseContainer&>(v.stdcont()); +} +template <class DV> +typename DV::BaseContainer& test2_resortaux_ptrvector (ConstDataVector<DV>& v) +{ + return const_cast<typename DV::BaseContainer&>(v.asDataVector()->stdcont()); +} +template <class DV> +void test2_resortaux1() +{ + typedef typename DV::base_value_type T; + const int N=10; + stlrand.seed = 2; + + DV v; + SG::AuxStoreInternal store; + for (int i=0; i<N; i++) + v.push_back (new T(i)); + setaux(v, store); + + typename DV::BaseContainer& pv = test2_resortaux_ptrvector (v); + + for (int j=0; j < 10; j++) { + std::random_shuffle (pv.begin(), pv.end(), stlrand); + v.resortAux (v.begin(), v.end()); + CHECK_INDICES(v); + checkaux(v); + } + for (int j=0; j < 10; j++) { + std::random_shuffle (pv.begin()+2, pv.end()-2, stlrand); + v.resortAux (v.begin()+2, v.end()-2); + CHECK_INDICES(v); + checkaux(v); + } + + DV v2(v); + typename DV::BaseContainer& pv2 = test2_resortaux_ptrvector (v2); + for (int j=0; j < 10; j++) { + std::random_shuffle (pv2.begin(), pv2.end(), stlrand); + v.resortAux (v2.begin(), v2.end()); + CHECK_INDICES(v); + checkaux(v); + } + + DV v3; + typename DV::BaseContainer& pv3 = test2_resortaux_ptrvector (v3); + for (int i=0; i<N; i++) + v3.push_back (new T(i)); + for (int j=0; j < 10; j++) { + std::random_shuffle (pv3.begin(), pv3.end(), stlrand); + v3.resortAux (v3.begin(), v3.end()); + CHECK_INDICES(v3); + } + + v.setStore (v.getConstStore()); + bool caught = false; + try { + v.resortAux (v.begin(), v.end()); + } + catch (SG::ExcConstAuxData&) { + caught = true; + } + myassert (caught || + !typename SG::AuxStore_traits<T>::flag() || + !v.trackIndices()); + +} +template <class B, class D> +void test2_resortaux() +{ + test2_resortaux1<DataVector<B> > (); + test2_resortaux1<DataVector<D> > (); + test2_resortaux1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_resortaux1<ConstDataVector<DataVector<D> > > (); +} + +template <class DV> +void test2_move1() +{ +#if __cplusplus > 201100 + typedef typename DV::base_value_type T; + + clear_dtor_log(); + { + DV v1; + SG::AuxStoreInternal store1; + v1.push_back (CxxUtils::make_unique<T>(1)); + v1.push_back (CxxUtils::make_unique<T>(2)); + v1.push_back (CxxUtils::make_unique<T>(3)); + setaux (v1, store1); + checkaux (v1); + CHECK_INDICES (v1); + + DV v2 (std::move (v1)); + assert (v2.size() == 3); + assert (v2[0]->x == 1); + assert (v2[1]->x == 2); + assert (v2[2]->x == 3); + checkaux (v2); + CHECK_INDICES (v2); + v2.push_back (make_comp_unique<T>(4)); + + assert (v1.size() == 0); + + DV v3; + v3 = std::move (v2); + assert (v3.size() == 4); + assert (v3[0]->x == 1); + assert (v3[1]->x == 2); + assert (v3[2]->x == 3); + assert (v3[3]->x == 4); + checkaux (v3); + CHECK_INDICES (v3); + v3.push_back (make_comp_unique<T>(5)); + + assert (v2.size() == 0); + + check_dtor_log(); + } + clear_dtor_log(); +#endif +} +template <class B, class D> +void test2_move() +{ + test2_move1<DataVector<B> > (); + test2_move1<DataVector<D> > (); + test2_move1<DataVector<typename test2_maybeconst<D>::type> > (); + test2_move1<ConstDataVector<DataVector<D> > > (); +} + + +template <class B, class D> +void test2_offset() +{ + typedef DataVector<B> DVB; + typedef DataVector<D> DVD; + assert (DVB::baseOffset (typeid(DVB)) == 0); + assert (DVB::baseOffset (typeid(DVD)) == -1); + DVD vd; + DVB& vb = vd; + int offs = reinterpret_cast<char*>(&vb) - reinterpret_cast<char*>(&vd); + assert (DVD::baseOffset (typeid(DVD)) == 0); + assert (DVD::baseOffset (typeid(DVB)) == offs); + assert (DVD::baseOffset (typeid(int)) == -1); +} + + +template <class B, class D> +void test2_elconversions1() +{ + DataVector<D> v1; + for (int i=0; i<5; i++) + v1.push_back (CxxUtils::make_unique<D>(i)); + DataVector<D> v2; + for (int i=5; i<10; i++) + v2.push_back (CxxUtils::make_unique<D>(i)); + + SGTest::TestStore store; + SG::CurrentEventStore::setStore (&store); + store.record (&v1, "v1"); + store.record (&v2, "v2"); + + std::vector<ElementLink<DataVector<D> > > links; + for (int i=0; i<5; i++) { + links.emplace_back ("v1", i); + links.emplace_back ("v2", i); + } + + std::vector<ElementLink<DataVector<D> > > links2; + for (int i=0; i<5; i++) { + links2.emplace_back ("v2", i); + links2.emplace_back ("v1", i); + } + + ConstDataVector<DataVector<B> > dv (links); + for (int i=0; i<5; i++) { + assert (dv[i*2] == v1[i]); + assert (dv[i*2+1] == v2[i]); + } + + ConstDataVector<DataVector<B> > dv2; + dv2.assign (links2); + for (int i=0; i<5; i++) { + assert (dv2[i*2] == v2[i]); + assert (dv2[i*2+1] == v1[i]); + } +} + + +template <class B, class D> +void test2_elconversions() +{ + test2_elconversions1<B,B>(); + test2_elconversions1<D,D>(); + test2_elconversions1<B,D>(); +} + + +template <class B, class D> +void do_test2() +{ + boost::function_requires<boost::ForwardContainerConcept<DataVector<B> > >(); + boost::function_requires<boost::ForwardContainerConcept<DataVector<D> > >(); + + test2_initial<B,D> (); + test2_default_ctor<B,D> (); + test2_sized_ctor<B,D> (); + test2_insertion_ctor<B,D> (); + test2_copy_ctor<B,D> (); + test2_dtor<B,D> (); + test2_push_back<B,D> (); + test2_operator_index_const<B,D> (); + test2_at_const<B,D> (); + test2_size<B,D> (); + test2_stdcont<B,D> (); + test2_empty<B,D> (); + test2_reserve_capacity<B,D> (); + test2_max_size<B,D> (); + test2_front_back_const<B,D> (); + test2_begin_end_const<B,D> (); + test2_rbegin_rend_const<B,D> (); + test2_elementproxy<B,D> (); + test2_operator_index<B,D> (); + test2_at<B,D> (); + test2_swapelement<B,D> (); + test2_swapelement_unique<B,D> (); + test2_swapelement_iter<B,D> (); + test2_swapelement_iter_unique<B,D> (); + test2_resize<B,D> (); + test2_pop_back<B,D> (); + test2_front_back<B,D> (); + test2_begin_end<B,D> (); + test2_rbegin_rend<B,D> (); + test2_erase_range<B,D> (); + test2_erase_single<B,D> (); + test2_operator_assign<B,D> (); + test2_insert_value<B,D> (); + test2_insert_range<B,D> (); + test2_insertMove<B,D> (); + test2_clear<B,D> (); + test2_swap<B,D> (); + test2_assign<B,D> (); + test2_relops<B,D> (); + test2_sort<B,D> (); + test2_inplace_merge<B,D> (); + test2_iter_swap_memb<B,D> (); + test2_iter_swap<B,D> (); + test2_remove<B,D> (); + test2_unique<B,D> (); + test2_reverse<B,D> (); + test2_rotate<B,D> (); + test2_random_shuffle<B,D> (); + test2_partition<B,D> (); + test2_asdatavector<D> (); + test2_assignelement<B,D> (); + test2_swapranges<B,D> (); + test2_resortaux<B,D> (); + test2_move<B,D> (); + test2_offset<B,D> (); + test2_elconversions<B,D>(); +} + + +template <class T> +void dump_classid() +{ + typedef ClassID_traits<DataVector<T> > traits; + std::cout << "name: " << traits::typeName() << "\n"; + std::cout << " clid, vers, is_do: " + << std::hex << traits::ID() << std::dec << " " + << traits::s_version << " " + << traits::s_isDataObject << "\n"; +} + + diff --git a/EDM/athena/Control/AthContainers/test/ElementProxy_test.cxx b/EDM/athena/Control/AthContainers/test/ElementProxy_test.cxx new file mode 100644 index 00000000..6589ab34 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/ElementProxy_test.cxx @@ -0,0 +1,308 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ElementProxy_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file ElementProxy_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2010 + * @brief Regression tests for ElementProxy. + */ + + +#undef NDEBUG + + +//*************************************************************************** +// Change assertions failures to exceptions, so we can catch them. +// + +#include <string> +#include <stdexcept> +#include <sstream> + +class test_err + : public std::exception +{ +public: + explicit test_err (const char* file, + int line, + const char* what); + virtual ~test_err() throw() {} + virtual const char* what() const throw() { return m_what.c_str(); } +private: + std::string m_what; +}; + + +test_err::test_err (const char* file, + int line, + const char* what) +{ + std::ostringstream os; + os << file << ":" << line << " assertion failure: " << what; + m_what = os.str(); +} + + +void throw_test_err (const char* file, int line, const char* what) +{ + throw (test_err (file, line, what)); +} + +#define ATHCONTAINERS_ASSERT(X) do { \ + if (!(X)) { \ + throw_test_err (__FILE__, __LINE__, #X); \ + } \ + } while (0) + +//*************************************************************************** + + + +#include "AthContainers/tools/ElementProxy.h" +#include "AthContainers/exceptions.h" +#include "CxxUtils/make_unique.h" +#include "TestTools/expect_exception.h" +#include <vector> +#include <cassert> + + +#if __cplusplus > 201100 +using CxxUtils::make_unique; +#endif + + +std::vector<int> dtor_log; + + +struct A +{ + virtual ~A() {} +}; +struct B : public A +{ + B(int the_x) : x(the_x) {} + ~B() { dtor_log.push_back(x); } + int x; +}; + + +void check_dtor (int x = -1) +{ + if (x == -1) + assert (dtor_log.size() == 0); + else { + assert (dtor_log.size() == 1); + assert (dtor_log[0] == x); + dtor_log.clear(); + } +} + + +struct Cont + : public std::vector<A*> +{ + typedef std::vector<A*> BaseContainer; + typedef B* value_type; + typedef B base_value_type; + typedef value_type& reference; + static const bool has_virtual = false; + + Cont (SG::OwnershipPolicy ownPolicy = SG::OWN_ELEMENTS, + bool can_insert_p = false) + : m_ownPolicy (ownPolicy), + m_can_insert (can_insert_p) + { + } + + void swapBaseElement(BaseContainer::iterator pos, A* newElem, A*& oldElem) + { + oldElem = dynamic_cast<B*> (*pos); + *pos = newElem; + } + + void assignElement (BaseContainer::iterator pos, + value_type newElem) + { + ATHCONTAINERS_ASSERT (m_can_insert); + BaseContainer::value_type old = *pos; + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete old; + *pos = newElem; + } + +#if __cplusplus > 201100 + void assignElement (BaseContainer::iterator pos, + std::unique_ptr<base_value_type> newElem) + { + ATHCONTAINERS_ASSERT (m_can_insert); + ATHCONTAINERS_ASSERT (this->m_ownPolicy == SG::OWN_ELEMENTS); + BaseContainer::value_type old = *pos; + delete old; + *pos = newElem.release(); + } +#endif + + void assignBaseElement (BaseContainer::iterator pos, + BaseContainer::value_type newElem) + { + ATHCONTAINERS_ASSERT (m_can_insert); + BaseContainer::value_type old = *pos; + if (this->m_ownPolicy == SG::OWN_ELEMENTS) + delete old; + *pos = newElem; + } + + SG::OwnershipPolicy ownPolicy() const { return m_ownPolicy; } + bool can_insert() const { return m_can_insert; } + + SG::OwnershipPolicy m_ownPolicy; + bool m_can_insert; +}; + + +// own/cannot insert +void test1() +{ + Cont v; + B* b1 = new B(1); + v.push_back (b1); + B* b2 = new B(2); + v.push_back (b2); + + typedef DataModel_detail::ElementProxy<Cont> EP; + EP ep1 (v.begin(), &v); + assert ((B*)ep1 == b1); + assert (ep1->x == 1); + ep1 = b1; + assert (ep1->x == 1); + assert (ep1.container() == &v); + + EP ep1a (v.begin(), &v); + ep1 = ep1a; + assert (ep1->x == 1); + + bool caught = false; + try { + ep1 = b2; + } + catch (test_err&) { + caught = true; + } + assert (caught); + + EP ep2 (v.begin()+1, &v); + caught = false; + try { + ep1 = ep2; + } + catch (test_err&) { + caught = true; + } + assert (caught); + + check_dtor(); +} + + +// own/can insert +void test2() +{ + Cont v (SG::OWN_ELEMENTS, true); + B* b1 = new B(1); + v.push_back (b1); + B* b2 = new B(2); + v.push_back (b2); + B* b3 = new B(3); + v.push_back (b3); + + typedef DataModel_detail::ElementProxy<Cont> EP; + EP ep1 (v.begin(), &v); + assert (ep1->x == 1); + check_dtor(); + ep1 = b1; + assert (ep1->x == 1); + check_dtor(); + ep1 = b2; + assert (ep1->x == 2); + check_dtor(1); + + EP ep2 (v.begin()+1, &v); + ep1 = ep2; + assert (ep1->x == 2); + check_dtor(); + + EP ep3 (v.begin()+2, &v); + bool caught = false; + try { + ep1 = ep3; + } + catch (test_err&) { + caught = true; + } + assert (caught); + + Cont v2 (SG::VIEW_ELEMENTS, true); + v2.push_back (new B(1)); + v2.push_back (new B(2)); + v2.push_back (new B(3)); + EP ep3a (v2.begin()+2, &v2); + ep1 = ep3a; + assert (ep1->x == 3); + check_dtor(2); + +#if __cplusplus > 201100 + ep1 = make_unique<B> (4); + assert (ep1->x == 4); + check_dtor(3); + EP ep3b (v2.begin()+1, &v2); + EXPECT_EXCEPTION (test_err, + ep3b = make_unique<B> (10)); + check_dtor(10); +#endif +} + + +// unowned/can insert +void test3() +{ + Cont v (SG::VIEW_ELEMENTS, true); + B* b1 = new B(1); + v.push_back (b1); + B* b2 = new B(2); + v.push_back (b2); + B* b3 = new B(3); + v.push_back (b3); + + typedef DataModel_detail::ElementProxy<Cont> EP; + EP ep1 (v.begin(), &v); + assert (ep1->x == 1); + + ep1 = b2; + assert (ep1->x == 2); + + EP ep3 (v.begin()+2, &v); + ep1 = ep3; + assert (ep1->x == 3); + + Cont v2 (SG::OWN_ELEMENTS, true); + v2.push_back (new B(1)); + v2.push_back (new B(2)); + v2.push_back (new B(3)); + EP ep2 (v2.begin()+1, &v2); + ep1 = ep2; + assert (ep1->x == 2); + + check_dtor(); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/IsMostDerivedFlag_test.cxx b/EDM/athena/Control/AthContainers/test/IsMostDerivedFlag_test.cxx new file mode 100644 index 00000000..27d2161c --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/IsMostDerivedFlag_test.cxx @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/IsMostDerivedFlag_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2013 + * @brief Regression tests for IsMostDerivedFlag. + */ + + +#undef NDEBUG +#include "AthContainers/tools/IsMostDerivedFlag.h" +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + SG::IsMostDerivedFlag f1; + assert (f1 == false); + f1 = true; + assert (f1 == true); + f1 = false; + assert (f1 == false); + SG::IsMostDerivedFlag f2 (true); + assert (f2 == true); + SG::IsMostDerivedFlag f3 (f2); + assert (f3 == false); +#if __cplusplus > 201100 + SG::IsMostDerivedFlag f4 (std::move (f2)); + assert (f4 == false); +#endif +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/PackedContainer_test.cxx b/EDM/athena/Control/AthContainers/test/PackedContainer_test.cxx new file mode 100644 index 00000000..d0854d69 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/PackedContainer_test.cxx @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/PackedContainer_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2014 + * @brief Regression tests for PackedContainer + */ + +#undef NDEBUG +#include "AthContainers/PackedContainer.h" +#include <iostream> +#include <cassert> +#include <stdint.h> + + +void test1() +{ + std::cout << "test1\n"; + + SG::PackedContainer<int32_t> pc1; + assert (pc1.parms().nbits() == 32); + assert (pc1.parms().isSigned() == 1); + assert (pc1.parms().isFloat() == 0); + + SG::PackedContainer<uint32_t> pc2; + assert (pc2.parms().nbits() == 32); + assert (pc2.parms().isSigned() == 0); + assert (pc2.parms().isFloat() == 0); + + SG::PackedContainer<uint16_t> pc3; + assert (pc3.parms().nbits() == 16); + assert (pc3.parms().isSigned() == 0); + assert (pc3.parms().isFloat() == 0); + + SG::PackedContainer<int8_t> pc4; + assert (pc4.parms().nbits() == 8); + assert (pc4.parms().isSigned() == 1); + assert (pc4.parms().isFloat() == 0); + + SG::PackedContainer<float> pc5; + assert (pc5.parms().nbits() == 32); + assert (pc5.parms().nmantissa() == 23); + assert (pc5.parms().isSigned() == 1); + assert (pc5.parms().isFloat() == 1); + assert (pc5.parms().rounding() == 0); + assert (pc5.parms().scale() == 0); + assert (pc5.parms().hasScale() == 0); + + SG::PackedContainer<double> pc6; + assert (pc6.parms().nbits() == 32); + assert (pc6.parms().nmantissa() == 23); + assert (pc6.parms().isSigned() == 1); + assert (pc6.parms().isFloat() == 1); + assert (pc6.parms().rounding() == 0); + assert (pc6.parms().scale() == 0); + assert (pc6.parms().hasScale() == 0); + + SG::PackedContainer<std::vector<int16_t> > pc7; + assert (pc7.parms().nbits() == 16); + assert (pc7.parms().isSigned() == 1); + assert (pc7.parms().isFloat() == 0); + + SG::PackedContainer<std::vector<std::vector<float> > > pc8; + assert (pc8.parms().nbits() == 32); + assert (pc8.parms().isSigned() == 1); + assert (pc8.parms().isFloat() == 1); + + assert (pc1.setOption ("nbits", 23)); + assert (pc1.parms().nbits() == 23); + assert (pc1.parms().isSigned() == 1); + assert (pc1.parms().isFloat() == 0); + + assert (pc5.setOption ("scale", 2.5)); + assert (pc5.parms().scale() == 2.5); + assert (pc5.parms().hasScale() == 1); + assert (pc5.setOption ("scale", static_cast<double>(3.5))); + assert (pc5.parms().scale() == 3.5); + assert (pc5.parms().hasScale() == 1); + + pc2.setParms (pc1.parms()); + assert (pc2.parms().nbits() == 23); + assert (pc2.parms().isSigned() == 1); + assert (pc2.parms().isFloat() == 0); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/PackedConverter_test.cxx b/EDM/athena/Control/AthContainers/test/PackedConverter_test.cxx new file mode 100644 index 00000000..642896f5 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/PackedConverter_test.cxx @@ -0,0 +1,329 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/PackedContainer_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2014 + * @brief Regression tests for PackedContainer + */ + +#undef NDEBUG +#include "AthContainers/PackedConverter.h" +#include "TestTools/random.h" +#include "TestTools/FLOATassert.h" +#include "CxxUtils/ones.h" +#include <typeinfo> +#include <vector> +#include <iostream> +#include <cassert> + + +struct OutputArgs +{ + OutputArgs() : ipos(0) {} + std::vector<uint32_t> vec; + size_t ipos; + OutputArgs& operator<< (uint32_t x) { vec.push_back(x); return *this; } + OutputArgs& operator>> (uint32_t& x) { x = vec[ipos++]; return *this; } +}; + + +template <class T> +void fill_cont (size_t nbits, std::vector<T>& cont, size_t n, bool is_signed) +{ + for (size_t i = 0; i < n; i++) { + if (is_signed) { + int max = CxxUtils::ones<uint32_t> (nbits-1); + if (nbits < 30) max *= 2; + if (nbits < 29) max *= 2; + cont.push_back (static_cast<T> (Athena_test::randi (max, -max-1))); + } + else + cont.push_back (static_cast<T> (Athena_test::rng())); + } +} + + +template <class T> +void fill_float_cont (size_t /*nbits*/, std::vector<T>& cont, size_t n, bool is_signed) +{ + for (size_t i = 0; i < n; i++) { + if (is_signed) + cont.push_back (Athena_test::randf(200) - 100); + else + cont.push_back (Athena_test::randf(100)); + } +} + + +void fill_cont (size_t nbits, std::vector<float>& cont, size_t n, bool is_signed) +{ + fill_float_cont (nbits, cont, n, is_signed); +} + + +void fill_cont (size_t nbits, std::vector<double>& cont, size_t n, bool is_signed) +{ + fill_float_cont (nbits, cont, n, is_signed); +} + + +template <class T> +void fill_cont (size_t nbits, std::vector<std::vector<T> >& cont, size_t n, bool is_signed) +{ + cont.resize (n); + for (size_t i = 0; i < n; i++) { + size_t nelt = Athena_test::randi (30); + fill_cont (nbits, cont[i], nelt, is_signed); + assert (cont[i].size() == nelt); + } +} + + +void compare_signed_int (size_t nbits, int x1, int x2) +{ + int max = CxxUtils::ones<uint32_t> (nbits-1); + int min = - max-1; + + if (x1 > max) + assert (x2 == max); + else if (x1 < min) + assert (x2 == min); + else + assert (x1 == x2); +} + + +template <class T1, class T2> +void compare_int_vec (size_t nbits, + const std::vector<T1>& c1, + const std::vector<T2>& c2) +{ + uint32_t mask = CxxUtils::ones<uint32_t> (nbits); + assert (c1.size() == c2.size()); + for (size_t i = 0; i < c1.size(); i++) { + //std::cout << c1[i] << " " << c2[i] << "\n"; + if (std::numeric_limits<T2>::is_signed) + compare_signed_int (nbits, c1[i], c2[i]); + else { + uint32_t val1 = static_cast<uint32_t> (c1[i]); + assert (static_cast<T2> (mask & val1) == c2[i]); + } + } +} + + +template <class T> +void compare_float_vec (size_t nmantissa, + const std::vector<T>& c1, + const std::vector<T>& c2) +{ + float thresh = 1; + for (size_t i = 0; i < nmantissa; i++) + thresh /= 2; + assert (c1.size() == c2.size()); + for (size_t i = 0; i < c1.size(); i++) { + assert (Athena_test::isEqual (c1[i], c2[i], thresh)); + } +} + + +template <class T1, class T2> +void compare_cont (const SG::PackedParameters& parms, + const std::vector<T1>& c1, + const std::vector<T2>& c2) +{ + compare_int_vec (parms.nbits(), c1, c2); +} + + +void compare_cont (const SG::PackedParameters& parms, + const std::vector<float>& c1, + const std::vector<float>& c2) +{ + compare_float_vec (parms.nmantissa(), c1, c2); +} + + +void compare_cont (const SG::PackedParameters& parms, + const std::vector<double>& c1, + const std::vector<double>& c2) +{ + compare_float_vec (parms.nmantissa(), c1, c2); +} + + +template <class T1, class T2> +void compare_cont (const SG::PackedParameters& parms, + const std::vector<std::vector<T1> >& c1, + const std::vector<std::vector<T2> >& c2) +{ + assert (c1.size() == c2.size()); + for (size_t i = 0; i < c1.size(); i++) { + compare_int_vec (parms.nbits(), c1[i], c2[i]); + } +} + + +void compare_cont (const SG::PackedParameters& parms, + const std::vector<std::vector<float> >& c1, + const std::vector<std::vector<float> >& c2) +{ + assert (c1.size() == c2.size()); + for (size_t i = 0; i < c1.size(); i++) { + compare_float_vec (parms.nmantissa(), c1[i], c2[i]); + } +} + + +void compare_cont (const SG::PackedParameters& parms, + const std::vector<std::vector<double> >& c1, + const std::vector<std::vector<double> >& c2) +{ + assert (c1.size() == c2.size()); + for (size_t i = 0; i < c1.size(); i++) { + compare_float_vec (parms.nmantissa(), c1[i], c2[i]); + } +} + + +template <class T1, class T2> +void compare_cont (const SG::PackedParameters& parms, + const std::vector<std::vector<std::vector<T1> > >& c1, + const std::vector<std::vector<std::vector<T2> > >& c2) +{ + assert (c1.size() == c2.size()); + for (size_t i = 0; i < c1.size(); i++) { + compare_cont (parms, c1[i], c2[i]); + } +} + + +template <class T1, class T2> +void testit (size_t nbits, size_t n = 100, bool is_signed = false, + size_t nmantissa = 23) +{ + std::vector<T1> c1; + + fill_cont (nbits, c1, n, is_signed); + assert (c1.size() == n); + + SG::PackedParameters parms; + parms.setNbits (nbits); + parms.setNmantissa (nmantissa); + parms.setSigned (is_signed); + if (typeid(T1) == typeid(float) || + typeid(T1) == typeid(double) || + typeid(T1) == typeid(std::vector<float>) || + typeid(T1) == typeid(std::vector<double>) || + typeid(T1) == typeid(std::vector<std::vector<float> >) || + typeid(T1) == typeid(std::vector<std::vector<double> >)) + parms.setFloat (true); + + OutputArgs args; + + SG::PackedConverter cnv (parms); + cnv.write (n, c1, args); + + std::vector<T2> c2; + cnv.read (n, c2, args); + assert (c2.size() == n); + + compare_cont (parms, c1, c2); +} + + +#define TESTIT1(T) testit<T,T> + + +void test1() +{ + std::cout << "test1\n"; + + for (int nbits=1; nbits <= 32; ++nbits) { + TESTIT1(uint32_t) (nbits); + TESTIT1(uint16_t) (nbits); + TESTIT1(uint8_t) (nbits); + } + + for (int nbits=2; nbits <= 32; ++nbits) { + TESTIT1(int32_t) (nbits, 100, true); + TESTIT1(int16_t) (nbits, 100, true); + TESTIT1(int8_t) (nbits, 100, true); + } + + TESTIT1(float) (24, 100, false, 16); + TESTIT1(float) (24, 100, true, 16); + + TESTIT1(double) (24, 100, false, 16); + TESTIT1(double) (24, 100, true, 16); +} + + +// Test doubly-nested vectors. +void test2() +{ + std::cout << "test2\n"; + for (int nbits=1; nbits <= 32; ++nbits) { + TESTIT1(std::vector<uint32_t>) (nbits); + TESTIT1(std::vector<uint16_t>) (nbits); + TESTIT1(std::vector<uint8_t>) (nbits); + } + + for (int nbits=2; nbits <= 32; ++nbits) { + TESTIT1(std::vector<int32_t>) (nbits, 100, true); + TESTIT1(std::vector<int16_t>) (nbits, 100, true); + TESTIT1(std::vector<int8_t>) (nbits, 100, true); + } + + TESTIT1(std::vector<float>) (24, 100, false, 16); + TESTIT1(std::vector<float>) (24, 100, true, 16); + TESTIT1(std::vector<double>) (24, 100, false, 16); + TESTIT1(std::vector<double>) (24, 100, true, 16); +} + + +// Test triply-nested vectors. +void test3() +{ + std::cout << "test3\n"; + + for (int nbits=1; nbits <= 32; ++nbits) { + TESTIT1(std::vector<std::vector<uint32_t> >) (nbits); + TESTIT1(std::vector<std::vector<uint16_t> >) (nbits); + TESTIT1(std::vector<std::vector<uint8_t> >) (nbits); + } + + for (int nbits=2; nbits <= 32; ++nbits) { + TESTIT1(std::vector<std::vector<int32_t> >) (nbits, 100, true); + TESTIT1(std::vector<std::vector<int16_t> >) (nbits, 100, true); + TESTIT1(std::vector<std::vector<int8_t> >) (nbits, 100, true); + } + + TESTIT1(std::vector<std::vector<float> >) (24, 100, false, 16); + TESTIT1(std::vector<std::vector<float> >) (24, 100, true, 16); + TESTIT1(std::vector<std::vector<double> >) (24, 100, false, 16); + TESTIT1(std::vector<std::vector<double> >) (24, 100, true, 16); +} + + +// Test some simple conversions. +void test4() +{ + std::cout << "test4\n"; + + testit<uint16_t, uint32_t> (13); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/PackedParameters_test.cxx b/EDM/athena/Control/AthContainers/test/PackedParameters_test.cxx new file mode 100644 index 00000000..49654e58 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/PackedParameters_test.cxx @@ -0,0 +1,203 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/PackedParameters_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Regression tests for PackedParameters + */ + + +#undef NDEBUG +#include "AthContainers/PackedParameters.h" +#include <cassert> +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + + SG::PackedParameters p1; + assert (p1.nbits() == 32); + assert (p1.nmantissa() == 23); + assert (p1.scale() == 0); + assert (p1.flags() == 0); + assert (!p1.isSigned()); + assert (!p1.isFloat()); + assert (!p1.hasScale()); + assert (!p1.rounding()); + + SG::PackedParameters p2 (27, SG::PackedParameters::FLAG_IS_SIGNED); + assert (p2.nbits() == 27); + assert (p2.nmantissa() == 26); + assert (p2.scale() == 0); + assert (p2.flags() == SG::PackedParameters::FLAG_IS_SIGNED); + assert ( p2.isSigned()); + assert (!p2.isFloat()); + assert (!p2.hasScale()); + assert (!p2.rounding()); + + SG::PackedParameters p3 (static_cast<uint16_t>(0)); + assert (p3.nbits() == 16); + assert (p3.nmantissa() == 16); + assert (p3.scale() == 0); + assert (!p3.isSigned()); + assert (!p3.isFloat()); + assert (!p3.hasScale()); + assert (!p3.rounding()); + + SG::PackedParameters p4 (static_cast<int32_t>(0)); + assert (p4.nbits() == 32); + assert (p4.nmantissa() == 23); + assert (p4.scale() == 0); + assert ( p4.isSigned()); + assert (!p4.isFloat()); + assert (!p4.hasScale()); + assert (!p4.rounding()); + + SG::PackedParameters p5 (static_cast<float>(0)); + assert (p5.nbits() == 32); + assert (p5.nmantissa() == 23); + assert (p5.scale() == 0); + assert ( p5.isSigned()); + assert ( p5.isFloat()); + assert (!p5.hasScale()); + assert (!p5.rounding()); + + SG::PackedParameters p6 (static_cast<double>(0)); + assert (p6.nbits() == 32); + assert (p6.nmantissa() == 23); + assert (p6.scale() == 0); + assert ( p6.isSigned()); + assert ( p6.isFloat()); + assert (!p6.hasScale()); + assert (!p6.rounding()); + + assert (p1.setNbits (16)); + assert (p1.nbits() == 16); + assert (p1.nmantissa() == 16); + assert (!p1.isSigned()); + assert (!p1.setNbits (0)); + assert (!p1.setNbits (33)); + assert (p1.nbits() == 16); + assert (p1.setNbits (1)); + assert (p1.nbits() == 1); + assert (p1.nmantissa() == 1); + assert (!p1.isSigned()); + assert (!p1.setSigned(true)); + assert (p1.setNbits (7)); + assert (p1.setNmantissa (7)); + assert (p1.nbits() == 7); + assert (p1.nmantissa() == 7); + assert (!p1.isSigned()); + assert (p1.setSigned(true)); + assert (p1.nbits() == 7); + assert (p1.nmantissa() == 6); + assert (p1.isSigned()); + assert (p1.setSigned(false)); + assert (p1.nbits() == 7); + assert (p1.nmantissa() == 6); + assert (!p1.isSigned()); + assert (!p1.setNmantissa (0)); + assert (!p1.setNmantissa (8)); + assert (p1.nmantissa() == 6); + + assert (!p1.hasScale()); + assert (p1.scale() == 0); + assert (p1.setScale(2)); + assert (p1.scale() == 2); + assert (p1.hasScale()); + assert (p1.setScale(1)); + assert (p1.scale() == 1); + assert (!p1.hasScale()); + assert (p1.setScale(0)); + assert (p1.scale() == 0); + assert (!p1.hasScale()); + + assert (!p1.rounding()); + assert (p1.setRounding(true)); + assert (p1.rounding()); + assert (p1.setRounding(false)); + assert (!p1.rounding()); + + assert (!p1.isFloat()); + assert (p1.setFloat(true)); + assert (p1.isFloat()); + assert (p1.setFloat(false)); + assert (!p1.isFloat()); +} + + +bool testvalid (const std::string& s) +{ + return SG::PackedParameters::isValidOption (SG::AuxDataOption (s, 0)); +} +void test2() +{ + std::cout << "test2\n"; + + assert (testvalid ("nbits")); + assert (testvalid ("nmantissa")); + assert (testvalid ("scale")); + assert (testvalid ("signed")); + assert (testvalid ("rounding")); + assert (testvalid ("float")); + assert (!testvalid ("xxx")); +} + + +void test3() +{ + std::cout << "test3\n"; + + SG::PackedParameters p; + + assert (p.nbits() == 32); + assert (p.setOption (SG::AuxDataOption ("nbits", 17))); + assert (p.nbits() == 17); + assert (!p.setOption (SG::AuxDataOption ("nbits", 33))); + + assert (p.nmantissa() == 17); + assert (p.setOption (SG::AuxDataOption ("nmantissa", 13))); + assert (p.nmantissa() == 13); + assert (!p.setOption (SG::AuxDataOption ("nmantissa", 23))); + + assert (p.scale() == 0); + assert (!p.hasScale()); + assert (p.setOption (SG::AuxDataOption ("scale", 2))); + assert (p.scale() == 2); + assert (p.hasScale()); + + assert (!p.isSigned()); + assert (p.setOption (SG::AuxDataOption ("signed", 1))); + assert (p.isSigned()); + assert (p.setOption (SG::AuxDataOption ("signed", 0))); + assert (!p.isSigned()); + + assert (!p.rounding()); + assert (p.setOption (SG::AuxDataOption ("rounding", 1))); + assert (p.rounding()); + assert (p.setOption (SG::AuxDataOption ("rounding", 0))); + assert (!p.rounding()); + + assert (!p.isFloat()); + assert (p.setOption (SG::AuxDataOption ("float", 1))); + assert (p.isFloat()); + assert (p.setOption (SG::AuxDataOption ("float", 0))); + assert (!p.isFloat()); + + assert (!p.setOption (SG::AuxDataOption ("xxx", 1))); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/TestThinningSvc.icc b/EDM/athena/Control/AthContainers/test/TestThinningSvc.icc new file mode 100644 index 00000000..052eb2bc --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/TestThinningSvc.icc @@ -0,0 +1,145 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file TestThinningSvc.icc + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Dummy thinning service, for regression tests. + */ + + +#include "SGTools/DataProxy.h" +#include "SGTools/TestStore.h" +#include "AthenaKernel/IThinningSvc.h" +#include <map> + + +class TestThinningSvc + : virtual public IThinningSvc, public SGTest::TestStore +{ +public: + StatusCode sysInitialize() override + { std::cout << "sysInitialize\n"; std::abort(); } + StatusCode sysStart() override + { std::cout << "sysStart\n"; std::abort(); } + StatusCode sysStop() override + { std::cout << "sysStop\n"; std::abort(); } + StatusCode sysFinalize() override + { std::cout << "sysFinalize\n"; std::abort(); } + StatusCode sysReinitialize() override + { std::cout << "sysReinitialize\n"; std::abort(); } + StatusCode sysRestart() override + { std::cout << "sysRestart\n"; std::abort(); } + StatusCode configure() override + { std::cout << "configure\n"; std::abort(); } + StatusCode initialize() override + { std::cout << "initialize\n"; std::abort(); } + StatusCode start() override + { std::cout << "start\n"; std::abort(); } + StatusCode stop() override + { std::cout << "stop\n"; std::abort(); } + StatusCode finalize() override + { std::cout << "finalize\n"; std::abort(); } + StatusCode terminate() override + { std::cout << "terminate\n"; std::abort(); } + StatusCode reinitialize() override + { std::cout << "reinitialize\n"; std::abort(); } + StatusCode restart() override + { std::cout << "restart\n"; std::abort(); } + Gaudi::StateMachine::State FSMState() const override + { std::cout << "FSMState\n"; std::abort(); } + Gaudi::StateMachine::State targetFSMState() const override + { std::cout << "targetFSMState\n"; std::abort(); } + void setServiceManager (ISvcManager*) override + { std::cout << "setServiceManager\n"; std::abort(); } + StatusCode register_slimmer (Athena::ISlimmingHdlr */*handler*/) override + { std::cout << "register_slimmer\n"; std::abort(); } + virtual Athena::IThinningHdlr* handler( SG::DataProxy* /*proxy*/ ) override + { std::cout << "handler\n"; std::abort(); } + virtual StatusCode + filter_impl( Athena::IThinningHdlr* /*handler*/, + SG::DataProxy* /*proxy*/, + const Filter_t& /*filter*/, + const IThinningSvc::Operator::Type /*op*/ = Operator::And ) override + { std::cout << "filter_impl\n"; std::abort(); } + StatusCode commit() override + { std::cout << "commit\n"; std::abort(); } + StatusCode rollback() override + { std::cout << "rollback\n"; std::abort(); } + virtual + sgkey_t stringToKey (const std::string& /*str*/, CLID /*clid*/) override + { std::abort(); } + virtual + const std::string* keyToString (sgkey_t /*key*/) const override + { std::abort(); } + virtual + const std::string* keyToString (sgkey_t /*key*/, + CLID& /*clid*/) const override + { std::abort(); } + virtual + void registerKey (sgkey_t /*key*/, + const std::string& /*str*/, + CLID /*clid*/) override + { std::abort(); } + + virtual + bool thinningOccurred() const override + { + return m_map.size() > 0; + } + + virtual + bool is_thinned_impl(const SG::DataProxy* p) const override + { + proxymap_t::const_iterator i = m_map.find (p); + if (i != m_map.end()) + return true; + return false; + } + + using SGTest::TestStore::proxy; + virtual + SG::DataProxy* proxy(const void* const pTransient) const override + { + objmap_t::const_iterator i = m_objmap.find (pTransient); + if (i != m_objmap.end()) + return i->second; + return 0; + } + + virtual + std::size_t index_impl( const SG::DataProxy* objProxy, + std::size_t idx ) const override + { + proxymap_t::const_iterator i = m_map.find (objProxy); + if (i != m_map.end()) { + map_t::const_iterator ii = i->second.find (idx); + if (ii != i->second.end()) + return ii->second; + } + return idx; + } + + void remap (const void* obj, size_t from, size_t to) + { + SG::DataProxy* proxy = m_objmap[obj]; + if (!proxy) { + proxy = new SG::DataProxy(); + m_objmap[obj] = proxy; + } + + m_map[proxy][from] = to; + } + + + typedef std::map<const void*, SG::DataProxy*> objmap_t; + objmap_t m_objmap; + + typedef std::map<size_t, size_t> map_t; + + typedef std::map<const SG::DataProxy*, map_t> proxymap_t; + proxymap_t m_map; +}; diff --git a/EDM/athena/Control/AthContainers/test/ViewVectorBase_test.cxx b/EDM/athena/Control/AthContainers/test/ViewVectorBase_test.cxx new file mode 100644 index 00000000..075377aa --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/ViewVectorBase_test.cxx @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/ViewVectorBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Tests for ViewVectorBase. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include "AthContainers/ViewVectorBase.h" +#include "AthContainers/DataVector.h" +#include "AthContainers/AuxElement.h" +#include "SGTools/TestStore.h" +#include "SGTools/CLASS_DEF.h" +#include <iostream> +#include <cassert> + + +class X + : public SG::AuxElement +{ +public: + X(int x) : m_x(x) {} + int m_x; +}; +static const CLID x_clid = 8324723; +CLASS_DEF (DataVector<X>, x_clid, 1) + + +class Y {}; + + +class ViewVectorBaseTest + : public SG::ViewVectorBase +{ +public: + virtual void toPersistent() override {} + virtual void toTransient() override {} + + void testToPersistent (DataVector<X>& dv) + { + doToPersistent (dv); + } + + template <class DV> + void testToTransient (DV& dv) + { + doToTransient (dv); + } + + void checkELV (unsigned int); + + void checkClear() + { + clearPersistent(); + assert (m_persKey.size() == 0); + assert (m_persIndex.size() == 0); + } +}; + + + +void ViewVectorBaseTest::checkELV (unsigned int sgkey) +{ + assert (m_persKey.size() == 10); + assert (m_persIndex.size() == 10); + for (unsigned int i=0; i < 10; i++) { + assert (m_persKey[i] == sgkey); + assert (m_persIndex[i] == 9-i); + } +} + + +void test1() +{ + std::cout << "test1\n"; + ViewVectorBaseTest vvb1; + + DataVector<X>* dv = new DataVector<X>; + for (int i = 0; i < 10; i++) + dv->push_back (new X(i)); + SGTest::store.record (dv, "dv"); + unsigned int sgkey = SGTest::store.stringToKey ("dv", x_clid); + + DataVector<X> vv (SG::VIEW_ELEMENTS); + for (int i = 0; i < 10; i++) + vv.push_back ((*dv)[9-i]); + + vvb1.testToPersistent (vv); + vvb1.checkELV (sgkey); + assert (vv.size() == 10); + + vvb1.setClearOnPersistent(); + vvb1.testToPersistent (vv); + vvb1.checkELV (sgkey); + assert (vv.size() == 0); + + vvb1.testToTransient (vv); + assert (vv.size() == 10); + for (int i = 0; i < 10; i++) + assert (vv[i] == (*dv)[9-i]); + + + vvb1.checkELV (sgkey); + vvb1.checkClear(); + + for (int i = 0; i < 10; i++) + SGTest::store.remap (sgkey, 12345, i, i); + vvb1.testToPersistent (vv); + vvb1.checkELV (12345); + + DataVector<Y> vy (SG::VIEW_ELEMENTS); + vvb1.testToTransient (vy); + assert (vy.empty()); +} + + +int main() +{ + SGTest::initTestStore(); + test1(); + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/EDM/athena/Control/AthContainers/test/ViewVector_test.cxx b/EDM/athena/Control/AthContainers/test/ViewVector_test.cxx new file mode 100644 index 00000000..96182a11 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/ViewVector_test.cxx @@ -0,0 +1,227 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/ViewVector_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Tests for ViewVector. + */ + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + + +#undef NDEBUG +#include <boost/preprocessor/stringize.hpp> +#include "AthContainers/ViewVector.h" +#include "AthContainers/ConstDataVector.h" +#include "AthContainers/DataVector.h" +#include "SGTools/BaseInfo.h" +#include "SGTools/TestStore.h" +#include "SGTools/CLASS_DEF.h" +#include "TestTools/expect_exception.h" +#include <iostream> +#include <cassert> + + +class C {}; +typedef DataVector<C> DV; +typedef ViewVector<DV> VV; + + +class X + : public SG::AuxElement +{ +public: + X(int x) : m_x(x) {} + int m_x; +}; +static const CLID x_clid = 8324723; +CLASS_DEF (DataVector<X>, x_clid, 1) + + +void checkit (const VV& vv, const DV& dv, int n = -1) +{ + if (n < 0) + n = dv.size(); + assert (vv.ownPolicy() == SG::VIEW_ELEMENTS); + assert (static_cast<int>(vv.size()) == n); + for (int i=0; i < n; i++) + assert (vv[i] == dv[i]); +} + +void test1() +{ + std::cout << "test1\n"; + + DV dv; + for (int i=0; i < 10; i++) + dv.push_back (new C); + + VV vv1; + assert (vv1.ownPolicy() == SG::VIEW_ELEMENTS); + VV vv2 (SG::VIEW_ELEMENTS); + assert (vv2.ownPolicy() == SG::VIEW_ELEMENTS); + EXPECT_EXCEPTION (SG::ExcViewVectorNotView, VV vvx(SG::OWN_ELEMENTS)); + + VV vv3 (10); + assert (vv3.ownPolicy() == SG::VIEW_ELEMENTS); + assert (vv3.size() == 10); + VV vv4 (10, SG::VIEW_ELEMENTS); + assert (vv4.ownPolicy() == SG::VIEW_ELEMENTS); + assert (vv4.size() == 10); + EXPECT_EXCEPTION (SG::ExcViewVectorNotView, VV(10, SG::OWN_ELEMENTS)); + + VV vv5 (dv.begin(), dv.end()); + checkit (vv5, dv); + + VV vv6 (vv5); + checkit (vv6, dv); + + VV vv7 (std::move (vv5)); + assert (vv5.size() == 0); + checkit (vv7, dv); + + VV vv8 (dv); + checkit (vv8, dv); + + DV dv2 (dv); + VV vv9 (std::move(dv2)); + assert (dv2.size() == 0); + checkit (vv9, dv); + + DV dv3; + EXPECT_EXCEPTION (SG::ExcViewVectorNotView, VV(std::move(dv3))); + + VV vv10 {dv[0], dv[1]}; + checkit (vv10, dv, 2); + + vv2 = vv10; + checkit (vv2, dv, 2); + + vv2 = dv; + checkit (vv2, dv); + + vv2 = std::move(vv10); + assert (vv10.size() == 0); + checkit (vv2, dv, 2); + + dv2 = dv; + vv2 = std::move(dv2); + assert (dv2.size() == 0); + checkit (vv2, dv); + EXPECT_EXCEPTION (SG::ExcViewVectorNotView, vv2 = std::move(dv3)); + + vv2 = {dv[0], dv[1]}; + checkit (vv2, dv, 2); + + vv2.clear(); + checkit (vv2, dv, 0); + vv2.resize(10); + vv2.clear (SG::VIEW_ELEMENTS); + checkit (vv2, dv, 0); + EXPECT_EXCEPTION (SG::ExcViewVectorNotView, vv2.clear (SG::OWN_ELEMENTS)); + + vv2.resize(10); + vv2.clear (SG::VIEW_ELEMENTS, SG::NEVER_TRACK_INDICES); + checkit (vv2, dv, 0); + EXPECT_EXCEPTION (SG::ExcViewVectorNotView, vv2.clear (SG::OWN_ELEMENTS, + SG::NEVER_TRACK_INDICES)); +} + + +void test2() +{ + std::cout << "test2\n"; + + const SG::BaseInfoBase* bib = SG::BaseInfoBase::find (typeid (VV)); + assert (bib != nullptr); + assert (bib->is_base (typeid (DV))); +} + + +class D {}; +typedef ViewVector<DataVector<D> > DView; +VIEWVECTOR_CLASS_DEF(DView, 9823475) + + +void test3() +{ + std::cout << "test3\n"; + + EXPECT_EXCEPTION (SG::ExcMissingViewVectorCLID, ClassID_traits<VV>::ID()); + assert (ClassID_traits<DView>::ID() == 9823475); + assert (ClassID_traits<DView>::typeName() == "DView"); + assert (ClassID_traits<DView>::typeInfo() == typeid(DView)); +} + + +// toPersistent/toTransient +void test4() +{ + std::cout << "test4\n"; + DataVector<X> *dv = new DataVector<X>; + for (int i=0; i < 10; i++) + dv->push_back (new X(i)); + SGTest::store.record (dv, "dv"); + + ViewVector<DataVector<X> > vv; + for (int i=0; i < 10; i++) + vv.push_back ((*dv)[9-i]); + + vv.toPersistent(); + assert (vv.size() == 10); + vv.clear(); + assert (vv.size() == 0); + vv.toTransient(); + assert (vv.size() == 10); + for (int i=0; i < 10; i++) + assert (vv[i] == (*dv)[9-i]); + + vv.clearPersistent(); + assert (vv.size() == 10); + for (int i=0; i < 10; i++) + assert (vv[i] == (*dv)[9-i]); + + vv.toTransient(); + assert (vv.size() == 0); + + for (int i=0; i < 10; i++) + vv.push_back ((*dv)[9-i]); + vv.setClearOnPersistent(); + vv.toPersistent(); + assert (vv.size() == 0); + vv.toTransient(); + assert (vv.size() == 10); + for (int i=0; i < 10; i++) + assert (vv[i] == (*dv)[9-i]); +} + + +int main() +{ + SGTest::initTestStore(); + test1(); + test2(); + test3(); + test4(); + return 0; +} + + +class Z {}; +template class DataVector<Z>; +template class ViewVector<DataVector<Z> >; +template class ConstDataVector<ViewVector<DataVector<Z> > >; +template class ViewVector<ConstDataVector<DataVector<Z> > >; + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/auxid_set_equal.icc b/EDM/athena/Control/AthContainers/test/auxid_set_equal.icc new file mode 100644 index 00000000..de7b5af2 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/auxid_set_equal.icc @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Helper to test auxid_set_t for equality. +// Needed since the CxxUtils version doesn't implement operator==. + + +#include <set> + + +bool operator== (const SG::auxid_set_t& a, const SG::auxid_set_t& b) +{ + std::set<SG::auxid_t> aa (a.begin(), a.end()); + std::set<SG::auxid_t> bb (b.begin(), b.end()); + return aa == bb; +} diff --git a/EDM/athena/Control/AthContainers/test/copyAuxStoreThinned_test.cxx b/EDM/athena/Control/AthContainers/test/copyAuxStoreThinned_test.cxx new file mode 100644 index 00000000..67388f67 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/copyAuxStoreThinned_test.cxx @@ -0,0 +1,191 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/copyAuxStoreThinned_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Regression tests for copyAuxStoreThinned + */ + + +#undef NDEBUG + +#ifndef XAOD_STANDALONE + +#include "AthContainers/tools/copyAuxStoreThinned.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/PackedContainer.h" +#include "AthContainers/tools/foreach.h" +#include <vector> +#include <iostream> +#include <cassert> + + +#include "TestThinningSvc.icc" + + +class AuxStoreTest + : public SG::AuxStoreInternal +{ +public: + AuxStoreTest() {} + void suppress (SG::auxid_t auxid) + { m_suppressed.insert (auxid); } + + virtual const SG::auxid_set_t& getSelectedAuxIDs() const + { + m_selected = getAuxIDs(); + ATHCONTAINERS_FOREACH(SG::auxid_t auxid, m_suppressed) + m_selected.erase (auxid); + return m_selected; + } + +private: + SG::auxid_set_t m_suppressed; + mutable SG::auxid_set_t m_selected; +}; + + +void compare (const SG::PackedParameters& a, + const SG::PackedParameters& b) +{ + assert (a.nbits() == b.nbits()); + assert (a.isFloat() == b.isFloat()); + assert (a.isSigned() == b.isSigned()); + assert (a.rounding() == b.rounding()); + assert (a.nmantissa() == b.nmantissa()); + assert (a.scale() == b.scale()); +} + + +void compare (const SG::AuxStoreInternal& a, + const SG::AuxStoreInternal& b, + bool thinned = false, + SG::auxid_t suppressed = SG::null_auxid) +{ + if (thinned) { + assert (a.size()/2 == b.size()); + } + else { + assert (a.size() == b.size()); + } + + const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + ATHCONTAINERS_FOREACH(SG::auxid_t id, a.getAuxIDs()) { + if (id == suppressed) { + assert (b.getAuxIDs().count(id) == 0); + continue; + } + const char* aptr = reinterpret_cast<const char*>(a.getData(id)); + const char* bptr = reinterpret_cast<const char*>(b.getData(id)); + assert (aptr != 0 && bptr != 0); + + size_t sz = reg.getEltSize(id); + for (size_t ia=0, ib=0; ia < a.size(); ++ia) { + if (!thinned || ia%2 == 0) { + assert (memcmp (aptr + ia*sz , bptr + ib*sz, sz) == 0); + ++ib; + } + } + + assert (a.getIOType(id) == b.getIOType(id)); + if (a.getIOType(id) == &typeid(SG::PackedContainer<int>)) { + const SG::PackedContainer<int>* ap + = reinterpret_cast<const SG::PackedContainer<int>*> (a.getIOData(id)); + const SG::PackedContainer<int>* bp + = reinterpret_cast<const SG::PackedContainer<int>*> (b.getIOData(id)); + compare (ap->parms(), bp->parms()); + } + else if (a.getIOType(id) == &typeid(SG::PackedContainer<float>)) { + const SG::PackedContainer<float>* ap + = reinterpret_cast<const SG::PackedContainer<float>*> (a.getIOData(id)); + const SG::PackedContainer<float>* bp + = reinterpret_cast<const SG::PackedContainer<float>*> (b.getIOData(id)); + compare (ap->parms(), bp->parms()); + } + } +} + + +void test1() +{ + std::cout << "test1\n"; + TestThinningSvc svc; + + AuxStoreTest src; + SG::AuxStoreInternal dst; + + copyAuxStoreThinned (src, dst, 0); + compare (src, dst); + + copyAuxStoreThinned (src, dst, &svc); + compare (src, dst); + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + SG::auxid_t pityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("pInt"); + SG::auxid_t pftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("pFloat"); + + int* iptr = reinterpret_cast<int*> (src.getData (ityp, 10, 10)); + float* fptr = reinterpret_cast<float*> (src.getData (ftyp, 10, 10)); + int* piptr = reinterpret_cast<int*> (src.getData (pityp, 10, 10)); + float* pfptr = reinterpret_cast<float*> (src.getData (pftyp, 10, 10)); + + src.setOption (pityp, SG::AuxDataOption ("nbits", 10)); + src.setOption (pityp, SG::AuxDataOption ("signed", false)); + src.setOption (pftyp, SG::AuxDataOption ("nbits", 12)); + src.setOption (pftyp, SG::AuxDataOption ("signed", true)); + src.setOption (pftyp, SG::AuxDataOption ("rounding", true)); + src.setOption (pftyp, SG::AuxDataOption ("nmantissa", 8)); + src.setOption (pftyp, SG::AuxDataOption ("scale", 2.0)); + + for (int i=0; i < 10; i++) { + iptr[i] = i; + fptr[i] = 10*i + 0.5; + piptr[i] = i + 13; + pfptr[i] = 10*i + 0.5 + 13; + } + + SG::AuxStoreInternal src2; + svc.remap (&src2, 1, 2); + + copyAuxStoreThinned (src, dst, &svc); + compare (src, dst); + + for (int i=0, i1=0; i < 10; ++i) { + if (i%2 == 0) { + svc.remap (&src, i, i1); + ++i1; + } + else { + svc.remap (&src, i, IThinningSvc::RemovedIdx); + } + } + + copyAuxStoreThinned (src, dst, &svc); + compare (src, dst, true); + + SG::AuxStoreInternal dst2; + src.suppress (ftyp); + copyAuxStoreThinned (src, dst2, &svc); + compare (src, dst2, true, ftyp); +} + +int main() +{ + test1(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/copyThinned_test.cxx b/EDM/athena/Control/AthContainers/test/copyThinned_test.cxx new file mode 100644 index 00000000..2760f5c3 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/copyThinned_test.cxx @@ -0,0 +1,173 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/copyThinned_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Regression tests for copyThinned + */ + + +#undef NDEBUG + +#ifndef XAOD_STANDALONE + +#include "AthContainers/tools/copyThinned.h" +#include "AthContainers/tools/foreach.h" +#include "AthContainers/DataVector.h" +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxTypeRegistry.h" +#include <vector> +#include <iostream> +#include <cassert> + + +#include "TestThinningSvc.icc" + + +void compare (const SG::AuxStoreInternal& a, + const SG::AuxStoreInternal& b, + bool thinned = false) +{ + if (thinned) { + assert (a.size()/2 == b.size()); + } + else { + assert (a.size() == b.size()); + } + + const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + ATHCONTAINERS_FOREACH(SG::auxid_t id, a.getAuxIDs()) { + const char* aptr = reinterpret_cast<const char*>(a.getData(id)); + const char* bptr = reinterpret_cast<const char*>(b.getData(id)); + assert (aptr != 0 && bptr != 0); + + size_t sz = reg.getEltSize(id); + for (size_t ia=0, ib=0; ia < a.size(); ++ia) { + if (!thinned || ia%2 == 0) { + assert (memcmp (aptr + ia*sz , bptr + ib*sz, sz) == 0); + ++ib; + } + } + } +} + + +void compare (const DataVector<int>& a, + const DataVector<int>& b, + bool thinned = false) +{ + if (thinned) { + assert (a.size()/2 == b.size()); + } + else { + assert (a.size() == b.size()); + } + + for (size_t ia=0, ib=0; ia < a.size(); ++ia) { + if (!thinned || ia%2 == 0) { + assert (*a[ia] == *b[ib]); + ++ib; + } + } +} + + +void compare (const std::vector<int>& a, + const std::vector<int>& b, + bool /*thinned*/ = false) +{ + assert (a.size() == b.size()); + for (size_t i = 0; i < a.size(); i++) + assert (a[i] == b[i]); +} + + +template <class CONTAINER> +void tryit (CONTAINER& cont, IThinningSvc* svc, bool thinned = false) +{ + const CONTAINER* newcont = SG::copyThinned (cont, svc); + compare (cont, *newcont, thinned); + delete newcont; +} + + +void test1() +{ + std::cout << "test1\n"; + TestThinningSvc svc; + + SG::AuxStoreInternal store; + DataVector<int> dv; + std::vector<int> v; + + tryit (store, 0); + tryit (dv, 0); + tryit (v, 0); + + tryit (store, &svc); + tryit (dv, &svc); + tryit (v, &svc); + + SG::auxid_t ityp = SG::AuxTypeRegistry::instance().getAuxID<int> ("anInt"); + SG::auxid_t ftyp = SG::AuxTypeRegistry::instance().getAuxID<float> ("aFloat"); + + int* iptr = reinterpret_cast<int*> (store.getData (ityp, 10, 10)); + float* fptr = reinterpret_cast<float*> (store.getData (ftyp, 10, 10)); + for (int i=0; i < 10; i++) { + iptr[i] = i; + fptr[i] = 10*i; + + v.push_back(i); + dv.push_back (new int(i)); + } + + SG::AuxStoreInternal store2; + DataVector<int> dv2; + std::vector<int> v2; + + svc.remap (&store2, 1, 2); + svc.remap (&dv2, 1, 2); + svc.remap (&v2, 1, 2); + + tryit (store, &svc); + tryit (dv, &svc); + tryit (v, &svc); + + for (int i=0, i1=0; i < 10; ++i) { + if (i%2 == 0) { + svc.remap (&store, i, i1); + svc.remap (&dv, i, i1); + svc.remap (&v, i, i1); + ++i1; + } + else { + svc.remap (&store, i, IThinningSvc::RemovedIdx); + svc.remap (&dv, i, IThinningSvc::RemovedIdx); + svc.remap (&v, i, IThinningSvc::RemovedIdx); + } + } + + tryit (store, &svc, true); + tryit (dv, &svc, true); + tryit (v, &svc, true); +} + + +int main() +{ + test1(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/dataVectorAsELV_test.cxx b/EDM/athena/Control/AthContainers/test/dataVectorAsELV_test.cxx new file mode 100644 index 00000000..e3652c8e --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/dataVectorAsELV_test.cxx @@ -0,0 +1,93 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/dataVectorAsELV_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Tests for dataVectorAsELV. + */ + + +// Disable this test in standalone mode: +#ifndef XAOD_STANDALONE + +#undef NDEBUG +#include "AthContainers/dataVectorAsELV.h" +#include "AthContainers/DataVector.h" +#include "AthContainers/AuxElement.h" +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" +#include <iostream> +#include <cassert> + + +class X {}; +CLASS_DEF( DataVector<X> , 9901 , 1 ) + +class Y : public SG::AuxElement {}; +CLASS_DEF( DataVector<Y> , 9902 , 1 ) + + +void test1() +{ + std::cout << "test1\n"; + size_t N = 3; + + DataVector<X> dvx1; + for (size_t i = 0; i < N; i++) + dvx1.push_back (new X); + + std::vector<ElementLink<DataVector<X> > > linksx1 = + SG::dataVectorAsELV (dvx1); + + for (size_t i = 0; i < N; i++) + assert (dvx1[i] == *linksx1[i]); + + DataVector<X> dvx2 (SG::VIEW_ELEMENTS); + for (size_t i = 0; i < N; i++) + dvx2.push_back (dvx1[N-1-i]); + + EXPECT_EXCEPTION (SG::ExcDVToELV, SG::dataVectorAsELV (dvx2)); + + DataVector<Y> dvy1; + for (size_t i = 0; i < N; i++) + dvy1.push_back (new Y); + + std::vector<ElementLink<DataVector<Y> > > linksy1 = + SG::dataVectorAsELV (dvy1); + + for (size_t i = 0; i < N; i++) + assert (dvy1[i] == *linksy1[i]); + + DataVector<Y> dvy2 (SG::VIEW_ELEMENTS); + for (size_t i = 0; i < N; i++) + dvy2.push_back (dvy1[N-1-i]); + + std::vector<ElementLink<DataVector<Y> > > linksy2 = + SG::dataVectorAsELV (dvy2); + + for (size_t i = 0; i < N; i++) + assert (dvy2[i] == *linksy2[i]); + + dvy2.push_back (new Y); + EXPECT_EXCEPTION (SG::ExcDVToELV, SG::dataVectorAsELV (dvy2)); +} + + +int main() +{ + SGTest::initTestStore(); + test1(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/debug_test.cxx b/EDM/athena/Control/AthContainers/test/debug_test.cxx new file mode 100644 index 00000000..7e141c0d --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/debug_test.cxx @@ -0,0 +1,189 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/debug_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2015 + * @brief Regression tests for debug + */ + + +#undef NDEBUG +#include "AthContainers/debug.h" +#include "AthContainers/DataVector.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxStoreInternal.h" +#include <iostream> +#include <cassert> + + +struct A + : public SG::AuxElement +{ + int& xint() + { static Accessor<int> acc ("xint"); return acc(*this); } + int xint() const + { static Accessor<int> acc ("xint"); return acc(*this); } + + float& xfloat() + { static Accessor<float> acc ("xfloat"); return acc(*this); } + float xfloat() const + { static Accessor<float> acc ("xfloat"); return acc(*this); } + + std::vector<int>& xvint() + { static Accessor<std::vector<int> > acc ("xvint"); return acc(*this); } + const std::vector<int>& xvint() const + { static Accessor<std::vector<int> > acc ("xvint"); return acc(*this); } +}; + + +void test1() +{ + std::cout << "test1\n"; + SG::auxid_t id1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("foo"); + SG::auxid_t id2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("foo", "bar"); + assert (SGdebug::aux_var_name(id1) == "::foo"); + SGdebug::print_aux_var_name(id2); +} + + +void test2() +{ + std::cout << "test2\n"; + DataVector<A> dv; + SG::AuxStoreInternal store; + dv.setStore (&store); + + dv.push_back (new A); + dv.push_back (new A); + dv.push_back (new A); + + dv[0]->xint() = 1; + dv[1]->xint() = 2; + dv[2]->xint() = 3; + + dv[0]->xfloat() = 1.5; + dv[1]->xfloat() = 2.5; + dv[2]->xfloat() = 3.5; + + std::cout << "... set ...\n"; + SGdebug::print_aux_vars (store.getAuxIDs()); + std::cout << "... store ...\n"; + SGdebug::print_aux_vars (store); + SGdebug::print_aux_vars (&store); + std::cout << "... vec ...\n"; + SGdebug::print_aux_vars (dv); + SGdebug::print_aux_vars (&dv); + std::cout << "... elt ...\n"; + SGdebug::print_aux_vars (dv[1]); + SGdebug::print_aux_vars (*dv[1]); +} + + +template <class T> +void test3_one (const char* name, const T& val) +{ + SG::auxid_t id = SG::AuxTypeRegistry::instance().getAuxID<T> (name); + std::cout << name << " " << SGdebug::aux_var_as_string (id, &val) << "\n"; +} + + +void test3() +{ + std::cout << "test3\n"; + test3_one<int> ("a_int", -2); + test3_one<unsigned int> ("a_uint", 10); + test3_one<short> ("a_short", 10); + test3_one<unsigned short> ("a_ushort", 20); + test3_one<char> ("a_char", 'a'); + test3_one<unsigned char> ("a_uchar", 'b'); + test3_one<long> ("a_long", 50); + test3_one<unsigned long> ("a_ulong", 60); + test3_one<long long> ("a_llong", 50); + test3_one<unsigned long long> ("a_ullong", 60); + test3_one<float> ("a_float", 123.5); + test3_one<double> ("a_double", 223.5); + test3_one<bool> ("a_bool", true); + + test3_one<std::vector<int> > ("a_intvec", std::vector<int>{1,-2,3}); + test3_one<std::vector<unsigned int> > ("a_uintvec", std::vector<unsigned int>{1,2,3}); + test3_one<std::vector<short> > ("a_shortvec", std::vector<short>{4,5,6}); + test3_one<std::vector<unsigned short> > ("a_ushortvec", std::vector<unsigned short>{7,8,9}); + test3_one<std::vector<char> > ("a_chartvec", std::vector<char>{'a','b','c'}); + test3_one<std::vector<unsigned char> > ("a_uchartvec", std::vector<unsigned char>{'d','e','f'}); + test3_one<std::vector<long> > ("a_longvec", std::vector<long>{10,11,12}); + test3_one<std::vector<unsigned long> > ("a_ulongvec", std::vector<unsigned long>{13,14,15}); + test3_one<std::vector<long long> > ("a_llongvec", std::vector<long long>{16,17,18}); + test3_one<std::vector<unsigned long long> > ("a_ullongvec", std::vector<unsigned long long>{19,20,21}); + test3_one<std::vector<float> > ("a_floatvec", std::vector<float>{1.1,1.2,1.3}); + test3_one<std::vector<double> > ("a_doublevec", std::vector<double>{2.1,2.2,2.3}); + test3_one<std::vector<bool> > ("a_boolvec", std::vector<bool>{true,false,true}); + + test3_one<A> ("a_a", A()); +} + + +void test4() +{ + std::cout << "test4\n"; + DataVector<A> dv; + SG::AuxStoreInternal store; + dv.setStore (&store); + + dv.push_back (new A); + dv.push_back (new A); + dv.push_back (new A); + + dv[0]->xint() = 1; + dv[1]->xint() = 2; + dv[2]->xint() = 3; + + dv[0]->xfloat() = 1.5; + dv[1]->xfloat() = 2.5; + dv[2]->xfloat() = 3.5; + + dv[0]->xvint() = std::vector<int> {10, 11, 12}; + dv[1]->xvint() = std::vector<int> {13, 14, 15}; + dv[2]->xvint() = std::vector<int> {16, 17, 18}; + + SGdebug::dump_aux_vars (store, 10); + + std::cout << "... print elt 1 from store\n"; + SGdebug::dump_aux_vars (store, 1); + std::cout << "... print elt 0 from store\n"; + SGdebug::dump_aux_vars (&store, 0); + + std::cout << "\n"; + std::cout << "... print entire store\n"; + SGdebug::dump_aux_vars (store); + SGdebug::dump_aux_vars (&store); + + std::cout << "\n"; + std::cout << "... print elt 1 from vec\n"; + SGdebug::dump_aux_vars (dv, 1); + std::cout << "... print elt 0 from vec\n"; + SGdebug::dump_aux_vars (&dv, 0); + + std::cout << "\n"; + std::cout << "... print entire vec\n"; + SGdebug::dump_aux_vars (dv); + SGdebug::dump_aux_vars (&dv); + + std::cout << "\n"; + std::cout << "... print elt 1\n"; + SGdebug::dump_aux_vars (*dv[1]); + std::cout << "... print elt 0\n"; + SGdebug::dump_aux_vars (dv[0]); +} + +int main() +{ + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/error_test.cxx b/EDM/athena/Control/AthContainers/test/error_test.cxx new file mode 100644 index 00000000..cf97e310 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/error_test.cxx @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/error_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for error. + */ + + +#undef NDEBUG +#include "AthContainers/tools/error.h" + + +void test1() +{ + ATHCONTAINERS_ERROR("context", "message"); + ATHCONTAINERS_ERROR("context2", + AthContainers_detail::typeinfoName (typeid(int))); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/exceptions_test.cxx b/EDM/athena/Control/AthContainers/test/exceptions_test.cxx new file mode 100644 index 00000000..94e95f24 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/exceptions_test.cxx @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/exceptions_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for exceptions. + */ + + +#undef NDEBUG +#include "AthContainers/exceptions.h" +#include "AthContainers/AuxTypeRegistry.h" +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t id1 = r.getAuxID<int> ("foo"); + SG::auxid_t id2 = r.getAuxID<float> ("bar", "cl"); + + std::cout << SG::ExcNoAuxStore(id1).what() << "\n"; + std::cout << SG::ExcNoAuxStore(id2).what() << "\n"; + std::cout << SG::ExcNoAuxStore(SG::null_auxid).what() << "\n"; + std::cout << SG::ExcNoAuxStore("op").what() << "\n"; + + std::cout << SG::ExcBadAuxVar(id1).what() << "\n"; + + std::cout << SG::ExcConstAuxData("someop", id1).what() << "\n"; + std::cout << SG::ExcConstAuxData("otherop").what() << "\n"; + + std::cout << SG::ExcUntrackedSetStore().what() << "\n"; + + std::cout << SG::ExcBadPrivateStore("op").what() << "\n"; + + std::cout << SG::ExcAuxTypeMismatch(id1, typeid(int), typeid(float)).what() << "\n"; + std::cout << SG::ExcAuxTypeMismatch(id2, typeid(int), typeid(float)).what() << "\n"; + + std::cout << SG::ExcInsertionInBaseClass("op", typeid(int), typeid(float)).what() << "\n"; + + std::cout << SG::ExcStoreLocked(id1).what() << "\n"; + std::cout << SG::ExcStoreLocked("op").what() << "\n"; + std::cout << SG::ExcNonowningContainer().what() << "\n"; + std::cout << SG::ExcUnknownAuxItem("foo").what() << "\n"; + std::cout << SG::ExcUnknownAuxItem("foo", "bar").what() << "\n"; + std::cout << SG::ExcUnknownAuxItem("foo", "bar", &typeid(int)).what() << "\n"; + std::cout << SG::ExcDVToELV("why").what() << "\n"; + std::cout << SG::ExcViewVectorNotView().what() << "\n"; + std::cout << SG::ExcMissingViewVectorCLID(typeid(int)).what() << "\n"; + std::cout << SG::ExcInsertMoveOwnershipMismatch().what() << "\n"; +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/foreach_test.cxx b/EDM/athena/Control/AthContainers/test/foreach_test.cxx new file mode 100644 index 00000000..63f7b3e4 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/foreach_test.cxx @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/foreach_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression test for foreach.h + */ + + +#undef NDEBUG +#include "AthContainers/tools/foreach.h" +#include <vector> +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + std::vector<int> v; + for (int i=0; i < 10; i++) + v.push_back (i+10); + ATHCONTAINERS_FOREACH (int x, v) + std::cout << x << " "; + std::cout << "\n"; +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/getThinnedFlags_test.cxx b/EDM/athena/Control/AthContainers/test/getThinnedFlags_test.cxx new file mode 100644 index 00000000..cdc7d9cf --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/getThinnedFlags_test.cxx @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/getThinnedFlags_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Regression tests for getThinnedFlags + */ + +#undef NDEBUG + +#ifndef XAOD_STANDALONE + +#include "AthContainers/tools/getThinnedFlags.h" +#include <vector> +#include <iostream> +#include <cassert> + + +#include "TestThinningSvc.icc" + + +void test1() +{ + std::cout << "test1\n"; + TestThinningSvc svc; + + std::vector<int> c; + for (int i=0; i < 10; i++) c.push_back(i); + + std::vector<int> c2; + + size_t n = 0; + std::vector<unsigned char> flags; + assert (SG::getThinnedFlags (0, c, n, flags) == false); + assert (n == 10); + assert (flags.empty()); + + n = 0; + assert (SG::getThinnedFlags (&svc, c, n, flags) == false); + assert (n == 10); + assert (flags.empty()); + + svc.remap (&c2, 1, 2); + n = 0; + assert (SG::getThinnedFlags (&svc, c, n, flags) == false); + assert (n == 10); + assert (flags.empty()); + + for (int i=0, i1=0; i < 10; ++i) { + if (i%2 == 0) { + svc.remap (&c, i, i1); + ++i1; + } + else { + svc.remap (&c, i, IThinningSvc::RemovedIdx); + } + } + + n = 0; + assert (SG::getThinnedFlags (&svc, c, n, flags) == true); + assert (n == 5); + assert (flags.size() == 10); + for (int i=0; i < 10; ++i) { + assert (flags[i] == (i%2 == 1)); + } +} + + +int main() +{ + test1(); + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/normalizedTypeinfoName_test.cxx b/EDM/athena/Control/AthContainers/test/normalizedTypeinfoName_test.cxx new file mode 100644 index 00000000..d862c563 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/normalizedTypeinfoName_test.cxx @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/normalizedTypeinfoName_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Regression tests for normalizedTypeinfoName + */ + +#undef NDEBUG +#include "AthContainers/normalizedTypeinfoName.h" +#include "AthContainers/DataVector.h" +#include <vector> +#include <map> +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + + const std::type_info& ti1 = typeid (std::vector<int>); + assert (SG::normalizedTypeinfoName (ti1) == "std::vector<int>"); + assert (SG::normalizedTypeinfoName (ti1) == "std::vector<int>"); + + const std::type_info& ti2 = typeid (DataVector<int>); + assert (SG::normalizedTypeinfoName (ti2) == "DataVector<int>"); + + const std::type_info& ti3 = typeid (std::map<int, float>); + assert (SG::normalizedTypeinfoName (ti3) == "std::map<int,float>"); + + const std::type_info& ti4 = typeid (std::vector<std::string>); + assert (SG::normalizedTypeinfoName (ti4) == "std::vector<std::string>"); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/removeDuplicates_test.cxx b/EDM/athena/Control/AthContainers/test/removeDuplicates_test.cxx new file mode 100644 index 00000000..b817f3a6 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/removeDuplicates_test.cxx @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +// Disable this test in standalone compilation: +#ifndef XAOD_STANDALONE + +#define DO_REMOVE_DUPLICATES 1 +#include <cassert> +#include "AthContainers/DataVector.h" +#include "AthContainers/DataList.h" +using namespace std; +int main() { + DataVector<int> *pDV = new DataVector<int>; + int *pDuplicated = new int(0); + pDV->push_back(pDuplicated); + pDV->push_back(new int(1)); + pDV->push_back(pDuplicated); //this is an error: duplicates pointer + { + ostream_iterator<int*> os(cout, " "); + cout << "--> We have purposely duplicated an element of pDV: " << hex; + std::copy(pDV->begin(), pDV->end(), os); + cout << dec <<endl; + } + cout << "---> now we should see a warning message from ~DataVector" <<endl; + delete pDV; pDV=0; + cout << "<--- ~DataVector returns" <<endl; + DataList<int> *pDL = new DataList<int>; + pDuplicated = new int(0); + pDL->push_back(pDuplicated); + pDL->push_back(new int(1)); + pDL->push_back(pDuplicated); //this is an error: duplicates pointer + { + ostream_iterator<int*> os(cout, " "); + cout << "--> We have purposely duplicated an element of pDL: " << hex; + std::copy(pDL->begin(), pDL->end(), os); + cout << dec <<endl; + } + cout << "---> now we should see a warning message from ~DataList" <<endl; + delete pDL; pDL=0; + cout << "<--- ~DataList returns" <<endl; + return 0; +} + +#else + +int main() { + return 0; +} + +#endif // not XAOD_STANDALONE diff --git a/EDM/athena/Control/AthContainers/test/threading_nothreads_test.cxx b/EDM/athena/Control/AthContainers/test/threading_nothreads_test.cxx new file mode 100644 index 00000000..2d5a6332 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/threading_nothreads_test.cxx @@ -0,0 +1,15 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/threading_nothreads_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for threading, with threads disabled. + */ + + +#define ATHCONTAINERS_NO_THREADS +#include "threading_test.cxx" diff --git a/EDM/athena/Control/AthContainers/test/threading_test.cxx b/EDM/athena/Control/AthContainers/test/threading_test.cxx new file mode 100644 index 00000000..a3564bd7 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/threading_test.cxx @@ -0,0 +1,124 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainers/test/threading_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression tests for threading. + */ + + +#undef NDEBUG +#include "AthContainers/tools/threading.h" +#include <iostream> +#include <cassert> + + +class test_mutex +{ +public: + void lock_shared() const { std::cout << "lock_shared\n"; } + void unlock_shared() const { std::cout << "unlock_shared\n"; } + void lock_upgrade() { std::cout << "lock_upgrade\n"; } + void unlock_upgrade() { std::cout << "unlock_upgrade\n"; } + void lock() { std::cout << "lock\n"; } + void unlock() { std::cout << "unlock\n"; } + void unlock_upgrade_and_lock() { std::cout << "unlock_upgrade_and_lock\n"; } +}; + + +void test1() +{ + using AthContainers_detail::strict_shared_lock; + + std::cout << "test1\n"; + test_mutex m; + strict_shared_lock<test_mutex> lock (m); +} + + +void test2() +{ + using AthContainers_detail::upgrading_lock; + using AthContainers_detail::upgrade_mutex; + + std::cout << "test2\n"; + test_mutex m; + { + upgrading_lock<test_mutex> lock (m); + } + { + upgrading_lock<test_mutex> lock (m); + lock.upgrade(); + } + { + upgrading_lock<test_mutex> lock (m); + lock.upgrade(); + lock.upgrade(); + } + + upgrade_mutex mm; + upgrading_lock<upgrade_mutex> lock (mm); + lock.upgrade(); + lock.upgrade(); +} + + +void test3() +{ + using AthContainers_detail::fence_acq_rel; + using AthContainers_detail::fence_seq_cst; + using AthContainers_detail::mutex; + using AthContainers_detail::lock_guard; + + std::cout << "test3\n"; + + fence_acq_rel(); + fence_seq_cst(); + + mutex m; + { + lock_guard<mutex> g (m); + } +} + + +struct Payload +{ + Payload(int i) : m_i(i) { std::cout << "ctor " << i << "\n"; } + ~Payload() { std::cout << "dtor " << m_i << "\n"; } + Payload& operator= (const Payload&) = default; + int m_i; +}; + +void test4() +{ + using AthContainers_detail::thread_specific_ptr; + + std::cout << "test4\n"; + + thread_specific_ptr<Payload> p; + assert (p.get() == 0); + assert (p.release() == 0); + p.reset (new Payload(1)); + assert (p.get()->m_i == 1); + assert (p->m_i == 1); + assert ((*p).m_i == 1); + Payload* pp = p.release(); + assert (pp->m_i == 1); + assert (p.get() == 0); + p.reset (new Payload(2)); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/AthContainers/test/ut_ConstDataVector_basic_test.cxx b/EDM/athena/Control/AthContainers/test/ut_ConstDataVector_basic_test.cxx new file mode 100644 index 00000000..96ccc6f4 --- /dev/null +++ b/EDM/athena/Control/AthContainers/test/ut_ConstDataVector_basic_test.cxx @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_ConstDataVector_basic_test.cxx 626924 2014-11-07 15:00:54Z krasznaa $ + +// System include(s): +#include <cassert> + +// Local include(s): +#include "AthContainers/DataVector.h" +#include "AthContainers/ConstDataVector.h" + +/// Structure used in the test +struct DummyStruct { + int m_dummy = 0; ///< Dummy variable +}; + +int main() { + + // Create a ConstDataVector: + ConstDataVector< DataVector< DummyStruct > > cdv; + cdv.push_back( new DummyStruct() ); + cdv.push_back( new DummyStruct() ); + + // Some dummy test: + assert( cdv.size() == 2 ); + + // Try looping over it: + for( const DummyStruct* d : cdv ) { + assert( d->m_dummy == 0 ); + } + ConstDataVector< DataVector< DummyStruct > >::const_iterator itr = + cdv.begin(); + ConstDataVector< DataVector< DummyStruct > >::const_iterator end = + cdv.end(); + for( ; itr != end; ++itr ) { + assert( ( *itr )->m_dummy == 0 ); + } + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.h new file mode 100644 index 00000000..4d8baaa4 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.h @@ -0,0 +1,102 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersInterfaces/AuxDataOption.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2014 + * @brief Hold information about an option setting request. + */ + + +#ifndef ATHCONTAINERSINTERFACES_AUXDATAOPTION_H +#define ATHCONTAINERSINTERFACES_AUXDATAOPTION_H + + +#include <string> + + +namespace SG { + + +/** + * @brief Hold information about an option setting request. + * + * This is used to pass an option setting through the @c setOption + * interface, which is used to decouple the user interface from the + * auxiliary store representation classes. + * + * This class holds a name and a value, which can be either an int + * or a float. + */ +class AuxDataOption +{ +public: + /** + * @brief Constructor, with an integer value. + * @param name The option name. + * @param val The option value. + */ + AuxDataOption (const std::string& name, int val); + + + /** + * @brief Constructor, with a float value. + * @param name The option name. + * @param val The option value. + */ + AuxDataOption (const std::string& name, float val); + + + /** + * @brief Constructor, with a double value. + * @param name The option name. + * @param val The option value. + */ + AuxDataOption (const std::string& name, double val); + + + /** + * @brief The name of the option. + */ + std::string name() const; + + + /** + * @brief Return the option value as an integer. + */ + int intVal() const; + + + /** + * @brief Return the option value as a float. + */ + float floatVal() const; + + +private: + /// The option name. + std::string m_name; + + /// Are we holding an int or a float? + bool m_isInt; + + /// The stored value + union { + float f; + int i; + } m_val; +}; + + +} // namespace SG + + +#include "AthContainersInterfaces/AuxDataOption.icc" + + +#endif // not ATHCONTAINERSINTERFACES_AUXDATAOPTION_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.icc b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.icc new file mode 100644 index 00000000..e8f67ead --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxDataOption.icc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersInterfaces/AuxDataOption.icc + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2014 + * @brief Hold information about an option setting request. + */ + + +namespace SG { + + +/** + * @brief Constructor, with an integer value. + * @param name The option name. + * @param val The option value. + */ +inline +AuxDataOption::AuxDataOption (const std::string& name, int val) + : m_name (name), + m_isInt(true) +{ + m_val.i = val; +} + + +/** + * @brief Constructor, with a float value. + * @param name The option name. + * @param val The option value. + */ +inline +AuxDataOption::AuxDataOption (const std::string& name, float val) + : m_name (name), + m_isInt(false) +{ + m_val.f = val; +} + +/** + * @brief Constructor, with a double value. + * @param name The option name. + * @param val The option value. + */ +inline +AuxDataOption::AuxDataOption (const std::string& name, double val) + : m_name (name), + m_isInt(false) +{ + m_val.f = val; +} + + +/** + * @brief The name of the option. + */ +inline +std::string AuxDataOption::name() const +{ + return m_name; +} + + +/** + * @brief Return the option value as an integer. + */ +inline +int AuxDataOption::intVal() const +{ + if (m_isInt) + return m_val.i; + else + return m_val.f; +} + + +/** + * @brief Return the option value as a float. + */ +inline +float AuxDataOption::floatVal() const +{ + if (m_isInt) + return m_val.i; + else + return m_val.f; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxStore_traits.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxStore_traits.h new file mode 100644 index 00000000..b9561527 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxStore_traits.h @@ -0,0 +1,181 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxStore_traits.h 644841 2015-02-06 16:30:19Z ssnyder $ +/** + * @file AthContainersInterfaces/AuxStore_traits.h + * @author scott snyder <snyder@bnl.gov>, Paolo Calafiura + * @date Sep, 2013 + * @brief Associate @c AuxStore classes with EDM container classes. + * + * A @c DataVector may have auxiliary data associated with it, + * which are kept in separate AuxStore objects. + * + * When an object is retrieved from StoreGate, StoreGate can also + * look for an auxiliary store object and associate it with the container. + * This traits class is used to get the types of objects for which + * to look in StoreGate. + * + * There are two types defined, @c type and @c const_type, for non-const + * and const AuxStores, respectively. + * + * By default, these are @c SG::IAuxStore and @c SG::IConstAuxStore + * for types which have auxiliary data (either DOBJ or DOBJ::base_value_type + * derives from @c SG::IAuxElement). Otherwise, both types default + * to @c SG::NoAuxStore. + * + * These defaults may be overridden using the @c CLASS_AUXSTORE macro. + */ + + +#ifndef ATHCONTAINERSINTERFACES_AUXSTORE_TRAITS_H +#define ATHCONTAINERSINTERFACES_AUXSTORE_TRAITS_H + + +#include "AthContainersInterfaces/IAuxElement.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IConstAuxStore.h" + + +#if __cplusplus < 201100 +# include <boost/type_traits/is_base_of.hpp> +// boost::conditional was introduced sometime before 1.46. It's not present +// in the Boost version found on SLC6 by default. But we do need to use it +// if the migration to c++11 should be smooth... +# include <boost/version.hpp> +# if BOOST_VERSION < 104601 +# include <boost/mpl/if.hpp> +namespace boost { + template <bool b, class T, class U> + struct conditional : public mpl::if_c<b, T, U> {}; +} +# else +# include <boost/type_traits/conditional.hpp> +# endif // BOOST_VERSION +namespace SG_STD_OR_BOOST = boost; +#else +# include <type_traits> +namespace SG_STD_OR_BOOST = std; +#endif +#include <string> + + + +namespace SG { + + +/** + * @brief Mark that there's no associated AuxStore class. + */ +class NoAuxStore {}; + + +/// Default traits values for aux data case. +struct AuxStore_traits_AuxDefault +{ + typedef SG_STD_OR_BOOST::true_type flag; + + typedef IAuxStore type; + static const std::string& typeName() + { + static const std::string name ("SG::IAuxStore"); + return name; + } + + typedef IConstAuxStore const_type; + static const std::string& const_typeName() + { + static const std::string name ("SG::IConstAuxStore"); + return name; + } +}; + + +/// Default traits values for no-aux data case. +struct AuxStore_traits_NoAuxDefault +{ + typedef SG_STD_OR_BOOST::false_type flag; + + typedef NoAuxStore type; + static const std::string& typeName() + { + static const std::string name ("SG::NoAuxStore"); + return name; + } + + typedef NoAuxStore const_type; + static const std::string& const_typeName() + { + static const std::string name ("SG::NoAuxStore"); + return name; + } +}; + + +/// Helper for the case where DOBJ::base_value_type does not derive +/// from SG::IAuxElement. Test DOBJ itself. +template <class DOBJ, class FLAG_> +struct AuxStore_traits1 +{ + typedef typename SG_STD_OR_BOOST::conditional< + SG_STD_OR_BOOST::is_base_of<IAuxElement, DOBJ>::value, + AuxStore_traits_AuxDefault, + AuxStore_traits_NoAuxDefault>::type + type; +}; + + +/// Helper for the case where DOBJ::base_value_type does derive +/// from SG::IAuxElement. +/// @c AuxStore_traits is instantiated with the second template +/// argument set to @c true_type. The second argument in this +/// specialization is @c true_type if @c DOBJ::base_value_type +/// derives from @c IAuxElement and @c false_type if it does not. +/// Further, if @c DOBJ does not have an attribute @c base_value_type, +/// then this specialization is ignored (SFINAE). +template <class DOBJ> +struct AuxStore_traits1<DOBJ, + typename SG_STD_OR_BOOST::is_base_of< + IAuxElement, typename DOBJ::base_value_type>::type> +{ + typedef AuxStore_traits_AuxDefault type; +}; + + +/** + * @brief Associate @c AuxStore classes with EDM container classes + * (default implementation). + * + * Yields @c SG::IAuxStore and @c SG::IConstAuxStore for types that + * can have auxiliary data and @c NoAuxStore for others. + */ +template <class DOBJ> +struct AuxStore_traits + : public AuxStore_traits1<DOBJ, SG_STD_OR_BOOST::true_type>::type +{ + /// Attributes inherited from the base class: + /// typedef flag + /// typedef type + /// typedef const_type + /// function typeName + /// function const_typeName +}; + + +/** + * @brief Associate @c AuxStore classes with EDM container classes. + * This specialization allows using pointer types directly + * as an argument. + */ +template <class DOBJ> +struct AuxStore_traits<DOBJ*> : public AuxStore_traits<DOBJ> {}; + + + +} // namespace SG + + +#endif // not ATHCONTAINERSINTERFACES_AUXSTORE_TRAITS_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxTypes.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxTypes.h new file mode 100644 index 00000000..2a9c244a --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/AuxTypes.h @@ -0,0 +1,58 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxTypes.h 583546 2014-02-16 01:26:00Z ssnyder $ +/** + * @file AthContainersInterfaces/AuxTypes.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Basic definitions for auxiliary types. + * + * This defines types used to identify pieces of aux data. + */ + + +#ifndef ATHCONTAINERSINTERFACES_AUXTYPES_H +#define ATHCONTAINERSINTERFACES_AUXTYPES_H + + +#include <cstddef> + +// Can't do this until dictionaries are built with c++11. +// Can't use the boost version either; genreflex mishandles it. +#if 0 +#if __cplusplus < 201100 +# include "CxxUtils/unordered_set.h" +namespace SG_STD_OR_SG = SG; +#else +# include <unordered_set> +namespace SG_STD_OR_SG = std; +#endif +#endif + +#include "CxxUtils/unordered_set.h" + + +namespace SG { + +/// Identifier for a particular aux data item. +typedef size_t auxid_t; + +/// A set of aux data identifiers. +typedef SG::unordered_set<size_t> auxid_set_t; + +/// To signal no aux data item. +static const auxid_t null_auxid = static_cast<auxid_t> (-1); + +/// Used as type_info when we read an aux data item but it doesn't +/// exist in the registry. +class AuxTypePlaceholder {}; + +} // namespace SG + + + +#endif // not ATHCONTAINERSINTERFACES_AUXTYPES_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/CLASS_AUXSTORE.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/CLASS_AUXSTORE.h new file mode 100644 index 00000000..850df231 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/CLASS_AUXSTORE.h @@ -0,0 +1,59 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: CLASS_AUXSTORE.h 568070 2013-10-31 11:07:18Z krasznaa $ +/** + * @file AthContainersInterfaces/CLASS_AUXSTORE_.h + * @author Paolo Calafiura + * @date Sep, 2013 + * @brief Allow overriding defaults for associated aux store classes. + */ + +#ifndef ATHCONTAINERSINTERFACES_CLASS_AUXSTORE +#define ATHCONTAINERSINTERFACES_CLASS_AUXSTORE 1 + + +/** + * @brief define which AUXSTORE and CONSTAUXSTORE to use for a DOBJ type. + * CLASS_AUXSTORE specifies the default IAuxStore and IConstAuxStore interfaces + * CLASS_AUXSTORE3 allows to specify any AuxStore type. + */ +#include "AthContainersInterfaces/AuxStore_traits.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IConstAuxStore.h" + + +#define CLASS_AUXSTORE(DOBJ) \ + namespace SG { \ + template <> struct AuxStore_traits< DOBJ > { \ + typedef SG::IAuxStore type; \ + typedef SG::IConstAuxStore const_type; \ + static const std::string& typeName() { \ + static const std::string s_name = "SG::IAuxStore";\ + return s_name; \ + } \ + static const std::string& const_typeName() { \ + static const std::string s_name = "SG::IConstAuxStore"; \ + return s_name; \ + } \ + }; } +#define CLASS_AUXSTORE3(DOBJ, AUXSTORE, CONSTAUXSTORE) \ + namespace SG { \ + template <> struct AuxStore_traits< DOBJ > { \ + typedef AUXSTORE type; \ + typedef CONSTAUXSTORE const_type; \ + static const std::string& typeName() { \ + static const std::string s_name = #AUXSTORE; \ + return s_name; \ + } \ + static const std::string& const_typeName() { \ + static const std::string s_name = #CONSTAUXSTORE; \ + return s_name; \ + } \ + }; } + + +#endif // not ATHCONTAINERSINTERFACES_CLASS_AUXSTORE diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxElement.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxElement.h new file mode 100644 index 00000000..9bbd1444 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxElement.h @@ -0,0 +1,47 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IAuxElement.h 591267 2014-04-04 10:12:14Z krasznaa $ +/** + * @file AthContainersInterfaces/IAuxElement.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Flag that a class may have auxiliary data associated with it. + */ + + +#ifndef ATHCONTAINERSINTERFACES_IAUXELEMENT_H +#define ATHCONTAINERSINTERFACES_IAUXELEMENT_H + + +namespace SG { + + +/** + * @brief Flag that a class may have auxiliary data associated with it. + * + * This is an empty class, existing only to flag that a class may + * have auxiliary data associated with it. @c SG::AuxElement derives + * from this, but one should use this class for tests rather + * than @c SG::AuxElement to avoid dependency issues. + * + * This is an `interface' in the sense that it identifies a group of classes, + * but it defines no functionality itself. In fact, this class should + * not have a virtual table. + */ +class IAuxElement +{ +public: + IAuxElement() : m_dummy( 0 ) { ++m_dummy; } +private: + int m_dummy; ///< A temporary variable needed to make ROOT I/O work... +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSINTERFACES_IAUXELEMENT_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxSetOption.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxSetOption.h new file mode 100644 index 00000000..1e94e40b --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxSetOption.h @@ -0,0 +1,57 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file IAuxSetOption.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2014 + * @brief Abstract interface for setting a option on a aux data container. + */ + + +#ifndef ATHCONTAINERSINTERFACES_IAUXSETOPTION_H +#define ATHCONTAINERSINTERFACES_IAUXSETOPTION_H + + +namespace SG { + + +class AuxDataOption; + + +/** + * @brief Abstract interface for setting a option on a aux data container. + * + * A container used to hold auxiliary data can optionally provide this + * interface. This allows user code to set options for the container + * via the @c setOption interface. + * + * This is used, for example, to set packing parameters for @c PackedContainer. + */ +class IAuxSetOption +{ +public: + /// Make sure this class has a vtable. + virtual ~IAuxSetOption() {} + + + /** + * @brief Make an option setting. + * @param option The option to set. + * + * The interpretation of the option depends on the concrete class. + * + * Returns true if the option setting was successful; false otherwise. + */ + virtual bool setOption (const AuxDataOption& option) = 0; +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSINTERFACES_IAUXSETOPTION_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStore.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStore.h new file mode 100644 index 00000000..0fc215f6 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStore.h @@ -0,0 +1,193 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IAuxStore.h 797203 2017-02-14 19:35:56Z ssnyder $ +/** + * @file AthContainersInterfaces/IAuxStore.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Interface for non-const operations on an auxiliary store. + * + * A @c DataVector may have auxiliary data associated with it. + * These data are kept in separate AuxStore objects; this defines + * the interface for non-const operations on such a store. + * Const operations are defined by the base class + * @c IConstAuxStore. + * + * An AuxStore may store a number of different aux data items; + * these are identified by an integer of type @c auxid_t. + * Each item is stored as a vector with one entry per entry + * in the containing @c DataVector. + * + * This interface provides methods for getting a non-const pointer + * to an existing vector of aux data items and for operations that + * change the number of aux data items. + * of existing aux data items. + */ + + +#ifndef ATHCONTAINERSINTERFACES_IAUXSTORE_H +#define ATHCONTAINERSINTERFACES_IAUXSTORE_H + + +#include "AthContainersInterfaces/IConstAuxStore.h" +#include <cstddef> + + +namespace SG { + + +class AuxDataOption; + + +/** + * @brief Interface for non-const operations on an auxiliary store. + */ +class IAuxStore + : public IConstAuxStore +{ +public: + /// Pick up the const version from the base class. + using IConstAuxStore::getData; + + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + * + * If the container is locked, throw an exception. + */ + virtual void* getData (auxid_t auxid, size_t size, size_t capacity) = 0; + + + /** + * @brief Return a set of identifiers for writable data items + * in this store. + * + * This should include only non-const identifiers. + */ + virtual const SG::auxid_set_t& getWritableAuxIDs() const = 0; + + + /** + * @brief Change the size of all aux data vectors. + * @param sz The new size. + * + * This should be called when the size of the container changes. + * This should resize the vectors for all aux data items. + * + * If the size of the container grows, the new elements should + * be default-initialized; if it shrinks, destructors should + * be run as appropriate. + * + * Should return @c true if it is known that none of the data pointers + * changed (and thus the cache does not need to be cleared), false + * otherwise. + */ + virtual bool resize (size_t sz) = 0; + + + /** + * @brief Change the capacity of all aux data vectors. + * @param sz The new capacity. + * + * This should be called when the capacity of the container changes + * (by @c reserve). This should change the capacity for the vectors + * for all aux data items. + */ + virtual void reserve (size_t sz) = 0; + + + /** + * @brief Shift the elements of the container. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + virtual void shift (size_t pos, ptrdiff_t offs) = 0; + + + /** + * @brief Move all elements from @c other to this store. + * @param pos The starting index of the insertion. + * @param other Store from which to do the move. + * @param ignore Set of variables that should not be added to the store. + * + * Let @c len be the size of @c other. The store will be increased + * in size by @c len elements, with the elements at @c pos being + * copied to @c pos+len. Then, for each auxiliary variable, the + * entire contents of that variable for @c other will be moved to + * this store at index @c pos. This will be done via move semantics + * if possible; otherwise, it will be done with a copy. Variables + * present in this store but not in @c other will have the corresponding + * elements default-initialized. Variables in @c other but not in this + * store will be added unless they are in @c ignore. + * + * Returns true if it is known that none of the vectors' memory moved, + * false otherwise. + */ + virtual bool insertMove (size_t pos, + IAuxStore& other, + const SG::auxid_set_t& ignore = SG::auxid_set_t()) + = 0; + + + /** + * @brief Set an option for a given auxiliary variable. + * @param auxid The identifier of the desired aux data item. + * @param option The option to set. + * + * The interpretation of the option depends on the particular representation + * of the variable. + * + * Returns true if the option setting was successful; false otherwise. + */ + virtual bool setOption (auxid_t /*auxid*/, const AuxDataOption& /*option*/) + { return false; } +}; + + +} // namespace SG + + + +#ifndef XAOD_STANDALONE +#include "SGTools/BaseInfo.h" +#include "SGTools/CLASS_DEF.h" +SG_BASE( SG::IAuxStore, SG::IConstAuxStore ); +CLASS_DEF( SG::IAuxStore , 178378299 , 1 ) +#endif + + +#endif // not ATHCONTAINERSINTERFACES_IAUXSTORE_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreHolder.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreHolder.h new file mode 100644 index 00000000..c7d97fa3 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreHolder.h @@ -0,0 +1,80 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IAuxStoreHolder.h 570883 2013-11-16 18:47:55Z krasznaa $ +#ifndef ATHCONTAINERSINTERFACES_IAUXSTOREHOLDER_H +#define ATHCONTAINERSINTERFACES_IAUXSTOREHOLDER_H + +namespace SG { + + // Forward declaration(s): + class IAuxStore; + + /** + * @short Interface for objects taking part in direct ROOT I/O + * + * This interface needs to be implemented by classes that serve as + * auxiliary containers that we want to use in our EDM directly. + * It allows the I/O infrastructure to give a store object to the + * object implementing this interface. At that point the object given + * to this interface will be the one doing the ROOT I/O for the + * "dynamic" auxiliary variables. + * + * Currently there's a single implementation of this, + * "xAODCore/AuxContainerBase.h", but we may want to have other + * implementations later on as well. + * + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + * @author Marcin Nowak <Marcin.Nowak@cern.ch> + * + * $Revision: 570883 $ + * $Date: 2013-11-16 19:47:55 +0100 (Sat, 16 Nov 2013) $ + */ + class IAuxStoreHolder { + + public: + /// Virtual destructor to make vtable happy... + virtual ~IAuxStoreHolder() {} + + /// Give an auxiliary store object to the holder object + /// + /// The purpose of this function is to give an alternate store + /// object to this object instead of the one it uses normally. + /// + /// @param store Pointer to an object implementing direct ROOT I/O + /// + virtual void setStore( IAuxStore* store ) = 0; + + /// Return the pointer to the store object currently in use + /// + /// There's not much use case for this function yet, but it makes the + /// interface complete at least. + /// + virtual IAuxStore* getStore() const = 0; + + /// Type of the auxiliary store + /// + /// In the xAOD EDM we use auxiliary store objects in some cases to + /// describe a single object, and in most cases to describe a container + /// of objects. This enumeration declares which type the object + /// implementing this interface is. + /// + enum AuxStoreType { + AST_ObjectStore = 0, ///< The store describes a single object + AST_ContainerStore = 1 ///< The store describes a container + }; + + /// Return the type of the store object + /// + /// @see AuxStoreType + /// + virtual AuxStoreType getStoreType() const = 0; + + }; // class IAuxStoreHolder + +} // namespace SG + +#endif // ATHCONTAINERSINTERFACES_IAUXSTOREHOLDER_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreIO.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreIO.h new file mode 100644 index 00000000..3883db62 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxStoreIO.h @@ -0,0 +1,116 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IAuxStoreIO.h 584348 2014-02-20 09:21:15Z krasznaa $ +/** + * @file AthContainersInterfaces/IAuxStoreIO.h + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + * @date Aug, 2013 + * @brief Interface providing I/O for a generic auxiliary store. + */ + + +#ifndef ATHCONTAINERSINTERFACES_IAUXSTOREIO_H +#define ATHCONTAINERSINTERFACES_IAUXSTOREIO_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include <typeinfo> +#include <set> + + +namespace SG { + + +/** + * @brief Interface providing I/O for a generic auxiliary store + * + * In order to read/write the properties stored in a generic + * auxiliary store object, this interface needs to be used. + * It allows the infrastructure code to inspect the contents + * of the object, and access it in a way that allows the + * information to be passed to the persistency system. + * + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + * @author Marcin Nowak <Marcin.Nowak@cern.ch> + * + * $Revision: 584348 $ + * $Date: 2014-02-20 10:21:15 +0100 (Thu, 20 Feb 2014) $ + */ +class IAuxStoreIO +{ +public: + /// Destructor. + virtual ~IAuxStoreIO() {} + + + /** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ + virtual const void* getIOData (SG::auxid_t auxid) const = 0; + + + /** + * @brief Return the type of the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * For an aux data item of type @c T, this will usually be + * @c std::vector<T>. For standalone objects, however, it will + * usually be @c T; and @c std::vector<char> will be used instead + * of @c std::vector<bool>. + * + * Returns 0 if the requested aux data item does not exist. + */ + virtual const std::type_info* getIOType (SG::auxid_t auxid) const = 0; + + + /** + * @brief Get the list of all dynamically created variables. + */ + virtual const SG::auxid_set_t& getDynamicAuxIDs() const = 0; + + + /** + * @brief Set up the object to only expose selected data items to the IO + * @param attr The attributes for selecting the variables to be written. + * + * The convention for the formatting of the attributes expected by this + * function is still a bit in flux, documentation will be provided later. + */ + virtual void selectAux (const std::set<std::string>& /*attr*/) {} + + + /** + * @brief Get a list of all the variables that need to be written out. + * + * The return value of this function depends on the parameters passed to + * selectAux previously. + */ + virtual const SG::auxid_set_t& getSelectedAuxIDs() const { + // default all are selected + return getDynamicAuxIDs(); + } + +}; // class IAuxStoreIO + + +} // namespace SG + + +#ifndef XAOD_STANDALONE +#include "SGTools/CLASS_DEF.h" +CLASS_DEF( SG::IAuxStoreIO, 55879233, 1 ) +#endif + + +#endif // not ATHCONTAINERSINTERFACES_IAUXSTOREIO_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVector.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVector.h new file mode 100644 index 00000000..cc65b889 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVector.h @@ -0,0 +1,180 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IAuxTypeVector.h 797203 2017-02-14 19:35:56Z ssnyder $ +/** + * @file AthContainersInterfaces/IAuxTypeVector.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Abstract interface for manipulating vectors of arbitrary types. + */ + + +#ifndef ATHCONTAINERSINTERFACES_IAUXTYPEVECTOR_H +#define ATHCONTAINERSINTERFACES_IAUXTYPEVECTOR_H + + +#include <cstddef> +#include <typeinfo> + + +namespace SG { + + +class AuxDataOption; + + +/** + * @brief Abstract interface for manipulating vectors of arbitrary types. + * + * The auxiliary data for a container are stored in a set of STL vectors, + * one for each data item. However, we want to allow storing arbitrary + * types in these vectors. Thus, we define this abstract interface + * to operate on the vectors. The concrete version of this will + * own one vector. + */ +class IAuxTypeVector +{ +public: + /// Destructor. + virtual ~IAuxTypeVector() {} + + + /** + * @brief Make a copy of this vector. + */ + virtual IAuxTypeVector* clone() const = 0; + + + /** + * @brief Return a pointer to the start of the vector's data. + */ + virtual void* toPtr() = 0; + + + /** + * @brief Return a pointer to the STL vector itself. + */ + virtual void* toVector() = 0; + + + /** + * @brief Return the size of the vector. + */ + virtual size_t size() const = 0; + + + /** + * @brief Change the size of the vector. + * @param sz The new vector size. + * Returns true if it is known that iterators have not been invalidated; + * false otherwise. + */ + virtual bool resize (size_t sz) = 0; + + + /** + * @brief Change the capacity of the vector. + * @param sz The new vector capacity. + */ + virtual void reserve (size_t sz) = 0; + + + /** + * @brief Shift the elements of the vector. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + virtual void shift (size_t pos, ptrdiff_t offs) = 0; + + + /** + * @brief Insert elements into the vector via move semantics. + * @param pos The starting index of the insertion. + * @param beg Start of the range of elements to insert. + * @param end End of the range of elements to insert. + * + * @c beg and @c end define a range of container elements, with length + * @c len defined by the difference of the pointers divided by the + * element size. + * + * The size of the container will be increased by @c len, with the elements + * starting at @c pos copied to @c pos+len. + * + * The contents of the @c beg:end range will then be moved to our vector + * starting at @c pos. This will be done via move semantics if possible; + * otherwise, it will be done with a copy. + * + * Returns true if it is known that the vector's memory did not move, + * false otherwise. + */ + virtual bool insertMove (size_t pos, void* beg, void* end) = 0; + + + /** + * @brief Set an option for this variable. + * @param option The option to set. + * + * The interpretation of the option depends on the particular representation + * of the variable provided by the concrete class. + * + * Returns true if the option setting was successful; false otherwise. + */ + virtual bool setOption (const AuxDataOption& /*option*/) + { return false; } + + + /** + * @brief Make a packed version of the variable. + * + * If possible, return a new vector object that stores the data + * in a @c PackedContainer. The data itself should be _moved_ + * to the new container (so that this vector becomes empty). + * This ensures that pointers to the data are preserved. + * + * If successful, a newly-allocated object is returned. + * A null pointer is returned on failure (operation not supported, + * type can't be packed, type is already packed). + */ + virtual IAuxTypeVector* toPacked() { return 0; } + + + /** + * @brief Return the type of the complete object to be saved. + * + * For example, if the object is a @c std::vector, then we return + * the @c type_info of the vector. But if we're holding + * a @c PackedContainer, then we return the @c type_info of the + * @c PackedContainer. + * + * Can return null if the operation is not supported. In that case, + * I/O will use the type found from the variable registry. + */ + virtual const std::type_info* objType() const { return 0; } +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSINTERFACES_IAUXTYPEVECTOR_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVectorFactory.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVectorFactory.h new file mode 100644 index 00000000..764f47ca --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IAuxTypeVectorFactory.h @@ -0,0 +1,147 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersInterfaces/IAuxTypeVectorFactory.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Interface for factory objects that create vectors. + */ + + +#ifndef ATHCONTAINERSINTERFACES_IAUXTYPEVECTORFACTORY_H +#define ATHCONTAINERSINTERFACES_IAUXTYPEVECTORFACTORY_H + + +#include <cstddef> +#include <typeinfo> +#include <cstdlib> + + +namespace SG { + + +class IAuxTypeVector; + + +/** + * @brief Interface for factory objects that create vectors. + * + * The auxiliary data for a container are stored in a set of STL vectors, + * one for each data item. However, we want to allow storing arbitrary + * types in these vectors. Thus, we define an abstract interface + * to operate on the vectors, @c IAuxTypeVector. + * + * Now, we need to registry of how to create an appropriate + * @c IAuxTypeVector for a given @c std::type_info. To make that + * easier, we encapsulate the creation of those vector objects + * using this factory interface. There will be one instance of this + * for each vector type that we deal with. Usually, this interface + * will be implemented by @c AuxTypeVector; however, other implementations + * are used, for example, for reading auxiliary data from root when + * we don't know its type at compile-time. + */ +class IAuxTypeVectorFactory +{ +public: + /** + * @brief Destructor. + */ + virtual ~IAuxTypeVectorFactory() {} + + + /** + * @brief Create a vector object of this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + virtual IAuxTypeVector* create (size_t size, size_t capacity) const = 0; + + + /** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * But if @c isPacked is @c true, then @c data + * should instead point at an object of type @c SG::PackedContainer<T>. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + virtual IAuxTypeVector* createFromData (void* /*data*/, + bool /*isPacked*/, + bool /*ownFlag*/) const + { std::abort(); } + + + /** + * @brief Copy an element between vectors. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + virtual void copy (void* dst, size_t dst_index, + const void* src, size_t src_index) const = 0; + + + /** + * @brief Swap an element between vectors. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ + virtual void swap (void* a, size_t aindex, + void* b, size_t bindex) const = 0; + + + /** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ + virtual void clear (void* dst, size_t dst_index) const = 0; + + + /** + * @brief Return the size of an element of this vector type. + */ + virtual size_t getEltSize() const = 0; + + + /** + * @brief Return the @c type_info of the vector. + */ + virtual const std::type_info* tiVec() const = 0; + + + /** + * @brief True if the vectors created by this factory work by dynamic + * emulation (via @c TVirtualCollectionProxy or similar); false + * if the std::vector code is used directly. + */ + virtual bool isDynamic() const = 0; +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSINTERFACES_IAUXTYPEVECTORFACTORY_H diff --git a/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IConstAuxStore.h b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IConstAuxStore.h new file mode 100644 index 00000000..98a8322d --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/AthContainersInterfaces/IConstAuxStore.h @@ -0,0 +1,155 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IConstAuxStore.h 612954 2014-08-21 19:25:01Z ssnyder $ +/** + * @file AthContainersInterfaces/IConstAuxStore.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2013 + * @brief Interface for const operations on an auxiliary store. + */ + + +#ifndef ATHCONTAINERSINTERFACES_ICONSTAUXSTORE_H +#define ATHCONTAINERSINTERFACES_ICONSTAUXSTORE_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include <cstddef> + + +namespace SG { + + +/** + * @brief Interface for const operations on an auxiliary store. + * + * A @c DataVector may have auxiliary data associated with it. + * These data are kept in separate AuxStore objects; this defines + * the interface for const operations on such a store. + * + * An AuxStore may store a number of different aux data items; + * these are identified by an integer of type @c auxid_t. + * Each item is stored as a vector with one entry per entry + * in the containing @c DataVector. + * + * This interface provides methods for getting a const pointer + * to an existing vector of aux data items and for getting the set + * of existing aux data items. + * + * In addition, sometimes we want to add additional auxiliary data to + * an existing, const container; this is called `decorating' it. + * For example, we retrieve a const container from StoreGate, + * run some algorithm on it, and attach additional data to the object + * that can be accessed by downstream algorithms or written to a file. + * To support this, we add the @c getDecoration operation, as well + * as @c lock and @c clearDecorations. When the object is first + * being filled, it is unlocked. It gets locked when @c StoreGateSvc::setConst + * is called on it. From then on, we can only create decorations. + * Calling @c clearDecorations will restore the state back to where + * it was when @c lock was called. (Be sure that the container's + * cache also gets cleared.) + * + * @c getDecoration then works as follows: + * + * - If the item doesn't exist, then it will be created. If the container + * is locked, then the new item will be marked as a decoration. + * - If the item already exists, then we allow access only if either + * the container is not locked or the item is marked as a decoration. + */ +class IConstAuxStore +{ +public: + /// Destructor. + virtual ~IConstAuxStore() {} + + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * This should return 0 if the item doesn't exist. + */ + virtual const void* getData (SG::auxid_t auxid) const = 0; + + + /** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it then it will be created and initialized + * with default values. If the container is locked, then the new + * item will be marked as a decoration. @c size and @c capacity give + * the size for the new aux data item vector. + * + * If the data item already exists, then we return it if either the + * container is not locked or the item is marked as a decoration. + * Otherwise we throw an exception. + */ + virtual void* getDecoration (auxid_t auxid, size_t size, size_t capacity) = 0; + + + /** + * @brief Return a set of identifiers for existing data items + * in this store. + * + * This should include identifiers for all items, + * const and non-const. + */ + virtual const SG::auxid_set_t& getAuxIDs() const = 0; + + + /** + * @brief Lock the container. + * + * After this, only decorations can be changed/modified. + * If the container is already locked, this is a no-op. + */ + virtual void lock() = 0; + + + /** + * @brief Clear all decorations. + * + * Erase all decorations from the store, restoring the state to when + * @c lock was called. Be sure to clear the cache of the referencing + * container! + */ + virtual void clearDecorations() = 0; + + + /** + * @brief Return the number of elements in the store. + * + * May return 0 for a store with no aux data. + */ + virtual size_t size() const = 0; +}; + + +} // namespace SG + + + +#ifndef XAOD_STANDALONE +#include "SGTools/CLASS_DEF.h" +CLASS_DEF( SG::IConstAuxStore , 187169987 , 1 ) +#endif // not XAOD_STANDALONE + + +#endif // not ATHCONTAINERSINTERFACES_ICONSTAUXSTORE_H diff --git a/EDM/athena/Control/AthContainersInterfaces/CMakeLists.txt b/EDM/athena/Control/AthContainersInterfaces/CMakeLists.txt new file mode 100644 index 00000000..d30bbfb4 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/CMakeLists.txt @@ -0,0 +1,33 @@ +################################################################################ +# Package: AthContainersInterfaces +################################################################################ + +# Declare the package name: +atlas_subdir( AthContainersInterfaces ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/CxxUtils + Control/SGTools + PRIVATE + AtlasTest/TestTools ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) + +# Component(s) in the package: +atlas_add_test( AuxStore_traits_test + SOURCES + test/AuxStore_traits_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} CxxUtils SGTools TestTools ) + +atlas_add_test( AuxDataOption_test + SOURCES + test/AuxDataOption_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} CxxUtils SGTools TestTools ) + +# Install files from the package: +atlas_install_headers( AthContainersInterfaces ) + diff --git a/EDM/athena/Control/AthContainersInterfaces/cmt/Makefile.RootCore b/EDM/athena/Control/AthContainersInterfaces/cmt/Makefile.RootCore new file mode 100644 index 00000000..7b206c6f --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/cmt/Makefile.RootCore @@ -0,0 +1,24 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = AthContainersInterfaces +PACKAGE_PRELOAD = +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = CxxUtils +PACKAGE_TRYDEP = +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 0 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 1 +PACKAGE_REFLEX = 0 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/EDM/athena/Control/AthContainersInterfaces/cmt/requirements b/EDM/athena/Control/AthContainersInterfaces/cmt/requirements new file mode 100644 index 00000000..4da8fad4 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/cmt/requirements @@ -0,0 +1,20 @@ +package AthContainersInterfaces + +author scott snyder <snyder@bnl.gov> + +use AtlasPolicy AtlasPolicy-* + +# Only if XAOD_STANDALONE not defined. +use SGTools SGTools-* Control + +# Only with c++03. +use CxxUtils CxxUtils-* Control +use AtlasBoost AtlasBoost-* External + + +private +use TestTools TestTools-* AtlasTest + +apply_pattern UnitTest_run unit_test=AuxStore_traits +apply_pattern UnitTest_run unit_test=AuxDataOption + diff --git a/EDM/athena/Control/AthContainersInterfaces/ispellwords b/EDM/athena/Control/AthContainersInterfaces/ispellwords new file mode 100644 index 00000000..2eef389b --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/ispellwords @@ -0,0 +1,809 @@ +personal_ws-1.1 en 698 +assoPointer +persistency +IdentifiableContainer +multi +toContainedElement +GaudiKernel +situ +someone's +refcnt +GENERATEINDEXINGPOLICIES +elementShortRef +originalSize +unary +blk +arg +objectContainer +dataID +bkt +Amram +endif +typeid +fooB +ForwardIndexingPolicy +JetCollection +resized +constr +PackedArray +const's +RandomAccessIterator +CompareAndPrint +del +IProxyDict +deallocate +dep +DVLNoBase +cassert +creat +ASHSTLAllocator +ness +Resizes +autoselect +doinit +setElement +DataVector +theAsso +addHostDObj +gaudi +Dreizin +scott +theAssociatedObjects +cmt +objIndex +assocIndex +dir +ArenaAllocatorRegistry +allocator's +persistifiable +InhVectorIntLink +functor +nclear +crc +elmts +ssnyder +Predwrapper +MessageSvc +DNC +readback +binet +theTrack +DL's +DataPool +Faz +newAssoc +fdl +GenerateIndexingPolicy +ConstDataVector +AtlasReflex +fangled +fdv +LongRef +pCont's +gcc +Ilija +HistogramPersis +absFluff +liint +getAssociations +allo +isDefault +utest +ArenaCachingHandle +depcy +nctor +ELs +CVS +ClassName +destructor +tTrack +elt +hashtable's +PlainPtrElementLink +ELV +DList +DSO +resetWithKeyAndIndex +DataLinkVector +ElemLink +resetWithKey +typedef +pbad +dum +firstAssoc +cxx +theStore +BaseContainer +persistified +dvl +endAssociation +ispellwords +ILink +endHostDObjs +shortRefs +shortrefs +GenParticleIndexing +Elsing +DV's +BinaryPredicate +anOther +FooDequeLink +moveHostDObjs +theObjects +FooDeque +ArenaBase +AtlasSEAL +FNV +NoBase +icc +iCtr +NOGAUDI +swapElement +defaultHeader +objectPointer +src's +StoreGateSvc +hashtable +CopyConstructible +findProxy +BeginEvent +GNUC +toPersistentDL +iff +firstAssObject +bitsize +pCopyDerFluff +findAssociationObjects +DataVectorBase +fdvlcopy +line'll +func +ArenaHandleBaseAllocT +asDataList +CLID's +CLIDs +convertable +fdlcopy +hoc +DHAVE +functionalities +addArena +dataGet +namespaces +StoreGate +IOSTREAMS +oldElem +DataProxy +paolo +eltest +jobOs +AssociationLinks +DataLink +RVersion +pAssoc +hpp +TODO +valgrind +DataProxyStorageBase +srini +getObject +ASSCONT +cerr +proxying +ASSOCONT +DataListBase +AthenaPOOL +Calafiura +MapIndexingPolicy +param +AssociationVector +IProxyDictWithPool +persistify +changeState +canReclear +doxygen +setHashAndIndex +runtime +lcg +args +DataList +DataPtrs +rebinder +theAssociations +inserters +uint +ndtor +DVLCast +theAssociationObjects +assoStore +AssociationVectorCollection +isStreamable +irt +resetTo +AssociationVectorIterator +wronglmint +pairtype +pdata +RemoveDataPtr +theType +printf +setStorableObject +ArenaHeapSTLAllocator +iJet +doRemap +toPersistable +OBJCONT +deallocation +iTracks +getFirstAssociation +SGFolder +AssociationLinkCollection +objectIter +lhs +storeName +ArenaBlockAllocatorBase +rvalue +DerivedFluff +ElemLinkVector +ArenaHeaderGaudiClear +mem +hasher +dobjs +assoIter +Quarrie +hasAssociations +assoContainer +dereferencing +cinquanta +IdentContIndexingPolicy +DVLDataBucket +ElementLinkVector +vers +PDTR +nav +Hong +forwardContainer +cinq +eltSize +AtlasBoost +CINT +typeinfoName +reverseIterators +ArenaPoolAllocator +kwd +ndx +resize +indexingPolicy +tradeoff +ClusterContainer +oldInt +getDataSourcePointer +MacOSX +NavigationToken +asso +PlainPtrStorage +bool +shortref +shortRef +dieci +DataMap +Nir +OBJTYPE +asDataVector +ArenaHeapAllocator +DataLinks +gmake +mLink +castfn +AssociationBaseCollection +clid +deps +LWG +namespace +IOHandler +ArenaAllocatorCreatorInit +pdf +pAssocs +dflt +dfluff +pDL +reflextion +typename +typeName +DVLIterator +iTrack +getDataSource +initParams +LXR +DataBucket +pDV +pJets +refCount +snyder +ASSOBJECT +initGaudi +Srini's +multimap +pTransient +DataBucketTrait +dict +ElemLinkRefs +interoperate +nreserve +lastAssObject +theAssoc +TrackContainer +init +minRefCount +impl +OwnershipPolicy +otherElemLinkRefs +AssociativeIndexingPolicy +DataVector's +oper +IsSTLSequence +findProxyFromKey +newAss +mutators +addTrack +IncidentSvc +makeIndex +sgkey +StrictWeakOrdering +lastTrack +ClassID +classID +calaf +rbegin +containsAssociation +SetIndexingPolicy +ifndef +assocPointer +BaseConstReference +pos +PtrVector +ret +pre +params +BList +theAssocs +ArenaAllocatorBase +Dufus +GaudiClear +ppvInterface +reextracted +lookup +arghh +rhs +pointee +maxRefCount +config +toPersistentState +intL +Sep +hostDObjs +ClassIDSvc +ptr +BVec +intV +pvp +getDataSourcePointerFromGaudi +RNG +pTracks +Metafunction +ArenaHandleBase +shortIterFromLong +tCluster +successFlag +genreflex +DataProxyStorage +DataProxyStorageData +theJet +ElementType +ELVDEBUG +PtrList +AllocatorCreatorBase +asStorable +ArenaSharedHeapSTLAllocator +AthenaKernel +ChangeLog +getLastAssocation +nblock +dvlinfo +DVLInfo +PlainPtrDataLink +src +cout +IDtype +pcopy +jobO +Vec +resizePool +TestTools +dtors +DataPtr +tdefs +enums +ArenaSTLAllocator +findHostDObj +DataList's +toIndexedElement +stl +sizeof +svc +cptr +sss +checkreq +dobj +Vukotic +packageinfo +frexp +str +setData +MyObj +iter +DVLEltBase +AssociationType +clidsvc +CLIDSvc +backNavigation +toPersistent +theCluster +mustClear +storable +IInterface +AssociationObjectIterator +DefaultKey +TSS +inlined +Rajagopalan +makeFunc +savannah +ArenaBlock +multiset +GeneratorObjects +reverseLookup +DefaultState +Obreshkov +pred +malloc +myassert +AthExStoreGateExamples +DVLInfoBase +setOwner +txt +myCluster +FIXME +LIBSTDCXX +ArenaAllocatorCreator +Gemmeren +makeAllocator +JetTrackAssociation +IOVSvc +prev +newElement +beginAssociation +specializable +removeHostDObj +toAccessible +RefVector +EndEvent +PersistentState +tinfo +myassertion +elcnv +ctor +struct +vpvp +dereference +allocvec +getDataRef +ElementParameter +fdvl +AthenaROOTAccess +ControlTest +objectIndex +iHost +emacs +alloc +pElem +riid +accessor +setValid +DataObject +makeCurrent +dpint +symLink +decls +ElementLink +bb +anAss +DataSource +linkOffset +linkoffset +lookups +refVector's +DPSB +isValid +ibadlint +ForwardIterator +assoIndex +firstTrack +NDEBUG +NULLs +templated +endl +br +getDataPtr +venti +eg +dl +mainpage +VirtBases +DefaultIndexingPolicy +utests +reportStr +fd +FooDataVectorLink +CxxUtils +ivint +findInContainer +dv +DVLTYPE +RehashPolicy +ElementProxy +theObject +fn +JetTrackAssociationCollection +SGASSERTERROR +checkForRemap +iliint +toTransient +anotherString +ctors +AssociationLink +FolderItem +IdentContIndex +dereferences +iptrlint +intLF +DataModel +getLastAssociation +IP +indices +multithreaded +sstream +intLL +ld +destructors +Elts +ownPolicy +tryELRemap +li +rvalues +DeclareIndexingPolicy +Koenig +IndexingPolicies +nd +xyz +Austern +delArena +TrackParticleContainer +minSize +toAccessibleState +storagePolicy +NavFourMon +ArenaHandle +ConstDataList +ok +TrackParticle +ChronoStatSvc +ElemLinkRef +ns +findAssociation +Compwrapper +proxied +gccxml +RegisterDVLEltBaseInit +badI +DataPoolTest +os +stdcont +stdCont +initializer +lastAssoc +DVec +ri +BaseInfo +sg +ElemLinks +ElemLink's +targ +DirSearchPath +ELVRef +intVF +headp +BidirectionalIterator +cplusplus +Tavori +SGElvRef +dtor +enum +schaffer +intVL +vd +ForwardContainerConcept +InUse +sz +WG +ArenaPoolSTLAllocator +inline +typedefs +typedef's +Vo +getE +vp +sgname +sgName +rObj +SequenceIndexing +setStorable +trenta +AssociationMap +abc +thinning's +newElem +jobOptions +getAssociationObjects +myarena +lvalues +CategoryOrTraversal +PTAss +accessors +Mytype +raiseInvalidErrorBase +MyElement +rdata +adaptors +toPersistentNomap +DVL's +endcode +aFoo +ftemplate +ExtractKey +ArenaHandleBaseT +defaultDataSource +IdentifiedState +lvalue +ElementHolder +adaptor +preload +ifdef +AssociationBase +theContext +AssociationObject +ArenaHeader +ElementLinks +toIdentified +wrongvint +AssociationObjects +Baz +overridable +const +SGTools +NULLLINK +DefaultKeyState +getDataSourcePointerFunc +libstdc +persistable +SGgetDataSource +AthContainers +lexicographically +ve +D2List +D2 +wouldn +VIRTBASES2 +VIRTBASES1 +list2 +list1 +Sebastien +B3 +B2 +B1 +allocator +shouldn +unowned +D2Vec +v2 +v1 +preallocate +pCont +isConst +coverity +didn +doesn +AbsFluff +test1 +intL2 +intL2L +intL2F +resizing +dfluff5 +dfluff4 +isn +vd2 +vd1 +vb2 +vb1 +test2 +intV2 +intV2L +intV2F +intV3 +AthContainersInterfaces +AUXTYPES +interface' +IAUXELEMENT +auxid +IConstAuxStore +AuxStore +IAUXSTORE +krasznaa +IAuxStoreIO +Krasznahorkay +XAOD +AuxStores +EDM +IAuxElement +SFINAE +NoAuxStore +AUXSTORE3 +IAuxStore +CONSTAUXSTORE +IAUXTYPEVECTOR +ptrdiff +getIOType +getIOData +getVector +getWritableAuxIDs +wscript +that'll +unordered +SLC6 +AuxTypes +IAuxStoreHolder +Nowak +Marcin +xAODCore +vtable +xAOD +AuxStoreType +IAuxTypeVector +initialiser +hwafize +yml +hscript +RootCore +getSelectedAuxIDs +selectAux +AuxTypePlaceholder +Obo +AuxTypeVector +dst +bindex +aindex +TVirtualCollectionProxy +IAUXTYPEVECTORFACTORY +clearDecorations +getDecoration +AthenaOutputStream +attr +MacOS +setOption +AUXDATAOPTION +IAuxSetOption +PackedContainer +IAuxTypeVectorFactory +objType +toPacked diff --git a/EDM/athena/Control/AthContainersInterfaces/share/AuxDataOption_test.ref b/EDM/athena/Control/AthContainersInterfaces/share/AuxDataOption_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/share/AuxDataOption_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthContainersInterfaces/share/AuxStore_traits_test.ref b/EDM/athena/Control/AthContainersInterfaces/share/AuxStore_traits_test.ref new file mode 100644 index 00000000..ef4acc29 --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/share/AuxStore_traits_test.ref @@ -0,0 +1,9 @@ +int SG::NoAuxStore SG::NoAuxStore SG::NoAuxStore SG::NoAuxStore +vector<int> SG::NoAuxStore SG::NoAuxStore SG::NoAuxStore SG::NoAuxStore +DV<int> SG::NoAuxStore SG::NoAuxStore SG::NoAuxStore SG::NoAuxStore +D SG::IAuxStore SG::IConstAuxStore SG::IAuxStore SG::IConstAuxStore +DV<D> SG::IAuxStore SG::IConstAuxStore SG::IAuxStore SG::IConstAuxStore +W SG::IAuxStore SG::IConstAuxStore SG::IAuxStore SG::IConstAuxStore +X Y Z Y Z +W* SG::IAuxStore SG::IConstAuxStore SG::IAuxStore SG::IConstAuxStore +X* Y Z Y Z diff --git a/EDM/athena/Control/AthContainersInterfaces/test/AuxDataOption_test.cxx b/EDM/athena/Control/AthContainersInterfaces/test/AuxDataOption_test.cxx new file mode 100644 index 00000000..8cb7ec5b --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/test/AuxDataOption_test.cxx @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersInterfaces/test/AuxDataOption_traits_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Regression test for AuxDataOption_traits. + */ + + +#undef NDEBUG +#include "AthContainersInterfaces/AuxDataOption.h" +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + + SG::AuxDataOption o1 ("o1", static_cast<int> (1)); + assert (o1.name() == "o1"); + assert (o1.intVal() == 1); + assert (o1.floatVal() == 1); + + SG::AuxDataOption o2 ("o2", static_cast<float> (2.5)); + assert (o2.name() == "o2"); + assert (o2.intVal() == 2); + assert (o2.floatVal() == 2.5); + + SG::AuxDataOption o3 ("o3", static_cast<double> (3.5)); + assert (o3.name() == "o3"); + assert (o3.intVal() == 3); + assert (o3.floatVal() == 3.5); +} + + +int main() +{ + test1(); + return 0; +} + diff --git a/EDM/athena/Control/AthContainersInterfaces/test/AuxStore_traits_test.cxx b/EDM/athena/Control/AthContainersInterfaces/test/AuxStore_traits_test.cxx new file mode 100644 index 00000000..732fa59c --- /dev/null +++ b/EDM/athena/Control/AthContainersInterfaces/test/AuxStore_traits_test.cxx @@ -0,0 +1,74 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxStore_traits_test.cxx 627017 2014-11-07 21:46:42Z ssnyder $ +/** + * @file AthContainersInterfaces/test/AuxStore_traits_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2013 + * @brief Regression test for AuxStore_traits. + */ + + +#undef NDEBUG +#include "AthContainersInterfaces/AuxStore_traits.h" +#include "AthContainersInterfaces/CLASS_AUXSTORE.h" +#include <iostream> +#include <vector> + + +void whichClass (const SG::NoAuxStore*) { std::cout << "SG::NoAuxStore "; } +void whichClass (const SG::IAuxStore*) { std::cout << "SG::IAuxStore "; } +void whichClass (const SG::IConstAuxStore*) { std::cout << "SG::IConstAuxStore "; } + + + +template <class DOBJ> +void testit (const std::string& name) +{ + typedef SG::AuxStore_traits<DOBJ> traits; + std::cout << name << " "; + whichClass ((typename traits::type*)0); + whichClass ((typename traits::const_type*)0); + std::cout << traits::typeName() << " " << traits::const_typeName() << "\n"; +} + + +template <class T> +struct DV +{ + typedef T base_value_type; +}; + + +struct D : public SG::IAuxElement {}; + + +struct W {}; +CLASS_AUXSTORE(W) + +struct X {}; +struct Y {}; +struct Z {}; +CLASS_AUXSTORE3(X, Y, Z) + + +void whichClass (const Y*) { std::cout << "Y "; } +void whichClass (const Z*) { std::cout << "Z "; } + + +int main() +{ + testit<int> ("int"); + testit<std::vector<int> > ("vector<int>"); + testit<DV<int> > ("DV<int>"); + testit<D> ("D"); + testit<DV<D> > ("DV<D>"); + testit<W> ("W"); + testit<X> ("X"); + testit<W*> ("W*"); + testit<X*> ("X*"); + + return 0; +} diff --git a/EDM/athena/Control/AthLinks/AthLinks/AssociationMap.h b/EDM/athena/Control/AthLinks/AthLinks/AssociationMap.h new file mode 100644 index 00000000..3077bd46 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/AssociationMap.h @@ -0,0 +1,244 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHLINKS_ASSOCIATIONMAP_H +#define ATHLINKS_ASSOCIATIONMAP_H + +#define ASSOCIATION_CONTEXT +#define ASSOCIATIONMAP_CONTEXT + +/*! \brief templated base class for a look-up map for associations + * + * The templated base class \c AssociationMap provides all functionality to + * support a mapped look-up between object of a given type and their + * associations, typically of a different type (many-to-many look-up). + * Concrete objects instantiated from implementation classes derived from + * \c AssociationMap are not automatically storable. The concrete class needs + * to either be \c DataObject itself, or the corresponding object needs to + * be collected into a storable \c DataVector. + * + * The internal storage model is a matrix, where the rows are keyed by the + * object pointer and the columns are pointers to associations. The number of + * columns (= associations) typically varies row-by-row. + * + * \author Peter Loch <loch@physics.arizona.edu> + * \date June 1, 2004 - first implementation + */ + +#include "AthLinks/ElementLink.h" +#include "AthLinks/ElementLinkVector.h" +#include "AthLinks/tools/GenerateIndexingPolicy.h" + +#include <map> +#include <list> +#include <algorithm> + +template<class OBJCONT,class ASSCONT> +class AssociationMap +{ + public: + + /*! \name Argument and Internal Store Types */ + /*@{*/ + typedef OBJCONT object_container_type; + typedef typename object_container_type::base_value_type object_type; + typedef + typename + SG::GenerateIndexingPolicy<object_container_type>::type::index_type + object_index_type; + typedef ElementLink<object_container_type> object_link; + typedef typename std::list<const object_type*> object_list; + + typedef ASSCONT asso_container_type; + typedef typename asso_container_type::base_value_type asso_type; + typedef + typename + SG::GenerateIndexingPolicy<asso_container_type>::type::index_type + asso_index_type; + typedef typename std::list<const asso_type*> asso_list; + typedef ElementLink<asso_container_type> asso_link; + typedef ElementLinkVector<asso_container_type> asso_store; + typedef typename asso_store::const_iterator asso_store_iterator; + typedef typename std::map<object_link,asso_store> store_type; + typedef typename store_type::iterator store_iterator_type; + /*@}*/ + + /*! \name Constructors and Destructor */ + /*@{*/ + AssociationMap(); + virtual ~AssociationMap(); + /*@}*/ + + + /*! \name Store Iterator Types */ + /*@{*/ +#include "AthLinks/tools/AssociationVectorIterator.h" + /*! \brief association iterator type */ + typedef AssociationVectorIterator asso_iterator; +#include "AthLinks/tools/AssociationObjectIterator.h" + /*! \brief object iterator type */ + typedef AssociationObjectIterator object_iterator; + /*@}*/ + + /*! \name Add Associations + * + * \param objectContainer - pointer to the object container + * \param objectIndex - index of object in container + * \param objectPointer - pointer to object + * \param assoContainer - container of potentially associated objects + * \param assoIndex - index of associated object in container + * \param assoPointer - pointer to associated object + */ + /*@{*/ + void addAssociation(const object_container_type* objectContainer, + const object_index_type& objectIndex, + const asso_container_type* assoContainer, + const asso_index_type& assoIndex); + void addAssociation(const object_container_type* objectContainer, + const object_type* objectPointer, + const asso_container_type* assoContainer, + const asso_type* assoPointer); + void addAssociation(const object_link& objectLink, + const asso_link& assoLink); + /*@}*/ + + /*! \name Object and Association Iterators + * + * The association iterators are returned for a given object, which can + * either be referenced by its pointer or its iterator in the internal store. + * \param objectPointer - pointer to a given object + * \param objectIter - iterator to a given object + */ + /*@{*/ + /*! \brief begin iterator for objects */ + object_iterator beginObject() const; + /*! \brief end iterator for objects */ + object_iterator endObject() const; + + /*! \brief begin iterator for associations */ + asso_iterator beginAssociation(const object_type* objectPointer) const; + asso_iterator beginAssociation(const object_iterator& objectIter) const; + /*! \brief end iterator for associations */ + asso_iterator endAssociation(const object_type* objectPointer) const; + asso_iterator endAssociation(const object_iterator& objectIter) const; + /*@}*/ + + /// \brief get association iterators by object iterator + + + + /// \brief type-safe retrieval of object pointer from iterator + const object_type* getObject(const object_iterator& objectIter) const + { return (*objectIter).getObject(); } + + /// \brief finding an object with allocation + object_iterator findObject(const object_type* theObject) const + { return object_iterator(m_associationMap).find(theObject); } + + /// \brief testing if object is in store + bool containsObject(const object_type* theObject) const + { return this->findObject(theObject) != this->endObject(); } + + /// \brief retrieve number of objects in store + size_t getNumberOfObjects() const { return this->size(); } + + /// \brief associations iterator access + /// + /// The associations are accessed as function of the row key (the object). + + + const asso_type* getAssociation(asso_iterator assoIter) const + { return *assoIter; } + + /// \brief find association + asso_iterator findAssociation(const object_iterator& objectIter, + const asso_type* assoPointer) const + { return objectIter.findAssociation(assoPointer); } + asso_iterator findAssociation(const object_type* objectPointer, + const asso_type* assoPointer) const; + + /// \brief containment check + bool containsAssociation(const object_iterator& objectIter, + const asso_type* assoPointer) const + { return objectIter.containsAssociation(assoPointer); } + + bool containsAssociation(const object_type* objectPointer, + const asso_type* assoPointer) const; + bool containsAssociation(const asso_type* assoPointer) const; + + /// \brief get all objects for a given association + bool getObjects(const asso_type* assoPointer, object_list& theObjects) const; + + /// \brief get all objects for a given association + bool getObjects(const asso_iterator& assoIter, object_list& theObjects) const + { return this->getObjects(*assoIter,theObjects); } + + /// \brief get all associations for a given object + bool getAssociations(const object_type* objPointer, asso_list& assocs) const; + + /// \brief get all associations for a given object + bool getAssociations(const object_iterator& objIter, asso_list& assocs) const + { return this->getAssociations(objIter.getObject(),assocs); } + + /// \brief get number of associations + size_t size() { return m_associationMap.size(); } + + /// \brief get number of associations + size_t size() const { return m_associationMap.size(); } + + size_t size(const object_type* objectPointer) const; + + size_t getNumberOfAssociations(const object_type* objectPointer) const + { return this->size(objectPointer); } + + size_t size(const object_iterator& objectIter) const + { return objectIter.getNumberOfAssociations(); } + + size_t getNumberOfAssociations(const object_iterator& objectIter) const + { return this->size(objectIter); } + + protected: + + /// \brief internal store + store_type m_associationMap; + + /// \brief internally used find method + store_iterator_type internalFind(const object_link& objectLink, + const asso_link& assoLink) + { + // check key + store_iterator_type mapEnd = m_associationMap.end(); + store_iterator_type foundIter = mapEnd; + for ( store_iterator_type iMap = m_associationMap.begin(); + iMap != mapEnd; + ++iMap ) { + // look for the address of the pointed-at object + // must dereference the ElementLink pointer + if ( iMap->first.cptr() == objectLink.cptr() ) { + foundIter = iMap; + break; + } + } + + if ( foundIter == m_associationMap.end() ) { return foundIter; } + // check data + if ( std::find((foundIter->second).begin(), + (foundIter->second).end(), + assoLink) != + (foundIter->second).end() ) + { return foundIter; } + // not found at all + return m_associationMap.end(); + } + + /// \brief internally used function to add links to store + bool addToStore(const object_link& objectLink, const asso_link& assoLink); + +}; + +#include "AthLinks/AssociationMap.icc" + +#undef ASSOCIATION_CONTEXT +#undef ASSOCIATIONMAP_CONTEXT +#endif diff --git a/EDM/athena/Control/AthLinks/AthLinks/AssociationMap.icc b/EDM/athena/Control/AthLinks/AthLinks/AssociationMap.icc new file mode 100644 index 00000000..98982555 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/AssociationMap.icc @@ -0,0 +1,285 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +///////////////////////////////// +// Constructors and Destructor // +///////////////////////////////// + +template<class OBJCONT,class ASSCONT> +AssociationMap<OBJCONT,ASSCONT>::AssociationMap() +{ } + +template<class OBJCONT,class ASSCONT> +AssociationMap<OBJCONT,ASSCONT>::~AssociationMap() +{ + m_associationMap.clear(); +} + +//////////////////////////////////// +// Add Association Implementation // +//////////////////////////////////// + +// add using indices +template<class OBJCONT,class ASSCONT> +void +AssociationMap<OBJCONT,ASSCONT>::addAssociation(const object_container_type* + objectContainer, + const object_index_type& + objectIndex, + const asso_container_type* + assoContainer, + const asso_index_type& + assoIndex) +{ + // object link + object_link objectLink( *objectContainer, objectIndex ); + objectLink.setElement( (*objectContainer)[objectIndex] ); + + // association link + asso_link assoLink( *assoContainer, assoIndex ); + assoLink.setElement( (*assoContainer)[assoIndex]); + + // add to store + this->addToStore(objectLink,assoLink); +} + +// add using pointers +template<class OBJCONT,class ASSCONT> +void +AssociationMap<OBJCONT,ASSCONT>::addAssociation(const object_container_type* + objectContainer, + const object_type* + objectPointer, + const asso_container_type* + assoContainer, + const asso_type* + assoPointer) +{ + // add to store + this->addToStore( object_link( objectPointer, *objectContainer ), + asso_link ( assoPointer, *assoContainer ) ); +} + +// add using links +template<class OBJCONT,class ASSCONT> +void +AssociationMap<OBJCONT,ASSCONT>::addAssociation(const object_link& + objectLink, + const asso_link& + assoLink) +{ + // add to store + this->addToStore( objectLink, assoLink ); +} + +///////////////////// +// Iterator Access // +///////////////////// + +// first object +template<class OBJCONT,class ASSCONT> +inline typename AssociationMap<OBJCONT,ASSCONT>::object_iterator +AssociationMap<OBJCONT,ASSCONT>::beginObject() const +{ + return object_iterator(m_associationMap).begin(); +} + +// last object ++ +template<class OBJCONT,class ASSCONT> +inline typename AssociationMap<OBJCONT,ASSCONT>::object_iterator +AssociationMap<OBJCONT,ASSCONT>::endObject() const +{ + return object_iterator(m_associationMap).end(); +} + +template<class OBJCONT,class ASSCONT> +inline typename AssociationMap<OBJCONT,ASSCONT>::asso_iterator +AssociationMap<OBJCONT,ASSCONT>::beginAssociation(const object_iterator& + objectIter ) const +{ + return this->beginAssociation(objectIter.getObject()); +} + +template<class OBJCONT,class ASSCONT> +inline typename AssociationMap<OBJCONT,ASSCONT>::asso_iterator +AssociationMap<OBJCONT,ASSCONT>::endAssociation(const object_iterator& + objectIter ) const +{ + return this->endAssociation(objectIter.getObject()); +} + +// association begin iterator +template<class OBJCONT,class ASSCONT> +typename AssociationMap<OBJCONT,ASSCONT>::asso_iterator +AssociationMap<OBJCONT,ASSCONT>::beginAssociation(const object_type* + objectPointer) const +{ + // find object + object_iterator foundIter = this->findObject(objectPointer); + + // object found + if ( foundIter != this->endObject() ) + { + return foundIter.getFirstAssociation(); + } + // dummy end() + else + { + return object_iterator(m_associationMap, + m_associationMap.end()).getLastAssociation(); + } +} + +// association end iterator +template<class OBJCONT,class ASSCONT> +typename AssociationMap<OBJCONT,ASSCONT>::asso_iterator +AssociationMap<OBJCONT,ASSCONT>::endAssociation(const object_type* + objectPointer) const +{ + // find object + object_iterator foundIter = this->findObject(objectPointer); + + // object found + if ( foundIter != this->endObject() ) + { + return foundIter.getLastAssociation(); + } + // dummy end() + else + { + return object_iterator(m_associationMap, + m_associationMap.end()).getLastAssociation(); + } +} + +//////////////////////////// +// Store Parameter Access // +//////////////////////////// + +template<class OBJCONT,class ASSCONT> +size_t +AssociationMap<OBJCONT,ASSCONT>::size(const object_type* objectPointer) const +{ + object_iterator foundIter = this->findObject(objectPointer); + if ( foundIter != this->endObject() ) + { + return this->size(foundIter); + } + return 0; +} + +///////////// +// Finders // +///////////// + + +// find association for given object +template<class OBJCONT,class ASSCONT> +typename AssociationMap<OBJCONT,ASSCONT>::asso_iterator +AssociationMap<OBJCONT,ASSCONT>::findAssociation(const object_type* objectPointer, + const asso_type* assoPointer) + const +{ + // find object first + object_iterator foundIter = object_iterator(m_associationMap).find(objectPointer); + if ( foundIter == this->endObject() ) + { + return object_iterator(m_associationMap, + m_associationMap.end()).getLastAssociation(); + } + // find association + return (foundIter.second()).find(assoPointer); +} + +// check on association for a given object +template<class OBJCONT,class ASSCONT> +bool +AssociationMap<OBJCONT,ASSCONT>::containsAssociation(const object_type* objectPointer, + const asso_type* assoPointer) const +{ + const object_iterator obj = this->findObject( objectPointer ); + if ( obj != endObject() ) { + return obj.containsAssociation(assoPointer); + } else { + return false; + } +} + +// find if it contains association anywhere +template<class OBJCONT,class ASSCONT> +bool +AssociationMap<OBJCONT,ASSCONT>::containsAssociation(const asso_type* + assoPointer) + const +{ + const object_iterator lastObj = this->endObject(); + for ( object_iterator objItr = this->beginObject(); + objItr != lastObj; + ++objItr ) { + asso_iterator lastAsso = this->endAssociation( objItr ); + for ( asso_iterator assItr = this->beginAssociation(objItr); + assItr != lastAsso; + ++assItr ) { + if ( *assItr == assoPointer ) { + return true; + } + }//> end loop over associated objects + }//> end loop over objects + + return false; +} + +// retrieve all objects for a given association +template<class OBJCONT,class ASSCONT> +bool +AssociationMap<OBJCONT,ASSCONT>::getObjects(const asso_type* assoPointer, + object_list& theObjects) const +{ + const object_iterator objEnd = this->endObject(); + for ( object_iterator objItr = this->beginObject(); + objItr != objEnd; + ++objItr ) { + const object_type* pObj = objItr.getObject(); + if ( this->containsAssociation(pObj,assoPointer) ) { + theObjects.push_back(pObj); + } + } + return theObjects.size() > 0; +} + +// retrieve all associated-objects for a given object +template<class OBJCONT,class ASSCONT> +bool +AssociationMap<OBJCONT,ASSCONT>::getAssociations(const object_type* objPointer, + asso_list& assocs) const +{ + const size_t origSize = assocs.size(); + const asso_iterator assocEnd = this->endAssociation(objPointer); + for ( asso_iterator assocItr = this->beginAssociation(objPointer); + assocItr != assocEnd; + ++assocItr ) { + assocs.push_back( *assocItr ); + } + return assocs.size() > origSize; +} + +/////////////////////////////////////////////////////////////////// +/// Protected methods: +/////////////////////////////////////////////////////////////////// + +template<class OBJCONT,class ASSCONT> +bool +AssociationMap<OBJCONT,ASSCONT>::addToStore(const object_link& objectLink, + const asso_link& assoLink) +{ + // check if already in (no association to be stored twice) + if ( this->internalFind(objectLink,assoLink) != m_associationMap.end() ) { + return false; + } else { + // store + m_associationMap[objectLink].push_back(assoLink); + return true; + } +} + diff --git a/EDM/athena/Control/AthLinks/AthLinks/AthLinksDict.h b/EDM/athena/Control/AthLinks/AthLinks/AthLinksDict.h new file mode 100644 index 00000000..85d0478a --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/AthLinksDict.h @@ -0,0 +1,8 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthLinks/tools/DataProxyHolder.h" +#include "AthLinks/ElementLinkBase.h" +#include "AthLinks/ElementLinkVectorBase.h" +#include "AthLinks/DataLinkBase.h" diff --git a/EDM/athena/Control/AthLinks/AthLinks/DataLink.h b/EDM/athena/Control/AthLinks/AthLinks/DataLink.h new file mode 100644 index 00000000..91267c4f --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/DataLink.h @@ -0,0 +1,324 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataLink.h 714258 2015-12-12 04:18:16Z ssnyder $ +/** + * @file DataLink.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Object reference supporting deferred reading from StoreGate. + */ + + +#ifndef ATHLINKS_DATALINK_H +#define ATHLINKS_DATALINK_H + + +#include "AthLinks/DataLinkBase.h" +#include "SGTools/ClassID_traits.h" +#include "AthenaKernel/DefaultKey.h" +class IProxyDict; + + +/** + * @brief Object reference supporting deferred reading from StoreGate. + * + * This is a kind of smart pointer that can reference objects in StoreGate + * by key. This allows deferred-reading semantics, and also allows references + * to objects that may be in a different physical data file (`back-navigation'). + * + * For example: + * + *@code + * DataLink<MyClass> link ("mykey"); + * ... + * // Look up the object `mykey' of class MyClass in StoreGate. + * const MyClass* obj = *link; + @endcode + * + * You can also initialize a link directly with a pointer: + * + *@code + * MyClass* obj = ...; + * DataLink<MyClass> link (obj); + @endcode + * + * However, if the object has not been recorded in the event store, + * the possible operations on the link will be limited. (In particular, + * such a link cannot be made persistent.) + * + * A @c DataLink can exist in one of three states: + * + * - A null reference. + * - Referring to an object in StoreGate. In this case, the link refers + * to the @c DataProxy for the referred-to object. + * - Referring to an object directly by pointer. When you initialize + * a link from a pointer, the link will try to find the corresponding + * proxy. However, if one doesn't exist, the link will remember the pointer + * directly. If a subsequent operation is attempted that requires + * the proxy (such as @c toPersistent or getting the key) and the object + * still isn't in StoreGate, @c SG::ExcPointerNotInSG will be thrown. + * + * Internally, a link stores a hashed version of the SG key + CLID; + * this is the part that's persistent. (In the case of a link referencing + * an object not in SG, this field is 0.) There is also a transient + * pointer to either the proxy or the object itself (if the object is not + * in SG). This latter pointer is factored out as @c DataProxyHolder + * in order to share implementation with @c ElementLink. Further, everything + * which does not depend on the @c STORABLE template parameter, including + * all the object state, is factored out into the non-templated base class + * @c DataLinkBase. + * + * If the link is being saved directly with ROOT, then @c toPersistent + * should be called prior to writing. This will ensure that the + * hashed StoreGate key is set correctly (and will raise an exception + * if the link is referencing an object not in SG). This will also + * handle any remapping of the link. When a link is read directly + * from ROOT, @c toTransient should be called to set the proxy pointer. + * This would normally be done via a ROOT read rule. + * + * A link references objects in a particular event store. + * When a link is constructed, a global default store is used + * (see SGTools/CurrentEventStore.h). If a link is subsequently modified, + * it stays associated with the same store, unless the link was null + * or was referencing an object directly by pointer, in which case + * the global default is again used. Alternatively, the event + * store may be passed explicitly using the optional @c sg parameter. + */ +template <class STORABLE> +class DataLink + : public DataLinkBase +{ +public: + /// Names for the referenced type and derivatives. + typedef STORABLE value_type; + typedef STORABLE* pointer; + typedef const STORABLE* const_pointer; + typedef STORABLE& reference; + typedef const STORABLE& const_reference; + + /// A string SG key. + typedef DataLinkBase::ID_type ID_type; + + /// A hashed SG key. + typedef DataLinkBase::sgkey_t sgkey_t; + + + /** + * @brief Return the CLID for the class that we reference. + */ + static const CLID& classID(); + + + //======================================================================== + /** @name Constructors. */ + //@{ + + + /** + * @brief Default constructor --- gives the equivalent of a NULL pointer. + */ + DataLink(); + + + /** + * @brief Constructor --- link to a STORABLE using a transient ref to it. + * @param data The object to which to link. + * @param sg Associated store; if 0, use the global default. + */ + DataLink(const_reference data, IProxyDict* sg=0); + + + /** + * @brief Constructor --- link to a STORABLE using a transient pointer to it. + * @param data The object to which to link. + * @param sg Associated store; if 0, use the global default. + */ + DataLink(const_pointer pdata, IProxyDict* sg=0); + + + /** + * @brief Constructor --- link to a STORABLE using a string ID. + * @param dataID Key of the object. + * @param sg Associated store; if 0, use the global default. + */ + DataLink(const ID_type& dataID, IProxyDict* sg=0); + + + /** + * @brief Constructor --- link to a STORABLE using a hashed ID. + * @param key Hashed key of the object. + * @param sg Associated store; if 0, use the global default. + * + * May throw @c ExcCLIDMismatch. + */ + DataLink(sgkey_t key, IProxyDict* sg=0); + + + /** + * @brief Constructor from a hashed key and a proxy holder object. + * Used internally for EL -> DL conversion. + * @param key Hashed key of the object. + * @param holder Internal holder object for the proxy. + */ + DataLink(sgkey_t key, const SG::DataProxyHolder& holder); + + + //@} + //======================================================================== + /** @name Setters. */ + //@{ + + + /** + * @brief Set the link to an object given by a reference. + * @param data The object to which to link. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void toStorableObject(const_reference data, IProxyDict* sg = 0); + + + /** + * @brief Set the link to an object given by a string key. + * @param dataID Key of the object. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void toIdentifiedObject(const ID_type& dataID, IProxyDict* sg = 0); + + + /** + * @brief Set the link to an object given by a hashed key. + * @param key Hashed key of the object. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ + void toIdentifiedObject(sgkey_t key, IProxyDict* sg = 0); + + + /** + * @brief Set the link to the default object of this type. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * Note that this is _not_ the same as clearing the link + * (use @c clear for that). This produces a link that will resolve + * to any object in SG of the given type, provided that there is only + * one of them. (An attempt to dereference an ambiguous default link + * will give an error.) + */ + void toDefaultObject (IProxyDict* sg = 0); + + + //@} + //======================================================================== + /** @name Accessors. */ + //@{ + + /** + * @brief Return a pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + const_pointer getDataPtr() const; + + + /** + * @brief Return a pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + pointer getDataNonConstPtr(); + + + /** + * @brief Dereference the link. + */ + const_reference operator* () const; + + + /** + * @brief Dereference the link. + */ + const_pointer operator->() const; + + + /** + * @brief Dereference the link. + */ + operator const_pointer() const; + + + /** + * @brief Dereference the link. + */ + const_pointer cptr() const; + + + /** + * @brief Test to see if the link is dereferencable. + */ + bool isValid() const; + + + + /** + * @brief True if the link is not dereferencable. + */ + bool operator!() const; + + + // Inherited from base class: + // bool isDefault() const; + // const ID_type& dataID() const; + // sgkey_t key() const; + // void clear(); + // SG::DataProxy* proxy (bool nothrow = false) const; + // IProxyDict* source() const; + // bool toTransient (IProxyDict* sg = 0); + // bool toPersistent(); + // bool toPersistentNoRemap(); + // bool operator== (const DataLinkBase& other) const; + // bool operator!= (const DataLinkBase& other) const; + + +private: + /** + * @brief Return a (void) pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + const void* storable() const; + + + /** + * @brief Return a (void) pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + void* storableNonConst(); +}; + + +#include "AthLinks/DataLink.icc" + + +#endif // not ATHLINKS_DATALINK_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/DataLink.icc b/EDM/athena/Control/AthLinks/AthLinks/DataLink.icc new file mode 100644 index 00000000..e2323b4a --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/DataLink.icc @@ -0,0 +1,319 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataLink.icc 714258 2015-12-12 04:18:16Z ssnyder $ +/** + * @file AthLinks/DataLink.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Object reference supporting deferred reading from StoreGate. + */ + + +#include "AthLinks/exceptions.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/DataProxy.h" + + +/** + * @brief Return the CLID for the class that we reference. + */ +template <typename STORABLE> +inline +const CLID& DataLink<STORABLE>::classID() +{ + return ClassID_traits<value_type>::ID(); +} + + +/** + * @brief Default constructor --- gives the equivalent of a NULL pointer. + */ +template <typename STORABLE> +inline +DataLink<STORABLE>::DataLink() +{ +} + + +/** + * @brief Constructor --- link to a STORABLE using a transient ref to it. + * @param data The object to which to link. + * @param sg Associated store; if 0, use the global default. + */ +template <typename STORABLE> +inline +DataLink<STORABLE>::DataLink(const_reference data, IProxyDict* sg/*=0*/) + : DataLinkBase (&data, classID(), sg) +{ +} + + +/** + * @brief Constructor --- link to a STORABLE using a transient pointer to it. + * @param data The object to which to link. + * @param sg Associated store; if 0, use the global default. + */ +template <typename STORABLE> +inline +DataLink<STORABLE>::DataLink(const_pointer pdata, IProxyDict* sg/*=0*/) + : DataLinkBase (pdata, classID(), sg) +{ +} + + +/** + * @brief Constructor --- link to a STORABLE using a string ID. + * @param dataID Key of the object. + * @param sg Associated store; if 0, use the global default. + */ +template <typename STORABLE> +inline +DataLink<STORABLE>::DataLink(const ID_type& dataID, + IProxyDict* sg /*=0*/) + : DataLinkBase (dataID, classID(), sg) +{ +} + + +/** + * @brief Constructor --- link to a STORABLE using a hashed ID. + * @param key Hashed key of the object. + * @param sg Associated store; if 0, use the global default. + * + * May throw @c ExcCLIDMismatch. + */ +template <typename STORABLE> +inline +DataLink<STORABLE>::DataLink(sgkey_t key, IProxyDict* sg /*=0*/) + : DataLinkBase (key, classID(), sg) +{ +} + + +/** + * @brief Constructor from a hashed key and a proxy holder object. + * Used internally for EL -> DL conversion. + * @param key Hashed key of the object. + * @param holder Internal holder object for the proxy. + */ +template <typename STORABLE> +inline +DataLink<STORABLE>::DataLink(sgkey_t key, const SG::DataProxyHolder& holder) + : DataLinkBase (key, holder) +{ +} + + +/** + * @brief Set the link to an object given by a reference. + * @param data The object to which to link. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <typename STORABLE> +inline +void DataLink<STORABLE>::toStorableObject(const_reference data, + IProxyDict* sg /*= 0*/) +{ + DataLinkBase::toStorableObject (&data, classID(), sg); +} + + +/** + * @brief Set the link to an object given by a string key. + * @param dataID Key of the object. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <typename STORABLE> +inline +void DataLink<STORABLE>::toIdentifiedObject(const ID_type& dataID, + IProxyDict* sg /*= 0*/) +{ + DataLinkBase::toIdentifiedObject (dataID, classID(), sg); +} + + +/** + * @brief Set the link to an object given by a hashed key. + * @param key Hashed key of the object. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ +template <typename STORABLE> +inline +void DataLink<STORABLE>::toIdentifiedObject(sgkey_t key, + IProxyDict* sg /*= 0*/) +{ + DataLinkBase::toIdentifiedObject (key, classID(), sg); +} + + +/** + * @brief Set the link to the default object of this type. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * Note that this is _not_ the same as clearing the link + * (use @c clear for that). This produces a link that will resolve + * to any object in SG of the given type, provided that there is only + * one of them. (An attempt to dereference an ambiguous default link + * will give an error.) + */ +template <typename STORABLE> +inline +void DataLink<STORABLE>::toDefaultObject (IProxyDict* sg /*= 0*/) +{ + DataLinkBase::toIdentifiedObject (SG::DEFAULTKEY, classID(), sg); +} + + +/** + * @brief Return a pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <typename STORABLE> +inline +typename DataLink<STORABLE>::const_pointer +DataLink<STORABLE>::getDataPtr() const +{ + return reinterpret_cast<const_pointer> (this->storable()); +} + + +/** + * @brief Return a pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <typename STORABLE> +inline +typename DataLink<STORABLE>::pointer +DataLink<STORABLE>::getDataNonConstPtr() +{ + return reinterpret_cast<pointer> (this->storableNonConst()); +} + + +/** + * @brief Dereference the link. + */ +template< typename STORABLE> +inline +typename DataLink< STORABLE >::const_reference +DataLink< STORABLE >::operator* () const +{ + const_pointer p = this->getDataPtr(); + if (!p) + throwInvalidLink(); + return *p; +} + + +/** + * @brief Dereference the link. + */ +template< typename STORABLE> +inline +typename DataLink< STORABLE >::const_pointer +DataLink< STORABLE >::operator->() const +{ + return this->getDataPtr(); +} + + +/** + * @brief Dereference the link. + */ +template< typename STORABLE> +inline +DataLink<STORABLE>::operator const_pointer() const +{ + return cptr(); +} + + +/** + * @brief Dereference the link. + */ +template< typename STORABLE> +inline +typename DataLink< STORABLE >::const_pointer +DataLink< STORABLE >::cptr() const +{ + return this->getDataPtr(); +} + + +/** + * @brief Test to see if the link is dereferencable. + */ +template <typename STORABLE> +inline +bool +DataLink<STORABLE>::isValid() const +{ + return 0 != getDataPtr(); +} + + +/** + * @brief True if the link is not dereferencable. + */ +template <typename STORABLE> +inline +bool DataLink<STORABLE>::operator!() const +{ + return !isValid(); +} + + +/** + * @brief Return a (void) pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <typename STORABLE> +inline +const void* DataLink<STORABLE>::storable() const +{ + typedef STORABLE* fn_t (SG::DataProxy*); + fn_t* fn = &SG::DataProxy_cast<STORABLE>; + return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID()); +} + + +/** + * @brief Return a (void) pointer to the currently-referenced object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <typename STORABLE> +inline +void* DataLink<STORABLE>::storableNonConst() +{ + typedef STORABLE* fn_t (SG::DataProxy*); + fn_t* fn = &SG::DataProxy_cast<STORABLE>; + return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID()); +} + + + + diff --git a/EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.h b/EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.h new file mode 100644 index 00000000..1df04118 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.h @@ -0,0 +1,306 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataLinkBase.h 714258 2015-12-12 04:18:16Z ssnyder $ +/** + * @file AthLinks/DataLinkBase.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Type-independent part of @c DataLink; holds the persistent state. + */ + + +#ifndef ATHLINKS_DATALINKBASE_H +#define ATHLINKS_DATALINKBASE_H + + +#include "AthLinks/tools/DataProxyHolder.h" + + +namespace SG { +class DataProxy; +} +class IProxyDict; + + +/** + * @brief Type-independent part of @c DataLink; holds the persistent state. + * + * The persistent state for a @c DataLink is the hashed SG key, stored here + * as @c m_persKey. The transient member @c m_proxy contains the data proxy + * pointer. + */ +class DataLinkBase +{ +public: + /// Type of hashed keys. + typedef SG::DataProxyHolder::sgkey_t sgkey_t; + + /// Type of string keys. + typedef SG::DataProxyHolder::ID_type ID_type; + + typedef SG::DataProxyHolder::pointer_t pointer_t; + typedef SG::DataProxyHolder::const_pointer_t const_pointer_t; + + /// Function casting from a @c SG::DataProxy to a pointer. + typedef SG::DataProxyHolder::castfn_t castfn_t; + + + /** + * @brief Test to see if we're in the default state. + */ + bool isDefault() const; + + + /** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ + const ID_type& dataID() const; + + + /** + * @brief Return the SG key that we reference, as a hash. + * + * Returns 0 on failure. + */ + sgkey_t key() const; + + + /** + * @brief Clear the link (make it null). + */ + void clear(); + + + /** + * @brief Return the @c DataProxy for this link. + * @param nothrow If true, return 0 on failure instead of throwing + * an exception. + * + * If this is a null link, we return 0. + * If we're directly referencing an object that's not in StoreGate, + * either return 0 or throw @c ExcPointerNotInSG, depending + * on @c nothrow. Otherwise, return the proxy for the object + * we're referencing. + */ + SG::DataProxy* proxy (bool nothrow = false) const; + + + /** + * @brief Return the data source for this reference. + */ + IProxyDict* source() const; + + + + /** + * @brief Finish initialization after link has been read. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. + * Returns true. + * + * If @c sg is 0, then we use the global default store. + */ + bool toTransient (IProxyDict* sg = 0); + + + /** + * @brief Prepare this link for writing. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * Ensures the hashed SG key to be saved is correct. + * If this link is referencing an object not in SG, + * we throw @c ExcPointerNotInSG. + * + * If the target of the link has been remapped, then the link will be + * updated with the remapped hash key. + * + * Returns true. + */ + bool toPersistent(); + + + /** + * @brief Prepare this link for writing. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * Ensures the hashed SG key to be saved is correct. + * If this link is referencing an object not in SG, + * we throw @c ExcPointerNotInSG. + * + * This version does not perform link remapping. + * + * Returns true. + */ + bool toPersistentNoRemap(); + + + /** + * @brief Compare for equality. + */ + bool operator== (const DataLinkBase& other) const; + + + /** + * @brief Compare for inequality. + */ + bool operator!= (const DataLinkBase& other) const; + + + +protected: + /// For component testing. + friend class DataLinkBase_test; + + + /** + * @brief Default constructor. + */ + DataLinkBase(); + + + /** + * @brief Constructor from pointer to object. + * @param obj Pointer to the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + * + * May throw @c ExcCLIDMismatch. + */ + DataLinkBase (const_pointer_t obj, CLID link_clid, IProxyDict* sg); + + + /** + * @brief Constructor from a string key. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + DataLinkBase (const ID_type& dataID, CLID link_clid, IProxyDict* sg); + + + /** + * @brief Constructor from a hashed key. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + * + * May throw @c ExcCLIDMismatch. + */ + DataLinkBase (sgkey_t key, CLID link_clid, IProxyDict* sg); + + + /** + * @brief Constructor from a hashed key and a proxy holder object. + * Used internally for EL -> DL conversion. + * @param key Hashed key of the object. + * @param holder Internal holder object for the proxy. + */ + DataLinkBase (sgkey_t key, const SG::DataProxyHolder& holder); + + + /** + * @brief Set the link to an object given by a pointer. + * @param obj Pointer to the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ + void toStorableObject (const_pointer_t obj, + CLID clid_in, + IProxyDict* sg); + + + /** + * @brief Set the link to an object given by a string key. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void toIdentifiedObject (const ID_type& dataID, + CLID clid, + IProxyDict* sg); + + + /** + * @brief Set the link to an object given by a hashed key. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ + void toIdentifiedObject (sgkey_t key, + CLID clid, + IProxyDict* sg); + + + /** + * @brief Return a pointer to the currently-referenced object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + void* storableBase (castfn_t* castfn, const CLID& clid) const; + + + + /** + * @brief Throw a @c ExcInvalidLink exception for this link. + * @param sgkey The hashed key for this link. + * + * This will fill in parameters for the exception message from the proxy. + */ + void throwInvalidLink() const; + + + +private: + /// The hashed key for this link. + sgkey_t m_persKey; + + /// SG proxy for this link. + SG::DataProxyHolder m_proxy; //! Transient. +}; + + +#include "AthLinks/DataLinkBase.icc" + + +#endif // not ATHLINKS_DATALINKBASE_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.icc b/EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.icc new file mode 100644 index 00000000..a355ff59 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/DataLinkBase.icc @@ -0,0 +1,347 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/DataLinkBase.icc + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Type-independent part of @c DataLink; holds the persistent state. + */ + + +/** + * @brief Test to see if we're in the default state. + */ +inline +bool DataLinkBase::isDefault() const +{ + return m_persKey == 0 && m_proxy.isDefault(); +} + + +/** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ +inline +const DataLinkBase::ID_type& DataLinkBase::dataID() const +{ + return m_proxy.dataID(); +} + + +/** + * @brief Return the SG key that we reference, as a hash. + * + * Returns 0 on failure. + */ +inline +DataLinkBase::sgkey_t DataLinkBase::key() const +{ + return m_persKey; +} + + +/** + * @brief Clear the link (make it null). + */ +inline +void DataLinkBase::clear() +{ + m_persKey = 0; + m_proxy.clear(); +} + + +/** + * @brief Return the @c DataProxy for this link. + * @param nothrow If true, return 0 on failure instead of throwing + * an exception. + * + * If this is a null link, we return 0. + * If we're directly referencing an object that's not in StoreGate, + * either return 0 or throw @c ExcPointerNotInSG, depending + * on @c nothrow. Otherwise, return the proxy for the object + * we're referencing. + */ +inline +SG::DataProxy* DataLinkBase::proxy (bool nothrow /*= false*/) const +{ + return m_proxy.proxy (nothrow); +} + + +/** + * @brief Return the data source for this reference. + */ +inline +IProxyDict* DataLinkBase::source() const +{ + return m_proxy.source(); +} + + +/** + * @brief Finish initialization after link has been read. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. + * Returns true on success. + * + * If @c sg is 0, then we use the global default store. + */ +inline +bool DataLinkBase::toTransient (IProxyDict* sg /*= 0*/) +{ + m_proxy.toTransient (m_persKey, sg); + return true; +} + + +/** + * @brief Prepare this link for writing. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * Ensures the hashed SG key to be saved is correct. + * If this link is referencing an object not in SG, + * we throw @c ExcPointerNotInSG. + * + * Returns true. + * + * This version does not perform link remapping. + */ +inline +bool DataLinkBase::toPersistent() +{ + size_t dum = 0; + m_proxy.toPersistent (m_persKey, dum); + return true; +} + + +/** + * @brief Prepare this link for writing. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * Ensures the hashed SG key to be saved is correct. + * If this link is referencing an object not in SG, + * we throw @c ExcPointerNotInSG. + * + * This version does not perform link remapping. + * + * Returns true. + */ +inline +bool DataLinkBase::toPersistentNoRemap() +{ + m_proxy.toPersistentNoRemap (m_persKey); + return true; +} + + +/** + * @brief Compare for equality. + */ +inline +bool DataLinkBase::operator== (const DataLinkBase& other) const +{ + if (m_persKey != 0 && other.m_persKey != 0) + return m_persKey == other.m_persKey; + return (m_proxy == other.m_proxy); +} + + +/** + * @brief Compare for inequality. + */ +inline +bool DataLinkBase::operator!= (const DataLinkBase& other) const +{ + return !(*this == other); +} + + +//**************************************************************************** + + + +/** + * @brief Default constructor. + */ +inline +DataLinkBase::DataLinkBase() + : m_persKey(0) +{ +} + + +/** + * @brief Constructor from pointer to object. + * @param obj Pointer to the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + * + * May throw @c ExcCLIDMismatch. + */ +inline +DataLinkBase::DataLinkBase (const_pointer_t obj, + CLID link_clid, + IProxyDict* sg) +{ + toStorableObject (obj, link_clid, sg); +} + + +/** + * @brief Constructor from a string key. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + * + * May throw @c ExcCLIDMismatch. + */ +inline +DataLinkBase::DataLinkBase (const ID_type& dataID, + CLID link_clid, + IProxyDict* sg) +{ + toIdentifiedObject (dataID, link_clid, sg); +} + + +/** + * @brief Constructor from a hashed key. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + * + * May throw @c ExcCLIDMismatch. + */ +inline +DataLinkBase::DataLinkBase (sgkey_t key, CLID link_clid, IProxyDict* sg) +{ + toIdentifiedObject (key, link_clid, sg); +} + + +/** + * @brief Constructor from a hashed key and a proxy holder object. + * Used internally for EL -> DL conversion. + * @param key Hashed key of the object. + * @param holder Internal holder object for the proxy. + */ +inline +DataLinkBase::DataLinkBase (sgkey_t key, const SG::DataProxyHolder& holder) + : m_persKey (key), + m_proxy (holder) +{ +} + + +/** + * @brief Set the link to an object given by a pointer. + * @param obj Pointer to the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ +inline +void DataLinkBase::toStorableObject (const_pointer_t obj, + CLID link_clid, + IProxyDict* sg) +{ + m_persKey = m_proxy.toStorableObject (obj, link_clid, sg); +} + + +/** + * @brief Set the link to an object given by a string key. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +inline +void DataLinkBase::toIdentifiedObject (const ID_type& dataID, + CLID link_clid, + IProxyDict* sg) +{ + m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg); +} + + +/** + * @brief Set the link to an object given by a hashed key. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ +inline +void DataLinkBase::toIdentifiedObject (sgkey_t key, + CLID link_clid, + IProxyDict* sg) +{ + m_persKey = key; + m_proxy.toIdentifiedObject (key, link_clid, sg); +} + + +/** + * @brief Return a pointer to the currently-referenced object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +inline +void* DataLinkBase::storableBase (castfn_t* castfn, + const CLID& clid) const +{ + return m_proxy.storableBase (castfn, clid); +} + + +/** + * @brief Throw a @c ExcInvalidLink exception for this link. + * @param sgkey The hashed key for this link. + * + * This will fill in parameters for the exception message from the proxy. + */ +inline +void DataLinkBase::throwInvalidLink() const +{ + m_proxy.throwInvalidLink(m_persKey); +} diff --git a/EDM/athena/Control/AthLinks/AthLinks/DataPtr.h b/EDM/athena/Control/AthLinks/AthLinks/DataPtr.h new file mode 100644 index 00000000..b2385a54 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/DataPtr.h @@ -0,0 +1,174 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHLINKS_DATAPTR_H +#define ATHLINKS_DATAPTR_H + +#ifndef _CPP_ALGORITHM + #include <algorithm> // for std::swap +#endif +#include <cassert> +#ifndef __TYPEINFO__ + #include <typeinfo> +#endif + + +/** @class DataPtr + * @brief a ref-counted pointer + * + * @param T the pointee type + * + * @author ATLAS Collaboration + * $Id: DataPtr.h 567807 2013-10-30 09:30:16Z krasznaa $ + **/ + +template<typename T> +class DataPtr +{ + public: + + typedef T DataPtr_type; + typedef unsigned short counter_type; + + /// default constructor + DataPtr() : m_pointer(0), p_count(new counter_type(0)) { +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "default constructor called on " <<this << "->" << ptr() + << " use_count " << use_count() <<endl; +#endif + } + + /// constructor from ptr: stores a copy of pointer + /// Y must be convertible to a T* + template <typename Y> + DataPtr(Y* pointer) : m_pointer( pointer ), p_count(new counter_type(1)) { +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "pointer constructor called on " <<this << "->" << ptr() + << " input " << pointer + << " use_count " << use_count() <<endl; +#endif + } + + /// copy constructor: makes a copy of the pointer in rhs and of its count ptr + DataPtr( const DataPtr& rhs ) : + m_pointer( rhs.m_pointer ), p_count( rhs.p_count ) + { + ++(*p_count); +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "copy constructor called on " <<this << "->" << ptr() + << " input " << rhs.ptr() + << " use_count " << use_count() <<endl; +#endif + } + + /// the destructor will delete the object pointed to + ~DataPtr() { +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "destructor called on " <<this << "->" << ptr() + << " use_count " << use_count() <<endl; +#endif + if (*p_count == 0) { + assert(m_pointer==0); + delete p_count; + } else if (*p_count == 1) { + delete p_count; + delete m_pointer; + } else --(*p_count); + + } + + /// dereference operators: + T& operator*() const { return *ptr(); } + T* operator->() const { return ptr(); } + + // converter to pointer + operator T*() const { return ptr(); } + + /// explicit pointer accessors (sometimes necessary to help the compiler) + T* ptr() const { return m_pointer; } + + /// assignment operator, protect against self-assignment and exceptions + DataPtr& operator=( const DataPtr& rhs ) + { + DataPtr<T> temp( rhs ); + swap( temp ); +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "equal operator called on " <<this << "->" << ptr() + << " input " << rhs.ptr() + << " use_count " << use_count() <<endl; +#endif + return *this; + } + + /// assignment from a Convertible DataPtr + template <typename U> + DataPtr& operator=( const DataPtr<U>& rhs ) + { + DataPtr<T> temp( rhs ); + swap( temp ); +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "convert equal operator called on " <<this << "->" << ptr() + << " input " << rhs.ptr() + << " use_count " << use_count() <<endl; +#endif + return *this; + } + + /// swap contents + void swap( DataPtr& rhs ) + { + std::swap(m_pointer, rhs.m_pointer); + std::swap(p_count, rhs.p_count); +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "swap called on " <<this << "->" << ptr() + << " input " << rhs.ptr() + << " use_count " << use_count() <<endl; +#endif + } + + /// reset contents + void reset() + { + swap(DataPtr<T>(), this); +#ifdef DATAPTR_DEBUG + cout << typeid(*this).name() << " DEBUG: " + << "reset called on " <<this << "->" << ptr() + << " use_count " << use_count() <<endl; +#endif + } + + ///returns number of objects using the shared_ptr. Slow! + long use_count() const { assert(p_count); return *p_count; } + + private: + T* m_pointer; + counter_type* p_count; + +}; + +//comparison operator at the object level +//this of course requires the pointed-to type T to define operator == +template <typename T> +inline bool operator==(const DataPtr<T>& lhs, const DataPtr<T>& rhs) { + return (lhs.ptr() == rhs.ptr()); + //FIXME this requires T to be concrete + // boost::function_requires< boost::EqualityComparableConcept<T> >(); + //FIXME this requires T to have an == oper + // return ((lhs.operator->() == 0 && rhs.operator->() == 0) || + // (lhs.operator->() != 0 && rhs.operator->() != 0 && *lhs == *rhs) ); +} +template <typename T> +inline bool operator!=(const DataPtr<T>& lhs, const DataPtr<T>& rhs) { + return !(lhs == rhs); +} + + +#endif // not ATHLINKS_DATAPTR_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/DeclareIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/DeclareIndexingPolicy.h new file mode 100644 index 00000000..88c69c5b --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/DeclareIndexingPolicy.h @@ -0,0 +1,60 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DeclareIndexingPolicy.h 723806 2016-02-13 16:18:51Z ssnyder $ +#ifndef ATHLINKS_DECLAREINDEXINGPOLICY_H +# define ATHLINKS_DECLAREINDEXINGPOLICY_H + +/** \file DeclareIndexingPolicy.h + * @brief declare to which family the container belongs as far + * as its indexing policy is concerned + + * @author Paolo Calafiura - ATLAS Collaboration + * $Id: DeclareIndexingPolicy.h 723806 2016-02-13 16:18:51Z ssnyder $ + */ + +#include "AthLinks/tools/DefaultIndexingPolicy.h" +#include "AthLinks/tools/ForwardIndexingPolicy.h" +#include "AthLinks/tools/MapIndexingPolicy.h" +#include "AthLinks/tools/SetIndexingPolicy.h" +#include "AthLinks/tools/IdentContIndexingPolicy.h" + +/** \def CONTAINER_INDEXING_POLICY(CONTAINER, POLICY) + * @brief declare the indexing policy to be used for a container + * @param CONTAINER ... + * @param POLICY the indexing policy for CONTAINER + */ +#define CONTAINER_INDEXING_POLICY(CONTAINER, POLICY) \ +template <> \ +struct DefaultIndexingPolicy < CONTAINER > { \ + typedef POLICY< CONTAINER > type; \ +}; + +/** \def CONTAINER_IS_SEQUENCE(CONTAINER) \ + * @brief declare that CONTAINER is a STL sequence (like vector, list) + */ +#define CONTAINER_IS_SEQUENCE(CONTAINER) \ + CONTAINER_INDEXING_POLICY(CONTAINER, SG::ForwardIndexingPolicy) + +/** \def CONTAINER_IS_MAP(CONTAINER) \ + * @brief declare that CONTAINER behaves like a STL map + */ +#define CONTAINER_IS_MAP(CONTAINER) \ + CONTAINER_INDEXING_POLICY(CONTAINER, SG::MapIndexingPolicy) + +/** \def CONTAINER_IS_MAP(CONTAINER) \ + * @brief declare that CONTAINER behaves like a STL set + */ +#define CONTAINER_IS_SET(CONTAINER) \ + CONTAINER_INDEXING_POLICY(CONTAINER, SG::SetIndexingPolicy) + +/** \def CONTAINER_IS_IDENTCONT(CONTAINER) + * @brief declare that CONTAINER is an identifiable container + */ +#define CONTAINER_IS_IDENTCONT( CONTAINER ) \ + CONTAINER_INDEXING_POLICY( CONTAINER, SG::IdentContIndexingPolicy ) + +#endif // ATHLINKS_DECLAREINDEXINGPOLICY_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLink.h b/EDM/athena/Control/AthLinks/AthLinks/ElementLink.h new file mode 100644 index 00000000..eb5a4cae --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLink.h @@ -0,0 +1,704 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ElementLink.h 714258 2015-12-12 04:18:16Z ssnyder $ +/** + * @file AthLinks/ElementLink.h + * @author scott snyder <snyder@bnl.gov> + * @date Dec, 2013 + * @brief a persistable pointer to an element of a STORABLE (data object) + */ + + +#ifndef ATHLINKS_ELEMENTLINK_H +#define ATHLINKS_ELEMENTLINK_H + + +#include "AthLinks/tools/ElementLinkTraits.h" +#include "AthLinks/DataLink.h" +#include "AthenaKernel/IProxyDict.h" +#include <utility> + + +/** + * @class ElementLink + * @brief a persistable pointer to an element of a STORABLE (data object) + * @param STORABLE host object type (e,g. vector<Elem>, NOT Elem), + * + * An @c ElementLink maintains a reference to a container that can + * be in StoreGate (a la @c DataLink) and an index within that container. + * This then identifies an element within the container. + * + * The preferred way to initialize an @c ElementLink is with the StoreGate + * key and index. However, the link may also be initialized using the + * container directly instead of the key, or with the element directly. + * In the latter case, the reference to the container can be specified later. + * Be aware, though, that if you initialize the link from the element + * directly, without the index, the container will have to be searched + * if the index is needed, which could be slow. Also, if the index + * and StoreGate key are not available (for example, the container + * wasn't recorded in StoreGate), then the link will not be persistable. + * + * The relationship between the container and the index is encapsulated + * by an `indexing policy' class. You normally don't need to worry + * about this, as the appropriate policy is automatically chosen + * for STL sequence types as well as for STL set and map types. + * However, it is possible to customize the policy used, if needed. + * See the macros in DeclareIndexingPolicy.h; the interface + * required of an indexing policy is summarized in tools/ElementLinkTraits.h. + * + * Forward declarations: + * + * Dealing with forward declarations has been a problem. For example, + * you have a class @c MyCont which is a vector of pointers to @c MyElt, + * where @c MyElt contains an @c ElementLink<MyCont>. Here is a way + * to get this to work. + * + * In your header for @c MyElt, make a forward declaration for @c MyCont. + * Then include the special macro @c ELEMENTLINK_FWD: + * + *@code + * ELEMENTLINK_FWD(MyCont, MyElt); + @endcode + * + * where the first argument is the container type and the second argument + * is the base type of the (pointer) value type of the container. + * You can then write a data member + * of type @c ElementLink<MyCont>. You will need to have the complete + * definition of @c MyCont available in order to actaully call methods + * on the link, so you'll likely need to include the header for @c MyCont + * within the implementation file for @c MyElt. A more complete example + * of what the header for @c MyElt might look like: + * + *@code + * #include "AthLinks/ElementLink.h" + * + * class MyElt; + * class MyCont; + * ELEMENTLINK_FWD(MyCont, MyElt); + * + * class MyElt { ... + * ElementLink<MyCont> m_link; + * }; + @endcode + * + * Restrictions: + * - This only works for containers that are vector-like and which + * contain pointers (@c DataVector works.) + * - @c MyCont can't be a typedef. In most cases, @c MyCont will + * have to be a class that derives from the actual container class. + * - The @c ELEMENTLINK_FWD macro must be used in the global scope + * (outside of any namespace). + * - The complete definition of the container must be visible + * before calling any methods on the link. The container header + * can be included from the implementation file for the element; + * however, this implies that anything touching the link cannot + * be written as inline code in the element header. + * + * Implementation notes: + * + * Internally, we store a hashed SG key, a @c DataProxyHolder instance + * to encapsulate access to the @c DataProxy, the index, and a cached + * copy of the element to which we refer. These last two are in general + * of arbitrary type. However, the vast majority of EL instantiations + * refer to vectors of pointers; in that case, we can get away fixed + * types for these (an unsigned for the index and a void* for the cached + * element). Since it makes ROOT I/O easier if our state is in + * a non-templated class, we move all the state of @c ElementLink + * into a base class. The particular type of base class is chosen + * by @c ElementLinkTraits: the non-templated class @c ElementLinkBase + * is used for the vector of pointers case, while the templated + * @c GenericElementLinkBase class is used for the general case. + */ +template <class STORABLE> +class ElementLink + : public SG::ElementLinkTraits<STORABLE>::Base +{ +private: + /// Traits class, from which to derive types. + typedef SG::ElementLinkTraits<STORABLE> Traits; + + /// Base class (factoring out code that doesn't directly depend on STORABLE). + typedef typename Traits::Base Base; + + /// Function casting from a @c SG::DataProxy to a pointer. + typedef typename Base::castfn_t castfn_t; + + +public: + /// The indexing policy. + typedef typename Traits::IndexingPolicy IndexingPolicy; + + /// The index type presented to and returned from the link. + typedef typename IndexingPolicy::index_type index_type; + + /// Type of hashed keys. + typedef typename Base::sgkey_t sgkey_t; + + /// Type of string keys. + typedef typename Base::ID_type ID_type; + + /// Type of container (storable) and derived types. + typedef STORABLE value_type; + typedef STORABLE* pointer; + typedef const STORABLE* const_pointer; + typedef const STORABLE& BaseConstReference; + typedef const STORABLE* BaseConstPointer; + + + /// Container element and derived types. + typedef typename IndexingPolicy::ElementType ElementType; + typedef typename IndexingPolicy::ElementConstReference ElementConstReference; + typedef typename IndexingPolicy::ElementConstPointer ElementConstPointer; + + + /** + * @brief Return the CLID for the class that we reference. + */ + static const CLID& classID(); + + + //======================================================================== + /** @name Constructors. */ + //@{ + + + /** + * @brief Default constructor. Makes a null link. + */ + ElementLink(); + + + /** + * @brief Construct a link from a string storable key and an index. O(1) + * @param dataID Key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + ElementLink(const ID_type& dataID, index_type elemID, + IProxyDict* sg = 0); + + + /** + * @brief Construct a link from a hashed storable key and an index. O(1) + * @param key Hashed key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + ElementLink(sgkey_t key, index_type elemID, IProxyDict* sg = 0); + + + /** + * @brief Construct from a string storable key, index, AND pointer to element. O(1) + * @param dataID Key of the object. + * @param elemID The index of the element within the container. + * @param pEl Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ + ElementLink(const ID_type& dataID, + index_type elemID, + ElementType pEl, + IProxyDict* sg = 0); + + + /** + * @brief Construct from a hashed storable key, index, AND pointer to element. O(1) + * @param key Hashed key of the object. + * @param elemID The index of the element within the container. + * @param pEl Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ + ElementLink (sgkey_t key, + index_type elemID, + ElementType pEl, + IProxyDict* sg = 0); + + + /** + * @brief Construct a link from an index and reference to the container. O(1) + * @param data Reference to the container (storable). + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + ElementLink (BaseConstReference data, + index_type elemID, + IProxyDict* sg = 0); + + + /** + * @brief Construct from an element and reference to the container. O(N) + * @param element The element to reference. + * @param data Reference to the container (storable). + * @param sg Associated store. + * + * Does the same thing as the default ctor followed by @c toContainedElement. + * Note the reversed parameter order compared to the previous + * constructor. This is to prevent ambiguities in the case that + * the contained type is convertable to an int. + * + * Will throw @c SG::ExcElementNotFound if the element is not + * in the container. + * + * If @c sg is 0, we take the global default. + */ + ElementLink (const ElementType& element, + BaseConstReference data, + IProxyDict* sg = 0); + + + // Use default copy ctor. + + + /** + * @brief Constructor allowing a derived -> base conversion. + */ + template <class U> + ElementLink (const ElementLink<U>& other); + + + //@) + //======================================================================== + /** @name Dereferencing the link. */ + //@{ + + + /** + * @brief Return a pointer to the currently-referenced container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + const_pointer getDataPtr() const; + + + /** + * @brief Return a pointer to the currently-referenced container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + pointer getDataNonConstPtr(); + + + /** + * @brief Return a link to the currently-referenced container object. + */ + DataLink<STORABLE> getDataLink(); + + + /** + * @brief Return a link to the currently-referenced container object. + */ + const DataLink<STORABLE> getDataLink() const; + + + /** + * @brief Return a pointer to the currently-referenced container object. + */ + BaseConstPointer getStorableObjectPointer() const; + + + /** + * @brief Return a reference to the currently-referenced container object. + */ + BaseConstReference getStorableObjectRef() const; + + + /** + * @brief Return a pointer to the referenced element. + * + * Be aware: if the element is a pointer, then this will yield + * a pointer to a pointer. + */ + ElementConstPointer cptr() const; + + + /** + * @brief Return a reference to the referenced element. + * + * Will throw an exception if the link is not valid. + */ + ElementConstReference operator* () const; + + + /** + * @brief Return a pointer to the referenced element. + */ + ElementConstPointer operator->() const; + + + /** + * @brief Convert to a pointer to the referenced element. + */ + operator ElementConstPointer () const; + + + /** + * @brief Test to see if the link can be dereferenced. + */ + bool isValid() const; + + + /** + * @brief Test to see if the link can not be dereferenced. + */ + bool operator!() const; + + + /** + * @brief Return the cached element, if any. + */ + ElementType cachedElement() const; + + + + //@) + //======================================================================== + /** @name Modifying the link. */ + //@{ + + + /** + * @brief Set the link to an element given by index and pointer to container. + * @param data Reference to the container (storable). + * @param elemID The index of the element within the container. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool toIndexedElement(BaseConstReference data, index_type elemID, + IProxyDict* sg = 0); + + + /** + * @brief Set from element pointer and a reference to the container (storable) + * @param data Reference to the container (storable). + * @param element The element. + * @param sg Associated store. + * @returns True if the link was changed. + * + * O(N) for sequences! + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool toContainedElement(BaseConstReference data, + ElementType element, + IProxyDict* sg = 0); + + + /** + * @brief Set to point to an element. + * @param element The element. + * @returns True if the link was changed. + * + * The collection and the element can be specified independently + * using @c setElement and @c setStorableObject. + * + * If the link is already set, this will return false and leave the + * link unchanged. + */ + bool setElement(ElementType element); + + + /** + * @brief Set link to point to a new container (storable). + * @param data Reference to the container (storable). + * @param replace True if we can change an existing link. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged unless @c replace is set. The @c replace argument + * should be set if the element is now in a new storable container; + * e.g. element ptr has been put in a new view container. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool setStorableObject(BaseConstReference data, + bool replace=false, + IProxyDict* sg = 0); + + + /** + * @brief Set the link to an element given by string key and index. + * @param dataID Key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void resetWithKeyAndIndex(const ID_type& dataID, index_type elemID, + IProxyDict* sg=0); + + + /** + * @brief Set the link to an element given by string key and index. + * @param key Hashed key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void resetWithKeyAndIndex(sgkey_t key, index_type elemID, + IProxyDict* sg=0); + + + //@} + + + // Inherited from base class: + // bool isDefaultIndex() const + // Test the index validity. + // bool hasCachedElement() const + // Test to see if this link has a cached element pointer. + // bool isDefault() const + // Test to see if this link is in the default state. + // index_type index() const + // Return the index of the link. + // ID_type dataID() const + // Return the SG key that we reference, as a string. + // sgkey_t key() const + // Return the SG key that we reference, as a hash. + // IProxyDict* source() const + // Return the data source for the reference. + // void reset() + // Reset the link to a null state. + // bool toTransient (IProxyDict*) + // Finish initialization after link has been read. + // bool doPersistent() + // Prepare this link for writing. + + +private: + /** + * @brief Return a (void) pointer to the currently-referenced + * container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + const void* storable() const; + + + /** + * @brief Return a (void) pointer to the currently-referenced + * container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + void* storableNonConst(); +}; + + +/** + * @brief Ordering relation for @c ElementLink (less-than) + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +bool operator < (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs); + + +/** + * @brief Ordering relation for @c ElementLink (greater-than) + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +bool operator > (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs); + + +/** + * @brief Equality relation for @c ElementLink. + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +bool operator == (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs); + + +/** + * @brief Inequality relation for @c ElementLink. + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +bool operator != (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs); + + +namespace SG_detail { + + +/** + * @brief See if an EL is being remapped. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + * + * This version is for the case where the EL index is a @c size_t. + * For other index types, the the templated version below is used + * (which doesn't allow remapping indices). + */ +inline +bool checkForRemap (IProxyDict* sg, + SG::sgkey_t sgkey_in, + size_t index_in, + SG::sgkey_t& sgkey_out, + size_t& index_out); + + +/** + * @brief See if an EL is being remapped. + * @param sgkey_in Original hashed key of the EL. + * @param dum_in Ignored. + * @param sgkey_out[out] New hashed key for the EL. + * @param dum_out[out] Ignored. + * @return True if there is a remapping; false otherwise. + * + * This version catches the cases where the container index type + * isn't a @c size_t. We don't support changing the index in this case. + */ +template <class T> +inline +bool checkForRemap (IProxyDict* sg, + SG::sgkey_t sgkey_in, + const T& /*dum_in*/, + SG::sgkey_t& sgkey_out, + T& /*dum_out*/); + + +} // namespace SG_detail + + +namespace std { + + +/** + * @brief Specialization for a @c pair containing an @c ElementLink, + * allowing for faster initialization. + * + * [c++11 has another way of doing this --- `piecewise construction'. + * The way you use that is not the same, however; so we'll keep + * this in place for now.] + * + * When @c ElementLink is used with the @c Navigable class, we make + * lists of @c std::pair<ElementLink<T1>, T2>. To create one + * of these pairs, one would generally do something like: + * + *@code + * pairtype (ElementLink<T1> (container, index), par) + @endcode + * + * This, however, requires superfluous calls to the @c ElementLink + * constructor and destructor: first we create a temporary @c ElementLink, + * then we copy-construct the @c ElementLink within the @c pair from it, + * and finally we destroy the temporary. In certain cases, this + * extra ctor/dtor pair can have a significant effect on performance + * (this was observed for building cells into towers). It would be + * faster if we could pass the container and index args directly + * into the @c pair's constructor; then we wouldn't need to create + * the temporary: + * + *@code + * pairtype (container, index, par) + @endcode + * + * The class below is a specialization of @c std::pair for the case + * where the first type is an @c ElementLink which adds such a constructor. + * Everything else is a copy of the standard contents of @c std::pair. + * + * (For those nervous about the appearance here of `namespace std', + * note that specializing a library class within the @c std namespace + * is explicitly allowed by the C++ standard, provided that it's specialized + * on a user-defined type.) + */ +template <typename CONT, typename T2> +struct pair<ElementLink<CONT>, T2> +{ + // Standard pair types. + typedef ElementLink<CONT> first_type; + typedef T2 second_type; + + // Standard pair members. + first_type first; + second_type second; + + // Standard pair constructors. + pair() : first(), second() {} + pair (const first_type& x, const second_type& y) : first (x), second (y) {} + template <class U, class V> + pair (const pair<U, V>& p) : first (p.first), second (p.second) {} + + // Helper type. + typedef typename SG::GenerateIndexingPolicy<CONT>::type::index_type + external_index_type; + + // Extra constructor to allow avoiding a temporary for the + // @c ElementLink initialization. + pair (const CONT& child_container, + const external_index_type& index, + const T2& y) + : first (child_container, index), second (y) + {} + + // Extra constructor to allow avoiding a temporary for the + // @c ElementLink initialization. + pair (const CONT& child_container, + const external_index_type& index, + IProxyDict* sg, + const T2& y) + : first (child_container, index, sg), second (y) + {} + + void swap (pair& p) + { + std::swap (first, p.first); + std::swap (second, p.second); + } +}; + + +} // namespace std + + +#include "AthLinks/ElementLink.icc" + + +#endif // not ATHLINKS_ELEMENTLINK_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLink.icc b/EDM/athena/Control/AthLinks/AthLinks/ElementLink.icc new file mode 100644 index 00000000..6ea33c64 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLink.icc @@ -0,0 +1,657 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/ElementLink.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief a persistable pointer to an element of a STORABLE (data object) + */ + + +#include "AthLinks/exceptions.h" + + +/** + * @brief Return the CLID for the class that we reference. + */ +template <class STORABLE> +inline +const CLID& ElementLink<STORABLE>::classID() +{ + return ClassID_traits<value_type>::ID(); +} + + +/** + * @brief Default constructor. Makes a null link. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink() +{ +} + + +/** + * @brief Construct a link from a string storable key and an index. O(1) + * @param dataID Key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink(const ID_type& dataID, index_type elemID, + IProxyDict* sg /*= 0*/) + : Base (dataID, classID(), elemID, sg) +{ +} + + +/** + * @brief Construct a link from a hashed storable key and an index. O(1) + * @param key Hashed key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink(sgkey_t key, index_type elemID, + IProxyDict* sg /*= 0*/) + : Base (key, classID(), elemID, sg) +{ +} + + +/** + * @brief Construct from a string storable key, index, AND pointer to element. O(1) + * @param dataID Key of the object. + * @param elemID The index of the element within the container. + * @param pEl Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink(const ID_type& dataID, + index_type elemID, + ElementType pEl, + IProxyDict* sg /*= 0*/) + : Base (dataID, classID(), elemID, pEl, sg) +{ +} + + +/** + * @brief Construct from a hashed storable key, index, AND pointer to element. O(1) + * @param key Hashed key of the object. + * @param elemID The index of the element within the container. + * @param pEl Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink (sgkey_t key, + index_type elemID, + ElementType pEl, + IProxyDict* sg /*= 0*/) + : Base (key, classID(), elemID, pEl, sg) +{ +} + + +/** + * @brief Construct a link from an index and reference to the container. O(1) + * @param data Reference to the container (storable). + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink (BaseConstReference data, + index_type elemID, + IProxyDict* sg /* = 0*/) + : Base (&data, classID(), elemID, sg) +{ +} + + +/** + * @brief Construct from an element and reference to the container. O(N) + * @param element The element to reference. + * @param data Reference to the container (storable). + * @param sg Associated store. + * + * Does the same thing as the default ctor followed by @c toContainedElement. + * Note the reversed parameter order compared to the previous + * constructor. This is to prevent ambiguities in the case that + * the contained type is convertable to an int. + * + * Will throw @c SG::ExcElementNotFound if the element is not + * in the container. + * + * If @c sg is 0, we take the global default. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::ElementLink (const ElementType& element, + BaseConstReference data, + IProxyDict* sg /*= 0*/) +{ + toContainedElement (data, element, sg); +} + + +/** + * @brief Constructor allowing a derived -> base conversion. + */ +template <class STORABLE> +template <class U> +inline +ElementLink<STORABLE>::ElementLink (const ElementLink<U>& other) + : Base (other, + (SG::ElementLinkTraits<U>*)0, + (Traits*)0) +{ +} + + +/** + * @brief Return a pointer to the currently-referenced container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::const_pointer +ElementLink<STORABLE>::getDataPtr() const +{ + return reinterpret_cast<const_pointer> (this->storable()); +} + + +/** + * @brief Return a pointer to the currently-referenced container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::pointer +ElementLink<STORABLE>::getDataNonConstPtr() +{ + return reinterpret_cast<pointer> (this->storableNonConst()); +} + + +/** + * @brief Return a link to the currently-referenced container object. + */ +template <class STORABLE> +inline +DataLink<STORABLE> ElementLink<STORABLE>::getDataLink() +{ + return DataLink<STORABLE> (this->key(), this->proxyHolder()); +} + + +/** + * @brief Return a link to the currently-referenced container object. + */ +template <class STORABLE> +inline +const DataLink<STORABLE> ElementLink<STORABLE>::getDataLink() const +{ + return DataLink<STORABLE> (this->key(), this->proxyHolder()); +} + + +/** + * @brief Return a pointer to the currently-referenced container object. + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::BaseConstPointer +ElementLink<STORABLE>::getStorableObjectPointer() const +{ + return getDataPtr(); +} + + +/** + * @brief Return a reference to the currently-referenced container object. + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::BaseConstReference +ElementLink<STORABLE>::getStorableObjectRef() const +{ + return *getDataPtr(); +} + + +/** + * @brief Return a pointer to the referenced element. + * + * Be aware: if the element is a pointer, then this will yield + * a pointer to a pointer. + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::ElementConstPointer +ElementLink<STORABLE>::cptr() const +{ + ElementConstPointer ret = 0; + if (this->getCachedElement (ret)) + return ret; + + const STORABLE* ptr = this->getDataPtr(); + if (ptr && IndexingPolicy::isValid(this->storedIndex())) { + this->setCachedElement (IndexingPolicy::lookup(this->storedIndex(), *ptr)); + this->getCachedElement (ret); + } + return ret; +} + + +/** + * @brief Return a reference to the referenced element. + * + * Will throw an exception if the link is not valid. + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::ElementConstReference +ElementLink<STORABLE>::operator* () const +{ + ElementConstPointer ptr = cptr(); + if (!ptr) + SG::throwExcInvalidLink (classID(), this->dataID(), this->key()); + return *ptr; +} + + +/** + * @brief Return a pointer to the referenced element. + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::ElementConstPointer +ElementLink<STORABLE>::operator->() const +{ + return cptr(); +} + + +/** + * @brief Convert to a pointer to the referenced element. + */ +template <class STORABLE> +inline +ElementLink<STORABLE>::operator ElementConstPointer () const +{ + return cptr(); +} + + +/** + * @brief Test to see if the link can be dereferenced. + */ +template <class STORABLE> +inline +bool ElementLink<STORABLE>::isValid() const +{ + return (0 != cptr()); +} + + +/** + * @brief Test to see if the link can not be dereferenced. + */ +template <class STORABLE> +inline +bool ElementLink<STORABLE>::operator!() const +{ + return !isValid(); +} + + +/** + * @brief Return the cached element, if any. + */ +template <class STORABLE> +inline +typename ElementLink<STORABLE>::ElementType +ElementLink<STORABLE>::cachedElement() const +{ + ElementConstPointer ret = 0; + if (this->getCachedElement (ret)) + return *ret; + return ElementType(); +} + + +/** + * @brief Set the link to an element given by index and pointer to container. + * @param data Reference to the container (storable). + * @param elemID The index of the element within the container. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class STORABLE> +inline +bool +ElementLink<STORABLE>::toIndexedElement(BaseConstReference data, + index_type elemID, + IProxyDict* sg /*= 0*/) +{ + return Base::toIndexedElement (&data, classID(), elemID, sg); +} + + +/** + * @brief Set from element pointer and a reference to the container (storable) + * @param data Reference to the container (storable). + * @param element The element. + * @param sg Associated store. + * @returns True if the link was changed. + * + * O(N) for sequences! + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class STORABLE> +inline +bool ElementLink<STORABLE>::toContainedElement(BaseConstReference data, + ElementType element, + IProxyDict* sg /*= 0*/) +{ + index_type index = this->index(); + IndexingPolicy::reverseLookup (data, element, index); + bool ret = Base::toIndexedElement (&data, classID(), index, sg); + if (ret) + this->setCachedElement (element); + return ret; +} + + +/** + * @brief Set to point to an element. + * @param element The element. + * @returns True if the link was changed. + * + * The collection and the element can be specified independently + * using @c setElement and @c setStorableObject. + * + * If the link is already set, this will return false and leave the + * link unchanged. + */ +template <class STORABLE> +inline +bool ElementLink<STORABLE>::setElement(ElementType element) +{ + if (!this->isDefaultIndex() || this->hasCachedElement()) + return false; + this->setCachedElement (element); + const STORABLE* ptr = this->getDataPtr(); + if (ptr) { + index_type index = this->index(); + IndexingPolicy::reverseLookup (*ptr, element, index); + this->setIndex (index); + } + return true; +} + + +/** + * @brief Set link to point to a new container (storable). + * @param data Reference to the container (storable). + * @param replace True if we can change an existing link. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged unless @c replace is set. The @c replace argument + * should be set if the element is now in a new storable container; + * e.g. element ptr has been put in a new view container. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class STORABLE> +inline +bool ElementLink<STORABLE>::setStorableObject(BaseConstReference data, + bool replace /*= false*/, + IProxyDict* sg /*= 0*/) +{ + bool ret = Base::setStorableObject (&data, classID(), replace, sg); + if (ret) { + ElementConstPointer elt = 0; + if (this->isDefaultIndex() && this->getCachedElement (elt)) { + index_type index = this->index(); + IndexingPolicy::reverseLookup (data, *elt, index); + this->setIndex (index); + return true; + } + } + return ret; +} + + +/** + * @brief Set the link to an element given by string key and index. + * @param dataID Key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class STORABLE> +inline +void ElementLink<STORABLE>::resetWithKeyAndIndex(const ID_type& dataID, + index_type elemID, + IProxyDict* sg /*= 0*/) +{ + Base::resetWithKeyAndIndex (dataID, classID(), elemID, sg); +} + + +/** + * @brief Set the link to an element given by string key and index. + * @param key Hashed key of the object. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class STORABLE> +inline +void ElementLink<STORABLE>::resetWithKeyAndIndex(sgkey_t key, + index_type elemID, + IProxyDict* sg /*= 0*/) +{ + Base::resetWithKeyAndIndex (key, classID(), elemID, sg); +} + + +/** + * @brief Return a (void) pointer to the currently-referenced + * container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <class STORABLE> +inline +const void* ElementLink<STORABLE>::storable() const +{ + typedef STORABLE* fn_t (SG::DataProxy*); + fn_t* fn = &SG::DataProxy_cast<STORABLE>; + return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID()); +} + + +/** + * @brief Return a (void) pointer to the currently-referenced + * container object. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <class STORABLE> +inline +void* ElementLink<STORABLE>::storableNonConst() +{ + typedef STORABLE* fn_t (SG::DataProxy*); + fn_t* fn = &SG::DataProxy_cast<STORABLE>; + return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID()); +} + + +/** + * @brief Ordering relation for @c ElementLink (less-than) + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +bool operator < (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs) +{ + bool lhsDefault = lhs.isDefault(); + bool rhsDefault = rhs.isDefault(); + if (lhsDefault && rhsDefault) return false; + if (lhsDefault) return true; + if (rhsDefault) return false; + if (lhs.key() == 0 || rhs.key() == 0 || lhs.isDefaultIndex() || rhs.isDefaultIndex()) + SG::throwExcIncomparableEL(); + if (lhs.key() < rhs.key()) return true; + if (lhs.key() > rhs.key()) return false; + if (lhs.index() < rhs.index()) return true; + return false; +} + + +/** + * @brief Ordering relation for @c ElementLink (greater-than) + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +inline +bool operator > (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs) +{ + return (rhs < lhs); +} + + +/** + * @brief Equality relation for @c ElementLink. + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +inline +bool operator == (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs) +{ + return !((lhs < rhs) || (rhs < lhs)); +} + + +/** + * @brief Inequality relation for @c ElementLink. + * @param lhs Left-hand-side EL. + * @param rhs Right-hand-side EL. + */ +template <typename STORABLE> +inline +bool operator != (const ElementLink<STORABLE>& lhs, + const ElementLink<STORABLE>& rhs) +{ + return !(lhs == rhs); +} + + +namespace SG_detail { + + +/** + * @brief See if an EL is being remapped. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + * + * This version is for the case where the EL index is a @c size_t. + * For other index types, the the templated version below is used + * (which doesn't allow remapping indices). + */ +inline +bool checkForRemap (IProxyDict* sg, + SG::sgkey_t sgkey_in, + size_t index_in, + SG::sgkey_t& sgkey_out, + size_t& index_out) +{ + return sg->tryELRemap (sgkey_in, index_in, sgkey_out, index_out); +} + + +/** + * @brief See if an EL is being remapped. + * @param sgkey_in Original hashed key of the EL. + * @param dum_in Ignored. + * @param sgkey_out[out] New hashed key for the EL. + * @param dum_out[out] Ignored. + * @return True if there is a remapping; false otherwise. + * + * This version catches the cases where the container index type + * isn't a @c size_t. We don't support changing the index in this case. + */ +template <class T> +inline +bool checkForRemap (IProxyDict* sg, + SG::sgkey_t sgkey_in, + const T& /*dum_in*/, + SG::sgkey_t& sgkey_out, + T& /*dum_out*/) +{ + size_t index_in = 0; + size_t index_out; + return sg->tryELRemap (sgkey_in, index_in, sgkey_out, index_out); +} + + +} // namespace SG_detail diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.h b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.h new file mode 100644 index 00000000..16664b36 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.h @@ -0,0 +1,460 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/ElementLinkBase.h + * @author scott snyder <snyder@bnl.gov> + * @date Dec, 2013 + * @brief Base class for ElementLinks to vectors of pointers. + */ + + +#ifndef ATHLINKS_ELEMENTLINKBASE_H +#define ATHLINKS_ELEMENTLINKBASE_H + + +#include "AthLinks/tools/DataProxyHolder.h" +#include "AthLinks/tools/ForwardIndexingPolicy.h" +#include "AthenaKernel/sgkey_t.h" +#include <cstdlib> +#include <stdint.h> + + +/** + * @brief Base class for ElementLinks to vectors of pointers. + * + * This holds the type-independent portion of an @c ElementLink for the + * case where the target container holds pointers and has vector-like indexing. + * This is the most common case, and for this case, we can have + * a non-templated class; this simplifies persistency. + * + * Other types of @c ElementLink will use instead @c GenericElementLinkBase. + * + * See ElementLinkTraits.h for a summary of the requirements for these + * base classes. + * + * This class stores the hashed SG key of the target container and + * the index of the element within the container. (The type of the + * index should be the same as in @c ForwardIndexingPolicy; however, we + * don't depend on the indexing policy since that class is templated.) + * Those two members make up the persistent state. We also store + * a transient @c DataProxyHolder, which encapsulates the pointer + * to the @c DataProxy and factors out code that's common with @c DataLink. + * Further, we store a copy of the element to which the link refers; this + * is also transient (and mutable). In the case of @c ElementLinkBase, + * the element will always be a pointer, so we can store it as a generic + * void*. + */ +class ElementLinkBase +{ +private: + /// Value to mark an invalid index. + static const uint32_t INVALID = static_cast<uint32_t> (-1); + + /// Generic pointer to an element. + typedef const void* ElementType; + + /// Generic pointer to the container (storable). + typedef SG::DataProxyHolder::const_pointer_t const_pointer_t; + + +public: + /// The index type presented to and returned from the link. + typedef size_t index_type; + + /// The type of the index as it is stored internally. + typedef uint32_t stored_index_type; + + /// Type of hashed keys. + typedef SG::DataProxyHolder::sgkey_t sgkey_t; + + /// Type of string keys. + typedef SG::DataProxyHolder::ID_type ID_type; + + /// Function casting from a @c SG::DataProxy to a pointer. + typedef void* castfn_t (SG::DataProxy*); + + + + /** + * @brief Test the index validity. + * @returns True if the index is not valid (in default state). + */ + bool isDefaultIndex() const; + + + /** + * @brief Test to see if this link has a cached element pointer. + */ + bool hasCachedElement() const; + + + /** + * @brief Test to see if this link is in the default state. + */ + bool isDefault() const; + + + /** + * @brief Return the index of the link. + */ + index_type index() const; + + + /** + * @brief Return the index of the link. + * (Deprecated; use @c index() instead.) + */ + stored_index_type persIndex() const; + + + /** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ + const ID_type& dataID() const; + + + /** + * @brief Return the SG key that we reference, as a hash. + * + * Returns 0 on failure. + */ + sgkey_t key() const; + + + /** + * @brief Return the SG key that we reference, as a hash. + * (Deprecated; use @c key instead.) + * + * Returns 0 on failure. + */ + sgkey_t persKey() const; + + + /** + * @brief Return the data source for this reference. + */ + IProxyDict* source() const; + + + /** + * @brief Return the SG proxy for the container holding this element. + * + * If this is a null link, we return 0. + * If we're directly referencing an object that's not in StoreGate, + * either return 0 or throw @c ExcPointerNotInSG, depending + * on @c nothrow. Otherwise, return the proxy for the object + * we're referencing. + */ + const SG::DataProxy* proxy() const; + + + /** + * @brief Reset the link to a null state. + */ + void reset (); + + + /** + * @brief Finish initialization after link has been read. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. + * Returns true. + * + * If @c sg is 0, then we use the global default store. + */ + bool toTransient (IProxyDict* sg = 0); + + + /** + * @brief Prepare this link for writing. + * + * This method should be called before trying to write the link with root. + * It will make sure the persistent fields of the link are valid. + * It will also perform remapping if needed. + * + * Will return true on success. Will return false if either the container + * or the element index has not been specified. Will throw + * @c ExcPointerNotInSG if the link is referencing a container that + * is not in SG. + */ + bool toPersistent(); + + + /** + * @brief Adjust for thinning. + * + * If this link points to a container that has been thinned, + * it will be adjusted accordingly. + * + * Returns @c true if the link was changed; @c false otherwise. + */ + bool thin(); + + + /** + * @brief Default constructor. Makes a null link. + * + * (Must be public for root i/o.) + */ + ElementLinkBase(); + + +protected: + /** + * @brief Construct a link from a string key and an index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + ElementLinkBase (const ID_type& dataID, + CLID link_clid, + index_type elemID, + IProxyDict* sg); + + + /** + * @brief Construct a link from a hashed key and an index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + ElementLinkBase (sgkey_t key, + CLID link_clid, + index_type elemID, + IProxyDict* sg); + + + + /** + * @brief Construct a link from a string key, index, AND pointer to element. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ + ElementLinkBase (const ID_type& dataID, + CLID link_clid, + index_type elemID, + const void* elt, + IProxyDict* sg); + + + /** + * @brief Construct a link from a hashed key, index, AND pointer to element. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ + ElementLinkBase (sgkey_t key, + CLID link_clid, + index_type elemID, + const void* elt, + IProxyDict* sg); + + + /** + * @brief Construct a link from an index and pointer to the container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + ElementLinkBase (const_pointer_t obj, + CLID link_clid, + index_type elemID, + IProxyDict* sg); + + + /** + * @brief Constructor from a link referencing a different type. + * @param other The object from which to copy. + * + * @c FROM_TRAITS is the @c ElementLinkTraits class for @c other; + * @c TO_TRAITS is the traits class for this object. + * The actual pointer values are not used, just the types are used. + * Default conversions for the storable pointer (i.e., derived->base) + * are allowed. + */ + template <class FROM_TRAITS, class TO_TRAITS> + ElementLinkBase (const ElementLinkBase& other, + FROM_TRAITS*, TO_TRAITS*); + + + /** + * @brief Return a pointer to the currently-referenced container object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + void* storableBase (castfn_t* castfn, CLID clid) const; + + + /** + * @brief Set the container referenced by the link to @c data. + * @param data Pointer to the new container. + * @param link_clid CLID of the link being set. + * @param replace True if we can change an existing link. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged unless @c replace is set. The @c replace argument + * should be set if the element is now in a new storable container; + * e.g. element ptr has been put in a new view container. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool setStorableObject (const_pointer_t data, + CLID link_clid, + bool replace, + IProxyDict* sg); + + + /** + * @brief Set the link to an element given by index and pointer to container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool toIndexedElement (const_pointer_t obj, + CLID link_clid, + index_type elemID, + IProxyDict* sg); + + + /** + * @brief Set the link to an element given by string key and index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void resetWithKeyAndIndex (const ID_type& dataID, + CLID link_clid, + index_type elemID, + IProxyDict* sg); + + + /** + * @brief Set the link to an element given by string key and index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void resetWithKeyAndIndex (sgkey_t key, + CLID link_clid, + index_type elemID, + IProxyDict* sg); + + + /** + * @brief Set the index part of the link. + * @param index New index value. + */ + void setIndex (index_type index); + + + /** + * @brief Return the stored representation of the link index. + */ + const stored_index_type& storedIndex() const; + + + /** + * @brief Set the cached element stored in the link. + * @param elt New value for the cached element. + */ + void setCachedElement (ElementType elt) const; + + + /** + * @brief Retrieve the cached element from the link. + * @param elt[out] The cached element. + * @returns True if an element was cached; false otherwise. + * + * @c elt is left unmodified if there is no cached element. + */ + template <class T> + bool getCachedElement (const T* & elt) const; + + + /** + * @brief Return the internal proxy holder object. + */ + const SG::DataProxyHolder& proxyHolder() const; + + +private: + /// For regression testing. + friend class ElementLinkBase_test; + + /// The hashed key for this link. + SG::sgkey_t m_persKey; + + /// The index of the element within the container for this link. + stored_index_type m_persIndex; + + /// SG proxy for this link. + SG::DataProxyHolder m_proxy; //! Transient + + /// Cached copy of the element to which this link refers. + mutable ElementType m_element; //! Transient +}; + + +#include "AthLinks/ElementLinkBase.icc" + + +#endif // not ATHLINKS_ELEMENTLINKBASE_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.icc b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.icc new file mode 100644 index 00000000..bc559192 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkBase.icc @@ -0,0 +1,556 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/ElementLinkBase.icc + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Base class for ElementLinks to vectors of pointers. + */ + + +/** + * @brief Test the index validity. + * @returns True if the index is not valid (in default state). + */ +inline +bool ElementLinkBase::isDefaultIndex() const +{ + return m_persIndex == INVALID; +} + + +/** + * @brief Test to see if this link has a cached element pointer. + */ +inline +bool ElementLinkBase::hasCachedElement() const +{ + return m_element != 0; +} + + +/** + * @brief Test to see if this link is in the default state. + */ +inline +bool ElementLinkBase::isDefault() const +{ + return m_proxy.isDefault() && !hasCachedElement() && isDefaultIndex(); +} + + +/** + * @brief Return the index of the link. + */ +inline +ElementLinkBase::index_type +ElementLinkBase::index() const +{ + if (m_persIndex == INVALID) + return static_cast<ElementLinkBase::index_type>(-1); + return m_persIndex; +} + +/** + * @brief Return the index of the link. + * (Deprecated; use @c index() instead.) + */ +inline +ElementLinkBase::stored_index_type +ElementLinkBase::persIndex() const +{ + return m_persIndex; +} + + +/** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ +inline +const ElementLinkBase::ID_type& +ElementLinkBase::dataID() const +{ + return m_proxy.dataID(); +} + + +/** + * @brief Return the SG key that we reference, as a hash. + * + * Returns 0 on failure. + */ +inline +ElementLinkBase::sgkey_t +ElementLinkBase::key() const +{ + return m_persKey; +} + +/** + * @brief Return the SG key that we reference, as a hash. + * (Deprecated; use @c key instead.) + * + * Returns 0 on failure. + */ +inline +ElementLinkBase::sgkey_t +ElementLinkBase::persKey() const +{ + return m_persKey; +} + + +/** + * @brief Return the data source for this reference. + */ +inline +IProxyDict* ElementLinkBase::source() const +{ + return m_proxy.source(); +} + + +/** + * @brief Return the SG proxy for the container holding this element. + * + * If this is a null link, we return 0. + * If we're directly referencing an object that's not in StoreGate, + * either return 0 or throw @c ExcPointerNotInSG, depending + * on @c nothrow. Otherwise, return the proxy for the object + * we're referencing. + */ +inline +const SG::DataProxy* ElementLinkBase::proxy() const +{ + return m_proxy.proxy(true); +} + + +/** + * @brief Reset the link to a null state. + */ +inline +void ElementLinkBase::reset () +{ + m_proxy.clear(); + m_persKey = 0; + m_element = 0; + m_persIndex = INVALID; +} + + +/** + * @brief Finish initialization after link has been read. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. + * Returns true. + * + * If @c sg is 0, then we use the global default store. + */ +inline +bool ElementLinkBase::toTransient (IProxyDict* sg /*= 0*/) +{ + m_proxy.toTransient (m_persKey, sg); + m_element = 0; + return true; +} + + +/** + * @brief Prepare this link for writing. + * + * This method should be called before trying to write the link with root. + * It will make sure the persistent fields of the link are valid. + * It will also perform remapping if needed. + * + * Will return true on success. Will return false if either the container + * or the element index has not been specified. Will throw + * @c ExcPointerNotInSG if the link is referencing a container that + * is not in SG. + */ +inline +bool ElementLinkBase::toPersistent() +{ + if (isDefault()) return true; + if (m_proxy.isDefault() || isDefaultIndex()) return false; + if (m_proxy.toPersistent (m_persKey, m_persIndex)) + m_element = 0; + return true; +} + + +/** + * @brief Adjust for thinning. + * + * If this link points to a container that has been thinned, + * it will be adjusted accordingly. + * + * Returns @c true if the link was changed; @c false otherwise. + */ +inline +bool ElementLinkBase::thin() +{ + bool ret1 = toPersistent(); + size_t index = m_persIndex; + bool ret = m_proxy.thin (m_persKey, index); + if (ret) + m_persIndex = index; + return ret1 || ret; +} + + +/** + * @brief Default constructor. Makes a null link. + */ +inline +ElementLinkBase::ElementLinkBase() + : m_persKey (0), + m_persIndex (INVALID), + m_element (0) +{ +} + + +/** + * @brief Construct a link from a string key and an index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +inline +ElementLinkBase::ElementLinkBase (const ID_type& dataID, + CLID link_clid, + index_type elemID, + IProxyDict* sg) + : m_persIndex (elemID), + m_element (0) +{ + m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg); +} + + +/** + * @brief Construct a link from a hashed key and an index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +inline +ElementLinkBase::ElementLinkBase (sgkey_t key, + CLID link_clid, + index_type elemID, + IProxyDict* sg) + : m_persKey (key), + m_persIndex (elemID), + m_element (0) +{ + m_proxy.toIdentifiedObject (key, link_clid, sg); +} + + +/** + * @brief Construct a link from a string key, index, AND pointer to element. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ +inline +ElementLinkBase::ElementLinkBase (const ID_type& dataID, + CLID link_clid, + index_type elemID, + const void* elt, + IProxyDict* sg) + : m_persIndex (elemID), + m_element (elt) +{ + m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg); +} + + +/** + * @brief Construct a link from a hashed key, index, AND pointer to element. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ +inline +ElementLinkBase::ElementLinkBase (sgkey_t key, + CLID link_clid, + index_type elemID, + const void* elt, + IProxyDict* sg) + : m_persKey (key), + m_persIndex (elemID), + m_element (elt) +{ + m_proxy.toIdentifiedObject (key, link_clid, sg); +} + + +/** + * @brief Construct a link from an index and pointer to the container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +inline +ElementLinkBase::ElementLinkBase (const_pointer_t obj, + CLID link_clid, + index_type elemID, + IProxyDict* sg) + : m_persIndex (elemID), + m_element (0) +{ + m_persKey = m_proxy.toStorableObject (obj, link_clid, sg); +} + + +/** + * @brief Constructor from a link referencing a different type. + * @param other The object from which to copy. + * + * @c FROM_TRAITS is the @c ElementLinkTraits class for @c other; + * @c TO_TRAITS is the traits class for this object. + * The actual pointer values are not used, just the types are used. + * Default conversions for the storable pointer (i.e., derived->base) + * are allowed. + */ +template <class FROM_TRAITS, class TO_TRAITS> +ElementLinkBase::ElementLinkBase (const ElementLinkBase& other, + FROM_TRAITS*, + TO_TRAITS*) + : m_persKey (other.m_persKey), + m_persIndex (other.m_persIndex), + m_proxy (other.m_proxy, + (typename FROM_TRAITS::Storable*)0, + (typename TO_TRAITS::Storable*)0) +{ + typedef typename FROM_TRAITS::IndexingPolicy FromIndexingPolicy; + typedef typename TO_TRAITS::IndexingPolicy ToIndexingPolicy; + typedef typename FromIndexingPolicy::ElementType FromElementType; + typedef typename ToIndexingPolicy::ElementType ToElementType; + FromElementType from_elt = reinterpret_cast<FromElementType>(other.m_element); + ToElementType to_elt = from_elt; + m_element = to_elt; +} + + +/** + * @brief Return a pointer to the currently-referenced container object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +inline +void* ElementLinkBase::storableBase (castfn_t* castfn, CLID clid) const +{ + return m_proxy.storableBase (castfn, clid); +} + + +/** + * @brief Set the container referenced by the link to @c data. + * @param data Pointer to the new container. + * @param link_clid CLID of the link being set. + * @param replace True if we can change an existing link. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged unless @c replace is set. The @c replace argument + * should be set if the element is now in a new storable container; + * e.g. element ptr has been put in a new view container. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +inline +bool ElementLinkBase::setStorableObject (const_pointer_t data, + CLID link_clid, + bool replace, + IProxyDict* sg) +{ + if (!m_proxy.isDefault()) { + if (!replace) return false; + m_persIndex = INVALID; + } + + m_persKey = m_proxy.toStorableObject (data, link_clid, sg); + return true; +} + + +/** + * @brief Set the link to an element given by index and pointer to container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +inline +bool ElementLinkBase::toIndexedElement (const_pointer_t obj, + CLID link_clid, + index_type elemID, + IProxyDict* sg) +{ + if (m_proxy.isDefault() && isDefaultIndex() && !hasCachedElement()) { + m_persKey = m_proxy.toStorableObject (obj, link_clid, sg); + m_persIndex = elemID; + //m_element= 0; // Redundant --- must be 0 due to above test. + return true; + } + return false; +} + + +/** + * @brief Set the link to an element given by string key and index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +inline +void ElementLinkBase::resetWithKeyAndIndex (const ID_type& dataID, + CLID link_clid, + index_type elemID, + IProxyDict* sg) +{ + m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg); + m_persIndex = elemID; + m_element = 0; +} + + +/** + * @brief Set the link to an element given by string key and index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +inline +void ElementLinkBase::resetWithKeyAndIndex (sgkey_t key, + CLID link_clid, + index_type elemID, + IProxyDict* sg) +{ + m_persKey = key; + m_proxy.toIdentifiedObject (key, link_clid, sg); + m_persIndex = elemID; + m_element = 0; +} + + +/** + * @brief Set the index part of the link. + * @param index New index value. + */ +inline +void ElementLinkBase::setIndex (index_type index) +{ + m_persIndex = index; +} + + +/** + * @brief Return the stored representation of the link index. + */ +inline +const ElementLinkBase::stored_index_type& +ElementLinkBase::storedIndex() const +{ + return m_persIndex; +} + + +/** + * @brief Set the cached element stored in the link. + * @param elt New value for the cached element. + */ +inline +void ElementLinkBase::setCachedElement (ElementType elt) const +{ + m_element = elt; +} + + +/** + * @brief Retrieve the cached element from the link. + * @param elt[out] The cached element. + * @returns True if an element was cached; false otherwise. + * + * @c elt is left unmodified if there is no cached element. + */ +template <class T> +inline +bool ElementLinkBase::getCachedElement (const T* & elt) const +{ + if (m_element) { + elt = reinterpret_cast<const T*> (&m_element); + return true; + } + return false; +} + + +/** + * @brief Return the internal proxy holder object. + */ +inline +const SG::DataProxyHolder& ElementLinkBase::proxyHolder() const +{ + return m_proxy; +} + diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.h b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.h new file mode 100644 index 00000000..79c612a6 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.h @@ -0,0 +1,513 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHLINKS_ELEMENTLINKVECTOR_H +#define ATHLINKS_ELEMENTLINKVECTOR_H + +#include <algorithm> +#include <exception> +#include <functional> +#include <vector> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/iterator_adaptors.hpp> + +#include "AthLinks/ElementLinkVectorBase.h" +#include "AthLinks/DataLink.h" +#include "AthLinks/ElementLink.h" +#include "AthLinks/tools/SGELVRef.h" +#include "AthLinks/tools/selection_ns.h" + + +// Forward declaration(s): +ENTER_ROOT_SELECTION_NS +template< class STORABLE > +struct ElementLinkVector; +EXIT_ROOT_SELECTION_NS + +// forward declarations of our friends +template <typename DOBJ> +bool +operator <(const ElementLinkVector<DOBJ>& lhs, + const ElementLinkVector<DOBJ>& rhs); +template <typename DOBJ> +bool +operator ==(const ElementLinkVector<DOBJ>& lhs, + const ElementLinkVector<DOBJ>& rhs); + +/** @class ElementLinkVector + * @brief a vector of "compact" element links. It turns the host data object + * key into an index. The memory size of a compact link is three + * words/link, and only 2 words/link needs to be persistified. + * It also maintains a vector of hosts used to generate the "short ref" + * + * @param DOBJ host object type (e,g. vector<Elem>, NOT Elem), + * All host data objects must have the same type. + * xxx + * @param IndexingPolicy policy to find the element in the host DOBJ \n + * IndexingPolicy is generated automatically for STL sequences + * (e.g. vector, DataList etc). For other types of containers + * (e.g. maps), the container author must define the container type + * using the macros in tools/DeclareIndexingPolicies.h \n + * Advanced developers may have to define an ad-hoc indexing policy + * (e.g. GenParticleIndexing in GeneratorObjects/McEventIndexingPolicy.h) + * + * @author ATLAS Collaboration + * $Id: ElementLinkVector.h 702198 2015-10-21 20:58:43Z ssnyder $ + **/ + +template <typename DOBJ> +class ElementLinkVector : public ElementLinkVectorBase +{ +private: + typedef ElementLinkVector<DOBJ> ElemLinkVec; + typedef SG::ELVRef<DOBJ> ElemLinkRef; + + +public: + typedef typename std::vector< DataLink<DOBJ> > DataLinkVector; + typedef ElementLink<DOBJ> ElemLink; + + /** @class Short2LongRef + * @brief a functor turning an ElemLinkRef into an ElementLink + */ + struct Short2LongRef : public std::unary_function<ElemLinkRef, ElemLink> { + // i.e. friend class ElemLinkRef; + typedef ElementLinkVector<DOBJ> ElemLinkVec; + ElemLink operator()(ElemLinkRef& shortRef) const { + return shortRef.elementLink(); + } + const ElemLink operator()(const ElemLinkRef& shortRef) const { + return shortRef.elementLink(); + } + }; + +private: + ///the element links stored as ElemLinkRefs for compactness + typedef typename std::vector<ElemLinkRef> RefVector; + RefVector m_shortRefs; + + ///the dobjs hosting our elements. They are all of type DOBJ + DataLinkVector m_hostDObjs; + +public: + typedef typename ElemLink::ElementConstPointer ElementConstPointer; + typedef typename ElemLink::index_type index_type; + typedef typename ElemLink::ID_type ID_type; + typedef typename ElemLink::sgkey_t sgkey_t; + + + // We used to just use transform_iterator directly. + // However, postincrement for transform_iterator is implemented as a free + // function, which pyroot doesn't see. This causes python iteration + // over ElementLinkVector to fail. + template <class Iterator> + class ELVIterator + : public boost::transform_iterator<Short2LongRef, Iterator> + { + public: + typedef boost::transform_iterator<Short2LongRef, Iterator> Base; + using Base::Base; + using Base::operator++; + using Base::operator--; + ELVIterator operator++(int) { ELVIterator tmp=*this; ++(*this); return tmp; } + ELVIterator operator--(int) { ELVIterator tmp=*this; --(*this); return tmp; } + }; + + ///\name vector typedefs: it behaves like a vector<ElemLink> + //@{ + typedef ElemLink& reference; + //FIXME typedef const ElemLink& const_reference; + typedef ElemLink const_reference; + typedef ELVIterator<typename RefVector::iterator> iterator; + typedef ELVIterator<typename RefVector::const_iterator> const_iterator; + //1.30 typedef typename boost::transform_iterator_generator<Short2LongRef, typename RefVector::iterator>::type iterator; + //1.30 typedef typename boost::transform_iterator_generator<Short2LongRef, typename RefVector::const_iterator>::type const_iterator; + typedef typename RefVector::size_type size_type; + typedef typename RefVector::difference_type difference_type; + typedef ElemLink value_type; + typedef typename RefVector::allocator_type allocator_type; + typedef ElemLink* pointer; + typedef const ElemLink* const_pointer; + typedef ELVIterator<typename RefVector::reverse_iterator> reverse_iterator; + typedef ELVIterator<typename RefVector::const_reverse_iterator> const_reverse_iterator; + //1.30 typedef typename boost::transform_iterator_generator<Short2LongRef, typename RefVector::reverse_iterator>::type reverse_iterator; + //1.30 typedef typename boost::transform_iterator_generator<Short2LongRef, typename RefVector::const_reverse_iterator>::type const_reverse_iterator; + //@} + + + /// \name recommended (fast) access to contents of ElemLinks + /// by-pass the expensive creation of ElemLinks + //@{ + /// pointer to an element, given its ElementLinkVector index. O(1) + ElementConstPointer elementCPtr(size_type index) const { + return m_shortRefs[index].cptr(); + } + /// host index of an element, given its ElementLinkVector index. O(1) + index_type elementIndex(size_type index) const { + return m_shortRefs[index].elementIndex(); + } + /// dataID (long ref) of an element, given its ElementLinkVector index. O(1) + ID_type elementDataID(size_type index) const { + return m_shortRefs[index].dataID(); + } + + //@} + + /// \name iterators to DataLinkVector of host dobjs. Use e.g. for persistency + //@{ + const DataLinkVector& hostDObjs() const { return m_hostDObjs; } + typename DataLinkVector::iterator beginHostDObjs() { + return m_hostDObjs.begin(); + } + typename DataLinkVector::iterator endHostDObjs() { + return m_hostDObjs.end(); + } + typename DataLinkVector::const_iterator beginHostDObjs() const { + return m_hostDObjs.begin(); + } + typename DataLinkVector::const_iterator endHostDObjs() const { + return m_hostDObjs.end(); + } + ///find the host of an element. Returns endHostDObjs() if not found + typename DataLinkVector::const_iterator findHostDObj(const ElemLink& link) const; + ///find the host of an element. Returns endHostDObjs() if not found + typename DataLinkVector::iterator findHostDObj(const ElemLink& link); + + // Set the vector of host data objects from @a dobjs. + // @a dobjs is destroyed. + // This is an error if the vector is not empty. + void moveHostDObjs (DataLinkVector& dobjs); + + //@} + + + /// \name vector constructors (no Allocators) + //@{ + ElementLinkVector() : ElementLinkVectorBase() { } + + ElementLinkVector(size_type n, const ElemLink& link) : + ElementLinkVectorBase(), m_shortRefs(n, ElemLinkRef(link)) + { + if (n > 0) + addHostDObj(link); + } + + ElementLinkVector(int n, const ElemLink& link = ElemLink()) : + ElementLinkVectorBase(), m_shortRefs(n, ElemLinkRef(link)) + { + if (n > 0) + addHostDObj(link); + } + + ElementLinkVector(long n, const ElemLink& link = ElemLink()) : + ElementLinkVectorBase(), m_shortRefs(n, ElemLinkRef(link)) + { + if (n > 0) + addHostDObj(link); + } + + explicit ElementLinkVector(size_type n) : + ElementLinkVectorBase(), m_shortRefs(n, ElemLinkRef()) { } + + ElementLinkVector(const ElemLinkVec& vec) : + ElementLinkVectorBase( vec ), + m_shortRefs(vec.m_shortRefs), m_hostDObjs(vec.m_hostDObjs) { } + + ElementLinkVector(ElemLinkVec&& vec) : + ElementLinkVectorBase( std::move(vec) ), + m_shortRefs(std::move(vec.m_shortRefs)), + m_hostDObjs(std::move(vec.m_hostDObjs)) { } + + ElementLinkVector& operator= (const ElemLinkVec& vec) + { + if (this != &vec) { + m_persKeys = vec.m_persKeys; + m_persIndices = vec.m_persIndices; + m_shortRefs = vec.m_shortRefs; + m_hostDObjs = vec.m_hostDObjs; + } + return *this; + } + + ElementLinkVector& operator= (ElemLinkVec&& vec) + { + if (this != &vec) { + m_persKeys = std::move(vec.m_persKeys); + m_persIndices = std::move(vec.m_persIndices); + m_shortRefs = std::move(vec.m_shortRefs); + m_hostDObjs = std::move(vec.m_hostDObjs); + } + return *this; + } + + template <class InputIterator> + void assign(InputIterator first, InputIterator last) { + clear(); + insert(begin(), first, last); + } + void assign(size_type n, const ElemLink& link) { + clear(); + insert(begin(), n, link); + } + + bool toPersistent(); + + // Also return list of shortrefs. + bool toPersistent(std::vector<typename DataLinkVector::size_type>& shortrefs); + + // Just the DataLink part of toPersistent(). + bool toPersistentDL(); + bool toTransient(); + void doRemap(); + //@} + + /// \name vector iterators + //@{ + + iterator begin() { return iterator(m_shortRefs.begin(), Short2LongRef()); } + const_iterator begin() const { + return const_iterator(m_shortRefs.begin(), Short2LongRef()); + } + iterator end() { return iterator(m_shortRefs.end(), Short2LongRef()); } + const_iterator end() const { + return const_iterator(m_shortRefs.end(), Short2LongRef()); + } + reverse_iterator rbegin() { return reverse_iterator(m_shortRefs.begin(), Short2LongRef()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(m_shortRefs.begin(), Short2LongRef()); + } + reverse_iterator rend() { return reverse_iterator(m_shortRefs.end(), Short2LongRef()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(m_shortRefs.end(), Short2LongRef()); + } + //@} + + /// \name vector capacity + //@{ + size_type size() const { return m_shortRefs.size(); } + size_type max_size() const { return m_shortRefs.max_size(); } + void resize(size_type sz, const ElemLink& link = ElemLink()); + size_type capacity() const { return m_shortRefs.capacity(); } + bool empty() const { return 0 == size(); } + void reserve(size_type n) { return m_shortRefs.reserve(n); } + //@} + + /// \name vector element accessors. NB only CONST accessors + //@{ + // reference operator[](size_type n); + const_reference + operator[](size_type n) const { return m_shortRefs[n].elementLink(); } + // reference at(size_type n); + const_reference + at(size_type n) const { return m_shortRefs.at(n).elementLink(); } + // reference front(); + const_reference front() const{ return m_shortRefs.front().elementLink(); } + // reference back(); + const_reference back() const{ return m_shortRefs.back().elementLink(); } + //@} + + /// \name vector Modifiers + //@{ + void push_back(const ElemLink& link) { + addHostDObj(link); + m_shortRefs.push_back(ElemLinkRef(link)); + } + void pop_back() { //FIXME CHECK + removeHostObj(back()); + m_shortRefs.pop_back(); + } + + // Add an element by indices. + // (Mostly for use from persistency.) + void push_back (typename DataLinkVector::size_type nameIndex, + typename ElemLinkRef::index_type elementIndex); + + iterator insert(iterator position, const ElemLink& link); + void insert(iterator position, size_type n, const ElemLink& link); + + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + + void swap(ElemLinkVec& vec) { + m_hostDObjs.swap(vec.m_hostDObjs); + m_shortRefs.swap(vec.m_shortRefs); + } + + void clear() { + m_hostDObjs.clear(); + m_shortRefs.clear(); + } + //@} + +private: + /// Function setting up the object for forward indexing types + void toTransient( uint64_t& dummy ); + void toTransient( uint32_t& dummy ); + /// Function taking care of all the other indexing types (no direct ROOT I/O) + template< typename INDEX_TYPE > + void toTransient( INDEX_TYPE& dummy ); + + ///remove host of link from list. O(N) in m_hostDObjs (which is small) + void removeHostObj(const ElemLink& +#ifdef __ELVDEBUG + link +#endif + ) { +#ifdef __ELVDEBUG + std::cout << "DUMMY removeHostDObj called for link " + << link.dataID() << "/" << link.index() << std::endl; +#endif + //FIXME this is a dummy until we find how to remove an host w/o + //FIXME screwing up the otherElemLinkRefs + //FIXME m_hostDObjs.erase(findHostDObj(link)); + } + + ///add host of link to list. No duplicates. O(N) in m_hostDObjs + void addHostDObj(const ElemLink& link); + + ///get a short ref iterator from an iterator + typename RefVector::const_iterator + shortIterFromLong(const_iterator longIter) const { + typename RefVector::const_iterator ret(m_shortRefs.begin()); + advance(ret, distance(begin(), longIter)); +#ifdef __ELVDEBUG + std::cout << "shortIterFromLong(const version) called for " + << longIter->dataID() << "/" << longIter->index() + << " advance by " << distance(begin(), longIter) + << " result is " << ret->dataID() << "/" << ret->index() << std::endl; +#endif + return ret; + } + + ///get a short ref iterator from an iterator + typename RefVector::iterator + shortIterFromLong(iterator longIter) { + typename RefVector::iterator ret(m_shortRefs.begin()); + advance(ret, distance(begin(), longIter)); +#ifdef __ELVDEBUG + std::cout << "shortIterFromLong called for " + << longIter->dataID() << "/" << longIter->index() + << " advance by " << distance(begin(), longIter) + << " result is " << ret->dataID() << "/" << ret->index() << std::endl; +#endif + return ret; + } + + /// \name FIXME don't know how to implement + //@{ + template <class InputIterator> + ElementLinkVector(InputIterator first, InputIterator last); + template <class InputIterator> + void insert(iterator position, InputIterator first, InputIterator last); + //@} + + ///access m_shortRefs + friend bool operator == <>(const ElemLinkVec&, const ElemLinkVec&); + ///access m_shortRefs + friend bool operator < <>(const ElemLinkVec&, const ElemLinkVec&); + + /// Needed for the simplified Reflex class name + typedef typename + ROOT_SELECTION_NS::ElementLinkVector< DOBJ>::self DictSel; + +}; // class ElementLinkVector + +/* + * The following piece of code makes the Reflex dictionary think of + * "ElementLinkVector< T, DataProxyStorage< T >, + * SG::GenerateIndexingPolicy< T >::type >" + * simply as "ElementLinkVector< T >". This is vital for tricking + * ROOT into reading this object's payload back into a different + * ElementLink implementation in vanilla ROOT. + */ +ENTER_ROOT_SELECTION_NS + + +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + + +template< class STORABLE > +struct ElementLinkVector { + typedef ElementLinkVector< STORABLE> self; + /// Do not generate such dictionaries automatically + ROOT_SELECTION_NS::NO_SELF_AUTOSELECT dummy; + /// Mark all transient members: + ROOT_SELECTION_NS::TRANSIENT m_shortRefs; + ROOT_SELECTION_NS::TRANSIENT m_hostDObjs; +}; + + +#else + + +template< class STORABLE > +struct ElementLinkVector +#if ROOT_VERSION_CODE > ROOT_VERSION( 6, 0, 2 ) + : public SelectNoInstance +#endif +{ + typedef ElementLinkVector< STORABLE> self; + /// Mark all transient members: + ROOT_SELECTION_NS::MemberAttributes< kTransient > m_shortRefs; + ROOT_SELECTION_NS::MemberAttributes< kTransient > m_hostDObjs; +}; + + +#endif + + +EXIT_ROOT_SELECTION_NS + +// Hide the rest from the dictionary generator: +#ifndef __GCCXML__ + +#include "AthLinks/ElementLinkVector.icc" +#include "AthLinks/tools/SGELVRef.icc" /* to avoid circular deps */ + +/// \name vector comparison operators +//@{ +template <typename DOBJ> +bool +operator <(const ElementLinkVector<DOBJ>& lhs, + const ElementLinkVector<DOBJ>& rhs) { + return (lhs.m_shortRefs < rhs.m_shortRefs); +} +template <typename DOBJ> +bool +operator >(const ElementLinkVector<DOBJ>& lhs, + const ElementLinkVector<DOBJ>& rhs) { + return rhs < lhs; +} +template <typename DOBJ> +bool +operator ==(const ElementLinkVector<DOBJ>& lhs, + const ElementLinkVector<DOBJ>& rhs) { + return (lhs.m_shortRefs == rhs.m_shortRefs); +} +template <typename DOBJ> +bool +operator !=(const ElementLinkVector<DOBJ>& lhs, + const ElementLinkVector<DOBJ>& rhs) { + return !operator==(lhs, rhs); +} +//FIXME ops <= , => etc +//@} + +namespace std { +template <typename DOBJ> +void +swap(ElementLinkVector<DOBJ>& lhs, + ElementLinkVector<DOBJ>& rhs) { +#ifdef __ELVDEBUG + std::cout << "std::swap called for lhs " << std::hex << &lhs + << " rhs " << &rhs << std::dec << std::endl; +#endif + lhs.swap(rhs); +} +} + +#endif // not __GCCXML__ +#endif /*ATHLINKS_ELEMENTLINKVECTOR_H*/ diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.icc b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.icc new file mode 100644 index 00000000..79c00332 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVector.icc @@ -0,0 +1,326 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#ifndef GAUDIKERNEL_SYSTEM_H +#include "GaudiKernel/System.h" +#endif + +#ifndef ATHENAKERNEL_ERRORCHECK_H +#include "AthenaKernel/errorcheck.h" +#endif + +#include <cassert> +#include <stdexcept> +/* #define __ELVDEBUG */ + +template <typename DOBJ> +typename ElementLinkVector<DOBJ>::DataLinkVector::const_iterator +ElementLinkVector<DOBJ>::findHostDObj(const ElemLink& link) const +{ + //DataLink<DOBJ> dl (link.storagePolicy()); + DataLink<DOBJ> dl = link.getDataLink(); + typename DataLinkVector::const_iterator iHost(beginHostDObjs()), eHost(endHostDObjs()); + while ((eHost != iHost) && (*iHost != dl)) ++iHost; +#ifdef __ELVDEBUG + std::cout << "findHostDObj (const version) called for link " + << link.dataID() << "/" << link.index() + << " - which is " << ((iHost != eHost) ? "" : " NOT ") + << " in ELV host dobjs list " << std::endl; +#endif + return iHost; +} + +template <typename DOBJ> +typename ElementLinkVector<DOBJ>::DataLinkVector::iterator +ElementLinkVector<DOBJ>::findHostDObj(const ElemLink& link) +{ + //DataLink<DOBJ> dl (link.storagePolicy()); + DataLink<DOBJ> dl (link.key()); + typename DataLinkVector::iterator iHost(beginHostDObjs()), eHost(endHostDObjs()); + while ((eHost != iHost) && (*iHost != dl)) ++iHost; +#ifdef __ELVDEBUG + std::cout << "findHostDObj (non-const version) called for link " + << link.dataID() << "/" << link.index() + << " - which is " << ((iHost != eHost) ? "" : " NOT ") + << " in ELV host dobjs list " << std::endl; +#endif + return iHost; +} + + +template <typename DOBJ> +typename ElementLinkVector<DOBJ>::iterator +ElementLinkVector<DOBJ>::insert(iterator position, const ElemLink& link) +{ +#ifdef __ELVDEBUG + std::cout << "insert of link " + << link.dataID() << "/" << link.index() << " after " + << position->dataID() << "/" << position->index() <<endl; +#endif + addHostDObj(link); + return iterator(m_shortRefs.insert(shortIterFromLong(position), ElemLinkRef( link)), + Short2LongRef()); +} + +template <typename DOBJ> +void +ElementLinkVector<DOBJ>::insert(iterator position, size_type n, const ElemLink& link) +{ + addHostDObj(link); + m_shortRefs.insert(shortIterFromLong(position), n, ElemLinkRef(link)); +} + +template <typename DOBJ> +typename ElementLinkVector<DOBJ>::iterator +ElementLinkVector<DOBJ>::erase(iterator position) +{ + const ElemLink& save(*position); + iterator ret(m_shortRefs.erase(shortIterFromLong(position)), Short2LongRef()); + removeHostObj(save); + return ret; +} + +template <typename DOBJ> +typename ElementLinkVector<DOBJ>::iterator +ElementLinkVector<DOBJ>::erase(iterator first, iterator last) +{ + iterator i(first); + while (i != last) removeHostObj(*i++); //FIXME won't work in ELVDEBUG as such + return iterator(m_shortRefs.erase(shortIterFromLong(first), + shortIterFromLong(last)), + Short2LongRef()); +} + +template <typename DOBJ> +void +ElementLinkVector<DOBJ>:: +resize(size_type sz, const ElemLink& link) +{ + if (sz > size()) { insert(end(), sz-size(), link); } + else if (sz < size()) { erase(begin()+sz, end()); } +} + +template <typename DOBJ> +bool +ElementLinkVector<DOBJ>::toTransient() +{ + // Call the appropriate function for making use of the persistent data + // if we're doing direct ROOT I/O: + if( m_isDirectIO ) { + index_type dummy; + toTransient( dummy ); + m_isDirectIO = false; + } + + bool success = true; + // set the proper state of all DataLinks + typename DataLinkVector::iterator iter = beginHostDObjs(); + for (; iter!= endHostDObjs(); iter++) { + if (! (*iter).toTransient()) success = false; + } + + // set the refVector's to transient mode. Note that RefVector would + // need the owner (this) as it is constructed from persistency using + // the default constructor + typename RefVector::iterator refIter = m_shortRefs.begin(); + for (; refIter!= m_shortRefs.end(); refIter++) { + if (! (*refIter).toTransient(*this)) success = false; + } + + return success; +} + + +template <typename DOBJ> +bool +ElementLinkVector<DOBJ>::toPersistentDL() +{ + doRemap(); + + //set all DataLinks to persistent state + bool success = true; + typename DataLinkVector::iterator iter = beginHostDObjs(); + for (; iter!= endHostDObjs(); iter++) { + if (! (*iter).toPersistentNoRemap()) success = false; + } + + return success; +} + + +template <typename DOBJ> +bool +ElementLinkVector<DOBJ>::toPersistent() +{ + bool success = toPersistentDL(); + + // set all ElementLink Refs to persistent state + typename RefVector::iterator refIter = m_shortRefs.begin(); + for (; refIter!= m_shortRefs.end(); refIter++) { + if (! (*refIter).toPersistent(*this)) success = false; + } + + // WARNING: The code doesn't take thinning into account at the + // moment!!! + + // Reset the base class's variables: + m_persKeys.clear(); + m_persIndices.clear(); + + // Copy the info into the base class: + typename RefVector::const_iterator ref_itr = m_shortRefs.begin(); + typename RefVector::const_iterator ref_end = m_shortRefs.end(); + for( ; ref_itr != ref_end; ++ref_itr ) { + m_persKeys.push_back( ref_itr->elementLink().persKey() ); + m_persIndices.push_back( ref_itr->elementLink().persIndex() ); + } + + return success; +} + + +template <typename DOBJ> +bool +ElementLinkVector<DOBJ>::toPersistent + (std::vector<typename DataLinkVector::size_type>& shortrefs) +{ + bool success = toPersistentDL(); + + // set all ElementLink Refs to persistent state + shortrefs.reserve (m_shortRefs.size()); + typename RefVector::iterator refIter = m_shortRefs.begin(); + for (; refIter!= m_shortRefs.end(); refIter++) { + typename DataLinkVector::size_type shortref; + if (! (*refIter).toPersistent(*this, shortref)) success = false; + shortrefs.push_back (shortref); + } + + return success; +} + + +template <typename DOBJ> +void +ElementLinkVector<DOBJ>::doRemap() +{ + bool remapping = false; + typename RefVector::iterator refIter = m_shortRefs.begin(); + for (; refIter!= m_shortRefs.end(); refIter++) { + if (refIter->doRemap()) { + if (!remapping) { + m_hostDObjs.clear(); + typename RefVector::iterator ri2 = m_shortRefs.begin(); + for (; ri2 != refIter; ++ri2) { + addHostDObj (ri2->elementLink()); + } + remapping = true; + } + } + if (remapping) + addHostDObj (refIter->elementLink()); + } +} + + +// Set the vector of host data objects from @a dobjs. +// @a dobjs is destroyed. +// This is an error if the vector is not empty. +template <typename DOBJ> +void +ElementLinkVector<DOBJ>::moveHostDObjs + (DataLinkVector& dobjs) +{ + if (!this->empty()) { + MsgStream log(Athena::getMessageSvc(), "ElementLink"); + log << MSG::ERROR + << "ElementLinkVector::moveHostDObjs called on non-empty vector." + << endmsg; + throw std::runtime_error("ElementLinkVector::moveHistDObjs : vector not empty"); + } + m_hostDObjs.swap (dobjs); +} + + +template <typename DOBJ> +void +ElementLinkVector<DOBJ>::push_back + (typename DataLinkVector::size_type nameIndex, + typename ElemLinkRef::index_type elementIndex) +{ + m_shortRefs.push_back (ElemLinkRef (nameIndex, elementIndex, *this)); +} + +template< typename DOBJ > +void ElementLinkVector< DOBJ >:: +toTransient( uint64_t& /*dummy*/ ) { + + // A little sanity check: + assert( m_persKeys.size() == m_persIndices.size() ); + + // Clear the object: + clear(); + + // Now re-create the links based on the persistent info: + for( size_t i = 0; i < m_persKeys.size(); ++i ) { + push_back( ElemLink( m_persKeys[ i ], m_persIndices[ i ] ) ); + } + + return; +} + +template< typename DOBJ > +void ElementLinkVector< DOBJ >:: +toTransient( uint32_t& /*dummy*/ ) { + + // A little sanity check: + assert( m_persKeys.size() == m_persIndices.size() ); + + // Clear the object: + clear(); + + // Now re-create the links based on the persistent info: + for( size_t i = 0; i < m_persKeys.size(); ++i ) { + push_back( ElemLink( m_persKeys[ i ], m_persIndices[ i ] ) ); + } + + return; +} + +template< typename DOBJ > +template< typename INDEX_TYPE > +void ElementLinkVector< DOBJ >:: +toTransient( INDEX_TYPE& /*dummy*/ ) { + + REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, "ElementLinkVector" ) + << "Using direct ROOT I/O for type " + << System::typeinfoName( typeid( this ) ) + << " not supported"; + + return; +} + +template< typename DOBJ > +void ElementLinkVector< DOBJ >:: +addHostDObj( const ElemLink& link ) { + + // Check if we already have it: + if( endHostDObjs() != findHostDObj( link ) ) { + return; + } + + //DataLink< DOBJ > dl( link.storagePolicy() ); + DataLink< DOBJ > dl( link.key() ); + if( ! dl.isDefault() ) { + m_hostDObjs.push_back( dl ); +#ifdef __ELVDEBUG + std::cout << "addHostDObj added link " + << link.dataID() << "/" << link.index() << std::endl; +#endif + } + + return; +} diff --git a/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVectorBase.h b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVectorBase.h new file mode 100644 index 00000000..cbfeba11 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/ElementLinkVectorBase.h @@ -0,0 +1,70 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ElementLinkVectorBase.h 589034 2014-03-24 00:25:32Z ssnyder $ +#ifndef ATHLINKS_ELEMENTLINKVECTORBASE_H +#define ATHLINKS_ELEMENTLINKVECTORBASE_H + +// System include(s): +extern "C" { +# include <stdint.h> +} +#include <vector> + +/** + * @short Base class holding the container independent part of ElementLinkVector + * + * This class holds the ROOT persistifiable part of the + * ElementLinkVector<T> class. In the simplest form imaginable. + * + * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + * + * $Revision: 589034 $ + * $Date: 2014-03-24 01:25:32 +0100 (Mon, 24 Mar 2014) $ + */ +class ElementLinkVectorBase { + +public: + /// Default constructor + ElementLinkVectorBase( const std::vector< uint32_t >& keys = + std::vector< uint32_t >(), + const std::vector< uint32_t >& indices = + std::vector< uint32_t >() ); + /// Virtual destructor, to make vtable happy... + virtual ~ElementLinkVectorBase() {} + + /// Get the keys/identifiers of the referenced containers + const std::vector< uint32_t >& persKeys() const; + /// Set the keys/identifiers of the referenced containers + void setPersKeys( const std::vector< uint32_t >& keys ); + + /// Get the indices of the referenced objects in the containers + const std::vector< uint32_t >& persIndices() const; + /// Set the indices of the referenced objects in the containers + void setPersIndices( const std::vector< uint32_t >& indices ); + + /// Reset the object's internal cache + virtual bool toTransient() = 0; + +protected: + /// Keys/identifiers of the referenced containers + std::vector< uint32_t > m_persKeys; + /// Indices of the referenced objects in the containers + std::vector< uint32_t > m_persIndices; + + /// A transient variable signaling when direct I/O is happening + /// + /// This flag is used exclusively by the ElementLinkVector<>::toTransient() + /// function to know when it should take the persistent data stored in this + /// object into account. That function is called in normal P->T conversions + /// as well, in which case using the data from this class would just reset + /// the object to its default state. + /// + bool m_isDirectIO; + +}; // class ElementLinkVectorBase + +#endif // ATHLINKS_ELEMENTLINKVECTORBASE_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.h b/EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.h new file mode 100644 index 00000000..6413e988 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.h @@ -0,0 +1,473 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: GenericElementLinkBase.h 714258 2015-12-12 04:18:16Z ssnyder $ +/** + * @file AthLinks/GenericElementLinkBase.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2014 + * @brief Generic base class for ElementLinks. + */ + + +#ifndef ATHLINKS_GENERICELEMENTLINKBASE_H +#define ATHLINKS_GENERICELEMENTLINKBASE_H + + +#include "AthLinks/tools/DataProxyHolder.h" +#include "AthLinks/tools/selection_ns.h" + + +// Forward declaration(s): +ENTER_ROOT_SELECTION_NS +namespace SG { +template< class INDEXING_POLICY > +struct GenericElementLinkBase; +} +EXIT_ROOT_SELECTION_NS + + +template <class POLICY> +class ElementLinkBaseT_test; + + +namespace SG { + + +/** + * @brief Generic base class for ElementLinks. + * + * The part of @c ElementLink that doesn't directly depend on the particular + * container class is factored out here. We do, however, need to know + * both the index and element types. We get these from the indexing + * policy (so we do have an indirect dependence on the container type). + * + * This class holds all the state of the @c ElementLink. The persistent + * part is the hashed SG key of the container and the index of the + * element within the container. We also store a transient @c DataProxyHolder, + * which encapsulates the pointer to the @c DataProxy and factors out + * code shared with @c DataLink. Further, we store a (transient and mutable) + * copy of the element to which this link refers, as well as a flag to tell + * if the cached element is valid. + * + * The main reason for breaking out the base class like this is that + * for the common case where the container has vector-like indexing + * and the element is a pointer type we actually use the non-templated + * class @c ElementLinkBase instead of this one. @c ElementLinkBase + * is essentially the same as this, but specialized for the case of + * the index being an unsigned int and the element being a pointer. + * This factorization makes direct ROOT persistency easier for this + * common case. + * + * See ElementLinkTraits.h for a summary of the requirements for these + * base classes. + */ +template <class INDEXING_POLICY> +class GenericElementLinkBase +{ +private: + /// Generic pointer to an element. + typedef typename INDEXING_POLICY::ElementType ElementType; + typedef typename INDEXING_POLICY::ElementConstPointer ElementConstPointer; + + /// Generic pointer to the container (storable). + typedef SG::DataProxyHolder::const_pointer_t const_pointer_t; + + +public: + /// The index type presented to and returned from the link. + typedef typename INDEXING_POLICY::index_type index_type; + + /// The type of the index as it is stored internally. + typedef typename INDEXING_POLICY::stored_index_type stored_index_type; + + /// Type of hashed keys. + typedef SG::DataProxyHolder::sgkey_t sgkey_t; + + /// Type of string keys. + typedef SG::DataProxyHolder::ID_type ID_type; + + /// Function casting from a @c SG::DataProxy to a pointer. + typedef void* castfn_t (SG::DataProxy*); + + +public: + /** + * @brief Test the index validity. + * @returns True if the index is not valid (in default state). + */ + bool isDefaultIndex() const; + + + /** + * @brief Test to see if this link has a cached element pointer. + */ + bool hasCachedElement() const; + + + /** + * @brief Test to see if this link is in the default state. + */ + bool isDefault() const; + + + /** + * @brief Return the index of the link. + */ + index_type index() const; + + + /** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ + const ID_type& dataID() const; + + + /** + * @brief Return the SG key that we reference, as a hash. + * + * Returns 0 on failure. + */ + sgkey_t key() const; + + + /** + * @brief Return the data source for this reference. + */ + IProxyDict* source() const; + + + /** + * @brief Return the SG proxy for the container holding this element. + * + * If this is a null link, we return 0. + * If we're directly referencing an object that's not in StoreGate, + * either return 0 or throw @c ExcPointerNotInSG, depending + * on @c nothrow. Otherwise, return the proxy for the object + * we're referencing. + */ + const SG::DataProxy* proxy() const; + + + /** + * @brief Reset the link to a null state. + */ + void reset (); + + + /** + * @brief Finish initialization after link has been read. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. + * Returns true. + * + * If @c sg is 0, then we use the global default store. + */ + bool toTransient (IProxyDict* sg = 0); + + + /** + * @brief Prepare this link for writing. + * + * This method should be called before trying to write the link with root. + * It will make sure the persistent fields of the link are valid. + * It will also perform remapping if needed. + * + * Will return true on success. Will return false if either the container + * or the element index has not been specified. Will throw + * @c ExcPointerNotInSG if the link is referencing a container that + * is not in SG. + */ + bool toPersistent(); + + +protected: + /** + * @brief Default constructor. Makes a null link. + */ + GenericElementLinkBase(); + + + /** + * @brief Construct a link from a string key and an index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + GenericElementLinkBase (const ID_type& dataID, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg); + + + /** + * @brief Construct a link from a hashed key and an index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + GenericElementLinkBase (sgkey_t key, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg); + + + /** + * @brief Construct a link from a string key, index, AND pointer to element. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ + GenericElementLinkBase (const ID_type& dataID, + CLID link_clid, + const index_type& elemID, + const ElementType& elt, + IProxyDict* sg); + + + /** + * @brief Construct a link from a hashed key, index, AND pointer to element. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ + GenericElementLinkBase (sgkey_t key, + CLID link_clid, + const index_type& elemID, + const ElementType& elt, + IProxyDict* sg); + + + /** + * @brief Construct a link from an index and pointer to the container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ + GenericElementLinkBase (const_pointer_t obj, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg); + + + /** + * @brief Constructor from a link referencing a different type. + * @param other The object from which to copy. + * + * @c FROM_TRAITS is the @c ElementLinkTraits class for @c other; + * @c TO_TRAITS is the traits class for this object. + * The actual pointer values are not used, just the types are used. + * Default conversions for the storable pointer (i.e., derived->base) + * are allowed. + */ + template <class OTHER_INDEXING_POLICY, class FROM_TRAITS, class TO_TRAITS> + GenericElementLinkBase (const GenericElementLinkBase<OTHER_INDEXING_POLICY>& other, + FROM_TRAITS*, TO_TRAITS*); + + + /** + * @brief Return a pointer to the currently-referenced container object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + void* storableBase (castfn_t* castfn, const CLID& clid) const; + + + /** + * @brief Set the container referenced by the link to @c data. + * @param data Pointer to the new container. + * @param link_clid CLID of the link being set. + * @param replace True if we can change an existing link. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged unless @c replace is set. The @c replace argument + * should be set if the element is now in a new storable container; + * e.g. element ptr has been put in a new view container. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool setStorableObject (const_pointer_t data, + CLID link_clid, + bool replace, + IProxyDict* sg); + + + /** + * @brief Set the to an element given by index and pointer to container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + bool toIndexedElement (const_pointer_t obj, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg); + + + /** + * @brief Set the link to an element given by string key and index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void resetWithKeyAndIndex (const ID_type& dataID, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg); + + + /** + * @brief Set the link to an element given by string key and index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + void resetWithKeyAndIndex (sgkey_t key, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg); + + + /** + * @brief Set the index part of the link. + * @param index New index value. + */ + void setIndex (const index_type& index); + + + /** + * @brief Return the stored representation of the link index. + */ + const stored_index_type& storedIndex() const; + + + /** + * @brief Set the cached element stored in the link. + * @param elt New value for the cached element. + */ + void setCachedElement (const ElementType& elt) const; + + + /** + * @brief Retrieve the cached element from the link. + * @param elt[out] The cached element. + * @returns True if an element was cached; false otherwise. + * + * @c elt is left unmodified if there is no cached element. + */ + bool getCachedElement (ElementConstPointer& elt) const; + + + /** + * @brief Return the internal proxy holder object. + */ + const SG::DataProxyHolder& proxyHolder() const; + + +private: + template <class OTHER_POLICY> + friend class GenericElementLinkBase; + + /// For regression testing. + template <class POLICY> + friend class ::ElementLinkBaseT_test; + + /// The hashed key for this link. + SG::sgkey_t m_key; + + /// The index of the element within the container for this link. + stored_index_type m_index; + + /// SG proxy for this link. + SG::DataProxyHolder m_proxy; //! Transient + + /// Do we have a cached element? + mutable bool m_cacheValid; //! Transient + + /// Cached copy of the element to which this link refers. + mutable ElementType m_element; //! Transient + + /// Connect to selection rules. + typedef typename + ROOT_SELECTION_NS::SG::GenericElementLinkBase<INDEXING_POLICY>::self DictSel; +}; + + +} // namespace SG + + +/// Selection rules: declare transient members. +ENTER_ROOT_SELECTION_NS +namespace SG { +template <class INDEXING_POLICY> +struct GenericElementLinkBase : SelectNoInstance { + typedef GenericElementLinkBase<INDEXING_POLICY> self; + ROOT_SELECTION_NS::TRANSIENT m_proxy; + ROOT_SELECTION_NS::TRANSIENT m_cacheValid; + ROOT_SELECTION_NS::TRANSIENT m_element; +}; + +} +EXIT_ROOT_SELECTION_NS + + +#include "AthLinks/GenericElementLinkBase.icc" + + +#endif // not ATHLINKS_GENERICELEMENTLINKBASE_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.icc b/EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.icc new file mode 100644 index 00000000..92da25be --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/GenericElementLinkBase.icc @@ -0,0 +1,567 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/GenericElementLinkBase.icc + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Generic base class for ElementLinks. + */ + + + +namespace SG { + + +/** + * @brief Test the index validity. + * @returns True if the index is not valid (in default state). + */ +template <class INDEXING_POLICY> +inline +bool +GenericElementLinkBase<INDEXING_POLICY>::isDefaultIndex() const +{ + return ! INDEXING_POLICY::isValid (m_index); +} + + +/** + * @brief Test to see if this link has a cached element pointer. + */ +template <class INDEXING_POLICY> +inline +bool +GenericElementLinkBase<INDEXING_POLICY>::hasCachedElement() const +{ + return m_cacheValid; +} + + +/** + * @brief Test to see if this link is in the default state. + */ +template <class INDEXING_POLICY> +inline +bool +GenericElementLinkBase<INDEXING_POLICY>::isDefault() const +{ + return m_proxy.isDefault() && !hasCachedElement() && isDefaultIndex(); +} + + +/** + * @brief Return the index of the link. + */ +template <class INDEXING_POLICY> +inline +typename GenericElementLinkBase<INDEXING_POLICY>::index_type +GenericElementLinkBase<INDEXING_POLICY>::index() const +{ + return INDEXING_POLICY::storedToExternal (m_index); +} + + +/** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ +template <class INDEXING_POLICY> +inline +const typename GenericElementLinkBase<INDEXING_POLICY>::ID_type& +GenericElementLinkBase<INDEXING_POLICY>::dataID() const +{ + return m_proxy.dataID(); +} + + +/** + * @brief Return the SG key that we reference, as a hash. + * + * Returns 0 on failure. + */ +template <class INDEXING_POLICY> +inline +typename GenericElementLinkBase<INDEXING_POLICY>::sgkey_t +GenericElementLinkBase<INDEXING_POLICY>::key() const +{ + return m_key; +} + + +/** + * @brief Return the data source for this reference. + */ +template <class INDEXING_POLICY> +inline +IProxyDict* +GenericElementLinkBase<INDEXING_POLICY>::source() const +{ + return m_proxy.source(); +} + + +/** + * @brief Return the SG proxy for the container holding this element. + * + * If this is a null link, we return 0. + * If we're directly referencing an object that's not in StoreGate, + * either return 0 or throw @c ExcPointerNotInSG, depending + * on @c nothrow. Otherwise, return the proxy for the object + * we're referencing. + */ +template <class INDEXING_POLICY> +inline +const SG::DataProxy* +GenericElementLinkBase<INDEXING_POLICY>::proxy() const +{ + return m_proxy.proxy(true); +} + + +/** + * @brief Reset the link to a null state. + */ +template <class INDEXING_POLICY> +inline +void GenericElementLinkBase<INDEXING_POLICY>::reset () +{ + m_proxy.clear(); + m_key = 0; + m_cacheValid = 0; + INDEXING_POLICY::reset (m_index); +} + + +/** + * @brief Finish initialization after link has been read. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. + * Returns true. + * + * If @c sg is 0, then we use the global default store. + */ +template <class INDEXING_POLICY> +inline +bool +GenericElementLinkBase<INDEXING_POLICY>::toTransient (IProxyDict* sg /*= 0*/) +{ + m_proxy.toTransient (m_key, sg); + m_cacheValid = 0; + return true; +} + + +/** + * @brief Prepare this link for writing. + * + * This method should be called before trying to write the link with root. + * It will make sure the persistent fields of the link are valid. + * It will also perform remapping if needed. + * + * Will return true on success. Will return false if either the container + * or the element index has not been specified. Will throw + * @c ExcPointerNotInSG if the link is referencing a container that + * is not in SG. + */ +template <class INDEXING_POLICY> +inline +bool +GenericElementLinkBase<INDEXING_POLICY>::toPersistent() +{ + if (isDefault()) return true; + if (m_proxy.isDefault() || isDefaultIndex()) return false; + if (m_proxy.toPersistent (m_key, m_index)) + m_cacheValid = 0; + return true; +} + + +/** + * @brief Default constructor. Makes a null link. + */ +template <class INDEXING_POLICY> +inline +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase() + : m_key(0), + m_cacheValid(false), + m_element() +{ + INDEXING_POLICY::reset (m_index); +} + + +/** + * @brief Construct a link from a string key and an index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +template <class INDEXING_POLICY> +inline +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase + (const ID_type& dataID, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg) + : m_index (elemID), + m_cacheValid(false), + m_element() +{ + m_key = m_proxy.toIdentifiedObject (dataID, link_clid, sg); +} + + +/** + * @brief Construct a link from a hashed key and an index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +template <class INDEXING_POLICY> +inline +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase + (sgkey_t key, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg) + : m_key (key), + m_index (elemID), + m_cacheValid (false), + m_element() +{ + m_proxy.toIdentifiedObject (key, link_clid, sg); +} + + +/** + * @brief Construct a link from a string key, index, AND pointer to element. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ +template <class INDEXING_POLICY> +inline +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase + (const ID_type& dataID, + CLID link_clid, + const index_type& elemID, + const ElementType& elt, + IProxyDict* sg) + : m_index (elemID), + m_cacheValid (true), + m_element (elt) +{ + m_key = m_proxy.toIdentifiedObject (dataID, link_clid, sg); +} + + +/** + * @brief Construct a link from a hashed key, index, AND pointer to element. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param elt Pointer to the element. + * @param sg Associated store. + * + * USE CAREFULLY: no coherency checks, we just trust you! + * + * If @c sg is 0, we take the global default. + */ +template <class INDEXING_POLICY> +inline +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase + (sgkey_t key, + CLID link_clid, + const index_type& elemID, + const ElementType& elt, + IProxyDict* sg) + : m_key (key), + m_index (elemID), + m_cacheValid (true), + m_element (elt) +{ + m_proxy.toIdentifiedObject (key, link_clid, sg); +} + + +/** + * @brief Construct a link from an index and pointer to the container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, we take the global default. + */ +template <class INDEXING_POLICY> +inline +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase + (const_pointer_t obj, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg) + : m_index (elemID), + m_cacheValid (false), + m_element() +{ + m_key = m_proxy.toStorableObject (obj, link_clid, sg); +} + + +/** + * @brief Constructor from a link referencing a different type. + * @param other The object from which to copy. + * + * @c FROM_TRAITS is the @c ElementLinkTraits class for @c other; + * @c TO_TRAITS is the traits class for this object. + * The actual pointer values are not used, just the types are used. + * Default conversions for the storable pointer (i.e., derived->base) + * are allowed. + */ +template <class INDEXING_POLICY> +template <class OTHER_INDEXING_POLICY, class FROM_TRAITS, class TO_TRAITS> +GenericElementLinkBase<INDEXING_POLICY>::GenericElementLinkBase + (const GenericElementLinkBase<OTHER_INDEXING_POLICY>& other, + FROM_TRAITS*, + TO_TRAITS*) + : m_key (other.m_key), + m_index (other.m_index), + m_proxy (other.m_proxy, + (typename FROM_TRAITS::Storable*)0, + (typename TO_TRAITS::Storable*)0), + m_cacheValid (other.m_cacheValid), + m_element (other.m_element) +{ + // The TRAITS template args are redundant here with the indexing policy args, + // but we need this signature for the non-templated ElementLinkBase case. +} + + +/** + * @brief Return a pointer to the currently-referenced container object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +template <class INDEXING_POLICY> +inline +void* GenericElementLinkBase<INDEXING_POLICY>::storableBase + (castfn_t* castfn, const CLID& clid) const +{ + return m_proxy.storableBase (castfn, clid); +} + + +/** + * @brief Set the container referenced by the link to @c data. + * @param data Pointer to the new container. + * @param link_clid CLID of the link being set. + * @param replace True if we can change an existing link. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged unless @c replace is set. The @c replace argument + * should be set if the element is now in a new storable container; + * e.g. element ptr has been put in a new view container. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class INDEXING_POLICY> +inline +bool GenericElementLinkBase<INDEXING_POLICY>::setStorableObject + (const_pointer_t data, + CLID link_clid, + bool replace, + IProxyDict* sg) +{ + if (!m_proxy.isDefault()) { + if (!replace) return false; + INDEXING_POLICY::reset (m_index); + } + + m_key = m_proxy.toStorableObject (data, link_clid, sg); + return true; +} + + +/** + * @brief Set the to an element given by index and pointer to container. + * @param obj Pointer to the container (storable). + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * @returns True if the link was changed. + * + * If the link is already set, this will return false and leave the + * link unchanged. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class INDEXING_POLICY> +inline +bool GenericElementLinkBase<INDEXING_POLICY>::toIndexedElement + (const_pointer_t obj, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg) +{ + if (m_proxy.isDefault() && isDefaultIndex() && !hasCachedElement()) { + m_key = m_proxy.toStorableObject (obj, link_clid, sg); + m_index = elemID; + m_cacheValid = false; + return true; + } + return false; +} + + +/** + * @brief Set the link to an element given by string key and index. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class INDEXING_POLICY> +inline +void GenericElementLinkBase<INDEXING_POLICY>::resetWithKeyAndIndex + (const ID_type& dataID, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg) +{ + m_key = m_proxy.toIdentifiedObject (dataID, link_clid, sg); + m_index = elemID; + m_cacheValid = false; +} + + +/** + * @brief Set the link to an element given by string key and index. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param elemID The index of the element within the container. + * @param sg Associated store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +template <class INDEXING_POLICY> +inline +void GenericElementLinkBase<INDEXING_POLICY>::resetWithKeyAndIndex + (sgkey_t key, + CLID link_clid, + const index_type& elemID, + IProxyDict* sg) +{ + m_key = key; + m_proxy.toIdentifiedObject (key, link_clid, sg); + m_index = elemID; + m_cacheValid = false; +} + + +/** + * @brief Set the index part of the link. + * @param index New index value. + */ +template <class INDEXING_POLICY> +inline +void +GenericElementLinkBase<INDEXING_POLICY>::setIndex (const index_type& index) +{ + m_index = index; +} + + +/** + * @brief Return the stored representation of the link index. + */ +template <class INDEXING_POLICY> +inline +const typename GenericElementLinkBase<INDEXING_POLICY>::stored_index_type& +GenericElementLinkBase<INDEXING_POLICY>::storedIndex() const +{ + return m_index; +} + + +/** + * @brief Set the cached element stored in the link. + * @param elt New value for the cached element. + */ +template <class INDEXING_POLICY> +inline +void +GenericElementLinkBase<INDEXING_POLICY>::setCachedElement (const ElementType& elt) const +{ + m_element = elt; + m_cacheValid = true; +} + + +/** + * @brief Retrieve the cached element from the link. + * @param elt[out] The cached element. + * @returns True if an element was cached; false otherwise. + * + * @c elt is left unmodified if there is no cached element. + */ +template <class INDEXING_POLICY> +inline +bool +GenericElementLinkBase<INDEXING_POLICY>::getCachedElement (ElementConstPointer& elt) const +{ + if (m_cacheValid) { + elt = &m_element; + return true; + } + return false; +} + + +/** + * @brief Return the internal proxy holder object. + */ +template <class INDEXING_POLICY> +inline +const SG::DataProxyHolder& +GenericElementLinkBase<INDEXING_POLICY>::proxyHolder() const +{ + return m_proxy; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/AthLinks/exceptions.h b/EDM/athena/Control/AthLinks/AthLinks/exceptions.h new file mode 100644 index 00000000..0d11d01c --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/exceptions.h @@ -0,0 +1,243 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/exceptions.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Exceptions that can be thrown from AthLinks. + */ + + +#ifndef ATHLINKS_EXCEPTIONS_H +#define ATHLINKS_EXCEPTIONS_H + + +#include "AthenaKernel/sgkey_t.h" +#include "CxxUtils/noreturn.h" +#include "GaudiKernel/ClassID.h" +#include <stdexcept> + + +namespace SG { + + +/** + * @brief Exception --- The object referenced by a DataLink / ElementLink is + * not registered in SG. + * + * You have a DataLink or ElementLink that's referencing an object + * directly by a pointer. You attempted an operation on the link + * that requires finding the object's StoreGate information (such as trying + * to make it persistent), but the object had not been registered + * in StoreGate. + */ +class ExcPointerNotInSG + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param pointer Pointer to the object that the link is referencing. + */ + ExcPointerNotInSG (const void* pointer); +}; + + +/** + * @brief Exception --- Attempt to set DataLink / ElementLink with CLID <clid> + * to object with CLID <clid>. + * + * + * The object being assigned to a link doesn't match the link's + * declared type. It should not be possible to do this through the + * link's public interfaces, but it could occur reading a corrupt + * input file. + */ +class ExcCLIDMismatch + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param obj_clid The CLID of the object being assigned to the link. + * @param link_clid The declared CLID of the link. + */ + ExcCLIDMismatch (CLID obj_clid, CLID link_clid); +}; + + +/** + * @brief Exception --- Attempt to dereference invalid DataLink / ElementLink " + * + * You tried to dereference a link that either is null or for which the + * referenced object can not be retrieved from StoreGate. + */ +class ExcInvalidLink + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID of the link. + * @param key String key of the link. + * @param sgkey Hashed key of the link. + */ + ExcInvalidLink (CLID clid, const std::string& key, SG::sgkey_t sgkey); +}; + + +/** + * @brief Throw a SG::ExcInvalidLink exception. + * @param clid CLID of the link. + * @param key String key of the link. + * @param sgkey Hashed key of the link. + */ +ATH_NORETURN(void throwExcInvalidLink (CLID clid, + const std::string& key, + SG::sgkey_t sgkey)); + + +/** + * @brief Exception --- ForwardIndexingPolicy: internal link state is invalid. + * + * You tried to dereference a link to a container described by + * ForwardIndexingPolicy (a vector or similar), but the index + * was outside of the range of the container. + */ +class ExcBadForwardLink + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param index Index in the link. + * @param size Size of the referenced container. + */ + ExcBadForwardLink (size_t index, size_t size); +}; + + +/** + * @brief Throw a SG::ExcBadForwardLink exception. + * @param index Index in the link. + * @param size Size of the referenced container. + */ +ATH_NORETURN(void throwExcBadForwardLink (size_t index, size_t size)); + + +/** + * @brief Exception --- element not found + * + * You had an ElementLink initialized with a pointer to the element directly. + * Some operation requires the index of the element within its container, + * but the element is not present in the container. + */ +class ExcElementNotFound + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param where The operation being attempted. + */ + ExcElementNotFound (const std::string& where); +}; + + +/** + * @brief Throw a SG::ExcElementNotFound exception. + * @param where The operation being attempted. + */ +ATH_NORETURN(void throwExcElementNotFound (const char* where)); + + +/// Backwards compatibility. +typedef ExcElementNotFound maybe_thinning_error; + + + +/** + * @brief Exception --- invalid index + * + * You tried to set the index for an ElementLink to an invalid value. + */ +class ExcInvalidIndex + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param where The operation being attempted. + */ + ExcInvalidIndex (const std::string& where); +}; + + +/** + * @brief Throw a SG::ExcInvalidIndex exception. + * @param where The operation being attempted. + */ +ATH_NORETURN(void throwExcInvalidIndex (const char* where)); + + +/** + * @brief Exception --- index not found + * + * You have an ElementLink referencing an associative container. + * You tried to dereference the link, but the index stored in the link + * wasn't present in the container. + */ +class ExcIndexNotFound + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param where The operation being attempted. + */ + ExcIndexNotFound (const std::string& where); +}; + + +/** + * @brief Throw a SG::ExcIndexNotFound exception. + * @param where The operation being attempted. + */ +ATH_NORETURN(void throwExcIndexNotFound (const char* where)); + + +/** + * @brief Exception --- incomparable ElementLink + * + * In order to comare two ElementLink instances, both must have available + * both the StoreGate key of the container and the index within the + * container. If only a pointer to the element is available, then + * the link cannot be compared. (This is to avoid the results + * of comparisons possibly changing.) + */ +class ExcIncomparableEL + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + */ + ExcIncomparableEL(); +}; + + +/** + * @brief Throw a SG::IncomparableEL exception. + */ +ATH_NORETURN(void throwExcIncomparableEL()); + + +} // namespace SG + + +#endif // not ATHLINKS_EXCEPTIONS_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/selection.xml b/EDM/athena/Control/AthLinks/AthLinks/selection.xml new file mode 100644 index 00000000..ee0b253d --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/selection.xml @@ -0,0 +1,49 @@ +<lcgdict> + <class name="SG::DataProxyHolder"> + <field name="m_proxy" transient="true"/> + </class> + + <!-- The element link vector base class(es): --> + <class name="ElementLinkVectorBase" > + <field name="m_isDirectIO" transient="true" /> + </class> + <read sourceClass="ElementLinkVectorBase" version="[1-]" + targetClass="ElementLinkVectorBase" source="" + target="m_isDirectIO" > + <![CDATA[ + // Tell the object that direct ROOT I/O is happening: + m_isDirectIO = true; + // Let the object prepare for being used: + if (newObj) newObj->toTransient(); + ]]> + </read> + + <!-- The data link base class(es): --> + <class name="DataLinkBase" > + <field name="m_proxy" transient="true" /> + </class> + <read sourceClass="DataLinkBase" version="[1-]" + targetClass="DataLinkBase" source="" + target="" + > + <![CDATA[ + // Let the object prepare for being used: + newObj->toTransient(); + ]]> + </read> + + <class name="ElementLinkBase"> + <field name="m_proxy" transient="true"/> + <field name="m_element" transient="true"/> + </class> + <read sourceClass="ElementLinkBase" version="[1-]" + targetClass="ElementLinkBase" source="" + target="" + > + <![CDATA[ + // Let the object prepare for being used: + if (newObj) newObj->toTransient(); + ]]> + </read> + +</lcgdict> diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/AssociationObjectIterator.h b/EDM/athena/Control/AthLinks/AthLinks/tools/AssociationObjectIterator.h new file mode 100644 index 00000000..39efe7bc --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/AssociationObjectIterator.h @@ -0,0 +1,311 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*! \file */ +/*! \class AssociationObjectIterator + * \brief object iterator for association maps (internal use only!) + */ +/*! \class AssociationObjectIterator + * + * The \c AssociationObjectIterator protects the \c AssociationMap class from + * specifics of the internal look-up map.\n + * This is not a stand-alone class. It can only be compiled within the + * \c AssociationMap class, or similar classes providing the required type + * definitions! + * + * \author Peter Loch <loch@physics.arizona.edu> + * \date June 2, 2004 - first implementation + * + * fn AssociationObjectIterator begin() + * brief begin object iterator + * + * fn AssociationObjectIterator end() + * brief end object iterator + * + * fn AssociationObjectIterator next() + * brief advances iterator forward + * + * fn AssociationObjectIterator prev() + * brief steps iterator back + * + * fn AssociationObjectIterator operator++() + * brief same as \c next() + * + * fn AssociationObjectIterator operator++(int) + * brief same as \c next() + * + * fn AssociationObjectIterator operator--() + * brief same as \c prev() + * + * fn AssociationObjectIterator operator--(int) + * brief same as \c prev() + * + * fn bool operator==(const AssociationObjectIterator&) + * brief equality comparator + * + * fn bool operator!=(const AssociationObjectIterator&) + * brief inequality comparator + * + * fn AssociationObjectIterator operator*() + * brief iterator value access operator + * + * var const object_type* first + * brief public variable holding object pointer + * + * var asso_iterator second + * brief public variable holding iterator to associations + * + * fn AssociationObjectIterator find(const object_type*) + * brief returns iterator for a given object + * + * fn const object_type* getObject() + * brief get pointer to object (same as \c first ) + * + * fn const object_link& getObjectLink() + * brief get link to object + * + * fn asso_iterator getFirstAssociation() + * brief get iterator to first association (same as \c second.begin() ) + * + * fn asso_iterator getLastAssocation() + * brief get end iterator for associations (same as \c second.end() ) + * + * fn asso_iterator findAssociation(const asso_type*) + * brief returns iterator for specific associated object + * + * fn bool containsAssociation(const asso_type*) + * brief checks if given object is associated with current object + * + * fn size_t size() + * brief number of associations for current object + * + */ + +/*! \brief code only expands with the \a ASSOCIATIONMAP_CONTEXT */ +#ifdef ASSOCIATIONMAP_CONTEXT + +class AssociationObjectIterator +{ +public: + +/*! \name Constructors and Destructor */ +/*@{*/ +/*! \brief default constructor */ +AssociationObjectIterator() : m_store(0) +{ } + +/*! \brief useful alternate constructor + * + * \param theStore - reference to association map + */ +AssociationObjectIterator(const store_type& theStore) + : m_store(&theStore) + , m_actual(theStore.begin()) +{ } + +/*! \brief useful alternate constructor + * + * \param theStore - reference to association map + * \param pos - reference to a position in the association map + */ +AssociationObjectIterator(const store_type& theStore, + const typename store_type::const_iterator& pos) + : m_store(&theStore) + , m_actual(pos) +{ } + +/*! \brief copy constructor + */ +AssociationObjectIterator(const AssociationObjectIterator& rhs) : + m_store ( rhs.m_store ), + m_actual( rhs.m_actual ) +{} + +/*! \brief assignment operator + */ +AssociationObjectIterator& operator=(const AssociationObjectIterator& rhs) +{ + if ( this != &rhs ) { + m_store = rhs.m_store; + m_actual= rhs.m_actual; + } + return *this; +} + +/*! \brief default destructor */ +~AssociationObjectIterator() +{ } +/*@}*/ + +/*! \name Iterator Manipulation */ +/*@{*/ + +/*! \brief begin object iterator */ +AssociationObjectIterator begin() +{ return AssociationObjectIterator(*m_store); } + +/*! \brief end object iterator */ +AssociationObjectIterator end() +{ return AssociationObjectIterator(*m_store, m_store->end()); } + +AssociationObjectIterator begin() const +{ return AssociationObjectIterator(*m_store); } +/*! \brief end object iterator */ + +AssociationObjectIterator end() const +{ return AssociationObjectIterator(*m_store,m_store->end()); } + +/*! \brief forward advancement */ +AssociationObjectIterator next() +{ ++m_actual; return *this; } + +/*! \brief backward stepping */ +AssociationObjectIterator prev() +{ --m_actual; return *this; } + +/*! \brief post-forward advancement operator */ +AssociationObjectIterator operator++() +{ + AssociationObjectIterator tmp(*this); + ++m_actual; + return tmp; +} + +/*! \brief pre-forward advancement operator */ +AssociationObjectIterator operator++(int) { return this->next(); } + +/*! \brief post-backward stepping operator */ +AssociationObjectIterator operator--() +{ + AssociationObjectIterator tmp(*this); + --m_actual; + return tmp; +} + +/*! \brief pre-backward stepping operator */ +AssociationObjectIterator operator--(int) { return this->prev(); } +/*@}*/ + +/*! \name Iterator Comparisons */ +/*@{*/ +/*! \brief equality comparison + * + * \param anOther - an other \c AssociationObjectIterator + */ +bool operator==(const AssociationObjectIterator& anOther) const +{ return m_actual == anOther.m_actual; } +// bool operator==(AssociationObjectIterator& anOther) +// { return m_actual == anOther.m_actual; } +/*! \brief inequality comparison + * + * \param anOther - an other \c AssociationObjectIterator + */ +bool operator!=(const AssociationObjectIterator& anOther) const +{ return m_actual != anOther.m_actual; } +// bool operator!=(AssociationObjectIterator& anOther) +// { return m_actual != anOther.m_actual; } +/*@}*/ + +/*! \name Data Access */ +/*@{*/ +/*! \brief \c * operator returns iterator by value + * + * \warning This is not the standard behavior of STL-like iterators! This + * implementation hides the actual value type, though, because it + * is not the object type, as clients would probably expect. The + * stored objects can be accessed using the specialized methods + * provided by this class. + */ +AssociationObjectIterator operator*() const { return *this; } + +/*! \brief access to underlying object */ +const object_type* operator->() +{ return this->getObject(); } + +/*! \brief access to underlying object */ +const object_type* operator->() const +{ return this->getObject(); } + +/*! \brief access to object pointer */ +const object_type* first() const { return *(m_actual->first); } +/*! \brief access to iterator of first association */ +asso_iterator second() const +{ return asso_iterator(m_actual->second,m_actual->second.begin()); } +/*! \brief find a given object in store + * + * \param objectPointer - pointer reference to the object searched for + * + * This method returns an \c AssociationObjectIterator which can immediately + * provide access to the associations using the \c second public variable, + * the appropriate \c getFirstAssociation, \c getLastAssociation methods. + */ +AssociationObjectIterator find(const object_type* objectPointer) const +{ + const AssociationObjectIterator lastObj = this->end(); + AssociationObjectIterator firstObj = this->begin(); + AssociationObjectIterator foundObj = lastObj; + while (firstObj != lastObj ) + { + if ( firstObj.isValid() && firstObj.getObject() == objectPointer ) + { + foundObj = firstObj; + firstObj = lastObj; + } + else + { + ++firstObj; + } + } + return foundObj; +} +/*! \brief retrieve the pointer to a given object + * + * This method allows direct access to the object pointer stored in each + * \c AssociationObjectIterator instance. + * + */ +const object_type* getObject() const { return this->first(); } + +/*! \brief retrieve link to the object. */ +const object_link& getObjectLink() const { return m_actual->first; } + +bool isValid() const { return this->m_actual->first.isValid(); } + +/*! \brief retrieve iterator to first associated object */ +asso_iterator getFirstAssociation() const +{ + return asso_iterator(m_actual->second, m_actual->second.begin()); +} + +/*! \brief retrieve end iterator to internal associated object store */ +asso_iterator getLastAssociation() const +{ + return asso_iterator(m_actual->second, m_actual->second.end()); +} + +/*! \brief find the iterator for a given object */ +asso_iterator findAssociation(const asso_type* assoPointer) const +{ + asso_iterator assItr = asso_iterator(m_actual->second, + m_actual->second.begin()); + return assItr.find(assoPointer); +} + +/*! \brief check if the given object can be matched among the associated objects */ +bool containsAssociation(const asso_type* assoPointer) const +{ return this->findAssociation(assoPointer) != this->getLastAssociation(); } + +/*! \brief get number of association for current pointed-to object */ +size_t getNumberOfAssociations() const +{ return m_actual->second.size(); } + +size_t size() const { return m_store->size(); } + +private: + + const store_type* m_store; + typename store_type::const_iterator m_actual; +}; +#endif + diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/AssociationVectorIterator.h b/EDM/athena/Control/AthLinks/AthLinks/tools/AssociationVectorIterator.h new file mode 100644 index 00000000..9cdbeeba --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/AssociationVectorIterator.h @@ -0,0 +1,201 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef ASSOCIATION_CONTEXT +/*! \brief iterator for association vectors (internal use only) + * + * \c AssociationVectorIterator behaves with many respects like a + * STL iterator, but is also incomplete with respect to the STL implementation. + * It can only be used in the context of the association objects, and should + * not be included directly into client code. + */ + + class AssociationVectorIterator + { + public: + + /*! \brief alternate constructor + * + * The alternate constructor is the only meaningful constructor. It requires + * an argument + * \param \c assoStore is a reference to the association store in the + * implementation class + */ + AssociationVectorIterator(const asso_store& assoStore) + : m_store(&assoStore) + , m_actual(assoStore.begin()) + { } + + /*! \brief alternate constructor + * + * The alternate constructor is the only meaningful constructor. It requires + * an argument + * \param \c assoStore is a reference to the association store in the + * implementation class + * \param \c pos is a reference to a position in the association store + */ + AssociationVectorIterator(const asso_store& assoStore, + const asso_store_iterator& pos) + : m_store(&assoStore) + , m_actual(pos) + { } + + /*! \brief destructor */ + ~AssociationVectorIterator() { }; + + /*! \name Iterator Methods + * + * The \c begin(), \c end() and \c find() methods are usually provided by + * the store, here the iterator itself provides it. The iterator forward + * (\c next()) and backward (\c prev()) advancement methods are provided to + * support the corresponding operators. + */ + /*@{*/ + AssociationVectorIterator begin() + { + if ( m_store) { + return AssociationVectorIterator(*m_store); + } else { + throw std::runtime_error( "Null pointer to store of associations" ); + // dead-code + return AssociationVectorIterator( *m_store ); + } + } + + AssociationVectorIterator end() + { + if ( m_store ) { + return AssociationVectorIterator(*m_store); + } else { + throw std::runtime_error( "Null pointer to store of associations" ); + // dead-code + return AssociationVectorIterator( *m_store ); + } + } + + AssociationVectorIterator begin() const + { + if ( m_store) { + return AssociationVectorIterator(*m_store, m_store->begin()); + } else { + throw std::runtime_error( "Null pointer to store of associations" ); + // dead-code + return AssociationVectorIterator( *m_store ); + } + } + + AssociationVectorIterator end() const + { + if ( m_store ) { + return AssociationVectorIterator(*m_store, m_store->end()); + } else { + throw std::runtime_error( "Null pointer to store of associations" ); + // dead-code + return AssociationVectorIterator( *m_store ); + } + } + + AssociationVectorIterator next() { ++m_actual; return *this; } + AssociationVectorIterator prev() { --m_actual; return *this; } + + AssociationVectorIterator find(const asso_type* anAsso) const + { + typename asso_store::const_iterator assoEnd = m_store->end(); + //m_actual = m_store->begin(); + //size_t iCtr = 0; + for ( typename asso_store::const_iterator itr = m_store->begin(); + itr != assoEnd; ++itr ) { + if ( **itr == anAsso ) { + return AssociationVectorIterator( *m_store, itr ); + } + } + return this->end(); + } + /*@}*/ + + /*! \name Iterator Operations */ + /*@{*/ + + /*! \brief post-forward advancement operator */ + AssociationVectorIterator operator++() + { + AssociationVectorIterator tmp(*this); + ++m_actual; + return tmp; + } + + /*! \brief pre-forward advancement operator */ + AssociationVectorIterator operator++(int) { return this->next(); } + + /*! \brief post-forward advancement operator */ + AssociationVectorIterator operator--() { return this->prev(); } + + /*! \brief post-forward advancement operator */ + AssociationVectorIterator operator--(int) + { + AssociationVectorIterator tmp(*this); + --m_actual; + return tmp; + } + + // bool operator==(AssociationVectorIterator& anOther) + // { return m_actual == anOther.m_actual; } + bool operator==(const AssociationVectorIterator& anOther) const + { return m_actual == anOther.m_actual; } + + // bool operator!=(AssociationVectorIterator& anOther) + // { return m_actual != anOther.m_actual; } + bool operator!=(const AssociationVectorIterator& anOther) const + { return m_actual != anOther.m_actual; } + + /*! \brief object retrieval */ + const asso_type* operator*() const + { + return m_actual != m_store->end() + ? *(*m_actual) + : 0; + } + const asso_type* operator->() const + { + return m_actual != m_store->end() + ? *(*m_actual) + : 0; + } + + asso_link getLink() const + { + return *m_actual; + } + + bool isValid() const + { + return m_actual != m_store->end() && m_actual->isValid(); + } + + /*@}*/ + + /*! \name store parameters */ + /*@{*/ + size_t size() const { return m_store->size(); } + /*@}*/ + + private: + + /*! \brief default constructor */ + AssociationVectorIterator() : + m_store (0), + m_actual() + { }; + + private: + + /*! \brief pointer to store */ + const asso_store* m_store; + + /*! \brief actual store iterator */ + //asso_store_iterator m_actual; + typename asso_store::const_iterator m_actual; + }; + +#endif // ASSOCIATION_CONTEXT diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.h b/EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.h new file mode 100644 index 00000000..6af8a3b1 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.h @@ -0,0 +1,422 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/DataProxyHolder.h + * @author scott snyder <snyder@bnl.gov> + * @date Dec, 2013 + * @brief Manage @c DataProxy reference in ElementLink/DataLink. + */ + + +#ifndef ATHLINKS_DATAPROXYHOLDER_H +#define ATHLINKS_DATAPROXYHOLDER_H + + +#include "SGTools/CurrentEventStore.h" +#include "AthenaKernel/IStringPool.h" +#include "SGTools/DataProxy.h" +#include "SGTools/IProxyDictWithPool.h" // TEMPORARY +#include <string> + + +namespace SG { + + +/** + * @brief Manage @c DataProxy reference in ElementLink/DataLink. + * + * This class factors out operations on @c DataProxy that are common + * between @c ElementLink and @c DataLink, and holds a pointer to the + * proxy. This pointer is transient; the (persistent) SG key field + * is stored in the class that holds this one, and is passed as a parameter + * where needed. + * + * We can be initialized either with a key or with a pointer to an object. + * In the former case, we try immediately to look up the proxy for that key. + * If we find it, then we use it; otherwise, we create a dummy @c DataProxy + * for that key and add it to our store. If we're given a pointer, we again + * immediately try to look up the corresponding proxy. If we don't find it, + * then we store the pointer directly in the proxy member, with a flag + * to identify this case. Subsequent operations that require a proxy + * will again try to look up the proxy in the store; if that fails, + * then an exception will be thrown. + * + * When we create a new link, the store by default is taken from the + * global default given by SG::CurrentEventStore::store(). + * This is a thread-specific value, so fetching it can be expensive. + * If you are creating links inside a loop, it is best to fetch + * the default before the loop and then passing the result explicitly + * when you create the links. + */ +class DataProxyHolder +{ +public: + /// Type of hashed keys. + typedef IStringPool::sgkey_t sgkey_t; + + /// Type of string keys. + typedef std::string ID_type; + + /// Generic pointer type. + typedef void* pointer_t; + typedef const void* const_pointer_t; + + /// Function casting from a @c SG::DataProxy to a pointer. + typedef void* castfn_t (SG::DataProxy*); + + + + /** + * @brief Default constructor. + * + * Make a null link. + */ + DataProxyHolder(); + + + /** + * @brief Constructor from a holder referencing a different type. + * @param other The object from which to copy. + * + * @c FROM_STORABLE is the storable class to which @c other refers; + * @c TO_STORABLE is the storable class for this object. + * The actual pointer values are not used, just the types are used. + * Default conversions for the storable pointer (i.e., derived->base) + * are allowed. + */ + template <class FROM_STORABLE, class TO_STORABLE> + DataProxyHolder (const DataProxyHolder& other, FROM_STORABLE*, TO_STORABLE*); + + + /** + * @brief Reset the link to null. + */ + void clear(); + + + /** + * @brief Set the link to an object given by a pointer. + * @param obj Pointer to the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * This will try to look up the proxy for @c obj. If that succeeds, + * then we store the pointer to the proxy and return the SG key. + * Otherwise, we store a pointer to the object itself, flagging + * this case with the low bit, and return 0. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ + sgkey_t toStorableObject (const_pointer_t obj, + CLID link_clid, + IProxyDict* sg); + + + /** + * @brief Set the link to an object given by a string key. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * This will try to look up the proxy for @c dataID. If that succeeds, + * then we store the pointer to the proxy. Otherwise, we create + * a dummy proxy and add it to the store. We return the SG key + * in either case. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ + sgkey_t toIdentifiedObject (const ID_type& dataID, + CLID link_clid, + IProxyDict* sg); + + + /** + * @brief Set the link to an object given by a hashed key. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * This will try to look up the proxy for @c key. If that succeeds, + * then we store the pointer to the proxy. Otherwise, we create + * a dummy proxy and add it to the store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ + void toIdentifiedObject (sgkey_t key, + CLID link_clid, + IProxyDict* sg); + + + /** + * @brief Test to see if this is a null link. + */ + bool isDefault() const; + + + /** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ + const ID_type& dataID() const; + + + /** + * @brief Return a pointer to the currently-referenced object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ + void* storableBase (castfn_t* castfn, CLID clid) const; + + + + /** + * @brief Return the @c DataProxy for this link. + * @param nothrow If true, return 0 on failure instead of throwing + * an exception. + * + * If this is a null link, we return 0. + * Otherwise, if we're pointing at a @c DataProxy, return it. + * Otherwise, we're pointing at an object directly. Try to look up + * the corresponding @c DataProxy using the default store. Return it + * if we find it; otherwise, either throw @c ExcPointerNotInSG or + * return 0, depending on the @c nothrow parameter. + */ + SG::DataProxy* proxy (bool nothrow = false) const; + + + /** + * @brief Return the data source for this reference. + * + * If the link is null, return 0. + * If we're pointing at an object directly, then we return the default store + * if the object is found in SG; otherwise, throw @c ExcPointerNotInSG. + */ + IProxyDict* source() const; + + + /** + * @brief Finish initialization after link has been read. + * @param sgkey Hashed SG key. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. It calls @c toIdentifiedObject + * with the provided hashed key. + * + * If @c sg is 0, then we use the global default store. + */ + void toTransient (sgkey_t sgkey, IProxyDict* sg = 0); + + + /** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * This version does not perform link remapping. + */ + void toPersistentNoRemap (sgkey_t& sgkey); + + + /** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * If the target of the link has been remapped, then the @c sgkey and @c index + * parameters will be updated to reflect that, and @c true will be returned. + * Otherwise, if there was no remapping, then @c false will be returned. + * + * This version is for the case where indices are given by @c uint64_t. + */ + bool toPersistent (sgkey_t& sgkey, uint64_t& index); + + + /** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * If the target of the link has been remapped, then the @c sgkey and @c index + * parameters will be updated to reflect that, and @c true will be returned. + * Otherwise, if there was no remapping, then @c false will be returned. + * + * This version is for the case where indices are given by @c uint32_t. + */ + bool toPersistent (sgkey_t& sgkey, uint32_t& index); + + + /** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * This version is for the case where indices are not given by @c size_t. + * No remapping will be performed for this case; this function will + * always return false. + */ + template <class T> + bool toPersistent (sgkey_t& sgkey, const T& /*index*/); + + + /** + * @brief Adjust for thinning. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * If this link points to a container that has been thinned, + * @c sgkey and @c index will be adjusted accordingly. + * + * Returns @c true if the index was changed; @c false otherwise. + */ + bool thin (sgkey_t& sgkey, size_t& index); + + + /** + * @brief Compare for equality. + */ + bool operator== (const DataProxyHolder& other) const; + + + /** + * @brief Throw a @c ExcInvalidLink exception for this link. + * @param sgkey The hashed key for this link. + * + * This will fill in parameters for the exception message from the proxy. + */ + void throwInvalidLink (sgkey_t sgkey) const; + + +private: + /** + * @brief Test to see if we're pointing directly at an object. + * @returns True if we're pointing directly at an object, false + * if we're pointing at a @c DataProxy (or the link is null). + */ + bool isObjpointer() const; + + + /** + * @brief Return a pointer to the object we're pointing at directly. + * + * Should be used only if @c isObjpointer() is true. + */ + pointer_t objpointer() const; + + + /** + * @brief Store a direct pointer to an object. + * @param p Pointer to the object that we're referencing. + * + * This will overwrite @c m_proxy with the reference to the object. + */ + void storeObjpointer (const_pointer_t p); + + + /** + * @brief Helper for @c proxy(), for the case of a direct object pointer. + * @param nothrow If true, return 0 on failure instead of throwing + * an exception. + * + * This is the out-of-line portion of @c proxy(), called if this link + * is directly pointing at an object. Try to look up + * the corresponding @c DataProxy using the default store. Return it + * if we find it; otherwise, either throw @c ExcPointerNotInSG or + * return 0, depending on the @c nothrow parameter. + */ + SG::DataProxy* proxy1 (bool nothrow) const; + + + /** + * @brief Return the data source for this reference. + * + * If we're holding a pointer directly, rather than a proxy, + * then return 0 rather than raising an exception. + */ + IProxyDict* source1() const; + + + /** + * @brief Test to see if the link has been remapped. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * If this link has been remapped, @c sgkey and @c index will be + * adjusted accordingly. + * + * Returns @c true if the link was remapped, @c false otherwise. + */ + bool tryRemap (sgkey_t& sgkey, size_t& index); + + + /// The @c DataProxy referring to our object, if the LSB is clear; + /// pointer to the object which we're referencing directly if the LSB is set. + SG::DataProxy* m_proxy; //! Transient +}; + + +} // namespace SG + + +#include "AthLinks/tools/DataProxyHolder.icc" + + +#endif // not ATHLINKS_DATAPROXYHOLDER_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.icc b/EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.icc new file mode 100644 index 00000000..91dd84b7 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/DataProxyHolder.icc @@ -0,0 +1,162 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/DataProxyHolder.icc + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Manage @c DataProxy reference in ElementLink/DataLink. + */ + + +namespace SG { + + +/** + * @brief Default constructor. + * + * Make a null link. + */ +inline +DataProxyHolder::DataProxyHolder() + : m_proxy(0) +{ +} + + +/** + * @brief Constructor from a holder referencing a different type. + * @param other The object from which to copy. + * + * @c FROM_STORABLE is the storable class to which @c other refers; + * @c TO_STORABLE is the storable class for this object. + * The actual pointer values are not used, just the types are used. + * Default conversions for the storable pointer (i.e., derived->base) + * are allowed. + */ +template <class FROM_STORABLE, class TO_STORABLE> +DataProxyHolder::DataProxyHolder (const DataProxyHolder& other, + FROM_STORABLE*, TO_STORABLE*) +{ + if (other.isObjpointer()) { + FROM_STORABLE* from_ptr = reinterpret_cast<FROM_STORABLE*>(other.objpointer()); + TO_STORABLE* to_ptr = from_ptr; + storeObjpointer (to_ptr); + } + else + m_proxy = other.m_proxy; +} + + +/** + * @brief Reset the link to null. + */ +inline +void DataProxyHolder::clear() +{ + m_proxy = 0; +} + + +/** + * @brief Test to see if this is a null link. + */ +inline +bool DataProxyHolder::isDefault() const +{ + return m_proxy == 0; +} + + +/** + * @brief Return the @c DataProxy for this link. + * @param nothrow If true, return 0 on failure instead of throwing + * an exception. + * + * If this is a null link, we return 0. + * Otherwise, if we're pointing at a @c DataProxy, return it. + * Otherwise, we're pointing at an object directly. Try to look up + * the corresponding @c DataProxy using the default store. Return it + * if we find it; otherwise, either throw @c ExcPointerNotInSG or + * return 0, depending on the @c nothrow parameter. + */ +inline +SG::DataProxy* DataProxyHolder::proxy (bool nothrow /*= false*/) const +{ + if (!isObjpointer()) + return m_proxy; + + // Do the rest out-of-line. + return proxy1(nothrow); +} + + +/** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * This version is for the case where indices are not given by @c size_t. + * No remapping will be performed for this case; this function will + * always return false. + */ +template <class T> +bool DataProxyHolder::toPersistent (sgkey_t& sgkey, const T& /*index*/) +{ + toPersistentNoRemap (sgkey); + return false; +} + + +/** + * @brief Test to see if we're pointing directly at an object. + * @returns True if we're pointing directly at an object, false + * if we're pointing at a @c DataProxy (or the link is null). + */ +inline +bool DataProxyHolder::isObjpointer() const +{ + return (reinterpret_cast<unsigned long> (m_proxy) & 1) != 0; +} + + +/** + * @brief Return a pointer to the object we're pointing at directly. + * + * Should be used only if @c isObjpointer() is true. + */ +inline +DataProxyHolder::pointer_t DataProxyHolder::objpointer() const +{ + return reinterpret_cast<pointer_t> + (reinterpret_cast<unsigned long> (m_proxy) & ~1UL); +} + + +/** + * @brief Store a direct pointer to an object. + * @param p Pointer to the object that we're referencing. + * + * This will overwrite @c m_proxy with the reference to the object. + */ +inline +void DataProxyHolder::storeObjpointer (const_pointer_t p) +{ + assert ((reinterpret_cast<unsigned long>(p) & 1) == 0); + m_proxy = reinterpret_cast<SG::DataProxy*> + (reinterpret_cast<unsigned long>(p) | 1); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/DefaultIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/tools/DefaultIndexingPolicy.h new file mode 100644 index 00000000..1ea295cb --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/DefaultIndexingPolicy.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + type generator that associates a container with an IndexingPolicy. + Used by ElementLink + Please define a (partial) specialization for your container: + the default value provided here generates a compiler error. + The specializations for the STL containers are available in StoreGate/tools + ---------------------------------------------------------------- + ATLAS Collaboration + ***************************************************************************/ + +// $Id: DefaultIndexingPolicy.h,v 1.1 2003-04-07 23:58:32 calaf Exp $ + +#ifndef ATHLINKS_TOOLS_DEFAULTINDEXINGPOLICY_H +# define ATHLINKS_TOOLS_DEFAULTINDEXINGPOLICY_H + + +template <class Foo> class ERROR_PLEASE_ADD_ONE_OF_THE_PREDEFINED_POLICY_INCLUDE_FILES_OR_DEFINE_A_DEFAULT_INDEXING_POLICY_FOR_THIS_TYPE; +template <typename STORABLE> +struct DefaultIndexingPolicy { + typedef ERROR_PLEASE_ADD_ONE_OF_THE_PREDEFINED_POLICY_INCLUDE_FILES_OR_DEFINE_A_DEFAULT_INDEXING_POLICY_FOR_THIS_TYPE<STORABLE> type; +}; + +#endif // ATHLINKS_TOOLS_DEFAULTINDEXINGPOLICY_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/ElementLinkTraits.h b/EDM/athena/Control/AthLinks/AthLinks/tools/ElementLinkTraits.h new file mode 100644 index 00000000..b2d3a761 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/ElementLinkTraits.h @@ -0,0 +1,238 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/ElementLinkTraits.h + * @author scott snyder <snyder@bnl.gov> + * @date Dec, 2013 + * @brief Determine dependent types for @c ElementLink classes. + * + * An @c ElementLink class needs to store the index of the referenced + * element; it also caches a copy of the element itself. In general, + * these can be arbitrary types, and so the data members for them + * must be in a templated class. + * + * However, by far the most common use of @c ElementLink is to refer + * to an element in a vector-like container of pointers. In that case, + * we can get away with storing the persistent data in a non-templated + * class, and in fact that makes direct ROOT I/O much easier. + * + * So, what we do is factor out all the state of @c ElementLink into a base + * class. For the generic case, we use the templated @c GenericElementLinkBase + * class. However, for the case of a vector of pointers, we use instead + * the non-templated class @c ElementLinkBase. The choice of which + * base class to use is made by the traits class defined here, + * @c ElementLinkTraits. + * + * An @c ElementLink must also be associated with an indexing policy class. + * The traits class also provides the appropriate indexing policy; + * in general, this is generated by @c GenerateIndexingPolicy, + * but for the specialized case, we always use @c ForwardIndexingPolicy. + * + * See below for the interfaces that must be supplied by the @c ElementLink + * base classes and by the indexing policy. + */ + + +#ifndef ATHLINKS_ELEMENTLINKTRAITS_H +#define ATHLINKS_ELEMENTLINKTRAITS_H + + +#include "AthLinks/ElementLinkBase.h" +#include "AthLinks/tools/IsSTLSequence.h" +#include "AthLinks/tools/ForwardIndexingPolicy.h" +#include "AthLinks/tools/GenerateIndexingPolicy.h" +#include "AthLinks/GenericElementLinkBase.h" +#if __cplusplus > 201100 +# include <type_traits> +namespace SG_STD_OR_BOOST = std; +#else +# include "boost/type_traits/is_pointer.hpp" +namespace SG_STD_OR_BOOST = boost; +#endif + + +namespace SG { + + +// This is the interface that must be supplied by the ElementLink base class. +// typedef index_type --- The type of the index supplied to and returned +// from ElementLink. +// typedef sgkey_t --- Type of hashed keys. +// typedef ID_type --- Type of string keys. +// typedef casefn_t --- Function casting from DataProxy to pointer. +// +// Should have a valid copy constructor and assignment operator. +// +// bool isDefaultIndex() const +// Test the index validity. +// bool hasCachedElement() const +// Test to see if this link has a cached element pointer. +// bool isDefault() const +// Test to see if this link is in the default state. +// index_type index() const +// Return the index of the link. +// ID_type dataID() const +// Return the SG key that we reference, as a string. +// sgkey_t key() const +// Return the SG key that we reference, as a hash. +// IProxyDict* source() const +// Return the data source for the reference. +// void reset() +// Reset the link to a null state. +// bool toTransient (IProxyDict*) +// Finish initialization after link has been read. +// bool doPersistent() +// Prepare this link for writing. +// +// protected: +// Base() +// Makes a null link. +// Base(const ID_type&, CLID, index_type, IProxyDict*) +// Make link from string key and index. +// Base(sgkey_t, CLID, index_type, IProxyDict*) +// Make link from hashed key and index. +// Base(const ID_type&, CLID, index_type, const void*, IProxyDict*) +// Make link from string key, index, and element pointer. +// Base(sgkey_t, CLID, index_type, const void*, IProxyDict*) +// Make link from hashed key, index, and element pointer. +// Base(const_pointer_t, CLID, index_type, IProxyDict*) +// Make link from an index and a pointer to the container. +// Base(const ElementLink<OTHER>&, FROM_TRAITS*, TO_TRAITS*) +// Derived->base link conversion. +// SG::DataProxy* proxy() const +// Return the SG proxy for the container holding the element. +// void* storableBase(castfn_t*, CLID) +// Return a pointer to the currently-referenced container object. +// bool setStorableObject (const_pointer_t, CLID, bool, IProxyDict*) +// Set the container referenced by the link to a pointer. +// bool toIndexedElement (const_pointer_t, CLID, index_type,IProxyDict*) +// Set the to an element given by index and pointer to container. +// resetWithKeyAndIndex (const ID_type&, CLID, index_type, IProxyDict*) +// Set the link to an element given by string key and index. +// resetWithKeyAndIndex (sgkey_t, CLID, index_type, IProxyDict*) +// Set the link to an element given by string key and index. +// void setIndex(index_type) +// Set the index part of the link. +// const stored_index_type& storedIndex() const +// Return the stored representation of the link index. +// void setCachedElement(element_t) +// Set the cached element stored in the link. +// bool getCachedElement (const T* &) const +// Retrieve the cached element from the link. +// const SG::DataProxyHolder& proxyHolder() const +// Return a reference to the internal proxy holder object. + + + +// This is the interface that must be supplied by an indexing policy. +// All methods are static; instances of this class are never +// actually created. +// typedef ElementType --- The type returned when the link is dereferenced. +// typedef ElementConstReference --- Derived from ElementType. +// typedef ElementConstPointer --- Derived from ElementType. +// typedef index_type --- The type of the index supplied to and returned +// from ElementLink. +// typedef stored_index_type --- The type of the index actually stored +// within the ElementLink. Should +// be implicitly convertable to index_type +// (if not identical). +// static bool isValid (stored_index_type index); +// Test to see if an index has been set. +// static index_type storedToExternal (stored_index_type index) +// Convert from stored to external index. +// static void reset (stored_index_type& index); +// Reset an index to an invalid state. +// static ElementType lookup (index_type index, const CONT& data); +// Return the element identified by INDEX in DATA. +// May throw an exception if the index is not valid. +// static void reverseLookup(const CONT& data, +// ElementConstReference element, +// index_type& index); +// Find the (first) index for ELEMENT in DATA. +// Throw SG::ExcElementNotFound if the element is not in the container. +// + + + +/** + * @brief ElementLink classes for the generic case. + */ +template <class STORABLE, + class VALUE_TYPE = typename STORABLE::value_type, + bool IS_SEQUENCE = IsSTLSequence<STORABLE>::value> +class ElementLinkTraits1 +{ +public: + typedef STORABLE Storable; + typedef typename SG::GenerateIndexingPolicy<STORABLE>::type IndexingPolicy; + typedef typename SG::GenericElementLinkBase<IndexingPolicy> Base; +}; + + +/** + * @brief ElementLink classes for the case of a vector-like container + * of pointers. + */ +template <class STORABLE, class BASE_VALUE_TYPE> +class ElementLinkTraits1<STORABLE, BASE_VALUE_TYPE*, true> +{ +public: + typedef STORABLE Storable; + typedef ElementLinkBase Base; + typedef ForwardIndexingPolicy<STORABLE> IndexingPolicy; +}; + + + +/** + * @brief ElementLinkTraits class to specialize. + * + * This is split out from @c ElementLinkTraits1 to allow specializing + * this class on a container class with an incomplete definition. + */ +template <class STORABLE> +class ElementLinkTraits + : public ElementLinkTraits1<STORABLE> +{ +public: + typedef STORABLE Storable; + typedef typename ElementLinkTraits1<STORABLE>::Base Base; + typedef typename ElementLinkTraits1<STORABLE>::IndexingPolicy IndexingPolicy; +}; + + +} // namespace SG + + + +/** + * @brief Forward declaration helper for ElementLink. + * + * This macro helps in declaring an ElementLink to a container with + * an incomplete definition (that has been forward declared). + * Restriction: The container _must_ be a vector-like container of pointers. + * Must not be used inside a namespace. + * + * See comments in ElementLink.h for a usage example. + */ +#define ELEMENTLINK_FWD(TYPE, VALUE_TYPE) \ +namespace SG { \ +template<> \ +class ElementLinkTraits<TYPE> \ +{ \ +public: \ + typedef TYPE Storable; \ + typedef ElementLinkBase Base; \ + typedef ForwardIndexingPolicy<TYPE, VALUE_TYPE*> IndexingPolicy; \ +}; \ +} \ +class elementlink_fwd_dummy + + + +#endif // not ATHLINKS_ELEMENTLINKTRAITS_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.h new file mode 100644 index 00000000..03fd9f49 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.h @@ -0,0 +1,116 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/ForwardIndexingPolicy.h + * @author scott snyder <snyder@bnl.gov> + * @date Dec, 2013 + * @brief Indexing policy for a vector-like container. + */ + + +#ifndef ATHLINKS_FORWARDINDEXINGPOLICY_H +#define ATHLINKS_FORWARDINDEXINGPOLICY_H + + +#include "AthLinks/exceptions.h" +#include "AthLinks/tools/findInContainer.h" +#include "AthenaKernel/tools/type_tools.h" +#include <boost/concept_check.hpp> +#include <cstddef> +#include <stdint.h> + + +namespace SG { + + +/** + * @brief Indexing policy for a vector-like container. + * + * See ElementLinkTraits.h for a summary of the requirements for an indexing + * policy. + * + * Indexes here are size_type, with -1 used to mark an invalid index. + */ +template <class CONT, class VALUE_TYPE=typename CONT::value_type> +class ForwardIndexingPolicy +{ +private: + typedef VALUE_TYPE value_type; + + +public: + /// The type we get when we dereference a link, and derived types. + typedef typename type_tools::Copy<value_type>::type ElementType; + typedef typename type_tools::Copy<value_type>::const_reference ElementConstReference; + typedef typename type_tools::Copy<value_type>::const_pointer ElementConstPointer; + + /// The type of an index, as provided to or returned from a link. + typedef size_t index_type; + + /// The type of an index, as stored internally within a link. + typedef uint32_t stored_index_type; + + +private: + /// Value to mark an invalid index. + static const index_type INVALID = static_cast<index_type> (-1); + + +public: + /** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ + static bool isValid (stored_index_type index); + + + /** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ + static index_type storedToExternal (stored_index_type index); + + + /** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ + static void reset (stored_index_type& index); + + + /** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcBadForwardLink if the index is invalid. + */ + static ElementType lookup (index_type index, const CONT& data); + + + /** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ + static void reverseLookup(const CONT& data, + ElementConstReference element, + index_type& index); +}; + + +} // namespace SG + + +#include "AthLinks/tools/ForwardIndexingPolicy.icc" + + +#endif // not ATHLINKS_FORWARDINDEXINGPOLICY_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.icc b/EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.icc new file mode 100644 index 00000000..701c679e --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/ForwardIndexingPolicy.icc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/ForwardIndexingPolicy.icc + * @author scott snyder <snyder@bnl.gov> + * @date Dec, 2013 + * @brief Indexing policy for a vector-like container. + */ + + +namespace SG { + + +/** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ +template <class CONT, class VALUE_TYPE> +inline +bool ForwardIndexingPolicy<CONT, VALUE_TYPE>::isValid (stored_index_type index) +{ + return index != static_cast<stored_index_type>(INVALID); +} + + +/** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ +template <class CONT, class VALUE_TYPE> +inline +typename ForwardIndexingPolicy<CONT, VALUE_TYPE>::index_type +ForwardIndexingPolicy<CONT, VALUE_TYPE>::storedToExternal (stored_index_type index) +{ + if (index == static_cast<stored_index_type>(INVALID)) + return INVALID; + return index; +} + + +/** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ +template <class CONT, class VALUE_TYPE> +inline +void ForwardIndexingPolicy<CONT, VALUE_TYPE>::reset (stored_index_type& index) +{ + index = static_cast<stored_index_type>(INVALID); +} + + +/** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcBadForwardLink if the index is invalid. + */ +template <class CONT, class VALUE_TYPE> +inline +typename ForwardIndexingPolicy<CONT, VALUE_TYPE>::ElementType +ForwardIndexingPolicy<CONT, VALUE_TYPE>::lookup (index_type index, const CONT& data) +{ + if (!isValid(index) || (data.size() <= index)) { + SG::throwExcBadForwardLink (index, data.size()); + } + + typedef typename CONT::const_iterator const_iterator; + const_iterator iter = data.begin(); + std::advance(iter, index); + return *iter; +} + + +/** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ +template <class CONT, class VALUE_TYPE> +void ForwardIndexingPolicy<CONT, VALUE_TYPE>::reverseLookup(const CONT& data, + ElementConstReference element, + index_type& index) +{ + //compiler checks we can compare elements + ::boost::function_requires<typename ::boost::EqualityComparableConcept<ElementType> >(); + + // Note that reverse lookup redoes the lookup even if m_isValid is true. + // Must ensure that we get correct index before persistency + index = INVALID; + typename CONT::size_type cindex; + if (!SG::findInContainer (data, element, cindex)) + throwExcElementNotFound ("reverseLookup"); + index = cindex; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/GenerateIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/tools/GenerateIndexingPolicy.h new file mode 100644 index 00000000..b5b80940 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/GenerateIndexingPolicy.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + type generator that associates a known container with an IndexingPolicy. + Used by ElementLink + ---------------------------------------------------------------- + ATLAS Collaboration + ***************************************************************************/ + +// $Id: GenerateIndexingPolicy.h,v 1.3 2007-03-03 17:56:15 schaffer Exp $ + +#ifndef ATHLINKS_TOOLS_GENERATEINDEXINGPOLICY_H +# define ATHLINKS_TOOLS_GENERATEINDEXINGPOLICY_H + +#include "AthLinks/tools/ForwardIndexingPolicy.h" +#include "AthLinks/tools/DefaultIndexingPolicy.h" +#include "AthLinks/tools/IdentContIndexingPolicy.h" +#include "AthLinks/tools/IsSTLSequence.h" + + +namespace SG { + template <class CONTAINER> + struct GenerateIndexingPolicy { + private: + + typedef IsSTLSequence<CONTAINER> _isSTLSequence; + + BOOST_STATIC_CONSTANT(bool, isSTLSequence = _isSTLSequence::value); + + public: + typedef typename boost::detail::if_true<(isSTLSequence)>::template + then< + ForwardIndexingPolicy<CONTAINER>, + //else + typename DefaultIndexingPolicy<CONTAINER>::type + >::type type; + }; +} + +#endif // ATHLINKS_TOOLS_GENERATEINDEXINGPOLICIES_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndex.h b/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndex.h new file mode 100644 index 00000000..79218014 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndex.h @@ -0,0 +1,138 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHLINKS_TOOLS_IDENTCONTINDEX_H +# define ATHLINKS_TOOLS_IDENTCONTINDEX_H + +/** @class IdentContIndex + * @brief Identifiable container index to a contained object + * + * IdentContIndex is a helper class used in conjunction with + * IdentContIndexingPolicy to create a compound index to an object in + * an identifiable container. The index is composed of the hash id of + * the collection and the index of a object in the collection. An + * IdentContIndex provides an unsigned int compound, composed of two + * 16 bit hash id and collection index. + * + * @author RD Schaffer + * $Id: IdentContIndex.h,v 1.2 2007-06-14 22:41:47 ssnyder Exp $ + **/ + +class IdentContIndex +{ +public: + /// Constructors + //@{ + IdentContIndex(); + IdentContIndex(unsigned short collHash, unsigned short objIndex); + IdentContIndex(unsigned int hashAndIndex); + //@} + /// Accessor to hash, obj index and combined index + //@{ + /// collection hash id + unsigned short collHash() const; + /// object index in collection + unsigned short objIndex() const; + /// combined index + unsigned int hashAndIndex() const; + /// check that both fields are set + bool isValid() const; + //@} + + /// Setters of hash, obj index and combined index + //@{ + /// set collection hash id + void setHashAndIndex(unsigned int hashAndIndex); + /// set object index in collection + void setCollHash(unsigned short hash); + /// set combined index + void setObjIndex(unsigned short index); + //@} + +private: + unsigned short m_collHash; + unsigned short m_objIndex; +}; + + + +// inline definitions + +inline +IdentContIndex::IdentContIndex() + : + m_collHash(0xFFFF), + m_objIndex(0xFFFF) +{} + +inline +IdentContIndex::IdentContIndex(unsigned short collHash, unsigned short objIndex) + : + m_collHash(collHash), + m_objIndex(objIndex) +{} + +inline +IdentContIndex::IdentContIndex(unsigned int hashAndIndex) +{ + setHashAndIndex(hashAndIndex); +} + + +inline +unsigned short +IdentContIndex::collHash() const +{ + return (m_collHash); +} + +inline +unsigned short +IdentContIndex::objIndex() const +{ + return (m_objIndex); +} + +inline +unsigned int +IdentContIndex::hashAndIndex() const +{ + // Concatenate hash and index + unsigned int result = (m_collHash << 16) + m_objIndex; + return (result); +} + +inline +bool +IdentContIndex::isValid() const +{ + // is valid if both hash and index are not default values + return (m_collHash != 0xFFFF && m_objIndex != 0xFFFF); +} + + +inline +void +IdentContIndex::setHashAndIndex(unsigned int hashAndIndex) +{ + // Extract hash and index + m_collHash = static_cast<unsigned short> (hashAndIndex >> 16); + m_objIndex = static_cast<unsigned short> (hashAndIndex & 0xFFFF); +} + +inline +void +IdentContIndex::setCollHash(unsigned short hash) +{ + m_collHash = hash; +} + +inline +void +IdentContIndex::setObjIndex(unsigned short index) +{ + m_objIndex = index; +} + +#endif // not ATHLINKS_TOOLS_IDENTCONTINDEX_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.h new file mode 100644 index 00000000..9ad22d40 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.h @@ -0,0 +1,118 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/IdentContIndexingPolicy.h + * @author RD Schaffer + * @brief Indexing policy for an IdentifiableContainer. + */ + +#ifndef ATHLINKS_TOOLS_IDENTCONTINDEXINGPOLICY_H +#define ATHLINKS_TOOLS_IDENTCONTINDEXINGPOLICY_H + +#include "AthLinks/tools/IdentContIndex.h" +#include "AthLinks/exceptions.h" +#include "AthenaKernel/tools/type_tools.h" +#include "AthenaKernel/getMessageSvc.h" +#include "GaudiKernel/MsgStream.h" +#include <boost/concept_check.hpp> +#include <cassert> +#include <stdexcept> + + +namespace SG { + + +/** + * @brief Indexing policy for an IdentifiableContainer. + * + * See ElementLinkTraits.h for a summary of the requirements for an indexing + * policy. + * + * An identifiable container has a two-level index: the collection hash + * and the index within the collection. These are packed together + * in a 32-bit integer, which is what we expose as the index type. + * There's a value defined for an invalid index, so we don't need + * to use the @c IndexHolder wrapper. To unpack this index, use + * @c IdentContIndex. + */ +template <class CONT> +class IdentContIndexingPolicy +{ +private: + typedef typename CONT::IDENTIFIABLE coll_type; + typedef typename coll_type::value_type obj_type; + + +public: + /// The type we get when we dereference a link, and derived types. + typedef typename type_tools::Copy<obj_type>::type ElementType; + typedef typename type_tools::Copy<obj_type>::const_reference ElementConstReference; + typedef typename type_tools::Copy<obj_type>::const_pointer ElementConstPointer; + + /// The type of an index, as provided to or returned from a link. + typedef unsigned int index_type; + + /// The type of an index, as stored internally within a link. + typedef index_type stored_index_type; + + + /** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ + static bool isValid (stored_index_type index); + + + /** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ + static index_type storedToExternal (stored_index_type index); + + + /** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ + static void reset (stored_index_type& index); + + + /** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcInvalidIndex if the index is invalid and + * SG::ExcIndexNotFound if the index is not in the container. + */ + static + ElementType lookup (index_type index, const CONT& data); + + + /** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ + static void + reverseLookup(const CONT& data, + ElementConstReference element, + index_type& index); +}; + + +} // namespace SG + + +#include "AthLinks/tools/IdentContIndexingPolicy.icc" + + +#endif // ATHLINKS_TOOLS_IDENTCONTINDEXINGPOLICY_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.icc b/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.icc new file mode 100644 index 00000000..40fdcb9a --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/IdentContIndexingPolicy.icc @@ -0,0 +1,157 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/IdentContIndexingPolicy.icc + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Indexing policy for an IdentifiableContainer. + */ + + +#include <algorithm> + + +namespace SG { + + +/** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ +template <class CONT> +inline +bool IdentContIndexingPolicy<CONT>::isValid (stored_index_type index) +{ + return IdentContIndex(index).isValid(); +} + + +/** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ +template <class CONT> +inline +typename IdentContIndexingPolicy<CONT>::index_type +IdentContIndexingPolicy<CONT>::storedToExternal (stored_index_type index) +{ + return index; +} + + +/** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ +template <class CONT> +inline +void IdentContIndexingPolicy<CONT>::reset (stored_index_type& index) +{ + index = IdentContIndex().hashAndIndex(); +} + + +/** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcInvalidIndex if the index is invalid and + * SG::ExcIndexNotFound if the index is not in the container. + */ +template <class CONT> +typename IdentContIndexingPolicy<CONT>::ElementType +IdentContIndexingPolicy<CONT>::lookup (index_type index, const CONT& data) +{ + if (!isValid(index)) + SG::throwExcInvalidIndex ("IdentContIndexingPolicy"); + + // Find object with hash and index in collection + IdentContIndex compIndex(index); + typename CONT::const_iterator it = data.indexFind (compIndex.collHash()); + if (it != data.end()) { + // Found collection + // Check if objIndex was correctly set + if (compIndex.objIndex() < (*it)->size()) { + return ((**it)[compIndex.objIndex()]); + } + } + // No object found! + SG::throwExcIndexNotFound ("IdentContIndexingPolicy"); +} + + +/** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ +template <class CONT> +void +IdentContIndexingPolicy<CONT>::reverseLookup(const CONT& data, + ElementConstReference element, + index_type& index) +{ + //compiler checks we can compare elements + ::boost::function_requires<typename ::boost::EqualityComparableConcept<ElementType> >(); + + // The hash and possibly the object index may already have + // been set by the user. We verify that the index does + // correspond to the object, and otherwise we recalculate the + // index + IdentContIndex compIndex(index); + typename CONT::const_iterator it = data.indexFind (compIndex.collHash()); + if (it != data.end()) { + // Found collection + // Check if objIndex was correctly set + if (compIndex.objIndex() < (*it)->size()) { + if ((**it)[compIndex.objIndex()] == element) { + return; + } + } + // objIndex was not correctly set, look for object + for (unsigned int i = 0; i < (*it)->size(); ++i) { + if ((**it)[i] == element) { + // Save index in collection to object + compIndex.setObjIndex(i); + index = compIndex.hashAndIndex(); + return; + } + } + // Correct collection, but object not found + SG::throwExcElementNotFound ("IdentContIndexingPolicy: reverseLookup"); + return; // Not reached + } + + // Neither hash, nor object index set, must find both - THIS + // IS SLOW!! + for (typename CONT::const_iterator it = data.begin(); + it != data.end(); + ++it) { + const coll_type* coll = *it; + if (coll) { + typename coll_type::const_iterator objIt = + std::find (coll->begin(), coll->end(), + element); + if (objIt != coll->end()) { + // Save collection hash and index to object in collection + compIndex.setCollHash(coll->identifyHash()); + compIndex.setObjIndex(std::distance (coll->begin(), objIt)); + index = compIndex.hashAndIndex(); + return; + } + } + } + SG::throwExcElementNotFound ("IdentContIndexingPolicy: reverseLookup"); +} + + +} // namespace SG + + diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/IndexHolder.h b/EDM/athena/Control/AthLinks/AthLinks/tools/IndexHolder.h new file mode 100644 index 00000000..234490a7 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/IndexHolder.h @@ -0,0 +1,66 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/IndexHolder.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2014 + * @brief Store an @c ElementLink index for non-vector containers. + */ + + +#ifndef ATHLINKS_INDEXHOLDER_H +#define ATHLINKS_INDEXHOLDER_H + + +namespace SG { + + +/** + * @brief Store an @c ElementLink index for non-vector containers. + * + * When we store an index to a vector container, we use -1 as an invalid + * index value. However, in the general case where we have a container + * with an index of arbitrary type, we don't have a distinguished value + * we can use to represent invalid. So for that case, we need to store + * an additional valid flag along with the index. Things are factored + * like this so that we can avoid storing the flag for the common case + * of indexing a vector. + */ +template <class T> +class IndexHolder +{ +public: + /// Constructor. + IndexHolder() : m_valid(false) {} + + /// Copy constructor. + IndexHolder (const T& t) : m_index(t), m_valid(true) {} + + /// Return valid flag. + bool isValid() const { return m_valid; } + + /// Reset the index to a null value. + void reset() { m_valid = false; m_index = T(); } + + /// Retrieve the index. + operator const T&() const { return m_index; } + + +private: + /// The stored index. + T m_index; + + /// True if the index is valid. + bool m_valid; +}; + + +} // namespace SG + + +#endif // not ATHLINKS_INDEXHOLDER_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/IsSTLSequence.h b/EDM/athena/Control/AthLinks/AthLinks/tools/IsSTLSequence.h new file mode 100644 index 00000000..71acb438 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/IsSTLSequence.h @@ -0,0 +1,71 @@ +// Yo emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + determines whether CONTAINER is one of supported ATLAS sequences Requires + CONTAINER to define value_type + ---------------------------------------------------------------- + ATLAS Collaboration + ***************************************************************************/ + +// $Id: IsSTLSequence.h,v 1.5 2008-11-17 19:24:52 ssnyder Exp $ + +#ifndef ATHLINKS_TOOLS_ISSTLSEQUENCE_H +# define ATHLINKS_TOOLS_ISSTLSEQUENCE_H + +#include <vector> +#include <list> +#include <deque> +#include <type_traits> + + + +// CLASS DECLARATIONS +namespace SG { + // Some parts of Athena define FLAG as a macro. + template <class CONTAINER, class FLAG_> + struct TestSequenceTag + { + typedef std::false_type type; + }; + + template <class CONTAINER> + struct TestSequenceTag<CONTAINER, typename CONTAINER::isSequence> + { + typedef typename CONTAINER::isSequence type; + }; + + template <class CONTAINER> + struct IsSTLSequence { + private: + // Causes trouble with fwd decls? cf xAODTruth? + //BOOST_CONCEPT_ASSERT((boost::ContainerConcept<CONTAINER>)); + typedef typename CONTAINER::value_type value_type; + + // vectors + typedef typename std::is_base_of< std::vector<value_type>, CONTAINER> isVector; + + // lists + typedef typename std::is_base_of< std::list<value_type>, CONTAINER> isList; + + // queues + typedef typename std::is_base_of< std::deque<value_type>, CONTAINER> isDeque; + + // explicit tag, by adding + // typedef type_tools::true_tag isSequence; + // to a class. + typedef typename TestSequenceTag<CONTAINER, std::true_type>::type hasSequenceTag; + + public: + //putting it all together + static const bool value = + isDeque::value || + isList::value || + isVector::value || + hasSequenceTag::value; + }; +} +#endif // ATHLINKS_TOOLS_ISSTLSEQUENCE_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.h new file mode 100644 index 00000000..61790859 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.h @@ -0,0 +1,132 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/MapIndexingPolicy.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2014 + * @brief Indexing policy for a map-like container. + */ + + +#ifndef ATHLINKS_MAPINDEXINGPOLICY_H +#define ATHLINKS_MAPINDEXINGPOLICY_H + + + +#include "AthLinks/tools/DefaultIndexingPolicy.h" +#include "AthLinks/tools/RemoveDataPtr.h" +#include "AthLinks/tools/IndexHolder.h" +#include "AthLinks/exceptions.h" +#include "AthenaKernel/tools/type_tools.h" +#include "AthenaKernel/getMessageSvc.h" +#include "GaudiKernel/MsgStream.h" +#include <boost/concept_check.hpp> +#include <map> +#include <algorithm> +#include <cassert> + + +namespace SG { + + +/** + * @brief Indexing policy for a map-like container. + * + * See ElementLinkTraits.h for a summary of the requirements for an indexing + * policy. + * + * Indexes here are use IndexHolder, with the key of the container + * as the payload. The type returned from the link is the second type + * of the map. + */ +template <class MAP> +class MapIndexingPolicy +{ +private: + //compiler checks that MAP is an stl pair associative container + BOOST_CONCEPT_ASSERT((boost::PairAssociativeContainerConcept<MAP>)); + + typedef typename MAP::mapped_type mapped_type; + typedef typename MAP::const_iterator const_iterator; + + +public: + /// The type we get when we dereference a link, and derived types. + typedef typename type_tools::Copy<mapped_type>::type ElementType; + typedef typename type_tools::Copy<mapped_type>::const_reference ElementConstReference; + typedef typename type_tools::Copy<mapped_type>::const_pointer ElementConstPointer; + + /// The type of an index, as provided to or returned from a link. + typedef typename MAP::key_type index_type; + + /// The type of an index, as stored internally within a link. + typedef SG::IndexHolder<index_type> stored_index_type; + + + /** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ + static bool isValid (const stored_index_type& index) ; + + + /** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ + static index_type storedToExternal (stored_index_type index); + + + /** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ + static void reset (stored_index_type& index); + + + /** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcInvalidIndex if the index is invalid and + * SG::ExcIndexNotFound if the index is not in the container. + */ + static + ElementType lookup(const stored_index_type& index, const MAP& data); + + + /** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ + static void + reverseLookup(const MAP& data, + ElementConstReference element, + index_type& index); +}; + + +} // namespace SG + + +/// Set up to automatically use this indexing policy for maps. +template <typename KEY, typename ELEM> +struct DefaultIndexingPolicy<std::map<KEY, ELEM> > { + typedef SG::MapIndexingPolicy<std::map<KEY, ELEM> > type; +}; + + +#include "AthLinks/tools/MapIndexingPolicy.icc" + + +#endif // not ATHLINKS_MAPINDEXINGPOLICY_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.icc b/EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.icc new file mode 100644 index 00000000..f7b1b649 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/MapIndexingPolicy.icc @@ -0,0 +1,112 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/MapIndexingPolicy.icc + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Indexing policy for a set-like container. + */ + + +namespace SG { + + +/** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ +template <class MAP> +inline +bool MapIndexingPolicy<MAP>::isValid (const stored_index_type& index) +{ + return index.isValid(); +} + + +/** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ +template <class CONT> +inline +typename MapIndexingPolicy<CONT>::index_type +MapIndexingPolicy<CONT>::storedToExternal (stored_index_type index) +{ + return index; +} + + +/** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ +template <class MAP> +inline +void MapIndexingPolicy<MAP>::reset (stored_index_type& index) +{ + index.reset(); +} + + +/** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcInvalidIndex if the index is invalid and + * SG::ExcIndexNotFound if the index is not in the container. + */ +template <class MAP> +typename MapIndexingPolicy<MAP>::ElementType +MapIndexingPolicy<MAP>::lookup(const stored_index_type& index, + const MAP& data) +{ + if (!isValid(index)) + SG::throwExcInvalidIndex ("MapIndexingPolicy"); + const_iterator iter = data.find(index); + if (iter == data.end()) + SG::throwExcIndexNotFound ("MapIndexingPolicy"); + return iter->second; +} + + +/** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ +template <class MAP> +void +MapIndexingPolicy<MAP>::reverseLookup(const MAP& data, + ElementConstReference element, + index_type& index) +{ + //compiler checks we can compare elements + ::boost::function_requires<typename ::boost::EqualityComparableConcept<ElementType> >(); + + // Note that reverseLookup will recalculate index even if m_valid is true. + // Must ensure that index is write before persistency + const_iterator it = data.begin(); + const_iterator iend = data.end(); + while (it != iend) { + if (it->second == element) break; + ++it; + } + + if (it != iend) + { + index = it->first ; + } + else { + SG::throwExcElementNotFound ("reverseLookup"); + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/RemoveDataPtr.h b/EDM/athena/Control/AthLinks/AthLinks/tools/RemoveDataPtr.h new file mode 100644 index 00000000..142f82e3 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/RemoveDataPtr.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHLINKS_TOOLS_REMOVEDATAPTR_H +# define ATHLINKS_TOOLS_REMOVEDATAPTR_H +/*************************************************************************** + helper struct to treat pointers and DataPtr uniformly + ----------------------------------------------------- + ATLAS Collaboration + ***************************************************************************/ + +// $Id: RemoveDataPtr.h,v 1.1 2003-04-07 23:58:32 calaf Exp $ + +//<<<<<< INCLUDES >>>>>> + +#include "AthLinks/DataPtr.h" + +//namespace type_tools { + template <typename T> + struct RemoveDataPtr { + typedef T type; + }; + template <typename T> + struct RemoveDataPtr<DataPtr<T> > { + typedef typename DataPtr<T>::DataPtr_type* type; + }; +//} + +#endif // ATHLINKS_TOOLS_REMOVEDATAPTR_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.h b/EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.h new file mode 100644 index 00000000..116fe6ea --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHLINKS_TOOLS_SGELVREF_H +#define ATHLINKS_TOOLS_SGELVREF_H + +#include "AthLinks/DataLink.h" +#include "AthLinks/ElementLink.h" +#include <algorithm> +#include <exception> +#include <functional> +#include <vector> +#include <boost/iterator_adaptors.hpp> + + + +template <typename DOBJ> +class ElementLinkVector; + + /** @class SG::ELVRef + * @brief a short ref to an ElementLink into an ElementLinkVector. + * Used to be an internal class of ElementLinkVector. + * Had to pull out because of brain-damaged pool converters + */ + +namespace SG { + template <typename DOBJ> + class ELVRef + { + public: + typedef typename std::vector< DataLink<DOBJ> > DataLinkVector; + typedef ElementLinkVector<DOBJ> ElemLinkVec; + typedef ElementLink<DOBJ> ElemLink; + typedef typename ElemLink::IndexingPolicy IndexingPolicy; + typedef typename ElemLink::ElementConstPointer ElementConstPointer; + typedef typename ElemLink::index_type index_type; + typedef typename ElemLink::stored_index_type stored_index_type; + typedef typename ElemLink::ID_type ID_type; + + ///STL required + ELVRef(const ELVRef& rhs); + ///STL required + ELVRef& operator=(const ELVRef& rhs); + ///standard constructor + ELVRef(const ElemLink& link=ElemLink()); + /// Constructor from indices. + ELVRef(typename DataLinkVector::size_type hostIndex, + index_type elementIndex, + const ElemLinkVec& owner); + ///dataID of the host + ID_type dataID() const; + /// index into container (non-const, calculates and sets on demand): + index_type elementIndex() const; + ///element pointer in ElementLink + ElementConstPointer cptr() const { return m_link.cptr(); } + + /// get the corresponding ElementLink. O(1) + const ElemLink& elementLink() const { return m_link; } + + /// \name comparison ops (STL required) + //@{ + bool operator == (const ELVRef& rhs) const { + return ( (index() == rhs.index()) && (dataID() == rhs.dataID()) ); + } + bool operator < (const ELVRef& rhs) const { + return ( (index() < rhs.index()) || + ( (index() == rhs.index()) && (dataID() < rhs.dataID()) ) ); + } + //@} + + /// called by handlers to change state: + bool toPersistent(const ElemLinkVec& owner); + bool toPersistent(const ElemLinkVec& owner, + typename DataLinkVector::size_type& shortref); + bool toTransient(const ElemLinkVec& owner); + bool doRemap(); + + const stored_index_type& index() const + { + return m_index; + } + + private: + + //Transient members only. + ElemLink m_link; ///! the element pointer + + // Persistent members: + typename DataLinkVector::size_type m_shortRef; ///! index of the host dobj + + stored_index_type m_index; + }; +} +#endif // not ATHLINKS_TOOLS_SGELVREF_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.icc b/EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.icc new file mode 100644 index 00000000..872483d6 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/SGELVRef.icc @@ -0,0 +1,207 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <cassert> + +#include "AthenaKernel/getMessageSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "AthenaKernel/IThinningSvc.h" + +/* #define __ELVDEBUG */ + +// Standard Constructor +template <typename DOBJ> +SG::ELVRef<DOBJ>::ELVRef ( const ElemLink& link ) : + m_link( link ), m_shortRef( 0 ), m_index(link.index()) +{ +} + +// copy constructor +template <typename DOBJ> +SG::ELVRef<DOBJ>::ELVRef(const ELVRef& rhs) : + m_link(rhs.m_link), + m_shortRef(rhs.m_shortRef), + m_index (rhs.m_index) +{ } + +// constructor from indices. +template <typename DOBJ> +SG::ELVRef<DOBJ>::ELVRef + (typename DataLinkVector::size_type hostIndex, + index_type elementIndex, + const ElemLinkVec& owner) + : m_shortRef (hostIndex), + m_index(elementIndex) +{ + toTransient (owner); +} + +// return the index +template <typename DOBJ> +typename SG::ELVRef<DOBJ>::index_type +SG::ELVRef<DOBJ>::elementIndex() const +{ + return m_link.index(); +} + +// return the key +template <typename DOBJ> +typename SG::ELVRef<DOBJ>::ID_type +SG::ELVRef<DOBJ>::dataID() const { + return m_link.dataID(); +} + +// Move to persistent state +template <typename DOBJ> +bool +SG::ELVRef<DOBJ>::toPersistent + (const ElemLinkVec& owner) +{ + // Handle null reference. + if (m_link.isDefault()) + return true; + + // Do the contained EL. + if (!m_link.toPersistent()) + return false; + + // Transfer the index. + index_type index; + try { + index = this->m_link.index(); + } + catch (const SG::ExcElementNotFound&) + { + index = IThinningSvc::generateRemovedIdx<index_type>(); + } + m_index = index; + + // Calculate the distance in DataLinkVector + typename DataLinkVector::const_iterator iHost(owner.findHostDObj(m_link)); + + if ( iHost != owner.endHostDObjs() ) { + m_shortRef = std::distance(owner.beginHostDObjs(), iHost); + } + else { + MsgStream log(Athena::getMessageSvc(), "SG::ELVRef"); + log << MSG::WARNING + << "link not found in ElemLinkVector" << endmsg; + return false; + } + + return true; +} + +// Move to persistent state and return shortref. +template <typename DOBJ> +inline +bool +SG::ELVRef<DOBJ>::toPersistent + (const ElemLinkVec& owner, + typename DataLinkVector::size_type& shortref) +{ + bool ret = toPersistent (owner); + shortref = m_shortRef; + return ret; +} + + +// Move to transient state +template <typename DOBJ> +bool +SG::ELVRef<DOBJ>::toTransient + (const ElemLinkVec& owner) +{ + bool success = true; + + // handle thinned-away/null elements + if ( IThinningSvc::isThinned (m_shortRef) || + !IndexingPolicy::isValid(m_index)) + { + m_link = ElemLink(); + return success; + } + + // locate DataLink + typename DataLinkVector::const_iterator iHost(owner.beginHostDObjs()); + + if (m_shortRef >= (unsigned)(owner.endHostDObjs() - iHost)) { + MsgStream log(Athena::getMessageSvc(), "ElementLinkVector"); + log << MSG::ERROR + << "ELVRef::toTransient: shortref index of " << m_shortRef + << " is beyond the end of the host container (size " + << owner.endHostDObjs() - iHost << ")" << endmsg; + m_link = ElemLink(); + return false; + } + + std::advance(iHost, m_shortRef); + assert(iHost != owner.endHostDObjs()); + + // create a new ElementLink + m_link = ElemLink(iHost->key(), this->index()); + + return success; +} + +template <typename DOBJ> +bool +SG::ELVRef<DOBJ>::doRemap() +{ + SG::sgkey_t new_key; + index_type new_index; + if (this->m_link.isDefault()) + return false; + index_type index; + try { + index = this->m_link.index(); + } + catch (const SG::ExcElementNotFound&) + { + index = IThinningSvc::generateRemovedIdx<index_type>(); + } + + if (SG_detail::checkForRemap (this->m_link.source(), + this->m_link.key(), + index, + new_key, + new_index)) + { + this->m_link.resetWithKeyAndIndex (new_key, new_index); + return true; + } + return false; +} + + +// operator = +template <typename DOBJ> +SG::ELVRef<DOBJ>& +SG::ELVRef<DOBJ>::operator=(const ELVRef& rhs) { +#ifdef __ELVDEBUG + MsgStream log(Athena::getMessageSvc(), "SG::ELVRef"); + log << MSG::DEBUG + << "operator= called on " << dataID() << '/' << index() + << " with rhs " << rhs.dataID() << '/' << rhs.index() + << std::endl; +#endif + + if (&rhs != this) { + m_index = rhs.m_index; + m_link = rhs.m_link; + m_shortRef = rhs.m_shortRef; + } +#ifdef __ELVDEBUG + MsgStream log(Athena::getMessageSvc(), "SG::ELVRef"); + log << MSG::DEBUG + << "operator= result is " << dataID() << '/' << index() + << std::endl; +#endif + + return *this; +} + diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.h b/EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.h new file mode 100644 index 00000000..c13856fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.h @@ -0,0 +1,130 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/SetIndexingPolicy.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2014 + * @brief Indexing policy for a set-like container. + */ + + +#ifndef ATHLINKS_SETINDEXINGPOLICY_H +#define ATHLINKS_SETINDEXINGPOLICY_H + + + +#include "AthLinks/tools/DefaultIndexingPolicy.h" +#include "AthLinks/tools/RemoveDataPtr.h" +#include "AthLinks/tools/IndexHolder.h" +#include "AthLinks/exceptions.h" +#include "AthenaKernel/tools/type_tools.h" +#include "AthenaKernel/getMessageSvc.h" +#include "GaudiKernel/MsgStream.h" +#include <boost/concept_check.hpp> +#include <set> +#include <algorithm> +#include <cassert> + + +namespace SG { + + +/** + * @brief Indexing policy for a set-like container. + * + * See ElementLinkTraits.h for a summary of the requirements for an indexing + * policy. + * + * Indexes here are use IndexHolder, with the key of the container + * as the payload. + */ +template <class SET> +class SetIndexingPolicy +{ +private: + //compiler checks that SET is an stl simple associative container + BOOST_CONCEPT_ASSERT((boost::SimpleAssociativeContainerConcept<SET>)); + + typedef typename SET::reference reference; + typedef typename SET::iterator iterator; + +public: + /// The type we get when we dereference a link, and derived types. + typedef typename SET::value_type ElementType; + typedef typename SET::const_reference ElementConstReference; + typedef typename SET::const_pointer ElementConstPointer; + + /// The type of an index, as provided to or returned from a link. + typedef typename SET::key_type index_type; + + /// The type of an index, as stored internally within a link. + typedef SG::IndexHolder<index_type> stored_index_type; + + + /** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ + static bool isValid (const stored_index_type& index); + + + /** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ + static index_type storedToExternal (stored_index_type index); + + + /** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ + static void reset (stored_index_type& index); + + + /** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcInvalidIndex if the index is invalid and + * SG::ExcIndexNotFound if the index is not in the container. + */ + static + ElementType lookup(const stored_index_type& index, const SET& data); + + + /** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ + static void + reverseLookup (const SET& data, + ElementConstReference element, + index_type& same); +}; + +} // namespace SG + + + +/// Set up to automatically use this indexing policy for sets. +template <typename KEY> +struct DefaultIndexingPolicy <std::set<KEY> > { + typedef SG::SetIndexingPolicy<std::set<KEY> > type; +}; + + +#include "AthLinks/tools/SetIndexingPolicy.icc" + + +#endif // not ATHLINKS_SETINDEXINGPOLICY_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.icc b/EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.icc new file mode 100644 index 00000000..3325e2eb --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/SetIndexingPolicy.icc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/tools/SetIndexingPolicy.icc + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Indexing policy for a set-like container. + */ + + +namespace SG { + + +/** + * @brief Test to see if an index is valid. + * @param index The index to test. + */ +template <class SET> +inline +bool SetIndexingPolicy<SET>::isValid (const stored_index_type& index) +{ + return index.isValid(); +} + + +/** + * @brief Convert from stored to external index types. + * @param index The stored index. + */ +template <class CONT> +inline +typename SetIndexingPolicy<CONT>::index_type +SetIndexingPolicy<CONT>::storedToExternal (stored_index_type index) +{ + return index; +} + + +/** + * @brief Make an index invalid. + * @param index[out] The index to reset. + */ +template <class SET> +inline +void SetIndexingPolicy<SET>::reset (stored_index_type& index) +{ + index.reset(); +} + + +/** + * @brief Retrieve from a container the element corresponding to an index. + * @param index The index to fetch. + * @param data The container. + * + * Will throw SG::ExcInvalidIndex if the index is invalid and + * SG::ExcIndexNotFound if the index is not in the container. + */ +template <class SET> +typename SetIndexingPolicy<SET>::ElementType +SetIndexingPolicy<SET>::lookup(const stored_index_type& index, + const SET& data) +{ + if (!isValid(index)) + SG::throwExcInvalidIndex ("SetIndexingPolicy"); + iterator iter = data.find(index); + if (iter == data.end()) + SG::throwExcIndexNotFound ("SetIndexingPolicy"); + return *iter; +} + + +/** + * @brief Find the index of the (first) instance of ELEMENT in DATA. + * @param data The container to search. + * @param element The element to find. + * @param index[out] The index in the container of @c element. + * + * Throws SG::ExcElementNotFound if the element is not in the container. + */ +template <class SET> +void +SetIndexingPolicy<SET>::reverseLookup(const SET& data, + ElementConstReference element, + index_type& same) +{ + //compiler checks we can compare elements + ::boost::function_requires<typename ::boost::EqualityComparableConcept<ElementType> >(); + + // Note that reverseLookup will recalculate index even if m_valid is true. + // Must ensure that index is write before persistency + if (data.end() != data.find(element)) + { + same = element ; + } + else { + SG::throwExcElementNotFound ("reverseLookup"); + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/findInContainer.h b/EDM/athena/Control/AthLinks/AthLinks/tools/findInContainer.h new file mode 100644 index 00000000..fc622a84 --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/findInContainer.h @@ -0,0 +1,55 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: findInContainer.h,v 1.3 2007-06-14 22:38:50 ssnyder Exp $ +/** + * @file AthLinks/tools/findInContainer.h + * @author scott snyder + * @date Feb, 2007 + * @brief Define a specializable method for finding the index of an object + * within a container. + */ + +#ifndef ATHLINKS_FINDINCONTAINER_H +#define ATHLINKS_FINDINCONTAINER_H + + +namespace SG { + + +/** + * @brief Find the index of an object within a container. + * @param data The container to search. + * @param element The element for which to search. + * @param[out] index The found index of the element. + * @return true if the element was found; false otherwise. + * + * By default, this function will do an exhaustive search through + * the container to find the element. However, this function may + * be specialized if this can be done more efficiently for some + * specific container. + */ +template <typename CONT, typename ELT> +bool +findInContainer(const CONT& data, + const ELT& element, + typename CONT::size_type& index) +{ + typedef typename CONT::const_iterator const_iterator; + const_iterator end = data.end(); + index = 0; + for (const_iterator it = data.begin(); it != end; ++it) { + if (*it == element) return true; + ++index; + } + return false; +} + + +} // namespace SG + + +#endif // ATHLINKS_FINDINCONTAINER_H diff --git a/EDM/athena/Control/AthLinks/AthLinks/tools/selection_ns.h b/EDM/athena/Control/AthLinks/AthLinks/tools/selection_ns.h new file mode 100644 index 00000000..5f920b1e --- /dev/null +++ b/EDM/athena/Control/AthLinks/AthLinks/tools/selection_ns.h @@ -0,0 +1,66 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: selection_ns.h 599955 2014-06-02 16:12:57Z ssnyder $ +/** + * @file AthLinks/tools/selection_ns.h + * @author scott snyder + * @date Nov 2008 + * @brief Root changed the name of the selection namespace in 5.19. + * Define macros to work around. + */ + +#ifndef ATHLINKS_TOOLS_SELECTION_NS +#define ATHLINKS_TOOLS_SELECTION_NS + +#include "RVersion.h" + +#if ROOT_VERSION_CODE < ROOT_VERSION(5,99,0) + +#include <Reflex/Builder/DictSelection.h> + +#ifndef ROOT_SELECTION_NS +# define ROOT_SELECTION_NS Reflex::Selection +#endif + +#ifndef ENTER_ROOT_SELECTION_NS +# define ENTER_ROOT_SELECTION_NS namespace Reflex { namespace Selection { +#endif + +#ifndef EXIT_ROOT_SELECTION_NS +# define EXIT_ROOT_SELECTION_NS }} +#endif + +#else + +#include <RootMetaSelection.h> + +#ifndef ROOT_SELECTION_NS +# define ROOT_SELECTION_NS ROOT::Meta::Selection +#endif + +#ifndef ENTER_ROOT_SELECTION_NS +# define ENTER_ROOT_SELECTION_NS namespace ROOT { namespace Meta { namespace Selection { +#endif + +#ifndef EXIT_ROOT_SELECTION_NS +# define EXIT_ROOT_SELECTION_NS }}} +#endif + +ENTER_ROOT_SELECTION_NS +typedef MemberAttributes< kTransient > TRANSIENT; +typedef MemberAttributes< kNoAutoSelected > NO_SELF_AUTOSELECT; +EXIT_ROOT_SELECTION_NS + +#endif // ROOT version check + +#endif // not ATHLINKS_TOOLS_SELECTION_NS + + + + + + diff --git a/EDM/athena/Control/AthLinks/CMakeLists.txt b/EDM/athena/Control/AthLinks/CMakeLists.txt new file mode 100644 index 00000000..f2324e20 --- /dev/null +++ b/EDM/athena/Control/AthLinks/CMakeLists.txt @@ -0,0 +1,138 @@ +################################################################################ +# Package: AthLinks +################################################################################ + +# Declare the package name: +atlas_subdir( AthLinks ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthenaKernel + Control/CxxUtils + Control/SGTools + GaudiKernel + PRIVATE + AtlasTest/TestTools ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) + +# Component(s) in the package: +atlas_add_library( AthLinks + src/*.cxx + PUBLIC_HEADERS AthLinks + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} TestTools ) + +atlas_add_dictionary( AthLinksDict + AthLinks/AthLinksDict.h + AthLinks/selection.xml + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( exceptions_test + SOURCES + test/exceptions_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( DataProxyHolder_test + SOURCES + test/DataProxyHolder_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( IndexHolder_test + SOURCES + test/IndexHolder_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( IdentContIndex_test + SOURCES + test/IdentContIndex_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( ForwardIndexingPolicy_test + SOURCES + test/ForwardIndexingPolicy_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( SetIndexingPolicy_test + SOURCES + test/SetIndexingPolicy_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( MapIndexingPolicy_test + SOURCES + test/MapIndexingPolicy_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( IdentContIndexingPolicy_test + SOURCES + test/IdentContIndexingPolicy_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( IsSTLSequence_test + SOURCES + test/IsSTLSequence_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( DataLinkBase_test + SOURCES + test/DataLinkBase_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( DataLink_test + SOURCES + test/DataLink_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( ElementLinkBase_test + SOURCES + test/ElementLinkBase_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( GenericElementLinkBase_test + SOURCES + test/GenericElementLinkBase_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( ElementLink_test + SOURCES + test/ElementLink_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( ElementLinkFwd_test + SOURCES + test/ElementLinkFwd_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( DataPtr_test + SOURCES + test/DataPtr_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks ) + +atlas_add_test( AssociationMap_test + SOURCES + test/AssociationMap_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel TestTools AthLinks + EXTRA_PATTERNS "ClassIDSvc Initialized successfully|^HistogramPersis.* INFO" ) + diff --git a/EDM/athena/Control/AthLinks/cmt/requirements b/EDM/athena/Control/AthLinks/cmt/requirements new file mode 100644 index 00000000..c27cc96a --- /dev/null +++ b/EDM/athena/Control/AthLinks/cmt/requirements @@ -0,0 +1,48 @@ +package AthLinks + +author Paolo Calafiura <Paolo.Calafiura@cern.ch> +author Hong Ma <hma@bnl.gov> +author Srini Rajagopalan <srinir@bnl.gov> +author scott snyder <snyder@bnl.gov> + +use AtlasPolicy AtlasPolicy-* +use AthenaKernel AthenaKernel-* Control +use SGTools SGTools-* Control +use CxxUtils CxxUtils-* Control +use AtlasBoost AtlasBoost-* External +use GaudiInterface GaudiInterface-* External +use AtlasReflex AtlasReflex-* External + + +apply_pattern installed_library +library AthLinks *.cxx + + +private + +use TestTools TestTools-* AtlasTest +apply_pattern UnitTest_run unit_test=exceptions +apply_pattern UnitTest_run unit_test=DataProxyHolder +apply_pattern UnitTest_run unit_test=IndexHolder +apply_pattern UnitTest_run unit_test=IdentContIndex +apply_pattern UnitTest_run unit_test=ForwardIndexingPolicy +apply_pattern UnitTest_run unit_test=SetIndexingPolicy +apply_pattern UnitTest_run unit_test=MapIndexingPolicy +apply_pattern UnitTest_run unit_test=IdentContIndexingPolicy +apply_pattern UnitTest_run unit_test=IsSTLSequence +apply_pattern UnitTest_run unit_test=DataLinkBase +apply_pattern UnitTest_run unit_test=DataLink +apply_pattern UnitTest_run unit_test=ElementLinkBase +apply_pattern UnitTest_run unit_test=GenericElementLinkBase +apply_pattern UnitTest_run unit_test=ElementLink +apply_pattern UnitTest_run unit_test=ElementLinkFwd +apply_pattern UnitTest_run unit_test=DataPtr +apply_pattern UnitTest_run unit_test=AssociationMap \ + extrapatterns="ClassIDSvc Initialized successfully|^HistogramPersis.* INFO" + +macro_append DOXYGEN_INPUT " ../doc" + + +private +use AtlasROOT AtlasROOT-* External +apply_pattern lcgdict dict=AthLinks selectionfile=selection.xml headerfiles="../AthLinks/AthLinksDict.h" diff --git a/EDM/athena/Control/AthLinks/ispellwords b/EDM/athena/Control/AthLinks/ispellwords new file mode 100644 index 00000000..662abdfe --- /dev/null +++ b/EDM/athena/Control/AthLinks/ispellwords @@ -0,0 +1,875 @@ +personal_ws-1.1 en 698 +assoPointer +persistency +IdentifiableContainer +multi +toContainedElement +GaudiKernel +situ +someone's +refcnt +GENERATEINDEXINGPOLICIES +elementShortRef +originalSize +unary +blk +arg +objectContainer +dataID +bkt +Amram +endif +typeid +fooB +ForwardIndexingPolicy +JetCollection +resized +constr +PackedArray +const's +RandomAccessIterator +CompareAndPrint +del +IProxyDict +deallocate +dep +DVLNoBase +cassert +creat +ASHSTLAllocator +ness +Resizes +autoselect +doinit +setElement +DataVector +theAsso +addHostDObj +gaudi +Dreizin +scott +theAssociatedObjects +cmt +objIndex +assocIndex +dir +ArenaAllocatorRegistry +allocator's +persistifiable +InhVectorIntLink +functor +nclear +crc +elmts +ssnyder +Predwrapper +MessageSvc +DNC +readback +binet +theTrack +DL's +DataPool +Faz +newAssoc +fdl +GenerateIndexingPolicy +ConstDataVector +AtlasReflex +fangled +fdv +LongRef +pCont's +gcc +Ilija +HistogramPersis +absFluff +liint +getAssociations +allo +isDefault +utest +ArenaCachingHandle +depcy +nctor +ELs +CVS +ClassName +destructor +tTrack +elt +hashtable's +PlainPtrElementLink +ELV +DList +DSO +resetWithKeyAndIndex +DataLinkVector +ElemLink +resetWithKey +typedef +pbad +dum +firstAssoc +cxx +theStore +BaseContainer +persistified +dvl +endAssociation +ispellwords +ILink +endHostDObjs +shortRefs +shortrefs +GenParticleIndexing +Elsing +DV's +BinaryPredicate +anOther +FooDequeLink +moveHostDObjs +theObjects +FooDeque +ArenaBase +AtlasSEAL +FNV +NoBase +icc +iCtr +NOGAUDI +swapElement +defaultHeader +objectPointer +src's +StoreGateSvc +hashtable +CopyConstructible +findProxy +BeginEvent +GNUC +toPersistentDL +iff +firstAssObject +bitsize +pCopyDerFluff +findAssociationObjects +DataVectorBase +fdvlcopy +line'll +func +ArenaHandleBaseAllocT +asDataList +CLID's +CLIDs +convertable +fdlcopy +hoc +DHAVE +functionalities +addArena +dataGet +namespaces +StoreGate +IOSTREAMS +oldElem +DataProxy +paolo +eltest +jobOs +AssociationLinks +DataLink +RVersion +pAssoc +hpp +TODO +valgrind +DataProxyStorageBase +srini +getObject +ASSCONT +cerr +proxying +ASSOCONT +DataListBase +AthenaPOOL +Calafiura +MapIndexingPolicy +param +AssociationVector +IProxyDictWithPool +persistify +changeState +canReclear +doxygen +setHashAndIndex +runtime +lcg +args +DataList +DataPtrs +rebinder +theAssociations +inserters +uint +ndtor +DVLCast +theAssociationObjects +assoStore +AssociationVectorCollection +isStreamable +irt +resetTo +AssociationVectorIterator +wronglmint +pairtype +pdata +RemoveDataPtr +theType +printf +setStorableObject +ArenaHeapSTLAllocator +iJet +doRemap +toPersistable +OBJCONT +deallocation +iTracks +getFirstAssociation +SGFolder +AssociationLinkCollection +objectIter +lhs +storeName +ArenaBlockAllocatorBase +rvalue +DerivedFluff +ElemLinkVector +ArenaHeaderGaudiClear +mem +hasher +dobjs +assoIter +Quarrie +hasAssociations +assoContainer +dereferencing +cinquanta +IdentContIndexingPolicy +DVLDataBucket +ElementLinkVector +vers +PDTR +nav +Hong +forwardContainer +cinq +eltSize +AtlasBoost +CINT +typeinfoName +reverseIterators +ArenaPoolAllocator +kwd +ndx +resize +indexingPolicy +tradeoff +ClusterContainer +oldInt +getDataSourcePointer +MacOSX +NavigationToken +asso +PlainPtrStorage +bool +shortref +shortRef +dieci +DataMap +Nir +OBJTYPE +asDataVector +ArenaHeapAllocator +DataLinks +gmake +mLink +castfn +AssociationBaseCollection +clid +deps +LWG +namespace +IOHandler +ArenaAllocatorCreatorInit +pdf +pAssocs +dflt +dfluff +pDL +reflextion +typename +typeName +DVLIterator +iTrack +getDataSource +initParams +LXR +DataBucket +pDV +pJets +refCount +snyder +ASSOBJECT +initGaudi +Srini's +multimap +pTransient +DataBucketTrait +dict +ElemLinkRefs +interoperate +nreserve +lastAssObject +theAssoc +TrackContainer +init +minRefCount +impl +OwnershipPolicy +otherElemLinkRefs +AssociativeIndexingPolicy +DataVector's +oper +IsSTLSequence +findProxyFromKey +newAss +mutators +addTrack +IncidentSvc +makeIndex +sgkey +StrictWeakOrdering +lastTrack +ClassID +classID +calaf +rbegin +containsAssociation +SetIndexingPolicy +ifndef +assocPointer +BaseConstReference +pos +PtrVector +ret +pre +params +BList +theAssocs +ArenaAllocatorBase +Dufus +GaudiClear +ppvInterface +reextracted +lookup +arghh +rhs +pointee +maxRefCount +config +toPersistentState +intL +Sep +hostDObjs +ClassIDSvc +ptr +BVec +intV +pvp +getDataSourcePointerFromGaudi +RNG +pTracks +Metafunction +ArenaHandleBase +shortIterFromLong +tCluster +successFlag +genreflex +DataProxyStorage +DataProxyStorageData +theJet +ElementType +ELVDEBUG +PtrList +AllocatorCreatorBase +asStorable +ArenaSharedHeapSTLAllocator +AthenaKernel +ChangeLog +getLastAssocation +nblock +dvlinfo +DVLInfo +PlainPtrDataLink +src +cout +IDtype +pcopy +jobO +Vec +resizePool +TestTools +dtors +DataPtr +tdefs +enums +ArenaSTLAllocator +findHostDObj +DataList's +toIndexedElement +stl +sizeof +svc +cptr +sss +checkreq +dobj +Vukotic +packageinfo +frexp +str +setData +MyObj +iter +DVLEltBase +AssociationType +clidsvc +CLIDSvc +backNavigation +toPersistent +theCluster +mustClear +storable +IInterface +AssociationObjectIterator +DefaultKey +TSS +inlined +Rajagopalan +makeFunc +savannah +ArenaBlock +multiset +GeneratorObjects +reverseLookup +DefaultState +Obreshkov +pred +malloc +myassert +AthExStoreGateExamples +DVLInfoBase +setOwner +txt +myCluster +FIXME +LIBSTDCXX +ArenaAllocatorCreator +Gemmeren +makeAllocator +JetTrackAssociation +IOVSvc +prev +newElement +beginAssociation +specializable +removeHostDObj +toAccessible +RefVector +EndEvent +PersistentState +tinfo +myassertion +elcnv +ctor +struct +vpvp +dereference +allocvec +getDataRef +ElementParameter +fdvl +AthenaROOTAccess +ControlTest +objectIndex +iHost +emacs +alloc +pElem +riid +accessor +setValid +DataObject +makeCurrent +dpint +symLink +decls +ElementLink +bb +anAss +DataSource +linkOffset +linkoffset +lookups +refVector's +DPSB +isValid +ibadlint +ForwardIterator +assoIndex +firstTrack +NDEBUG +NULLs +templated +endl +br +getDataPtr +venti +eg +dl +mainpage +VirtBases +DefaultIndexingPolicy +utests +reportStr +fd +FooDataVectorLink +CxxUtils +ivint +findInContainer +dv +DVLTYPE +RehashPolicy +ElementProxy +theObject +fn +JetTrackAssociationCollection +SGASSERTERROR +checkForRemap +iliint +toTransient +anotherString +ctors +AssociationLink +FolderItem +IdentContIndex +dereferences +iptrlint +intLF +DataModel +getLastAssociation +IP +indices +multithreaded +sstream +intLL +ld +destructors +Elts +ownPolicy +tryELRemap +li +rvalues +DeclareIndexingPolicy +Koenig +IndexingPolicies +nd +xyz +Austern +delArena +TrackParticleContainer +minSize +toAccessibleState +storagePolicy +NavFourMon +ArenaHandle +ConstDataList +ok +TrackParticle +ChronoStatSvc +ElemLinkRef +ns +findAssociation +Compwrapper +proxied +gccxml +RegisterDVLEltBaseInit +badI +DataPoolTest +os +stdcont +stdCont +initializer +lastAssoc +DVec +ri +BaseInfo +sg +ElemLinks +ElemLink's +targ +DirSearchPath +ELVRef +intVF +headp +BidirectionalIterator +cplusplus +Tavori +SGElvRef +dtor +enum +schaffer +intVL +vd +ForwardContainerConcept +InUse +sz +WG +ArenaPoolSTLAllocator +inline +typedefs +typedef's +Vo +getE +vp +sgname +sgName +rObj +SequenceIndexing +setStorable +trenta +AssociationMap +abc +thinning's +newElem +jobOptions +getAssociationObjects +myarena +lvalues +CategoryOrTraversal +PTAss +accessors +Mytype +raiseInvalidErrorBase +MyElement +rdata +adaptors +toPersistentNomap +DVL's +endcode +aFoo +ftemplate +ExtractKey +ArenaHandleBaseT +defaultDataSource +IdentifiedState +lvalue +ElementHolder +adaptor +preload +ifdef +AssociationBase +theContext +AssociationObject +ArenaHeader +ElementLinks +toIdentified +wrongvint +AssociationObjects +Baz +overridable +const +SGTools +NULLLINK +DefaultKeyState +getDataSourcePointerFunc +libstdc +persistable +SGgetDataSource +AthLinks +StoragePolicy +IndexingPolicy +doesn +wouldn +T2 +T1 +EL +isn +Short2LongRef +Allocators +refVector +x86 +isSequence +Store2 +test1 +t1 +Foo298342 +test2 +test3 +test4 +test5 +pvp3 +vpvp3 +vp3 +Loch +krasznaa +De +DataLinkBase +Krasznahorkay +IDENTCONT +dummy1 +dummy2 +ElementLinkBase +ElementLinkVectorBase +vtable +wasn +comparator +resetCachedSource +ExcCLIDMismatch +ExcPointerNotInSG +nothrow +toIdentifiedObject +ExcInvalidLink +isObjpointer +LSB +DATAPROXYHOLDER +INDEXHOLDER +Muon +TTree +isDirectIO +boolean +svn +standalone01 +El +hscript +hwafize +Sebastien +Didn +ExcBadForwardLink +ExcElementNotFound +ExcInvalidIndex +ExcIndexNotFound +DataProxyHolder +TestStore +foo1 +foo3 +toStorableObject +foo2 +foo4 +foo4a +foo6 +exact1 +addToStore +IndexHolder +asd +addRef +queryInterface +proxy2 +keyToString1 +registerKey +mykey' +mykey +MyClass +navigation' +dereferencable +toPersistentNoRemap +persKey +GenericElementLinkBase +ElementLinkTraits +instantiations +policy' +elemID +pEl +dereferenced +isDefaultIndex +hasCachedElement +doPersistent +std' +construction' +piecewise +casefn +storableBase +setIndex +storedIndex +setCachedElement +getCachedElement +ElementConstReference +ElementConstPointer +xAODTruth +StoreGateSvc'' +current' +cCont +tCont +foo5 +foo30 +foo7 +foo20 +foo21 +foo22 +foo23 +foo101 +foocont +foocont2 +foocont3 +foocont3a +foocont3b +t2 +foocont4 +foocont20 +test6 +foocont21 +test7 +fooVec +el4 +el1 +FooVecLink4 +fooVec2 +FooVecLink2 +FooVec2Link2 +test8 +strvec +strvec2 +test9 +strset +strset2 +test10 +strmap +strmap2 +identcont +test11 +imap +imap2 +test12 +strcont +0b +1b +2b +3b +strcont2 +2bj +strcont3 +uint64 +uint32 +storedToExternal +Reimplementation +root6 +ROOT6 +Nowak +Marcin +persIndex +ThinningSvc +tryRemap +DataModelAthenaPool +transIndex +Couldn diff --git a/EDM/athena/Control/AthLinks/share/AssociationMap_test.ref b/EDM/athena/Control/AthLinks/share/AssociationMap_test.ref new file mode 100644 index 00000000..4b9c97fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/AssociationMap_test.ref @@ -0,0 +1,34 @@ + *** AssociationMap test in progress: +Build fake data and associations: +Cluster Container...............: 3 clusters +Track Container.................: 3 tracks +Associate Clusters and Tracks...: [0,0] with data [1,-1] +Associate Clusters and Tracks...: [0,1] with data [1,-2] +Associate Clusters and Tracks...: [0,2] with data [1,-3] +Associate Clusters and Tracks...: [1,0] with data [2,-1] +Associate Clusters and Tracks...: [1,1] with data [2,-2] +Associate Clusters and Tracks...: [1,2] with data [2,-3] +Associate Clusters and Tracks...: [2,0] with data [3,-1] +Associate Clusters and Tracks...: [2,1] with data [3,-2] +Associate Clusters and Tracks...: [2,2] with data [3,-3] +List of objects in AssociationMap: + Cluster : + Track : -1 + Track : -2 + Track : -3 + Cluster : + Track : -1 + Track : -2 + Track : -3 + Cluster : + Track : -1 + Track : -2 + Track : -3 +Check that AssociationMap contains myCluster : true +Number of associations for myCluster= 3 +Number of association objects:3 + + *** Test AssociationMap<TrackContainer,TrackContainer> : +Associate Tracks and Tracks...: [0,1] with data [-1,-2] +Associate Tracks and Tracks...: [0,2] with data [-1,-3] +Associate Tracks and Tracks...: [1,2] with data [-2,-3] diff --git a/EDM/athena/Control/AthLinks/share/DataLinkBase_test.ref b/EDM/athena/Control/AthLinks/share/DataLinkBase_test.ref new file mode 100644 index 00000000..45aaa06d --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/DataLinkBase_test.ref @@ -0,0 +1,5 @@ +test1 +test2 +test3 +test4 +test5 diff --git a/EDM/athena/Control/AthLinks/share/DataLink_test.ref b/EDM/athena/Control/AthLinks/share/DataLink_test.ref new file mode 100644 index 00000000..69fa79ca --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/DataLink_test.ref @@ -0,0 +1,9 @@ +test1 +SG::DataProxy_castWARNING this proxy 0x24c57d0 [23423556/foo30] is in an invalid state +test2 +test3 +test4 +SG::DataProxy_castWARNING this proxy 0x24cd8d0 [23423556/foo20] is in an invalid state +SG::DataProxy_castWARNING this proxy 0x24cdc10 [0/] is in an invalid state +SG::DataProxy_castWARNING this proxy 0x24cdff0 [23423556/foo22] is in an invalid state +test5 diff --git a/EDM/athena/Control/AthLinks/share/DataProxyHolder_test.ref b/EDM/athena/Control/AthLinks/share/DataProxyHolder_test.ref new file mode 100644 index 00000000..50615b92 --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/DataProxyHolder_test.ref @@ -0,0 +1,8 @@ +test1 +test2 +test3 +test4 +test5 +test6 +DataProxyHolder... ERROR FILE:LINE (bool SG::DataProxyHolder::thin(SG::DataProxyHolder::sgkey_t&, size_t&)): Couldn't get proxy for target object +test7 diff --git a/EDM/athena/Control/AthLinks/share/DataProxyStorageData_test.ref b/EDM/athena/Control/AthLinks/share/DataProxyStorageData_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthLinks/share/DataProxyStorage_test.ref b/EDM/athena/Control/AthLinks/share/DataProxyStorage_test.ref new file mode 100644 index 00000000..a4144f7d --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/DataProxyStorage_test.ref @@ -0,0 +1,13 @@ +test1 +Caught exception: dereferencing invalid DataLink in state NULLLINK +Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout +DataProxyStorage ERROR ../src/DataProxyStorage.cxx:41 (const std::string&DataProxyStorageBase::dataID() const): Can't translate hash 1234 to a string +Caught exception: dereferencing invalid DataLink in state IDENTIFIED (312268004 -> Foo298342/23423556) +test2 +Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout +DataProxyStorage ERROR ../src/DataProxyStorage.cxx:138 (DataProxyStorageBase::DataProxyStorageBase(void*, IProxyDictWithPool*)): initializing a link with a NULL data ptr +Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout +DataProxyStorage ERROR ../src/DataProxyStorage.cxx:263 (void DataProxyStorageBase::setDataBase(void*, const unsigned int&)): initializing a link with a NULL data ptr +test3 +test4 +test5 diff --git a/EDM/athena/Control/AthLinks/share/DataPtr_test.ref b/EDM/athena/Control/AthLinks/share/DataPtr_test.ref new file mode 100644 index 00000000..ffca8539 --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/DataPtr_test.ref @@ -0,0 +1,5 @@ +0x804ef68->0x804f238 use count 1 content 0 +0x804ef70->0x804f258 use count 1 content 1 +0x804ef78->0x804f278 use count 5 content 2 +0x804ef80->0x804f278 use count 5 content 2 +*** DataPtr_test OK *** diff --git a/EDM/athena/Control/AthLinks/share/ElementHolder_test.ref b/EDM/athena/Control/AthLinks/share/ElementHolder_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthLinks/share/ElementLinkBase_test.ref b/EDM/athena/Control/AthLinks/share/ElementLinkBase_test.ref new file mode 100644 index 00000000..45aaa06d --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/ElementLinkBase_test.ref @@ -0,0 +1,5 @@ +test1 +test2 +test3 +test4 +test5 diff --git a/EDM/athena/Control/AthLinks/share/ElementLinkFwd_test.ref b/EDM/athena/Control/AthLinks/share/ElementLinkFwd_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/ElementLinkFwd_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/ElementLink_test.ref b/EDM/athena/Control/AthLinks/share/ElementLink_test.ref new file mode 100644 index 00000000..12f4169d --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/ElementLink_test.ref @@ -0,0 +1,13 @@ +test1 +test2 +test3 +test4 +test5 +test6 +test7 +test8 +test9 +test10 +test11 +test12 +test13 diff --git a/EDM/athena/Control/AthLinks/share/ForwardIndexingPolicy_test.ref b/EDM/athena/Control/AthLinks/share/ForwardIndexingPolicy_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/ForwardIndexingPolicy_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/GenericElementLinkBase_test.ref b/EDM/athena/Control/AthLinks/share/GenericElementLinkBase_test.ref new file mode 100644 index 00000000..fadbf1d8 --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/GenericElementLinkBase_test.ref @@ -0,0 +1,4 @@ +test1 +test2 +test3 +test4 diff --git a/EDM/athena/Control/AthLinks/share/IdentContIndex_test.ref b/EDM/athena/Control/AthLinks/share/IdentContIndex_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/IdentContIndex_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/IdentContIndexingPolicy_test.ref b/EDM/athena/Control/AthLinks/share/IdentContIndexingPolicy_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/IdentContIndexingPolicy_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/IndexHolder_test.ref b/EDM/athena/Control/AthLinks/share/IndexHolder_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/IndexHolder_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/IsSTLSequence_test.ref b/EDM/athena/Control/AthLinks/share/IsSTLSequence_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/IsSTLSequence_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/MapIndexingPolicy_test.ref b/EDM/athena/Control/AthLinks/share/MapIndexingPolicy_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/MapIndexingPolicy_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/SetIndexingPolicy_test.ref b/EDM/athena/Control/AthLinks/share/SetIndexingPolicy_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/SetIndexingPolicy_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthLinks/share/exceptions_test.ref b/EDM/athena/Control/AthLinks/share/exceptions_test.ref new file mode 100644 index 00000000..81876813 --- /dev/null +++ b/EDM/athena/Control/AthLinks/share/exceptions_test.ref @@ -0,0 +1,9 @@ +test1 +SG::ExcPointerNotInSG: The object referenced by a DataLink / ElementLink is not registered in StoreGate: 0x1234. +SG::ExcCLIDMismatch: Attempt to set DataLink / ElementLink with CLID 456 to object with CLID 123 +SG::ExcInvalidLink: Attempt to dereference invalid DataLink / ElementLink [123/key] (765) +SG::ExcBadForwardLink: ForwardIndexingPolicy: internal link state is invalid: m_index =123 is >= data container size =345 +SG::ExcElementNotFound: test: element not found +SG::ExcInvalidIndex: test: invalid index +SG::ExcIndexNotFound: test: index not found +SG::ExcIncomparableEL: Attempt to compare an ElementLink that does not have a SG key or index. diff --git a/EDM/athena/Control/AthLinks/src/DataProxyHolder.cxx b/EDM/athena/Control/AthLinks/src/DataProxyHolder.cxx new file mode 100644 index 00000000..d3c65881 --- /dev/null +++ b/EDM/athena/Control/AthLinks/src/DataProxyHolder.cxx @@ -0,0 +1,542 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/src/DataProxyHolder.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Manage @c DataProxy reference in ElementLink/DataLink. + */ + + +#include "AthLinks/tools/DataProxyHolder.h" +#include "AthLinks/exceptions.h" +#include "SGTools/DataProxy.h" +#include "SGTools/TransientAddress.h" +#include "SGTools/CurrentEventStore.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IThinningSvc.h" +#include "AthenaKernel/errorcheck.h" + + +namespace SG { + + +/** + * @brief Set the link to an object given by a pointer. + * @param obj Pointer to the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * This will try to look up the proxy for @c obj. If that succeeds, + * then we store the pointer to the proxy and return the SG key. + * Otherwise, we store a pointer to the object itself, flagging + * this case with the low bit, and return 0. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +DataProxyHolder::sgkey_t +DataProxyHolder::toStorableObject (const_pointer_t obj, + CLID link_clid, + IProxyDict* sg) +{ + sgkey_t key = 0; + if (obj == 0) { + // Setting the link to null. + m_proxy = 0; + } + else { + // Find the store to use. + if (sg == 0) + sg = this->source1(); + if (sg == 0) + sg = SG::CurrentEventStore::store(); + + m_proxy = sg->proxy (obj); + if (m_proxy == 0) { + // Didn't find a proxy for this object. + // Store the object pointer directly, and return 0. + storeObjpointer (obj); + } + else { + // Found a proxy. Fetch the SG key and check that the type of the object + // is consistent with the link type. + SG::TransientAddress* tad = m_proxy->transientAddress(); + key = tad->sgkey(); + if (link_clid != m_proxy->clID() && !tad->transientID (link_clid)) + throw SG::ExcCLIDMismatch (m_proxy->clID(), link_clid); + } + } + return key; +} + + +/** + * @brief Set the link to an object given by a string key. + * @param dataID Key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * @returns The SG key for this object. + * + * This will try to look up the proxy for @c dataID. If that succeeds, + * then we store the pointer to the proxy. Otherwise, we create + * a dummy proxy and add it to the store. We return the SG key + * in either case. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + */ +DataProxyHolder::sgkey_t +DataProxyHolder::toIdentifiedObject (const ID_type& dataID, + CLID link_clid, + IProxyDict* sg) +{ + // Find the store to use. + if (sg == 0) + sg = this->source1(); + if (sg == 0) + sg = SG::CurrentEventStore::store(); + + if (!sg) + return 0; + + // Look up the proxy. + m_proxy = sg->proxy (link_clid, dataID); + if (m_proxy == 0) { + // Didn't find a proxy; make a dummy. + SG::TransientAddress* tad = new SG::TransientAddress (link_clid, dataID); + tad->setSGKey (sg->stringToKey (dataID, link_clid)); + m_proxy = new SG::DataProxy (tad, (IConversionSvc*)0); + if (sg->addToStore (link_clid, m_proxy).isFailure()) + std::abort(); + } + + // Return the proxy's sgkey. + return m_proxy->transientAddress()->sgkey(); +} + + +/** + * @brief Set the link to an object given by a hashed key. + * @param key Hashed key of the object. + * @param link_clid CLID of the link being set. + * @param sg Associated store. + * + * This will try to look up the proxy for @c key. If that succeeds, + * then we store the pointer to the proxy. Otherwise, we create + * a dummy proxy and add it to the store. + * + * If @c sg is 0, then we take the store from whatever the link's currently + * set to. If the link has no current store, then we take the global + * default. + * + * May throw @c ExcCLIDMismatch. + */ +void +DataProxyHolder::toIdentifiedObject (sgkey_t sgkey, + CLID link_clid, + IProxyDict* sg) +{ + if (!sgkey) return; + + // Find the store to use. + if (sg == 0) + sg = this->source1(); + if (sg == 0) + sg = SG::CurrentEventStore::store(); + + if (!sg) + return; + + // Look up the proxy. + m_proxy = sg->proxy_exact (sgkey); + + CLID clid = CLID_NULL; + const std::string* key = nullptr; + if (m_proxy == 0) { + // Didn't find it --- have SG query proxy providers. + // Try to turn the hashed key into a string key + clid. + key = sg->keyToString (sgkey, clid); + if (key) { + if (link_clid != CLID_NULL && clid != link_clid) + throw SG::ExcCLIDMismatch (clid, link_clid); + m_proxy = sg->proxy (clid, *key); + } + } + + if (m_proxy == 0) { + // Still didn't find it --- make a dummy. + SG::TransientAddress* tad; + if (key) + tad = new SG::TransientAddress (clid, *key); + else + tad = new SG::TransientAddress(); + tad->setSGKey (sgkey); + m_proxy = new SG::DataProxy (tad, (IConversionSvc*)0); + if (sg->addToStore (clid, m_proxy).isFailure()) + std::abort(); + } + else if (link_clid != CLID_NULL && + m_proxy->clID() != CLID_NULL && + !m_proxy->transientAddress()->transientID(link_clid)) + { + // Found a proxy, but types don't match. + throw SG::ExcCLIDMismatch (m_proxy->clID(), link_clid); + } +} + + +/** + * @brief Return the SG key that we reference, as a string. + * + * Returns a null string on failure. + */ +const DataProxyHolder::ID_type& +DataProxyHolder::dataID() const +{ + SG::DataProxy* dp = proxy (true); + if (dp) + return dp->name(); + + static std::string dummy; + return dummy; +} + + +/** + * @brief Return a pointer to the currently-referenced object. + * @param castfn Function to do the cast from data proxy to object. + * If 0, use a dynamic cast. + * @param clid The CLID of the desired object. + * This is used to determine how the returned pointer + * is to be converted. + * @return A pointer to an object of the type given by @a clid, + * or null on a failure (or if the reference is null). + */ +void* DataProxyHolder::storableBase (castfn_t* castfn, CLID clid) const +{ + // Test for null link. + if (!m_proxy) + return 0; + + // Test for direct pointer to an object. + if (isObjpointer()) + return objpointer(); + + // We have a proxy. Get the object pointer from the proxy. + // We have to take care of converting to the proper return type, though + // (as requested by clid). + void* obj = castfn ? castfn (m_proxy) : SG::DataProxy_cast (m_proxy, clid); + if (obj) + return obj; + + // We failed. It may be that we don't have a conversion + // between clid and the object type: it may have been stored + // using a hard cast. Check to see if this object has actually + // been registered under the requested clid. + if (m_proxy->transientAddress()->transientID (clid)) { + DataBucketBase* db = + dynamic_cast<DataBucketBase*> (m_proxy->accessData()); + + // Do a hard cast... + if (db) + return db->object(); + } + + return 0; +} + + +/** + * @brief Return the data source for this reference. + * + * If the link is null, return 0. + * If we're pointing at an object directly, then we return the default store + * if the object is found in SG; otherwise, throw @c ExcPointerNotInSG. + */ +IProxyDict* DataProxyHolder::source() const +{ + SG::DataProxy* dp = proxy(); + if (!dp) + return 0; + return dp->store(); +} + + +/** + * @brief Finish initialization after link has been read. + * @param sgkey Hashed SG key. + * @param sg Associated store. + * + * This should be called after a link has been read by root + * in order to set the proxy pointer. It calls @c toIdentifiedObject + * with the provided hashed key. + * + * If @c sg is 0, then we use the global default store. + */ +void +DataProxyHolder::toTransient (sgkey_t sgkey, IProxyDict* sg /*= 0*/) +{ + m_proxy = 0; + if (sgkey) + toIdentifiedObject (sgkey, CLID_NULL, sg); +} + + +/** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * This version does not perform link remapping. + */ +void DataProxyHolder::toPersistentNoRemap (sgkey_t& sgkey) +{ + if (!sgkey && m_proxy) { + m_proxy = proxy(); // May throw. + sgkey = m_proxy->transientAddress()->sgkey(); + } +} + + +/** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * If the target of the link has been remapped, then the @c sgkey and @c index + * parameters will be updated to reflect that, and @c true will be returned. + * Otherwise, if there was no remapping, then @c false will be returned. + * + * This version is for the case where indices are given by @c uint64_t. + */ +bool DataProxyHolder::toPersistent (sgkey_t& sgkey, uint64_t& index) +{ + toPersistentNoRemap (sgkey); + size_t index_s = index; + bool ret = tryRemap (sgkey, index_s); + if (ret) + index = index_s; + return ret; +} + + +/** + * @brief Prepare this link for writing. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * One of the @c toPersistent methods should be called before + * trying to write the link with root. + * + * This takes a reference to the hashed SG key. In the case where we're + * referencing an object directly by pointer, the hashed key will be 0. + * In that case, we try to look up the object in the default store. + * If we find it, the hashed key is updated appropriately; otherwise, + * we throw @c ExcPointerNotInSG. + * + * If the target of the link has been remapped, then the @c sgkey and @c index + * parameters will be updated to reflect that, and @c true will be returned. + * Otherwise, if there was no remapping, then @c false will be returned. + * + * This version is for the case where indices are given by @c uint32_t. + */ +bool DataProxyHolder::toPersistent (sgkey_t& sgkey, uint32_t& index) +{ + toPersistentNoRemap (sgkey); + size_t index_s = index; + bool ret = tryRemap (sgkey, index_s); + if (ret) + index = index_s; + return ret; +} + + +/** + * @brief Test to see if the link has been remapped. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * If this link has been remapped, @c sgkey and @c index will be + * adjusted accordingly. + * + * Returns @c true if the link was remapped, @c false otherwise. + */ +bool DataProxyHolder::tryRemap (sgkey_t& sgkey, size_t& index) +{ + if (sgkey) { + // Check for remapping. + sgkey_t sgkey_out; + size_t index_out = 0; + if (this->source()->tryELRemap (sgkey, index, sgkey_out, index_out)) { + this->toIdentifiedObject (sgkey_out, CLID_NULL, this->source()); + sgkey = sgkey_out; + index = index_out; + return true; + } + } + + return false; +} + + +/** + * @brief Adjust for thinning. + * @param sgkey Reference to the hashed SG key. + * @param index Index of this link. + * + * If this link points to a container that has been thinned, + * @c sgkey and @c index will be adjusted accordingly. + * + * Returns @c true if the index was changed; @c false otherwise. + */ +bool DataProxyHolder::thin (sgkey_t& sgkey, size_t& index) +{ + bool result = false; + if (sgkey) { + // Check if thinning is needed for this link: + IThinningSvc* thinSvc = IThinningSvc::instance(); + if( ! thinSvc ) { + // If the service is not available, return now. Since this just means + // that there is no thinning defined for this stream. + return false; + } + // Try to get a DataProxy for our link: + SG::DataProxy* dp = proxy( true ); + if( ! dp ) { + // If we were not successful, let's give up. + REPORT_MESSAGE_WITH_CONTEXT( MSG::ERROR, + "DataProxyHolder::toPersistent" ) + << "Couldn't get proxy for target object"; + return false; + } + // Get the updated index: + const std::size_t persIdx = thinSvc->index( dp, index ); + // If the object was thinned away, set the persistent variables to an + // invalid state. Otherwise update just the index variable. + if( persIdx == IThinningSvc::RemovedIdx ) { + sgkey = 0; + index = 0; + result = true; + } + else { + if (index != persIdx) + result = true; + index = persIdx; + } + } + + return result; +} + + +/** + * @brief Throw a @c ExcInvalidLink exception for this link. + * @param sgkey The hashed key for this link. + * + * This will fill in parameters for the exception message from the proxy. + */ +void DataProxyHolder::throwInvalidLink (sgkey_t sgkey) const +{ + CLID clid = CLID_NULL; + std::string key; + SG::DataProxy* dp = proxy(); + if (dp) { + clid = dp->clID(); + key = dp->name(); + } + throw SG::ExcInvalidLink (clid, key, sgkey); +} + + +/** + * @brief Helper for @c proxy(), for the case of a direct object pointer. + * @param nothrow If true, return 0 on failure instead of throwing + * an exception. + * + * This is the out-of-line portion of @c proxy(), called if this link + * is directly pointing at an object. Try to look up + * the corresponding @c DataProxy using the default store. Return it + * if we find it; otherwise, either throw @c ExcPointerNotInSG or + * return 0, depending on the @c nothrow parameter. + */ +SG::DataProxy* DataProxyHolder::proxy1(bool nothrow) const +{ + const_pointer_t obj = reinterpret_cast<const_pointer_t> + (reinterpret_cast<unsigned long> (m_proxy) & ~1UL); + SG::DataProxy* proxy = SG::CurrentEventStore::store()->proxy (obj); + if (proxy == 0 && !nothrow) + throw SG::ExcPointerNotInSG (obj); + return proxy; +} + + + +/** + * @brief Return the data source for this reference. + * + * If we're holding a pointer directly, rather than a proxy, + * then return 0 rather than raising an exception. + */ +IProxyDict* DataProxyHolder::source1() const +{ + if (!m_proxy || (reinterpret_cast<unsigned long>(m_proxy) & 1) == 1) + return 0; + return m_proxy->store(); +} + + +/** + * @brief Compare for equality. + */ +bool DataProxyHolder::operator== (const DataProxyHolder& other) const +{ + if (m_proxy == other.m_proxy) return true; + + // One could refer to an object directly by pointer, the other could + // have a proxy. + + const_pointer_t ptr = 0; + const DataProxy* proxy = 0; + if (isObjpointer() && !other.isObjpointer()) { + ptr = objpointer(); + proxy = other.m_proxy; + } + else if (other.isObjpointer() && !isObjpointer()) { + ptr = other.objpointer(); + proxy = m_proxy; + } + else + return false; + + if (proxy->store()->proxy(ptr) == proxy) + return true; + + return false; +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/src/ElementLinkVectorBase.cxx b/EDM/athena/Control/AthLinks/src/ElementLinkVectorBase.cxx new file mode 100644 index 00000000..a67057ef --- /dev/null +++ b/EDM/athena/Control/AthLinks/src/ElementLinkVectorBase.cxx @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ElementLinkVectorBase.cxx 567807 2013-10-30 09:30:16Z krasznaa $ + +// Local include(s): +#include "AthLinks/ElementLinkVectorBase.h" + +ElementLinkVectorBase:: +ElementLinkVectorBase( const std::vector< uint32_t >& keys, + const std::vector< uint32_t >& indices ) + : m_persKeys( keys ), m_persIndices( indices ), m_isDirectIO( false ) { + +} + +const std::vector< uint32_t >& ElementLinkVectorBase::persKeys() const { + + return m_persKeys; +} + +void +ElementLinkVectorBase::setPersKeys( const std::vector< uint32_t >& keys ) { + + m_persKeys = keys; + return; +} + +const std::vector< uint32_t >& ElementLinkVectorBase::persIndices() const { + + return m_persIndices; +} + +void +ElementLinkVectorBase:: +setPersIndices( const std::vector< uint32_t >& indices ) { + + m_persIndices = indices; + return; +} diff --git a/EDM/athena/Control/AthLinks/src/exceptions.cxx b/EDM/athena/Control/AthLinks/src/exceptions.cxx new file mode 100644 index 00000000..ecf5b7ce --- /dev/null +++ b/EDM/athena/Control/AthLinks/src/exceptions.cxx @@ -0,0 +1,256 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/src/exceptions.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Exceptions that can be thrown from AthLinks. + */ + + +#include "AthLinks/exceptions.h" +#include <sstream> +#include <string> + + +namespace SG { + + +/// For setting debugger breakpoints +void AthLinks_error() {} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excPointerNotInSG_format (const void* pointer) +{ + std::ostringstream os; + os << "SG::ExcPointerNotInSG: " + << "The object referenced by a DataLink / ElementLink is not registered " + << "in StoreGate: " << pointer << "."; + return os.str(); +} + + +/** + * @brief Constructor. + * @param pointer Pointer to the object that the link is referencing. + */ +ExcPointerNotInSG::ExcPointerNotInSG (const void* pointer) + : std::runtime_error (excPointerNotInSG_format (pointer)) +{ + AthLinks_error(); +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string excCLIDMismatch_format (CLID obj_clid, CLID link_clid) +{ + std::ostringstream os; + os << "SG::ExcCLIDMismatch: " + << "Attempt to set DataLink / ElementLink with CLID " << link_clid + << " to object with CLID " << obj_clid; + return os.str(); +} + + +/** + * @brief Constructor. + * @param obj_clid The CLID of the object being assigned to the link. + * @param link_clid The declared CLID of the link. + */ +ExcCLIDMismatch::ExcCLIDMismatch (CLID obj_clid, CLID link_clid) + : std::runtime_error (excCLIDMismatch_format (obj_clid, link_clid)) +{ + AthLinks_error(); +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string +excInvalidLink_format (CLID clid, const std::string& key, SG::sgkey_t sgkey) +{ + std::ostringstream os; + os << "SG::ExcInvalidLink: " + << "Attempt to dereference invalid DataLink / ElementLink " + << "[" << clid << "/" << key << "] (" << sgkey << ")"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID of the link. + * @param key String key of the link. + * @param sgkey Hashed key of the link. + */ +ExcInvalidLink::ExcInvalidLink (CLID clid, + const std::string& key, + SG::sgkey_t sgkey) + : std::runtime_error (excInvalidLink_format (clid, key, sgkey)) +{ + AthLinks_error(); +} + + +/** + * @brief Throw a SG::ExcInvalidLink exception. + * @param clid CLID of the link. + * @param key String key of the link. + * @param sgkey Hashed key of the link. + */ +void throwExcInvalidLink (CLID clid, const std::string& key, SG::sgkey_t sgkey) +{ + throw ExcInvalidLink (clid, key, sgkey); +} + + +//************************************************************************* + + +/// Helper: format exception error string. +std::string +excBadForwardLink_format (size_t index, size_t size) +{ + std::ostringstream os; + os << "SG::ExcBadForwardLink: " + << "ForwardIndexingPolicy: internal link state is invalid"; + if (index != static_cast<size_t>(-1)) { + os << ": m_index =" << index + << " is >= data container size =" + << size << std::ends; + } + return os.str(); +} + + +/** + * @brief Constructor. + * @param index Index in the link. + * @param size Size of the referenced container. + */ +ExcBadForwardLink::ExcBadForwardLink (size_t index, size_t size) + : std::runtime_error (excBadForwardLink_format (index, size)) +{ + AthLinks_error(); +} + + +/** + * @brief Throw a SG::ExcBadForwardLink exception. + * @param index Index in the link. + * @param size Size of the referenced container. + */ +void throwExcBadForwardLink (size_t index, size_t size) +{ + throw ExcBadForwardLink (index, size); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param where The operation being attempted. + */ +ExcElementNotFound::ExcElementNotFound (const std::string& where) + : std::runtime_error ("SG::ExcElementNotFound: " + where + + ": element not found") +{ + AthLinks_error(); +} + + +/** + * @brief Throw a SG::ExcElementNotFound exception. + * @param where The operation being attempted. + */ +void throwExcElementNotFound (const char* where) +{ + throw ExcElementNotFound (where); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param where The operation being attempted. + */ +ExcInvalidIndex::ExcInvalidIndex (const std::string& where) + : std::runtime_error ("SG::ExcInvalidIndex: " + where + ": invalid index") +{ + AthLinks_error(); +} + + +/** + * @brief Throw a SG::ExcInvalidIndex exception. + * @param where The operation being attempted. + */ +void throwExcInvalidIndex (const char* where) +{ + throw ExcInvalidIndex (where); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param where The operation being attempted. + */ +ExcIndexNotFound::ExcIndexNotFound (const std::string& where) + : std::runtime_error ("SG::ExcIndexNotFound: " + where + ": index not found") +{ + AthLinks_error(); +} + + +/** + * @brief Throw a SG::ExcIndexNotFound exception. + * @param where The operation being attempted. + */ +void throwExcIndexNotFound (const char* where) +{ + throw ExcIndexNotFound (where); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + */ +ExcIncomparableEL::ExcIncomparableEL() + : std::runtime_error ("SG::ExcIncomparableEL: Attempt to compare an ElementLink that does not have a SG key or index.") +{ + AthLinks_error(); +} + + +/** + * @brief Throw a SG::ExcIncomparableSG exception. + */ +void throwExcIncomparableEL() +{ + throw ExcIncomparableEL(); +} + + +} // namespace SG diff --git a/EDM/athena/Control/AthLinks/test/AssociationMap_test.cxx b/EDM/athena/Control/AthLinks/test/AssociationMap_test.cxx new file mode 100644 index 00000000..67b5b979 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/AssociationMap_test.cxx @@ -0,0 +1,281 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG + +#include "AthLinks/AssociationMap.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/CLASS_DEF.h" +#include <iostream> +#include <vector> + + +#include "SGTools/TestStore.h" +using namespace SGTest; + + +class Cluster +{ +public: + Cluster() : m_e(0.) { }; + Cluster(double e) : m_e(e) { }; + ~Cluster() { }; + double getE() const { return m_e; } +private: + double m_e; +}; + +template <class T> +struct DV : public std::vector<T*> +{ + typedef T base_value_type; +}; + +class ClusterContainer : public DV< Cluster > +{ +public: + ClusterContainer() : DV< Cluster >() { }; + virtual ~ClusterContainer() { }; +}; + +CLASS_DEF( ClusterContainer, 12345, 1) + +class Track +{ +public: + Track() : m_p(0.) { }; + Track(double p) : m_p(p) { }; + ~Track() { }; + double getP() const { return m_p; } +private: + double m_p; +}; + +class TrackContainer : public DV< Track > +{ +public: + TrackContainer() : DV< Track >() { }; + virtual ~TrackContainer() { }; +}; + +CLASS_DEF( TrackContainer, 54321, 1 ) + +class PTAss + : public AssociationMap< ClusterContainer, TrackContainer > +{ +public: + + PTAss() : AssociationMap< ClusterContainer, TrackContainer >() { } + virtual ~PTAss() { } +}; + +CLASS_DEF( PTAss , 94601450 , 1 ) + +class TTAss : public AssociationMap<TrackContainer,TrackContainer> +{ +public: + TTAss() : AssociationMap< TrackContainer, TrackContainer >() { } + virtual ~TTAss() { } +}; + +CLASS_DEF( TTAss, 67890, 1 ) + + +int main() +{ + initTestStore(); + + std::cout << " *** AssociationMap test in progress: " << std::endl; + + std::cout << "Build fake data and associations:" << std::endl; + + ClusterContainer* cCont = new ClusterContainer(); + cCont->push_back(new Cluster(1.)); + cCont->push_back(new Cluster(2.)); + cCont->push_back(new Cluster(3.)); + std::cout << "Cluster Container...............: " << cCont->size() + << " clusters" << std::endl; + + TrackContainer* tCont = new TrackContainer(); + tCont->push_back(new Track(-1.)); + tCont->push_back(new Track(-2.)); + tCont->push_back(new Track(-3.)); + std::cout << "Track Container.................: " << tCont->size() + << " tracks" << std::endl; + + store.record (cCont, "cCont"); + store.record (tCont, "tCont"); + + PTAss* aMap = new PTAss(); + size_t tCtr = 0; + size_t cCtr = 0; + + ///////////////////////////////////////////////// + /// Exploring AssociationMap non-const interface + /// + + ClusterContainer::const_iterator cEnd = cCont->end(); + + for ( ClusterContainer::const_iterator cIter = cCont->begin(); + cIter != cEnd; + ++cIter ) { + for ( tCtr=0; tCtr<tCont->size(); ++tCtr ) { + const Track* aTrack = (*tCont)[tCtr]; + std::cout << "Associate Clusters and Tracks...: [" << cCtr + << "," << tCtr + << "] with data [" + << (*cIter)->getE() + << "," + << aTrack->getP() + << "]" + << std::endl; + try { + if ( 0 == tCtr ) { + aMap->addAssociation(cCont,(*cCont)[cCtr],tCont,(*tCont)[tCtr]); + } + else if ( 1 == tCtr ) { + aMap->addAssociation(ElementLink<ClusterContainer> ("cCont", cCtr), + ElementLink<TrackContainer> ("tCont", tCtr)); + } + else { + aMap->addAssociation(cCont,cCtr,tCont,tCtr); + } + } catch(std::exception& error) { + std::cerr << "Caught std::exception:" << std::endl + << error.what() + << std::endl; + } + } + ++cCtr; + } + + ///////////////////////////////////////////////// + /// Exploring AssociationMap const interface + /// + + const PTAss * const cstMap = aMap; + const Cluster * const myCluster = (*cCont)[0]; + const Track * const myTrack = (*tCont)[0]; + + std::cout << "List of objects in AssociationMap:" << std::endl; + { + PTAss::object_iterator cEnd = cstMap->endObject(); + for ( PTAss::object_iterator cIter = cstMap->beginObject(); + cIter != cEnd; + ++cIter ) { + const Cluster * const theCluster = (*cIter).getObject(); + assert (*(cIter.getObjectLink()) == theCluster); + std::cout << "\tCluster " + << ": " /*<< theCluster->getE()*/ << std::endl; + PTAss::asso_iterator tEnd = cstMap->endAssociation(theCluster); + for ( PTAss::asso_iterator tIter = cstMap->beginAssociation(theCluster); + tIter != tEnd; + ++tIter ) { + const Track * const theTrack = *tIter; + assert (*(tIter.getLink()) == theTrack); + std::cout << "\t\tTrack " + << ": " << theTrack->getP() << std::endl; + const Track * const assoTrack = cstMap->getAssociation( tIter ); + assert( theTrack == assoTrack ); + + assert( tIter == cstMap->findAssociation( theCluster, theTrack ) ); + assert( tIter == cstMap->findAssociation( cIter, theTrack ) ); + + assert( cstMap->containsAssociation( theCluster, theTrack ) ); + assert( cstMap->containsAssociation( theTrack ) ); + + { + std::list<const Cluster*> objectList; + assert( cstMap->getObjects( theTrack, objectList ) ); + assert( tCont->size() == objectList.size() ); + } + + { + std::list<const Cluster*> objectList; + assert( cstMap->getObjects( cstMap->beginAssociation(theCluster), + objectList ) ); + assert( tCont->size() == objectList.size() ); + } + + assert( tCont->size() == cstMap->getNumberOfAssociations(cIter) ); + assert( tCont->size() == cstMap->getNumberOfAssociations(theCluster) ); + } + } + } + + std::cout << "Check that AssociationMap contains myCluster : " + << ( cstMap->containsObject( myCluster ) ? "true" : "false" ) + << std::endl; + + std::cout << "Number of associations for myCluster" + << "= " << cstMap->size( myCluster ) + << std::endl; + assert( tCont->size() == cstMap->size( myCluster ) ); + + { + PTAss::asso_list myTracks; + cstMap->getAssociations( myCluster, myTracks ); + assert( tCont->size() == myTracks.size() ); + } + { + PTAss::asso_list myTracks; + cstMap->getAssociations( cstMap->findObject(myCluster), myTracks ); + assert( tCont->size() == myTracks.size() ); + } + + std::cout << "Number of association objects:" << cstMap->size() << std::endl; + assert( cCtr == cstMap->size() ); + + + //////////////////////////////////////////////////// + /// Exploring AssociationMap with OBJCONT=ASSOCONT + /// + + std::cout << std::endl + << " *** Test AssociationMap<TrackContainer,TrackContainer> :" + << std::endl; + TTAss* ttAsso = new TTAss(); + + ///////////////////////////////////////////////// + /// Exploring AssociationMap non-const interface + /// + + TrackContainer::const_iterator tEnd = tCont->end(); + unsigned int tIdx = 0; + for ( TrackContainer::const_iterator tIter = tCont->begin(); + tIter != tEnd; + ++tIter,++tIdx ) { + unsigned int assoIdx = tIdx+1; + for ( TrackContainer::const_iterator assItr = tIter+1; + assItr != tEnd; + ++assItr,++assoIdx ) { + if ( *tIter != *assItr ) { + std::cout << "Associate Tracks and Tracks...: [" << tIdx + << "," << assoIdx + << "] with data [" + << (*tIter)->getP() + << "," + << (*assItr)->getP() + << "]" + << std::endl; + if ( tIdx - assoIdx == 1 ) { + ttAsso->addAssociation( tCont, *tIter, tCont, *assItr ); + } else { + ttAsso->addAssociation( tCont, tIdx, tCont, assoIdx ); + } + } + }//> loop over tracks to be associated + }//> loop over tracks + + ///////////////////////////////////////////////// + /// Exploring AssociationMap const interface + /// + + const TTAss * const ttMap = ttAsso; + + assert( tCont->size()-1 == ttMap->size( myTrack ) ); + + assert( tCont->size()-1 == ttMap->size() ); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/AthLinks.xml b/EDM/athena/Control/AthLinks/test/AthLinks.xml new file mode 100644 index 00000000..9fe39c06 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/AthLinks.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AthLinksTest" type="makecheck" suite="Examples"> + <package>Control/AthLinks</package> + <timelimit>40</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov, snyder@fnal.gov, binet@cern.ch</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/AthLinks/test/DataLinkBase_test.cxx b/EDM/athena/Control/AthLinks/test/DataLinkBase_test.cxx new file mode 100644 index 00000000..bc4aa16d --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/DataLinkBase_test.cxx @@ -0,0 +1,310 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/DataLinkBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Regression tests for DataLinkBase + */ + +#undef NDEBUG +#include "AthLinks/DataLinkBase.h" +#include "AthLinks/exceptions.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/CLASS_DEF.h" +#include "AthenaKernel/getMessageSvc.h" +#include <iostream> +#include <cassert> + + +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" + + +using namespace SGTest; + + +class DataLinkBase_test + : public DataLinkBase +{ +public: + DataLinkBase_test() {} + DataLinkBase_test(SG::sgkey_t key, CLID clid) : DataLinkBase (key, clid, 0) {} + DataLinkBase_test(const DataLinkBase::ID_type& key, CLID clid) + : DataLinkBase (key, clid, 0) {} + DataLinkBase_test(DataLinkBase::const_pointer_t obj, + CLID clid) : DataLinkBase (obj, clid, 0) {} + DataLinkBase_test(sgkey_t key, const SG::DataProxyHolder& holder) + : DataLinkBase (key, holder) {} + + using DataLinkBase::storableBase; + using DataLinkBase::toStorableObject; + using DataLinkBase::toIdentifiedObject; + using DataLinkBase::throwInvalidLink; +}; + + +struct Foo +{ + Foo (int the_x) : x (the_x) {} + virtual ~Foo() {} + int x; +}; +const unsigned int fooclid = 23423556; +CLASS_DEF (Foo, fooclid, 1) + + +struct Bar + : public Foo +{ + Bar (int the_x) : Foo (the_x) {} + virtual ~Bar() {} +}; +const unsigned int barclid = 23423557; +CLASS_DEF (Bar, barclid, 1) + + +void* foocast (SG::DataProxy*) +{ + return 0; +} + + +void test1() +{ + std::cout << "test1\n"; + + DataLinkBase_test l1; + assert (l1.isDefault()); + assert (l1.dataID() == ""); + assert (l1.key() == 0); + assert (l1.storableBase (foocast, fooclid) == 0); + assert (l1.proxy() == 0); + assert (l1.source() == 0); + + Foo* foo1 = new Foo(1); + store.record (foo1, "foo1"); + TestStore::sgkey_t sgkey1 = store.stringToKey ("foo1", fooclid); + TestStore::sgkey_t sgkey3 = store.stringToKey ("foo3", fooclid); + + // An object not in SG + Foo* foo2 = new Foo(2); + + // toStorableObject + + l1.toStorableObject (foo1, fooclid, 0); + assert (!l1.isDefault()); + assert (l1.dataID() == "foo1"); + assert (l1.key() == sgkey1); + assert (l1.storableBase (foocast, fooclid) == foo1); + assert (l1.proxy()->name() == "foo1"); + assert (l1.source() == &store); + + l1.toStorableObject (foo2, fooclid, 0); + assert (!l1.isDefault()); + assert (l1.dataID() == ""); + assert (l1.key() == 0); + assert (l1.storableBase (foocast, fooclid) == foo2); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, + assert (l1.proxy()->name() == "foo2")); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, + assert (l1.source() == &store)); + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, + l1.toStorableObject (foo1, barclid, 0)); + + // toIdentifiedObject with string key + + l1.toIdentifiedObject ("foo1", fooclid, 0); + assert (!l1.isDefault()); + assert (l1.dataID() == "foo1"); + assert (l1.key() == sgkey1); + assert (l1.storableBase (foocast, fooclid) == foo1); + assert (l1.proxy()->name() == "foo1"); + assert (l1.source() == &store); + + l1.toIdentifiedObject ("foo3", fooclid, 0); + assert (!l1.isDefault()); + assert (l1.dataID() == "foo3"); + assert (l1.key() == sgkey3); + assert (l1.storableBase (foocast, fooclid) == 0); + assert (l1.proxy()->name() == "foo3"); + assert (l1.source() == &store); + + // toIdentifiedObject with hashed key + + l1.toIdentifiedObject (sgkey1, fooclid, 0); + assert (!l1.isDefault()); + assert (l1.dataID() == "foo1"); + assert (l1.key() == sgkey1); + assert (l1.storableBase (foocast, fooclid) == foo1); + assert (l1.proxy()->name() == "foo1"); + assert (l1.source() == &store); + + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, + l1.toIdentifiedObject (sgkey1, barclid, 0)); + + l1.toIdentifiedObject (sgkey3, fooclid, 0); + assert (!l1.isDefault()); + assert (l1.dataID() == "foo3"); + assert (l1.key() == sgkey3); + assert (l1.storableBase (foocast, fooclid) == 0); + assert (l1.proxy()->name() == "foo3"); + assert (l1.source() == &store); + + + l1.clear(); + assert (l1.isDefault()); + assert (l1.dataID() == ""); + assert (l1.key() == 0); + assert (l1.storableBase (foocast, fooclid) == 0); + assert (l1.proxy() == 0); + assert (l1.source() == 0); + + DataLinkBase_test l2 (foo1, fooclid); + assert (!l2.isDefault()); + assert (l2.dataID() == "foo1"); + assert (l2.key() == sgkey1); + assert (l2.storableBase (foocast, fooclid) == foo1); + assert (l2.proxy()->name() == "foo1"); + assert (l2.source() == &store); + + DataLinkBase_test l3 (static_cast<std::string>("foo1"), fooclid); + assert (!l3.isDefault()); + assert (l3.dataID() == "foo1"); + assert (l3.key() == sgkey1); + assert (l3.storableBase (foocast, fooclid) == foo1); + assert (l3.proxy()->name() == "foo1"); + assert (l3.source() == &store); + + DataLinkBase_test l4 (sgkey1, fooclid); + assert (!l4.isDefault()); + assert (l4.dataID() == "foo1"); + assert (l4.key() == sgkey1); + assert (l4.storableBase (foocast, fooclid) == foo1); + assert (l4.proxy()->name() == "foo1"); + assert (l4.source() == &store); + + SG::DataProxyHolder holder; + holder.toIdentifiedObject ("foo1", fooclid, 0); + DataLinkBase_test l5 (sgkey1, holder); + assert (!l5.isDefault()); + assert (l5.dataID() == "foo1"); + assert (l5.key() == sgkey1); + assert (l5.storableBase (foocast, fooclid) == foo1); + assert (l5.proxy()->name() == "foo1"); + assert (l5.source() == &store); +} + + +// toPersistent / toTransient +void test2() +{ + std::cout << "test2\n"; + + Foo* foo4 = new Foo(4); + store.record (foo4, "foo4"); + TestStore::sgkey_t sgkey4 = store.stringToKey ("foo4", fooclid); + + DataLinkBase_test l1 (sgkey4, fooclid); + l1.toTransient(); + assert (!l1.isDefault()); + assert (l1.dataID() == "foo4"); + assert (l1.key() == sgkey4); + assert (l1.storableBase (foocast, fooclid) == foo4); + assert (l1.proxy()->name() == "foo4"); + assert (l1.source() == &store); + + l1.clear(); + assert (l1.toPersistentNoRemap() == true); + assert (l1.key() == 0); + + Foo* foo5 = new Foo(5); + l1.toStorableObject (foo5, fooclid, 0); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, l1.toPersistentNoRemap()); + assert (l1.key() == 0); + + l1.toIdentifiedObject ("foo4", fooclid, 0); + l1.toPersistentNoRemap(); + assert (l1.key() == sgkey4); + + assert (l1.toPersistent() == true); + assert (l1.key() == sgkey4); + + store.remap<Foo> ("foo4", "foo4", 0, 0); + assert (l1.toPersistent() == true); + assert (l1.key() == sgkey4); + assert (l1.dataID() == "foo4"); + + store.remap<Foo> ("foo4", "foo4a", 0, 0); + assert (l1.toPersistent() == true); + assert (l1.dataID() == "foo4a"); + assert (l1.key() == store.stringToKey ("foo4a", fooclid)); +} + + +// alt store +void test3() +{ + std::cout << "test3\n"; + + TestStore store2; + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// equality +void test4() +{ + std::cout << "test4\n"; + + Foo* foo5 = new Foo(5); + + DataLinkBase_test l1; + DataLinkBase_test l2; + + assert (l1 == l2); + assert (!(l1 != l2)); + + l1.toStorableObject (foo5, fooclid, 0); + store.record (foo5, "foo5"); + l2.toIdentifiedObject ("foo5", fooclid, 0); + assert (l1 == l2); + assert (l2 == l1); + assert (!(l1 != l2)); + assert (!(l2 != l1)); + l2.toIdentifiedObject ("foo6", fooclid, 0); + assert (!(l1 == l2)); + assert (!(l2 == l1)); + assert (l1 != l2); + assert (l2 != l1); +} + + +// other +void test5() +{ + std::cout << "test5\n"; + + DataLinkBase_test l1; + l1.toIdentifiedObject ("foo6", fooclid, 0); + EXPECT_EXCEPTION (SG::ExcInvalidLink, l1.throwInvalidLink()); +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + SGTest::initTestStore(); + + test1(); + test2(); + test3(); + test4(); + test5(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/DataLink_test.cxx b/EDM/athena/Control/AthLinks/test/DataLink_test.cxx new file mode 100644 index 00000000..b09502c7 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/DataLink_test.cxx @@ -0,0 +1,382 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/DataLink_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Regression tests for DataLink + */ + +#undef NDEBUG +#include "AthLinks/DataLink.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/CLASS_DEF.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/DataProxy.h" +#include "SGTools/ClassID_traits.h" +#include "SGTools/TransientAddress.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/getMessageSvc.h" +#include <iostream> +#include <cstdlib> +#include <cassert> + + +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" + + +using namespace SGTest; + + +struct Foo +{ + Foo (int the_x) : x (the_x) {} + virtual ~Foo() {} + int x; +}; +const unsigned int fooclid = 23423556; +CLASS_DEF (Foo, fooclid, 1) + + +struct Bar + : public Foo +{ + Bar (int the_x) : Foo (the_x) {} + virtual ~Bar() {} +}; +const unsigned int barclid = 23423557; +CLASS_DEF (Bar, barclid, 1) + + +void test1() +{ + std::cout << "test1\n"; + + DataLink<Foo> dl1; + assert (dl1.isDefault()); + assert (!dl1.isValid()); + assert (!dl1); + assert (dl1.cptr() == 0); + assert (dl1.getDataPtr() == 0); + assert (dl1.getDataNonConstPtr() == 0); + assert (dl1.dataID() == ""); + assert (dl1.key() == 0); + assert (dl1.source() == 0); + + assert (dl1.classID() == fooclid); + + DataLink<Foo> dl2 ((Foo*)0); + assert (dl2.isDefault()); + assert (!dl2.isValid()); + assert (!dl2); + assert (dl2.cptr() == 0); + assert (dl2.getDataPtr() == 0); + assert (dl2.getDataNonConstPtr() == 0); + assert (dl2.dataID() == ""); + assert (dl2.key() == 0); + assert (dl2.source() == 0); + + assert (dl1 == dl2); + assert (! (dl1 != dl2)); + + Foo* foo2 = new Foo(10); + + store.record (foo2, "foo2"); + DataLink<Foo> dl3 (foo2); + assert (!dl3.isDefault()); + assert (dl3.isValid()); + assert (!!dl3); + assert (dl3.cptr() == foo2); + assert (dl3->x == 10); + assert ((*dl3).x == 10); + const Foo* foo2a = dl3; + assert (foo2a = foo2); + assert (foo2 == dl3.getDataPtr()); + assert (foo2 == dl3.getDataNonConstPtr()); + assert (dl3.source() == &store); + + Bar* bar = new Bar (5); + store.record (bar, "bar"); + + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, DataLink<Foo> dlx (bar)); + + DataLink<Bar> dlb (bar); + assert (dlb.isValid()); + + DataLink<Foo> dl4 (dl3); + assert (dl4.cptr() == foo2); + assert (dl4 == dl3); + assert (dl4 != dl1); + assert (dl4.dataID() == "foo2"); + assert (dl4.key() == store.stringToKey ("foo2", fooclid)); + + dl4.clear(); + assert (dl4.isDefault()); + assert (dl4.cptr() == 0); + dl4 = dl3; + assert (dl4.cptr() == foo2); + dl4.clear(); + assert (dl4.isDefault()); + assert (dl4.cptr() == 0); + + const Foo& foo2b = *foo2; + DataLink<Foo> dl5 (foo2b); + assert (dl5.cptr() == foo2); + + DataLink<Foo> dl6 ("foo2"); + assert (!dl6.isDefault()); + assert (dl6.isValid()); + assert (!!dl6); + assert (dl6.cptr() == foo2); + assert (dl6->x == 10); + + TestStore::sgkey_t sgkey = store.stringToKey ("foo2", fooclid); + DataLink<Foo> dl7 (sgkey); + assert (!dl7.isDefault()); + assert (dl7.isValid()); + assert (!!dl7); + assert (dl7.cptr() == foo2); + assert (dl7->x == 10); + + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, + { + TestStore::sgkey_t sgkey_x = + store.stringToKey ("bar", barclid); + DataLink<Foo> dlx (sgkey_x); + }); + + TestStore store2; + Foo* foo3 = new Foo(20); + store2.record (foo3, "foo2"); + + DataLink<Foo> dl8 (foo3, &store2); + assert (dl8.cptr() == foo3); + DataLink<Foo> dl9 (*foo3, &store2); + assert (dl9.cptr() == foo3); + DataLink<Foo> dl10 ("foo2", &store2); + assert (dl10.cptr() == foo3); + DataLink<Foo> dl11 (sgkey, &store2); + assert (dl11.cptr() == foo3); + assert (dl11.source() == &store2); + + Foo* foo4 = new Foo(40); + + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, dl3.toStorableObject (*bar)); + + store.record (foo4, "foo4"); + dl3.toStorableObject (*foo4); + assert (dl3.cptr() == foo4); + dl3.toStorableObject (*foo3, &store2); + assert (dl3.cptr() == foo3); + + dl3.toIdentifiedObject ("foo2", &store); + assert (dl3.cptr() == foo2); + dl3.toIdentifiedObject ("foo4"); + assert (dl3.cptr() == foo4); + + dl3.toIdentifiedObject (sgkey); + assert (dl3.cptr() == foo2); + dl3.toIdentifiedObject (sgkey, &store2); + assert (dl3.cptr() == foo3); + + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, + { + TestStore::sgkey_t sgkey_x = + store.stringToKey ("bar", barclid); + dl3.toIdentifiedObject (sgkey_x, &store); + }); + + Foo* foox = new Foo(50); + store.record (foox, ""); + dl4.toDefaultObject(); + assert (dl4.cptr() == foox); + + DataLink<Foo> dl30; + + EXPECT_EXCEPTION (SG::ExcInvalidLink, *dl30); + + dl30.toIdentifiedObject ("foo30"); + EXPECT_EXCEPTION (SG::ExcInvalidLink, *dl30); + + Foo* foo30 = new Foo(30); + store.record (foo30, "foo30"); + const Foo& rfoo30 = *dl30; + assert (&rfoo30 == foo30); + + SG::DataProxyHolder holder; + holder.toIdentifiedObject ("foo2", fooclid, 0); + DataLink<Foo> l50 (sgkey, holder); + assert (!l50.isDefault()); + assert (l50.dataID() == "foo2"); + assert (l50.key() == sgkey); + assert (l50.cptr() == foo2); + assert (l50.proxy()->name() == "foo2"); + assert (l50.source() == &store); +} + + +class DataLinkBase_test +{ +public: + static void setLink (DataLinkBase& l, DataLinkBase::sgkey_t key) + { + l.m_persKey = key; + } +}; + + +// toTransient, toPersistent +void test2() +{ + std::cout << "test2\n"; + + TestStore::sgkey_t sgkey = store.stringToKey ("foo5", fooclid); + + Foo* foo5 = new Foo(50); + store.record (foo5, "foo5"); + DataLink<Foo> dl; + DataLinkBase_test::setLink (dl, sgkey); + dl.toTransient(); + assert (dl.cptr() == foo5); + + DataLink<Foo> dl2; + dl2.toPersistent(); + assert (!dl2); + dl2.toIdentifiedObject ("foo5"); + assert (dl2.cptr() == foo5); + dl2.toPersistent(); + assert (dl2.cptr() == foo5); + + + Foo* foo6 = new Foo(60); + store.record (foo6, "foo6"); + Foo* foo7 = new Foo(70); + store.record (foo7, "foo7"); + store.remap<Foo> ("foo6", "foo7"); + + dl2.toIdentifiedObject ("foo6"); + assert (dl2.cptr() == foo6); + dl2.toPersistent(); + assert (dl2.cptr() == foo7); +} + + +// default store setting +void test3() +{ + std::cout << "test3\n"; + + TestStore store2; + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// dummy proxy creation. +void test4() +{ + std::cout << "test4\n"; + + DataLink<Foo> dl1; + dl1.toIdentifiedObject ("foo20"); + assert (!dl1.isDefault()); + assert (dl1.dataID() == "foo20"); + assert (dl1.classID() == fooclid); + assert (!dl1.isValid()); + + TestStore::sgkey_t sgkey = store.stringToKey ("foo20", fooclid); + assert (dl1.key() == sgkey); + Foo* foo20 = new Foo(20); + store.record (foo20, "foo20"); + assert (dl1.isValid()); + assert (dl1.cptr() == foo20); + + TestStore store2; + TestStore::sgkey_t sgkey2 = store2.stringToKey ("foo21", fooclid); + + DataLink<Foo> dl2; + dl2.toIdentifiedObject (sgkey2); + assert (!dl2.isDefault()); + assert (dl2.key() == sgkey2); + assert (dl2.dataID() == ""); + assert (dl2.classID() == fooclid); + assert (!dl2.isValid()); + + Foo* foo21 = new Foo(21); + store.record (foo21, "foo21"); + assert (dl2.isValid()); + assert (dl2.cptr() == foo21); + + TestStore::sgkey_t sgkey3 = store.stringToKey ("foo22", fooclid); + + DataLink<Foo> dl3; + dl3.toIdentifiedObject (sgkey3); + assert (!dl3.isDefault()); + assert (dl3.key() == sgkey3); + assert (dl3.dataID() == "foo22"); + assert (dl3.classID() == fooclid); + assert (!dl3.isValid()); + + Foo* foo22 = new Foo(22); + store.record (foo22, "foo22"); + assert (dl3.isValid()); + assert (dl3.cptr() == foo22); + + TestStore::sgkey_t sgkey4 = store.stringToKey ("foo23", barclid); + DataLink<Foo> dl4; + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, dl4.toIdentifiedObject (sgkey4)); +} + + +// references to pointers not in SG. +void test5() +{ + std::cout << "test5\n"; + + Foo* foo1 = new Foo(101); + DataLink<Foo> dl1 (foo1); + assert (!dl1.isDefault()); + assert (dl1.isValid()); + assert (!!dl1); + assert (dl1.cptr() == foo1); + assert (dl1.getDataPtr() == foo1); + assert (dl1.getDataNonConstPtr() == foo1); + assert (dl1.key() == 0); + assert (dl1.dataID() == ""); + + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, dl1.source()); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, dl1.toPersistent()); + + store.record (foo1, "foo101"); + assert (dl1.dataID() == "foo101"); + assert (dl1.source() == &store); + assert (dl1.key() == 0); + dl1.toPersistent(); + + TestStore::sgkey_t sgkey101 = store.stringToKey ("foo101", fooclid); + assert (dl1.key() == sgkey101); + + Foo* foo2 = new Foo(102); + dl1.toStorableObject (*foo2); + assert (dl1.cptr() == foo2); + assert (dl1.key() == 0); +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + initTestStore(); + + test1(); + test2(); + test3(); + test4(); + test5(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/DataProxyHolder_test.cxx b/EDM/athena/Control/AthLinks/test/DataProxyHolder_test.cxx new file mode 100644 index 00000000..f05157e8 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/DataProxyHolder_test.cxx @@ -0,0 +1,355 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/DataProxyHolder_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Regression tests for DataProxyHolder + */ + +#undef NDEBUG +#include "AthLinks/tools/DataProxyHolder.h" +#include "AthLinks/exceptions.h" +#include "SGTools/CLASS_DEF.h" +#include "AthenaKernel/getMessageSvc.h" +#include "AthenaKernel/errorcheck.h" +#include <iostream> +#include <cassert> + + +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" +#include "TestThinningSvc.icc" + + +using namespace SGTest; + + +struct Foo +{ + Foo (int the_x) : x (the_x) {} + virtual ~Foo() {} + int x; +}; +const unsigned int fooclid = 23423556; +CLASS_DEF (Foo, fooclid, 1) + + +struct Bar + : public Foo +{ + Bar (int the_x) : Foo (the_x) {} + virtual ~Bar() {} +}; +const unsigned int barclid = 23423557; +CLASS_DEF (Bar, barclid, 1) + + +void* foocast (SG::DataProxy*) +{ + return 0; +} + + +void test1() +{ + std::cout << "test1\n"; + + SG::DataProxyHolder h1; + assert (h1.isDefault()); + assert (h1.dataID() == ""); + assert (h1.storableBase (foocast, fooclid) == 0); + assert (h1.proxy() == 0); + assert (h1.source() == 0); + + Foo* foo1 = new Foo(1); + store.record (foo1, "foo1"); + TestStore::sgkey_t sgkey1 = store.stringToKey ("foo1", fooclid); + TestStore::sgkey_t sgkey3 = store.stringToKey ("foo3", fooclid); + TestStore::sgkey_t sgkey3x = store.stringToKey ("foo3x", fooclid); + + // An object not in SG + Foo* foo2 = new Foo(2); + + // toStorableObject + + assert (h1.toStorableObject (foo1, fooclid, 0) == sgkey1); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo1"); + assert (h1.storableBase (foocast, fooclid) == foo1); + assert (h1.proxy()->name() == "foo1"); + assert (h1.source() == &store); + + assert (h1.toStorableObject (foo2, fooclid, 0) == 0); + assert (!h1.isDefault()); + assert (h1.dataID() == ""); + assert (h1.storableBase (foocast, fooclid) == foo2); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, + assert (h1.proxy()->name() == "foo2")); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, + assert (h1.source() == &store)); + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, + h1.toStorableObject (foo1, barclid, 0)); + + // toIdentifiedObject with string key + + assert (h1.toIdentifiedObject ("foo1", fooclid, 0) == sgkey1); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo1"); + assert (h1.storableBase (foocast, fooclid) == foo1); + assert (h1.proxy()->name() == "foo1"); + assert (h1.source() == &store); + + assert (h1.toIdentifiedObject ("foo3", fooclid, 0) == sgkey3); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo3"); + assert (h1.storableBase (foocast, fooclid) == 0); + assert (h1.proxy()->name() == "foo3"); + assert (h1.source() == &store); + + // toIdentifiedObject with hashed key + + store.m_missedProxies.clear(); + h1.toIdentifiedObject (sgkey1, fooclid, 0); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo1"); + assert (h1.storableBase (foocast, fooclid) == foo1); + assert (h1.proxy()->name() == "foo1"); + assert (h1.source() == &store); + assert (store.m_missedProxies.empty()); + + EXPECT_EXCEPTION (SG::ExcCLIDMismatch, + h1.toIdentifiedObject (sgkey1, barclid, 0)); + + h1.toIdentifiedObject (sgkey3, fooclid, 0); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo3"); + assert (h1.storableBase (foocast, fooclid) == 0); + assert (h1.proxy()->name() == "foo3"); + assert (h1.source() == &store); + + h1.toIdentifiedObject (sgkey3x, fooclid, 0); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo3x"); + assert (h1.storableBase (foocast, fooclid) == 0); + assert (h1.proxy()->name() == "foo3x"); + assert (h1.source() == &store); + assert (store.m_missedProxies.size() == 1); + assert (store.m_missedProxies[0].first == fooclid); + assert (store.m_missedProxies[0].second == "foo3x"); + + h1.clear(); + assert (h1.isDefault()); + assert (h1.dataID() == ""); + assert (h1.storableBase (foocast, fooclid) == 0); + assert (h1.proxy() == 0); + assert (h1.source() == 0); +} + + +// toPersistent / toTransient +void test2() +{ + std::cout << "test2\n"; + + Foo* foo4 = new Foo(4); + store.record (foo4, "foo4"); + TestStore::sgkey_t sgkey4 = store.stringToKey ("foo4", fooclid); + + SG::DataProxyHolder h1; + h1.toTransient (sgkey4); + assert (!h1.isDefault()); + assert (h1.dataID() == "foo4"); + assert (h1.storableBase (foocast, fooclid) == foo4); + assert (h1.proxy()->name() == "foo4"); + assert (h1.source() == &store); + + h1.clear(); + TestStore::sgkey_t sgkey = 0; + h1.toPersistentNoRemap (sgkey); + assert (sgkey == 0); + + Foo* foo5 = new Foo(5); + h1.toStorableObject (foo5, fooclid, 0); + sgkey = 0; + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, h1.toPersistentNoRemap (sgkey)); + + sgkey = 0; + h1.toIdentifiedObject ("foo4", fooclid, 0); + h1.toPersistentNoRemap (sgkey); + assert (sgkey == sgkey4); + + sgkey = 0; + size_t index = 10; + assert (h1.toPersistent (sgkey, index) == false); + assert (sgkey == sgkey4); + assert (index == 10); + + store.remap<Foo> ("foo4", "foo4", 10, 20); + assert (h1.toPersistent (sgkey, index) == true); + assert (sgkey == sgkey4); + assert (index == 20); + assert (h1.dataID() == "foo4"); + + store.remap<Foo> ("foo4", "foo4a", 10, 20); + index = 10; + assert (h1.toPersistent (sgkey, index) == true); + assert (index == 20); + assert (h1.dataID() == "foo4a"); + assert (sgkey == store.stringToKey ("foo4a", fooclid)); + + h1.toIdentifiedObject ("foo4", fooclid, 0); + std::string sindex = "10"; + sgkey = 0; + assert (h1.toPersistent (sgkey, sindex) == false); + assert (sgkey == sgkey4); + assert (sindex == "10"); +} + + +// alt store +void test3() +{ + std::cout << "test3\n"; + + TestStore store2; + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// equality +void test4() +{ + std::cout << "test4\n"; + + Foo* foo5 = new Foo(5); + + SG::DataProxyHolder h1; + SG::DataProxyHolder h2; + + assert (h1 == h2); + + h1.toStorableObject (foo5, fooclid, 0); + store.record (foo5, "foo5"); + h2.toIdentifiedObject ("foo5", fooclid, 0); + assert (h1 == h2); + assert (h2 == h1); + h2.toIdentifiedObject ("foo6", fooclid, 0); + assert (!(h1 == h2)); + assert (!(h2 == h1)); +} + + +// other +void test5() +{ + std::cout << "test5\n"; + + SG::DataProxyHolder h1; + TestStore::sgkey_t sgkey6 = store.stringToKey ("foo6", fooclid); + assert (h1.toIdentifiedObject ("foo6", fooclid, 0) == sgkey6); + EXPECT_EXCEPTION (SG::ExcInvalidLink, + h1.throwInvalidLink (sgkey6)); +} + + +// thinning +void test6() +{ + std::cout << "test6\n"; + TestThinningSvc svc; + SG::DataProxyHolder h1; + TestStore::sgkey_t sgkey = 0; + size_t index = 10; + + assert (h1.thin (sgkey, index) == false); + assert (sgkey == 0); + assert (index == 10); + + TestStore::sgkey_t sgkey_foo = store.stringToKey ("foo", fooclid); + sgkey = sgkey_foo; + assert (h1.thin (sgkey, index) == false); + assert (sgkey == sgkey_foo); + assert (index == 10); + + TestThinningSvc::instance (&svc, true); + assert (h1.thin (sgkey, index) == false); + assert (sgkey == sgkey_foo); + assert (index == 10); + + Foo* foo = new Foo(0); + store.record (foo, "foo"); + h1.toTransient (sgkey); + assert (h1.thin (sgkey, index) == false); + assert (sgkey == sgkey_foo); + assert (index == 10); + + svc.remap (10, 12); + assert (h1.thin (sgkey, index) == true); + assert (sgkey == sgkey_foo); + assert (index == 12); + + svc.remap (20, IThinningSvc::RemovedIdx); + index = 20; + assert (h1.thin (sgkey, index) == true); + assert (sgkey == 0); + assert (index == 0); +} + + +// converting ctor +void test7() +{ + std::cout << "test7\n"; + + SG::DataProxyHolder dp1; + + // An object not in SG + Bar* bar2 = new Bar(2); + assert (dp1.toStorableObject (bar2, barclid, 0) == 0); + + SG::DataProxyHolder dp2 (dp1, (Bar*)0, (Bar*)0); + assert (dp1.storableBase (foocast, barclid) == bar2); + assert (dp2.storableBase (foocast, barclid) == bar2); + + SG::DataProxyHolder dp3 (dp1, (Bar*)0, (Foo*)0); + assert (dp3.storableBase (foocast, fooclid) == static_cast<Foo*>(bar2)); + + // An object in SG + TestStore::sgkey_t sgkey = store.stringToKey ("bar2", barclid); + store.record (bar2, "bar2"); + SG::DataProxyHolder dp4; + assert (dp4.toIdentifiedObject ("bar2", barclid, 0) == sgkey); + assert (dp4.dataID() == "bar2"); + assert (dp4.storableBase (foocast, barclid) == bar2); + + SG::DataProxyHolder dp5 (dp4, (Bar*)0, (Bar*)0); + assert (dp5.dataID() == "bar2"); + assert (dp5.storableBase (foocast, barclid) == bar2); + + SG::DataProxyHolder dp6 (dp4, (Bar*)0, (Foo*)0); + assert (dp6.dataID() == "bar2"); + assert (dp6.storableBase (foocast, barclid) == bar2); +} + + +int main() +{ + errorcheck::ReportMessage::hideErrorLocus(true); + Athena::getMessageSvcQuiet = true; + SGTest::initTestStore(); + + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/DataPtr_test.cxx b/EDM/athena/Control/AthLinks/test/DataPtr_test.cxx new file mode 100644 index 00000000..46ce0c2a --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/DataPtr_test.cxx @@ -0,0 +1,108 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +#include "AthLinks/DataPtr.h" + +#include <cassert> +#include <iostream> +#include <string> +#include <vector> + + +using namespace std; + +struct Fluff { + virtual ~Fluff() {} + int m_int; + float m_float; + string m_string; + Fluff() : m_int(1), m_float(-379.456f), + m_string("this is the Fluff struct") {} +}; + +struct DerivedFluff : public Fluff { + virtual ~DerivedFluff() {} + string m_anotherString; + DerivedFluff() : + Fluff(), m_anotherString("this is the DerivedFluff struct") {} +}; + +int main () { + typedef vector< DataPtr<int> > IntVector; + IntVector intV; + intV.reserve(10); + + int i; + for (i=0; i<3; ++i) intV.push_back(new int(i)); + + + DataPtr<int> vp3(intV[2]); + + assert (2 == vp3.use_count()); + int* pvp3 = vp3; + const int* cpvp3 = vp3.ptr(); + assert(*cpvp3==*pvp3); + DataPtr<int> vpvp3(vp3); + //FIXME DataPtr<int> vpvp3(pvp3); + // the above causes the cleanup at the end of the job to dump core + // what happens (I think) is that vpvp3 is not aware that it is sharing + // the c++ pointer with vp3, so the ref count is screwed and intV[2] and + // intV[3] end up trying to delete the same c++ pointer + assert (3 == vpvp3.use_count()); + DataPtr<int> vpvpvp3 = vpvp3; + assert(*vpvp3==*intV[2]); + assert (4 == vp3.use_count()); + assert (4 == vpvp3.use_count()); + assert (4 == vpvpvp3.use_count()); + assert(vpvpvp3==vp3); + assert(intV[0]!=vp3); + assert(intV[1]==intV[1]); + assert(!(intV[2]!=intV[2])); + + intV.push_back(vpvp3); + assert (5 == vpvp3.use_count()); + + IntVector::const_iterator it(intV.begin()); + IntVector::const_iterator iEnd(intV.end()); + while (it!=iEnd) { + cout << hex << &*it << "->" << it->ptr() << dec + << " use count " << it->use_count() + << " content " << **it << endl; + ++it; + } + + vector< DataPtr<Fluff> > fluffV; + fluffV.push_back(new Fluff()); + Fluff* pf = fluffV[0]; + assert(pf->m_string==Fluff().m_string); + + + DerivedFluff* pdf(new DerivedFluff()); + DataPtr<Fluff> pDerFluff(pdf); + DerivedFluff* extracted = dynamic_cast<DerivedFluff*>((Fluff*)pDerFluff); + assert (0 != extracted); + assert (extracted->m_anotherString == pdf->m_anotherString); + + + //FIXME here is an error that gets undetected (except when using valgrind) + //we fill a DataPtr with a plain ptr extracted from another DataPtr + //this creates two DataPtrs both with refcnt = 1 pointing to the same obj! + //DataPtr<Fluff> pCopyDerFluff(extracted); + //DerivedFluff* reextracted = dynamic_cast<DerivedFluff*>((Fluff*)pCopyDerFluff); + //assert (0 != reextracted); + //assert (reextracted->m_anotherString == pdf->m_anotherString); + + DataPtr<Fluff> pBadCopyFluff(pDerFluff); + DerivedFluff* badextracted = dynamic_cast<DerivedFluff*>((Fluff*)pBadCopyFluff); + assert (0 != badextracted); + assert (badextracted->m_anotherString == pdf->m_anotherString); + + + cerr << "*** DataPtr_test OK ***" <<endl; + return 0; + +} + + diff --git a/EDM/athena/Control/AthLinks/test/ELFCont.h b/EDM/athena/Control/AthLinks/test/ELFCont.h new file mode 100644 index 00000000..672dea66 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/ELFCont.h @@ -0,0 +1,34 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/ELFCont.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2015 + * @brief Test for ElementLink forward declaration. + */ + + +#ifndef ATHLINKS_ELFCONT_H +#define ATHLINKS_ELFCONT_H + + +#include "ELFElt.h" +#include "SGTools/CLASS_DEF.h" +#include <vector> + + +class ELFCont + : public std::vector<ELFElt*> +{ +}; + + +CLASS_DEF( ELFCont , 171212016 , 1 ) + + +#endif // not ATHLINKS_ELFCONT_H diff --git a/EDM/athena/Control/AthLinks/test/ELFElt.h b/EDM/athena/Control/AthLinks/test/ELFElt.h new file mode 100644 index 00000000..c0cf3334 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/ELFElt.h @@ -0,0 +1,45 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/ELFElt.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2015 + * @brief Test for ElementLink forward declaration. + */ + + +#ifndef ATHLINKS_ELFELT_H +#define ATHLINKS_ELFELT_H + + +#include "AthLinks/ElementLink.h" + + +class ELFCont; +class ELFElt; + + +ELEMENTLINK_FWD(ELFCont, ELFElt); + + +class ELFElt +{ +public: + ELFElt(int x) : m_x(x) {} + int x() const { return m_x; } + void setLink (const std::string& key, int ndx); + + const ELFElt* ptr() const; + +private: + int m_x; + ElementLink<ELFCont> m_link; +}; + + +#endif // not ATHLINKS_ELFELT_H diff --git a/EDM/athena/Control/AthLinks/test/ElementLinkBase_test.cxx b/EDM/athena/Control/AthLinks/test/ElementLinkBase_test.cxx new file mode 100644 index 00000000..289e167a --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/ElementLinkBase_test.cxx @@ -0,0 +1,547 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/ElementLinkBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for ElementLinkBase + */ + + +#undef NDEBUG +#include "AthLinks/ElementLinkBase.h" +#include "AthLinks/exceptions.h" +#include "AthLinks/tools/ForwardIndexingPolicy.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/CLASS_DEF.h" +#include "AthenaKernel/getMessageSvc.h" +#include <vector> +#include <iostream> +#include <cstdlib> +#include <cassert> + + +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" +#include "TestThinningSvc.icc" + + +using namespace SGTest; + + +struct Foo +{ + Foo (int the_x = 0) : x (the_x) {} + virtual ~Foo() {} + int x; + + bool operator== (const Foo& other) const + { return x == other.x; } + bool operator!= (const Foo& other) const + { return x != other.x; } +}; + +typedef std::vector<Foo*> FooCont; + +const unsigned int fooclid = 23423556; +CLASS_DEF (FooCont, fooclid, 1) +CLASS_DEF (std::vector<Foo>, 23423558, 1) + +// Ensure an offset between Bar and Foo base. +struct XXX { virtual ~XXX(){} XXX():x(0){} int x; }; + +struct Bar + : public XXX, public Foo +{ + Bar (int the_y = 0) : Foo(the_y+10), y (the_y) {} + int y; +}; + +struct BarCont + : public XXX, public FooCont +{ + typedef Bar* value_type; + struct const_iterator + : public FooCont::const_iterator + { + const_iterator (FooCont::const_iterator it) + : FooCont::const_iterator (it) {} + Bar* operator*() const { + const FooCont::const_iterator* baseit= static_cast<const FooCont::const_iterator*>(this); + return static_cast<Bar*> (**baseit); + } + }; + const_iterator begin() const { return const_iterator(FooCont::begin()); } + const_iterator end() const { return const_iterator(FooCont::end()); } + Bar* operator[] (size_t i) const + { + const FooCont* base = static_cast<const FooCont*> (this); + return static_cast<Bar*> ((*base)[i]); + } +}; + + +const unsigned int barclid = 23423566; +CLASS_DEF (BarCont, barclid, 1) +CLASS_DEF (std::vector<Bar>, 23423568, 1) + +SG_BASE(Bar, Foo); +SG_BASE(BarCont, FooCont); + + +struct FooTraits +{ + typedef FooCont Storable; + typedef SG::ForwardIndexingPolicy<FooCont> IndexingPolicy; +}; + + +struct BarTraits +{ + typedef BarCont Storable; + typedef SG::ForwardIndexingPolicy<BarCont> IndexingPolicy; +}; + + +class ElementLinkBase_test + : public ElementLinkBase +{ +public: + ElementLinkBase_test() {} + ElementLinkBase_test(const std::string& key, CLID clid, unsigned index, + IProxyDict* sg) + : ElementLinkBase (key, clid, index, sg) {} + ElementLinkBase_test(SG::sgkey_t key, CLID clid, unsigned index, + IProxyDict* sg) + : ElementLinkBase (key, clid, index, sg) {} + ElementLinkBase_test(const std::string& key, CLID clid, unsigned index, + const void* elt, IProxyDict* sg) + : ElementLinkBase (key, clid, index, elt, sg) {} + ElementLinkBase_test(SG::sgkey_t key, CLID clid, unsigned index, + const void* elt, IProxyDict* sg) + : ElementLinkBase (key, clid, index, elt, sg) {} + ElementLinkBase_test(const void* obj, CLID clid, index_type index, + IProxyDict* sg) + : ElementLinkBase (obj, clid, index, sg) {} + template <class FROM_STORABLE, class TO_STORABLE> + ElementLinkBase_test (const ElementLinkBase& other, + FROM_STORABLE* from, TO_STORABLE* to) + : ElementLinkBase (other, from, to) {} + using ElementLinkBase::getCachedElement; + using ElementLinkBase::storableBase; + using ElementLinkBase::storedIndex; + using ElementLinkBase::toIndexedElement; + using ElementLinkBase::setCachedElement; + using ElementLinkBase::setIndex; + using ElementLinkBase::setStorableObject; + using ElementLinkBase::resetWithKeyAndIndex; + using ElementLinkBase::proxyHolder; + + void setLink (SG::sgkey_t key, + unsigned int index) + { + m_persKey = key; + m_persIndex = index; + } +}; + + +void test1() +{ + std::cout << "test1\n"; + + typedef ElementLinkBase_test Link; + typedef const Foo* element_t; + typedef const element_t* element_const_pointer; + element_const_pointer eltp = 0; + + FooCont* foocont = new FooCont; + foocont->push_back (new Foo(0)); + foocont->push_back (new Foo(1)); + foocont->push_back (new Foo(2)); + foocont->push_back (new Foo(3)); + const Foo* elt2 = (*foocont)[2]; + std::string key = "foocont"; + store.record (foocont, key); + Link::index_type index1 = 1; + Link::index_type index2 = 2; + TestStore::sgkey_t sgkey = store.stringToKey (key, fooclid); + + Link::index_type null_index = static_cast<Link::index_type>(-1); + + FooCont* foocont2 = new FooCont; + foocont2->push_back (new Foo(11)); + foocont2->push_back (new Foo(12)); + foocont2->push_back (new Foo(13)); + foocont2->push_back (new Foo(14)); + std::string key2 = "foocont2"; + store.record (foocont2, key2); + Link::index_type index1b = 1; + Link::index_type index2b = 2; + TestStore::sgkey_t sgkey2 = store.stringToKey (key2, fooclid); + + Link el1; + assert (el1.isDefault()); + assert (el1.index() == null_index); + assert (el1.persIndex() == static_cast<Link::stored_index_type>(null_index)); + assert (el1.storableBase (0, fooclid) == 0); + assert (el1.dataID() == ""); + assert (el1.key() == 0); + assert (el1.persKey() == 0); + assert (el1.source() == 0); + eltp = 0; + assert (!el1.getCachedElement(eltp)); + assert (eltp == 0); + assert (el1.proxy() == 0); + assert (!el1.hasCachedElement()); + assert (el1.storedIndex() == static_cast<Link::stored_index_type>(null_index)); + + Link el2 (key, fooclid, index2, 0); + eltp = 0; + assert (!el2.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el2.isDefault()); + assert (el2.index() == index2); + assert (el2.persIndex() == index2); + assert (el2.dataID() == key); + assert (el2.key() == sgkey); + assert (el2.persKey() == sgkey); + assert (el2.source() == &store); + assert (el2.proxy()->name() == key); + assert (el2.proxy() == el2.proxyHolder().proxy()); + assert (!el2.hasCachedElement()); + assert (el2.storedIndex() == index2); + assert (el2.storableBase (0, fooclid) == foocont); + + Link el3 (sgkey, fooclid, index2, 0); + eltp = 0; + assert (!el3.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el3.isDefault()); + assert (el3.index() == index2); + assert (el3.dataID() == key); + assert (el3.key() == sgkey); + assert (el3.source() == &store); + assert (!el3.hasCachedElement()); + assert (el3.storableBase (0, fooclid) == foocont); + + Link el4 (key, fooclid, index2, elt2, 0); + eltp = 0; + assert (el4.getCachedElement(eltp)); + assert (*eltp == elt2); + assert (!el4.isDefault()); + assert (el4.index() == index2); + assert (el4.dataID() == key); + assert (el4.key() == sgkey); + assert (el4.source() == &store); + assert (el4.hasCachedElement()); + assert (el4.storableBase (0, fooclid) == foocont); + + Link el5 (sgkey, fooclid, index2, elt2, 0); + eltp = 0; + assert (el5.getCachedElement(eltp)); + assert (*eltp == elt2); + assert (!el5.isDefault()); + assert (el5.index() == index2); + assert (el5.dataID() == key); + assert (el5.key() == sgkey); + assert (el5.source() == &store); + assert (el5.storableBase (0, fooclid) == foocont); + assert (el5.hasCachedElement()); + + Link el6 (foocont2, fooclid, index2b, 0); + assert (!el6.isDefault()); + assert (el6.index() == index2b); + assert (el6.dataID() == key2); + assert (el6.key() == sgkey2); + assert (el6.source() == &store); + assert (el6.storableBase (0, fooclid) == foocont2); + eltp = 0; + assert (!el6.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el6.hasCachedElement()); + + Link el7 (el6); + assert (!el7.isDefault()); + assert (el7.index() == index2b); + assert (el7.dataID() == key2); + assert (el7.key() == sgkey2); + assert (el7.source() == &store); + assert (el7.storableBase (0, fooclid) == foocont2); + eltp = 0; + assert (!el7.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el7.hasCachedElement()); + + el1 = el7; + assert (!el1.isDefault()); + assert (el1.index() == index2b); + assert (el1.dataID() == key2); + assert (el1.key() == sgkey2); + assert (el1.source() == &store); + assert (el1.storableBase (0, fooclid) == foocont2); + eltp = 0; + assert (!el1.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el1.hasCachedElement()); + + Link el8; + assert (el8.isDefault()); + assert (el8.toIndexedElement (foocont, fooclid, index1, 0)); + assert (!el8.isDefault()); + assert (el8.index() == index1); + assert (el8.dataID() == key); + assert (el8.key() == sgkey); + assert (el8.source() == &store); + assert (el8.storableBase (0, fooclid) == foocont); + assert (!el8.toIndexedElement (foocont, fooclid, index1, 0)); + el8.reset(); + assert (el8.isDefault()); + assert (!el8.hasCachedElement()); + eltp = 0; + assert (!el8.getCachedElement(eltp)); + assert (eltp == 0); + el8.setCachedElement (elt2); + assert (el8.hasCachedElement()); + eltp = 0; + assert (el8.getCachedElement(eltp)); + assert (*eltp == elt2); + assert (!el8.toIndexedElement (foocont, fooclid, index1, 0)); + assert (el8.isDefaultIndex()); + assert (el8.storedIndex() == static_cast<Link::stored_index_type>(null_index)); + el8.setIndex (3); + assert (!el8.isDefaultIndex()); + assert (el8.storedIndex() == 3); + assert (!el8.toIndexedElement (foocont, fooclid, index1, 0)); + + Link el11; + el11.setIndex (index2); + assert (el11.setStorableObject (foocont, fooclid, false, 0)); + assert (!el11.isDefault()); + assert (el11.index() == index2); + assert (el11.dataID() == key); + assert (el11.key() == sgkey); + assert (el11.source() == &store); + assert (el11.storableBase (0, fooclid) == foocont); + assert (!el11.hasCachedElement()); + assert (!el11.setStorableObject (foocont2, fooclid, false, 0)); + assert (el11.setStorableObject (foocont2, fooclid, true, 0)); + assert (el11.index() == null_index); + assert (el11.storableBase (0, fooclid) == foocont2); + assert (el11.dataID() == key2); + + Link el12; + el12.setCachedElement (elt2); + assert (el12.hasCachedElement()); + el12.resetWithKeyAndIndex (key2, fooclid, index1b, 0); + assert (!el12.hasCachedElement()); + assert (!el12.isDefault()); + assert (el12.index() == index1b); + assert (el12.dataID() == key2); + assert (el12.key() == sgkey2); + assert (el12.source() == &store); + assert (el12.storableBase (0, fooclid) == foocont2); + + el12.setCachedElement (elt2); + assert (el12.hasCachedElement()); + el12.resetWithKeyAndIndex (sgkey, fooclid, index2, 0); + assert (!el12.hasCachedElement()); + assert (!el12.isDefault()); + assert (el12.index() == index2); + assert (el12.dataID() == key); + assert (el12.key() == sgkey); + assert (el12.source() == &store); + assert (el12.storableBase (0, fooclid) == foocont); + + el12.reset(); + assert (el12.isDefault()); + assert (el12.index() == null_index); + assert (el12.dataID() == ""); + assert (el12.key() == 0); + assert (el12.source() == 0); + assert (el12.storableBase (0, fooclid) == 0); + assert (!el12.hasCachedElement()); +} + + +// toTransient, toPersistent +void test2() +{ + std::cout << "test2\n"; + + TestStore::sgkey_t sgkey = store.stringToKey ("foocont3", fooclid); + + FooCont* foocont3 = new FooCont; + for (int i=0; i < 4; i++) + foocont3->push_back (new Foo(i+200)); + std::string key3 = "foocont3"; + store.record (foocont3, key3); + TestStore::sgkey_t sgkey3 = store.stringToKey (key3, fooclid); + + typedef ElementLinkBase_test Link; + Link el1; + assert (el1.proxy() == 0); + el1.setLink (sgkey, 2); + assert (el1.toTransient()); + assert (!el1.hasCachedElement()); + assert (el1.proxy()->name() == key3); + + Link el2; + assert (el2.toPersistent()); + assert (el2.isDefault()); + el2 = Link (key3, fooclid, 1, 0); + assert (el2.storableBase (0, fooclid) == foocont3); + assert (el2.index() == 1); + assert (el2.key() == sgkey3); + assert (el2.toPersistent()); + assert (el2.storableBase (0, fooclid) == foocont3); + assert (el2.index() == 1); + assert (el2.key() == sgkey3); + + FooCont* foocont3a = new FooCont; + for (int i=0; i < 4; i++) + foocont3a->push_back (new Foo(i+300)); + std::string key3a = "foocont3a"; + TestStore::sgkey_t sgkey3a = store.stringToKey (key3a, fooclid); + store.record (foocont3a, key3a); + + FooCont* foocont3b = new FooCont; + for (int i=0; i < 4; i++) + foocont3b->push_back (new Foo(i+350)); + std::string key3b = "foocont3b"; + TestStore::sgkey_t sgkey3b = store.stringToKey (key3b, fooclid); + store.record (foocont3b, key3b); + + store.remap<FooCont> (key3a, key3b, 2, 1); + + el2 = Link (key3a, fooclid, 2, 0); + assert (el2.index() == 2); + assert (el2.key() == sgkey3a); + assert (el2.toPersistent()); + assert (el2.index() == 1); + assert (el2.key() == sgkey3b); + + el2.reset(); + el2.setIndex (2); + assert (!el2.toPersistent()); + el2.reset(); + el2.setStorableObject (foocont3, fooclid, true, 0); + assert (!el2.toPersistent()); + el2.setIndex (2); + assert (el2.toPersistent()); + + FooCont* foocont4 = new FooCont; + el2.setStorableObject (foocont4, fooclid, true, 0); + el2.setIndex (2); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, el2.toPersistent()); +} + + +// default store setting +void test3() +{ + std::cout << "test3\n"; + TestStore store2; + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// thinning +void test4() +{ + std::cout << "test4\n"; + + TestThinningSvc svc; + TestThinningSvc::instance (&svc, true); + SG::DataProxyHolder h1; + TestStore::sgkey_t sgkey_foo = store.stringToKey ("foo", fooclid); + TestStore::sgkey_t sgkey = sgkey_foo; + size_t index = 10; + h1.toTransient (sgkey); + + assert (h1.thin (sgkey, index) == false); + assert (sgkey == sgkey_foo); + assert (index == 10); + + svc.remap (10, 12); + assert (h1.thin (sgkey, index) == true); + assert (sgkey == sgkey_foo); + assert (index == 12); +} + + +// Converting constructor +void test5() +{ + std::cout << "test5\n"; + + BarCont* bar = new BarCont; + bar->push_back (new Bar (1)); + bar->push_back (new Bar (2)); + bar->push_back (new Bar (3)); + + // Reference to raw element. + ElementLinkBase_test el1; + el1.setCachedElement ((*bar)[1]); + ElementLinkBase_test el2 (el1, (BarTraits*)0, (FooTraits*)0); + + typedef const Foo* foo_element_t; + typedef const Bar* bar_element_t; + typedef const foo_element_t* foo_element_const_pointer; + typedef const bar_element_t* bar_element_const_pointer; + + foo_element_const_pointer foop1 = 0; + bar_element_const_pointer barp1 = 0; + assert (el1.getCachedElement (barp1)); + assert (el2.getCachedElement (foop1)); + assert (*barp1 == (*bar)[1]); + assert (*barp1 == *foop1); + assert (static_cast<const void*>(*barp1) != static_cast<const void*>(*foop1)); + + // Storable not in SG. + ElementLinkBase_test el3 (bar, barclid, 1, nullptr); + ElementLinkBase_test el4 (el3, (BarTraits*)0, (FooTraits*)0); + BarCont* barcont1 = reinterpret_cast<BarCont*>(el3.storableBase (0, barclid)); + FooCont* foocont1 = reinterpret_cast<FooCont*>(el4.storableBase (0, fooclid)); + assert (barcont1 == bar); + assert (barcont1 == foocont1); + assert (static_cast<void*>(barcont1) != static_cast<void*>(foocont1)); + assert (el3.index() == 1); + assert (el4.index() == 1); + assert (el3.key() == 0); + assert (el4.key() == 0); + + // Storable in SG. + std::string key = "barcont"; + store.record (bar, key); + ElementLinkBase_test el5 (key, barclid, 1, nullptr); + ElementLinkBase_test el6 (el5, (BarTraits*)0, (FooTraits*)0); + barcont1 = reinterpret_cast<BarCont*>(el5.storableBase (0, barclid)); + foocont1 = reinterpret_cast<FooCont*>(el6.storableBase (0, fooclid)); + assert (barcont1 == bar); + assert (barcont1 == foocont1); + assert (static_cast<void*>(barcont1) != static_cast<void*>(foocont1)); + assert (el5.index() == 1); + assert (el6.index() == 1); + assert (el5.dataID() == key); + assert (el6.dataID() == key); +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + initTestStore(); + + test1(); + test2(); + test3(); + test4(); + test5(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/ElementLinkFwd_test.cxx b/EDM/athena/Control/AthLinks/test/ElementLinkFwd_test.cxx new file mode 100644 index 00000000..68648c85 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/ElementLinkFwd_test.cxx @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +#include "ELFElt.h" +#include "ELFCont.h" +#include "SGTools/CurrentEventStore.h" +#include "AthenaKernel/getMessageSvc.h" +#include <iostream> +#include <cassert> + + +#include "SGTools/TestStore.h" +using namespace SGTest; + + +void ELFElt::setLink (const std::string& key, int ndx) +{ + m_link.resetWithKeyAndIndex (key, ndx); +} + + +const ELFElt* ELFElt::ptr() const +{ + return *m_link; +} + + +void test1() +{ + std::cout << "test1\n"; + + const int nelt = 5; + ELFCont* cont = new ELFCont; + store.record (cont, "elf"); + for (int i=0; i < nelt; i++) { + cont->push_back (new ELFElt(i)); + (*cont)[i]->setLink ("elf", nelt-1-i); + } + + for (int i=0; i < nelt; i++) { + assert ((*cont)[i]->ptr()->x() == nelt-1-i); + } +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + initTestStore(); + + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/ElementLink_test.cxx b/EDM/athena/Control/AthLinks/test/ElementLink_test.cxx new file mode 100644 index 00000000..6e10c1ae --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/ElementLink_test.cxx @@ -0,0 +1,1189 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +#include "AthLinks/ElementLink.h" +#include "AthLinks/ElementLinkVector.h" +#include "AthLinks/DeclareIndexingPolicy.h" +#include "AthLinks/exceptions.h" +#include "AthLinks/tools/SetIndexingPolicy.h" +#include "AthLinks/tools/MapIndexingPolicy.h" +#include "AthLinks/tools/IdentContIndexingPolicy.h" +#include "AthenaKernel/getMessageSvc.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/CLASS_DEF.h" +#include <vector> +#include <set> +#include <iostream> +#include <cstdlib> +#include <cassert> + + +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" + + +using namespace SGTest; + + +struct Foo +{ + Foo (int the_x = 0) : x (the_x) {} + virtual ~Foo() {} + int x; + + bool operator== (const Foo& other) const + { return x == other.x; } + bool operator!= (const Foo& other) const + { return x != other.x; } +}; + +typedef std::vector<Foo*> FooCont; + +const unsigned int fooclid = 23423556; +CLASS_DEF (FooCont, fooclid, 1) +CLASS_DEF (std::vector<Foo>, 23423558, 1) + + +typedef std::vector<std::string> StrVec; +const unsigned int strclid = 23423557; +CLASS_DEF (StrVec, strclid, 1) + +typedef std::set<std::string> StrSet; +const unsigned int strsetclid = 23423558; +CLASS_DEF (StrSet, strsetclid, 1) + +typedef std::map<std::string, int> StrMap; +const unsigned int strmapclid = 23423559; +CLASS_DEF (StrMap, strmapclid, 1) + + +// Ensure an offset between Bar and Foo base. +struct XXX { virtual ~XXX(){} XXX():x(0){} int x; }; + +struct Bar + : public XXX, public Foo +{ + Bar (int the_y = 0) : Foo(the_y+10), y (the_y) {} + int y; +}; + +struct BarCont + : public XXX, public FooCont +{ + typedef std::true_type isSequence; + typedef Bar* value_type; + struct const_iterator + : public FooCont::const_iterator + { + const_iterator (FooCont::const_iterator it) + : FooCont::const_iterator (it) {} + Bar* operator*() const { + const FooCont::const_iterator* baseit= static_cast<const FooCont::const_iterator*>(this); + return static_cast<Bar*> (**baseit); + } + }; + const_iterator begin() const { return const_iterator(FooCont::begin()); } + const_iterator end() const { return const_iterator(FooCont::end()); } + Bar* operator[] (size_t i) const + { + const FooCont* base = static_cast<const FooCont*> (this); + return static_cast<Bar*> ((*base)[i]); + } +}; + + +const unsigned int barclid = 23423566; +CLASS_DEF (BarCont, barclid, 1) +CLASS_DEF (std::vector<Bar>, 23423568, 1) + +SG_BASE(Bar, Foo); +SG_BASE(BarCont, FooCont); + + +struct Baz + : public std::string +{ + Baz (std::string the_s = "") : std::string(the_s), s (the_s+"asd") {} + std::string s; +}; + + +struct BazCont + : public XXX, public StrSet +{ + typedef Baz key_type; + typedef Baz value_type; + typedef const Baz* const_pointer; + typedef const Baz& const_reference; + + struct const_iterator + : public StrSet::const_iterator + { + const_iterator (StrSet::const_iterator it) + : StrSet::const_iterator (it) {} + Baz operator*() const { + const StrSet::const_iterator* baseit= static_cast<const StrSet::const_iterator*>(this); + return Baz (**baseit); + } + }; + const_iterator begin() const { return const_iterator(StrSet::begin()); } + const_iterator end() const { return const_iterator(StrSet::end()); } +}; + + +CONTAINER_IS_SET(BazCont) +const unsigned int bazclid = 23423576; +CLASS_DEF (BazCont, bazclid, 1) + +SG_BASE(Baz, std::string); +SG_BASE(BazCont, StrSet); + + + + +struct IdentTest +{ + struct IDENTIFIABLE + : public std::vector<std::string> + { + unsigned short identifyHash() const { return m_hash; } + unsigned short m_hash; + }; + typedef std::vector<IDENTIFIABLE*> vec_t; + typedef vec_t::const_iterator const_iterator; + typedef std::string value_type; + + const_iterator indexFind(unsigned short ndx) const + { + if (ndx < m_vec.size()) + return m_vec.begin() + ndx; + return end(); + } + + const_iterator begin() const + { + return m_vec.begin(); + } + const_iterator end() const + { + return m_vec.end(); + } + + void fill (std::string prefix); + + vec_t m_vec; +}; + + +CLASS_DEF (IdentTest, 23423560, 1) + +void IdentTest::fill (std::string prefix) +{ + for (int i=0; i < 4; i++) { + IDENTIFIABLE* v = new IDENTIFIABLE; + for (int j=0; j<4; j++) { + std::ostringstream os; + os << prefix << (i*4+j); + v->push_back (os.str()); + } + v->m_hash = i; + m_vec.push_back (v); + } +} + + +template <> +struct DefaultIndexingPolicy<IdentTest> { + typedef SG::IdentContIndexingPolicy<IdentTest> type; +}; + + +class ElementLinkBase_test +{ +public: + static void setLink (ElementLinkBase& l, + SG::sgkey_t key, + unsigned int index) + { + l.m_persKey = key; + l.m_persIndex = index; + } +}; + + +template <class CONT> +struct Index +{ + typedef typename CONT::value_type type; + Index(const CONT* cont) : m_cont(*cont) {} + const type& operator[] (size_t idx) const + { return m_cont[idx]; } + const CONT& m_cont; +}; + + +template <class T> +struct Index<std::set<T> > +{ + typedef std::set<T> CONT; + typedef typename CONT::value_type type; + Index(const CONT*) {} + const type& operator[] (const type& idx) const { return idx; } +}; + + +template <class K, class V> +struct Index<std::map<K, V> > +{ + typedef std::map<K, V> CONT; + typedef V type; + Index(const CONT* cont) : m_cont(*cont) {} + const type& operator[] (const K& idx) const + { + typename CONT::const_iterator it = m_cont.find (idx); + if (it == m_cont.end()) std::abort(); + return it->second; + } + const CONT& m_cont; +}; + + +template <> +struct Index<IdentTest> +{ + typedef IdentTest CONT; + typedef std::string type; + Index(const CONT* cont) : m_cont(*cont) {} + const type& operator[] (unsigned idx) const + { + typename CONT::const_iterator it = m_cont.indexFind ((idx>>16)&0xffff); + if (it == m_cont.end()) std::abort(); + return (**it)[idx&0xffff]; + } + const CONT& m_cont; +}; + + +template <class CONT, class IDX> +const typename Index<CONT>::type& doindex (const CONT* cont, const IDX& idx) +{ + return Index<CONT>(cont)[idx]; +} + + + +template <class CONT> +void testit (const std::string& key, + const CONT* cont, + const std::string& key2, + const CONT* cont2, + const typename ElementLink<CONT>::index_type& index1, + const typename ElementLink<CONT>::index_type& index1b, + const typename ElementLink<CONT>::index_type& index2, + const typename ElementLink<CONT>::index_type& index2b, + const typename ElementLink<CONT>::index_type& null_index) +{ + typedef ElementLink<CONT> Link; + typedef typename Link::ElementType element_t; + element_t null_element = element_t(); + CLID clid = ClassID_traits<CONT>::ID(); + TestStore::sgkey_t sgkey = store.stringToKey (key, clid); + TestStore::sgkey_t sgkey2 = store.stringToKey (key2, clid); + + Link el1; + assert (el1.isDefault()); + assert (el1.index() == null_index); + assert (!el1.isValid()); + assert (!el1); + assert (el1.cptr() == 0); + assert (el1.getDataPtr() == 0); + assert (el1.getDataNonConstPtr() == 0); + assert (el1.getStorableObjectPointer() == 0); + assert (el1.dataID() == ""); + assert (el1.key() == 0); + assert (el1.source() == 0); + assert (el1.cachedElement() == null_element); + assert (el1.proxy() == 0); + + EXPECT_EXCEPTION (SG::ExcInvalidLink, *el1); + + assert (el1.classID() == clid); + + Link el2 (key, index2); + assert (el2.cachedElement() == null_element); + assert (!el2.isDefault()); + assert (el2.index() == index2); + assert (el2.isValid()); + assert (!!el2); + assert (*el2.cptr() == doindex(cont, index2)); + assert (el2.getDataPtr() == cont); + assert (el2.getDataNonConstPtr() == cont); + assert (el2.getStorableObjectPointer() == cont); + assert (&el2.getStorableObjectRef() == cont); + assert (el2.dataID() == key); + assert (el2.key() == sgkey); + assert (el2.source() == &store); + typename Link::ElementConstPointer foo2 = el2; + assert (*foo2 == doindex(cont, index2)); + typename Link::ElementConstReference foo3 = *el2; + assert (foo3 == doindex(cont, index2)); + assert (el2.cachedElement() == doindex(cont, index2)); + assert (el2.proxy()->name() == key); + + Link el3 (sgkey, index2); + assert (!el3.isDefault()); + assert (el3.index() == index2); + assert (el3.isValid()); + assert (!!el3); + assert (*el3.cptr() == doindex(cont, index2)); + assert (el3.getDataPtr() == cont); + assert (el3.getDataNonConstPtr() == cont); + assert (el3.dataID() == key); + assert (el3.key() == sgkey); + assert (el3.source() == &store); + + Link el4 (key, index2, doindex(cont, index2)); + assert (!el4.isDefault()); + assert (el4.index() == index2); + assert (el4.isValid()); + assert (!!el4); + assert (*el4.cptr() == doindex(cont, index2)); + assert (el4.getDataPtr() == cont); + assert (el4.getDataNonConstPtr() == cont); + assert (el4.dataID() == key); + assert (el4.key() == sgkey); + assert (el4.source() == &store); + + { + DataLink<CONT> dl1 = el4.getDataLink(); + assert (!dl1.isDefault()); + assert (dl1.isValid()); + assert (dl1.cptr() == cont); + assert (dl1.dataID() == key); + assert (dl1.key() == sgkey); + assert (dl1.source() == &store); + + const Link& cel4 = el4; + const DataLink<CONT> dl2 = cel4.getDataLink(); + assert (!dl2.isDefault()); + assert (dl2.isValid()); + assert (dl2.cptr() == cont); + assert (dl2.dataID() == key); + assert (dl2.key() == sgkey); + assert (dl2.source() == &store); + } + + Link el5 (sgkey, index2, doindex(cont, index2)); + assert (!el5.isDefault()); + assert (el5.index() == index2); + assert (el5.isValid()); + assert (!!el5); + assert (*el5.cptr() == doindex(cont, index2)); + assert (el5.getDataPtr() == cont); + assert (el5.getDataNonConstPtr() == cont); + assert (el5.dataID() == key); + assert (el5.key() == sgkey); + assert (el5.source() == &store); + + Link el6 (*cont2, index2b); + assert (!el6.isDefault()); + assert (el6.index() == index2b); + assert (el6.isValid()); + assert (!!el6); + assert (*el6.cptr() == doindex(cont2, index2b)); + assert (el6.getDataPtr() == cont2); + assert (el6.getDataNonConstPtr() == cont2); + assert (el6.dataID() == key2); + assert (el6.key() == sgkey2); + assert (el6.source() == &store); + + Link el7 (el6); + assert (!el7.isDefault()); + assert (el7.index() == index2b); + assert (el7.isValid()); + assert (!!el7); + assert (*el7.cptr() == doindex(cont2, index2b)); + assert (el7.getDataPtr() == cont2); + assert (el7.getDataNonConstPtr() == cont2); + assert (el7.dataID() == key2); + assert (el7.key() == sgkey2); + assert (el7.source() == &store); + + el1 = el7; + assert (!el1.isDefault()); + assert (el1.index() == index2b); + assert (el1.isValid()); + assert (!!el1); + assert (*el1.cptr() == doindex(cont2, index2b)); + assert (el1.getDataPtr() == cont2); + assert (el1.getDataNonConstPtr() == cont2); + assert (el1.dataID() == key2); + assert (el1.key() == sgkey2); + assert (el1.source() == &store); + + Link el8; + assert (el8.isDefault()); + assert (el8.toIndexedElement (*cont, index1)); + assert (!el8.isDefault()); + assert (el8.index() == index1); + assert (el8.isValid()); + assert (!!el8); + assert (*el8.cptr() == doindex(cont, index1)); + assert (el8.getDataPtr() == cont); + assert (el8.getDataNonConstPtr() == cont); + assert (el8.dataID() == key); + assert (el8.key() == sgkey); + assert (el8.source() == &store); + assert (!el8.toIndexedElement (*cont, index2)); + + Link el9; + assert (el9.isDefault()); + assert (el9.toContainedElement (*cont, doindex(cont, index2))); + assert (!el9.isDefault()); + assert (el9.index() == index2); + assert (el9.isValid()); + assert (!!el9); + assert (*el9.cptr() == doindex(cont, index2)); + assert (el9.getDataPtr() == cont); + assert (el9.getDataNonConstPtr() == cont); + assert (el9.dataID() == key); + assert (el9.key() == sgkey); + assert (el9.source() == &store); + assert (!el9.toContainedElement (*cont, doindex(cont, index2))); + + EXPECT_EXCEPTION (SG::ExcElementNotFound, + { + Link el9a; + el9a.toContainedElement (*cont, doindex(cont2, index2b)); + }); + + Link el10 (doindex(cont, index1), *cont); + assert (!el10.isDefault()); + assert (el10.index() == index1); + assert (el10.isValid()); + assert (!!el10); + assert (*el10.cptr() == doindex(cont, index1)); + assert (el10.getDataPtr() == cont); + assert (el10.getDataNonConstPtr() == cont); + assert (el10.dataID() == key); + assert (el10.key() == sgkey); + assert (el10.source() == &store); + + Link el11; + assert (el11.setElement (doindex(cont, index2))); + assert (!el11.isDefault()); + assert (el11.index() == null_index); + assert (el11.isValid()); + assert (!!el11); + assert (*el11.cptr() == doindex(cont, index2)); + assert (el11.getDataPtr() == 0); + assert (el11.getDataNonConstPtr() == 0); + assert (el11.dataID() == ""); + assert (el11.key() == 0); + assert (el11.source() == 0); + + assert (el11.setStorableObject (*cont)); + assert (!el11.isDefault()); + assert (el11.index() == index2); + assert (el11.isValid()); + assert (!!el11); + assert (*el11.cptr() == doindex(cont, index2)); + assert (el11.getDataPtr() == cont); + assert (el11.getDataNonConstPtr() == cont); + assert (el11.dataID() == key); + assert (el11.key() == sgkey); + assert (el11.source() == &store); + + assert (!el11.setElement (doindex(cont, index2))); + assert (!el11.setStorableObject (*cont)); + + Link el12; + assert (el12.setStorableObject (*cont)); + assert (!el12.isDefault()); + assert (el12.index() == null_index); + assert (!el12.isValid()); + assert (!el12); + assert (el12.cptr() == 0); + assert (el12.getDataPtr() == cont); + assert (el12.getDataNonConstPtr() == cont); + assert (el12.dataID() == key); + assert (el12.key() == sgkey); + assert (el12.source() == &store); + + assert (el12.setElement (doindex(cont, index2))); + assert (!el12.isDefault()); + assert (el12.index() == index2); + assert (el12.isValid()); + assert (!!el12); + assert (*el12.cptr() == doindex(cont, index2)); + assert (el12.getDataPtr() == cont); + assert (el12.getDataNonConstPtr() == cont); + assert (el12.dataID() == key); + assert (el12.key() == sgkey); + assert (el12.source() == &store); + + assert (!el12.setElement (doindex(cont, index2))); + assert (!el12.setStorableObject (*cont)); + + el12.resetWithKeyAndIndex (key2, index1b); + assert (!el12.isDefault()); + assert (el12.index() == index1b); + assert (el12.isValid()); + assert (!!el12); + assert (*el12.cptr() == doindex(cont2, index1b)); + assert (el12.getDataPtr() == cont2); + assert (el12.getDataNonConstPtr() == cont2); + assert (el12.dataID() == key2); + assert (el12.key() == sgkey2); + assert (el12.source() == &store); + + el12.resetWithKeyAndIndex (sgkey, index2); + assert (!el12.isDefault()); + assert (el12.index() == index2); + assert (el12.isValid()); + assert (!!el12); + assert (*el12.cptr() == doindex(cont, index2)); + assert (el12.getDataPtr() == cont); + assert (el12.getDataNonConstPtr() == cont); + assert (el12.dataID() == key); + assert (el12.key() == sgkey); + assert (el12.source() == &store); + + el12.reset(); + assert (el12.isDefault()); + assert (el12.index() == null_index); + assert (!el12.isValid()); + assert (!el12); + assert (el12.cptr() == 0); + assert (el12.getDataPtr() == 0); + assert (el12.getDataNonConstPtr() == 0); + assert (el12.dataID() == ""); + assert (el12.key() == 0); + assert (el12.source() == 0); +} + + +void test1() +{ + std::cout << "test1\n"; + + FooCont* foocont = new FooCont; + foocont->push_back (new Foo(1)); + foocont->push_back (new Foo(2)); + foocont->push_back (new Foo(3)); + foocont->push_back (new Foo(4)); + store.record (foocont, "foocont"); + + FooCont* foocont2 = new FooCont; + foocont2->push_back (new Foo(11)); + foocont2->push_back (new Foo(12)); + foocont2->push_back (new Foo(13)); + foocont2->push_back (new Foo(14)); + store.record (foocont2, "foocont2"); + + testit<FooCont> ("foocont", foocont, + "foocont2", foocont2, + 1, 1, 2, 2, -1); +} + + +// Testing references to objects not in SG. +void test2() +{ + std::cout << "test2\n"; + + TestStore::sgkey_t fookey = store.stringToKey ("foocont_t2", fooclid); + Foo* foo1 = new Foo(101); + + ElementLink<FooCont> el1; + assert (el1.setElement (foo1)); + assert (!el1.isDefault()); + assert ((int)el1.index() == -1); + assert (el1.isValid()); + assert (!!el1); + assert (*el1.cptr() == foo1); + assert (el1.getDataPtr() == 0); + assert (el1.getDataNonConstPtr() == 0); + assert (el1.dataID() == ""); + assert (el1.key() == 0); + assert (el1.source() == 0); + assert (el1.proxy() == 0); + + ElementLink<FooCont> el2 (fookey, 2, foo1); + assert (!el2.isDefault()); + assert ((int)el2.index() == 2); + assert (el2.isValid()); + assert (!!el2); + assert (*el2.cptr() == foo1); + assert (el2.getDataPtr() == 0); + assert (el2.getDataNonConstPtr() == 0); + assert (el2.dataID() == "foocont_t2"); + assert (el2.key() == fookey); + assert (el2.source() == &store); + assert (el2.proxy()->name() == "foocont_t2"); + + FooCont* foocont = new FooCont; + for (int i=0; i < 4; i++) + foocont->push_back (new Foo(i+100)); + + ElementLink<FooCont> el3 (*foocont, 2); + assert (!el3.isDefault()); + assert ((int)el3.index() == 2); + assert (el3.isValid()); + assert (!!el3); + assert (*el3.cptr() == (*foocont)[2]); + assert (el3.getDataPtr() == foocont); + assert (el3.getDataNonConstPtr() == foocont); + assert (el3.dataID() == ""); + + store.record (foocont, "foocont_t2"); + assert (el3.dataID() == "foocont_t2"); + assert (el3.key() == 0); // toPersistent should set this + assert (el3.source() == &store); + assert (el3.proxy()->name() == "foocont_t2"); + + assert (el3.toPersistent()); + assert (el3.key() == fookey); +} + + +// toTransient, toPersistent +void test3() +{ + std::cout << "test3\n"; + + TestStore::sgkey_t sgkey = store.stringToKey ("foocont3", fooclid); + + FooCont* foocont3 = new FooCont; + for (int i=0; i < 4; i++) + foocont3->push_back (new Foo(i+200)); + store.record (foocont3, "foocont3"); + + ElementLink<FooCont> el1; + ElementLinkBase_test::setLink(el1, sgkey, 2); + assert (el1.toTransient()); + assert (*el1.cptr() == (*foocont3)[2]); + + ElementLink<FooCont> el2; + assert (el2.toPersistent()); + assert (!el2); + el2 = ElementLink<FooCont> ("foocont3", 1); + assert (*el2.cptr() == (*foocont3)[1]); + assert (el2.toPersistent()); + assert (*el2.cptr() == (*foocont3)[1]); + + FooCont* foocont3a = new FooCont; + for (int i=0; i < 4; i++) + foocont3a->push_back (new Foo(i+300)); + store.record (foocont3a, "foocont3a"); + + FooCont* foocont3b = new FooCont; + for (int i=0; i < 4; i++) + foocont3b->push_back (new Foo(i+350)); + store.record (foocont3b, "foocont3b"); + + store.remap<FooCont> ("foocont3a", "foocont3b", 2, 1); + + el2 = ElementLink<FooCont> ("foocont3a", 2); + assert (*el2.cptr() == (*foocont3a)[2]); + assert (el2.toPersistent()); + assert (*el2.cptr() == (*foocont3b)[1]); + + ElementLink<FooCont> el3; + el3.setElement ((*foocont3a)[2]); + assert (!el3.toPersistent()); +} + + +// test alt store +void test4() +{ + std::cout << "test4\n"; + + TestStore store2; + FooCont* foocont4 = new FooCont; + for (int i=0; i < 4; i++) + foocont4->push_back (new Foo(i+400)); + store2.record (foocont4, "foocont4"); + + ElementLink<FooCont> el1 ("foocont4", 2, &store2); + assert (*el1.cptr() == (*foocont4)[2]); + + ElementLink<FooCont> el2 ("foocont4", 2); + assert (el2.cptr() == 0); + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + + ElementLink<FooCont> el3 ("foocont4", 2); + assert (*el3.cptr() == (*foocont4)[2]); + + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// dummy proxy creation +void test5() +{ + std::cout << "test5\n"; + + ElementLink<FooCont> el1 ("foocont20", 2); + assert (!el1.isDefault()); + assert (el1.dataID() == "foocont20"); + assert (el1.classID() == fooclid); + assert (!el1.isValid()); + + TestStore::sgkey_t sgkey = store.stringToKey ("foocont20", fooclid); + assert (el1.key() == sgkey); + FooCont* foocont20 = new FooCont; + for (int i=0; i < 4; i++) + foocont20->push_back (new Foo(i+500)); + store.record (foocont20, "foocont20"); + assert (el1.isValid()); + assert (*el1.cptr() == (*foocont20)[2]); +} + + +// comparison ops +void test6() +{ + std::cout << "test6\n"; + + ElementLink<FooCont> el1 ("foocont20", 2); + ElementLink<FooCont> el2 ("foocont21", 1); + + assert (el1 < el2); + assert (!(el1 > el2)); + assert (el1 != el2); + assert (el1 == el1); + + ElementLink<FooCont> el3; + assert (!(el3 < el3)); + assert (el3 < el1); + assert (!(el1 < el3)); + + Foo foo; + ElementLink<FooCont> el4; + el4.setElement(&foo); + assert (el3 < el4); + assert (!(el4 < el3)); + + bool res = false; + EXPECT_EXCEPTION (SG::ExcIncomparableEL, res = el4 < el1); + EXPECT_EXCEPTION (SG::ExcIncomparableEL, res = el1 < el4); + assert (res == false); +} + + +class Hell { +public: + Hell() { }; + ElementLink<FooCont> test(FooCont& cont, ElementLink<FooCont>& link) { + const Foo* f = *link; + ElementLink<FooCont> ftest; + ftest.toContainedElement(cont, f); + return ftest; + } + + int get( const Foo& f) {return f.x;} +}; + + +// tests from ControlTest +void test7() +{ + std::cout << "test7\n"; + + FooCont* fooVec = new FooCont(); + Foo* f1 = new Foo(1); + Foo* f2 = new Foo(2); + Foo* f3 = new Foo(3); + + fooVec->push_back(f1); + fooVec->push_back(f2); + fooVec->push_back(f3); + store.record (fooVec, "fooVec"); + ElementLink<FooCont> FooVecLink1; + FooVecLink1.toContainedElement(*fooVec, f1); + + // move to persistent state and check index + FooVecLink1.toPersistent(); + assert(FooVecLink1.index() == 0); + // get the pointer from ElementLink and check + assert ((**FooVecLink1).x == 1); + + // test of indexed Element + ElementLink <FooCont> FooVecLink2(*fooVec, 1); + // Dereference to make sure we get Foo2 back: + assert ((**FooVecLink2).x == 2); + // move to persistent state and check index + FooVecLink2.toPersistent(); + assert(FooVecLink2.index() == 1); + + ElementLink <FooCont> FooVecLink21; + assert( FooVecLink21.toIndexedElement(*fooVec, 1) ); + // Dereference to make sure we get Foo2 back: + assert ((**FooVecLink21).x == 2); + // move to persistent state and check index + FooVecLink21.toPersistent(); + assert(FooVecLink21.index() == 1); + + // test of Element Link with key + ElementLink<FooCont> FooVecLink3("fooVec", 2); + assert (FooVecLink3.index() == 2); + const Foo* f = *FooVecLink3; + assert (f->x == 3); + + // check resetWithKeyAndIndex + // assign el1 to el4 + ElementLink<FooCont> FooVecLink4 = FooVecLink1; + // check index + assert(FooVecLink4.index() == 0); + // get the pointer from ElementLink and check + assert ((**FooVecLink4).x == 1); + // reset EL + FooVecLink4.resetWithKeyAndIndex("fooVec", 2); + // Should be in valid state + assert (FooVecLink4.isValid()); + // Should be in identified state + //assert (IdentifiedState::valid(&FooVecLink4)); + // move to transient and check that it has the right values + FooVecLink4.toTransient(); + f = *FooVecLink4; + assert (f->x == 3); + + + // create a vector of element links and iterate over it: + // test of ElementLink in/out of scope + ElementLink<FooCont> linkTest; + linkTest.toContainedElement(*fooVec, f); + Hell h; + ElementLink<FooCont> ftest = h.test(*fooVec, linkTest); + // make sure that the two pointers are the same. + assert (f == *ftest); + + // test of ElementLink setElement, setStorable + ElementLink<FooCont> linkset; + assert( linkset.toPersistent() ); + + const Foo* pCF(f); + linkset.setElement(pCF); // set only element + linkset.toPersistent(); // XXX SHOULD BE AN ERROR??? + + linkset.setStorableObject(*fooVec); // set Collection + assert (linkset.index() == 2); + assert ((**linkset).x == 3); + assert( linkset.toPersistent() ); + + // test2: + std::vector<std::string> strVec; + store.record(&strVec, " key"); + strVec.push_back("foo"); + strVec.push_back("bar"); + + // Test2: test of contained Element + ElementLink< std::vector<std::string> > strLink1; + std::string x = "foo"; // note that you cannot pass foo directly. + strLink1.toContainedElement(strVec, x); + // note that the call to .index() itself calls toPersistent() + assert (strLink1.index() == 0); + assert (*strLink1=="foo"); + + // Test2: test of indexed Element + ElementLink< std::vector<std::string> > strLink2(strVec, 1); + assert(*strLink2 == "bar"); + + // test 3: use simple vector<objects> for test. + std::vector<Foo>* fooVec2 = new std::vector<Foo>(); + Foo foo1(1); + Foo foo2(2); + fooVec2->push_back(foo1); + fooVec2->push_back(foo2); + store.record(fooVec2, "fooVec2"); + + ElementLink< std::vector<Foo> > FooVec2Link1; + FooVec2Link1.toContainedElement(*fooVec2, foo1); + assert (foo1 == *FooVec2Link1.cptr()); + + // Test3: test of contained Element + // move to persistent state + FooVec2Link1.toPersistent(); + assert(FooVec2Link1.index() == 0); + + // Test3: test of indexed Element + ElementLink< std::vector<Foo> > FooVec2Link2(*fooVec2, 1); + // Dereference to make sure we get Foo2 back: + // assert(FooVecLink2.d() == 2.0); + // move to persistent state + // assert(FooVec2Link2.index() == 1); + FooVec2Link2.toPersistent(); + // test of ElementLinkVector: + + // Starting Test 4: Testing ElementLinkVector + typedef ElementLinkVector<FooCont> ELVec; + ELVec linkVector; + linkVector.push_back(FooVecLink1); + linkVector.push_back(FooVecLink2); + linkVector.push_back(FooVecLink3); + const Foo* fv = *linkVector.elementCPtr(0); //!!FIXME + assert (fv->x == 1); + assert ((**linkVector.elementCPtr(1)).x == 2); + assert ((**linkVector.elementCPtr(2)).x == 3); + // let us check the begin() end() of ElementLinkVector: + int result = 0; + ELVec::iterator iter(linkVector.begin()), iend(linkVector.end()); + for (; iter!=iend; ++iter) { + result += 1; + assert ((**iter)->x == result); + } +} + + +// Test for vector with non-pointer payload +void test8() +{ + std::cout << "test8\n"; + + StrVec* strvec = new StrVec; + strvec->push_back ("1"); + strvec->push_back ("2"); + strvec->push_back ("3"); + strvec->push_back ("4"); + store.record (strvec, "strvec"); + + StrVec* strvec2 = new StrVec; + strvec2->push_back ("11"); + strvec2->push_back ("12"); + strvec2->push_back ("13"); + strvec2->push_back ("14"); + store.record (strvec2, "strvec2"); + + testit<StrVec> ("strvec", strvec, + "strvec2", strvec2, + 1, 1, 2, 2, -1); + + ElementLink<StrVec> el2 ("strvec", 2); + assert (el2->size() == 1); +} + + +// Test for set +void test9() +{ + std::cout << "test9\n"; + + StrSet* strset = new StrSet; + strset->insert ("1"); + strset->insert ("2"); + strset->insert ("3"); + strset->insert ("4"); + store.record (strset, "strset"); + + StrSet* strset2 = new StrSet; + strset2->insert ("11"); + strset2->insert ("12"); + strset2->insert ("13"); + strset2->insert ("14"); + store.record (strset2, "strset2"); + + testit<StrSet> ("strset", strset, + "strset2", strset2, + "1", "11", "2", "12", ""); + + ElementLink<StrVec> el2 ("strvec", 2); + assert (el2->size() == 1); +} + + +// Test for map +void test10() +{ + std::cout << "test10\n"; + + StrMap* strmap = new StrMap; + (*strmap)["1"] = 1; + (*strmap)["2"] = 2; + (*strmap)["3"] = 3; + (*strmap)["4"] = 4; + store.record (strmap, "strmap"); + + StrMap* strmap2 = new StrMap; + (*strmap2)["11"] = 11; + (*strmap2)["12"] = 12; + (*strmap2)["13"] = 13; + (*strmap2)["14"] = 14; + store.record (strmap2, "strmap2"); + + testit<StrMap> ("strmap", strmap, + "strmap2", strmap2, + "1", "11", "2", "12", ""); +} + + +// Test for identcont +void test11() +{ + std::cout << "test11\n"; + + IdentTest* imap = new IdentTest; + imap->fill ("a"); + store.record (imap, "imap"); + + IdentTest* imap2 = new IdentTest; + imap2->fill ("b"); + store.record (imap2, "imap2"); + + testit<IdentTest> ("imap", imap, + "imap2", imap2, + IdentContIndex(1,1).hashAndIndex(), + IdentContIndex(1,1).hashAndIndex(), + IdentContIndex(2,2).hashAndIndex(), + IdentContIndex(2,2).hashAndIndex(), + IdentContIndex().hashAndIndex()); +} + + +// default store setting +void test12() +{ + std::cout << "test12\n"; + TestStore store2; + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// Converting ctor. +void test13() +{ + std::cout << "test13\n"; + + // Pointer, raw element. + BarCont* bar = new BarCont; + bar->push_back (new Bar (1)); + bar->push_back (new Bar (2)); + bar->push_back (new Bar (3)); + + size_t null_index = -1; + + ElementLink<BarCont> el1; + el1.setElement ((*bar)[1]); + ElementLink<FooCont> el2 (el1); + assert (*el1.cptr() == (*bar)[1]); + assert (*el2.cptr() == (*bar)[1]); + assert (static_cast<const void*>(*el1.cptr()) != + static_cast<const void*>(*el2.cptr())); + assert (el1.getDataPtr() == nullptr); + assert (el2.getDataPtr() == nullptr); + assert (el1.key() == 0); + assert (el2.key() == 0); + assert (el1.index() == null_index); + assert (el2.index() == null_index); + + // Pointer, storable not in SG. + ElementLink<BarCont> el3 (*bar, 1); + ElementLink<FooCont> el4 (el3); + assert (*el3.cptr() == (*bar)[1]); + assert (*el4.cptr() == (*bar)[1]); + assert (static_cast<const void*>(*el3.cptr()) != + static_cast<const void*>(*el4.cptr())); + assert (el3.getDataPtr() == bar); + assert (el4.getDataPtr() == bar); + assert (static_cast<const void*>(el3.getDataPtr()) != + static_cast<const void*>(el4.getDataPtr())); + assert (el3.key() == 0); + assert (el4.key() == 0); + assert (el3.index() == 1); + assert (el4.index() == 1); + + // Pointer, storable in SG. + store.record (bar, "barcont"); + ElementLink<BarCont> el5 ("barcont", 1); + ElementLink<FooCont> el6 (el5); + assert (*el5.cptr() == (*bar)[1]); + assert (*el6.cptr() == (*bar)[1]); + assert (static_cast<const void*>(*el5.cptr()) != + static_cast<const void*>(*el6.cptr())); + assert (el5.getDataPtr() == bar); + assert (el6.getDataPtr() == bar); + assert (static_cast<const void*>(el5.getDataPtr()) != + static_cast<const void*>(el6.getDataPtr())); + assert (el5.dataID() == "barcont"); + assert (el6.dataID() == "barcont"); + assert (el5.index() == 1); + assert (el6.index() == 1); + + // Non-pointer, raw element. + BazCont* baz = new BazCont; + baz->insert ("1"); + baz->insert ("2"); + baz->insert ("3"); + + ElementLink<BazCont> el11; + el11.setElement (Baz ("bar1")); + ElementLink<StrSet> el12 (el11); + assert (*el11.cptr() == "bar1"); + assert (*el12.cptr() == "bar1"); + assert (el11.cptr()->s == "bar1asd"); + assert (el11.getDataPtr() == nullptr); + assert (el12.getDataPtr() == nullptr); + assert (el11.key() == 0); + assert (el12.key() == 0); + assert (el11.index() == ""); + assert (el12.index() == ""); + + // Non-pointer, storable not in SG. + ElementLink<BazCont> el13 (*baz, Baz("2")); + ElementLink<StrSet> el14 (el13); + assert (*el13.cptr() == "2"); + assert (*el14.cptr() == "2"); + assert (el13.cptr()->s == "2asd"); + assert (el13.getDataPtr() == baz); + assert (el14.getDataPtr() == baz); + assert (static_cast<const void*>(el13.getDataPtr()) != + static_cast<const void*>(el14.getDataPtr())); + assert (el13.key() == 0); + assert (el14.key() == 0); + assert (el13.index() == Baz("2")); + assert (el14.index() == "2"); + + // Non-pointer, storable in SG. + store.record (baz, "bazcont"); + ElementLink<BazCont> el15 ("bazcont", Baz("2")); + ElementLink<StrSet> el16 (el15); + assert (*el15.cptr() == "2"); + assert (*el16.cptr() == "2"); + assert (el15.cptr()->s == "2asd"); + assert (el16.getDataPtr() == baz); + assert (el15.getDataPtr() == baz); + assert (static_cast<const void*>(el15.getDataPtr()) != + static_cast<const void*>(el16.getDataPtr())); + assert (el15.dataID() == "bazcont"); + assert (el16.dataID() == "bazcont"); + assert (el15.index() == Baz("2")); + assert (el16.index() == "2"); +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + initTestStore(); + + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/ForwardIndexingPolicy_test.cxx b/EDM/athena/Control/AthLinks/test/ForwardIndexingPolicy_test.cxx new file mode 100644 index 00000000..f3006bb3 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/ForwardIndexingPolicy_test.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/ForwardIndexingPolicy_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for ForwardIndexingPolicy. + */ + + +#undef NDEBUG +#include "AthLinks/tools/ForwardIndexingPolicy.h" +#include <vector> +#include <iostream> +#include <cassert> + + +#include "TestTools/expect_exception.h" + + +void test1() +{ + std::cout << "test1\n"; + + typedef std::vector<int> Cont; + typedef SG::ForwardIndexingPolicy<Cont> Pol; + + Pol::stored_index_type idx; + Pol::reset (idx); + assert ((int)idx == -1); + assert (!Pol::isValid(idx)); + idx = 1; + assert (Pol::isValid(idx)); + Pol::index_type idx2 = idx; + assert (idx2 == 1); + + Cont c; + c.push_back (0); + c.push_back (1); + c.push_back (2); + + Pol::ElementType elt = c[0]; + assert (elt == 0); + Pol::ElementConstReference r_elt = elt; + assert (r_elt == 0); + Pol::ElementConstPointer p_elt = &elt; + assert (*p_elt == 0); + + Pol::reset (idx); + assert (Pol::lookup (1, c) == 1); + EXPECT_EXCEPTION (SG::ExcBadForwardLink, Pol::lookup (10, c)); + EXPECT_EXCEPTION (SG::ExcBadForwardLink, Pol::lookup (idx, c)); + + Pol::reverseLookup (c, 2, idx2); + assert (idx2 == 2); + EXPECT_EXCEPTION (SG::ExcElementNotFound, Pol::reverseLookup (c, 10, idx2)); + + assert (Pol::storedToExternal(0) == 0); + assert (Pol::storedToExternal(3) == 3); + assert (Pol::storedToExternal(static_cast<Pol::stored_index_type>(-1)) == + static_cast<Pol::index_type>(-1)); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/GenericElementLinkBase_test.cxx b/EDM/athena/Control/AthLinks/test/GenericElementLinkBase_test.cxx new file mode 100644 index 00000000..0d6203f4 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/GenericElementLinkBase_test.cxx @@ -0,0 +1,504 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/GeneicElementLinkBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for GenericElementLinkBase + */ + + +#undef NDEBUG +#include "AthLinks/GenericElementLinkBase.h" +#include "AthLinks/exceptions.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/CLASS_DEF.h" +#include "AthLinks/tools/MapIndexingPolicy.h" +#include "AthLinks/tools/SetIndexingPolicy.h" +#include "AthenaKernel/getMessageSvc.h" +#include <map> +#include <iostream> +#include <cstdlib> +#include <cassert> + + +#include "SGTools/TestStore.h" +#include "TestTools/expect_exception.h" + + +using namespace SGTest; + + +typedef std::map<std::string, std::string> StrMap; +const unsigned int strmapclid = 23423559; +CLASS_DEF (StrMap, strmapclid, 1) + + +typedef std::set<std::string> StrSet; +const unsigned int strsetclid = 23423571; +CLASS_DEF (StrSet, strsetclid, 1) + + +struct Bar + : public std::string +{ + Bar (std::string the_s = "") : std::string(the_s), s (the_s+"asd") {} + std::string s; +}; + + +// Ensure an offset between BarCont and base. +struct XXX { virtual ~XXX(){} XXX():x(0){} int x; }; + +struct BarCont + : public XXX, public StrSet +{ + typedef Bar key_type; + typedef Bar value_type; + typedef const Bar* const_pointer; + typedef const Bar& const_reference; + + struct const_iterator + : public StrSet::const_iterator + { + const_iterator (StrSet::const_iterator it) + : StrSet::const_iterator (it) {} + Bar operator*() const { + const StrSet::const_iterator* baseit= static_cast<const StrSet::const_iterator*>(this); + return Bar (**baseit); + } + }; + const_iterator begin() const { return const_iterator(StrSet::begin()); } + const_iterator end() const { return const_iterator(StrSet::end()); } +}; + + +const unsigned int barclid = 23423576; +CLASS_DEF (BarCont, barclid, 1) + +SG_BASE(Bar, std::string); +SG_BASE(BarCont, StrSet); + + +struct StrTraits +{ + typedef StrSet Storable; + typedef SG::SetIndexingPolicy<StrSet> IndexingPolicy; +}; + + +struct BarTraits +{ + typedef BarCont Storable; + typedef SG::SetIndexingPolicy<BarCont> IndexingPolicy; +}; + + +template <class POLICY> +class ElementLinkBaseT_test + : public SG::GenericElementLinkBase<POLICY> +{ +public: + typedef SG::GenericElementLinkBase<POLICY> Base; + typedef typename Base::index_type index_type; + + ElementLinkBaseT_test() {} + ElementLinkBaseT_test(const std::string& key, CLID clid, + const index_type& index, + IProxyDict* sg) + : Base (key, clid, index, sg) {} + ElementLinkBaseT_test(SG::sgkey_t key, CLID clid, + const index_type& index, + IProxyDict* sg) + : Base (key, clid, index, sg) {} + ElementLinkBaseT_test(const std::string& key, CLID clid, + const index_type& index, + const std::string& elt, IProxyDict* sg) + : Base (key, clid, index, elt, sg) {} + ElementLinkBaseT_test(SG::sgkey_t key, CLID clid, + const index_type& index, + const std::string& elt, IProxyDict* sg) + : Base (key, clid, index, elt, sg) {} + ElementLinkBaseT_test(const void* obj, CLID clid, + const index_type& index, + IProxyDict* sg) + : Base (obj, clid, index, sg) {} + template <class OTHER_POLICY, class FROM_STORABLE, class TO_STORABLE> + ElementLinkBaseT_test (const SG::GenericElementLinkBase<OTHER_POLICY>& other, + FROM_STORABLE* from, TO_STORABLE* to) + : Base (other, from, to) {} + using Base::getCachedElement; + using Base::storableBase; + using Base::storedIndex; + using Base::toIndexedElement; + using Base::setCachedElement; + using Base::setIndex; + using Base::setStorableObject; + using Base::resetWithKeyAndIndex; + using Base::proxyHolder; + + void setLink (SG::sgkey_t key, + const std::string& index) + { + this->m_key = key; + this->m_index = index; + } +}; + + +typedef ElementLinkBaseT_test<SG::MapIndexingPolicy<StrMap> > + ElementLinkBase_test; + + +void test1() +{ + std::cout << "test1\n"; + + typedef ElementLinkBase_test Link; + CLID clid = strmapclid; + typedef std::string element_t; + typedef const element_t* element_const_pointer; + element_const_pointer eltp = 0; + + StrMap* cont = new StrMap; + (*cont)["0"] = "10"; + (*cont)["1"] = "11"; + (*cont)["2"] = "12"; + (*cont)["3"] = "13"; + std::string key = "strcont"; + TestStore::sgkey_t sgkey = store.stringToKey (key, clid); + store.record (cont, key); + Link::index_type index1 = "1"; + Link::index_type index2 = "2"; + std::string elt2 = (*cont)[index2]; + + Link::index_type null_index; + + StrMap* cont2 = new StrMap; + (*cont2)["0b"] = "110"; + (*cont2)["1b"] = "111"; + (*cont2)["2b"] = "112"; + (*cont2)["3b"] = "113"; + std::string key2 = "strcont2"; + store.record (cont2, key2); + Link::index_type index1b = "1b"; + Link::index_type index2b = "2bj"; + TestStore::sgkey_t sgkey2 = store.stringToKey (key2, clid); + + Link el1; + assert (el1.isDefault()); + assert (el1.index() == null_index); + assert (el1.storableBase (0, clid) == 0); + assert (el1.dataID() == ""); + assert (el1.key() == 0); + assert (el1.source() == 0); + eltp = 0; + assert (!el1.getCachedElement(eltp)); + assert (eltp == 0); + assert (el1.proxy() == 0); + assert (!el1.hasCachedElement()); + assert (!el1.storedIndex().isValid()); + + Link el2 (key, clid, index2, 0); + eltp = 0; + assert (!el2.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el2.isDefault()); + assert (el2.index() == index2); + assert (el2.dataID() == key); + assert (el2.key() == sgkey); + assert (el2.source() == &store); + assert (el2.proxy()->name() == key); + assert (el2.proxy() == el2.proxyHolder().proxy()); + assert (!el2.hasCachedElement()); + assert (el2.storedIndex().isValid()); + assert (el2.storableBase (0, clid) == cont); + + Link el3 (sgkey, clid, index2, 0); + eltp = 0; + assert (!el3.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el3.isDefault()); + assert (el3.index() == index2); + assert (el3.dataID() == key); + assert (el3.key() == sgkey); + assert (el3.source() == &store); + assert (!el3.hasCachedElement()); + assert (el3.storableBase (0, clid) == cont); + + Link el4 (key, clid, index2, elt2, 0); + eltp = 0; + assert (el4.getCachedElement(eltp)); + assert (*eltp == elt2); + assert (!el4.isDefault()); + assert (el4.index() == index2); + assert (el4.dataID() == key); + assert (el4.key() == sgkey); + assert (el4.source() == &store); + assert (el4.hasCachedElement()); + assert (el4.storableBase (0, clid) == cont); + + Link el5 (sgkey, clid, index2, elt2, 0); + eltp = 0; + assert (el5.getCachedElement(eltp)); + assert (*eltp == elt2); + assert (!el5.isDefault()); + assert (el5.index() == index2); + assert (el5.dataID() == key); + assert (el5.key() == sgkey); + assert (el5.source() == &store); + assert (el5.storableBase (0, clid) == cont); + assert (el5.hasCachedElement()); + + Link el6 (cont2, clid, index2b, 0); + assert (!el6.isDefault()); + assert (el6.index() == index2b); + assert (el6.dataID() == key2); + assert (el6.key() == sgkey2); + assert (el6.source() == &store); + assert (el6.storableBase (0, clid) == cont2); + eltp = 0; + assert (!el6.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el6.hasCachedElement()); + + Link el7 (el6); + assert (!el7.isDefault()); + assert (el7.index() == index2b); + assert (el7.dataID() == key2); + assert (el7.key() == sgkey2); + assert (el7.source() == &store); + assert (el7.storableBase (0, clid) == cont2); + eltp = 0; + assert (!el7.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el7.hasCachedElement()); + + el1 = el7; + assert (!el1.isDefault()); + assert (el1.index() == index2b); + assert (el1.dataID() == key2); + assert (el1.key() == sgkey2); + assert (el1.source() == &store); + assert (el1.storableBase (0, clid) == cont2); + eltp = 0; + assert (!el1.getCachedElement(eltp)); + assert (eltp == 0); + assert (!el1.hasCachedElement()); + + Link el8; + assert (el8.isDefault()); + assert (el8.toIndexedElement (cont, clid, index1, 0)); + assert (!el8.isDefault()); + assert (el8.index() == index1); + assert (el8.dataID() == key); + assert (el8.key() == sgkey); + assert (el8.source() == &store); + assert (el8.storableBase (0, clid) == cont); + assert (!el8.toIndexedElement (cont, clid, index1, 0)); + el8.reset(); + assert (el8.isDefault()); + assert (!el8.hasCachedElement()); + eltp = 0; + assert (!el8.getCachedElement(eltp)); + assert (eltp == 0); + el8.setCachedElement (elt2); + assert (el8.hasCachedElement()); + eltp = 0; + assert (el8.getCachedElement(eltp)); + assert (*eltp == elt2); + assert (!el8.toIndexedElement (cont, clid, index1, 0)); + assert (el8.isDefaultIndex()); + assert ((std::string)(el8.storedIndex()) == null_index); + el8.setIndex ("3"); + assert (!el8.isDefaultIndex()); + assert ((std::string)(el8.storedIndex()) == "3"); + assert (!el8.toIndexedElement (cont, clid, index1, 0)); + + Link el11; + el11.setIndex (index2); + assert (el11.setStorableObject (cont, clid, false, 0)); + assert (!el11.isDefault()); + assert (el11.index() == index2); + assert (el11.dataID() == key); + assert (el11.key() == sgkey); + assert (el11.source() == &store); + assert (el11.storableBase (0, clid) == cont); + assert (!el11.hasCachedElement()); + assert (!el11.setStorableObject (cont2, clid, false, 0)); + assert (el11.setStorableObject (cont2, clid, true, 0)); + assert (el11.index() == null_index); + assert (el11.storableBase (0, clid) == cont2); + assert (el11.dataID() == key2); + + Link el12; + el12.setCachedElement (elt2); + assert (el12.hasCachedElement()); + el12.resetWithKeyAndIndex (key2, clid, index1b, 0); + assert (!el12.hasCachedElement()); + assert (!el12.isDefault()); + assert (el12.index() == index1b); + assert (el12.dataID() == key2); + assert (el12.key() == sgkey2); + assert (el12.source() == &store); + assert (el12.storableBase (0, clid) == cont2); + + el12.setCachedElement (elt2); + assert (el12.hasCachedElement()); + el12.resetWithKeyAndIndex (sgkey, clid, index2, 0); + assert (!el12.hasCachedElement()); + assert (!el12.isDefault()); + assert (el12.index() == index2); + assert (el12.dataID() == key); + assert (el12.key() == sgkey); + assert (el12.source() == &store); + assert (el12.storableBase (0, clid) == cont); + + el12.reset(); + assert (el12.isDefault()); + assert (el12.index() == null_index); + assert (el12.dataID() == ""); + assert (el12.key() == 0); + assert (el12.source() == 0); + assert (el12.storableBase (0, clid) == 0); + assert (!el12.hasCachedElement()); +} + + +// toTransient, toPersistent +void test2() +{ + std::cout << "test2\n"; + + typedef ElementLinkBase_test Link; + CLID clid = strmapclid; + + StrMap* cont3 = new StrMap; + (*cont3)["200"] = "300"; + (*cont3)["201"] = "301"; + (*cont3)["202"] = "302"; + (*cont3)["203"] = "303"; + std::string key3 = "strcont3"; + store.record (cont3, key3); + TestStore::sgkey_t sgkey3 = store.stringToKey (key3, clid); + Link::index_type index1 = "201"; + Link::index_type index2 = "202"; + + Link el1; + assert (el1.proxy() == 0); + el1.setLink (sgkey3, "202"); + assert (el1.toTransient()); + assert (!el1.hasCachedElement()); + assert (el1.proxy()->name() == key3); + + Link el2; + assert (el2.toPersistent()); + assert (el2.isDefault()); + el2 = Link (key3, clid, index1, 0); + assert (el2.storableBase (0, clid) == cont3); + assert (el2.index() == index1); + assert (el2.key() == sgkey3); + assert (el2.toPersistent()); + assert (el2.storableBase (0, clid) == cont3); + assert (el2.index() == index1); + assert (el2.key() == sgkey3); + + el2.reset(); + el2.setIndex (index2); + assert (!el2.toPersistent()); + el2.reset(); + el2.setStorableObject (cont3, clid, true, 0); + assert (!el2.toPersistent()); + el2.setIndex (index2); + assert (el2.toPersistent()); + + StrMap* cont4 = new StrMap; + el2.setStorableObject (cont4, clid, true, 0); + el2.setIndex (index2); + EXPECT_EXCEPTION (SG::ExcPointerNotInSG, el2.toPersistent()); +} + + +// default store setting +void test3() +{ + std::cout << "test3\n"; + TestStore store2; + + assert (SG::CurrentEventStore::setStore(&store2) == &store); + assert (SG::CurrentEventStore::setStore(&store) == &store2); +} + + +// Converting constructor +void test4() +{ + std::cout << "test4\n"; + + BarCont* bar = new BarCont; + bar->insert ("1"); + bar->insert ("2"); + bar->insert ("3"); + + typedef ElementLinkBaseT_test<SG::SetIndexingPolicy<StrSet> > + BaseLinkBase; + typedef ElementLinkBaseT_test<SG::SetIndexingPolicy<BarCont> > + DerLinkBase; + + // Reference to raw element. + DerLinkBase el1; + el1.setCachedElement (Bar ("bar1")); + BaseLinkBase el2 (el1, (BarTraits*)0, (StrTraits*)0); + + const Bar* derp1 = 0; + const std::string* basep1 = 0; + assert (el1.getCachedElement (derp1)); + assert (el2.getCachedElement (basep1)); + assert (*derp1 == "bar1"); + assert (derp1->s == "bar1asd"); + assert (*basep1 == "bar1"); + + // Storable not in SG. + DerLinkBase el3 (bar, barclid, Bar("2"), nullptr); + BaseLinkBase el4 (el3, (BarTraits*)0, (StrTraits*)0); + BarCont* barcont1 = reinterpret_cast<BarCont*>(el3.storableBase (0, barclid)); + StrSet* strcont1 = reinterpret_cast<StrSet*>(el4.storableBase (0, strsetclid)); + assert (barcont1 == bar); + assert (barcont1 == strcont1); + assert (static_cast<void*>(barcont1) != static_cast<void*>(strcont1)); + assert (el3.index() == Bar("2")); + assert (el4.index() == "2"); + assert (el3.key() == 0); + assert (el4.key() == 0); + + // Storable in SG. + std::string key = "barcont"; + store.record (bar, key); + DerLinkBase el5 (key, barclid, Bar("2"), nullptr); + BaseLinkBase el6 (el5, (BarTraits*)0, (StrTraits*)0); + barcont1 = reinterpret_cast<BarCont*>(el5.storableBase (0, barclid)); + strcont1 = reinterpret_cast<StrSet*>(el6.storableBase (0, strsetclid)); + assert (barcont1 == bar); + assert (barcont1 == strcont1); + assert (static_cast<void*>(barcont1) != static_cast<void*>(strcont1)); + assert (el5.index() == Bar("2")); + assert (el6.index() == "2"); + assert (el5.dataID() == key); + assert (el6.dataID() == key); +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + initTestStore(); + + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/IdentContIndex_test.cxx b/EDM/athena/Control/AthLinks/test/IdentContIndex_test.cxx new file mode 100644 index 00000000..276a22a7 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/IdentContIndex_test.cxx @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/IdentContIndex_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for IdentContIndex. + */ + + +#undef NDEBUG +#include "AthLinks/tools/IdentContIndex.h" +#include <vector> +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + + IdentContIndex i1; + assert (!i1.isValid()); + assert (i1.collHash() == 0xffff); + assert (i1.objIndex() == 0xffff); + assert (i1.hashAndIndex() == 0xffffffff); + + IdentContIndex i2 (123, 456); + assert (i2.isValid()); + assert (i2.collHash() == 123); + assert (i2.objIndex() == 456); + assert (i2.hashAndIndex() == 123*0x10000 + 456); + + IdentContIndex i3 (456*0x10000 + 123); + assert (i3.isValid()); + assert (i3.collHash() == 456); + assert (i3.objIndex() == 123); + assert (i3.hashAndIndex() == 456*0x10000 + 123); + + IdentContIndex i4; + i4.setCollHash (234); + assert (!i4.isValid()); + assert (i4.collHash() == 234); + assert (i4.objIndex() == 0xffff); + assert (i4.hashAndIndex() == 234*0x10000 + 0xffff); + i4.setObjIndex (345); + assert (i4.isValid()); + assert (i4.collHash() == 234); + assert (i4.objIndex() == 345); + assert (i4.hashAndIndex() == 234*0x10000 + 345); + + IdentContIndex i5; + i5.setObjIndex (456); + assert (!i5.isValid()); + assert (i5.collHash() == 0xffff); + assert (i5.objIndex() == 456); + assert (i5.hashAndIndex() == 0xffff0000 + 456); + i5.setCollHash (567); + assert (i5.isValid()); + assert (i5.collHash() == 567); + assert (i5.objIndex() == 456); + assert (i5.hashAndIndex() == 567*0x10000 + 456); + + i5.setHashAndIndex (678*0x10000 + 789); + assert (i5.isValid()); + assert (i5.collHash() == 678); + assert (i5.objIndex() == 789); + assert (i5.hashAndIndex() == 678*0x10000 + 789); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/IdentContIndexingPolicy_test.cxx b/EDM/athena/Control/AthLinks/test/IdentContIndexingPolicy_test.cxx new file mode 100644 index 00000000..657cb9b7 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/IdentContIndexingPolicy_test.cxx @@ -0,0 +1,129 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/IdentContIndexingPolicy_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for IdentContIndexingPolicy. + */ + + +#undef NDEBUG +#include "AthLinks/tools/IdentContIndexingPolicy.h" +#include <map> +#include <vector> +#include <string> +#include <iostream> +#include <cassert> + + +#include "TestTools/expect_exception.h" + + +class Cont +{ +public: + struct IDENTIFIABLE : public std::vector<std::string> + { + unsigned identifyHash() const { return m_hash; } + unsigned m_hash; + }; + + typedef std::map<int, IDENTIFIABLE> map_t; + + class const_iterator + { + public: + typedef map_t::const_iterator base_t; + + const_iterator (base_t it) : m_it (it) {} + const IDENTIFIABLE* operator*() { return &m_it->second; } + bool operator== (const_iterator other) const + { return m_it == other.m_it; } + bool operator!= (const_iterator other) const + { return m_it != other.m_it; } + + void operator++() { ++m_it; } + + private: + base_t m_it; + }; + + const_iterator begin() const { return const_iterator (m_map.begin()); } + const_iterator end() const { return const_iterator (m_map.end()); } + const_iterator indexFind(int hash) const + { return const_iterator (m_map.find (hash)); } + + void set (unsigned hash, unsigned idx, std::string val) + { + IDENTIFIABLE& i = m_map[hash]; + i.m_hash = hash; + if (i.size() <= idx) + i.resize (idx+1); + i[idx] = val; + } + +private: + map_t m_map; +}; + + +void test1() +{ + std::cout << "test1\n"; + + typedef SG::IdentContIndexingPolicy<Cont> Pol; + + Pol::stored_index_type idx; + Pol::reset (idx); + assert (!Pol::isValid(idx)); + idx = Pol::stored_index_type(123*0x10000 + 456); + assert (Pol::isValid(idx)); + Pol::index_type idx2 = idx; + assert (idx2 == 123*0x10000 + 456); + Pol::reset (idx); + assert (!Pol::isValid(idx)); + + Cont c; + c.set (0, 1, "one"); + c.set (2, 3, "two"); + c.set (2, 4, "three"); + + Pol::ElementType elt = (**c.indexFind(0))[1]; + assert (elt == "one"); + Pol::ElementConstReference r_elt = elt; + assert (r_elt == "one"); + Pol::ElementConstPointer p_elt = &elt; + assert (*p_elt == "one"); + + Pol::reset (idx); + assert (Pol::lookup (2*0x10000 + 3, c) == "two"); + EXPECT_EXCEPTION (SG::ExcInvalidIndex, Pol::lookup (idx, c)); + EXPECT_EXCEPTION (SG::ExcIndexNotFound, Pol::lookup (2*0x10000 + 10, c)); + EXPECT_EXCEPTION (SG::ExcIndexNotFound, Pol::lookup (5*0x10000 + 1, c)); + + Pol::reset (idx2); + Pol::reverseLookup (c, "three", idx2); + assert (idx2 == 2*0x10000 + 4); + Pol::reverseLookup (c, "three", idx2); + assert (idx2 == 2*0x10000 + 4); + idx2 = 2*0x10000 + 5; + Pol::reverseLookup (c, "three", idx2); + assert (idx2 == 2*0x10000 + 4); + idx2 = 1*0x10000 + 4; + Pol::reverseLookup (c, "three", idx2); + assert (idx2 == 2*0x10000 + 4); + EXPECT_EXCEPTION (SG::ExcElementNotFound, Pol::reverseLookup (c, "ten", idx2)); + + assert (Pol::storedToExternal (Pol::stored_index_type(123)) == 123); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/IndexHolder_test.cxx b/EDM/athena/Control/AthLinks/test/IndexHolder_test.cxx new file mode 100644 index 00000000..34ca4c01 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/IndexHolder_test.cxx @@ -0,0 +1,39 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/IndexHolder_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Regression tests for IndexHolder. + */ + +#undef NDEBUG +#include "AthLinks/tools/IndexHolder.h" +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + + SG::IndexHolder<std::string> h; + assert (!h.isValid()); + + h = SG::IndexHolder<std::string> ("asd"); + assert (h.isValid()); + assert (static_cast<const std::string&>(h) == "asd"); + + h.reset(); + assert (!h.isValid()); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/IsSTLSequence_test.cxx b/EDM/athena/Control/AthLinks/test/IsSTLSequence_test.cxx new file mode 100644 index 00000000..2222792e --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/IsSTLSequence_test.cxx @@ -0,0 +1,82 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/IsSTLSequence_test.cxx + * @author scott snyder + * @date Aug, 2013 + * @brief Regression test for @c IsSTLSequence. + */ + + +#undef NDEBUG + + +#include "AthLinks/tools/IsSTLSequence.h" +#include <type_traits> +#include <set> +#include <cassert> +#include <iostream> + + +class V1 : public std::vector<float> {}; +class L1 : public std::list<float> {}; +class Q1 : public std::deque<float> {}; + +struct X1 +{ + typedef int value_type; + typedef size_t size_type; + typedef int difference_type; + typedef const int* const_iterator; + typedef const int* const_pointer; + typedef const int& const_reference; + + size_t size() const; + size_t max_size() const; + bool empty() const; + const_iterator begin() const; + const_iterator end() const; +}; +struct Y1 +{ + typedef int value_type; + typedef size_t size_type; + typedef int difference_type; + typedef const int* const_iterator; + typedef const int* const_pointer; + typedef const int& const_reference; + + size_t size() const; + size_t max_size() const; + bool empty() const; + const_iterator begin() const; + const_iterator end() const; + + typedef std::true_type isSequence; +}; + + +void test1() +{ + std::cout << "test1\n"; + assert (SG::IsSTLSequence<std::vector<int> >::value); + assert (SG::IsSTLSequence<V1>::value); + assert (SG::IsSTLSequence<std::list<int> >::value); + assert (SG::IsSTLSequence<L1>::value); + assert (SG::IsSTLSequence<std::deque<int> >::value); + assert (SG::IsSTLSequence<Q1>::value); + assert (SG::IsSTLSequence<Y1>::value); + + assert ( ! SG::IsSTLSequence<std::set<int> >::value ); + assert ( ! SG::IsSTLSequence<X1>::value); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/MapIndexingPolicy_test.cxx b/EDM/athena/Control/AthLinks/test/MapIndexingPolicy_test.cxx new file mode 100644 index 00000000..a79eb2ad --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/MapIndexingPolicy_test.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/MapIndexingPolicy_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for MapIndexingPolicy. + */ + + +#undef NDEBUG +#include "AthLinks/tools/MapIndexingPolicy.h" +#include <vector> +#include <iostream> +#include <cassert> + + +#include "TestTools/expect_exception.h" + + +void test1() +{ + std::cout << "test1\n"; + typedef std::map<int, std::string> Cont; + typedef SG::MapIndexingPolicy<Cont> Pol; + + Pol::stored_index_type idx; + Pol::reset (idx); + assert (!Pol::isValid(idx)); + idx = Pol::stored_index_type(1); + assert (Pol::isValid(idx)); + Pol::index_type idx2 = idx; + assert (idx2 == 1); + Pol::reset (idx); + assert (!Pol::isValid(idx)); + + Cont c; + c[0] = "0"; + c[1] = "1"; + c[2] = "2"; + + Pol::ElementType elt = c[0]; + assert (elt == "0"); + Pol::ElementConstReference r_elt = elt; + assert (r_elt == "0"); + Pol::ElementConstPointer p_elt = &elt; + assert (*p_elt == "0"); + + Pol::reset (idx); + assert (Pol::lookup (1, c) == "1"); + EXPECT_EXCEPTION (SG::ExcIndexNotFound, Pol::lookup (10, c)); + EXPECT_EXCEPTION (SG::ExcInvalidIndex, Pol::lookup (idx, c)); + + Pol::reverseLookup (c, "2", idx2); + assert (idx2 == 2); + EXPECT_EXCEPTION (SG::ExcElementNotFound, Pol::reverseLookup (c, "10", idx2)); + + assert (Pol::storedToExternal (Pol::stored_index_type(3)) == 3); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/SetIndexingPolicy_test.cxx b/EDM/athena/Control/AthLinks/test/SetIndexingPolicy_test.cxx new file mode 100644 index 00000000..a9ed2cdb --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/SetIndexingPolicy_test.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/SetIndexingPolicy_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Regression tests for SetIndexingPolicy. + */ + + +#undef NDEBUG +#include "AthLinks/tools/SetIndexingPolicy.h" +#include <vector> +#include <iostream> +#include <cassert> + + +#include "TestTools/expect_exception.h" + + +void test1() +{ + std::cout << "test1\n"; + + typedef std::set<int> Cont; + typedef SG::SetIndexingPolicy<Cont> Pol; + + Pol::stored_index_type idx; + Pol::reset (idx); + assert (!Pol::isValid(idx)); + idx = Pol::stored_index_type(1); + assert (Pol::isValid(idx)); + Pol::index_type idx2 = idx; + assert (idx2 == 1); + Pol::reset (idx); + assert (!Pol::isValid(idx)); + + Cont c; + c.insert (0); + c.insert (1); + c.insert (2); + + Pol::ElementType elt = *c.begin(); + assert (elt == 0); + Pol::ElementConstReference r_elt = elt; + assert (r_elt == 0); + Pol::ElementConstPointer p_elt = &elt; + assert (*p_elt == 0); + + Pol::reset (idx); + assert (Pol::lookup (1, c) == 1); + EXPECT_EXCEPTION (SG::ExcIndexNotFound, Pol::lookup (10, c)); + EXPECT_EXCEPTION (SG::ExcInvalidIndex, Pol::lookup (idx, c)); + + Pol::reverseLookup (c, 2, idx2); + assert (idx2 == 2); + EXPECT_EXCEPTION (SG::ExcElementNotFound, Pol::reverseLookup (c, 10, idx2)); + + assert (Pol::storedToExternal (Pol::stored_index_type(3)) == 3); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthLinks/test/TestThinningSvc.icc b/EDM/athena/Control/AthLinks/test/TestThinningSvc.icc new file mode 100644 index 00000000..c411bed9 --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/TestThinningSvc.icc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file TestThinningSvc.icc + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief Dummy thining service, for regression tests. + */ + + +#include "SGTools/TestStore.h" +#include "AthenaKernel/IThinningSvc.h" +#include <map> + + +class TestThinningSvc + : virtual public IThinningSvc, public SGTest::TestStore +{ +public: + StatusCode sysInitialize() + { std::cout << "sysInitialize\n"; std::abort(); } + StatusCode sysStart() + { std::cout << "sysStart\n"; std::abort(); } + StatusCode sysStop() + { std::cout << "sysStop\n"; std::abort(); } + StatusCode sysFinalize() + { std::cout << "sysFinalize\n"; std::abort(); } + StatusCode sysReinitialize() + { std::cout << "sysReinitialize\n"; std::abort(); } + StatusCode sysRestart() + { std::cout << "sysRestart\n"; std::abort(); } + StatusCode configure() + { std::cout << "configure\n"; std::abort(); } + StatusCode initialize() + { std::cout << "initialize\n"; std::abort(); } + StatusCode start() + { std::cout << "start\n"; std::abort(); } + StatusCode stop() + { std::cout << "stop\n"; std::abort(); } + StatusCode finalize() + { std::cout << "finalize\n"; std::abort(); } + StatusCode terminate() + { std::cout << "terminate\n"; std::abort(); } + StatusCode reinitialize() + { std::cout << "reinitialize\n"; std::abort(); } + StatusCode restart() + { std::cout << "restart\n"; std::abort(); } + Gaudi::StateMachine::State FSMState() const + { std::cout << "FSMState\n"; std::abort(); } + Gaudi::StateMachine::State targetFSMState() const + { std::cout << "targetFSMState\n"; std::abort(); } + void setServiceManager (ISvcManager*) + { std::cout << "setServiceManager\n"; std::abort(); } + bool thinningOccurred() const + { std::cout << "thinningOccurred\n"; std::abort(); } + StatusCode register_slimmer (Athena::ISlimmingHdlr */*handler*/) + { std::cout << "register_slimmer\n"; std::abort(); } + virtual Athena::IThinningHdlr* handler( SG::DataProxy* /*proxy*/ ) + { std::cout << "handler\n"; std::abort(); } + virtual StatusCode + filter_impl( Athena::IThinningHdlr* /*handler*/, + SG::DataProxy* /*proxy*/, + const Filter_t& /*filter*/, + const IThinningSvc::Operator::Type /*op*/ = Operator::And ) + { std::cout << "filter_impl\n"; std::abort(); } + StatusCode commit() + { std::cout << "commit\n"; std::abort(); } + StatusCode rollback() + { std::cout << "rollback\n"; std::abort(); } + bool is_thinned_impl(const SG::DataProxy* /*p*/) const + { std::cout << "is_thinned_impl\n"; std::abort(); } + + std::size_t index_impl( const SG::DataProxy* /*objProxy*/, + std::size_t idx ) const + { + map_t::const_iterator i = m_map.find (idx); + if (i != m_map.end()) + return i->second; + return idx; + } + + void remap (size_t from, size_t to) + { + m_map[from] = to; + } + + + typedef std::map<size_t, size_t> map_t; + map_t m_map; +}; diff --git a/EDM/athena/Control/AthLinks/test/exceptions_test.cxx b/EDM/athena/Control/AthLinks/test/exceptions_test.cxx new file mode 100644 index 00000000..8531c8bc --- /dev/null +++ b/EDM/athena/Control/AthLinks/test/exceptions_test.cxx @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthLinks/test/exceptions_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Regression tests for exceptions. + */ + + +#undef NDEBUG +#include "AthLinks/exceptions.h" +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + + std::cout << SG::ExcPointerNotInSG((char*)0x1234).what() << "\n"; + std::cout << SG::ExcCLIDMismatch(123, 456).what() << "\n"; + std::cout << SG::ExcInvalidLink (123, "key", 765).what() << "\n"; + std::cout << SG::ExcBadForwardLink (123, 345).what() << "\n"; + std::cout << SG::ExcElementNotFound ("test").what() << "\n"; + std::cout << SG::ExcInvalidIndex ("test").what() << "\n"; + std::cout << SG::ExcIndexNotFound ("test").what() << "\n"; + std::cout << SG::ExcIncomparableEL().what() << "\n"; +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgTool.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgTool.h new file mode 100644 index 00000000..fc305836 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgTool.h @@ -0,0 +1,257 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthAlgTool.h +// Header file for class AthAlgTool +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHALGTOOL_H +#define ATHENABASECOMPS_ATHALGTOOL_H 1 + +// STL includes +#include <string> +#include <type_traits> + +// FrameWork includes +#include "GaudiKernel/AlgTool.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthMemMacros.h" +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#include "AthenaBaseComps/AthCheckMacros.h" +#include "AthenaBaseComps/AthMessaging.h" +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/VarHandleProperty.h" +#include "StoreGate/VarHandleKeyProperty.h" +#include "StoreGate/VarHandleKey.h" +#include "StoreGate/VarHandleKeyArray.h" +#include "StoreGate/VarHandleKeyArrayProperty.h" +#include "AthenaKernel/IUserDataSvc.h" + +class AthAlgTool : + public ::AlgTool, + public ::AthMessaging +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + // fwd compat w/ gaudi-21 + using AthMessaging::msg; + + // Copy constructor: + + /// Constructor with parameters: + AthAlgTool( const std::string& type, + const std::string& name, + const IInterface* parent ); + + /// Destructor: + virtual ~AthAlgTool(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief The standard @c StoreGateSvc (event store) + * Returns (kind of) a pointer to the @c StoreGateSvc + */ + ServiceHandle<StoreGateSvc>& evtStore() const; + + /** @brief The standard @c StoreGateSvc/DetectorStore + * Returns (kind of) a pointer to the @c StoreGateSvc + */ + ServiceHandle<StoreGateSvc>& detStore() const; + + /** @brief The standard @c UserDataSvc + * Returns (kind of) a pointer to the @c UserDataSvc + */ + ServiceHandle<IUserDataSvc>& userStore() const; + +private: + // to keep track of VarHandleKeyArrays for data dep registration + mutable std::vector<SG::VarHandleKeyArray*> m_vhka; + + ///////////////////////////////////////////////////////////////// + // + //// For automatic registration of Handle data products + // + +public: + /** + * @brief Declare a new Gaudi property. + * @param name Name of the property. + * @param property Object holding the property value. + * @param doc Documenation string for the property. + * + * This is the version for types that derive from @c SG::VarHandleKey. + * The property value object is put on the input and output lists as + * appropriate; then we forward to the base class. + */ + Property* declareProperty(const std::string& name, + SG::VarHandleKey& hndl, + const std::string& doc, + std::true_type, + std::false_type) const + { + AthAlgTool* aa = const_cast<AthAlgTool*>(this); + Gaudi::DataHandle::Mode mode = hndl.mode(); + if (mode & Gaudi::DataHandle::Reader) + aa->declareInput(&hndl); + if (mode & Gaudi::DataHandle::Writer) + aa->declareOutput(&hndl); +#ifdef ATHENAHIVE + hndl.setOwner(aa); +#endif + + return AlgTool::declareProperty(name,hndl,doc); + } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + Property* declareProperty(const std::string& name, + SG::VarHandleKeyArray& hndArr, + const std::string& doc, + std::false_type, + std::true_type) const + { + + AthAlgTool* aa = const_cast<AthAlgTool*>(this); + + m_vhka.push_back(&hndArr); + + Property* p = AlgTool::declareProperty(name, hndArr, doc); + if (p != 0) { + p->declareUpdateHandler(&AthAlgTool::updateVHKA, aa); + } else { + ATH_MSG_ERROR("unable to call declareProperty on VarHandleKeyArray " + << name); + } + + return p; + + } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // since the contents of the VarHandleKeyArrays have not been read + // in from the configurables by the time that declareProperty is + // executed, we must cache them and loop through them later to + // register the data dependencies + + void updateVHKA(Property& /*p*/) { + // debug() << "updateVHKA for property " << p.name() << " " << p.toString() + // << " size: " << m_vhka.size() << endmsg; + for (auto &a : m_vhka) { + Gaudi::DataHandle::Mode mode = a->mode(); + std::vector<SG::VarHandleKey*> keys = a->keys(); + for (auto k : keys) { + if (mode & Gaudi::DataHandle::Reader) + this->declareInput(k); + if (mode & Gaudi::DataHandle::Writer) + this->declareOutput(k); + k->setOwner(this); + } + } + } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * @brief Declare a new Gaudi property. + * @param name Name of the property. + * @param property Object holding the property value. + * @param doc Documenation string for the property. + * + * This is the generic version, for types that do not derive + * from @c SG::VarHandleKey. It just forwards to the base class version + * of @c declareProperty. + */ + template <class T> + Property* declareProperty(const std::string& name, + T& property, + const std::string& doc, + std::false_type, + std::false_type) const + { + return AlgTool::declareProperty(name, property, doc); + } + + + /** + * @brief Declare a new Gaudi property. + * @param name Name of the property. + * @param property Object holding the property value. + * @param doc Documenation string for the property. + * + * This dispatches to either the generic @c declareProperty or the one + * for VarHandle/Key, depending on whether or not @c property + * derives from @c SG::VarHandleKey or SG::VarHandleKeyArray. + */ + template <class T> + Property* declareProperty(const std::string& name, + T& property, + const std::string& doc="none") const + { + return declareProperty (name, property, doc, + std::is_base_of<SG::VarHandleKey, T>(), + std::is_base_of<SG::VarHandleKeyArray,T>() + ); + } + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Protected methods: + /////////////////////////////////////////////////////////////////// +protected: + /// callback for output level property + void msg_update_handler(Property& outputLevel); + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + + /// Default constructor: + AthAlgTool(); //> not implemented + AthAlgTool (const AthAlgTool&); //> not implemented + AthAlgTool& operator= (const AthAlgTool&); //> not implemented + + typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t; + /// Pointer to StoreGate (event store by default) + mutable StoreGateSvc_t m_evtStore; + + /// Pointer to StoreGate (detector store by default) + mutable StoreGateSvc_t m_detStore; + + typedef ServiceHandle<IUserDataSvc> UserDataSvc_t; + /// Pointer to IUserDataSvc + mutable UserDataSvc_t m_userStore; + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline +ServiceHandle<StoreGateSvc>& AthAlgTool::evtStore() const +{ return m_evtStore; } + +inline +ServiceHandle<StoreGateSvc>& AthAlgTool::detStore() const +{ return m_detStore; } + +inline +ServiceHandle<IUserDataSvc>& AthAlgTool::userStore() const +{ return m_userStore; } + +#endif //> ATHENABASECOMPS_ATHALGTOOL_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgorithm.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgorithm.h new file mode 100644 index 00000000..d45912f7 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthAlgorithm.h @@ -0,0 +1,302 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthAlgorithm.h +// Header file for class AthAlgorithm +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHALGORITHM_H +#define ATHENABASECOMPS_ATHALGORITHM_H 1 + +// STL includes +#include <string> +#include <type_traits> + +// FrameWork includes +#include "GaudiKernel/Algorithm.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthCheckMacros.h" +#include "AthenaBaseComps/AthMemMacros.h" +#include "AthenaBaseComps/AthMessaging.h" +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/VarHandleProperty.h" +#include "StoreGate/VarHandleKeyProperty.h" +#include "StoreGate/VarHandleKeyArrayProperty.h" +#include "StoreGate/VarHandleKey.h" +#include "StoreGate/VarHandleKeyArray.h" +#include "AthenaKernel/IUserDataSvc.h" + +// Forward declaration + +/** @class AthAlgorithm AthAlgorithm.h AthenaBaseComps/AthAlgorithm.h + * + * Base class from which all concrete algorithm classes should + * be derived. + * In order for a concrete algorithm class to do anything + * useful the methods initialize(), execute() and finalize() + * should be overridden. + * The base class provides utility methods for accessing + * standard services (StoreGate service etc.); for declaring + * properties which may be configured by the job options + * service; and for creating sub algorithms. + * The only base class functionality which may be used in the + * constructor of a concrete algorithm is the declaration of + * member variables as properties. All other functionality, + * i.e. the use of services and the creation of sub-algorithms, + * may be used only in initialise() and afterwards (see the + * Gaudi and Athena user guides). + * + * @author Sebastien Binet + * @date 2008 + */ + +class AthAlgorithm + : public ::Algorithm, + public ::AthMessaging +{ + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // fwd compat w/ gaudi-21 + using AthMessaging::msg; + + // Copy constructor: + + /// Constructor with parameters: + AthAlgorithm(const std::string& name, + ISvcLocator* pSvcLocator, + const std::string& version=PACKAGE_VERSION); + + /// Destructor: + virtual ~AthAlgorithm(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief The standard @c StoreGateSvc + * Returns (kind of) a pointer to the @c StoreGateSvc + * @WARNING: deprecated. please use @c evtStore() instead + */ + ServiceHandle<StoreGateSvc>& sgSvc() const; + + /** @brief The standard @c StoreGateSvc (event store) + * Returns (kind of) a pointer to the @c StoreGateSvc + */ + ServiceHandle<StoreGateSvc>& evtStore() const; + + /** @brief The standard @c StoreGateSvc/DetectorStore + * Returns (kind of) a pointer to the @c StoreGateSvc + */ + ServiceHandle<StoreGateSvc>& detStore() const; + + /** @brief The standard @c UserDataSvc + * Returns (kind of) a pointer to the @c UserDataSvc + */ + ServiceHandle<IUserDataSvc>& userStore() const; + +private: + // to keep track of VarHandleKeyArrays for data dep registration + mutable std::vector<SG::VarHandleKeyArray*> m_vhka; + + ///////////////////////////////////////////////////////////////// + // + //// For automatic registration of Handle data products + // + +public: + /** + * @brief Declare a new Gaudi property. + * @param name Name of the property. + * @param property Object holding the property value. + * @param doc Documenation string for the property. + * + * This is the version for types that derive from @c SG::VarHandleKey. + * The property value object is put on the input and output lists as + * appropriate; then we forward to the base class. + */ + Property* declareProperty(const std::string& name, + SG::VarHandleKey& hndl, + const std::string& doc, + std::true_type, + std::false_type) const + { + AthAlgorithm* aa = const_cast<AthAlgorithm*>(this); + Gaudi::DataHandle::Mode mode = hndl.mode(); + if (mode & Gaudi::DataHandle::Reader) + aa->declareInput(&hndl); + if (mode & Gaudi::DataHandle::Writer) + aa->declareOutput(&hndl); + hndl.setOwner(aa); + + return Algorithm::declareProperty(name,hndl,doc); + } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + Property* declareProperty(const std::string& name, + SG::VarHandleKeyArray& hndArr, + const std::string& doc, + std::false_type, + std::true_type) const + { + + // std::ostringstream ost; + // ost << Algorithm::name() << " VHKA declareProp: " << name + // << " size: " << hndArr.keys().size() + // << " mode: " << hndArr.mode() + // << " vhka size: " << m_vhka.size() + // << "\n"; + // debug() << ost.str() << endmsg; + + AthAlgorithm* aa = const_cast<AthAlgorithm*>(this); + + m_vhka.push_back(&hndArr); + + Property* p = Algorithm::declareProperty(name, hndArr, doc); + if (p != 0) { + p->declareUpdateHandler(&AthAlgorithm::updateVHKA, aa); + } else { + ATH_MSG_ERROR("unable to call declareProperty on VarHandleKeyArray " + << name); + } + + return p; + + } + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // since the contents of the VarHandleKeyArrays have not been read + // in from the configurables by the time that declareProperty is + // executed, we must cache them and loop through them later to + // register the data dependencies + + void updateVHKA(Property& /*p*/) { + // debug() << "updateVHKA for property " << p.name() << " " << p.toString() + // << " size: " << m_vhka.size() << endmsg; + for (auto &a : m_vhka) { + Gaudi::DataHandle::Mode mode = a->mode(); + std::vector<SG::VarHandleKey*> keys = a->keys(); + for (auto k : keys) { + if (mode & Gaudi::DataHandle::Reader) + this->declareInput(k); + if (mode & Gaudi::DataHandle::Writer) + this->declareOutput(k); + k->setOwner(this); + } + } + } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + + /** + * @brief Declare a new Gaudi property. + * @param name Name of the property. + * @param property Object holding the property value. + * @param doc Documenation string for the property. + * + * This is the generic version, for types that do not derive + * from @c SG::VarHandleKey. It just forwards to the base class version + * of @c declareProperty. + */ + template <class T> + Property* declareProperty(const std::string& name, + T& property, + const std::string& doc, + std::false_type, + std::false_type + ) const + { + return Algorithm::declareProperty(name, property, doc); + } + + + /** + * @brief Declare a new Gaudi property. + * @param name Name of the property. + * @param property Object holding the property value. + * @param doc Documenation string for the property. + * + * This dispatches to either the generic @c declareProperty or the one + * for VarHandle/Key, depending on whether or not @c property + * derives from @c SG::VarHandleKey or @c SG::VarHandleKeyArray. + */ + template <class T> + Property* declareProperty(const std::string& name, + T& property, + const std::string& doc="none") const + { + + return declareProperty (name, property, doc, + std::is_base_of<SG::VarHandleKey, T>(), + std::is_base_of<SG::VarHandleKeyArray,T>() + ); + + } + + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Protected methods: + /////////////////////////////////////////////////////////////////// + protected: + + /// callback for output level property + void msg_update_handler(Property& outputLevel); + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// Default constructor: + AthAlgorithm(); //> not implemented + AthAlgorithm (const AthAlgorithm& ); //> not implemented + AthAlgorithm& operator= (const AthAlgorithm&); //> not implemented + + typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t; + /// Pointer to StoreGate (event store by default) + mutable StoreGateSvc_t m_evtStore; + + /// Pointer to StoreGate (detector store by default) + mutable StoreGateSvc_t m_detStore; + + typedef ServiceHandle<IUserDataSvc> UserDataSvc_t; + /// Pointer to IUserDataSvc + mutable UserDataSvc_t m_userStore; +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline +ServiceHandle<StoreGateSvc>& AthAlgorithm::sgSvc() const +{ return m_evtStore; } + +inline +ServiceHandle<StoreGateSvc>& AthAlgorithm::evtStore() const +{ return m_evtStore; } + +inline +ServiceHandle<StoreGateSvc>& AthAlgorithm::detStore() const +{ return m_detStore; } + +inline +ServiceHandle<IUserDataSvc>& AthAlgorithm::userStore() const +{ return m_userStore; } + +#endif //> !ATHENABASECOMPS_ATHALGORITHM_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCheckMacros.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCheckMacros.h new file mode 100644 index 00000000..2bd83c4d --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCheckMacros.h @@ -0,0 +1,59 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthCheckMacros.h +// Header file for useful macros when comes to using StatusCodes +// Author: S.Binet<binet@cern.ch> +// $Revision: 446910 $ +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHCHECKMACROS_H +#define ATHENABASECOMPS_ATHCHECKMACROS_H 1 + +// framework includes +#include "AthenaKernel/errorcheck.h" + +/*! @copydoc REPORT_ERROR_WITH_CONTEXT + */ +#define ATH_REPORT_ERROR_WITH_CONTEXT REPORT_ERROR_WITH_CONTEXT + +/*! @copydoc REPORT_MESSAGE_WITH_CONTEXT + */ +#define ATH_REPORT_MESSAGE_WITH_CONTEXT REPORT_MESSAGE_WITH_CONTEXT + +/*! @copydoc REPORT_ERROR + */ +#define ATH_REPORT_ERROR REPORT_ERROR + +/*! @copydoc REPORT_MESSAGE + */ +#define ATH_REPORT_MESSAGE REPORT_MESSAGE + +/*! @copydoc CHECK_WITH_CONTEXT + */ +#define ATH_CHECK_WITH_CONTEXT CHECK_WITH_CONTEXT + +/*! @copydoc CHECK + */ +#define ATH_CHECK CHECK + +/*! @copydoc CHECK_RECOVERABLE_WITH_CONTEXT + */ +#define ATH_CHECK_RECOVERABLE_WITH_CONTEXT CHECK_RECOVERABLE_WITH_CONTEXT + +/*! @copydoc CHECK_RECOVERABLE + */ +#define ATH_CHECK_RECOVERABLE CHECK_RECOVERABLE + +/*! @copydoc CHECK_FATAL_WITH_CONTEXT + */ +#define ATH_CHECK_FATAL_WITH_CONTEXT CHECK_FATAL_WITH_CONTEXT + +/*! @copydoc CHECK_FATAL + */ +#define ATH_CHECK_FATAL CHECK_FATAL + +#endif //> !ATHENABASECOMPS_ATHCHECKMACROS_H + diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCnvSvc.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCnvSvc.h new file mode 100644 index 00000000..301c8f56 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthCnvSvc.h @@ -0,0 +1,329 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthCnvSvc.h +// Header file for class AthCnvSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHCNVSVC_H +#define ATHENABASECOMPS_ATHCNVSVC_H 1 + +// STL includes +#include <string> + +// CxxUtils includes +#include "CxxUtils/unordered_map.h" // move to STL when available + +// GaudiKernel +#include "GaudiKernel/IConversionSvc.h" +#include "GaudiKernel/IAddressCreator.h" + +// AthenaBaseComps +#include "AthenaBaseComps/AthService.h" + +// Forward declaration +class ISvcLocator; +template <class TYPE> class SvcFactory; + + +/** @class AthCnvSvc AthCnvSvc.h AthenaBaseComps/AthCnvSvc.h + + Base class for all conversion services. It manages a set of Converters that + are specialized for conversions of specific objects. + + This supports self learning converters: + User hooks include the following (overridable) entries: + - findCnvFactory: returns a suitable converter factory + - createConverter: the actual convetrer creation + - configureConverter: configure converter before initialize + - initializeConverter: initializes the converter + - activateConverter: any additional configuration to be done after + initialize. + + configureConverter and activateConverter are user hooks, where + the convetrer can be manipulated by the hosting service + and knowledge can be supplied, which a "generic" converter cannot + aquire itself. + + These hooks allow any sub-classed conversion service to + override the calls and create converters, which aquire + the knowledge about their persistency type and the + object type they convert during the initialization. + + Only AFTER these three steps the converter must satisfy the + storage type of the hosting service and the class type of + the required object type. + + @author Markus Frank + @version 1.0 +*/ + +class AthCnvSvc + : virtual public ::IConversionSvc, + virtual public ::IAddressCreator, + public ::AthService +{ + friend class SvcFactory<AthCnvSvc>; + +public: + class WorkerEntry { + friend class AthCnvSvc; + private: + CLID m_class; + IConverter* m_converter; + public: + WorkerEntry(const CLID& cl, IConverter* cnv) + : m_class(cl), m_converter(cnv) { + } + WorkerEntry(const WorkerEntry& copy) + : m_class(copy.m_class), m_converter(copy.m_converter) { + } + WorkerEntry& operator = (const WorkerEntry& copy) { + m_class = copy.m_class; + m_converter = copy.m_converter; + return *this; + } + virtual ~WorkerEntry() { + } + IConverter* converter() { + return m_converter; + } + const CLID& clID() const { + return m_class; + } + // comparaison operators + bool operator == (const WorkerEntry& rhs) + { + return rhs.clID() == clID(); + } + bool operator < (const WorkerEntry& rhs) + { + return this->clID() < rhs.clID(); + } + }; + typedef SG::unordered_map<CLID,WorkerEntry> Workers; + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + // Copy constructor: + + /// Constructor with parameters: + AthCnvSvc( const std::string& name, ISvcLocator* pSvcLocator, long type ); + + // Assignment operator: + //AthCnvSvc &operator=(const AthCnvSvc &alg); + + /// Gaudi Service Implementation + //@{ + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode queryInterface (const InterfaceID& riid, + void** ppvInterface); + //@} + + ///@name @c IConversionSvc implementation + //@{ + /// Retrieve the class type of the data store the converter uses. + virtual long repSvcType() const; + + /// Implementation of IConverter: dummy call + const CLID& objType() const; + + /** Implementation of IConverter: Set Data provider service + @return Status code indicating success or failure + @param pService Pointer to data provider service + */ + virtual + StatusCode setDataProvider(IDataProviderSvc* pService); + + /** Implementation of IConverter: Get Data provider service + @return Pointer to data provider service + */ + virtual SmartIF<IDataProviderSvc>& dataProvider() const; + + /// Implementation of IConverter: Set conversion service the converter is connected to + virtual + StatusCode setConversionSvc(IConversionSvc* svc); + + /// Implementation of IConverter: Get conversion service the converter is connected to + virtual + SmartIF<IConversionSvc>& conversionSvc() const; + + /// Set address creator facility + virtual + StatusCode setAddressCreator(IAddressCreator* creator); + + /// Retrieve address creator facility + virtual + SmartIF<IAddressCreator>& addressCreator() const; + + /// Implementation of IConverter: Create the transient representation of an object. + virtual + StatusCode createObj(IOpaqueAddress* pAddress,DataObject*& refpObject); + + /// Implementation of IConverter: Resolve the references of the created transient object. + virtual + StatusCode fillObjRefs(IOpaqueAddress* pAddress, DataObject* pObject); + + /// Implementation of IConverter: Update the transient object from the other representation. + virtual + StatusCode updateObj(IOpaqueAddress* pAddress, DataObject* refpObject); + + /// Implementation of IConverter: Update the references of an updated transient object. + virtual + StatusCode updateObjRefs(IOpaqueAddress* pAddress, DataObject* pObject); + + /// Implementation of IConverter: Convert the transient object to the requested representation. + virtual + StatusCode createRep(DataObject* pObject, IOpaqueAddress*& refpAddress); + + /// Implementation of IConverter: Resolve the references of the converted object. + virtual + StatusCode fillRepRefs(IOpaqueAddress* pAddress,DataObject* pObject); + + /// Implementation of IConverter: Update the converted representation of a transient object. + virtual + StatusCode updateRep(IOpaqueAddress* pAddress, DataObject* pObject); + + /// Implementation of IConverter: Update the references of an already converted object. + virtual + StatusCode updateRepRefs(IOpaqueAddress* pAddress, DataObject* pObject); + + /// Add converter object to conversion service. + virtual + StatusCode addConverter(const CLID& clid); + + /// Add converter object to conversion service. + virtual + StatusCode addConverter(IConverter* pConverter); + + /// Remove converter object from conversion service (if present). + virtual + StatusCode removeConverter(const CLID& clid); + + /// Retrieve converter from list + virtual + IConverter* converter(const CLID& wanted); + + /// Connect the output file to the service with open mode. + virtual + StatusCode connectOutput(const std::string& outputFile, + const std::string& openMode); + + /// Connect the output file to the service. + virtual + StatusCode connectOutput(const std::string& output); + + /// Commit pending output. + virtual + StatusCode commitOutput(const std::string& output, bool do_commit); + + //@} + + /// Disconnect output files from the service. + virtual + StatusCode disconnectOutput(); + + /// @name @c IAddressCreator interface implementation + //@{ + /// Create a Generic address using explicit arguments to identify a single object. + virtual + StatusCode createAddress (long svc_type, + const CLID& clid, + const std::string* par, + const unsigned long* ip, + IOpaqueAddress*& refpAddress); + + /// Convert an address to string form + virtual + StatusCode convertAddress (const IOpaqueAddress* pAddress, + std::string& refAddress); + + /// Convert an address in string form to object form + virtual + StatusCode createAddress (long svc_type, + const CLID& clid, + const std::string& refAddress, + IOpaqueAddress*& refpAddress); + + /// Update state of the service + virtual + StatusCode updateServiceState(IOpaqueAddress* pAddress); + + //@} + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + /// Default constructor: + AthCnvSvc(); //< not implemented + AthCnvSvc (const AthCnvSvc&); //< not implemented + AthCnvSvc& operator= (const AthCnvSvc&); //< not implemented + + /////////////////////////////////////////////////////////////////// + // Protected data and methods: + /////////////////////////////////////////////////////////////////// +protected: + + /// Destructor: + virtual ~AthCnvSvc(); + + /// Create new Converter using factory + virtual + IConverter* createConverter (long typ, const CLID& clid, + const ICnvFactory* fac); + + /// Configure the new converter before initialize is called + virtual + StatusCode configureConverter (long typ, const CLID& clid, IConverter* cnv); + + /// Initialize the new converter + virtual + StatusCode initializeConverter (long typ, const CLID& clid, IConverter* cnv); + + /// Activate the new converter after initialization + virtual + StatusCode activateConverter (long typ, const CLID& clid, IConverter* cnv); + + /// Load converter or dictionary needed by the converter + virtual + void loadConverter(DataObject* pObject); + + /// Retrieve address creation interface + virtual + SmartIF<IAddressCreator>& addressCreator() { return m_addressCreator; } + + StatusCode makeCall (int typ, + bool ignore_add, + bool ignore_obj, + bool update, + IOpaqueAddress*& pAddress, + DataObject*& pObject); + + /// Pointer to data provider service + mutable SmartIF<IDataProviderSvc> m_dataSvc; + /// Pointer to the address creation service interface + mutable SmartIF<IAddressCreator> m_addressCreator; + /// Pointer to the IConversionSvc interface of this + mutable SmartIF<IConversionSvc> m_cnvSvc; + /// Conversion service type + long m_type; + /// List of conversion workers + Workers m_workers; +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +#endif //> !ATHENABASECOMPS_ATHCNVSVC_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthFilterAlgorithm.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthFilterAlgorithm.h new file mode 100644 index 00000000..dcdbb1f6 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthFilterAlgorithm.h @@ -0,0 +1,135 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthFilterAlgorithm.h +// Header file for class AthFilterAlgorithm +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHFILTERALGORITHM_H +#define ATHENABASECOMPS_ATHFILTERALGORITHM_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaKernel/ICutFlowSvc.h" +#include "AthenaBaseComps/AthAlgorithm.h" + +class AthFilterAlgorithm + : public ::AthAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + AthFilterAlgorithm( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~AthFilterAlgorithm(); + + // Assignment operator: + //AthFilterAlgorithm &operator=(const AthFilterAlgorithm &alg); + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ + virtual StatusCode sysInitialize(); + + /// Set the filter passed flag to the specified state + virtual void setFilterPassed( bool state ); + + /// @brief helper method to ease the setting of this filter's description + /// in derived classes + /// Note that this method should be called in the c-tor of derived classes + void setFilterDescription(const std::string& descr); + + /// @brief return a handle to an @c ICutFlowSvc instance + ServiceHandle<ICutFlowSvc>& cutFlowSvc(); + + /// return the @c CutIdentifier corresponding to the top-level cut of this filter algorithm + CutIdentifier cutID(); + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// Default constructor: + AthFilterAlgorithm(); + + /// The CutIdentifier for this filter algorithm + CutIdentifier m_cutID; + + typedef ServiceHandle<ICutFlowSvc> ICutFlowSvc_t; + /// handle to the service holding tables of cut-flows for filtering algs. + ICutFlowSvc_t m_cutFlowSvc; + + /// @brief filter description: describes what this filter does. + /// this is usually pushed to the @c ICutFlowSvc + std::string m_filterDescr; + + //special case: post-python default value of property FilterDescription sent to ICutFlowSvc only if not explicitely specifed before + bool m_resetSelfDescription; + void doNotResetSelfDescription( Property& ); + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +/** @brief return a handle to an @c ICutFlowSvc instance + */ +inline +ServiceHandle<ICutFlowSvc>& +AthFilterAlgorithm::cutFlowSvc() +{ + return m_cutFlowSvc; +} + + +// /** @brief return the top-level @c EventBookkeeper of this filter algorithm +// */ +// inline +// EventBookkeeper* +// AthFilterAlgorithm::ebk() +// { +// return m_ebk; +// } + + +/// return the @c CutIdentifier corresponding to the top-level cut of this filter algorithm +inline +CutIdentifier AthFilterAlgorithm::cutID() +{ + return m_cutID; +} + + +inline +void +AthFilterAlgorithm::doNotResetSelfDescription( Property& ) +{ + m_resetSelfDescription=false; +} + +#endif //> !ATHENABASECOMPS_ATHFILTERALGORITHM_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramAlgorithm.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramAlgorithm.h new file mode 100644 index 00000000..82ae425a --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramAlgorithm.h @@ -0,0 +1,119 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// @class AthHistogramAlgorithm.h +/// Header file for AthHistogramAlgorithm +/// @author: Karsten Koeneke (karsten.koeneke@cern.ch) +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHHISTOGRAMALGORITHM_H +#define ATHENABASECOMPS_ATHHISTOGRAMALGORITHM_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "GaudiKernel/ServiceHandle.h" + + +// Some needed forward declarations +class ITHistSvc; + + + + +class AthHistogramAlgorithm + : public ::AthAlgorithm, + public ::AthHistogramming +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + /// Constructor with parameters: + AthHistogramAlgorithm( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~AthHistogramAlgorithm(); + + + /** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ + virtual StatusCode sysInitialize(); + + + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief The standard @c THistSvc (for writing histograms and TTrees + * and more to a root file) + * Returns (kind of) a pointer to the @c THistSvc + */ + ServiceHandle<ITHistSvc>& histSvc() const; + + + + + /////////////////////////////////////////////////////////////////// + // Private methods: + /////////////////////////////////////////////////////////////////// +private: + /// Default constructor: + ///AthHistogramAlgorithm(); + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + + /// a handle on the Hist/TTree registration service + mutable ServiceHandle<ITHistSvc> m_histSvc; + + + + /// Name of the ROOT output stream (file) + std::string m_prefix; + + /// Name of the ROOT directory + std::string m_rootDir; + + /// The prefix for the histogram THx name + std::string m_histNamePrefix; + + /// The postfix for the histogram THx name + std::string m_histNamePostfix; + + /// The prefix for the histogram THx title + std::string m_histTitlePrefix; + + /// The postfix for the histogram THx title + std::string m_histTitlePostfix; + + + +}; + +// I/O operators +////////////////////// + +// For the THistSvc +inline ServiceHandle<ITHistSvc>& AthHistogramAlgorithm::histSvc() const +{ + return m_histSvc; +} + + +#endif //> !ATHENABASECOMPS_ATHHISTOGRAMALGORITHM_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramFilterAlgorithm.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramFilterAlgorithm.h new file mode 100644 index 00000000..49be5e06 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramFilterAlgorithm.h @@ -0,0 +1,115 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// @class AthHistogramFilterAlgorithm.h +/// Header file for AthHistogramAlgorithm +/// @author: Karsten Koeneke (karsten.koeneke@cern.ch) +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHHISTOGRAMFILTERALGORITHM_H +#define ATHENABASECOMPS_ATHHISTOGRAMFILTERALGORITHM_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthFilterAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "GaudiKernel/ServiceHandle.h" + + +// Some needed forward declarations +class ITHistSvc; + + + + +class AthHistogramFilterAlgorithm + : public ::AthFilterAlgorithm, + public ::AthHistogramming +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + /// Constructor with parameters: + AthHistogramFilterAlgorithm( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~AthHistogramFilterAlgorithm(); + + /** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ + virtual StatusCode sysInitialize(); + + + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief The standard @c THistSvc (for writing histograms and TTrees + * and more to a root file) + * Returns (kind of) a pointer to the @c THistSvc + */ + ServiceHandle<ITHistSvc>& histSvc() const; + + + + /////////////////////////////////////////////////////////////////// + // Private methods: + /////////////////////////////////////////////////////////////////// +private: + /// Default constructor: + ///AthHistogramFilterAlgorithm(); + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + + /// a handle on the Hist/TTree registration service + mutable ServiceHandle<ITHistSvc> m_histSvc; + + + /// Name of the ROOT output stream (file) + std::string m_prefix; + + /// Name of the ROOT directory + std::string m_rootDir; + + /// The prefix for the histogram THx name + std::string m_histNamePrefix; + + /// The postfix for the histogram THx name + std::string m_histNamePostfix; + + /// The prefix for the histogram THx title + std::string m_histTitlePrefix; + + /// The postfix for the histogram THx title + std::string m_histTitlePostfix; + + + +}; + +// I/O operators +////////////////////// + +// For the THistSvc +inline ServiceHandle<ITHistSvc>& AthHistogramFilterAlgorithm::histSvc() const +{ + return m_histSvc; +} + +#endif //> !ATHENABASECOMPS_ATHHISTOGRAMFILTERALGORITHM_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramTool.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramTool.h new file mode 100644 index 00000000..37c6a5ff --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramTool.h @@ -0,0 +1,113 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthHistogramTool.h +// Header file for class AthHistogramTool +// Author: Karsten Koeneke +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHHISTOGRAMTOOL_H +#define ATHENABASECOMPS_ATHHISTOGRAMTOOL_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "GaudiKernel/ServiceHandle.h" + + +// Some needed forward declarations +class ITHistSvc; + + + +class AthHistogramTool + : public ::AthAlgTool, + public ::AthHistogramming +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + /// Constructor with parameters: + AthHistogramTool( const std::string& type, + const std::string& name, + const IInterface* parent ); + + + /// Destructor: + virtual ~AthHistogramTool(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief The standard @c THistSvc (for writing histograms and TTrees + * and more to a root file) + * Returns (kind of) a pointer to the @c THistSvc + */ + ServiceHandle<ITHistSvc>& histSvc() const; + + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ + virtual StatusCode sysInitialize(); + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +protected: + + /// Pointer to the THistSvc (event store by default) + mutable ServiceHandle<ITHistSvc> m_histSvc; + + + /// Name of the ROOT output stream (file) + std::string m_prefix; + + /// Name of the ROOT directory + std::string m_rootDir; + + /// The prefix for the histogram THx name + std::string m_histNamePrefix; + + /// The postfix for the histogram THx name + std::string m_histNamePostfix; + + /// The prefix for the histogram THx title + std::string m_histTitlePrefix; + + /// The postfix for the histogram THx title + std::string m_histTitlePostfix; + + +}; + + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +// For the THistSvc +inline ServiceHandle<ITHistSvc>& AthHistogramTool::histSvc() const +{ + return m_histSvc; +} + + +#endif //> !ATHENABASECOMPS_ATHHISTOGRAMTOOL_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramming.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramming.h new file mode 100644 index 00000000..3f8150f4 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthHistogramming.h @@ -0,0 +1,349 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthHistogramming.h +// Header file for class AthHistogramming +// Author: Karsten Koeneke +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHHISTOGRAMMING_H +#define ATHENABASECOMPS_ATHHISTOGRAMMING_H 1 + +// STL includes +#include <string> +#include <map> + +// FrameWork includes +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ITHistSvc.h" +#include "AthenaBaseComps/AthCheckMacros.h" +#include "SGTools/crc64.h" +#include "GaudiKernel/MsgStream.h" + +// ROOT includes +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" +#include "TTree.h" +#include "TGraph.h" + + + + +class AthHistogramming +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + /// Constructor with parameters: + AthHistogramming( const std::string& name ); + + + /// Destructor: + virtual ~AthHistogramming(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief The standard @c THistSvc (for writing histograms and TTrees + * and more to a root file) + * Returns (kind of) a pointer to the @c THistSvc + */ + ServiceHandle<ITHistSvc>& histSvc() const; + + + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +protected: + + /// To be called by the derived classes to fill the internal configuration + StatusCode configAthHistogramming ( ServiceHandle<ITHistSvc>& histSvc, + const std::string& prefix, const std::string& rootDir, + const std::string& histNamePrefix, const std::string& histNamePostfix, + const std::string& histTitlePrefix, const std::string& histTitlePostfix ); + + // ----------------------- + // For histogramming + // ----------------------- + + /// Simplify the booking and registering (into THistSvc) of histograms + inline TH1* bookGetPointer( const TH1& hist, const std::string& tDir="", const std::string& stream="" ); + + /// Simplify the booking and registering (into THistSvc) of histograms + inline TH1* bookGetPointer( TH1* hist, const std::string& tDir="", const std::string& stream="" ); + + /// Simplify the booking and registering (into THistSvc) of histograms + TH1* bookGetPointer( TH1& histRef, std::string tDir="", std::string stream="" ); + + + /// Simplify the booking and registering (into THistSvc) of histograms + inline StatusCode book( const TH1& hist, const std::string& tDir="", const std::string& stream="" ); + + /// Simplify the booking and registering (into THistSvc) of histograms + inline StatusCode book( TH1* hist, const std::string& tDir="", const std::string& stream="" ); + + /// Simplify the booking and registering (into THistSvc) of histograms + inline StatusCode book( TH1& histRef, const std::string& tDir="", const std::string& stream="" ); + + + ///Simplify the retrieval of registered histograms of any type + TH1* hist( const std::string& histName, const std::string& tDir="", const std::string& stream="" ); + + ///Simplify the retrieval of registered 2-d histograms + inline TH2* hist2d( const std::string& histName, const std::string& tDir="", const std::string& stream="" ); + + ///Simplify the retrieval of registered 3-d histograms + inline TH3* hist3d( const std::string& histName, const std::string& tDir="", const std::string& stream="" ); + + + // ----------------------- + // For TTrees + // ----------------------- + + /// Simplify the booking and registering (into THistSvc) of TTrees + TTree* bookGetPointer( const TTree& treeRef, std::string tDir="", std::string stream="" ); + + /// Simplify the booking and registering (into THistSvc) of TTrees + inline StatusCode book( const TTree& treeRef, const std::string& tDir="", const std::string& stream="" ); + + ///Simplify the retrieval of registered TTrees + TTree* tree( const std::string& treeName, const std::string& tDir="", const std::string& stream="" ); + + + // ----------------------- + // For TGraphs + // ----------------------- + + /// Simplify the booking and registering (into THistSvc) of TGraphs + TGraph* bookGetPointer( const TGraph& graphRef, std::string tDir="", std::string stream="" ); + + /// Simplify the booking and registering (into THistSvc) of TGraphs + inline StatusCode book( const TGraph& graphRef, const std::string& tDir="", const std::string& stream="" ); + + ///Simplify the retrieval of registered TGraphs + TGraph* graph( const std::string& graphName, const std::string& tDir="", const std::string& stream="" ); + + + + + /////////////////////////////////////////////////////////////////// + // Private methods: + /////////////////////////////////////////////////////////////////// +private: + /// typedef for the internal hash + typedef uint32_t hash_t; + + /// Method to build individual booking string + void buildBookingString( std::string& bookingString, + std::string& histName, + std::string& tDir, + std::string& stream, + bool usePrefixPostfix = false); + + /// Helper method to replace sub-string + void myReplace( std::string& str, + const std::string& oldStr, + const std::string& newStr); + + /// Method to calculate a 32-bit hash from a string + hash_t hash( const std::string& histName ) const; + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + + /// Pointer to the THistSvc (event store by default) + mutable ServiceHandle<ITHistSvc> m_histSvc; + + + /// Typedef for convenience + typedef std::map< const hash_t, TH1* > HistMap_t; + + /// The map of histogram names to their pointers + HistMap_t m_histMap; + + + /// Typedef for convenience + typedef std::map< const hash_t, TTree* > TreeMap_t; + + /// The map of TTree names to their pointers + TreeMap_t m_treeMap; + + + /// Typedef for convenience + typedef std::map< const hash_t, TGraph* > GraphMap_t; + + /// The map of TGraph names to their pointers + GraphMap_t m_graphMap; + + + /// Name of the ROOT output stream (file) + std::string m_streamName; + + /// Name of the ROOT directory + std::string m_rootDir; + + /// The prefix for the histogram THx name + std::string m_histNamePrefix; + + /// The postfix for the histogram THx name + std::string m_histNamePostfix; + + /// The prefix for the histogram THx title + std::string m_histTitlePrefix; + + /// The postfix for the histogram THx title + std::string m_histTitlePostfix; + + + /// Instance name + std::string m_name; + + ///Cached Message Stream + mutable MsgStream m_msg; + +}; + + + + + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline TH1* AthHistogramming::bookGetPointer( const TH1& hist, const std::string& tDir, const std::string& stream ) +{ + // We need to create a non-const clone + TH1* histClone = dynamic_cast< TH1* >( hist.Clone() ); + if ( !histClone ) { + m_msg << MSG::ERROR << "Couldn't create a TH1 clone in bookGetPointer" << endreq; + return 0; + } + return this->bookGetPointer( *histClone, tDir, stream ); + +} + +inline TH1* AthHistogramming::bookGetPointer( TH1* hist, const std::string& tDir, const std::string& stream ) +{ + if ( !hist ) { + m_msg << MSG::ERROR << "Got a zero pointer to a TH1 in bookGetPointer" << endreq; + return 0; + } + return this->bookGetPointer( *hist, tDir, stream ); +} + + +inline StatusCode AthHistogramming::book( const TH1& hist, const std::string& tDir, const std::string& stream ) +{ + // We need to create a non-const clone + TH1* histClone = dynamic_cast< TH1* >( hist.Clone() ); + if ( !histClone ) { + m_msg << MSG::ERROR << "Couldn't create a TH1 clone" << endreq; + return StatusCode::FAILURE; + } + return this->book( *histClone, tDir, stream ); +} + +inline StatusCode AthHistogramming::book( TH1* hist, const std::string& tDir, const std::string& stream ) +{ + if ( !hist ) { + m_msg << MSG::ERROR << "Got a zero pointer to a TH1" << endreq; + return StatusCode::FAILURE; + } + return this->book( *hist, tDir, stream ); +} + +// Simplify the booking and registering (into THistSvc) of histograms +inline StatusCode AthHistogramming::book( TH1& histRef, const std::string& tDir, const std::string& stream ) +{ + // Call the other Book method and see if it returns a valid pointer + TH1* histPointer = this->bookGetPointer( histRef, tDir, stream ); + if ( !histPointer ) { + m_msg << MSG::ERROR << "Couldn't book a TH1" << endreq; + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; +} + + +// Simplify the retrieval of registered 2-d histograms +inline TH2* AthHistogramming::hist2d( const std::string& histName, const std::string& tDir, const std::string& stream ) +{ + // Get the TH1 pointer + TH1* th1Pointer = this->hist(histName, tDir, stream); + if ( !th1Pointer ) + { + m_msg << MSG::ERROR + << "Cannot get a 2-d histogram with name " << histName + << "... will probably seg-fault!" << endreq; + return NULL; + } + // If the TH1 pointer is valid, simply return the dynamic_cast + return dynamic_cast<TH2*>( th1Pointer ); +} + + +// Simplify the retrieval of registered 3-d histograms +inline TH3* AthHistogramming::hist3d( const std::string& histName, const std::string& tDir, const std::string& stream ) +{ + // Get the TH1 pointer + TH1* th1Pointer = this->hist(histName, tDir, stream); + if ( !th1Pointer ) + { + m_msg << MSG::ERROR + << "Cannot get a 3-d histogram with name " << histName + << "... will probably seg-fault!" << endreq; + return NULL; + } + // If the TH1 pointer is valid, simply return the dynamic_cast + return dynamic_cast<TH3*>( th1Pointer ); +} + + + +// Simplify the booking and registering (into THistSvc) of TTrees +inline StatusCode AthHistogramming::book( const TTree& treeRef, const std::string& tDir, const std::string& stream ) +{ + // Call the other Book method and see if it returns a valid pointer + TTree* treePointer = this->bookGetPointer( treeRef, tDir, stream ); + if ( treePointer ) + { + return StatusCode::SUCCESS; + } + else + { + return StatusCode::FAILURE; + } +} + + + + +// For the THistSvc +inline ServiceHandle<ITHistSvc>& AthHistogramming::histSvc() const +{ + return m_histSvc; +} + + +// Create a 32-bit hash out of the histogram name +inline AthHistogramming::hash_t AthHistogramming::hash( const std::string& histName ) const +{ + const uint64_t hash64 = SG::crc64( histName ); + return (hash_t)(hash64 & 0xFFFFFFFF); +} + + +#endif //> !ATHENABASECOMPS_ATHHISTOGRAMMINGTOOL_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMemMacros.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMemMacros.h new file mode 100644 index 00000000..ebf55f5b --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMemMacros.h @@ -0,0 +1,27 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthMemMacros.h +// Header file for useful macros when comes to using SegMemSvc +// Author: S.Binet<binet@cern.ch> +// $Revision$ +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHMEMMACROS_H +#define ATHENABASECOMPS_ATHMEMMACROS_H 1 + +// framework includes +#include "StoreGate/SegMemSvc.h" + +// non-caching macros +#define ATH_NEW(T) \ + new(this->memSvc()->SegMemSvc::allocate< T >(::SegMemSvc::EVENT,false))T + +// caching macros +#define ATH_CNEW(T) \ + new(this->memSvc()->SegMemSvc::allocate< T >(::SegMemSvc::EVENT, true))T + +#endif //> !ATHENABASECOMPS_ATHMEMMACROS_H + diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMessaging.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMessaging.h new file mode 100644 index 00000000..b01437ff --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMessaging.h @@ -0,0 +1,127 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthMessaging.h +// Header file for class AthMessaging +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHMESSAGING_H +#define ATHENABASECOMPS_ATHMESSAGING_H 1 + +// STL includes +#include <iosfwd> +#include <string> + +// framework includes +#include "GaudiKernel/IMessageSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Property.h" +#include "AthenaBaseComps/AthMsgStreamMacros.h" + +/** @class AthMessaging AthMessaging.h AthenaBaseComps/AthMessaging.h + * + * Mixin class to provide easy @c MsgStream access and capabilities. + * One usually inherits from this class and use it like so: + * @code + * void some_method (AthMessaging& o) + * { o.msg() << "foo" << endreq; } + * @endcode + */ + +class AthMessaging +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /// Constructor with parameters: + AthMessaging (IMessageSvc* msgSvc, const std::string& name); + + /// Constructor, from an explicit existing stream. + AthMessaging (MsgStream& msg); + + /// Destructor: + virtual ~AthMessaging(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief Test the output level + * @param lvl The message level to test against + * @return boolean Indicting if messages at given level will be printed + * @retval true Messages at level "lvl" will be printed + */ + bool + msgLvl (const MSG::Level lvl) const; + + /** The standard message stream. + * Returns a reference to the default message stream + * May not be invoked before sysInitialize() has been invoked. + */ + MsgStream& msg() const; + + /** The standard message stream. + * Returns a reference to the default message stream + * May not be invoked before sysInitialize() has been invoked. + */ + MsgStream& + msg (const MSG::Level lvl) const; + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Private methods: + /////////////////////////////////////////////////////////////////// + private: + + /// Default constructor: + AthMessaging(); //> not implemented + AthMessaging( const AthMessaging& rhs ); //> not implemented + AthMessaging& operator=( const AthMessaging& rhs ); //> not implemented + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// MsgStream instance (a std::cout like with print-out levels) + mutable MsgStream m_msg; +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +//std::ostream& operator<<( std::ostream& out, const AthMessaging& o ); + +inline +bool +AthMessaging::msgLvl (const MSG::Level lvl) const +{ + if (m_msg.level() <= lvl) { + m_msg << lvl; + return true; + } else { + return false; + } +} + +inline +MsgStream& +AthMessaging::msg() const +{ return m_msg; } + +inline +MsgStream& +AthMessaging::msg (const MSG::Level lvl) const +{ return m_msg << lvl; } + + +#endif //> !ATHENABASECOMPS_ATHMESSAGING_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMsgStreamMacros.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMsgStreamMacros.h new file mode 100644 index 00000000..d7dfde97 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthMsgStreamMacros.h @@ -0,0 +1,42 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthMsgStreamMacros.h +// Header file for useful macros when comes to using MsgStream +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHMSGSTREAMMACROS_H +#define ATHENABASECOMPS_ATHMSGSTREAMMACROS_H 1 + +// CxxUtils +#include "CxxUtils/AthUnlikelyMacros.h" + +// FIXME: operator precedence ?! +#define ATH_MSG_LVL_NOCHK(lvl, x) \ + this->msg(lvl) << x << endmsg + +#define ATH_MSG_LVL(lvl, x) \ + do { \ + if (ATH_UNLIKELY(this->msgLvl (lvl))) { \ + ATH_MSG_LVL_NOCHK(lvl, x); \ + } \ + } while (0) + +#define ATH_MSG_VERBOSE(x) ATH_MSG_LVL(MSG::VERBOSE, x) +#define ATH_MSG_DEBUG(x) ATH_MSG_LVL(MSG::DEBUG, x) +// note that we are using the _NOCHK variant here +#define ATH_MSG_INFO(x) ATH_MSG_LVL_NOCHK(MSG::INFO, x) +#define ATH_MSG_WARNING(x) ATH_MSG_LVL_NOCHK(MSG::WARNING, x) +#define ATH_MSG_ERROR(x) ATH_MSG_LVL_NOCHK(MSG::ERROR, x) +#define ATH_MSG_FATAL(x) ATH_MSG_LVL_NOCHK(MSG::FATAL, x) +#define ATH_MSG_ALWAYS(x) ATH_MSG_LVL_NOCHK(MSG::ALWAYS, x) + +// can be used like so: ATH_MSG(INFO) << "hello" << endmsg; +#define ATH_MSG(lvl) \ + if (this->msgLvl(MSG::lvl)) this->msg(MSG::lvl) + +#endif //> !ATHENABASECOMPS_ATHMSGSTREAMMACROS_H + diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthReentrantAlgorithm.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthReentrantAlgorithm.h new file mode 100644 index 00000000..152f4eab --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthReentrantAlgorithm.h @@ -0,0 +1,102 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaBaseComps/AthReentrantAlgorithm.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief An algorithm that can be simultaneously executed in multiple threads. + */ + + +#ifndef ATHENABASECOMPS_ATHREENTRANTALGORITHM_H +#define ATHENABASECOMPS_ATHREENTRANTALGORITHM_H + + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "GaudiKernel/EventContext.h" + + +/** + * @brief An algorithm that can be simultaneously executed in multiple threads. + * + * The default behavior of AthenaMT when an algorithm is to be run on different + * events in multiple threads is to clone the algorithm object and use + * a different instance for each thread. If, however, your algorithm + * derives from @c AthReentrantAlgorithm, then the same algorithm object may + * be used in multiple threads without cloning. + * + * Rather than @c execute, a reentrant algorithm will call @c execute_r, + * which has two differences. First, @c execute_r is @c const. If the + * same object is being used in multiple threads, it should not have any + * state which is being changed. Any attempt to get around this with + * @c mutable or @c const_cast should be viewed with great suspicion: + * that may not be thread-safe. + * + * Second, the @c execute_r method takes an explicit event context argument. + * This may be used to find the proper store for the event being processed + * by the current thread. + * + * The typical usage will be to declare a key object as a property of the + * algorithm and then construct a transient handle instance during @c execute_r + * from the key and the event context. For example: + * + *@code + * class MyAlg : public AthReentrantAlgorithm + * { + * ... + * SG::ReadHandleKey<MyObj> m_rhandle; + * }; + * + * MyAlg::MyAlg (const std::string& name, ISvcLocator* svcLoc) + * : AthReentrantAlgorithm (name, svcLoc) + * { + * declareProperty ("rhandle", m_rhandle); + * } + * + * StatusCode MyAlg::initialize() + * { + * ATH_CHECK( m_rhandle.initialize() ); + * return StatusCode::SUCCESS; + * } + * + * StatusCode MyAlg::execute_r (const EventContext& ctx) + * { + * SG::ReadHandle<MyObj> myobj (m_rhandle, ctx); + * const MyObj& p = *myobj; + * ... + * } + @endcode + */ +class AthReentrantAlgorithm + : public AthAlgorithm +{ +public: + /// Use constructor from base class. + using AthAlgorithm::AthAlgorithm; + + + /** + * @brief Standard Gaudi execute method. + * + * This cannot be overridden; you should override the reentrant method + * @c execute_r instead. + */ + virtual StatusCode execute() override final; + + + /** + * @brief Reentrant execute method. + * @param ctx The current event context. + * + * Override this for your algorithm. + */ + virtual StatusCode execute_r (const EventContext& ctx) const = 0; +}; + + +#endif // not ATHENABASECOMPS_ATHREENTRANTALGORITHM_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthService.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthService.h new file mode 100644 index 00000000..60e5bb9d --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/AthService.h @@ -0,0 +1,106 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthService.h +// Header file for class AthService +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENABASECOMPS_ATHSERVICE_H +#define ATHENABASECOMPS_ATHSERVICE_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/Service.h" +#include "GaudiKernel/MsgStream.h" +#include "AthenaBaseComps/AthMessaging.h" +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#include "AthenaBaseComps/AthCheckMacros.h" + +#include "StoreGate/ReadHandle.h" +#include "StoreGate/UpdateHandle.h" +#include "StoreGate/WriteHandle.h" +#include "StoreGate/VarHandleProperty.h" + +// Forward declaration +class ISvcLocator; +template <class TYPE> class SvcFactory; + +class AthService : + public ::Service, + public ::AthMessaging +{ + protected: + friend class SvcFactory<AthService>; + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // fwd compat w/ gaudi-21 + using ::AthMessaging::msg; + + // Copy constructor: + + /// Constructor with parameters: + AthService( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~AthService(); + + /// Initialize @c AthService + virtual StatusCode sysInitialize(); + virtual StatusCode initialize(); + + /// ReInitialize @c AthService + virtual StatusCode sysReinitialize(); + virtual StatusCode reinitialize(); + + /// Finalize @c AthService + virtual StatusCode sysFinalize(); + virtual StatusCode finalize(); + + virtual StatusCode queryInterface( const InterfaceID& riid, + void** ppvInterface ); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Protected methods: + /////////////////////////////////////////////////////////////////// + protected: + + /// callback for output level property + void msg_update_handler(Property& outputLevel); + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// Default constructor: + AthService(); + AthService (const AthService&); + AthService& operator= (const AthService&); + + /// need to cache output level during initialize + int m_ol; + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +#endif //> ATHENABASECOMPS_ATHSERVICE_H diff --git a/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/FilteredAlgorithm.h b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/FilteredAlgorithm.h new file mode 100644 index 00000000..5a288ea1 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/AthenaBaseComps/FilteredAlgorithm.h @@ -0,0 +1,90 @@ +// Dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENABASECOMPS_FILTEREDALGORTITHM_H +#define ATHENABASECOMPS_FILTEREDALGORTITHM_H 1 + +// STL include files +#ifndef _CPP_MEMORY + #include <memory> +#endif +#ifndef _CPP_MAP + #include <map> +#endif +#ifndef _CPP_SET + #include <set> +#endif +#ifndef _CPP_VECTOR + #include <vector> +#endif +#ifndef _CPP_STRING + #include <string> +#endif + +// Required for inheritance +#ifndef GAUDIKERNEL_IDATASELECTOR_H + #include "GaudiKernel/IDataSelector.h" +#endif +#ifndef ATHENABASECOMPS_ATHALGORITHM_H + #include "AthenaBaseComps/AthAlgorithm.h" +#endif +//get the CLID typedef +#ifndef GAUDIKERNEL_CLASSID_H + #include "GaudiKernel/ClassID.h" +#endif +#ifndef GAUDIKERNEL_PROPERTY_H + #include "GaudiKernel/Property.h" +#endif +#ifndef GAUDIKERNEL_SERVICEHANDLE_H + #include "GaudiKernel/ServiceHandle.h" +#endif + +#include "AthenaKernel/IDecisionSvc.h" + +/** @class FilteredAlgorithm + * @brief algorithm that marks for write data objects in SG + * + * @author srinir@bnl.gov + * $Id: FilteredAlgorithm.h,v 1.3 2009-01-26 12:48:55 binet Exp $ + */ +class FilteredAlgorithm : public AthAlgorithm +{ + +protected: + + /// Vector of names of Algorithms that this stream accepts + StringArrayProperty m_acceptNames; + /// Vector of names of Algorithms that this stream requires + StringArrayProperty m_requireNames; + /// Vector of names of Algorithms that this stream is vetoed by + StringArrayProperty m_vetoNames; + + ServiceHandle<IDecisionSvc> m_decSvc; + +protected: + /// Standard algorithm Constructor + FilteredAlgorithm(const std::string& name, ISvcLocator* pSvcLocator); + /// Standard Destructor + virtual ~FilteredAlgorithm(); + +public: + /// \name implement IAlgorithm + //@{ + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode execute(); + //@} + + /// Test whether this event should be output + bool isEventAccepted( ) const; + + + FilteredAlgorithm(); //> not implemented + FilteredAlgorithm (const FilteredAlgorithm&); //> not implemented + FilteredAlgorithm& operator= (const FilteredAlgorithm&); //> not implemented +}; + +#endif // !ATHENABASECOMPS_FILTEREDALGORITHM_H diff --git a/EDM/athena/Control/AthenaBaseComps/CMakeLists.txt b/EDM/athena/Control/AthenaBaseComps/CMakeLists.txt new file mode 100644 index 00000000..ece92654 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/CMakeLists.txt @@ -0,0 +1,40 @@ +# $Id: CMakeLists.txt 739578 2016-04-12 07:34:46Z krasznaa $ +################################################################################ +# Package: AthenaBaseComps +################################################################################ + +# Declare the package name: +atlas_subdir( AthenaBaseComps ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/AthenaKernel + Control/CxxUtils + Control/SGTools + Control/StoreGate + GaudiKernel + PRIVATE + AtlasTest/TestTools ) + +# External dependencies: +find_package( ROOT COMPONENTS Hist Tree Core ) + +# Component(s) in the package: +atlas_add_library( AthenaBaseComps + AthenaBaseComps/*.h src/*.cxx + PUBLIC_HEADERS AthenaBaseComps + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaKernel CxxUtils SGTools GaudiKernel + StoreGateLib ) + +# Test(s) in the package: +atlas_add_test( propertyHandling_test + SOURCES test/propertyHandling_test.cxx + LINK_LIBRARIES StoreGateLib TestTools AthenaBaseComps + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( AthReentrantAlgorithm_test + SOURCES test/AthReentrantAlgorithm_test.cxx + LINK_LIBRARIES StoreGateLib GaudiKernel TestTools AthenaBaseComps + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) diff --git a/EDM/athena/Control/AthenaBaseComps/cmt/requirements b/EDM/athena/Control/AthenaBaseComps/cmt/requirements new file mode 100644 index 00000000..64d66298 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/cmt/requirements @@ -0,0 +1,33 @@ +package AthenaBaseComps + +author Sebastien Binet <binet@cern.ch> + +## For Athena policies: it has to be the first use statement +use AtlasPolicy AtlasPolicy-* + +## For Gaudi tools, services and objects +use GaudiInterface GaudiInterface-* External + +use AtlasROOT AtlasROOT-* External + +use AthenaKernel AthenaKernel-* Control +use StoreGate StoreGate-* Control +use SGTools SGTools-* Control +use CxxUtils CxxUtils-* Control + +# Add cmake compatibility (doesn't do anything on CMT side of things) +apply_pattern cmake_add_command command="find_package(ROOT COMPONENTS Hist Tree)" + +branches AthenaBaseComps src + +library AthenaBaseComps *.cxx + +apply_pattern installed_library +# apply_pattern declare_joboptions files="*.py" +# apply_pattern declare_python_modules files="*.py" + + +private +use TestTools TestTools-* AtlasTest +apply_pattern UnitTest_run unit_test=propertyHandling +apply_pattern UnitTest_run unit_test=AthReentrantAlgorithm diff --git a/EDM/athena/Control/AthenaBaseComps/share/AthReentrantAlgorithm_test.ref b/EDM/athena/Control/AthenaBaseComps/share/AthReentrantAlgorithm_test.ref new file mode 100644 index 00000000..f2362352 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/share/AthReentrantAlgorithm_test.ref @@ -0,0 +1,29 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/propertyHandling_test.txt +JobOptionsSvc INFO # =======> /home/sss/atlas/dvtest/build/../tests/../share/propertyHandling_test.txt +JobOptionsSvc INFO # (1,1): alg.rkey = "FooSvc/aaa" +JobOptionsSvc INFO # (2,1): alg.wkey = "BarSvc/bbb" +JobOptionsSvc INFO # (3,1): alg.ukey = "ccc" +JobOptionsSvc INFO # (4,1): alg.rhandle = "FooSvc/ddd" +JobOptionsSvc INFO # (5,1): alg.whandle = "BarSvc/eee" +JobOptionsSvc INFO # (6,1): alg.uhandle = "fff" +JobOptionsSvc INFO # (8,1): tool.rkey = "FooSvc/taa" +JobOptionsSvc INFO # (9,1): tool.wkey = "BarSvc/tbb" +JobOptionsSvc INFO # (10,1): tool.ukey = "tcc" +JobOptionsSvc INFO # (11,1): tool.rhandle = "FooSvc/tdd" +JobOptionsSvc INFO # (12,1): tool.whandle = "BarSvc/tee" +JobOptionsSvc INFO # (13,1): tool.uhandle = "tff" +JobOptionsSvc INFO Job options successfully read in from ../share/propertyHandling_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Thu Feb 18 19:08:47 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 diff --git a/EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.ref b/EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.ref new file mode 100644 index 00000000..726dec73 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.ref @@ -0,0 +1,26 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/propertyHandling_test.txt +JobOptionsSvc INFO # =======> /home/sss/atlas/dvtest/build/../tests/../share/propertyHandling_test.txt +JobOptionsSvc INFO # (1,1): alg.rkey = "FooSvc/aaa" +JobOptionsSvc INFO # (2,1): alg.wkey = "BarSvc/bbb" +JobOptionsSvc INFO # (3,1): alg.ukey = "ccc" +JobOptionsSvc INFO # (5,1): tool.rkey = "FooSvc/taa" +JobOptionsSvc INFO # (6,1): tool.wkey = "BarSvc/tbb" +JobOptionsSvc INFO # (7,1): tool.ukey = "tcc" +JobOptionsSvc INFO Job options successfully read in from ../share/propertyHandling_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Thu Feb 18 18:47:06 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 631 CLIDRegistry entries for module ALL +test2 diff --git a/EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.txt b/EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.txt new file mode 100644 index 00000000..bef99621 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/share/propertyHandling_test.txt @@ -0,0 +1,16 @@ +alg.rkey = "FooSvc/aaa"; +alg.wkey = "BarSvc/bbb"; +alg.ukey = "ccc"; +alg.rhandle = "FooSvc/ddd"; +alg.whandle = "BarSvc/eee"; +alg.uhandle = "fff"; + +tool.rkey = "FooSvc/taa"; +tool.wkey = "BarSvc/tbb"; +tool.ukey = "tcc"; +tool.rhandle = "FooSvc/tdd"; +tool.whandle = "BarSvc/tee"; +tool.uhandle = "tff"; + +ralg.rkey = "FooSvc/aaa"; +ralg.whandle = "BarSvc/eee"; diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthAlgTool.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthAlgTool.cxx new file mode 100644 index 00000000..eacf2e08 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthAlgTool.cxx @@ -0,0 +1,107 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthAlgTool.cxx +// Implementation file for class AthAlgTool +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + + +// STL includes + +// FrameWork includes + +// AthenaBaseComps includes +#include "AthenaBaseComps/AthAlgTool.h" + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthAlgTool::AthAlgTool( const std::string& type, + const std::string& name, + const IInterface* parent ) : + ::AlgTool ( type, name, parent ), + ::AthMessaging ( msgSvc(), name ), + m_evtStore ( "StoreGateSvc/StoreGateSvc", name ), + m_detStore ( "StoreGateSvc/DetectorStore", name ), + m_userStore ( "UserDataSvc/UserDataSvc", name ) +{ + // + // Property declaration + // + //declareProperty( "Property", m_nProperty ); + + auto props = getProperties(); + for( Property* prop : props ) { + if( prop->name() != "OutputLevel" ) { + continue; + } + prop->declareUpdateHandler + (&AthAlgTool::msg_update_handler, this); + break; + } + + declareProperty( "EvtStore", + m_evtStore = StoreGateSvc_t ("StoreGateSvc", name), + "Handle to a StoreGateSvc instance: it will be used to " + "retrieve data during the course of the job" ); + + declareProperty( "DetStore", + m_detStore = StoreGateSvc_t ("StoreGateSvc/DetectorStore", name), + "Handle to a StoreGateSvc/DetectorStore instance: it will be used to " + "retrieve data during the course of the job" ); + + declareProperty( "UserStore", + m_userStore = UserDataSvc_t ("UserDataSvc/UserDataSvc", name), + "Handle to a UserDataSvc/UserDataSvc instance: it will be used to " + "retrieve user data during the course of the job" ); +} + +// Destructor +/////////////// +AthAlgTool::~AthAlgTool() +{ + ATH_MSG_DEBUG ("Calling destructor"); +} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +void +AthAlgTool::msg_update_handler( Property& outputLevel ) +{ + // We can't just rely on the return value of msgLevel() here. Since it's + // not well defined whether the base class gets updated with the new + // output level first, or this class. So by default just use the property + // itself. The fallback is only there in case Gaudi changes its property + // type at one point, to be able to fall back on something. + IntegerProperty* iprop = dynamic_cast< IntegerProperty* >( &outputLevel ); + if( iprop ) { + msg().setLevel( iprop->value() ); + } else { + msg().setLevel( msgLevel() ); + } +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthAlgorithm.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthAlgorithm.cxx new file mode 100644 index 00000000..e419251f --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthAlgorithm.cxx @@ -0,0 +1,107 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthAlgorithm.cxx +// Implementation file for class AthAlgorithm +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaBaseComps includes +#include "AthenaBaseComps/AthAlgorithm.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthAlgorithm::AthAlgorithm( const std::string& name, + ISvcLocator* pSvcLocator, + const std::string& version ) : + ::Algorithm ( name, pSvcLocator, version ), + ::AthMessaging( msgSvc(), name ), + m_evtStore ( "StoreGateSvc/StoreGateSvc", name ), + m_detStore ( "StoreGateSvc/DetectorStore", name ), + m_userStore ( "UserDataSvc/UserDataSvc", name ) +{ + // + // Property declaration + // + //declareProperty( "Property", m_nProperty ); + + auto props = getProperties(); + for( Property* prop : props ) { + if( prop->name() != "OutputLevel" ) { + continue; + } + prop->declareUpdateHandler + (&AthAlgorithm::msg_update_handler, this); + break; + } + + declareProperty( "EvtStore", + m_evtStore = StoreGateSvc_t ("StoreGateSvc", name), + "Handle to a StoreGateSvc instance: it will be used to " + "retrieve data during the course of the job" ); + + declareProperty( "DetStore", + m_detStore = StoreGateSvc_t ("StoreGateSvc/DetectorStore", name), + "Handle to a StoreGateSvc/DetectorStore instance: it will be used to " + "retrieve data during the course of the job" ); + + declareProperty( "UserStore", + m_userStore = UserDataSvc_t ("UserDataSvc/UserDataSvc", name), + "Handle to a UserDataSvc/UserDataSvc instance: it will be used to " + "retrieve user data during the course of the job" ); +} + +// Destructor +/////////////// +AthAlgorithm::~AthAlgorithm() +{ + ATH_MSG_DEBUG ("Calling destructor"); +} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +void +AthAlgorithm::msg_update_handler( Property& outputLevel ) +{ + // We can't just rely on the return value of msgLevel() here. Since it's + // not well defined whether the base class gets updated with the new + // output level first, or this class. So by default just use the property + // itself. The fallback is only there in case Gaudi changes its property + // type at one point, to be able to fall back on something. + IntegerProperty* iprop = dynamic_cast< IntegerProperty* >( &outputLevel ); + if( iprop ) { + msg().setLevel( iprop->value() ); + } else { + msg().setLevel( msgLevel() ); + } +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthCnvSvc.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthCnvSvc.cxx new file mode 100644 index 00000000..0c40845d --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthCnvSvc.cxx @@ -0,0 +1,637 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthCnvSvc.cxx +// Implementation file for class AthCnvSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/SvcFactory.h" +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/System.h" +#include "GaudiKernel/IConverter.h" +#include "GaudiKernel/IDataProviderSvc.h" +#include "GaudiKernel/IOpaqueAddress.h" + +// AthenaBaseComps includes +#include "AthenaBaseComps/AthCnvSvc.h" + +#ifndef HAVE_GAUDI_PLUGINSVC + namespace Rflx = ROOT::Reflex; +#endif +#include "GAUDI_VERSION.h" + +#include "GaudiKernel/Converter.h" + +enum CnvSvcAction { + CREATE_OBJ, + FILL_OBJ_REFS, + UPDATE_OBJ, + UPDATE_OBJ_REFS, + CREATE_REP, + FILL_REP_REFS, + UPDATE_REP, + UPDATE_REP_REFS +}; + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthCnvSvc::AthCnvSvc (const std::string& name, + ISvcLocator* pSvcLocator, + long type) : + ::AthService (name, pSvcLocator), + m_dataSvc (0), + m_addressCreator(0), + m_type (type), + m_workers ( ) +{ + // + // Property declaration + // + //declareProperty( "Property", m_nProperty ); + setAddressCreator(this).ignore(); + + m_cnvSvc = this; +} + +// Destructor +/////////////// +AthCnvSvc::~AthCnvSvc() +{ + // the following is hopefully (!) temporary hack to prevent deleting + // services we hold a reference count to. + // the problem is that these references might point back to us (so we + // end up recursively calling the d-tor) or be double-deleted later on + // by the ServiceManager. + // the correct fix is to have everybody use SmartIF<T> all over the code... + // + // "temporary hack" ha ha! (CGL 5/2014) + // + if (m_cnvSvc) { + m_cnvSvc->addRef(); + m_cnvSvc = 0; + } + if (m_addressCreator) { + m_addressCreator->addRef(); + m_addressCreator = 0; + } + if (m_dataSvc) { + m_dataSvc->addRef(); + m_dataSvc = 0; + } + + ATH_MSG_DEBUG ("release-ing all workers (" << m_workers.size() << ")..."); + for ( Workers::iterator + i = m_workers.begin(), + iend = m_workers.end(); + i != iend; + ++i ) { + IConverter *cnv = i->second.m_converter; + if (cnv) { + + if (!cnv->release()) { + i->second.m_converter = 0; + } + } + } + ATH_MSG_DEBUG ("release-ing all workers (" << m_workers.size() << ")... [done]"); + m_workers.clear(); + +} + +// Athena Service's Hooks +//////////////////////////// +StatusCode AthCnvSvc::initialize() +{ + return StatusCode::SUCCESS; +} + +StatusCode AthCnvSvc::finalize() +{ + ATH_MSG_DEBUG ("releasing all workers"); + for ( Workers::iterator + i = m_workers.begin(), + iend = m_workers.end(); + i != iend; + ++i ) { + if (!i->second.converter()->finalize().isSuccess()) { + ATH_MSG_ERROR ("finalizing worker w/ clid=[" << i->first << "]"); + } + i->second.converter()->release(); + } + //m_workers.clear(); + Workers().swap (m_workers); + + if (m_addressCreator) m_addressCreator->addRef(); + if (m_dataSvc) m_dataSvc->addRef(); + if (m_cnvSvc) m_cnvSvc->addRef(); + + m_addressCreator = 0; + m_dataSvc = 0; + m_cnvSvc = 0; + + return StatusCode::SUCCESS; +} + +// Query the interfaces. +// Input: riid, Requested interface ID +// ppvInterface, Pointer to requested interface +// Return: StatusCode indicating SUCCESS or FAILURE. +// N.B. Don't forget to release the interface after use!!! +StatusCode +AthCnvSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( riid == IConversionSvc::interfaceID() ) { + *ppvInterface = (IConversionSvc*)this; + } + else if ( riid == IConverter::interfaceID() ) { + *ppvInterface = (IConverter*)this; + } + else if ( riid == IAddressCreator::interfaceID() ) { + *ppvInterface = (IAddressCreator*)this; + } + else { + // Interface is not directly availible: try out a base class + return AthService::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + +///@name @c IConversionSvc implementation +//@{ +/// Retrieve the class type of the data store the converter uses. +long +AthCnvSvc::repSvcType() const +{ + return m_type; +} + +/// Implementation of IConverter: dummy call +const CLID& +AthCnvSvc::objType() const +{ + return CLID_NULL; +} + +/** Implementation of IConverter: Set Data provider service + @return Status code indicating success or failure + @param pService Pointer to data provider service +*/ +StatusCode +AthCnvSvc::setDataProvider(IDataProviderSvc* pDataSvc) +{ + if ( !pDataSvc ) return StatusCode::SUCCESS; //Atlas does not use DataSvc + if ( m_dataSvc ) m_dataSvc->release(); + m_dataSvc = pDataSvc; + m_dataSvc->addRef(); + Workers::iterator stop = m_workers.end(); + Workers::iterator start = m_workers.begin(); + for(Workers::iterator i=start; i != stop; i++ ) { + IConverter* cnv = i->second.converter(); + if ( 0 != cnv ) { + if (cnv->setDataProvider(m_dataSvc).isFailure()) { + ATH_MSG_ERROR ("setting Data Provider"); + } + } + } + return StatusCode::SUCCESS; +} + +/** Implementation of IConverter: Get Data provider service + @return Pointer to data provider service +*/ +SmartIF<IDataProviderSvc>& +AthCnvSvc::dataProvider() const +{ + return m_dataSvc; +} + +/// Implementation of IConverter: +/// Set conversion service the converter is connected to +StatusCode +AthCnvSvc::setConversionSvc(IConversionSvc* /*svc*/) +{ + return StatusCode::FAILURE; +} + +/// Implementation of IConverter: +/// Get conversion service the converter is connected to +SmartIF<IConversionSvc>& +AthCnvSvc::conversionSvc() const +{ + return m_cnvSvc; +} + +/// Set address creator facility +StatusCode +AthCnvSvc::setAddressCreator(IAddressCreator* creator) +{ + m_addressCreator = creator; + Workers::iterator stop = m_workers.end(); + Workers::iterator start = m_workers.begin(); + for(Workers::iterator i=start; i != stop; i++ ) { + IConverter* cnv = i->second.converter(); + if ( 0 != cnv ) { + if (cnv->setAddressCreator(m_addressCreator).isFailure()) { + ATH_MSG_ERROR ("setting Address Creator"); + } + } + } + return StatusCode::SUCCESS; +} + +/// Retrieve address creator facility +SmartIF<IAddressCreator>& +AthCnvSvc::addressCreator() const +{ + return m_addressCreator; +} + +/// Implementation of IConverter: +/// Create the transient representation of an object. +StatusCode +AthCnvSvc::createObj(IOpaqueAddress* pAddress,DataObject*& refpObject) +{ + return makeCall (CREATE_OBJ, false, true, false, pAddress, refpObject); +} + +/// Implementation of IConverter: +/// Resolve the references of the created transient object. +StatusCode +AthCnvSvc::fillObjRefs(IOpaqueAddress* pAddress, DataObject* pObject) +{ + return makeCall (FILL_OBJ_REFS, false, true, true, pAddress, pObject); +} + +/// Implementation of IConverter: +/// Update the transient object from the other representation. +StatusCode +AthCnvSvc::updateObj(IOpaqueAddress* pAddress, DataObject* pObject) +{ + return makeCall (UPDATE_OBJ, false, true, false, pAddress, pObject); +} + +/// Implementation of IConverter: +/// Update the references of an updated transient object. +StatusCode +AthCnvSvc::updateObjRefs(IOpaqueAddress* pAddress, DataObject* pObject) +{ + return makeCall (UPDATE_OBJ_REFS, false, true, true, pAddress, pObject); +} + +/// Implementation of IConverter: +/// Convert the transient object to the requested representation. +StatusCode +AthCnvSvc::createRep(DataObject* pObject, IOpaqueAddress*& refpAddress) +{ + return makeCall (CREATE_REP, true, false, false, refpAddress, pObject); +} + +/// Implementation of IConverter: +/// Resolve the references of the converted object. +StatusCode +AthCnvSvc::fillRepRefs(IOpaqueAddress* pAddress,DataObject* pObject) +{ + return makeCall (FILL_REP_REFS, true, false, false, pAddress, pObject); +} + +/// Implementation of IConverter: +/// Update the converted representation of a transient object. +StatusCode +AthCnvSvc::updateRep(IOpaqueAddress* pAddress, DataObject* pObject) +{ + return makeCall (UPDATE_REP, true, false, false, pAddress, pObject); +} + +/// Implementation of IConverter: +/// Update the references of an already converted object. +StatusCode +AthCnvSvc::updateRepRefs(IOpaqueAddress* pAddress, DataObject* pObject) +{ + return makeCall (UPDATE_REP_REFS, true, false, false, pAddress, pObject); +} + +/// Add converter object to conversion service. +StatusCode +AthCnvSvc::addConverter(const CLID& clid) +{ + // First look for the more specific converter + long typ = repSvcType(); + IConverter* pConverter = createConverter(typ, clid, 0); + if ( 0 != pConverter ) { + StatusCode status = configureConverter( typ, clid, pConverter ); + if ( status.isSuccess() ) { + status = initializeConverter( typ, clid, pConverter ); + if ( status.isSuccess() ) { + status = activateConverter( typ, clid, pConverter ); + if ( status.isSuccess() ) { + long conv_typ = pConverter->repSvcType(); + const CLID& conv_clid = pConverter->objType(); + typ = (typ<0xFF) ? typ : typ&0xFFFFFF00; + conv_typ = (conv_typ<0xFF) ? conv_typ : conv_typ&0xFFFFFF00; + if ( conv_typ == typ && conv_clid == clid ) { + return addConverter(pConverter); + } + } + } + } + pConverter->release(); + } + return NO_CONVERTER; +} + +/// Add converter object to conversion service. +StatusCode +AthCnvSvc::addConverter(IConverter* pConverter) +{ + if ( 0 != pConverter ) { + const CLID& clid = pConverter->objType(); + removeConverter(clid).ignore(); + m_workers.insert (std::make_pair(clid,WorkerEntry(clid, pConverter))); + pConverter->addRef(); + return StatusCode::SUCCESS; + } + return NO_CONVERTER; +} + +/// Remove converter object from conversion service (if present). +StatusCode +AthCnvSvc::removeConverter(const CLID& clid) +{ + Workers::iterator worker = m_workers.find (clid); + if ( worker != m_workers.end() ) { + worker->second.converter()->finalize().ignore(); + worker->second.converter()->release(); + + m_workers.erase (worker); + return StatusCode::SUCCESS; + } + return NO_CONVERTER; +} + +/// Retrieve converter from list +IConverter* +AthCnvSvc::converter(const CLID& clid) +{ + Workers::iterator worker = m_workers.find (clid); + if ( worker != m_workers.end() ) { + return worker->second.converter(); + } + if (addConverter (clid).isSuccess()) { + worker = m_workers.find (clid); + if (worker != m_workers.end()) { + return worker->second.converter(); + } + } else { + ATH_MSG_INFO("problem adding converter for CLID [" << clid << "]"); + } + return 0; +} + +/// Connect the output file to the service with open mode. +StatusCode +AthCnvSvc::connectOutput (const std::string& outputFile, + const std::string& /*openMode*/) +{ + return connectOutput (outputFile); +} + +/// Connect the output file to the service. +StatusCode +AthCnvSvc::connectOutput(const std::string& /*output*/) +{ + return StatusCode::SUCCESS; +} + +/// Commit pending output. +StatusCode +AthCnvSvc::commitOutput(const std::string& /*output*/, bool /*do_commit*/) +{ + return StatusCode::SUCCESS; +} +//@} + +/// Disconnect output files from the service. +StatusCode +AthCnvSvc::disconnectOutput() +{ + return StatusCode::SUCCESS; +} + +/// @name @c IAddressCreator interface implementation +//@{ +/// Create a Generic address using explicit arguments to identify a +/// single object. +StatusCode +AthCnvSvc::createAddress (long /*svc_type*/, + const CLID& /*clid*/, + const std::string* /*par*/, + const unsigned long* /*ip*/, + IOpaqueAddress*& refpAddress) +{ + refpAddress = 0; + return StatusCode::FAILURE; +} + +/// Convert an address to string form +StatusCode +AthCnvSvc::convertAddress (const IOpaqueAddress* /*pAddress*/, + std::string& refAddress) +{ + refAddress = ""; + return StatusCode::FAILURE; +} + +/// Convert an address in string form to object form +StatusCode +AthCnvSvc::createAddress (long /*svc_type*/, + const CLID& /*clid*/, + const std::string& /*refAddress*/, + IOpaqueAddress*& refpAddress) +{ + refpAddress = 0; + return StatusCode::FAILURE; +} + +/// Update state of the service +StatusCode +AthCnvSvc::updateServiceState(IOpaqueAddress* /*pAddress*/) +{ + return StatusCode::SUCCESS; +} +//@} + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/// Create new Converter using factory +IConverter* +AthCnvSvc::createConverter (long typ, + const CLID& clid, + const ICnvFactory* /*fac*/) +{ + IConverter *cnv = 0; + +#ifdef HAVE_GAUDI_PLUGINSVC +#if GAUDI_VERSION > CALC_GAUDI_VERSION(25, 3) + cnv = Gaudi::PluginService::Factory<IConverter*, ISvcLocator*>::create + (ConverterID(typ,clid), serviceLocator().get() ); +#else + cnv = Gaudi::PluginService::Factory1<IConverter*, ISvcLocator*>::create + (ConverterID(typ,clid), serviceLocator().get() ); +#endif +#else + cnv = Rflx::PluginService::CreateWithId<IConverter*> + (ConverterID (typ,clid), serviceLocator().get()); +#endif + + if (0==cnv) { + typ = (typ<0xFF) ? typ : typ&0xFFFFFF00; +#ifdef HAVE_GAUDI_PLUGINSVC +#if GAUDI_VERSION > CALC_GAUDI_VERSION(25, 3) + cnv = Gaudi::PluginService::Factory<IConverter*, ISvcLocator*>::create + (ConverterID(typ,clid), serviceLocator().get() ); +#else + cnv = Gaudi::PluginService::Factory1<IConverter*, ISvcLocator*>::create + (ConverterID(typ,clid), serviceLocator().get() ); +#endif +#else + cnv = Rflx::PluginService::CreateWithId<IConverter*> + (ConverterID(typ,clid), serviceLocator().get()); +#endif + } + return cnv; + +} + +/// Configure the new converter before initialize is called +StatusCode +AthCnvSvc::configureConverter (long /*typ*/, const CLID& /*clid*/, + IConverter* cnv) +{ + if (cnv) { + cnv->setConversionSvc(this).ignore(); + cnv->setAddressCreator(m_addressCreator).ignore(); + cnv->setDataProvider(m_dataSvc).ignore(); + return StatusCode::SUCCESS; + } + return NO_CONVERTER; + +} + +/// Initialize the new converter +StatusCode +AthCnvSvc::initializeConverter (long /*typ*/, const CLID& /*clid*/, + IConverter* cnv) +{ + if (cnv) { + return cnv->initialize(); + } + return NO_CONVERTER; +} + +/// Activate the new converter after initialization +StatusCode +AthCnvSvc::activateConverter (long /*typ*/, const CLID& /*clid*/, + IConverter* cnv) +{ + if (cnv) { + return StatusCode::SUCCESS; + } + return NO_CONVERTER; +} + +/// Load converter or dictionary needed by the converter +void +AthCnvSvc::loadConverter(DataObject* /*pObject*/) +{ +} + + +StatusCode +AthCnvSvc::makeCall (int typ, + bool ignore_add, + bool ignore_obj, + bool update, + IOpaqueAddress*& pAddress, + DataObject*& pObject) +{ + if ( 0 != pAddress || ignore_add ) { + if ( 0 != pObject || ignore_obj ) { + const CLID& obj_class = + (0 != pObject && !ignore_obj) ? pObject->clID() + : (0 != pAddress && !ignore_add) + ? pAddress->clID() + : CLID_NULL; + IConverter* cnv = converter(obj_class); + if ( !cnv && pObject ) { + //Give it a try to autoload the class (dictionary) for which the converter is needed + loadConverter( pObject); + cnv = converter(obj_class); + } + + StatusCode status(StatusCode::FAILURE,true); + if ( 0 != cnv ) { + switch(typ) { + case CREATE_OBJ: + pObject = 0; + status = cnv->createObj(pAddress, pObject); + break; + case FILL_OBJ_REFS: + status = cnv->fillObjRefs(pAddress, pObject); + break; + case UPDATE_OBJ: + status = cnv->updateObj(pAddress, pObject); + break; + case UPDATE_OBJ_REFS: + status = cnv->updateObjRefs(pAddress, pObject); + break; + case CREATE_REP: + pAddress = 0; + status = cnv->createRep(pObject, pAddress); + break; + case FILL_REP_REFS: + status = cnv->fillRepRefs(pAddress, pObject); + break; + case UPDATE_REP: + status = cnv->updateRep(pAddress, pObject); + break; + case UPDATE_REP_REFS: + status = cnv->updateRepRefs(pAddress, pObject); + break; + default: + status = StatusCode::FAILURE; + break; + } + if ( status.isSuccess() && update ) { + status = updateServiceState(pAddress); + } + return status; + } + status.ignore(); + msg(MSG::INFO) << "No converter for object "; + if ( pObject != 0 ) { + msg(MSG::INFO) << System::typeinfoName(typeid(*pObject)); + } + msg(MSG::INFO) << " CLID= " << obj_class << endmsg; + return NO_CONVERTER; + } + return INVALID_OBJECT; + } + return INVALID_ADDRESS; +} + diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthFilterAlgorithm.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthFilterAlgorithm.cxx new file mode 100644 index 00000000..5cfca63e --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthFilterAlgorithm.cxx @@ -0,0 +1,124 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthFilterAlgorithm.cxx +// Implementation file for class AthFilterAlgorithm +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaBaseComps includes +#include "AthenaBaseComps/AthFilterAlgorithm.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthFilterAlgorithm::AthFilterAlgorithm( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthAlgorithm( name, pSvcLocator ), + m_cutID ( 0 ), + m_cutFlowSvc("CutFlowSvc/CutFlowSvc", name) +{ + // + // Property declaration + // + //declareProperty( "Property", m_nProperty ); + + declareProperty("CutFlowSvc", m_cutFlowSvc, + "handle to the ICutFlowSvc instance this filtering algorithm" + " will use for building the flow of cuts."); + + declareProperty("FilterDescription", m_filterDescr = "N/A", + "describe to the cutflowsvc what this filter does.") + ->declareUpdateHandler(&AthFilterAlgorithm::doNotResetSelfDescription, this); + m_resetSelfDescription=true; +} + +// Destructor +/////////////// +AthFilterAlgorithm::~AthFilterAlgorithm() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ +StatusCode +AthFilterAlgorithm::sysInitialize() +{ + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- + // Bypass the initialization if the algorithm + // has already been initialized. + if ( Gaudi::StateMachine::INITIALIZED <= FSMState() ) return StatusCode::SUCCESS; + + // Set the Algorithm's properties + ATH_CHECK(setProperties()); + + // Bypass the initialization if the algorithm is disabled. + // Need to do this after setProperties. + if ( !isEnabled( ) ) return StatusCode::SUCCESS; + + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- END --- + + // register ourselves with the cutFlowSvc + if ( cutFlowSvc().retrieve().isSuccess()) { + m_cutID = cutFlowSvc()->registerFilter(this->name(), m_filterDescr); + if (0 == m_cutID) { + ATH_MSG_INFO("problem registering myself with cutflow-svc"); + } else { + ATH_MSG_VERBOSE("registered with cutflow-svc"); + } + } + + // re-direct to base class... + return AthAlgorithm::sysInitialize(); +} + +/// Set the filter passed flag to the specified state +void +AthFilterAlgorithm::setFilterPassed( bool state ) +{ + AthAlgorithm::setFilterPassed(state); + + if (state) { + m_cutFlowSvc->addEvent(m_cutID); + } +} + +/// @brief helper function to ease the setting of this filter's description +/// in derived classes +void +AthFilterAlgorithm::setFilterDescription(const std::string& descr) +{ + if( cutFlowSvc()==0 ){ + m_filterDescr = descr; + } + else if( m_resetSelfDescription and cutID() ){ + cutFlowSvc()->setFilterDescription(cutID(),descr); + } + else{ + ATH_MSG_INFO("problem setting filter description with cutflow-svc"); + } + + return; +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthHistogramAlgorithm.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramAlgorithm.cxx new file mode 100644 index 00000000..d086e791 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramAlgorithm.cxx @@ -0,0 +1,114 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// @class AthHistogramAlgorithm.h +/// Header file for class AthHistogramAlgorithm +/// @author: Karsten Koeneke (karsten.koeneke@cern.ch) +/////////////////////////////////////////////////////////////////// + +// This class' header file +#include "AthenaBaseComps/AthHistogramAlgorithm.h" + +// STL includes +#include <string> +#include <map> + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/ITHistSvc.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthHistogramAlgorithm::AthHistogramAlgorithm( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthAlgorithm( name, pSvcLocator ), + ::AthHistogramming( name ), + m_histSvc ( "THistSvc/THistSvc", name ) +{ + // + // Property declaration + // + // The histogram service + declareProperty("THistSvc", + m_histSvc = ServiceHandle<ITHistSvc>("THistSvc/THistSvc", name), + "Handle to a THistSvc instance: it will be used to write " + "ROOT objects to ROOT files" ); + // declareProperty("THistService", m_histSvc, "The THistSvc" ); + + declareProperty("RootStreamName", m_prefix = "/", "Name of the output ROOT stream (file) that the THistSvc uses"); + declareProperty("RootDirName", m_rootDir = "", + "Name of the ROOT directory inside the ROOT file where the histograms will go"); + + declareProperty( "HistNamePrefix", m_histNamePrefix = "", "The prefix for the histogram THx name" ); + declareProperty( "HistNamePostfix", m_histNamePostfix = "", "The postfix for the histogram THx name" ); + + declareProperty( "HistTitlePrefix", m_histTitlePrefix = "", "The prefix for the histogram THx title" ); + declareProperty( "HistTitlePostfix", m_histTitlePostfix = "", "The postfix for the histogram THx title" ); +} + + + + +// Destructor +/////////////// +AthHistogramAlgorithm::~AthHistogramAlgorithm() +{ + ATH_MSG_DEBUG ("Calling destructor"); +} + + + +/** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ +StatusCode AthHistogramAlgorithm::sysInitialize() +{ + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- + // Bypass the initialization if the algorithm + // has already been initialized. + if ( Gaudi::StateMachine::INITIALIZED <= FSMState() ) return StatusCode::SUCCESS; + + // Set the Algorithm's properties + ATH_CHECK(setProperties()); + + // Bypass the initialization if the algorithm is disabled. + // Need to do this after setProperties. + if ( !isEnabled( ) ) return StatusCode::SUCCESS; + + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- END --- + + + // Get the THistSvc + ATH_CHECK ( histSvc().retrieve() ); + + // Configure the underlying AthHistogramming helper + ATH_CHECK ( AthHistogramming::configAthHistogramming( histSvc(), + m_prefix, m_rootDir, + m_histNamePrefix, m_histNamePostfix, + m_histTitlePrefix, m_histTitlePostfix ) ); + + // Print some setup information into the log file + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + ATH_MSG_DEBUG (" using THistService = " << m_histSvc ); + ATH_MSG_DEBUG (" using RootStreamName = " << m_prefix ); + ATH_MSG_DEBUG (" using RootDirName = " << m_rootDir ); + ATH_MSG_DEBUG (" using HistNamePrefix = " << m_histNamePrefix ); + ATH_MSG_DEBUG (" using HistNamePostfix = " << m_histNamePostfix ); + ATH_MSG_DEBUG (" using HistTitlePrefix = " << m_histTitlePrefix ); + ATH_MSG_DEBUG (" using HistTitlePostfix = " << m_histTitlePostfix ); + + + // re-direct to base class... + return AthAlgorithm::sysInitialize(); +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthHistogramFilterAlgorithm.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramFilterAlgorithm.cxx new file mode 100644 index 00000000..3d5aff30 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramFilterAlgorithm.cxx @@ -0,0 +1,114 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// @class AthHistogramFilterAlgorithm.h +/// Header file for class AthHistogramAlgorithm +/// @author: Karsten Koeneke (karsten.koeneke@cern.ch) +/////////////////////////////////////////////////////////////////// + +// This class' header file +#include "AthenaBaseComps/AthHistogramFilterAlgorithm.h" + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/ITHistSvc.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthHistogramFilterAlgorithm::AthHistogramFilterAlgorithm( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthFilterAlgorithm( name, pSvcLocator ), + ::AthHistogramming( name ), + m_histSvc ( "THistSvc/THistSvc", name ) +{ + // + // Property declaration + // + // The histogram service + declareProperty("THistSvc", + m_histSvc = ServiceHandle<ITHistSvc>("THistSvc/THistSvc", name), + "Handle to a THistSvc instance: it will be used to write " + "ROOT objects to ROOT files" ); + + //declareProperty("THistService", m_histSvc, "The THistSvc" ); + declareProperty("RootStreamName", m_prefix = "/", "Name of the output ROOT stream (file) that the THistSvc uses"); + declareProperty("RootDirName", m_rootDir = "", + "Name of the ROOT directory inside the ROOT file where the histograms will go"); + + declareProperty( "HistNamePrefix", m_histNamePrefix = "", "The prefix for the histogram THx name" ); + declareProperty( "HistNamePostfix", m_histNamePostfix = "", "The postfix for the histogram THx name" ); + + declareProperty( "HistTitlePrefix", m_histTitlePrefix = "", "The prefix for the histogram THx title" ); + declareProperty( "HistTitlePostfix", m_histTitlePostfix = "", "The postfix for the histogram THx title" ); +} + + + + +// Destructor +/////////////// +AthHistogramFilterAlgorithm::~AthHistogramFilterAlgorithm() +{ + ATH_MSG_DEBUG ("Calling destructor"); +} + + + +/** Initialization method invoked by the framework. This method is responsible + * for any bookkeeping of initialization required by the framework itself. + * It will in turn invoke the initialize() method of the derived algorithm, + * and of any sub-algorithms which it creates. + */ +StatusCode AthHistogramFilterAlgorithm::sysInitialize() +{ + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- + // Bypass the initialization if the algorithm + // has already been initialized. + if ( Gaudi::StateMachine::INITIALIZED <= FSMState() ) return StatusCode::SUCCESS; + + // Set the Algorithm's properties + ATH_CHECK(setProperties()); + + // Bypass the initialization if the algorithm is disabled. + // Need to do this after setProperties. + if ( !isEnabled( ) ) return StatusCode::SUCCESS; + + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- END --- + + + // Get the THistSvc + ATH_CHECK ( histSvc().retrieve() ); + + // Configure the underlying AthHistogramming helper + ATH_CHECK ( AthHistogramming::configAthHistogramming( histSvc(), + m_prefix, m_rootDir, + m_histNamePrefix, m_histNamePostfix, + m_histTitlePrefix, m_histTitlePostfix ) ); + + // Print some setup information into the log file + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + ATH_MSG_DEBUG (" using THistService = " << m_histSvc ); + ATH_MSG_DEBUG (" using RootStreamName = " << m_prefix ); + ATH_MSG_DEBUG (" using RootDirName = " << m_rootDir ); + ATH_MSG_DEBUG (" using HistNamePrefix = " << m_histNamePrefix ); + ATH_MSG_DEBUG (" using HistNamePostfix = " << m_histNamePostfix ); + ATH_MSG_DEBUG (" using HistTitlePrefix = " << m_histTitlePrefix ); + ATH_MSG_DEBUG (" using HistTitlePostfix = " << m_histTitlePostfix ); + + + // re-direct to base class... + return AthFilterAlgorithm::sysInitialize(); +} + diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthHistogramTool.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramTool.cxx new file mode 100644 index 00000000..9ef63809 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramTool.cxx @@ -0,0 +1,114 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthHistogramTool.cxx +// Implementation file for class AthHistogramTool +// Author: Karsten Koeneke +/////////////////////////////////////////////////////////////////// + +// This class' header includes +#include "AthenaBaseComps/AthHistogramTool.h" + +// STL includes +#include <string> + +// Framework includes +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ITHistSvc.h" + + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthHistogramTool::AthHistogramTool( const std::string& type, + const std::string& name, + const IInterface* parent ) : + ::AthAlgTool( type, name, parent ), + ::AthHistogramming( name ), + m_histSvc ( "THistSvc/THistSvc", name ) +{ + // Properties go here + declareProperty("THistSvc", + m_histSvc = ServiceHandle<ITHistSvc>("THistSvc/THistSvc", name), + "Handle to a THistSvc instance: it will be used to write " + "ROOT objects to ROOT files" ); + + declareProperty("RootStreamName", m_prefix = "/", "Name of the output ROOT stream (file) that the THistSvc uses"); + declareProperty("RootDirName", m_rootDir = "", + "Name of the ROOT directory inside the ROOT file where the histograms will go"); + + declareProperty( "HistNamePrefix", m_histNamePrefix = "", "The prefix for the histogram THx name" ); + declareProperty( "HistNamePostfix", m_histNamePostfix = "", "The postfix for the histogram THx name" ); + + declareProperty( "HistTitlePrefix", m_histTitlePrefix = "", "The prefix for the histogram THx title" ); + declareProperty( "HistTitlePostfix", m_histTitlePostfix = "", "The postfix for the histogram THx title" ); +} + + + + +// Destructor +/////////////// +AthHistogramTool::~AthHistogramTool() +{ + ATH_MSG_DEBUG ("Calling destructor"); +} + + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + + +//============================================================================= +// Athena initialize method +//============================================================================= +StatusCode AthHistogramTool::sysInitialize() +{ + /* + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- + // Bypass the initialization if the algorithm + // has already been initialized. + if ( Gaudi::StateMachine::INITIALIZED <= FSMState() ) return StatusCode::SUCCESS; + + // Set the Algorithm's properties + ATH_CHECK(setProperties()); + + // Bypass the initialization if the algorithm is disabled. + // Need to do this after setProperties. + if ( !isEnabled( ) ) return StatusCode::SUCCESS; + + // ---- stolen from GaudiKernel/Algorithm::sysInitialize ------- END --- + */ + + // Get the THistSvc + ATH_CHECK ( histSvc().retrieve() ); + + // Configure the underlying AthHistogramming helper + ATH_CHECK ( AthHistogramming::configAthHistogramming( histSvc(), + m_prefix, m_rootDir, + m_histNamePrefix, m_histNamePostfix, + m_histTitlePrefix, m_histTitlePostfix ) ); + + // Print some setup information into the log file + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + ATH_MSG_DEBUG (" using THistService = " << m_histSvc ); + ATH_MSG_DEBUG (" using RootStreamName = " << m_prefix ); + ATH_MSG_DEBUG (" using RootDirName = " << m_rootDir ); + ATH_MSG_DEBUG (" using HistNamePrefix = " << m_histNamePrefix ); + ATH_MSG_DEBUG (" using HistNamePostfix = " << m_histNamePostfix ); + ATH_MSG_DEBUG (" using HistTitlePrefix = " << m_histTitlePrefix ); + ATH_MSG_DEBUG (" using HistTitlePostfix = " << m_histTitlePostfix ); + + + // re-direct to base class... + return AthAlgTool::sysInitialize(); +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthHistogramming.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramming.cxx new file mode 100644 index 00000000..6a0d50b4 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthHistogramming.cxx @@ -0,0 +1,504 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthHistogramming.cxx +// Implementation file for class AthHistogramming +// Author: Karsten Koeneke +/////////////////////////////////////////////////////////////////// + +// This class' header includes +#include "AthenaBaseComps/AthHistogramming.h" + +// Framework includes +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ITHistSvc.h" +#include "AthenaKernel/getMessageSvc.h" + +// STL includes +#include <string> +#include <map> + +// ROOT includes +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" +#include "TTree.h" +#include "TGraph.h" + + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthHistogramming::AthHistogramming( const std::string& name ) : + m_histSvc ( "THistSvc/THistSvc", name ), + m_streamName(""), + m_name ( name ), + m_msg( Athena::getMessageSvc(), name ) +{ +} + + + + +// Destructor +/////////////// +AthHistogramming::~AthHistogramming() +{ + //ATH_MSG_DEBUG ("Calling destructor of AthHistogramming"); + if ( m_msg.level() <= MSG::VERBOSE ) m_msg << MSG::DEBUG << "Calling destructor of AthHistogramming" << endreq; +} + + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +// To be called by the derived classes to fill the internal configuration +StatusCode AthHistogramming::configAthHistogramming( ServiceHandle<ITHistSvc>& histSvc, + const std::string& prefix, const std::string& rootDir, + const std::string& histNamePrefix, const std::string& histNamePostfix, + const std::string& histTitlePrefix, const std::string& histTitlePostfix ) +{ + m_histSvc = histSvc; + m_streamName = prefix; + m_rootDir = rootDir; + m_histNamePrefix = histNamePrefix; + m_histNamePostfix = histNamePostfix; + m_histTitlePrefix = histTitlePrefix; + m_histTitlePostfix = histTitlePostfix; + + return StatusCode::SUCCESS; +} + + + + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + + +// ----------------------- +// For histogramming +// ----------------------- + + +// ============================================================================= +// Simplify the booking and registering (into THistSvc) of histograms +// ============================================================================= +TH1* AthHistogramming::bookGetPointer( TH1& histRef, std::string tDir, std::string stream ) +{ + // Modify the name and title according to the prefixes of this classes instance + std::string histName(histRef.GetName()); + const std::string histTitle(histRef.GetTitle()); + std::string bookingString(""); + + this->buildBookingString( bookingString, histName, tDir, stream ); + histRef.SetTitle((m_histTitlePrefix+histTitle+m_histTitlePostfix).c_str() ); + histRef.SetName(histName.c_str()); + + // Check if the hash for this histName already exists, i.e., if we have a hash collision + const hash_t histHash = this->hash(histName); + HistMap_t::const_iterator it = m_histMap.find( histHash ); + if ( it != m_histMap.end() ) // It does exist! + { + m_msg << MSG::WARNING + << "Detected a hash collission. The hash for the histogram with name=" << histName + << " already exists and points to a histogram with name=" << it->second->GetName() + << " NOT going to book the new histogram and returning a NULL pointer!" << endreq; + return NULL; + } + + // Set the new name and title for the histogram, based on the prefixes that the user set for this class instance + // Create a clone that has the new name + + // Massage the final string to book things + + // Register the histogram into the THistSvc + if ( !((histSvc()->regHist(bookingString, &histRef)).isSuccess()) ) + { + m_msg << MSG::WARNING + << "Problem registering histogram with name " << histName + << ", name prefix " << m_histNamePrefix + << ", title " << histTitle + << ", tile prefix " << m_histTitlePrefix + << ", and tile postfix " << m_histTitlePostfix + << " in " << m_name << "!" << endreq; + return NULL; + } + + // Also register it in the local map of string to pointer + m_histMap.insert( m_histMap.end(), std::pair< const hash_t, TH1* >( histHash, &histRef ) ); + + return &histRef; +} + + + +// ============================================================================= +// Simplify the retrieval of registered histograms of any type +// ============================================================================= +TH1* AthHistogramming::hist( const std::string& histName, const std::string& tDir, const std::string& stream ) +{ + // Build a 32 bit hash out of the name + const hash_t histHash = this->hash(histName); + + // See if this entry exists in the map + HistMap_t::const_iterator it = m_histMap.find( histHash ); + if ( it == m_histMap.end() ) // It doesn't exist! + { // Let's see into the THistSvc if somebody else has registered the histogram... + + // Need to copy the strings as we will massage them from here on + std::string histNameCopy = histName; + std::string tDirCopy = tDir; + std::string streamCopy = stream; + + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, histNameCopy, tDirCopy, streamCopy ,false); + + TH1* histPointer(NULL); + if ( !((histSvc()->getHist(bookingString, histPointer)).isSuccess()) ) + { + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, histNameCopy, tDirCopy, streamCopy, true ); + + if ( !((histSvc()->getHist(bookingString, histPointer)).isSuccess()) ) + { + m_msg << MSG::WARNING + << "Problem retrieving the histogram with name (including pre- and post-fixes) " + << m_histNamePrefix + histNameCopy + m_histNamePostfix + << " or with name " << histNameCopy + << " in " << m_name << "... it doesn't exist, neither in the cached map nor in the THistSvc!" + << " Will return an NULL pointer... you have to handle it correctly!" << endreq; + return NULL; + } + // If we get to here, we actually found the histogram in the THistSvc. + // So let's add it to the local cache map and return its pointer + m_histMap.insert( m_histMap.end(), std::pair< const hash_t, TH1* >( histHash, histPointer ) ); + return histPointer; + } + // If we get to here, we actually found the histogram in the THistSvc. + // So let's add it to the local cache map and return its pointer + m_histMap.insert( m_histMap.end(), std::pair< const hash_t, TH1* >( histHash, histPointer ) ); + return histPointer; + } + + + // Return the pointer to the histogram that we got from the local cache map + return it->second; +} + + + + + +// ----------------------- +// For TTrees +// ----------------------- + +// ============================================================================= +// Simplify the booking and registering (into THistSvc) of TTrees +// ============================================================================= +TTree* AthHistogramming::bookGetPointer( const TTree& treeRef, std::string tDir, std::string stream ) +{ + // Get a pointer + TTree* treePointer = const_cast<TTree*>(&treeRef); + + // Check that we got a valid pointer + if ( !treePointer ) + { + m_msg << MSG::WARNING + << "We got an invalid TTree pointer in the BookGetPointer(TTree*) method of the class" << m_name + << "!" << endreq; + return NULL; + } + + // Modify the name and title according to the prefixes of this classes instance + std::string treeName = treePointer->GetName(); + const std::string treeTitle = treePointer->GetTitle(); + + // Check if the hash for this treeName already exists, i.e., if we have a hash collision + const hash_t treeHash = this->hash(treeName); + TreeMap_t::const_iterator it = m_treeMap.find( treeHash ); + if ( it != m_treeMap.end() ) // It does exist! + { + m_msg << MSG::WARNING + << "Detected a hash collission. The hash for the TTree with name=" << treeName + << " already exists and points to a TTree with name=" << it->second->GetName() + << " NOT going to book the new histogram and returning a NULL pointer!" << endreq; + return NULL; + } + + // Set the new name and title for the TTree, based on the prefixes that the user set for this class instance + treePointer->SetNameTitle( (treeName).c_str(), (treeTitle).c_str() ); + + // Create a clone that has the new name + TTree* treeClone = dynamic_cast< TTree* >( treePointer->Clone() ); + if( !treeClone ) + { + m_msg << MSG::WARNING + << "We couldn't clone the TTree in the BookGetPointer(TTree&) method of the class" << m_name + << "!" << endreq; + return NULL; + } + + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, treeName, tDir, stream ); + + // Register the TTree into the THistSvc + if ( !((histSvc()->regTree(bookingString, treeClone)).isSuccess()) ) + { + m_msg << MSG::WARNING + << "Problem registering TTree with name " << treeName + << ", title " << treeTitle + << " in " << m_name << "!" << endreq; + return NULL; + } + + // Also register it in the local map of string to pointer + m_treeMap.insert( m_treeMap.end(), std::pair< const hash_t, TTree* >( treeHash, treeClone ) ); + + return treeClone; +} + + + +// ============================================================================= +// Simplify the retrieval of registered TTrees +// ============================================================================= +TTree* AthHistogramming::tree( const std::string& treeName, const std::string& tDir, const std::string& stream ) +{ + // Build a 32 bit hash out of the name + const hash_t treeHash = this->hash(treeName); + + // See if this entry exists in the map + TreeMap_t::const_iterator it = m_treeMap.find( treeHash ); + if ( it == m_treeMap.end() ) // It doesn't exist! + { // Let's see into the THistSvc if somebody else has registered the TTree... + + // Need to copy the strings as we will massage them from here on + std::string treeNameCopy = treeName; + std::string tDirCopy = tDir; + std::string streamCopy = stream; + + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, treeNameCopy, tDirCopy, streamCopy ); + + TTree* treePointer(NULL); + if ( !((histSvc()->getTree(bookingString, treePointer)).isSuccess()) ) + { + m_msg << MSG::WARNING + << "Problem retrieving the TTree with name " << treeNameCopy + << " in " << m_name << "... it doesn't exist, neither in the cached map nor in the THistSvc!" + << " Will return an NULL pointer... you have to handle it correctly!" << endreq; + return NULL; + } + // If we get to here, we actually found the TTree in the THistSvc. + // So let's add it to the local cache map and return its pointer + m_treeMap.insert( m_treeMap.end(), std::pair< const hash_t, TTree* >( treeHash, treePointer ) ); + return treePointer; + } + + // Return the pointer to the TTree that we got from the local cache map + return it->second; +} + + + + + +// ----------------------- +// For TGraphs +// ----------------------- + +// ============================================================================= +// Simplify the booking and registering (into THistSvc) of TGraphs +// ============================================================================= +TGraph* AthHistogramming::bookGetPointer( const TGraph& graphRef, std::string tDir, std::string stream ) +{ + // Get a pointer + TGraph* graphPointer = const_cast<TGraph*>(&graphRef); + + // Check that we got a valid pointer + if ( !graphPointer ) + { + m_msg << MSG::WARNING + << "We got an invalid TGraph pointer in the BookGetPointer(TGraph*) method of the class" << m_name + << "!" << endreq; + return NULL; + } + + // Modify the name and title according to the prefixes of this classes instance + std::string graphName = graphPointer->GetName(); + const std::string graphTitle = graphPointer->GetTitle(); + + // Check if the hash for this graphName already exists, i.e., if we have a hash collision + const hash_t graphHash = this->hash(graphName); + GraphMap_t::const_iterator it = m_graphMap.find( graphHash ); + if ( it != m_graphMap.end() ) // It does exist! + { + m_msg << MSG::WARNING + << "Detected a hash collission. The hash for the TGraph with name=" << graphName + << " already exists and points to a TGraph with name=" << it->second->GetName() + << " NOT going to book the new histogram and returning a NULL pointer!" << endreq; + return NULL; + } + + // Set the new name and title for the TGraph, based on the prefixes that the user set for this class instance + graphPointer->SetNameTitle( (m_histNamePrefix+graphName+m_histNamePostfix).c_str(), + (m_histTitlePrefix+graphTitle+m_histTitlePostfix).c_str() ); + + // Create a clone that has the new name + TGraph* graphClone = dynamic_cast< TGraph* >( graphPointer->Clone() ); + if( !graphClone ) + { + m_msg << MSG::WARNING + << "We couldn't clone the TGraph in the BookGetPointer(TGraph&) method of the class" << m_name + << "!" << endreq; + return NULL; + } + + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, graphName, tDir, stream ); + + // Register the TGraph into the THistSvc + if ( !((histSvc()->regGraph(bookingString, graphClone)).isSuccess()) ) + { + m_msg << MSG::WARNING + << "Problem registering TGraph with name " << graphName + << ", title " << graphTitle + << " in " << m_name << "!" << endreq; + return NULL; + } + + // Also register it in the local map of string to pointer + m_graphMap.insert( m_graphMap.end(), std::pair< const hash_t, TGraph* >( graphHash, graphClone ) ); + + return graphClone; +} + + +// ============================================================================= +// Simplify the retrieval of registered TGraphs +// ============================================================================= +TGraph* AthHistogramming::graph( const std::string& graphName, const std::string& tDir, const std::string& stream ) +{ + // Build a 32 bit hash out of the name + const hash_t graphHash = this->hash(graphName); + + // See if this entry exists in the map + GraphMap_t::const_iterator it = m_graphMap.find( graphHash ); + if ( it == m_graphMap.end() ) // It doesn't exist! + { // Let's see into the THistSvc if somebody else has registered the TGraph... + + // Need to copy the strings as we will massage them from here on + std::string graphNameCopy = graphName; + std::string tDirCopy = tDir; + std::string streamCopy = stream; + + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, graphNameCopy, tDirCopy, streamCopy, true); + + TGraph* graphPointer(NULL); + if ( !((histSvc()->getGraph(bookingString, graphPointer)).isSuccess()) ) + { + // Massage the final string to book things + std::string bookingString(""); + this->buildBookingString( bookingString, graphNameCopy, tDirCopy, streamCopy, false ); + + if ( !((histSvc()->getGraph(bookingString, graphPointer)).isSuccess()) ) + { + m_msg << MSG::WARNING + << "Problem retrieving the TGraph with name (including pre- and post-fixes) " + << m_histNamePrefix + graphNameCopy + m_histNamePostfix + << " or with name " << graphNameCopy + << " in " << m_name << "... it doesn't exist, neither in the cached map nor in the THistSvc!" + << " Will return an NULL pointer... you have to handle it correctly!" << endreq; + return NULL; + } + // If we get to here, we actually found the TGraph in the THistSvc. + // So let's add it to the local cache map and return its pointer + m_graphMap.insert( m_graphMap.end(), std::pair< const hash_t, TGraph* >( graphHash, graphPointer ) ); + return graphPointer; + } + // If we get to here, we actually found the TGraph in the THistSvc. + // So let's add it to the local cache map and return its pointer + m_graphMap.insert( m_graphMap.end(), std::pair< const hash_t, TGraph* >( graphHash, graphPointer ) ); + return graphPointer; + } + + + // Return the pointer to the TGraph that we got from the local cache map + return it->second; +} + + + + + + + + + + +/////////////////////////////////////////////////////////////////// +// Private methods: +/////////////////////////////////////////////////////////////////// + +// ============================================================================= +// Helper method to build the final string to be passed to the THistSvc +// ============================================================================= +void AthHistogramming::buildBookingString( std::string& bookingString, + std::string& histName, + std::string& tDir, + std::string& stream, + bool usePrefixPostfix) +{ + // Massage the final string to book things + if(tDir.empty()) tDir = m_rootDir; + size_t pos = histName.rfind("/"); + if(pos != std::string::npos){ + tDir+="/"+histName.substr(0,pos); + histName.erase(0,pos+1); + }; + if(stream.empty()) stream = m_streamName; + + if(usePrefixPostfix){ + bookingString = "/"+m_streamName+"/"+tDir+"/"+m_histNamePrefix+histName+m_histNamePostfix; + } else { + bookingString = "/"+m_streamName+"/"+tDir+"/"+histName; + } + while(bookingString.find("//") != std::string::npos){ + this->myReplace(bookingString,"//","/"); + } + + return; +} + + +// Helper method to replace all sub-strings +void AthHistogramming::myReplace( std::string& str, + const std::string& oldStr, + const std::string& newStr) +{ + size_t pos = 0; + while((pos = str.find(oldStr, pos)) != std::string::npos) + { + str.replace(pos, oldStr.length(), newStr); + pos += newStr.length(); + } +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthMessaging.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthMessaging.cxx new file mode 100644 index 00000000..eccbca4e --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthMessaging.cxx @@ -0,0 +1,54 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthMessaging.cxx +// Implementation file for class AthMessaging +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaBaseComps includes +#include "AthenaBaseComps/AthMessaging.h" + +// STL includes + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +/// Constructor with parameters: +AthMessaging::AthMessaging (IMessageSvc* msgSvc, + const std::string& name) : + m_msg (msgSvc, name) +{} + +/// Constructor from an existing stream. +AthMessaging::AthMessaging (MsgStream& msg) + : m_msg (msg) +{} + +// Destructor +/////////////// +AthMessaging::~AthMessaging() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + + diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthReentrantAlgorithm.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthReentrantAlgorithm.cxx new file mode 100644 index 00000000..b7057e50 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthReentrantAlgorithm.cxx @@ -0,0 +1,26 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaBaseComps/src/AthReentrantAlgorithm.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief An algorithm that can be simultaneously executed in multiple threads. + */ + + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "GaudiKernel/ThreadLocalContext.h" + + +/** + * @brief Standard Gaudi execute method. + * + * Find the event context and call @c execute_r. + */ +StatusCode AthReentrantAlgorithm::execute() +{ + return execute_r (Gaudi::Hive::currentContext()); +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/AthService.cxx b/EDM/athena/Control/AthenaBaseComps/src/AthService.cxx new file mode 100644 index 00000000..b787eae0 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/AthService.cxx @@ -0,0 +1,151 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AthService.cxx +// Implementation file for class AthService +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + + +// STL includes + +// FrameWork includes + +// AthenaBaseComps includes +#include "AthenaBaseComps/AthService.h" + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AthService::AthService( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::Service ( name, pSvcLocator ), + ::AthMessaging ( msgSvc(), name ), + m_ol(0) +{ + // + // Property declaration + // + //declareProperty( "Property", m_nProperty, "descr" ); + + m_outputLevel + .declareUpdateHandler + (&AthService::msg_update_handler, this); + +} + +// Destructor +/////////////// +AthService::~AthService() +{ + ATH_MSG_DEBUG ("Calling destructor"); +} + +StatusCode AthService::sysInitialize() +{ + // Initialize it only if was not done +#ifdef GAUDIKERNEL_STATEMACHINE_H_ + if (Gaudi::StateMachine::OFFLINE != this->FSMState()) { + m_targetState = Gaudi::StateMachine::CONFIGURED; + +#else + if( m_state != OFFLINE ) { +#endif + ATH_MSG_WARNING ("Service already initialized"); + return StatusCode::SUCCESS; + } + + // Set the Service's properties + ATH_CHECK(setProperties()); + m_ol = m_outputLevel; + // if ( !setProperties().isSuccess() ) { + // return StatusCode::FAILURE; + // } +#ifdef GAUDIKERNEL_STATEMACHINE_H_ + m_state = Gaudi::StateMachine::ChangeState(Gaudi::StateMachine::CONFIGURE, + m_state); +#else + m_state = CONFIGURED; +#endif + + StatusCode sc = Service::sysInitialize(); + m_outputLevel = m_ol; + return sc; +} + +StatusCode AthService::initialize() +{ + m_outputLevel = m_ol; + return StatusCode::SUCCESS; +} + +StatusCode AthService::sysReinitialize() +{ + return Service::sysReinitialize(); +} + +StatusCode AthService::reinitialize() +{ + return StatusCode::SUCCESS; +} + +StatusCode AthService::sysFinalize() +{ +#ifdef GAUDIKERNEL_STATEMACHINE_H_ + if (Gaudi::StateMachine::OFFLINE == this->FSMState()) { + ATH_MSG_WARNING ("Service already offline"); + return StatusCode::SUCCESS; + } +#else + if( m_state == OFFLINE ) { + ATH_MSG_WARNING ("Service already offline"); + return StatusCode::SUCCESS; + } + m_state = OFFLINE; +#endif + return Service::sysFinalize(); +} + +StatusCode AthService::finalize() +{ + return StatusCode::SUCCESS; +} + +StatusCode +AthService::queryInterface( const InterfaceID& riid, + void** ppvi ) +{ + return Service::queryInterface( riid, ppvi ); +} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +void +AthService::msg_update_handler(Property& /*m_outputLevel*/) +{ + msg().setLevel (outputLevel()); +} diff --git a/EDM/athena/Control/AthenaBaseComps/src/FilteredAlgorithm.cxx b/EDM/athena/Control/AthenaBaseComps/src/FilteredAlgorithm.cxx new file mode 100644 index 00000000..5f5032b7 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/src/FilteredAlgorithm.cxx @@ -0,0 +1,135 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Framework include files +#include "GaudiKernel/GaudiException.h" +#include "GaudiKernel/AlgFactory.h" +#include "GaudiKernel/IAlgManager.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IProperty.h" +#include "GaudiKernel/MsgStream.h" +#include "AthenaBaseComps/FilteredAlgorithm.h" +#include <cassert> +#include <string> +#include <vector> + +using std::string; +using std::vector; + +// Standard Constructor +FilteredAlgorithm::FilteredAlgorithm(const string& name, + ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator), + m_decSvc("DecisionSvc/DecisionSvc",name) +{ + assert( pSvcLocator ); + declareProperty("AcceptAlgs", + m_acceptNames, + "Filters which if any are passed enable output"); + declareProperty("RequireAlgs", + m_requireNames, + "Filters which must all be passed to enable output"); + declareProperty("VetoAlgs", + m_vetoNames, + "Filters which if any are passed disable output"); + + declareProperty("decSvc", m_decSvc); + +} + +// Standard Destructor +FilteredAlgorithm::~FilteredAlgorithm() +{} + +// initialize data writer +StatusCode +FilteredAlgorithm::initialize() +{ + ATH_MSG_DEBUG ("In initialize "); + + // Decode the accept, required and veto Algorithms. + // The logic is the following: + // a. The event is accepted if all lists are empty. + // b. The event is provisionally accepted if any Algorithm in the + // accept list + // has been executed and has indicated that its filter is passed. This + // provisional acceptance can be overridden by the other lists. + // c. The event is rejected unless all Algorithms in the required list have + // been executed and have indicated that their filter passed. + // d. The event is rejected if any Algorithm in the veto list has been + // executed and has indicated that its filter has passed. + + // Use IDecisionSvc, FilteredAlgorithm is a wrapper around DecisionSvc + ATH_CHECK(m_decSvc.retrieve()); + ATH_MSG_DEBUG( "Found IDecisionSvc." ); + + // Register stream, no matter what Properties it has + if (!m_decSvc->addStream(this->name()).isSuccess()) { + ATH_MSG_ERROR("Couldn't add stream " << this->name()); + } + + // Propagate the FilteredAlgorithm's Properties to IDecisionSvc + for (std::vector<std::string>::const_iterator + it = m_acceptNames.value().begin(), + end= m_acceptNames.value().end(); + it != end; + ++it) { + ATH_MSG_DEBUG("Trying to add " << (*it) << " of stream " + << this->name() << " to AcceptAlg list"); + if (!m_decSvc->addAcceptAlg((*it), this->name()).isSuccess()) { + ATH_MSG_ERROR("Couldn't add acceptAlg"); + } + } + + for (std::vector<std::string>::const_iterator + it = m_requireNames.value().begin(), + end= m_requireNames.value().end(); + it != end; + ++it){ + ATH_MSG_DEBUG("Trying to add " << (*it) << " of stream " + << this->name() << " to RequireAlg list"); + if (!m_decSvc->addRequireAlg((*it), this->name()).isSuccess()) { + ATH_MSG_ERROR("Couldn't add requireAlg"); + } + } + + for (std::vector<std::string>::const_iterator + it = m_vetoNames.value().begin(), + end= m_vetoNames.value().end(); + it != end; + ++it){ + ATH_MSG_DEBUG("Trying to add " << (*it) << " of stream " + << this->name() << " to VetoAlg list"); + if (!m_decSvc->addVetoAlg((*it), this->name()).isSuccess()) { + ATH_MSG_ERROR("Couldn't add vetoAlg"); + } + } + + ATH_MSG_DEBUG ("End initialize "); + + return StatusCode::SUCCESS; +} + + +StatusCode +FilteredAlgorithm::finalize() +{ + + return StatusCode::SUCCESS; +} + +StatusCode +FilteredAlgorithm::execute() +{ + return StatusCode::SUCCESS; +} + +bool +FilteredAlgorithm::isEventAccepted( ) const +{ + bool result = true; + result = m_decSvc->isEventAccepted(this->name()); + return result; +} + diff --git a/EDM/athena/Control/AthenaBaseComps/test/AthReentrantAlgorithm_test.cxx b/EDM/athena/Control/AthenaBaseComps/test/AthReentrantAlgorithm_test.cxx new file mode 100644 index 00000000..0f1d285b --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/test/AthReentrantAlgorithm_test.cxx @@ -0,0 +1,128 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaBaseComps/test/AthReentrantAlgorithm_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Test property handling for AthReentrantAlgorithm. + */ + + +#undef NDEBUG +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/WriteHandle.h" +#include "TestTools/initGaudi.h" +#include "GaudiKernel/ThreadLocalContext.h" +#include <vector> +#include <cassert> +#include <iostream> + + +namespace AthenaBaseCompsTest { +class MyObj {}; +} +CLASS_DEF (AthenaBaseCompsTest::MyObj, 293847295, 1) +using AthenaBaseCompsTest::MyObj; + + +IProxyDict* pdict = nullptr; + + +class MyAlg + : public AthReentrantAlgorithm +{ +public: + MyAlg (const std::string& name, ISvcLocator* svcLoc); + + virtual StatusCode execute_r (const EventContext& ctx) const override; + + virtual void declareInput(Gaudi::DataHandle* im) override; + virtual void declareOutput(Gaudi::DataHandle* im) override; + + SG::ReadHandleKey<MyObj> rkey; + SG::WriteHandle<MyObj> whandle; + + std::vector<Gaudi::DataHandle*> inputs; + std::vector<Gaudi::DataHandle*> outputs; +}; + + +MyAlg::MyAlg (const std::string& name, ISvcLocator* svcLoc) + : AthReentrantAlgorithm (name, svcLoc) +{ + declareProperty ("rkey", rkey); + declareProperty ("whandle", whandle); +} + + +StatusCode MyAlg::execute_r (const EventContext& ctx) const +{ + pdict = ctx.proxy(); + return StatusCode::SUCCESS; +} + + +void MyAlg::declareInput(Gaudi::DataHandle* im) +{ + inputs.push_back (im); +} + + +void MyAlg::declareOutput(Gaudi::DataHandle* im) +{ + outputs.push_back (im); +} + + +void test1 (ISvcLocator* svcLoc) +{ + std::cout << "test1\n"; + + MyAlg alg ("ralg", svcLoc); alg.addRef(); + assert (alg.setProperties().isSuccess()); + + assert (alg.rkey.clid() == 293847295); + assert (alg.rkey.key() == "aaa"); + assert (alg.rkey.storeHandle().name() == "FooSvc"); + assert (alg.rkey.mode() == Gaudi::DataHandle::Reader); + + assert (alg.whandle.clid() == 293847295); + assert (alg.whandle.key() == "eee"); + assert (alg.whandle.storeHandle().name() == "BarSvc"); + assert (alg.whandle.mode() == Gaudi::DataHandle::Writer); + + std::vector<std::string> inputKeys { "aaa" }; + assert (alg.inputs.size() == inputKeys.size()); + for (size_t i = 0; i < inputKeys.size(); i++) + assert (alg.inputs[i]->objKey() == inputKeys[i]); + + std::vector<std::string> outputKeys { "eee" }; + assert (alg.outputs.size() == outputKeys.size()); + for (size_t i = 0; i < outputKeys.size(); i++) + assert (alg.outputs[i]->objKey() == outputKeys[i]); + + IProxyDict* xdict = &*alg.evtStore(); +#ifdef ATHENAHIVE + xdict = alg.evtStore()->hiveProxyDict(); +#endif + EventContext ctx; + ctx.setProxy (xdict); + Gaudi::Hive::setCurrentContext (ctx); + + assert (alg.execute().isSuccess()); + assert (pdict == xdict); +} + + +int main() +{ + ISvcLocator* svcLoc = nullptr; + Athena_test::initGaudi ("propertyHandling_test.txt", svcLoc); + + test1 (svcLoc); + return 0; +} diff --git a/EDM/athena/Control/AthenaBaseComps/test/AthenaBaseComps.xml b/EDM/athena/Control/AthenaBaseComps/test/AthenaBaseComps.xml new file mode 100644 index 00000000..8c550f43 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/test/AthenaBaseComps.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AtheneBaseCompsTest" type="makecheck" suite="Examples"> + <package>Control/AthenaBaseComps</package> + <timelimit>10</timelimit> + <author> scott snyder </author> + <mailto> snyder@bnl.gov </mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/AthenaBaseComps/test/propertyHandling_test.cxx b/EDM/athena/Control/AthenaBaseComps/test/propertyHandling_test.cxx new file mode 100644 index 00000000..c45eeee2 --- /dev/null +++ b/EDM/athena/Control/AthenaBaseComps/test/propertyHandling_test.cxx @@ -0,0 +1,248 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaBaseComps/test/propertyHandling_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Test property handling for VarHandle / VarHandleKey. + */ + + +#undef NDEBUG +#include "AthenaBaseComps/AthAlgorithm.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/WriteHandleKey.h" +#include "StoreGate/UpdateHandleKey.h" +#include "StoreGate/ReadHandle.h" +#include "StoreGate/WriteHandle.h" +#include "StoreGate/UpdateHandle.h" +#include "TestTools/initGaudi.h" +#include <vector> +#include <cassert> +#include <iostream> + + +namespace AthenaBaseCompsTest { +class MyObj {}; +} +CLASS_DEF (AthenaBaseCompsTest::MyObj, 293847295, 1) +using AthenaBaseCompsTest::MyObj; + + +class MyAthAlgorithm + : public AthAlgorithm +{ +public: + MyAthAlgorithm (const std::string& name, ISvcLocator* svcLoc); + + virtual StatusCode execute() override; + + virtual void declareInput(Gaudi::DataHandle* im) override; + virtual void declareOutput(Gaudi::DataHandle* im) override; + + SG::ReadHandleKey<MyObj> rkey; + SG::WriteHandleKey<MyObj> wkey; + SG::UpdateHandleKey<MyObj> ukey; + + SG::ReadHandle<MyObj> rhandle; + SG::WriteHandle<MyObj> whandle; + SG::UpdateHandle<MyObj> uhandle; + + std::vector<Gaudi::DataHandle*> inputs; + std::vector<Gaudi::DataHandle*> outputs; +}; + + +MyAthAlgorithm::MyAthAlgorithm (const std::string& name, ISvcLocator* svcLoc) + : AthAlgorithm (name, svcLoc) +{ + declareProperty ("rkey", rkey); + declareProperty ("wkey", wkey); + declareProperty ("ukey", ukey); + declareProperty ("rhandle", rhandle); + declareProperty ("whandle", whandle); + declareProperty ("uhandle", uhandle); +} + + +StatusCode MyAthAlgorithm::execute() +{ + return StatusCode::SUCCESS; +} + + +void MyAthAlgorithm::declareInput(Gaudi::DataHandle* im) +{ + inputs.push_back (im); +} + + +void MyAthAlgorithm::declareOutput(Gaudi::DataHandle* im) +{ + outputs.push_back (im); +} + + +class MyAthAlgTool + : public AthAlgTool +{ +public: + MyAthAlgTool (const std::string& type, + const std::string& name, + IInterface* parent); + + virtual void declareInput(Gaudi::DataHandle* im) override; + virtual void declareOutput(Gaudi::DataHandle* im) override; + + SG::ReadHandleKey<MyObj> rkey; + SG::WriteHandleKey<MyObj> wkey; + SG::UpdateHandleKey<MyObj> ukey; + + SG::ReadHandle<MyObj> rhandle; + SG::WriteHandle<MyObj> whandle; + SG::UpdateHandle<MyObj> uhandle; + + std::vector<Gaudi::DataHandle*> inputs; + std::vector<Gaudi::DataHandle*> outputs; +}; + + +MyAthAlgTool::MyAthAlgTool (const std::string& type, + const std::string& name, + IInterface* parent) + : AthAlgTool (type, name, parent) +{ + declareProperty ("rkey", rkey); + declareProperty ("wkey", wkey); + declareProperty ("ukey", ukey); + declareProperty ("rhandle", rhandle); + declareProperty ("whandle", whandle); + declareProperty ("uhandle", uhandle); +} + + +void MyAthAlgTool::declareInput(Gaudi::DataHandle* im) +{ + inputs.push_back (im); +} + + +void MyAthAlgTool::declareOutput(Gaudi::DataHandle* im) +{ + outputs.push_back (im); +} + + +void test1 (ISvcLocator* svcLoc) +{ + std::cout << "test1\n"; + + MyAthAlgorithm alg ("alg", svcLoc); alg.addRef(); + assert (alg.setProperties().isSuccess()); + + assert (alg.rkey.clid() == 293847295); + assert (alg.rkey.key() == "aaa"); + assert (alg.rkey.storeHandle().name() == "FooSvc"); + assert (alg.rkey.mode() == Gaudi::DataHandle::Reader); + + assert (alg.wkey.clid() == 293847295); + assert (alg.wkey.key() == "bbb"); + assert (alg.wkey.storeHandle().name() == "BarSvc"); + assert (alg.wkey.mode() == Gaudi::DataHandle::Writer); + + assert (alg.ukey.clid() == 293847295); + assert (alg.ukey.key() == "ccc"); + assert (alg.ukey.storeHandle().name() == "StoreGateSvc"); + assert (alg.ukey.mode() == Gaudi::DataHandle::Updater); + + assert (alg.rhandle.clid() == 293847295); + assert (alg.rhandle.key() == "ddd"); + assert (alg.rhandle.storeHandle().name() == "FooSvc"); + assert (alg.rhandle.mode() == Gaudi::DataHandle::Reader); + + assert (alg.whandle.clid() == 293847295); + assert (alg.whandle.key() == "eee"); + assert (alg.whandle.storeHandle().name() == "BarSvc"); + assert (alg.whandle.mode() == Gaudi::DataHandle::Writer); + + assert (alg.uhandle.clid() == 293847295); + assert (alg.uhandle.key() == "fff"); + assert (alg.uhandle.storeHandle().name() == "StoreGateSvc"); + assert (alg.uhandle.mode() == Gaudi::DataHandle::Updater); + + std::vector<std::string> inputKeys { "aaa", "ccc", "ddd", "fff" }; + assert (alg.inputs.size() == inputKeys.size()); + for (size_t i = 0; i < inputKeys.size(); i++) + assert (alg.inputs[i]->objKey() == inputKeys[i]); + + std::vector<std::string> outputKeys { "bbb", "ccc", "eee", "fff" }; + assert (alg.outputs.size() == outputKeys.size()); + for (size_t i = 0; i < outputKeys.size(); i++) + assert (alg.outputs[i]->objKey() == outputKeys[i]); +} + + +void test2 (ISvcLocator* svcLoc) +{ + std::cout << "test2\n"; + + MyAthAlgorithm alg ("alg", svcLoc); alg.addRef(); + MyAthAlgTool tool ("MyAthAlgTool", "tool", &alg); tool.addRef(); + assert (tool.setProperties().isSuccess()); + + assert (tool.rkey.clid() == 293847295); + assert (tool.rkey.key() == "taa"); + assert (tool.rkey.storeHandle().name() == "FooSvc"); + assert (tool.rkey.mode() == Gaudi::DataHandle::Reader); + + assert (tool.wkey.clid() == 293847295); + assert (tool.wkey.key() == "tbb"); + assert (tool.wkey.storeHandle().name() == "BarSvc"); + assert (tool.wkey.mode() == Gaudi::DataHandle::Writer); + + assert (tool.ukey.clid() == 293847295); + assert (tool.ukey.key() == "tcc"); + assert (tool.ukey.storeHandle().name() == "StoreGateSvc"); + assert (tool.ukey.mode() == Gaudi::DataHandle::Updater); + + + assert (tool.rhandle.clid() == 293847295); + assert (tool.rhandle.key() == "tdd"); + assert (tool.rhandle.storeHandle().name() == "FooSvc"); + assert (tool.rhandle.mode() == Gaudi::DataHandle::Reader); + + assert (tool.whandle.clid() == 293847295); + assert (tool.whandle.key() == "tee"); + assert (tool.whandle.storeHandle().name() == "BarSvc"); + assert (tool.whandle.mode() == Gaudi::DataHandle::Writer); + + assert (tool.uhandle.clid() == 293847295); + assert (tool.uhandle.key() == "tff"); + assert (tool.uhandle.storeHandle().name() == "StoreGateSvc"); + assert (tool.uhandle.mode() == Gaudi::DataHandle::Updater); + + std::vector<std::string> inputKeys { "taa", "tcc", "tdd", "tff" }; + assert (tool.inputs.size() == inputKeys.size()); + for (size_t i = 0; i < inputKeys.size(); i++) + assert (tool.inputs[i]->objKey() == inputKeys[i]); + + std::vector<std::string> outputKeys { "tbb", "tcc", "tee", "tff" }; + assert (tool.outputs.size() == outputKeys.size()); + for (size_t i = 0; i < outputKeys.size(); i++) + assert (tool.outputs[i]->objKey() == outputKeys[i]); +} + + +int main() +{ + ISvcLocator* svcLoc = nullptr; + Athena_test::initGaudi ("propertyHandling_test.txt", svcLoc); + + test1 (svcLoc); + test2 (svcLoc); + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/AddressProviderSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/AddressProviderSvc.h new file mode 100644 index 00000000..6088375c --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/AddressProviderSvc.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @ class AddressProviderSvc + * @brief helper class for ProxyProvider implementers + * + * @author ATLAS Collaboration + * $Id: AddressProviderSvc.h,v 1.4 2003-04-16 01:12:23 calaf Exp $ + ***************************************************************************/ + +#ifndef ATHENAKERNEL_ADDRESSPROVIDERSVC_H +#define ATHENAKERNEL_ADDRESSPROVIDERSVC_H + +//<<<<<< INCLUDES >>>>>> +#ifndef _CPP_STRING + #include <string> +#endif +#ifndef ATHENAKERNEL_IADDRESSPROVIDER_H + #include "AthenaKernel/IAddressProvider.h" +#endif +#ifndef GAUDIKERNEL_SERVICE_H + #include "GaudiKernel/Service.h" +#endif +#ifndef GAUDIKERNEL_ISVCLOCATOR_H + #include "GaudiKernel/ISvcLocator.h" +#endif + + +class AddressProviderSvc : public Service, virtual public IAddressProvider { + /// Standard Constructor + AddressProviderSvc( const std::string& name, ISvcLocator* svcloc) : + Service(name, svcloc) {}; + + void dummy(); +}; + +#endif // ATHENAKERNEL_ADRESSPROVIDERSVC_H + + + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/AlgorithmTimer.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/AlgorithmTimer.h new file mode 100644 index 00000000..5942f0bc --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/AlgorithmTimer.h @@ -0,0 +1,207 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ALGORITHMTIMER_H +#define ATHENAKERNEL_ALGORITHMTIMER_H + +/** + * @file AthenaKernel/AlgorithmTimer.h + * @brief Efficient realtime timers + * @author Rolf Seuster, Frank Winklmeier + * (based on TrigTimeAlgs/CookTimer, which in turn is based in AthenaKernel/CookTimer by W. Lavrijsen, S. Binet) + * + * $Id: AlgorithmTimer.h,v 1.3 2009-05-14 16:58:21 dquarrie Exp $ + */ + +// Framework includes +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/ServiceHandle.h" + +// System includes +#include <time.h> +#include <signal.h> +#ifdef __APPLE__ +#include <sys/signal.h> +#include <sys/time.h> +#endif + +// STL includes +#include <string> +#include <list> + +// Boost includes +#include <boost/function.hpp> + +#ifdef __APPLE__ +typedef sigval sigval_t; +typedef itimerval timer_t; +#endif //MacOSX + +namespace Athena { + + //forward declarations + class ScopedTimer; + + namespace AlgorithmTimerHandler + { + void onAlarmSignal(int sig, siginfo_t *info, void* extra); + void onAlarmThread(sigval_t sv); + } + + /** + * @class AlgorithmTimer + * @brief Timer that invokes a user callback once the time is reached + * + * AlgorithmTimer automatically disables itself in its destructor. Create it + * on the stack and it will therefore disable itself once it runs out of + * scope. Example: + * + * \code + * StatusCode MyAlgorithm::execute() + * { + * Athena::AlgorithmTimer(2000, myAlarmHandler); + * // something that takes a long time + * } + * \endcode + * + * The overhead of creating a AlgorithmTimer instance is very small. If you are + * still worried about it, you can re-use the instance by creating it outside + * the scope and starting/stopping it manually via its start() and stop() method. + * + * To get the best of both worlds you can create the AlgorithmTimer outside the + * scope and use an even smaller ScopedTimer instance to start the timer. Once the + * ScopedTimer instance runs out of scope it will disarm the associated AlgorithmTimer. + * + * \code + * MyAlgorithm::MyAlgorithm() : + * m_algorithmTimer(0, myAlarmHandler) // create it in disabled state + * { + * } + * + * StatusCode MyAlgorithm::execute() + * { + * Athena::ScopedTimer alarm(2000); // two seconds + * m_algorithmTimer.start(alarm); // this will start the timer + * // something that takes a long time + * } + * \endcode + * + */ + class AlgorithmTimer + { + friend void AlgorithmTimerHandler::onAlarmSignal(int sig, siginfo_t *info, void* extra); + friend void AlgorithmTimerHandler::onAlarmThread(sigval_t sv); + + public: + + /** + * @brief Configuration flags for AlgorithmTimer + */ + enum AlgorithmTimerConfig + { + DEFAULT = 0x0, ///< default + USEREALTIME = 0x1, ///< use real time instead of system time + DELIVERYBYTHREAD = 0x2 ///< deliver timeout by thread instead of signal + }; + + typedef boost::function<void()> callbackFct_t; + + /** + * @brief Create AlgorithmTimer instance and start it (unless seconds==0) + * @param milliseconds Time in milliseconds until expiration of the timer (0 = disabled) + * @param callback User callback to invoke once time is reached + * @param useRealTime true, if timer should use ral instead od CPU time + */ + AlgorithmTimer(unsigned int milliseconds, + callbackFct_t callback = NULL, + AlgorithmTimerConfig conf = DEFAULT); + + /** + * @brief Destroy and disable the timer + */ + ~AlgorithmTimer(); + + /** + * @brief (Re)start the timer with the last timeout used + */ + void start() { start(m_timeout); } + + /** + * @brief Start the timer + * @param milliseconds Time in milliseconds until expiration + */ + void start(unsigned int milliseconds); + + /** + * @brief Start the timer + * @param scope ScopedTimer instance to automatically stop the timer + */ + void start(ScopedTimer& scope); + + /** + * @brief Stop the timer and return the time left in [ms]. + */ + unsigned int stop(); + + /** + * @brief Returns the time left in milliseconds + */ + unsigned int timeLeft() const; + + /** + * @brief Returns the currently set timeout (in milliseconds) + */ + unsigned int timeout() const { return m_timeout; } + + /** + * @brief set the levelof details for (optional) gdb core dump + */ + void SetGDBCoreDumpDetails(unsigned int details) + { m_gdb_details = details; }; + + protected: + + unsigned int m_timeout; ///< timeout in milliseconds + struct sigevent m_sigevent; ///< for signal handler + timer_t m_timerid; ///< timer ID + callbackFct_t m_onAlarm; ///< user callback + + bool installSignalHandler(); ///< Install signal handler + bool uninstallSignalHandler(); ///< Uninstall signal handler + + private: + enum {SIGNO = SIGUSR1}; ///< Use this signal number + static struct sigaction s_oldSigHandler; ///< Old signal handler for SIGNO + static std::list<AlgorithmTimer*> s_registry; ///< List of all AlgorithmTimer instances + static bool s_handlerInstalled; ///< Signal handler installed? + + // Dummies + AlgorithmTimer(); ///< no default constructor + AlgorithmTimer(const AlgorithmTimer&); ///< no copying allowed + AlgorithmTimer& operator=(const AlgorithmTimer&); ///< no copying allowed + + callbackFct_t abortJob(); + + unsigned int m_gdb_details; + }; + + + /** + * @class ScopedTimer + * @brief Helper class to create a "scoped cook timer" without having to declare + * the CookTimer itself within the scope (see CookTimer documentation) + */ + class ScopedTimer { + friend class AlgorithmTimer; + public: + ScopedTimer(unsigned int milliseconds) : m_timeout(milliseconds), m_timer(0) {} + ~ScopedTimer() { if (m_timer) m_timer->stop(); } + private: + unsigned int m_timeout; ///< Timeout in milliseconds + AlgorithmTimer* m_timer; ///< AlgorithmTimer instance, set by AlgorithmTimer::start() + }; + +} // namespace Athena + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/AthDsoUtils.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/AthDsoUtils.h new file mode 100644 index 00000000..bf591910 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/AthDsoUtils.h @@ -0,0 +1,18 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ATHDSOUTILS_H +#define ATHENAKERNEL_ATHDSOUTILS_H + +#include "DataModelRoot/RootType.h" + +namespace Athena { + namespace DsoUtils { + bool inDso( const RootDataMember& mem, + const std::string& dsoname ); + } + +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h new file mode 100644 index 00000000..931abac3 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h @@ -0,0 +1,37 @@ +// dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ATHENAKERNELDICT_H +#define ATHENAKERNEL_ATHENAKERNELDICT_H 1 + +#include <vector> +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IEventSeek.h" +#include "AthenaKernel/IEventShare.h" +#include "AthenaKernel/ICollectionSize.h" +#include "AthenaKernel/IAthenaSummarySvc.h" +#include "AthenaKernel/ITPCnvSvc.h" +#include "AthenaKernel/ITPCnvBase.h" +#include "AthenaKernel/ILockable.h" +#include "AthenaKernel/errorcheck.h" +#include "AthenaKernel/ICutFlowSvc.h" + +#include "AthenaKernel/DsoDb.h" +#include "AthenaKernel/AthDsoUtils.h" +#include "AthenaKernel/tools/AthenaPackageInfo.h" + +#include "GaudiKernel/MsgStream.h" + + +namespace AthenaKernelDict { + struct tmp { + Ath::DsoDb::DsoMap_t m_0; + Ath::DsoDb::DsoMap_t::iterator m_1; + Ath::DsoDb::DsoMap_t::const_iterator m_2; + }; +} //> namespace AthenaKernelDict + +#endif // !ATHENAKERNEL_ATHENAKERNELDICT_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/Chrono.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/Chrono.h new file mode 100644 index 00000000..3ff0bcba --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/Chrono.h @@ -0,0 +1,85 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/Chrono.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2014 + * @brief Exception-safe @c IChronoSvc caller. + */ + + +#ifndef ATHENAKERNEL_CHRONO_H +#define ATHENAKERNEL_CHRONO_H + + +#include "GaudiKernel/IChronoSvc.h" +#include <string> + + +namespace Athena { + + +/** + * @brief Exception-safe @c IChronoSvc caller. + * + * The way to time something using the Gaudi @c IChronoSvc is like this: + * + *@code + * chronosvc->chronoStart ("someName"); + * doSomething(); + * chronosvc->chronoStop ("someName"); + @endcode + * + * This is of course not exception-safe. + * + * This wrapper provides an exception-safe way of calling @c IChronoSvc: + * + * @code + * { + * Chrono chrono ("someName", chronosvc); + * doSomething(); + * } + @endcode + */ +class Chrono +{ +public: + /** + * @brief Start a @c IChronoSvc timer. + * @param name Name of the timer. + * @param svc The @c IChronoSvc. + * + * The timer will stop when this object is destroyed. + */ + Chrono (const std::string& name, IChronoSvc* svc) + : m_name (name), + m_svc (svc) + { + m_svc->chronoStart (m_name); + } + + + /** + * @brief Destructor. Stop the timer. + */ + ~Chrono() + { + m_svc->chronoStop (m_name); + } + + +private: + std::string m_name; + IChronoSvc* m_svc; +}; + + +} // namespace Athena + + +#endif // not ATHENA_KERNEL_CHRONO_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/CloneService.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/CloneService.h new file mode 100644 index 00000000..63888f23 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/CloneService.h @@ -0,0 +1,16 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_CLONESERVICE_H +#define ATHENAKERNEL_CLONESERVICE_H +#include "GaudiKernel/StatusCode.h" +#include <string> +class IService; +class Service; +namespace CloneService { + /** given a reference to a parent svc sets a reference to a cloned child */ + StatusCode clone(const IService* parent, const std::string& childName, + Service*& child); +} +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/CloneTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/CloneTool.h new file mode 100644 index 00000000..626c3bfd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/CloneTool.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_CLONETOOL_H +#define ATHENAKERNEL_CLONETOOL_H +#include "GaudiKernel/StatusCode.h" +#include <string> +class InterfaceID; +class IAlgTool; +namespace CloneTool { + ///implementation, experts only + StatusCode typeless_clone(const IAlgTool& cloned, + const std::string& cloneName, + const InterfaceID& cloneID, + IAlgTool*& result); + + /** given a reference to a cloned AlgTool sets a reference to its clone */ + template <class CLONEDTOOL> + StatusCode clone(const CLONEDTOOL& cloned, + const std::string& cloneName, + CLONEDTOOL*& result) { + return typeless_clone(cloned, cloneName, CLONEDTOOL::interfaceID(), + (IAlgTool*&)result); + } +} +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/CondCont.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/CondCont.h new file mode 100644 index 00000000..bf4650dd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/CondCont.h @@ -0,0 +1,339 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef IOVSVC_CONDCONT_H +#define IOVSVC_CONDCONT_H 1 + +#include <iostream> +#include <set> +#include <vector> +#include <typeinfo> +#include <mutex> +#include <typeinfo> + +#include "GaudiKernel/EventIDBase.h" +#include "GaudiKernel/EventIDRange.h" + +#include "AthenaKernel/IOVEntryT.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/DataObjID.h" + +namespace SG { + class DataProxy; + template<class T> + class ReadCondHandle; + template<class T> + class WriteCondHandle; +} + +class CondContBase { +public: + CondContBase() {}; + virtual ~CondContBase(){}; + + // virtual void list() const { std::cout << "CCBase" << std::endl; } + virtual void list(std::ostringstream&) const = 0; + virtual int entries() const { return 0; } + virtual bool valid( const EventIDBase& t) const = 0; + virtual const DataObjID& id() const = 0; + virtual bool insert(const EventIDRange& r, DataObject* obj) = 0; + virtual bool insert(const EventIDRange& r, void* obj) = 0; + + virtual SG::DataProxy* proxy() const = 0; + virtual void setProxy(SG::DataProxy*) = 0; + + virtual bool range(const EventIDBase&, EventIDRange&) const = 0; + virtual std::vector<EventIDRange> ranges() const = 0; + +private: +}; + +/////////////////////////////////////////////////////////////////////////// + +template <typename T> +class CondCont: public CondContBase { +public: + + friend SG::ReadCondHandle<T>; + friend SG::WriteCondHandle<T>; + + CondCont(const DataObjID& id, SG::DataProxy* prx=nullptr): + m_id(id), m_proxy(prx) {}; + ~CondCont(); + + bool insert(const EventIDRange& r, DataObject* t); + bool insert(const EventIDRange& r, void* t); + bool insert(const EventIDRange& r, T* t); + + bool find(const EventIDBase& t, T*&) const; + + virtual void list(std::ostringstream&) const; + virtual int entries() const; + + virtual bool valid( const EventIDBase& t ) const; + + virtual const DataObjID& id() const { return m_id; } + + virtual SG::DataProxy* proxy() const { return m_proxy; } + virtual void setProxy(SG::DataProxy* prx) { m_proxy = prx; } + + virtual bool range(const EventIDBase&, EventIDRange&) const; + virtual std::vector<EventIDRange> ranges() const; + +private: + + bool findEntry(const EventIDBase& t, const IOVEntryT<T>*&) const; + + bool isRE(const EventIDBase&) const; + bool isTS(const EventIDBase&) const; + + mutable std::mutex m_mut; + + typedef std::set<IOVEntryT<T>, typename IOVEntryT<T>::IOVEntryTStartCritereon > CondContSet; + CondContSet m_condSet_clock, m_condSet_RE; + + DataObjID m_id; + + SG::DataProxy* m_proxy; + +}; + +// +/////////////////////////////////////////////////////////////////////////// +// + +template <typename T> +CondCont<T>::~CondCont<T>() { + // std::cout << "cleaning up - " << typeid( T ).name() << std::endl; + + for (auto itr=m_condSet_clock.begin(); itr != m_condSet_clock.end(); ++itr) { + delete itr->objPtr(); + } + m_condSet_clock.clear(); + for (auto itr=m_condSet_RE.begin(); itr != m_condSet_RE.end(); ++itr) { + delete itr->objPtr(); + } + m_condSet_RE.clear(); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool CondCont<T>::insert(const EventIDRange& r, void* obj) { + T* t = static_cast<T*>(obj); + + return insert(r, t); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool CondCont<T>::insert(const EventIDRange& r, DataObject* obj) { + T* t = dynamic_cast<T*>( obj ); + + if (t == 0) { + std::cerr << "CondCont<>T unable to dcast from DataObject to " + << typeid(*t).name() + << std::endl; + return false; + } + + return insert(r, t); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool CondCont<T>::insert(const EventIDRange& r, T* t) { + + std::lock_guard<std::mutex> lock(m_mut); + + if (r.start().isRunEvent() && r.stop().isRunEvent()) { + m_condSet_RE.emplace( IOVEntryT<T>(t, r) ); + } else if (r.start().isTimeStamp() && r.stop().isTimeStamp()) { + m_condSet_clock.emplace( IOVEntryT<T>(t,r) ); + } else { + std::cerr << "CondCont<T>::insert error: EventIDRange " << r + << " is neither fully RunEvent nor TimeStamp" + << std::endl; + return false; + } + + return true; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool CondCont<T>::valid(const EventIDBase& it) const { + typename CondContSet::const_iterator itr; + + std::lock_guard<std::mutex> lock(m_mut); + + if (it.isRunEvent()) { + itr = m_condSet_RE.begin(); + for (; itr != m_condSet_RE.end(); ++itr) { + // std::cout << " -> " << itr->range() << " : " << *(itr->objPtr()) + // << std::endl; + if ( itr->range().isInRange( it ) ) { + return true; + } + } + } else if (it.isTimeStamp()) { + itr = m_condSet_clock.begin(); + for (; itr != m_condSet_clock.end(); ++itr) { + if ( itr->range().isInRange( it ) ) { + return true; + } + } + } + + return false; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool CondCont<T>::find(const EventIDBase& it, T*& t) const { + // typename std::set<IOVEntryT<T>, IOVEntryTComp<T> >::const_iterator itr; + typename CondContSet::const_iterator itr; + + std::lock_guard<std::mutex> lock(m_mut); + + if (it.isRunEvent()) { + itr = m_condSet_RE.begin(); + for (; itr != m_condSet_RE.end(); ++itr) { + // std::cout << " -> " << itr->range() << " : " << *(itr->objPtr()) + // << std::endl; + if ( itr->range().isInRange( it ) ) { + t = itr->objPtr(); + return true; + } + } + } else if (it.isTimeStamp()) { + itr = m_condSet_clock.begin(); + for (; itr != m_condSet_clock.end(); ++itr) { + if ( itr->range().isInRange( it ) ) { + t = itr->objPtr(); + return true; + } + } + } + + return false; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool CondCont<T>::findEntry(const EventIDBase& it, const IOVEntryT<T>*& t) const { + typename CondContSet::const_iterator itr; + + std::lock_guard<std::mutex> lock(m_mut); + + if (it.isRunEvent()) { + itr = m_condSet_RE.begin(); + for (; itr != m_condSet_RE.end(); ++itr) { + if ( itr->range().isInRange( it ) ) { + t = &(*itr); + return true; + } + } + } else if (it.isTimeStamp()) { + itr = m_condSet_clock.begin(); + for (; itr != m_condSet_clock.end(); ++itr) { + if ( itr->range().isInRange( it ) ) { + t = &(*itr); + return true; + } + } + } + + return false; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +void CondCont<T>::list(std::ostringstream& ost) const { + std::lock_guard<std::mutex> lock(m_mut); + + ost << "id: " << m_id << " proxy: " << m_proxy << std::endl; + + ost << "clock: [" << m_condSet_clock.size() << "]" << std::endl; + // std::set<IOVEntryT<T>, IOVEntryT<T>::IOVEntryTStartCritereon >::const_iterator itr = m_condSet_clock.begin(); + typename CondContSet::const_iterator itr = m_condSet_clock.begin(); + for (; itr != m_condSet_clock.end(); ++itr) { + ost << *itr << std::endl; + } + ost << "RE: [" << m_condSet_RE.size() << "]" << std::endl; + itr = m_condSet_RE.begin(); + for (; itr != m_condSet_RE.end(); ++itr) { + ost << *itr << std::endl; + } +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +int CondCont<T>::entries() const { + std::lock_guard<std::mutex> lock(m_mut); + return m_condSet_RE.size() + m_condSet_clock.size(); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +std::vector<EventIDRange> +CondCont<T>::ranges() const { + std::lock_guard<std::mutex> lock(m_mut); + + std::vector<EventIDRange> r; + for (auto ent : m_condSet_RE) { + r.push_back( ent.range() ); + } + for (auto ent : m_condSet_clock) { + r.push_back( ent.range() ); + } + + return r; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool +CondCont<T>::range(const EventIDBase& now, EventIDRange& r) const { + std::lock_guard<std::mutex> lock(m_mut); + + typename CondContSet::const_iterator itr; + if (now.isRunEvent()) { + itr = m_condSet_RE.begin(); + for (; itr != m_condSet_RE.end(); ++itr) { + if ( itr->range().isInRange( now ) ) { + r = itr->range(); + return true; + } + } + } else if (now.isTimeStamp()) { + itr = m_condSet_clock.begin(); + for (; itr != m_condSet_clock.end(); ++itr) { + if ( itr->range().isInRange( now ) ) { + r = itr->range(); + return true; + } + } + } + + return false; +} + + +// #include "SGTools/CLASS_DEF.h" +// CLASS_DEF( CondContBase , 34480459 , 1 ) +// #include "SGTools/BaseInfo.h" +// // SG_BASE( CondCont<Cont>, CondContBase ) + +#endif + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/DataObjectSharedPtr.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/DataObjectSharedPtr.h new file mode 100644 index 00000000..94eca3a2 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/DataObjectSharedPtr.h @@ -0,0 +1,46 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/DataObjectSharedPtr.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Smart pointer to manage @c DataObject reference counts. + */ + + +#ifndef ATHENAKERNEL_DATAOBJECTSHAREDPTR_H +#define ATHENAKERNEL_DATAOBJECTSHAREDPTR_H + + +#include "GaudiKernel/DataObject.h" +#include "boost/intrusive_ptr.hpp" + + +inline void intrusive_ptr_add_ref (DataObject* o) +{ + o->addRef(); +} + + +inline void intrusive_ptr_release (DataObject* o) +{ + o->release(); +} + + +namespace SG { + + +template <class T> +using DataObjectSharedPtr = boost::intrusive_ptr<T>; + + +} // namespace SG + + +#endif // not ATHENAKERNEL_DATAOBJECTSHAREDPTR_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/DefaultKey.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/DefaultKey.h new file mode 100644 index 00000000..62aece8b --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/DefaultKey.h @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_DEFAULTKEY_H +#define ATHENAKERNEL_DEFAULTKEY_H + +#include <string> + +namespace SG +{ + const std::string DEFAULTKEY = ""; +} +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/DirSearchPath.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/DirSearchPath.h new file mode 100644 index 00000000..2b7c977b --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/DirSearchPath.h @@ -0,0 +1,12 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef JOBOPTIONS_DIRSEARCHPATH_H +# define JOBOPTIONS_DIRSEARCHPATH_H + +// use the GaudiKernel one + +#include "GaudiKernel/DirSearchPath.h" + +#endif // JOBOPTIONS_DIRSEARCHPATH_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/DsoDb.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/DsoDb.h new file mode 100644 index 00000000..253773f4 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/DsoDb.h @@ -0,0 +1,166 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// DsoDb.h +// Header file for class DsoDb +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_ATH_DSODB_H +#define ATHENAKERNEL_ATH_DSODB_H 1 + +// STL includes +#include <iosfwd> +#include <string> +#include <vector> +#include <map> +#include "CxxUtils/unordered_map.h" // migrate to STL + +#include "DataModelRoot/RootType.h" + +// Forward declaration + +namespace Ath { + +/** @brief helper class to query rootmap files and extract their content + */ +class DsoDb +{ + /////////////////////////////////////////////////////////////////// + // Public typedefs: + /////////////////////////////////////////////////////////////////// +public: + typedef std::vector<std::string> Libs_t; + typedef SG::unordered_map<std::string, Libs_t> DsoMap_t; + //typedef std::map<std::string, Libs_t> DsoMap_t; + + // helper functions for pythonizations + static + std::vector<std::string> + py_keys_from(const Ath::DsoDb::DsoMap_t& m) + { + std::vector<std::string> k; + k.reserve(m.size()); + for (Ath::DsoDb::DsoMap_t::const_iterator i = m.begin(), e = m.end(); + i != e; + ++i) { + k.push_back(i->first); + } + return k; + } + + static + std::vector<std::vector<std::string> > + py_vals_from(const Ath::DsoDb::DsoMap_t& m) + { + std::vector<Libs_t> v; + v.reserve(m.size()); + for (Ath::DsoDb::DsoMap_t::const_iterator i = m.begin(), e = m.end(); + i != e; + ++i) { + v.push_back(i->second); + } + return v; + } + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** factory for the DsoDb + */ + static + DsoDb* instance(); + + /// Destructor: + ~DsoDb(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /// list of all dsomap/rootmap files we know about + const std::vector<std::string>& dso_files() const + { return m_dsofiles; } + + /// repository of plugin factories + const DsoMap_t& pf() const { return m_pf; } + + /// repository of components + const DsoMap_t& db() const { return m_db; } + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + bool has_type(const std::string& type_name); + + std::string load_type(const std::string& type_name); + + /// list of reflex-types associated with a library name + std::vector<std::string> capabilities(const std::string& libname); + + /// list of libraries hosting duplicate reflex-types + DsoMap_t duplicates(const std::string& libname, bool pedantic=false); + + /// table of dict-duplicates: {type: [lib1, lib2, ...]} + DsoMap_t dict_duplicates(bool pedantic=false); + + /// table of plugin-factories-duplicates: {type: [lib1, lib2, ...]} + DsoMap_t pf_duplicates(bool pedantic=false); + + /// list of all libraries we know about + /// @param `detailed` if true, prints the full path to the library + Libs_t libs(bool detailed=false); + + /// return the table {type: [lib1, ...]} - concatenation of all + /// dict-entries and plugin-factories entries. + /// @param `pedantic` if true, retrieves the library's full path + DsoMap_t content(bool pedantic); + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// initialize the repository of dso file names + void build_repository(); + + /// get the duplicates for a given repository of components + void + get_dups(DsoMap_t& dups, const DsoMap_t& db, bool pedantic); + + /// load the reflex type after having loaded the hosting library + RootType rflx_type(const std::string& type_name); + + /// Default constructor: + DsoDb(); + + /// Copy constructor: + DsoDb( const DsoDb& rhs ); //> not implemented + + /// Assignment operator: + DsoDb& operator=( const DsoDb& rhs ); //> not implemented + + /// repository of plugin factories + DsoMap_t m_pf; + + /// repository of components + DsoMap_t m_db; + + /// list of dsofiles + std::vector<std::string> m_dsofiles; + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +//std::ostream& operator<<( std::ostream& out, const DsoDb& o ); + +} //> end namespace Ath + +#endif //> !ATHENAKERNEL_ATH_DSODB_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAddressProvider.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAddressProvider.h new file mode 100644 index 00000000..626af2ae --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAddressProvider.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @class IAddressProvider + * @brief interface for IOA providers + * + * @author <pcalafiura@lbl.gov> - ATLAS Collaboration + * + * $Id: IAddressProvider.h,v 1.9 2003-04-16 01:12:23 calaf Exp $ + ***************************************************************************/ + +#ifndef ATHENAKERNEL_IADDRESSPROVIDER_H +# define ATHENAKERNEL_IADDRESSPROVIDER_H + +//<<<<<< INCLUDES >>>>>> +#include <list> +#include "GaudiKernel/StatusCode.h" +#include "AthenaKernel/StoreID.h" + +//<<<<<< FORWARD DECLARATIONS >>>>>> +namespace SG { + class TransientAddress; +} + +//<<<<<< CLASS DECLARATIONS >>>>>> +class IAddressProvider { +public: + typedef std::list<SG::TransientAddress*> tadList; + typedef tadList::iterator tadListIterator; + + ///get all addresses from Provider : Called before Begin Event + virtual StatusCode preLoadAddresses(StoreID::type /* storeID */, + tadList& /* list */) { + return StatusCode::SUCCESS; + } + + /// get all new addresses from Provider for this Event. + virtual StatusCode loadAddresses(StoreID::type /* storeID */, + tadList& /* list */) { + return StatusCode::SUCCESS; + } + + /// update a transient Address + virtual StatusCode updateAddress(StoreID::type storeID, + SG::TransientAddress* pTAd) = 0; + + virtual ~IAddressProvider() {} +}; + +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> + +#endif // ATHENAKERNEL_IADDRESSPROVIDER_H + + + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAtRndmGenSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAtRndmGenSvc.h new file mode 100644 index 00000000..d91e279c --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAtRndmGenSvc.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @class IAtRndmGenSvc + * @brief manage multiple CLHEP random engines as named streams + * + * @author Giorgos Stavropoulos <George.Stavropoulos@cern.ch> + * @author Paolo Calafiura <pcalafiura@lbl.gov> + * $Id: IAtRndmGenSvc.h,v 1.9 2007-02-08 17:48:38 binet Exp $ + */ + +#ifndef ATHENAKERNEL_IATRNDMGENSVC_H +# define ATHENAKERNEL_IATRNDMGENSVC_H + +#include "GaudiKernel/IService.h" +#include <string> +#include "stdint.h" + +namespace CLHEP { + class HepRandomEngine; +} + +class IAtRndmGenSvc : virtual public IService { +public: + /// Interface to the CLHEP engine + //@{ + virtual CLHEP::HepRandomEngine* GetEngine(const std::string& streamName)=0; + virtual void CreateStream(uint32_t seed1, uint32_t seed2, + const std::string& streamName)=0; + virtual CLHEP::HepRandomEngine* setOnDefinedSeeds(uint32_t theSeed, + const std::string& streamName)=0; + virtual CLHEP::HepRandomEngine* setOnDefinedSeeds(uint32_t eventNumber, + uint32_t runNumber, + const std::string& streamName)=0; + ///seed all streams we manage, combining theSeed and the stream names + virtual bool setAllOnDefinedSeeds (uint32_t theSeed)=0; + ///seed all streams, combining eventNumber, runNumber and the stream names + virtual bool setAllOnDefinedSeeds (uint32_t eventNumber, uint32_t runNumber)=0; + //@} + + /// out-of-line destructor + virtual ~IAtRndmGenSvc(); + + /// Print methods + //@{ + virtual void print(const std::string& streamName)=0; + virtual void print()=0; + //@} + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); + +}; +inline +const InterfaceID& +IAtRndmGenSvc::interfaceID() { + static const InterfaceID IID("IAtRndmGenSvc", 1, 0); + return IID; +} + +#endif // ATHENAKERNEL_IATRNDMGENSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaBarCode.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaBarCode.h new file mode 100644 index 00000000..d74c9af6 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaBarCode.h @@ -0,0 +1,101 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENABARCODE_H +#define ATHENAKERNEL_IATHENABARCODE_H +/////////////////////////////////////////////////////////////////////////////// +/// +/// IAthenaBarCode interface class +/// +/// \author Yushu Yao +/// +/// \brief barcode for all INav4Mom classes +/// +// // +/////////////////////////////////////////////////////////////////////////////// + + +#include <GaudiKernel/StatusCode.h> +#include <stdint.h> +//#include <iostream> + +/////////////////////////////////////////////////////////////////////////////// +// +// Universal Object Identifier for all Navigable4Momentum Objects +// +// Class Structure: +// IAthenaBarCode INavigable I4Momentum +// | / / +// V / / +// INav4M +// | +// V +// IParticle +// | +// V +// ParticleImpl +// +/////////////////////////////////////////////////////////////////////////////// + +//Work Around dependency issue of Navigation +//If don't see IUserDataSvc.h yet, do the definitions here. +#include <stdint.h> // for uint64_t +typedef uint64_t AthenaBarCode_t; + +typedef AthenaBarCode_t AthenaBarCodeVersion_t; + +class IAthenaBarCode { + +public: + + static const AthenaBarCode_t UNDEFINEDBARCODE = (AthenaBarCode_t)(-1); + static const AthenaBarCode_t UNDEFINEDVERSION = UNDEFINEDBARCODE; + +public: + + //Constructors + + IAthenaBarCode() { } + virtual ~IAthenaBarCode(); + + //All the default implementations are for the classes that derives from + //INav4M but not ParticleImpl + +public: + //Public setter and getters + virtual AthenaBarCode_t getAthenaBarCode() const { + return UNDEFINEDBARCODE; + } + + virtual void setAthenaBarCode(AthenaBarCode_t /*id*/) { + // throw std::runtime_error("IAthenaBarCode::setAthenaBarCode():: can't set AthenaBarCode in the dummy implementation"); + } + +public: + //Comparing & Versioning Control + virtual bool hasSameAthenaBarCode(const IAthenaBarCode &/*obj*/) const { + return false; + } + + virtual bool hasSameAthenaBarCodeExceptVersion(const IAthenaBarCode &/*obj*/) const { + return false; + } + + virtual AthenaBarCodeVersion_t getVersion() const { + return UNDEFINEDVERSION; + } + + virtual void newVersion() { + // throw std::runtime_error("IAthenaBarCode::newVersion():: can't newVersion() in the dummy implementation"); + } + + virtual void setVersion(AthenaBarCodeVersion_t /*newversion*/) { + // throw std::runtime_error("IAthenaBarCode::setVersion():: can't setVersion() in the dummy implementation"); + } + +}; + +#endif // NAVIGATION_ATHENABARCODE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaEvtLoopPreSelectTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaEvtLoopPreSelectTool.h new file mode 100644 index 00000000..178c4df7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaEvtLoopPreSelectTool.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENAEVTLOOPPRESELECTTOOL_H +#define ATHENAKERNEL_IATHENAEVTLOOPPRESELECTTOOL_H + +/** @file IAthenaEvtLoopPreSelectTool.h + * @brief This file contains the class definition for the IAthenaEvtLoopPreSelectTool class. + * @author Marjorie Shapiro <mdshapiro@lbl.gov> + **/ + +// Gaudi +#include "GaudiKernel/IAlgTool.h" + +/** @class IAthenaEvtLoopPreSelectTool + * @brief This class provides the interface for AthenaEvtLoopPreSelectTool classes used by AthenaEventLoopMgr + **/ + +class EventInfo; + +class IAthenaEvtLoopPreSelectTool : virtual public IAlgTool { + +public: + + static const InterfaceID& interfaceID() { + static const InterfaceID IID_IAthenaEvtLoopPreSelectTool ("IAthenaEvtLoopPreSelectTool", 1, 0 ); + return IID_IAthenaEvtLoopPreSelectTool; + } + + + /// Initialize AlgTool + virtual StatusCode initialize() = 0; + /// called for each event to decide if the event should be passed to the EventSelector + virtual bool passEvent(const EventInfo* pEvent) = 0; + /// Finalize AlgTool + virtual StatusCode finalize() = 0; +}; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaIPCTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaIPCTool.h new file mode 100644 index 00000000..b734fa1b --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaIPCTool.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENAIPCTOOL_H +#define ATHENAKERNEL_IATHENAIPCTOOL_H + +#include "GaudiKernel/IAlgTool.h" + +static const InterfaceID IID_IAthenaIPCTool( "IAthenaIPCTool", 1, 0 ); + +class IAthenaIPCTool : virtual public ::IAlgTool { +public: + static const InterfaceID& interfaceID() { return IID_IAthenaIPCTool; } + + virtual StatusCode makeServer(int num) = 0; + virtual bool isServer() const = 0; + virtual StatusCode makeClient(int num) = 0; + virtual bool isClient() const = 0; + + virtual StatusCode putEvent(long eventNumber, const void* source, size_t nbytes, unsigned int status) const = 0; + virtual StatusCode getLockedEvent(void** target, unsigned int& status) const = 0; + virtual StatusCode lockEvent(long eventNumber) const = 0; + + virtual StatusCode putObject(const void* source, size_t nbytes, int num = 0) const = 0; + virtual StatusCode getObject(void** target, size_t& nbytes, int num = 0) const = 0; + virtual StatusCode clearObject(char** tokenString, int& num) const = 0; + virtual StatusCode lockObject(const char* tokenString, int num = 0) const = 0; +}; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputStreamTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputStreamTool.h new file mode 100644 index 00000000..26ff4a48 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputStreamTool.h @@ -0,0 +1,128 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENAOUTPUTSTREAMTOOL_H +# define ATHENAKERNEL_IATHENAOUTPUTSTREAMTOOL_H +/** + * @file IAthenaOutputStreamTool.h + * + * @brief Interface to an output stream tool + * + * @author RD Schaffer <R.D.Schaffer@cern.ch> + * + * $Id: IAthenaOutputStreamTool.h,v 1.4 2007-06-23 01:12:06 calaf Exp $ + */ + + +// Gaudi +#include "GaudiKernel/IAlgTool.h" + +#include <string> +#include <vector> + + +class DataObject; +namespace SG { + class IFolder; +} + +/** + ** @class IAthenaOutputStreamTool + ** + ** @brief This is a tool that allows streaming out of + ** DataObjects. This has been factorized out from AthenaOutputStream + ** to allow output streaming to occur from anywhere, for example + ** from the finalized method of an algorithm. + ** + ** How to use the IAthenaOutputStreamTool: + ** + ** An initial setup of services should be done either via the + ** interface with connectServices or via jobOptions. Note that the + ** defaults are set to Conditions data writing, since event data + ** writing is normally done with AthenaOutputStream.: + ** + ** To write to a POOL/ROOT file one simply needs: + ** + ** ToolSvc = Service( "ToolSvc" ) + ** ToolSvc.CondStream1.OutputFile = "SimplePoolFile.root" + ** + ** where one retrieves the AthenaOutputStreamTool with name + ** CondStream1. + ** The default job opts are: + ** + ** ConversionSvc = "AthenaPoolCnvSvc" + ** StoreName = "DetectorStore" + ** + ** After initialization of services, one writes out with a sequence + ** of: + ** + ** connectOutput() + ** streamObjects(<list of objects>) + ** commitOutput() + ** + ** where <list of objects> may be a vector of type/key pairs, or a + ** vector of DataObjects. + ** + **/ + +class IAthenaOutputStreamTool : virtual public IAlgTool +{ + +public: + + /// Specify which data store and conversion service to use + /// and whether to extend provenence + /// Only use if one wants to override jobOptions + virtual StatusCode connectServices(const std::string& dataStore, + const std::string& cnvSvc, + bool extendProvenenceRecord = false) = 0; + + /// Connect to the output stream + /// Must connectOutput BEFORE streaming + /// Only specify "outputName" if one wants to override jobOptions + virtual StatusCode connectOutput(const std::string& outputName = "") = 0; + + /// Commit the output stream after having streamed out objects + /// Must commitOutput AFTER streaming + virtual StatusCode commitOutput() = 0; + + /// Finalize the output stream after the last commit, e.g. in + /// finalize + virtual StatusCode finalizeOutput() = 0; + + + /// Stream out objects. Provide vector of typeName/key pairs. + /// If key is empty, assumes only one object and this + /// will fail if there is more than one + typedef std::pair<std::string, std::string> TypeKeyPair; + typedef std::vector< TypeKeyPair > TypeKeyPairs; + virtual StatusCode streamObjects(const TypeKeyPairs& typeKeys) = 0; + + /// Stream out a vector of objects + /// Must convert to DataObject, e.g. + /// #include "SGTools/StorableConversions.h" + /// T* obj = xxx; + /// DataObject* dataObject = SG::asStorable(obj); + typedef std::vector< DataObject* > DataObjectVec; + virtual StatusCode streamObjects (const DataObjectVec& dataObjects) = 0; + + /// Fill refs of an object - done as second iteration over + /// objects, after streamObject + virtual StatusCode fillObjectRefs(const DataObjectVec& dataObjects) = 0; + + /// Get ItemList from the OutputStreamTool (e.g. all input objects) + virtual StatusCode getInputItemList(SG::IFolder* m_p2BWrittenFromTool) = 0; + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); +}; + +inline +const InterfaceID& +IAthenaOutputStreamTool::interfaceID() { + static const InterfaceID IID("IAthenaOutputStreamTool", 1, 0); + return IID; +} + +#endif // ATHENAKERNEL_IATHENAOUTPUTSTREAMTOOL_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputTool.h new file mode 100644 index 00000000..07c23ed5 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaOutputTool.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENAOUTPUTTOOL_H +#define ATHENAKERNEL_IATHENAOUTPUTTOOL_H + +/** @file IAthenaOutputTool.h + * @brief This file contains the class definition for the IAthenaOutputTool class. + * @author Peter van Gemmeren <gemmeren@anl.gov> + * $Id: IAthenaOutputTool.h,v 1.2 2008-05-27 21:12:34 gemmeren Exp $ + **/ + +// Gaudi +#include "GaudiKernel/IAlgTool.h" + +/** @class IAthenaOutputTool + * @brief This class provides the interface for AthenaOutputTool classes used by AthenaOutputStream. + **/ +class IAthenaOutputTool : virtual public IAlgTool { + +public: + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); + + /// Initialize AlgTool + virtual StatusCode initialize() = 0; + /// Called at the end of initialize + virtual StatusCode postInitialize() = 0; + /// Called at the beginning of execute + virtual StatusCode preExecute() = 0; + /// Called at the end of execute + virtual StatusCode postExecute() = 0; + /// Called at the beginning of finalize + virtual StatusCode preFinalize() = 0; + /// Finalize AlgTool + virtual StatusCode finalize() = 0; +}; + +inline const InterfaceID& IAthenaOutputTool::interfaceID() { + static const InterfaceID IID("IAthenaOutputTool", 1, 0); + return IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSealSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSealSvc.h new file mode 100644 index 00000000..2cc07275 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSealSvc.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + Athena Kernel package + ----------------------------------------- + Copyright (C) 2004 by ATLAS Collaboration + ***************************************************************************/ + +//<doc><file> $Id: IAthenaSealSvc.h,v 1.5 2008-06-02 07:49:43 yyao Exp $ +//<version> $Name: not supported by cvs2svn $ + +#ifndef ATHENAKERNEL_IATHENASEALSVC_H +# define ATHENAKERNEL_IATHENASEALSVC_H + + +#include "GaudiKernel/IInterface.h" + +// Declaration of the interface ID ( interface id, major version, minor version) + + +/** @class IAthenaSealSvc + + * @brief The interface implemented by the AthenaSealSvc service. This is + * used by clients to check the seal dictionary. + + * @author RD Schaffer + */ +class IAthenaSealSvc : virtual public IInterface { +public: + /** Check dictionary for a class + - dictionary filler must have been loaded, either by the + "system" or explicitly with "load" below + @param typeName - type/name of class to check + */ + virtual StatusCode checkClass(const std::string& typeName) const = 0; + + + /** Dynamically load a dictionary filler + @param dictName - name of dict filler lib, e.g. MyClassesDict + */ + virtual StatusCode loadDictFiller(const std::string& dictName) const = 0; + + /// Retrieve interface ID + static const InterfaceID& interfaceID() { + static const InterfaceID iid("IAthenaSealSvc", 1 , 0); + return iid; + } +}; + + + + +#endif // ATHENAKERNEL_IATHENASEALSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h new file mode 100644 index 00000000..e6eda6ac --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENASELECTORTOOL_H +#define ATHENAKERNEL_IATHENASELECTORTOOL_H + +/** @file IAthenaSelectorTool.h + * @brief This file contains the class definition for the IAthenaSelectorTool class. + * @author Peter van Gemmeren <gemmeren@anl.gov> + * $Id: IAthenaSelectorTool.h,v 1.4 2008-06-09 13:45:54 gemmeren Exp $ + **/ + +// Gaudi +#include "GaudiKernel/IAlgTool.h" + +/** @class IAthenaSelectorTool + * @brief This class provides the interface for AthenaSelectorTool classes used by AthenaEventSelector. + **/ +class IAthenaSelectorTool : virtual public IAlgTool { + +public: + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); + + /// Initialize AlgTool + virtual StatusCode initialize() = 0; + /// Called at the end of initialize + virtual StatusCode postInitialize() = 0; + /// Called at the beginning of next + virtual StatusCode preNext() = 0; + /// Called at the end of next + virtual StatusCode postNext() = 0; + /// Called at the beginning of finalize + virtual StatusCode preFinalize() = 0; + /// Finalize AlgTool + virtual StatusCode finalize() = 0; +}; + +inline const InterfaceID& IAthenaSelectorTool::interfaceID() { + static const InterfaceID IID("IAthenaSelectorTool", 1, 0); + return IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h new file mode 100644 index 00000000..b2e60fd8 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENASERIALIZESVC_H +#define ATHENAKERNEL_IATHENASERIALIZESVC_H + +#include "GaudiKernel/IService.h" +#include "DataModelRoot/RootType.h" + +class Guid; + +static const InterfaceID IID_IAthenaSerializeSvc( "IAthenaSerializeSvc", 1, 0 ); + +class IAthenaSerializeSvc : virtual public ::IService { +public: + static const InterfaceID& interfaceID() { return IID_IAthenaSerializeSvc; } + + virtual void* serialize(const void* object, const std::string& name, size_t& nbytes) const = 0; + virtual void* serialize(const void* object, const Guid& id, size_t& nbytes) const = 0; + virtual void* serialize(const void* object, const RootType& cltype, size_t& nbytes) const = 0; + + virtual void* deserialize(void* buffer, size_t& nbytes, const std::string& name) const = 0; + virtual void* deserialize(void* buffer, size_t& nbytes, const Guid& id) const = 0; + virtual void* deserialize(void* buffer, size_t& nbytes, const RootType& cltype) const = 0; +}; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSummarySvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSummarySvc.h new file mode 100644 index 00000000..d50975e7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IAthenaSummarySvc.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IATHENASUMMARYSVC_H +#define ATHENAKERNEL_IATHENASUMMARYSVC_H + +#ifndef GAUDIKERNEL_ISERVICE_H + #include "GaudiKernel/IService.h" +#endif +#ifndef KERNEL_STATUSCODES_H + #include "GaudiKernel/StatusCode.h" +#endif +#ifndef GAUDIKERNEL_CLASSID_H + #include "GaudiKernel/ClassID.h" +#endif + +#include <string> + +/** @class IAthenaSummarySvc + * @brief Abstract produces summary of Athena stuff + * @author Charles Leggett + */ + +class IAthenaSummarySvc : virtual public IService { + +public: + /// Retrieve interface ID + static const InterfaceID& interfaceID(); + + virtual ~IAthenaSummarySvc(); + + virtual StatusCode createSummary() = 0; + virtual void setStatus(int) = 0; + virtual void addListener(const std::string&) = 0; + virtual void addSummary(const std::string&, const std::string&) = 0; + virtual const std::string& getOutputFile() const = 0; + + +}; + +inline +const InterfaceID& +IAthenaSummarySvc::interfaceID() { + static const InterfaceID IID("IAthenaSummarySvc", 1, 0); + return IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IClassIDSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IClassIDSvc.h new file mode 100644 index 00000000..0f643380 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IClassIDSvc.h @@ -0,0 +1,14 @@ +// dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ICLASSIDSVC_H +# define ATHENAKERNEL_ICLASSIDSVC_H + +// moved to GaudiKernel + +#include "GaudiKernel/IClassIDSvc.h" + +#endif // ATHENAKERNEL_ICLASSIDSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ICollectionSize.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ICollectionSize.h new file mode 100644 index 00000000..480ae67f --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ICollectionSize.h @@ -0,0 +1,49 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ICollectionSize.h,v 1.1 2005-05-05 00:15:02 calaf Exp $ +/** + * @file ICollectionSize.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2005 + * @brief Abstract interface for finding the size of an event collection. + */ + +#ifndef ATHENAKERNEL_ICOLLECTIONSIZE_H +#define ATHENAKERNEL_ICOLLECTIONSIZE_H + + +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/INamedInterface.h" + + +static const InterfaceID IID_ICollectionSize("ICollectionSize", 1 , 0); + + +/** + * @class ICollectionSize + * @brief Abstract interface for finding the size of an event collection. + */ +class ICollectionSize +{ +public: + /** + * @brief Destructor. + */ + virtual ~ICollectionSize () {}; + + + static const InterfaceID& interfaceID() { return IID_ICollectionSize; } + + + /** + * @brief Return the size of the collection. + */ + virtual int size () = 0; +}; + + +#endif // not ATHENAKERNEL_ICOLLECTIONSIZE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ICoreDumpSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ICoreDumpSvc.h new file mode 100644 index 00000000..677f3dbf --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ICoreDumpSvc.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ICOREDUMPSVC_H +#define ATHENAKERNEL_ICOREDUMPSVC_H + +/** + * @file ICoreDumpSvc.h + * @brief Interface of a core dump service + * @author Frank Winklmeier + * + * $Id: ICoreDumpSvc.h,v 1.2 2008-05-28 10:55:04 fwinkl Exp $ + */ + +#ifndef GAUDIKERNEL_IINTERFACE_H + #include "GaudiKernel/IInterface.h" +#endif +#ifndef _CPP_STRING + #include <string> +#endif + +/** + * @class ICoreDumpSvc + * @brief Interface of a core dump service + * @author Frank Winklmeier + * + * This interface allows to set and print core dump records. + */ + +class ICoreDumpSvc: virtual public IInterface { +public: + /// Retrieve interface ID + static const InterfaceID& interfaceID(); + + /// Virtualize D'tor + virtual ~ICoreDumpSvc() {} + + /// Set a name/value pair in the core dump record + virtual void setCoreDumpInfo( const std::string& name, const std::string& value ) = 0; + + /// Print all core dump records + virtual std::string dump() const = 0; +}; + + +inline const InterfaceID& ICoreDumpSvc::interfaceID() +{ + static const InterfaceID IID_ICoreDumpSvc("ICoreDumpSvc", 1, 0); + return IID_ICoreDumpSvc; +} + +#endif // ATHENAKERNEL_ICOREDUMPSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ICutFlowSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ICutFlowSvc.h new file mode 100644 index 00000000..a7b49442 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ICutFlowSvc.h @@ -0,0 +1,124 @@ +///////////////////////// -*- C++ -*- ////////////////////////////////////////////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Header file for class ICutFlowSvc // +// Authors: Joao Firmino da Costa (joao.costa@cern.ch) and David Cote (david.cote@cern.ch), July 2010 // +//////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_ICUTFLOWSVC_H +#define ATHENAKERNEL_ICUTFLOWSVC_H 1 + +//<<<<<< INCLUDES >>>>>> +#include <vector> +#include <string> +#include <map> +#include <stdint.h> // for uint32_t + + +//<<<<<< FORWARD DECLARATIONS >>>>>> +class INamedInterface; +//class EventBookkeeper; +//class EventBookkeeperCollection; +//class TTree; +// namespace xAOD{ +// class CutBookkeeper; +// } + + +/// InstanceIdentifier is a unique identifer used for every AthFilterAlgorithm instance +typedef uint32_t CutIdentifier; + + +/** + * @class ICutFlowSvc + * @brief This class provides an interface between event filtering algorithms and athena input/output streams, + * @brief and returns a comprehensive summary of filters "Cut Flow" by internally using T/P EventBookkeeper objects. + * @brief ICutFlowSvc also supports flat TTree format for D3PD usage. + */ + +class ICutFlowSvc + : virtual public ::INamedInterface +{ + +public: + + virtual ~ICutFlowSvc(); + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + +public: + + /// Register filter in the CutFlowSvc and returns the CutID of the + /// corresponding EventBookkeeper. + /// This method should be used by filters that register themselves. + virtual CutIdentifier registerFilter( const std::string& name, + const std::string& description ) = 0; + + /// Register cut as child of a filter in the CutFlowSvc and returns the CutID + /// of the corresponding EventBookkeeper. This method should be used by + /// filters to register their internal cuts that are not the Algs themselves. + virtual CutIdentifier registerCut( const std::string& name, + const std::string& description, + CutIdentifier parentCutID ) = 0; + + /// Tells CutFlowSvc that a filter is used directly by an outputStream with + /// a given logical context. The only foreseen client should the DecisionSvc, + /// with its Accept/Require/Veto. + virtual CutIdentifier registerTopFilter( const std::string& name, + const std::string& description, + unsigned int logic, + const std::string& outputStream ) = 0; + + /// Tells CutFlowSvc that a filter should not be treated as as being used by + /// another filter. This should be used by filters that use other filter Algs + /// internally, e.g., like the LogicalFilterCombiner + virtual CutIdentifier declareUsedOtherFilter( const std::string& name, + CutIdentifier originCutID ) = 0; + + /// Set the description of an existing EventBookkeeper + virtual void setFilterDescription( CutIdentifier cutID, + const std::string& descr ) = 0; + + /// Tells CutFlowSvc to update the event counter of a CutIdentifier cutID, + /// using the CutIdentifier returned by selfRegisterFilter or registerCut + /// Internally, the Monte Carlo event weight will be retrieved from the + /// xAOD::EventInfo object as evtWeight = evtInfo->mcEventWeight(); + virtual void addEvent( CutIdentifier cutID ) = 0; + + /// Tells CutFlowSvc to update the weighted event counter of a CutIdentifier cutID, + /// using CutIdentifier returned by selfRegisterFilter or registerCut + virtual void addEvent( CutIdentifier cutID, double weight) = 0; + + /// Get a CutBookkeeper given a CutID + // virtual xAOD::CutBookkeeper* getCutBookkeeper( const CutIdentifier cutID ) = 0; + + /// Helper function for D3PDs, dumps the CutFlowSvc content into a flat TTree. + /// The returned TTree is owned by the caller and can be eventually written by the caller in its favorite output TFile. + //virtual TTree* dumpCutFlowToTTree( const char* treeName="CutFlowTree" ) = 0; + + /// Inverse of above DumpCutFlowToTTree: when reading a D3PD, re-interpret the flat TTree to a usual transient EventBookkeeperCollection. + /// This should be the only method able to read flat TTrees, the other CutFlowSvc functionalities always work with EventBookkeepers. + /// The produced EventBookkeeperCollection remains internal to the CutFlowSvc, users can manipulate it using the usual ICutFlowSvc interface. + //virtual void loadCutFlowFromTTree( TTree* t ) = 0; + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); + +}; + + +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> +inline +const InterfaceID& +ICutFlowSvc::interfaceID() +{ + static const InterfaceID IID_ICutFlowSvc("ICutFlowSvc", 1, 0); + return IID_ICutFlowSvc; +} + + +#endif //> !ATHENAKERNEL_ICUTFLOWSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IDataShare.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IDataShare.h new file mode 100644 index 00000000..d3921bcc --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IDataShare.h @@ -0,0 +1,56 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: $ +/** + * @file IDataShare.h + * @author peter van gemmeren <gemmeren@anl.gov> + * @date March, 2015 + */ + +#ifndef ATHENAKERNEL_IDATASHARE_H +#define ATHENAKERNEL_IDATASHARE_H 1 + +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/INamedInterface.h" + +/** + * @class IDataShare + * @brief Abstract interface for sharing data + */ + +static const InterfaceID IID_IDataShare("IDataShare", 1 , 0); + +class IDataShare : virtual public INamedInterface +{ +public: + /** + * @brief Destructor. + */ + virtual ~IDataShare (); + + static const InterfaceID& interfaceID() { return IID_IDataShare; } + + /** + * @brief Make this a server. + * @param num The number for the server. + */ + virtual StatusCode makeServer(int num) = 0; + + /** + * @brief Make this a client. + * @param num The number for the client. + */ + virtual StatusCode makeClient(int num) = 0; + + /** + * @brief Read the data + */ + virtual StatusCode readData() const = 0; +}; + + +#endif // not ATHENAKERNEL_IDATASHARE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h new file mode 100644 index 00000000..d1f8bdd0 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h @@ -0,0 +1,93 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IDecisionSvc.h +// Header file for class IDecisionSvc +// Author: S.Binet<binet@cern.ch> +// B.Radics<radbal@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_IDECISIONSVC_H +#define ATHENAKERNEL_IDECISIONSVC_H 1 + +/** + * @class IDecisionSvc + * @brief This class defines a protocol to register boolean decisions and + * @brief and retrieve them and their combined result + */ + +// STL includes +#include <vector> +#include <string> +#include <map> + +// fwd declares +class INamedInterface; + + +class IDecisionSvc + : virtual public ::INamedInterface +{ + +public: + + virtual ~IDecisionSvc(); + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + +public: + + // Add Stream + virtual StatusCode addStream(const std::string& stream) = 0; + // Add methods of Accept/Require/Veto algorithms for a given stream + virtual StatusCode addAcceptAlg(const std::string& name, + const std::string& stream) = 0; + virtual StatusCode addRequireAlg(const std::string& name, + const std::string& stream) = 0; + virtual StatusCode addVetoAlg(const std::string& name, + const std::string& stream) = 0; + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + // Get methods of Accept/Require/Veto algorithms for a given stream + virtual + const std::vector<std::string> * getAcceptAlgs(const std::string& stream) const = 0; + + virtual + const std::vector<std::string> * getRequireAlgs(const std::string& stream) const = 0; + + virtual + const std::vector<std::string> * getVetoAlgs(const std::string& stream) const = 0; + + // Get list of streams + virtual const std::vector<std::string>* getStreams() const = 0; + + /// Test whether this event should be output, of a given stream + virtual bool isEventAccepted(const std::string& stream) const = 0; + + + static const InterfaceID& interfaceID(); + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline +const InterfaceID& +IDecisionSvc::interfaceID() +{ + static const InterfaceID IID_IDecisionSvc("IDecisionSvc", 1, 0); + return IID_IDecisionSvc; +} + + +#endif //> !ATHENAKERNEL_IDECISIONSVC_H + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IDictLoaderSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IDictLoaderSvc.h new file mode 100644 index 00000000..af220ba8 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IDictLoaderSvc.h @@ -0,0 +1,105 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IDictLoaderSvc.h +// Header file for class IDictLoaderSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_IDICTLOADERSVC_H +#define ATHENAKERNEL_IDICTLOADERSVC_H 1 + +/** @class IDictLoaderSvc a simple interface to interact with the Reflex + * dictionaries and abstract/workaround a few ROOT bugs. + * There are 2 methods in this interface: + * @c has_type to check if a type is known to the reflex system + * @c load_type to retrieve the @c RootType associated with a given + * C++ type (by name or by @c std::type_info) + */ + +// STL includes +#include <string> +#include <typeinfo> + +// FrameWork includes +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/ClassID.h" + +#include "DataModelRoot/RootType.h" + + +class IDictLoaderSvc + : virtual public ::IInterface +{ + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** Destructor: + */ + virtual ~IDictLoaderSvc(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + static const InterfaceID& interfaceID(); + + /** @brief check a @c Reflex dictionary exists for a given type + */ + virtual + bool has_type (const std::string& type_name) = 0; + + /** @brief check a @c Reflex dictionary exists for a given type + */ + virtual + bool has_type (const std::type_info& typeinfo) = 0; + + /** @brief check a @c Reflex dictionary exists for a given type + */ + virtual + bool has_type (CLID clid) = 0; + + /** @brief retrieve a @c RootType by name (auto)loading the dictionary + * by any necessary means. + */ + virtual + const RootType load_type (const std::string& type_name) = 0; + + /** @brief retrieve a @c RootType by @c std::type_info (auto)loading the + * dictionary by any necessary means. + * This method is preferred over the above one as it is guaranteed to + * succeed *IF* the dictionary for that type has been generated. + */ + virtual + const RootType load_type (const std::type_info& typeinfo) = 0; + + /** @brief retrieve a @c RootType by name (auto)loading the dictionary + * by any necessary means. + */ + virtual + const RootType load_type (CLID clid) = 0; + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline +const InterfaceID& +IDictLoaderSvc::interfaceID() +{ + static const InterfaceID IID_IDictLoaderSvc("IDictLoaderSvc", 1, 0); + return IID_IDictLoaderSvc; +} + + +#endif //> !ATHENAKERNEL_IDICTLOADERSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventDumperSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventDumperSvc.h new file mode 100644 index 00000000..1081b654 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventDumperSvc.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IEVENTDUMPERSVC_H +#define ATHENAKERNEL_IEVENTDUMPERSVC_H 1 + +/////////////////////////////////////////////////////////////////////////// +// +// IEventDumperSvc.h +// +// +// +// author: +// +/////////////////////////////////////////////////////////////////////////// + + +#include "GaudiKernel/IService.h" + + +/** @class IEventDumperSvc + * @brief Abstract interface for EventDumperSvc. Just a placeholder for now + * @author Charles Leggett + */ + +class IEventDumperSvc : virtual public IService +{ + + public: + + static const InterfaceID& interfaceID(); + +}; + +inline const InterfaceID& IEventDumperSvc::interfaceID() { + static const InterfaceID m_IID("IEventDumperSvc", 1, 0); + return m_IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventSeek.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventSeek.h new file mode 100644 index 00000000..775ba220 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventSeek.h @@ -0,0 +1,46 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IEventSeek.h,v 1.1 2005-05-05 00:15:02 calaf Exp $ +/** + * @file IEventSeek.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2005 + * @brief Abstract interface for seeking within an event stream. + */ + +#ifndef ATHENAKERNEL_IEVENTSEEK_H +#define ATHENAKERNEL_IEVENTSEEK_H 1 + +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/INamedInterface.h" + +/** + * @class IEventSeek + * @brief Abstract interface for seeking within an event stream. + */ + +class IEventSeek : virtual public INamedInterface +{ +public: + DeclareInterfaceID(IEventSeek, 1, 0); + + + /** + * @brief Seek to a given event number. + * @param evtnum The event number to which to seek. + */ + virtual StatusCode seek (int evtnum) = 0; + + /** + * @brief return the current event number. + * @return The current event number. + */ + virtual int curEvent () const = 0; +}; + + +#endif // not ATHENAKERNEL_IEVENTSEEK_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventShare.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventShare.h new file mode 100644 index 00000000..e394aceb --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEventShare.h @@ -0,0 +1,62 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: $ +/** + * @file IEventShare.h + * @author peter van gemmeren <gemmeren@anl.gov> + * @date August, 2011 + */ + +#ifndef ATHENAKERNEL_IEVENTSHARE_H +#define ATHENAKERNEL_IEVENTSHARE_H 1 + +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/INamedInterface.h" + +/** + * @class IEventShare + * @brief Abstract interface for sharing within an event stream. + */ + +static const InterfaceID IID_IEventShare("IEventShare", 1 , 0); + +class IEventShare : virtual public INamedInterface +{ +public: + /** + * @brief Destructor. + */ + virtual ~IEventShare (); + + static const InterfaceID& interfaceID() { return IID_IEventShare; } + + /** + * @brief Make this a server. + * @param num The number for the server. + */ + virtual StatusCode makeServer(int num) = 0; + + /** + * @brief Make this a client. + * @param num The number for the client. + */ + virtual StatusCode makeClient(int num) = 0; + + /** + * @brief Request to share a given event. + * @param evtnum The event sequence number to share. + */ + virtual StatusCode share (int evtnum) = 0; + + /** + * @brief Read the next maxevt events. + * @param maxevt The number of events to read. + */ + virtual StatusCode readEvent(int maxevt) = 0; +}; + +#endif // not ATHENAKERNEL_IEVENTSHARE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h new file mode 100644 index 00000000..397aae4a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h @@ -0,0 +1,116 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IEvtIdModifierSvc.h +// Header file for class IEvtIdModifierSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_IEVTIDMODIFIERSVC_H +#define ATHENAKERNEL_IEVTIDMODIFIERSVC_H 1 + +/** @class IEvtIdModifierSvc + */ + +// STL includes +#include <string> +#include <vector> + +// FrameWork includes +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/ClassID.h" + +// AthenaKernel includes + +// fwd declares +class EventID; + +class IEvtIdModifierSvc + : virtual public ::IInterface +{ + /////////////////////////////////////////////////////////////////// + // Public typedefs: + /////////////////////////////////////////////////////////////////// + public: + typedef unsigned int number_type; //FIXME: keep in synch with EventID!! + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** Destructor: + */ + virtual ~IEvtIdModifierSvc(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief return the current run-nbr (after modification) + */ + virtual number_type run_number() const =0; + + /** @brief return the current evt-nbr (after modification) + */ + virtual uint64_t event_number() const =0; + + /** @brief return the current time-stamp (after modification) + */ + virtual number_type time_stamp() const =0; + + /** @brief return the current lbk-nbr (after modification) + */ + virtual number_type lumi_block() const =0; + + /** @brief tell if the svc modified the run-nbr (for *this* event!) + */ + virtual bool has_modified_run_number() const =0; + + /** @brief tell if the svc modified the evt-nbr (for *this* event!) + */ + virtual bool has_modified_event_number() const =0; + + /** @brief tell if the svc modified the time-stamp (for *this* event!) + */ + virtual bool has_modified_time_stamp() const =0; + + /** @brief tell if the svc modified the lbk-nbr (for *this* event!) + */ + virtual bool has_modified_lumi_block() const =0; + + /** @brief return the (sorted) list of run-numbers which will be modified. + */ + virtual + std::vector<number_type> run_number_list() const =0; + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + static const InterfaceID& interfaceID(); + + /** @brief modify an `EventID`'s content + */ + virtual + void + modify_evtid(EventID*& evt_id, bool consume_stream=false) = 0; + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline const InterfaceID& IEvtIdModifierSvc::interfaceID() +{ + static const InterfaceID IID_IEvtIdModifierSvc("IEvtIdModifierSvc", 1, 0); + return IID_IEvtIdModifierSvc; +} + +#endif //> !ATHENAKERNEL_IEVTIDMODIFIERSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IGMASvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IGMASvc.h new file mode 100644 index 00000000..31665cfd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IGMASvc.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IGMASVC_H +#define ATHENAKERNEL_IGMASVC_H + +// Include Files +#ifndef GAUDIKERNEL_IINTERFACE_H + #include "GaudiKernel/IInterface.h" +#endif +#ifndef KERNEL_STATUSCODES_H + #include "GaudiKernel/StatusCode.h" +#endif +#ifndef _CPP_STRING + #include <string> +#endif + +/** @class IGMASvc IGMASvc.h AthenaKernel/IGMASvc.h + + * @brief The interface implemented by the GMASvc service. + + * @author David Quarrie +*/ +class IGMASvc : virtual public IInterface { +public: + + virtual StatusCode report( unsigned int level, const char* eventName, const char* eventData=0 ) = 0; + virtual StatusCode report( unsigned int level, const std::string& eventName ) = 0; + virtual StatusCode report( unsigned int level, const std::string& eventData, const std::string& eventData ) = 0; + + /// Retrieve interface ID + static const InterfaceID& interfaceID() { + static const InterfaceID _iid("IGMASvc", 1, 0); + return _iid; + } +}; + +#endif // ATHENAKERNEL_IGMASVC_H + + + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStore.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStore.h new file mode 100644 index 00000000..a354d855 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStore.h @@ -0,0 +1,50 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IHIVESTORE_H +# define ATHENAKERNEL_IHIVESTORE_H + + +#include "GaudiKernel/INamedInterface.h" + + +class IProxyDict; + +/** @class IHiveStore + * @brief the interface that provides access to the current hive store + * + * @author Paolo Calafiura - ATLAS + * $Id: IHiveStore.h 714254 2015-12-12 03:38:51Z ssnyder $ + */ + +class IHiveStore : virtual public INamedInterface { +public: + virtual ~IHiveStore() {} + + virtual IProxyDict* hiveProxyDict() = 0; + + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); +}; + +inline +const InterfaceID& +IHiveStore::interfaceID() { + static const InterfaceID IID("IHiveStore", 1, 0); + return IID; +} +#endif // ATHENAKERNEL_IHIVESTORE_H + + + + + + + + + + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStoreMgr.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStoreMgr.h new file mode 100644 index 00000000..1a643f7d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IHiveStoreMgr.h @@ -0,0 +1,72 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IHIVESTOREMGR_H +# define ATHENAKERNEL_IHIVESTOREMGR_H + + +#include "GaudiKernel/INamedInterface.h" +#include "GaudiKernel/DataObjID.h" + + +namespace SG { + class DataProxy; +} + +/** @class IHiveStoreMgr + * @brief the interface through which HiveWB control StoreGate instances + * + * @author Paolo Calafiura - ATLAS + * $Id: IHiveStoreMgr.h 547067 2013-05-07 22:14:35Z calaf $ + */ + +class IHiveStoreMgr : virtual public INamedInterface { +public: + /// clear the store + virtual StatusCode clearStore(bool forceRemove=false) =0; + + /** Get data objects registred in store since last getNewDataObjects call (or since init for 1st call) + * + * @param products [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode getNewDataObjects(DataObjIDColl& products)=0; + + /** Check if something has been added to the store since last getNewDataObjects call + * + * @param products [IN] Slot number (event slot) * + * @return Boolean indicating the presence of new products + */ + virtual bool newDataObjectsPresent()=0; + + /** make newly recorded DataObjects know to the WhiteBoard, by copying + * from thread local storag + */ + virtual void commitNewDataObjects() = 0; + + virtual ~IHiveStoreMgr() {} + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); +}; + +inline +const InterfaceID& +IHiveStoreMgr::interfaceID() { + static const InterfaceID IID("IHiveStoreMgr", 1, 0); + return IID; +} +#endif // ATHENAKERNEL_IHIVESTOREMGR_H + + + + + + + + + + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVDbSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVDbSvc.h new file mode 100644 index 00000000..ff2ab6d6 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVDbSvc.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IIOVDBSVC_H +#define ATHENAKERNEL_IIOVDBSVC_H + +/** + * + * @file IIOVDbSvc.h + * @brief Abstract interface to IOVDbSvc to access IOVRange and + * tag information + * + * @author Charles Leggett, RD Schaffer + * $Id: IIOVDbSvc.h,v 1.11 2009-02-02 17:54:35 leggett Exp $ + * + * + *****************************************************************************/ + +#include "GaudiKernel/IInterface.h" +#ifndef _CPP_STRING +#include <string> +#endif +#ifndef KERNEL_STATUSCODES_H +#include "GaudiKernel/StatusCode.h" +#endif +#ifndef GAUDIKERNEL_CLASSID_H +#include "GaudiKernel/ClassID.h" +#endif + +// Declaration of the interface ID. +static const InterfaceID IID_IOVDbSvc("IOVDbSvc", 1 , 0); + +class IOVRange; +class IOVTime; +class IOpaqueAddress; + +/** + * + * @class IIOVDbSvc + * @brief Abstract interface to IOVDbSvc to access IOVRange and + * tag information + */ +class IIOVDbSvc : virtual public IInterface { +public: + /// Retrieve interface ID + static const InterfaceID& interfaceID(); + + /// Get range for a particular data object + virtual StatusCode getRange (const CLID& clid, + const std::string& dbKey, + const IOVTime& time, + IOVRange& range, + std::string& tag, + IOpaqueAddress*& ioa) = 0; + + /// Set range for a particular data object + virtual StatusCode setRange (const CLID& clid, + const std::string& dbKey, + const IOVRange& range, + const std::string& tag ) = 0; + + /// Set time for begin run + virtual StatusCode signalBeginRun(const IOVTime& beginRunTime) = 0; + + /// Signal that callback has been fired + virtual void signalEndProxyPreload() = 0; + + /// Register callback for TagInfo access + virtual StatusCode registerTagInfoCallback() = 0; + + // return list of SG keys being provided by IOVDbSvc + virtual std::vector<std::string> getKeyList() = 0; + + // return information about one SG key + // - folder, tag, IOVRange and whether data has been retrieved + // (if not, range and tag may not be meaningful) + // return false if this key is not known to IOVDbSvc + virtual bool getKeyInfo(const std::string& key, std::string& foldername, + std::string& tag, IOVRange& range, bool& retrieved, + unsigned long long& bytesRead, float& readTime) = 0; + + // drop an IOVDbSvc-managed object from Storegate, indicating we will + // not read it again and can free up memory + // If resetCache=True, also drop the corresponding folder cache + // so any subsequent reads will access the database again + // returns False if key not known to IOVDbSvc + virtual bool dropObject(const std::string& key, + const bool resetCache=false) = 0; +}; + + +inline +const InterfaceID& +IIOVDbSvc::interfaceID() { + static const InterfaceID IID("IOVDbSvc", 1, 0); + return IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVSvc.h new file mode 100644 index 00000000..80d0e5bb --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIOVSvc.h @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IIOVSVC_H +#define ATHENAKERNEL_IIOVSVC_H + +#ifndef GAUDIKERNEL_ISERVICE_H + #include "GaudiKernel/IService.h" +#endif +#ifndef KERNEL_STATUSCODES_H + #include "GaudiKernel/StatusCode.h" +#endif +#ifndef GAUDIKERNEL_CLASSID_H + #include "GaudiKernel/ClassID.h" +#endif + +#ifndef _CPP_STRING + #include <string> +#endif +#ifndef _CPP_VECTOR + #include <vector> +#endif +#ifndef _CPP_SET + #include <set> +#endif + +#ifndef ATHENAKERNEL_IOVSVCDEFS_H + #include "AthenaKernel/IOVSvcDefs.h" +#endif + +class IOVRange; +class IOVTime; +class IIOVSvcTool; +class CallBackID; +class IOpaqueAddress; +class CondContBase; +class DataObjID; +class EventIDBase; + +namespace SG { + class DataProxy; + class TransientAddress; +} + +/** @class IIOVSvc + * @brief Abstract interface for IOVSvc. This is used (usually via + * StoreGateSvc regFcn and regHandle methods) to setup access to time-varying + * data, such as calibration. See http://annwm.lbl.gov/~leggett/Atlas/IOVSvc/main.shtml for details + * @author Charles Leggett + */ + +class IIOVSvc : virtual public IService { + +public: + /// Retrieve interface ID + static const InterfaceID& interfaceID(); + + virtual StatusCode createIOVTool( const std::string& storeName ) = 0; + virtual std::vector<std::string> getStoreNames() const = 0; + + /// @name interface to the IOVSvc CBTree + //@{ + + /** + * @brief register callback function + * @param[in] dp trigger callback after data in dp changes + * @param[in] c a unique identifier of the callback (see CallBackID) + * @param[in] fcn a boost::function object holding the callback function and the object it operates on + * @param[in] trigger request immediate callback of fcn (default false) + */ + virtual StatusCode regFcn(SG::DataProxy *dp, const CallBackID c, + const IOVSvcCallBackFcn& fcn, + bool trigger=false) = 0; + + /** + * @brief register callback function + * @param[in] c1 call back fcn2 after callback with CallBackID c1 is triggered + * @param[in] c2 a unique identifier of this callback + * @param[in] fcn2 a boost::function object holding the callback function and the object it operates on + * @param[in] trigger request immediate callback of fcn (default false) + */ + virtual StatusCode regFcn(const CallBackID c1, const CallBackID c2, + const IOVSvcCallBackFcn& fcn2, + bool trigger=false ) = 0; + + /** + * @brief register callback function + * @param[in] toolName call back fcn2 after the tool named toolName (registered as a callback) is triggered + * @param[in] c2 a unique identifier of the callback (see CallBackID) + * @param[in] fcn2 a boost::function object holding the callback function and the object it operates on + * @param[in] trigger request immediate callback of fcn (default false) + */ + virtual StatusCode regFcn(const std::string &toolName, const CallBackID c2, + const IOVSvcCallBackFcn& fcn2, + bool trigger=false) = 0; + + /// Subscribe method for DataProxy. key StoreGate key + virtual StatusCode regProxy( const SG::DataProxy *proxy, + const std::string& key, + const std::string& storeName="StoreGateSvc") = 0; + /// replace a registered proxy with a new version + virtual StatusCode replaceProxy( const SG::DataProxy *pOld, + const SG::DataProxy *pNew, + const std::string& storeName="StoreGateSvc") = 0; + + /// Another way to subscribe + virtual StatusCode regProxy( const CLID& clid, const std::string& key, + const std::string& storeName="StoreGateSvc" ) = 0; + //@} + + virtual StatusCode deregProxy( const SG::DataProxy *proxy ) = 0; + virtual StatusCode deregProxy( const CLID& clid, const std::string& key ) = 0; + + + + /// @name IOVRange accessors + //@{ + virtual StatusCode setRange(const CLID& clid, const std::string& key, + IOVRange&) = 0; + virtual StatusCode setRange(const CLID& clid, const std::string& key, + IOVRange&, + const std::string& storeName) = 0; + + virtual StatusCode getRange(const CLID& clid, const std::string& key, + IOVRange& iov ) const = 0; + + /// Get IOVRange from db for current event + virtual StatusCode getRangeFromDB(const CLID& clid, const std::string& key, + IOVRange& range, std::string &tag, + IOpaqueAddress*& ioa) const =0; + + /// Get IOVRange from db for a particular event + virtual StatusCode getRangeFromDB(const CLID& clid, const std::string& key, + const IOVTime& time, + IOVRange& range, std::string &tag, + IOpaqueAddress*& ioa) const=0; + + /// Set a particular IOVRange in db (and memory) + virtual StatusCode setRangeInDB(const CLID& clid, const std::string& key, + const IOVRange& range, + const std::string &tag) = 0; + //@} + + + /// pre-load transient Addresses + virtual StatusCode preLoadTAD( const SG::TransientAddress *, + const std::string& storeName="StoreGateSvc" ) = 0; + + // supply a list of TADs whose data will be preloaded via a 'partial preload' flag + virtual StatusCode preLoadDataTAD( const SG::TransientAddress *, + const std::string& storeName="StoreGateSvc" ) = 0; + + /// get the names of the tools that have been triggered + virtual StatusCode getTriggeredTools(const std::string& key, + std::set<std::string>& tools, + const std::string& storeName="StoreGateSvc") = 0; + + /// reset all proxies known to IOVSvc + virtual void resetAllProxies() = 0; + + virtual void ignoreProxy(const CLID& clid, const std::string& key, + const std::string& storeName="StoreGateSvc") = 0; + + virtual StatusCode createCondObj(CondContBase*, const DataObjID&, + const EventIDBase&) = 0; + +}; + +inline +const InterfaceID& +IIOVSvc::interfaceID() { + static const InterfaceID IID("IIOVSvc", 1, 0); + return IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IInputRename.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IInputRename.h new file mode 100644 index 00000000..ec878efd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IInputRename.h @@ -0,0 +1,61 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/IInputRename.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2016 + * @brief Interface to retrieve input rename map. + */ + + +#ifndef ATHENAKERNEL_IINPUTRENAME_H +#define ATHENAKERNEL_IINPUTRENAME_H + + +#include "AthenaKernel/sgkey_t.h" +#include "AthenaKernel/RCUObject.h" +#include "GaudiKernel/IInterface.h" +#include <unordered_map> + + +namespace Athena { + + +/** + * @brief Interface to retrieve input rename map. + * + * The address remapping service may be configured to rename objects on input. + * When this is done, the keys stored in ElementLink/DataLink also need to + * be adjusted. This interface allows fetching a map that gives the + * needed transformation of SG keys. The returned object is + * synchronized via RCU. + */ +class IInputRename + : virtual public IInterface +{ +public: + /// Type of the input rename map: sgkey_t -> sgkey_t. + typedef std::unordered_map<SG::sgkey_t, SG::sgkey_t> InputRenameMap_t; + typedef RCUObject<InputRenameMap_t> InputRenameRCU_t; + + DeclareInterfaceID (IInputRename,1,0); + + + /** + * @brief Retrieve a pointer to the input rename map. + * + * May return null if no renaming is to be done. + */ + virtual const InputRenameRCU_t* inputRenameMap() const = 0; +}; + + +} // namespace Athena + + +#endif // not ATHENAKERNEL_IINPUTRENAME_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponent.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponent.h new file mode 100644 index 00000000..b688d584 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponent.h @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#warning IIoComponent has moved to GaudiKernel. + +///////////////////////// -*- C++ -*- ///////////////////////////// +// IIoComponent.h +// Header file for class IIoComponent +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_IIOCOMPONENT_H +#define ATHENAKERNEL_IIOCOMPONENT_H 1 + +// This interface has moved to GaudiKernel + +#include "GaudiKernel/IIoComponent.h" + +#endif //> !ATHENAKERNEL_IIOCOMPONENT_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponentMgr.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponentMgr.h new file mode 100644 index 00000000..0e158c58 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IIoComponentMgr.h @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#warning IIoComponentMgr has moved to GaudiKernel + +///////////////////////// -*- C++ -*- ///////////////////////////// +// IIoComponentMgr.h +// Header file for class IIoComponentMgr +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_IIOCOMPONENTMGR_H +#define ATHENAKERNEL_IIOCOMPONENTMGR_H 1 + +// This interface has moved to GaudiKernel + +#include "GaudiKernel/IIoComponentMgr.h" + +#endif //> !ATHENAKERNEL_IIOCOMPONENTMGR_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IItemListSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IItemListSvc.h new file mode 100644 index 00000000..670bb68b --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IItemListSvc.h @@ -0,0 +1,79 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IItemListSvc.h +// Header file for class IItemListSvc +// Author: S.Binet<binet@cern.ch> +// B.Radics<radbal@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_IITEMLISTSVC_H +#define ATHENAKERNEL_IITEMLISTSVC_H 1 + +/** + * @class IItemListSvc + * @brief This class defines a protocol to register boolean decisions and + * @brief and retrieve them and their combined result + */ + +// STL includes +#include <vector> +#include <string> +#include <map> + +// fwd declares +class INamedInterface; + + +class IItemListSvc + : virtual public ::INamedInterface +{ + +public: + + virtual ~IItemListSvc(); + + /////////////////////////////////////////////////////////////////// + // Public interface methods + // non-const + // + // add a stream-item pair to the service listing + virtual StatusCode addStreamItem(std::string stream, std::string itemname) = 0; + // remove Item + virtual StatusCode removeStreamItem(std::string stream, std::string itemname) = 0; + // + // const + // + // check if a stream-item is registered + //virtual bool containsItem(const std::string itemname) const = 0; + virtual bool containsItem(const std::string itemname, const std::string stream="ANY") const = 0; + // check how many streams contain an item + //virtual long countItemInstances(const std::string itemname) const = 0; + // get the streams for a given item + virtual std::vector<std::string> getStreamsForItem(const std::string itemname) const = 0; + // get the items for a given stream + virtual std::vector<std::string> getItemsForStream(const std::string stream) const = 0; + +public: + + static const InterfaceID& interfaceID(); + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline +const InterfaceID& +IItemListSvc::interfaceID() +{ + static const InterfaceID IID_IItemListSvc("IItemListSvc", 1, 0); + return IID_IItemListSvc; +} + + +#endif //> !ATHENAKERNEL_IITEMLISTSVC_H + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IJobIDSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IJobIDSvc.h new file mode 100644 index 00000000..48dd804a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IJobIDSvc.h @@ -0,0 +1,49 @@ +// dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IJOBIDSVC_H +#define ATHENAKERNEL_IJOBIDSVC_H + +#include "GaudiKernel/IService.h" +#include "GaudiKernel/StatusCode.h" + +#include <string> +#include "uuid/uuid.h" + +namespace Athena { +class PackageInfo; +} + +/** @class IJobIDSvc + * @brief interface to JobIDSvc + * @author Yushu Yao <yyao@lbl.gov> - ATLAS Collaboration + *$Id: IJobIDSvc.h,v 1.3 2009-04-10 11:52:37 binet Exp $ + */ + +typedef uuid_t JobID_t; +typedef unsigned char* PJobID_t; + +class IJobIDSvc : virtual public IService { +public: + + virtual ~IJobIDSvc(); + + /// Get current JobID + virtual PJobID_t getJobID() const = 0; + virtual std::string toString() const = 0; + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); +}; + + +inline +const InterfaceID& IJobIDSvc::interfaceID() { + static const InterfaceID IID("IJobIDSvc", 1, 0); + return IID; +} + +#endif // ATHENAKERNEL_IJOBIDSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ILockable.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ILockable.h new file mode 100644 index 00000000..07ce6a01 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ILockable.h @@ -0,0 +1,50 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/ILockable.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Interface to allow an object to lock itself when made const in SG. + */ + + +#ifndef ATHENAKERNEL_ILOCKABLE_H +#define ATHENAKERNEL_ILOCKABLE_H + + +/** + * @brief Interface to allow an object to lock itself when made const in SG. + * + * An object recorded in StoreGate can be `locked' by a call to + * @c StoreGateSvc::setConst(). Normally, this just sets a flag in the + * @c DataProxy, which tells StoreGate not to allow non-const retrieves. + * However, sometimes the object itself should know about this; for example, + * when a container with an auxiliary store is locked. If an object + * in StoreGate derives from @c ILockable, then a setConst() operation + * will call @c lock() on the object. + */ +class ILockable +{ +public: + /// Destructor. + virtual ~ILockable() {} + + + /** + * @brief Lock this object. + * + * When an object in StoreGate is locked via @c StoreGateSvc::setConst, + * StoreGate will call this method on the object, provided the object + * derives from @c ILockable. + */ + virtual void lock() = 0; +}; + + + +#endif // not ATHENAKERNEL_ILOCKABLE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ILoggedMessageSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ILoggedMessageSvc.h new file mode 100644 index 00000000..850dec30 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ILoggedMessageSvc.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ILOGGEDMESSAGESVC_H +#define ATHENAKERNEL_ILOGGEDMESSAGESVC_H 1 + +// Include files +#include "GaudiKernel/IMessageSvc.h" +#include <string> +#include <vector> +#include <functional> + + +// Declaration of the interface ID ( interface id, major version, minor version) +static const InterfaceID IID_ILoggedMessageSvc(31, 1 , 1); + + +/** @class ILoggedMessageSvc ILoggedMessageSvc.h AthenaKernel/ILoggedMessageSvc.h + + Extends IMessageSvc to get logged messages + + @author Charles Leggett +*/ +class ILoggedMessageSvc : virtual public IMessageSvc { +public: + + /// Retrieve interface ID + static const InterfaceID& interfaceID() { return IID_ILoggedMessageSvc; } + + struct LoggedMessage { + int level; + std::string source; + std::string message; + + LoggedMessage(int l, const std::string& s, const std::string& m): + level(l),source(s),message(m){}; + }; + + + virtual const std::vector<std::pair<std::string, std::string> >& getMessages( MSG::Level ) const = 0; + virtual const std::vector< LoggedMessage >& getKeyMessages() const = 0; + + virtual ~ILoggedMessageSvc(); + + +}; + +#endif // ATHENAKERNEL_ILOGGEDMESSAGESVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IMemoryMonitorSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IMemoryMonitorSvc.h new file mode 100644 index 00000000..1a7bce40 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IMemoryMonitorSvc.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IMEMORYMONITORSVC_H +#define ATHENAKERNEL_IMEMORYMONITORSVC_H 1 + +/////////////////////////////////////////////////////////////////////////// +// +// IMemoryMonitorSvc.h +// +// Abstract interface for +// +// +// +/////////////////////////////////////////////////////////////////////////// + + +#include "GaudiKernel/IService.h" + +#include <string> +/** + * @class IMemoryMonitorSvc + * @brief Abstract interface for MemoryMonitorSvc. FIXME + * @author Charles Leggett + */ +class IMemoryMonitorSvc : virtual public IService +{ + + public: + + static const InterfaceID& interfaceID(); + virtual void addItem( const std::string& type, size_t size ) = 0; + +}; + +inline const InterfaceID& IMemoryMonitorSvc::interfaceID() { + static const InterfaceID m_IID("IMemoryMonitorSvc", 1, 0); + return m_IID; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/INextPassFilter.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/INextPassFilter.h new file mode 100644 index 00000000..cdeffc3e --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/INextPassFilter.h @@ -0,0 +1,22 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_INEXTPASSFILTER_H +# define ATHENAKERNEL_INEXTPASSFILTER_H +//<<<<<< CLASS DECLARATIONS >>>>>> +/** @class INextPassFilter + * @brief interface to a tool (typically) that decides whether + * the event loop mgr (typically) need to do another pass over the evts + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + *$Id: INextPassFilter.h,v 1.1 2005-06-10 21:31:23 calaf Exp $ + */ + +class INextPassFilter { +public: + /// decide whether we need another iteration + virtual bool doNextPass() = 0; + virtual ~INextPassFilter() {} +}; + +#endif // ATHENAKERNEL_INEXTPASSFILTER_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVEntryT.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVEntryT.h new file mode 100644 index 00000000..37d9548b --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVEntryT.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IOVENTRYT_H +#define ATHENAKERNEL_IOVENTRYT_H + +/***************************************************************************** + * + * IOVEntryT.h + * IOVSvc + * + * Author: Charles Leggett + * + * Validity range object that manages start and stop times, holding link + * to templated object. + * + *****************************************************************************/ + +#include "GaudiKernel/EventIDRange.h" +#include <set> + +template <typename T> + +class IOVEntryT { +public: + + // Ordered by increasing start times + class IOVEntryTStartCritereon { + public: + bool operator() ( const IOVEntryT<T> &p1, const IOVEntryT<T> &p2 ) const { + return p1.range().start() > p2.range().start(); + } + bool operator() ( const IOVEntryT<T> *p1, const IOVEntryT<T> *p2 ) const { + return p1->range().start() > p2->range().start(); + } + }; + + // Order by decreasing stop times + class IOVEntryTStopCritereon { + public: + bool operator() ( const IOVEntryT<T> &p1, const IOVEntryT<T> &p2 ) const { + return p1.range().stop() < p2.range().stop(); + } + bool operator() ( const IOVEntryT<T> *p1, const IOVEntryT<T> *p2 ) const { + return p1->range().stop() < p2->range().stop(); + } + }; + + IOVEntryT(){}; + IOVEntryT( T *obj, const EventIDRange& range): + m_objPtr(obj), m_range(range){} + + ~IOVEntryT() {} + + EventIDRange range() const { return m_range; } + void setRange( const EventIDRange& range) { m_range=range; } + + T* objPtr() const { return m_objPtr; } + void setPtr( T* ptr ) { m_objPtr = ptr; } + + friend std::ostream& operator<< (std::ostream& os, const IOVEntryT<T>& rhs) { + os << rhs.range() << " " << rhs.m_objPtr; + return os; + } + +private: + T* m_objPtr {}; + EventIDRange m_range {}; + +}; + +template <typename T> +class IOVEntryComp { +public: + bool operator() ( const IOVEntryT<T> &p1, const IOVEntryT<T> &p2 ) const { + return p1.range().start() > p2.range().start(); + } +}; + +// // Order by obj pointer +// class IOVEntryTProxyCritereon { +// public: +// bool operator() ( const IOVEntryT &p1, const IOVEntryT &p2) const { +// return p1.proxy() < p2.proxy(); +// } +// bool operator() ( const IOVEntryT *p1, const IOVEntryT *p2) const { +// return p1->proxy() < p2->proxy(); +// } +// }; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVRange.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVRange.h new file mode 100644 index 00000000..142f5bd9 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVRange.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IOVRANGE_H +#define ATHENAKERNEL_IOVRANGE_H + +/** + * + * @file IOVRange.h + * @brief Validity Range object. Holds two IOVTime instances (start and stop) + * + * @author Charles Leggett + * $Id: IOVRange.h,v 1.4 2008-10-31 22:43:07 leggett Exp $ + * + * + *****************************************************************************/ + +#ifndef ATHENAKERNEL_IOVTIME_H + #include "AthenaKernel/IOVTime.h" +#endif +#ifndef _CPP_IOSTREAM + #include <iostream> +#endif +#ifndef _CPP_STRING + #include <string> +#endif +#ifndef _CPP_SSTREAM + #include <sstream> +#endif + +class MsgStream; +class EventIDRange; + +/** + * @class IOVRange + * @brief Validity Range object. Holds two IOVTimes (start and stop) + */ +class IOVRange { +public: + IOVRange(): m_start(0),m_stop(0) {}; + IOVRange( const IOVTime& start, const IOVTime& stop ); + IOVRange( const EventIDRange& eir); + IOVRange( const IOVRange& r ):m_start(r.m_start),m_stop(r.m_stop) {}; + IOVRange& operator= (const IOVRange& r); + + IOVTime start() const { return m_start; } + IOVTime stop() const { return m_stop; } + + bool isInRange(const IOVTime& t) const { + return ( t>=m_start && t<m_stop ); + } + + friend bool operator==(const IOVRange& lhs, const IOVRange& rhs); + friend bool operator!=(const IOVRange& lhs, const IOVRange& rhs); + + friend std::ostream& operator<<(std::ostream& os, const IOVRange& rhs); + friend MsgStream& operator<<(MsgStream& os, const IOVRange& rhs); + + operator std::string() const; + +private: + + IOVTime m_start; + IOVTime m_stop; + +}; + + +inline bool operator==(const IOVRange& lhs, const IOVRange& rhs) { + return lhs.m_start==rhs.m_start && + lhs.m_stop==rhs.m_stop ; +} + +inline bool operator!=(const IOVRange& lhs, const IOVRange& rhs) { + return ! (lhs == rhs); +} + + +inline IOVRange::operator std::string () const { + std::ostringstream os; + os << "{" << m_start << " - " << m_stop << "}"; + return os.str(); +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVSvcDefs.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVSvcDefs.h new file mode 100644 index 00000000..bd62831f --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVSvcDefs.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IOVSVCDEFS_H +#define ATHENAKERNEL_IOVSVCDEFS_H +/** + * @file IOVSvcDefs.h + * @author Charles Leggett + * $Id: IOVSvcDefs.h,v 1.3 2007-06-14 01:57:23 calaf Exp $ + * @brief defines and typedefs for IOVSvc + */ + +#ifndef _CPP_LIST + #include <list> +#endif +#ifndef _CPP_STRING + #include <string> +#endif + +/** + * @brief short hand for IOVSvc call back argument list, to be used + * when no access to formal arguments is needed, e.g. in method declaration (.h) + * @code + * StatusCode callBack( IOVSVC_CALLBACK_ARGS ); + * @endcode + */ +#define IOVSVC_CALLBACK_ARGS int&,std::list<std::string>& + +/** + * @brief short hand for IOVSvc call back argument list, to be used + * when when only the keys argument is needed. + * @code + * StatusCode CoolHistExample::callBack( IOVSVC_CALLBACK_ARGS_K(keys) ) { + * @endcode + */ +#define IOVSVC_CALLBACK_ARGS_K(K) int&,std::list<std::string>& K + +/** + * @brief short hand for IOVSvc call back argument list, to be used + * when access to formal arguments is needed, e.g. in method definition (.cxx) + * @code + * StatusCode CoolHistExample::callBack( IOVSVC_CALLBACK_ARGS_P(I,keys) ) { + * @endcode + */ +#define IOVSVC_CALLBACK_ARGS_P(I,K) int& I,std::list<std::string>& K + + +#include "boost/function.hpp" + + +#ifndef KERNEL_STATUSCODES_H + #include "GaudiKernel/StatusCode.h" +#endif + +/* This can also be done as: +typedef boost::function2< StatusCode, IOVSVC_CALLBACK_ARGS > IOVSvcCallBackFcn; +*/ + +/// the type of an IOVSvc call back: it wraps both the method and the object +/// the method is called on +typedef boost::function< StatusCode (IOVSVC_CALLBACK_ARGS) > IOVSvcCallBackFcn; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVTime.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVTime.h new file mode 100644 index 00000000..b0595c6f --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IOVTime.h @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IOVTIME_H +#define ATHENAKERNEL_IOVTIME_H + +/** + * + * @file IOVTime.h + * @brief Basic time unit for IOVSvc. + * Hold time as a combination of run and event numbers + * + * @author Charles Leggett + * $Id: IOVTime.h,v 1.8 2007-06-14 01:57:23 calaf Exp $ + * + * + *****************************************************************************/ + +#ifndef _CPP_IOSTREAM + #include <iostream> +#endif +#ifndef _CPP_SSTREAM + #include <sstream> +#endif +#ifndef _CPP_STRING + #include <string> +#endif +#include <stdint.h> + +class MsgStream; +class EventIDBase; + +/** + * @class IOVTime + * @brief Basic time unit for IOVSvc. + * Hold time as a combination of run and event numbers + */ +class IOVTime { + +private: + enum IOVTime_type { + UNDEF = 0, + TIMESTAMP, + RUN_EVT, + BOTH + }; + +public: + static const uint32_t MINRUN; + static const uint32_t MAXRUN; + + static const uint32_t MINEVENT; + static const uint32_t MAXEVENT; + + static const uint64_t MAXRETIME; + static const uint64_t UNDEFRETIME; + + static const uint64_t MINTIMESTAMP; + static const uint64_t MAXTIMESTAMP; + static const uint64_t UNDEFTIMESTAMP; + +public: + /** + * @class SortByTimeStamp + * @brief Predicate. Used to sort by time stamp + */ + class SortByTimeStamp { + public: + bool operator() ( const IOVTime& t1, const IOVTime& t2 ) const { + return t1.timestamp() > t2.timestamp(); + } + bool operator() ( const IOVTime* t1, const IOVTime* t2 ) const { + return t1->timestamp() > t2->timestamp(); + } + }; + + /** + * @class SortByRunEvent + * @brief Predicate. Used to sort by run and event number + */ + class SortByRunEvent { + public: + bool operator() ( const IOVTime& t1, const IOVTime& t2 ) const { + return t1.re_time() > t2.re_time(); + } + bool operator() ( const IOVTime* t1, const IOVTime* t2 ) const { + return t1->re_time() > t2->re_time(); + } + }; + +public: + IOVTime(): m_status(IOVTime::UNDEF), m_time(UNDEFRETIME), + m_timestamp(UNDEFTIMESTAMP){}; + IOVTime( const uint64_t& timestamp ): m_status(IOVTime::TIMESTAMP), + m_time(IOVTime::UNDEFRETIME), m_timestamp(timestamp){}; + IOVTime( const uint32_t& run, const uint32_t& event ); + IOVTime( const uint32_t& run, const uint32_t& event, + const uint64_t& timestamp ); + IOVTime( const EventIDBase& eid); + + void setTimestamp( const uint64_t& timestamp ); + void setRETime( const uint64_t& time ); + void setRunEvent( const uint32_t& run, const uint32_t& event ); + void reset(); + + inline uint32_t run() const { return static_cast<uint32_t> (m_time>>32); } + inline uint32_t event() const { return static_cast<uint32_t> (m_time & 0xFFFFFFFF); } + inline uint64_t re_time() const { return m_time; } + inline uint64_t timestamp() const { return m_timestamp; } + + bool isValid() const; + inline bool isTimestamp() const { return (m_status == IOVTime::TIMESTAMP || + m_status== IOVTime::BOTH) ? 1 : 0; } + inline bool isRunEvent() const { return (m_status == IOVTime::RUN_EVT || + m_status == IOVTime::BOTH) ? 1 : 0; } + inline bool isBoth() const { return (m_status == IOVTime::BOTH) ? 1 : 0; } + + operator std::string() const; + + friend bool operator<(const IOVTime& lhs, const IOVTime& rhs); + friend bool operator>(const IOVTime& lhs, const IOVTime& rhs); + friend bool operator==(const IOVTime& lhs, const IOVTime& rhs); + friend bool operator!=(const IOVTime& lhs, const IOVTime& rhs); + friend bool operator>=(const IOVTime& lhs, const IOVTime& rhs); + friend bool operator<=(const IOVTime& lhs, const IOVTime& rhs); + + friend std::ostream& operator<<(std::ostream& os, const IOVTime& rhs); + friend MsgStream& operator<<(MsgStream& os, const IOVTime& rhs); + +private: + + IOVTime_type m_status; + uint64_t m_time; + uint64_t m_timestamp; +}; + +inline bool operator<(const IOVTime& lhs, const IOVTime& rhs) { + if (lhs.isTimestamp() && rhs.isTimestamp()) { + return lhs.m_timestamp < rhs.m_timestamp; + } else { + return lhs.m_time < rhs.m_time; + } +} +inline bool operator>(const IOVTime& lhs, const IOVTime& rhs) { + if (lhs.isTimestamp() && rhs.isTimestamp()) { + return lhs.m_timestamp > rhs.m_timestamp; + } else { + return lhs.m_time > rhs.m_time; + } +} +inline bool operator==(const IOVTime& lhs, const IOVTime& rhs) { + if (lhs.isTimestamp() && rhs.isTimestamp()) { + return lhs.m_timestamp == rhs.m_timestamp; + } else { + return lhs.m_time == rhs.m_time; + } +} +inline bool operator!=(const IOVTime& lhs, const IOVTime& rhs) { + return !(lhs == rhs) ; +} +inline bool operator>=(const IOVTime& lhs, const IOVTime& rhs) { + return !( lhs < rhs ); +} +inline bool operator<=(const IOVTime& lhs, const IOVTime& rhs) { + return !( lhs > rhs ); +} + +// template < class STR > +// inline STR& operator << (STR& os, const IOVTime& rhs) { +// os << rhs.m_time << ": [" << (rhs.m_time>>32) << "," +// << ( rhs.m_time & 0xFFFFFFFF ) << "]"; +// return os; +// } + +#endif + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IPageAccessControlSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IPageAccessControlSvc.h new file mode 100644 index 00000000..095edf31 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IPageAccessControlSvc.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IPAGEACCESSCONTROLSVC_H +#define ATHENAKERNEL_IPAGEACCESSCONTROLSVC_H + +/** + * @file IPageAccessControlSvc.h + * @brief Interface to a service that monitors memory page accesses + * @author Paolo Calafiura + * + * $Id: IPageAccessControlSvc.h,v 1.1 2009-03-04 23:38:52 calaf Exp $ + */ + +#ifndef GAUDIKERNEL_IINTERFACE_H + #include "GaudiKernel/IInterface.h" +#endif + +/** + * @class IPageAccessControlSvc + * @brief Interface to a service that monitors memory page accesses + * @author Paolo Calafiura + * + * This interface allows to start and stop the monitoring and to print a report + */ + +class PageAccessControl; + +class IPageAccessControlSvc: virtual public IInterface { +public: + /// Retrieve interface ID + static const InterfaceID& interfaceID(); + + /// Virtualize D'tor + virtual ~IPageAccessControlSvc() {} + + /// In baseline implementation, protect pages and install a SEGV handler + /// that counts the number of accesses to a protected address. + virtual bool startMonitoring() = 0; + virtual bool stopMonitoring() = 0; + /// has this pointer been accessed (read/written) + virtual bool accessed(const void* address) const =0; + /// In baseline implementation, controlled via PageAccessControlSvc.OutputLevel + virtual void report() const = 0; + + ///control access to the page containing address + virtual bool controlPage(const void* address) = 0; + + ///FIXME Access to the underlying @class PageAccessControl, used to + ///protect/restore page access + //hopefully not necessary virtual PageAccessControl* pac() = 0; +}; + + +inline const InterfaceID& IPageAccessControlSvc::interfaceID() +{ + static const InterfaceID IID_IPageAccessControlSvc("IPageAccessControlSvc", 1, 0); + return IID_IPageAccessControlSvc; +} + +#endif // ATHENAKERNEL_IPAGEACCESSCONTROLSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyDict.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyDict.h new file mode 100644 index 00000000..432bbda4 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyDict.h @@ -0,0 +1,169 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IPROXYDICT_H +# define ATHENAKERNEL_IPROXYDICT_H + +// INCLUDES +#include "AthenaKernel/sgkey_t.h" +#include "AthenaKernel/IStringPool.h" +#include "AthenaKernel/DataObjectSharedPtr.h" +#include "GaudiKernel/INamedInterface.h" +#include "GaudiKernel/ClassID.h" +#include <string> +#include <vector> +#include <memory> + +// DECLARATIONS +namespace SG { + class DataProxy; +} +class DataObject; +class IResetable; + + +/** + * @brief A proxy dictionary. + * + * This is the internal interface used by StoreGateSvc and similar. + * It provides interfaces for taking a set of @c DataProxy objects + * and looking them up by either CLID+key or by a pointer to the + * transient objects. + * + * Objects can be identified by either a CLID+key pair or by a hash of this + * data. This interface also provides methods for converting between + * the two representations. + * + * + * @author Paolo Calafiura - ATLAS + * $Id: IProxyDict.h,v 1.5 2007-12-11 02:56:22 binet Exp $ + */ +class IProxyDict : virtual public INamedInterface, + virtual public IStringPool +{ +public: + DeclareInterfaceID (IProxyDict, 2, 0); + virtual ~IProxyDict() override {} + + /** + * @brief Get proxy given a hashed key+clid. + * @param sgkey Hashed key to look up. + * + * Find an exact match; no handling of aliases, etc. + * Returns 0 to flag failure. + */ + virtual SG::DataProxy* proxy_exact (SG::sgkey_t sgkey) const = 0; + + + /** + * @brief Get proxy with given id and key. + * @param id The @c CLID of the desired object. + * @param key The key of the desired object. + * + * If the key is a null string, then it is a @em default key. + * Finding a proxy via the default key should succeed only if there + * is exactly one object with the given @c CLID in the store. + * Finding a proxy via a default key is considered deprecated + * for the case of the event store. + * + * Returns 0 to flag failure + */ + virtual SG::DataProxy* proxy(const CLID& id, + const std::string& key) const = 0; + + + /** + * @brief Get a proxy referencing a given transient object. + * @param pTransient The object to find. + * + * Returns 0 to flag failure + */ + virtual SG::DataProxy* proxy(const void* const pTransient) const=0; + + + /** + * @brief Return the list of all current proxies in store. + */ + virtual std::vector<const SG::DataProxy*> proxies() const = 0; + + + /** + * @brief Add a new proxy to the store. + * @param id CLID as which the proxy should be added. + * @param proxy The proxy to add. + * + * Simple addition of a proxy to the store. The key is taken as the + * primary key of the proxy. Does not handle things + * like overwrite, history, symlinks, etc. Should return failure + * if there is already an entry for this clid/key. + */ + virtual StatusCode addToStore (CLID id, SG::DataProxy* proxy) = 0; + + + /** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ + virtual SG::DataProxy* recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) = 0; + + + /** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ + virtual StatusCode updatedObject (CLID id, const std::string& key) = 0; + + + /** + * @brief Tell the store that a handle has been bound to a proxy. + * @param handle The handle that was bound. + * The default implementation does nothing. + */ + virtual void boundHandle (IResetable* handle); + + + /** + * @brief Tell the store that a handle has been unbound from a proxy. + * @param handle The handle that was unbound. + * The default implementation does nothing. + */ + virtual void unboundHandle (IResetable* handle); + + + /** + * @brief Test to see if the target of an ElementLink has moved. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + * + * The default implementation here always returns false. + */ + virtual bool tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out); +}; + + +#endif // ATHENAKERNEL_IPROXYDICT_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyProviderSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyProviderSvc.h new file mode 100644 index 00000000..86e4d337 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyProviderSvc.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @class IProxyProviderSvc.h + * @brief add on demand proxies to the address registry (SG) + * + * @author pcalafiura@lbl.gov - ATLAS Collaboration + ***************************************************************************/ + +// $Id: IProxyProviderSvc.h,v 1.9 2007-06-23 01:12:06 calaf Exp $ + +#ifndef ATHENAKERNEL_IPROXYPROVIDERSVC_H +# define ATHENAKERNEL_IPROXYPROVIDERSVC_H + +#include <string> +#include <list> +#include "AthenaKernel/StoreID.h" +#include "GaudiKernel/IService.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/ClassID.h" + +class IAddressProvider; +class IProxyRegistry; //this is the store + +namespace SG { + class DataProxy; + class TransientAddress; +} + +class IOpaqueAddress; + +class IProxyProviderSvc : virtual public IService { +public: + /// add proxies to the store before Begin Event: + virtual StatusCode preLoadProxies(IProxyRegistry& dataStore) = 0; + + ///add new proxies to store every Event: + virtual StatusCode loadProxies(IProxyRegistry& dataStore) = 0; + + ///get the default proxy for a given CLID/Key" + virtual SG::DataProxy* retrieveProxy(const CLID& id, + const std::string& key, + IProxyRegistry& dataStore) = 0; + + /// Update a transient Address: + virtual StatusCode updateAddress(StoreID::type sID, + SG::TransientAddress* pTAd) = 0; + + ///IAddressProvider manager functionality + ///add a provider to the set of known ones. PROVIDER IS OWNED BY THE CLIENT + virtual void addProvider(IAddressProvider* aProvider) = 0; + + static const InterfaceID& interfaceID(); + virtual ~IProxyProviderSvc() {} +}; + +inline +const InterfaceID& +IProxyProviderSvc::interfaceID() { + static InterfaceID ID("IProxyProviderSvc", 0 , 0); + return ID; +} + +#endif // ATHENAKERNEL_IPROXYPROVIDERSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyRegistry.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyRegistry.h new file mode 100644 index 00000000..82ddf911 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IProxyRegistry.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @class IProxyRegistry + * @brief a proxy registry (a read/write dictionary) + * + * @author Paolo Calafiura - ATLAS + * $Id: IProxyRegistry.h,v 1.11 2006-08-29 18:17:09 srini Exp $ + ***************************************************************************/ + +#ifndef ATHENAKERNEL_IPROXYREGISTRY_H +# define ATHENAKERNEL_IPROXYREGISTRY_H + +//<<<<<< INCLUDES >>>>>> +#ifndef KERNEL_STATUSCODES_H + #include "GaudiKernel/StatusCode.h" +#endif +#ifndef GAUDIKERNEL_CLASSID_H + #include "GaudiKernel/ClassID.h" +#endif +#ifndef ATHENAKERNEL_STOREID_H +# include "AthenaKernel/StoreID.h" +#endif +#ifndef _CPP_STRING + #include <string> +#endif + +//<<<<<< CLASS FORWARD DECLARATIONS >>>>>> +namespace SG { + class DataProxy; + class TransientAddress; +} + +class IProxyRegistry { +public: + /// add proxy to store. + virtual StatusCode addToStore(const CLID& id, SG::DataProxy* proxy) = 0; + + virtual StatusCode addAlias(const std::string& key, SG::DataProxy* proxy) = 0; + + virtual StoreID::type storeID() const = 0; //FIXME this should not be here + + /// locate a proxy for a given TransientAddress + virtual SG::DataProxy* proxy(const SG::TransientAddress* tAD) const = 0; + + /// get proxy with given id. Returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key) const=0; + + /// get proxy with given id. Returns 0 to flag failure + /// the key must match exactly (no wildcarding for the default key) + virtual SG::DataProxy* proxy_exact(const CLID& id, + const std::string& key) const = 0; + + virtual ~IProxyRegistry() {} +}; +#endif // ATHENAKERNEL_IPROXYREGISTRY_H + + + + + + + + + + diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IRCUSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IRCUSvc.h new file mode 100644 index 00000000..96290c30 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IRCUSvc.h @@ -0,0 +1,87 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/IRCUSvc.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + */ + + +#ifndef ATHENAKERNEL_IRCUSVC_H +#define ATHENAKERNEL_IRCUSVC_H + + +#include "AthenaKernel/RCUObject.h" +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/IInterface.h" +#include <memory> + + +namespace Athena { + + +/** + * @brief Interface for RCU service. + * + * See RCUObject.h for details of the RCU facility. + * + * The RCU service allows creating new RCU objects and registering + * them with the service, and also allows removing them from the service. + * The service will declare all registered RCU objects as quiescent + * at the end of an event. + */ +class IRCUSvc + : virtual public IInterface +{ +public: + DeclareInterfaceID (IRCUSvc,1,0); + + + /** + * @brief Make a new RCU object. + * @param args... Arguments to pass to the @c T constructor. + * + * The object will be registered with the service. + */ + template <class T, typename... Args> + std::unique_ptr<RCUObject<T> > newrcu (Args&&... args) + { + auto obj = CxxUtils::make_unique<RCUObject<T> > (*this, + std::forward<Args>(args)...); + add (obj.get()); + return obj; + } + + + /** + * @brief Remove an object from the service. + * @param obj The object to remove. + */ + virtual StatusCode remove (IRCUObject* obj) = 0; + + + /** + * @brief Return the number of event slots. + */ + virtual size_t getNumSlots() const = 0; + + +private: + /** + * @brief Remove an object from the service. + * @param obj The object to add. + */ + virtual void add (IRCUObject* obj) = 0; +}; + + +} // namespace Athena + + +#endif // not ATHENAKERNEL_IRCUSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IRegistrationStreamTool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IRegistrationStreamTool.h new file mode 100644 index 00000000..1e8577c2 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IRegistrationStreamTool.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IREGISTRATIONSTREAMTOOL_H +#define ATHENAKERNEL_IREGISTRATIONSTREAMTOOL_H 1 + +/** + * @file IRegistrationStreamTool.h + * + * @brief AlgTool which takes references provided by RegStream + * finds the appropriate CORAL object in storegate and stores + * them in a POOL collection. + * + * @author RD Schaffer <R.D.Schaffer@cern.ch> + * @author Jack Cranshaw <Jack.Cranshaw@cern.ch> + * + * $Id: IRegistrationStreamTool.h,v 1.4 2009-04-28 18:57:40 cranshaw Exp $ + * + */ + + +#include "GaudiKernel/IAlgTool.h" + +#include <map> + + + +/** + * @class IRegistrationStreamTool + * + * @brief AlgTool which takes references provided by RegStream + * finds the appropriate CORAL object in storegate and stores + * them in a POOL collection. + * + */ + +class IRegistrationStreamTool : virtual public IAlgTool { +public: + /// Working entry point + virtual StatusCode fill(std::vector<std::pair<std::string, std::string> >& refs, std::string key) = 0; + + virtual StatusCode commit() = 0; + + virtual const CLID& listID() = 0; + + virtual void setCollMetadataKeys(const std::vector<std::string>& keys) = 0; + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); +}; + + +inline const InterfaceID& IRegistrationStreamTool::interfaceID() { + static const InterfaceID IID("IRegistrationStreamTool", 1, 0); + return IID; +} + +#endif // ATHENAKERNEL_IREGISTRATIONSTREAMTOOL_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IResetable.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IResetable.h new file mode 100644 index 00000000..bac8b882 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IResetable.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IRESETABLE_H +#define ATHENAKERNEL_IRESETABLE_H + +#include <string> + +/** @class IResetable + * @brief a resetable object (e.g. a SG DataHandle) + * @author ATLAS Collaboration + * $Id: IResetable.h,v 1.2 2007-03-13 17:14:11 ssnyder Exp $ + **/ +class IResetable { +public: + virtual ~IResetable() {} + + /// Clear cached data from this object. + /// If HARD is true, then also clear any data that depends on the identity + /// of the current event store. HARD will be set if the handle could + /// potentially be looking at a different store the next time + /// it is used. (This happens in Hive.) + /// + /// For example, a VarHandle caches both a pointer to the referenced + /// object and a pointer to the DataProxy used to reference it. + /// If HARD is false, then only the object pointer need be cleared; but + /// if it is true, then the DataProxy pointer should be cleared as well + /// (and the object deregistered from the store). + virtual void reset (bool hard) = 0; + + // Backwards compatibility. + // FIXME: Needed by TrigDecisionTool. + // Look into getting rid of this once TDT is more up-to-date. + virtual void reset() { reset(false); } + + ///optional special action on final reset call (e.g. in caller destructor) + virtual void finalReset() {}; + virtual bool isSet() const = 0; + virtual const std::string& key() const = 0; +}; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ISlimmingHdlr.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ISlimmingHdlr.h new file mode 100644 index 00000000..74a5e0a7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ISlimmingHdlr.h @@ -0,0 +1,60 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ISLIMMINGHDLR_H +#define ATHENAKERNEL_ISLIMMINGHDLR_H 1 + +// STL includes +#include <typeinfo> + +// FrameWork includes +#include "GaudiKernel/INamedInterface.h" + +// Forward declaration + +namespace Athena { + +/** + * @class Athena::ISlimmingHdlr + * @brief This class defines a protocol to slim objects (removing parts of that + * object) + */ +class ISlimmingHdlr +{ +public: + /** @brief virtual destructor + */ + virtual ~ISlimmingHdlr(); + + /** @brief returns a pointer to the object being slimmed + */ + virtual void *object() =0; + + /** @brief returns the type-id of the object being slimmed + * (mostly for debugging purposes) + */ + virtual + const std::type_info& type_id() =0; + + /** @brief returns the component who requested the registration of that + * slimming handler + * (mostly for debugging purposes) + */ + virtual + const ::INamedInterface* requester() =0; + + /** @brief apply the slimming: remove parts of the object + */ + virtual void commit() =0; + + /** @brief restore object's state as before slimming was applied + */ + virtual void rollback() =0; +}; + +} //> namespace Athena + +#endif //> ATHENAKERNEL_ISLIMMINGHDLR_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IStringPool.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IStringPool.h new file mode 100644 index 00000000..2b89bcca --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IStringPool.h @@ -0,0 +1,90 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IStringPool.h,v 1.3 2008-09-03 17:19:10 ssnyder Exp $ +/** + * @file AthenaKernel/IStringPool.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2007 + * @brief Abstract interface for looking up strings/CLIDs in a pool. + */ + + +#ifndef ATHENAKERNEL_ISTRINGPOOL_H +#define ATHENAKERNEL_ISTRINGPOOL_H + + +#include "AthenaKernel/sgkey_t.h" +#include "GaudiKernel/ClassID.h" +#include <string> + + +/** + * @brief Abstract interface for looking up strings/CLIDs in a pool. + */ +class IStringPool +{ +public: + /// Destructor. + virtual ~IStringPool() {} + + /// Type of the keys. + typedef SG::sgkey_t sgkey_t; + + + /** + * @brief Find the key for a string/CLID pair. + * @param str The string to look up. + * @param clid The CLID associated with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ + virtual + sgkey_t stringToKey (const std::string& str, CLID clid) = 0; + + /** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key) const = 0; + + /** + * @brief Find the string and CLID corresponding to a given key. + * @param key The key to look up. + * @param clid[out] The found CLID. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key, + CLID& clid) const = 0; + + /** + * @brief Remember an additional mapping from key to string/CLID. + * @param key The key to enter. + * @param str The string to enter. + * @param clid The CLID associated with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + * Logs an error if @c key already corresponds to a different string. + */ + virtual + void registerKey (sgkey_t key, + const std::string& str, + CLID clid) = 0; +}; + + +#endif // not ATHENAKERNEL_ISTRINGPOOL_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvBase.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvBase.h new file mode 100644 index 00000000..56c50742 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvBase.h @@ -0,0 +1,92 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ITPCnvBase.h +// Header file for class ITPCnvBase +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_ITPCNVBASE_H +#define ATHENAKERNEL_ITPCNVBASE_H 1 + +#include "Gaudi/PluginService.h" +#include "GAUDI_VERSION.h" +#include <typeinfo> + +// Forward declaration +class MsgStream; + + +class ITPCnvBase +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: +#if GAUDI_VERSION > CALC_GAUDI_VERSION(25, 3) + typedef Gaudi::PluginService::Factory<ITPCnvBase*> Factory; +#else + typedef Gaudi::PluginService::Factory0<ITPCnvBase*> Factory; +#endif + /// Destructor: + virtual ~ITPCnvBase(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + // Methods for invoking conversions on objects given by generic + // pointers. + + /** Convert persistent object representation to transient + @param pers [IN] void* pointer to the persistent object + @param trans [OUT] void* pointer to the empty transient object + @param log [IN] output message stream + */ + virtual + void + persToTransUntyped(const void* pers, void* trans, MsgStream& msg) = 0; + + /** Convert transient object representation to persistent + @param trans [IN] void* pointer to the transient object + @param pers [OUT] void* pointer to the empty persistent object + @param log [IN] output message stream + */ + virtual + void + transToPersUntyped(const void* trans, void* pers, MsgStream& msg) = 0; + + /** return C++ type id of the transient class this converter is for + @return std::type_info& + */ + virtual + const std::type_info& transientTInfo() const = 0; + + /** return C++ type id of the persistent class this converter is for + @return std::type_info& + */ + virtual + const std::type_info& persistentTInfo() const = 0; + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +//std::ostream& operator<<( std::ostream& out, const ITPCnvBase& o ); + + + +#endif //> !ATHENAKERNEL_ITPCNVBASE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvSvc.h new file mode 100644 index 00000000..97270ef3 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITPCnvSvc.h @@ -0,0 +1,75 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ITPCnvSvc.h +// Header file for class ITPCnvSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef ATHENAKERNEL_ITPCNVSVC_H +#define ATHENAKERNEL_ITPCNVSVC_H 1 + +/** @class ITPCnvSvc + */ + + +#include "AthenaKernel/TPCnvFactory.h" +#include "GaudiKernel/IService.h" +#include "GaudiKernel/ClassID.h" +#include <string> + + +class ITPCnvBase; + + +class ITPCnvSvc + : virtual public ::IService +{ + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + DeclareInterfaceID(ITPCnvSvc,1,0); + + + /** Destructor: + */ + virtual ~ITPCnvSvc(); + + /** @brief load the T/P converter class named `cls` + * return NULL on failure. + * the converter is OWNED by the T/P converter service + */ + virtual + ITPCnvBase* + load_tpcnv(const std::string& cls) = 0; + + /** @brief return the T/P converter for a transient class (NULL if failure) + * `ITPCnvSvc` owns the `ITPCnvBase` pointer + */ + virtual + ITPCnvBase* + t2p_cnv(const std::string& transClassName, + Athena::TPCnvType::Value type = Athena::TPCnvType::Athena) = 0; + + /** @brief return the T/P converter for a transient class (NULL if failure) + * `ITPCnvSvc` owns the `ITPCnvBase` pointer + */ + virtual + ITPCnvBase* + t2p_cnv(const CLID& transClid, + Athena::TPCnvType::Value type = Athena::TPCnvType::Athena) = 0; + + /** @brief return the T/P converter for a persistent class (NULL if failure) + * `ITPCnvSvc` owns the `ITPCnvBase` pointer + */ + virtual + ITPCnvBase* + p2t_cnv(const std::string& persClassName, + Athena::TPCnvType::Value type = Athena::TPCnvType::Athena) = 0; + +}; + +#endif //> !ATHENAKERNEL_ITPCNVSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningHdlr.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningHdlr.h new file mode 100644 index 00000000..d14a030a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningHdlr.h @@ -0,0 +1,264 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ITHINNINGHDLR_H +#define ATHENAKERNEL_ITHINNINGHDLR_H 1 + +// STL includes +#include <algorithm> +#include <vector> +#include <list> +#include <utility> // for std::pair + +// boost includes +#ifndef BOOST_MPL_IF_HPP_INCLUDED + #include <boost/mpl/if.hpp> +#endif +#ifndef BOOST_TT_IS_BASE_OF_HPP_INCLUDED + #include <boost/type_traits/is_base_of.hpp> +#endif +#ifndef BOOST_TT_REMOVE_POINTER_HPP_INCLUDED + #include <boost/type_traits/remove_pointer.hpp> +#endif +#ifndef GAUDIKERNEL_DATAOBJECT_H + #include "GaudiKernel/DataObject.h" +#endif + +// FrameWork includes + +// Forward declaration +// class IdentifierHash; +// template <class T, class BASE> class DataVector; +// template <class T> class IdentifiableContainer; + +namespace Athena { + +/** + * @class Athena::IThinningHdlr + * @brief This class defines a protocol to pack and unpack thinned collections + */ +class IThinningHdlr +{ +public: + /** @brief virtual destructor + */ + virtual ~IThinningHdlr(); + + /** @brief remove an element from the proxied @c DataVector + */ + virtual void remove( const std::size_t idx ) = 0; + /** @brief pack the proxied collection + * This is needed in order to keep element link indices consistent + * and T/P converters unchanged. + */ + virtual void commit() = 0; + + /** @brief unpack the proxied @c DataVector ie: restore it as it was *before* + * any thinning took place + */ + virtual void rollback() = 0; + + /** @brief publish the type of underlying indexing (mapping or sequencing) + */ + virtual bool isMapping() const {return false;} +}; + +namespace detail { + /** @brief Predicate to spot non NULL pointers + */ + struct IsNonNullPtr + { + template <typename Element> + bool operator()( Element* f ) const + { return f != 0; } + }; +} + +/** + * @class DvThinningHdlr + * @brief Handle @c DataProxy holding @c DataVector. + * This class defines a (type-safe) protocol to pack and unpack + * thinned @c DataVector. + */ +template <typename Container> +class DvThinningHdlr : public ::Athena::IThinningHdlr +{ + typedef typename Container::PtrVector PtrVector; + /** Vector holding the pointers to the elements of @c DataVector, before + * any thinning took place + */ + const PtrVector m_backup; + PtrVector& m_container; + // +public: + DvThinningHdlr( const Container& c ) : + Athena::IThinningHdlr( ), + m_backup ( const_cast<Container&>(c).begin(), + const_cast<Container&>(c).end() ), + m_container( const_cast<PtrVector&>(const_cast<Container&>(c).stdcont()) ) + {} + + void remove( const std::size_t idx ) + { m_container[idx] = 0; } + + void commit() + { + typedef typename PtrVector::iterator Iter; + // move non NULL pointers at the begin of the vector, + // preserving relative order... + Iter itr = std::stable_partition( m_container.begin(), + m_container.end(), + Athena::detail::IsNonNullPtr() ); + // nicely truncate our container: removes the NULL elements + m_container.resize( std::distance( m_container.begin(), itr ) ); + } + + void rollback() + { + const std::size_t size = m_backup.size(); + m_container.resize( size ); + std::copy (m_backup.begin(), m_backup.end(), + m_container.begin()); + } +}; + +/** + * @class StdThinningHdlr + * @brief Handle @c DataProxy holding @c std::vector<T> + * This class defines a (type-safe) protocol to pack and unpack + * thinned @c DataVector. + */ +template <typename Container> +class StdThinningHdlr : public ::Athena::IThinningHdlr +{ + typedef Container Vector_t; + /** Vector holding the pointers to the elements of @c std::vector<T>, before + * any thinning took place + */ + const Vector_t m_backup; + Vector_t& m_container; + // +public: + StdThinningHdlr( const Container& c ) : + Athena::IThinningHdlr( ), + m_backup ( const_cast<Container&>(c).begin(), + const_cast<Container&>(c).end() ), + m_container( const_cast<Container&>(c) ) + {} + + void remove( const std::size_t idx ) + { m_container[idx] = 0; } + + void commit() + { + typedef typename Vector_t::iterator Iter; + // move non NULL pointers at the begin of the vector, + // preserving relative order... + Iter itr = std::stable_partition( m_container.begin(), + m_container.end(), + Athena::detail::IsNonNullPtr() ); + // nicely truncate our container: removes the NULL elements + m_container.resize( std::distance( m_container.begin(), itr ) ); + } + + void rollback() + { + const std::size_t size = m_backup.size(); + m_container.resize( size ); + std::copy (m_backup.begin(), m_backup.end(), + m_container.begin()); + } +}; + +/** + * @class IdcThinningHdlr + * @brief Handle @c DataProxy holding @c IdentifiableContainer + * This class defines a (type-safe) protocol to pack and unpack + * thinned @c IdentifiableContainer + */ +template <typename Container> +class IdcThinningHdlr : public ::Athena::IThinningHdlr +{ + typedef Container Idc_t; + typedef typename Idc_t::IDENTIFIABLE Identifiable_t; + typedef std::pair<std::size_t, Identifiable_t*> Backup_t; + typedef std::list<Backup_t> Backups_t; + + /** Vector holding the pointers to the elements of @c IdentifiableContainer, + * before any thinning took place + */ + Backups_t m_backup; + Idc_t &m_container; + // +public: + IdcThinningHdlr( const Container& c ) : + Athena::IThinningHdlr( ), + m_backup (), + m_container( const_cast<Idc_t&>(c) ) + {} + + void remove( const std::size_t idx ) + { + Identifiable_t *c = m_container.removeCollection (idx); + m_backup.push_back (std::make_pair(idx, c)); + } + + void commit() {/*no-op*/} + + void rollback() + { + typedef typename Backups_t::iterator Iter; + Iter end = m_backup.end(); + for ( Iter itr = m_backup.begin(); itr!=end; ++itr) { + m_container.addCollection (itr->second, itr->first).ignore(); + } + } + + /** @brief publish the type of underlying indexing (mapping or sequencing) + */ + virtual bool isMapping() const {return true;} +}; + +/** @brief metafunction to automagically dispatch on the type of a container + * and fetch the right thinning handler + */ +template <class Container> +struct get_thinning_handler +{ +private: + typedef typename Container::value_type value_type; + typedef typename boost::remove_pointer<value_type>::type base_value_type; + + typedef typename boost::is_base_of<std::vector<value_type>, + Container> + derives_from_std_vector; + +// typedef typename boost::is_base_of<DataVector<base_value_type>, +// Container> +// derives_from_datavector; + + // ASSUME a Container inheriting from DataObject means IdentifiableContainer + // XXX that's kind of a bold assumption... + typedef typename boost::is_base_of<DataObject, Container> + derives_from_dataobject; + +public: +#define if_c ::boost::mpl::if_c + typedef typename + if_c<derives_from_dataobject::value, + ::Athena::IdcThinningHdlr<Container>, + typename + if_c<derives_from_std_vector::value, + ::Athena::StdThinningHdlr<Container>, + ::Athena::DvThinningHdlr<Container> + >::type + >::type type; +#undef if_c +}; + +} //> namespace Athena + +#endif //> ATHENAKERNEL_ITHINNINGHDLR_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningSvc.h new file mode 100644 index 00000000..5f017bb8 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IThinningSvc.h @@ -0,0 +1,437 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ITHINNINGSVC_H +#define ATHENAKERNEL_ITHINNINGSVC_H + +// STL includes +#include <vector> +#include <algorithm> +#include <string> +#include <stdexcept> +#include <map> // XXX in fact we'd really want to use a hash_map... + // but that's in SGTools !!! + +// FrameWork includes +#include "GaudiKernel/IService.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IThinningHdlr.h" +#include "AthenaKernel/ISlimmingHdlr.h" + +// Forward declaration +class ThinningOutputTool; + +// python forward +struct _object; typedef _object PyObject; +class IThinningSvc; +namespace AthenaInternal { + PyObject* thinContainer (IThinningSvc*,PyObject*,PyObject*,int); + std::size_t thinIdxContainer(IThinningSvc*,PyObject*,std::size_t ); +} + +/** + * @class IThinningSvc + * @brief Abstract interface to ThinningSvc. The service allows to thin + * (remove elements from) a DataVector-like container while the + * container is being written out. See AthExThinning for an example of usage. + * @author S.Binet<binet@cern.ch> + */ +/////////////////////////////////////////////////////////////////// +class IThinningSvc : virtual public IService, + virtual public IProxyDict +{ + + /////////////////////////////////////////////////////////////////// + // Public typedefs: + /////////////////////////////////////////////////////////////////// + public: + + /// @brief the type holding the decision for each element of the container + typedef std::vector<bool> VecFilter_t; + /// @brief the type holding the decision for each element of the container + typedef std::map<std::size_t, bool> SparseFilter_t; + /// @brief the type holding the decision for each element of the container + typedef SparseFilter_t Filter_t; + + /////////////////////////////////////////////////////////////////// + // Public struct: + /////////////////////////////////////////////////////////////////// + public: + /** @brief Struct to hold the type of filtering one wants to apply. + * This is a poor-man way of modeling the && and || combination + * of different passes of thinning. + */ + struct Operator { + enum Type { + And = 0, + Or = 1 + }; + }; + + /////////////////////////////////////////////////////////////////// + // Public members: + /////////////////////////////////////////////////////////////////// + public: + // NB: This is an unsigned type, and thus represents the maximum + // size that the allocator can hold. (modeled after std::string::npos) + static const std::size_t RemovedIdx = static_cast<std::size_t>(-1); + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** @brief Destructor: + */ + virtual ~IThinningSvc(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + static const InterfaceID& interfaceID(); + + /** @brief Get the index after thinning of a given container, providing + * the old index. + * @returns IThinningSvc::RemovedIdx if the element asked-for has been + * removed during thinning. + */ + template< class Container > + std::size_t index( const Container* container, + std::size_t idx ) const { + const void* obj = static_cast<const void*>(container); + return this->index_impl( this->proxy(obj), idx ); + } + + /** @brief Tell clients if any thinning occurred during the event processing + */ + virtual + bool thinningOccurred() const = 0; + + /** @brief test if a container is thinned + */ + template<class Container> + bool + thinningOccurred(const Container* container) const + { + const void* obj = static_cast<const void*>(container); + const SG::DataProxy* p = this->proxy(obj); + return this->is_thinned_impl(p); + } + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief helper method to decide if an index value is thinned or not + */ + static + bool isThinned ( const std::size_t idx ); + + /** @brief helper method to generate a removed index value for different + * types of indices (integer, std::string,...) + */ + template <typename IndexType> + static + IndexType generateRemovedIdx() + { + throw std::runtime_error ("sorry... unimplemented generateRemovedIdx type"); + } + + /** @brief Helper method to retrieve the instance of the currently active + * thinning service. + * @param activeSvc the new active thinning svc instance. + * If null pointer, then returns old/current active thinning svc + * @param override the current activeSvc with the given one, even if + * the given one is NULL. + * FIXME: this is a horrible hack and bad things will happen in a + * multithreaded mode. It is well possible the active thinning svc + * gets swapped/updated in the middle of a "thinning transaction". + * The correct way of implementing this would be to get the pointer + * of the active thinning svc through an ActiveThinningSvc (as for + * the @c StoreGateSvc and its @c ActiveStoreSvc buddy). However, + * as the converters which need that @c IThinningSvc instance to + * recompute the correct indices of thinned containers, are "framework + * blind", it would just be moving the problem elsewhere... + * Note: would it be OK to put the holder of the active thinning svc in a + * thread-local storage ? + */ + static IThinningSvc* instance( IThinningSvc* activeSvc = 0, + bool override = false ); + + /// @brief A helper method to select elements from a DataVector container. + /// the elements of the @a filter vector are 'true' for the elements to be + /// kept. + /// If this container has already been filtered, the results are merged + /// according to the operator being passed (default is 'AND') + template< class Container > + StatusCode filter( const Container& in, + const IThinningSvc::VecFilter_t& filter, + const IThinningSvc::Operator::Type op = Operator::And ); + + /// @brief A helper method to select elements from a DataVector container. + /// the elements of the @a filter sparse vector are 'true' for the elements + /// to be kept. + /// If this container has already been filtered, the results are merged + /// according to the operator being passed (default is 'AND') + template< class Container > + StatusCode filter( const Container& in, + const IThinningSvc::Filter_t& filter, + const IThinningSvc::Operator::Type op = Operator::And ); + + /// @brief A helper method to select elements from a DataVector container. + /// The predicate is true for the elements to be kept. + /// If this container has already been filtered, the results are merged + /// according to the operator being passed (default is 'AND') + template< class Container, class Predicate > + StatusCode filter( const Container& in, + const Predicate& filter, + const IThinningSvc::Operator::Type op = Operator::And ); + + /// @brief A helper method to select elements from a typeless object + /// With the help of this function it is possible to record thinning + /// information about types that can't be handled by the service internally. + /// This information is instead just served to the outside (to the POOL + /// converters) via the interface of the service. + StatusCode typelessFilter( const void* in, + const IThinningSvc::VecFilter_t& filter, + const IThinningSvc::Operator::Type op = + Operator::And ); + + /// @brief A helper method to select elements from a typeless object + /// With the help of this function it is possible to record thinning + /// information about types that can't be handled by the service internally. + /// This information is instead just served to the outside (to the POOL + /// converters) via the interface of the service. + StatusCode typelessFilter( const void* in, + const IThinningSvc::Filter_t& filter, + const IThinningSvc::Operator::Type op = + Operator::And ); + + // slimming part + + /** @brief register a slimming handler with the @c IThinningSvc + * Registering a @c Athena::ISlimmingHdlr allows to slim an object and keep + * the side effects of slimming it 'guarded' within one output stream. + * The original state (before slimming) of the object will be restored after + * to-disk serialization took place. + * Note: @c IThinningSvc will take ownership of the handler. + */ + virtual + StatusCode register_slimmer (Athena::ISlimmingHdlr *handler) =0; + +// /** @brief retrieve an iterator over the @c ISlimmingHdlrs +// */ +// virtual +// range<Athena::ISlimmingHdlr> begin_slimmers() =0; + +// /** @brief retrieve an iterator over the @c ISlimmingHdlrs +// */ +// virtual +// range<Athena::ISlimmingHdlr> end_slimmers() =0; + + /////////////////////////////////////////////////////////////////// + // Protected methods: + /////////////////////////////////////////////////////////////////// + protected: + + /** @brief Retrieve the handler (if any) to thin a @c DataProxy + */ + virtual Athena::IThinningHdlr* handler( SG::DataProxy* proxy ) = 0; + + /** @brief Build the 'db' of elements to be kept for each container + */ + virtual StatusCode + filter_impl( Athena::IThinningHdlr* handler, + SG::DataProxy* proxy, + const Filter_t& filter, + const IThinningSvc::Operator::Type op = Operator::And ) = 0; + + /// @brief make the @c ThinningOutputTool a friend so it can access the + /// internal @c IThinningSvc::commit and + /// @c IThinningSvc::rollback methods + friend class ThinningOutputTool; + + /** @brief Commit the pending slimming and thinning actions + * - first apply slimming via the registered ISlimmingHdlrs + * - then apply thinning via the registered IThinningHdlrs + * - update the association of before/after-thinning indices + * - actually delete the requested to-be-thinned elements + */ + virtual + StatusCode commit() = 0; + + /** @brief Rollback the slimming and thinning actions: + * - first rollback thinning + * - restore the requested to-be-thinned elements + * - then rollback slimming + */ + virtual + StatusCode rollback() = 0; + + /** @brief Get the index after thinning of a given container, providing + * the old index. + * @returns IThinningSvc::RemovedIdx if the element asked-for has been + * removed during thinning. + */ + virtual + std::size_t index_impl( const SG::DataProxy* objProxy, + std::size_t idx ) const = 0; + + /** @brief test if a container is thinned + */ + virtual + bool is_thinned_impl(const SG::DataProxy* p) const = 0; + + /////////////////////////////////////////////////////////////////// + // Protected data: + /////////////////////////////////////////////////////////////////// + protected: + + + /////////////////////////////////////////////////////////////////// + // friends + /////////////////////////////////////////////////////////////////// + ///access filter_impl + friend + PyObject* + AthenaInternal::thinContainer(IThinningSvc*,PyObject*,PyObject*,int); + ///access index + friend + std::size_t + AthenaInternal::thinIdxContainer(IThinningSvc*,PyObject*,std::size_t); +}; + + +/////////////////////////////////////////////////////////////////// +// Thinning hook function. +// + + +/** + * @brief Propagate thinning. Called after applying thinning to @c in. + * @param in The object that was thinned. + * @param svc The thinning service (for convenience). + * @param filter Lists the elements to be kept. + * @param op How to merge results: AND or OR. + * + * Sometimes containers depend on one another, such that when one + * is thinned, the other must also be thinned in the same way. + * An example is the DataVector auxiliary stores. + * This function provides a way of automatically propagating + * thinning for certain types. Once thinning has been applied to an object, + * @c thinningHook will be called with a pointer to the object as the + * first argument. This default version is a no-op and matches + * any pointer type. However, additional overloads can be provided + * for specific container types. + */ +inline +StatusCode thinningHook (const void* /*in*/, + IThinningSvc* /*svc*/, + const IThinningSvc::Filter_t& /*filter*/, + const IThinningSvc::Operator::Type /*op*/ ) +{ + return StatusCode::SUCCESS; +} + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +inline const InterfaceID& IThinningSvc::interfaceID() +{ + static const InterfaceID IID_IThinningSvc("IThinningSvc", 1, 0); + return IID_IThinningSvc; +} + +template <> +std::size_t +IThinningSvc::generateRemovedIdx<std::size_t>(); + +template <> +std::string +IThinningSvc::generateRemovedIdx<std::string>(); + +// templates +/// specialization for SG::DataProxy +template<> +inline +std::size_t +IThinningSvc::index<SG::DataProxy>(const SG::DataProxy* dp, + std::size_t idx) const +{ + return this->index_impl( dp, idx ); +} + +template<> +inline +bool +IThinningSvc::thinningOccurred<SG::DataProxy>(const SG::DataProxy* dp) const +{ + return this->is_thinned_impl(dp); +} + + +template< class Container > +StatusCode +IThinningSvc::filter( const Container& in, + const IThinningSvc::VecFilter_t& filter, + const IThinningSvc::Operator::Type op ) +{ + IThinningSvc::Filter_t sparse_filter; + const std::size_t imax=filter.size(); + for ( std::size_t i = 0; i!=imax; ++i ) { + sparse_filter[i] = filter[i]; + } + return this->filter (in, sparse_filter, op); +} + +template< class Container > +StatusCode +IThinningSvc::filter( const Container& in, + const IThinningSvc::Filter_t& filter, + const IThinningSvc::Operator::Type op ) +{ + const void* obj = static_cast<const void*>(&in); + SG::DataProxy* proxy = this->proxy(obj); + Athena::IThinningHdlr* handler = this->handler(proxy); + if ( 0 == handler ) { + typedef typename + Athena::get_thinning_handler<Container>::type + handler_type; + handler = new handler_type( in ); + } + StatusCode sc = this->filter_impl( handler, proxy, filter, op ); + if (sc.isSuccess()) + sc = thinningHook (&in, this, filter, op); + return sc; +} + +template< class Container, class Predicate > +StatusCode +IThinningSvc::filter( const Container& in, + const Predicate& pred, + const IThinningSvc::Operator::Type op ) +{ + const void* obj = static_cast<const void*>(&in); + SG::DataProxy* proxy = this->proxy(obj); + Athena::IThinningHdlr* handler = this->handler(proxy); + if ( 0 == handler ) { + typedef typename + Athena::get_thinning_handler<Container>::type + handler_type; + handler = new handler_type( in ); + } + + Filter_t filter (in.begin(), in.end(), pred); + StatusCode sc = this->filter_impl( handler, proxy, + filter, op ); + if (sc.isSuccess()) + sc = thinningHook (&in, this, filter, op); + return sc; +} + + + +#endif //> ATHENAKERNEL_ITHINNINGSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ITimeKeeper.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITimeKeeper.h new file mode 100644 index 00000000..77832781 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITimeKeeper.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ITIMEKEEPER_H +# define ATHENAKERNEL_ITIMEKEEPER_H + +//<<<<<< INCLUDES >>>>>> +#include <ctime> /* time_t */ + +#ifndef GAUDIKERNEL_ISERVICE_H + #include "GaudiKernel/IService.h" +#endif + +//<<<<<< CLASS DECLARATIONS >>>>>> +/** @class ITimeKeeper + * @brief access cpu time info. In particular allows to know when job time + * is over + * N.B. times are in 1/100 CPU sec units (POSIX standard) + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> + * $Id: ITimeKeeper.h,v 1.3 2007-02-08 17:48:38 binet Exp $ + */ + +class ITimeKeeper : virtual public IService { +public: + /// main user call: inform time keeper that next job iteration is about + /// to start. Returns false to signal time is over (not enough time for + /// next iter) + virtual bool nextIter() = 0; + virtual time_t timeL() const = 0; ///< time remaining before limit + virtual time_t timeX() const = 0; ///< time used so far + virtual bool timeOver() const = 0; ///< is there time for another iter? + + /// Gaudi boilerplate + static const InterfaceID& interfaceID(); +}; + +#endif // ATHENAKERNEL_ITIMEKEEPER_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/ITriggerTime.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITriggerTime.h new file mode 100644 index 00000000..f364d9d1 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/ITriggerTime.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_ITRIGGERTIME_H +#define ATHENAKERNEL_ITRIGGERTIME_H +/** @file ITriggerTime.h + * @brief interface to a tool that returns the + * time offset of the current trigger. Used by PileUpMergeSvc + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + *$Id: ITriggerTime.h,v 1.2 2007-06-23 01:12:06 calaf Exp $ + */ + +#include "GaudiKernel/IAlgTool.h" + +/** @class ITriggerTime + * @brief interface to a tool that returns the + * time offset of the current trigger. Used by PileUpMergeSvc + */ +class ITriggerTime : public virtual IAlgTool { +public: + /// returns the time offset of the current trigger + virtual double time() = 0; + static const InterfaceID& interfaceID() { + static const InterfaceID IID( "ITriggerTime", 1, 0 ); + return IID; + } +}; +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IUserDataSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IUserDataSvc.h new file mode 100644 index 00000000..fa741918 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IUserDataSvc.h @@ -0,0 +1,333 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//Dear emacs, this is -*-c++-*- + +#ifndef IUSERDATASVC_H +#define IUSERDATASVC_H + +#include "GaudiKernel/IService.h" +#include "GaudiKernel/StatusCode.h" +#include "AthenaKernel/IAthenaBarCode.h" + +#include <string> +#include <typeinfo> +#include "boost/any.hpp" + + +/** @class IUserDataSvc + * @brief interface to UserDataSvc + * @author Yushu Yao <yyao@lbl.gov> - ATLAS Collaboration + * @author Walter Lampl <walter.lampl@cern.ch> + *$Id: IUserDataSvc.h,v 1.8 2008/05/27 22:09:42 yyao Exp $ + */ + +class IUserDataSvc : virtual public IService { + +public: + + //Standard destructor + ~IUserDataSvc() {} + + //Standard interfaceID query + static const InterfaceID& interfaceID(); + + + // * * * * * * * * * * * * * * * * * * * * * * * * + //NEW StoreGate-inspired interface: + //1. Event Level Decorations + // * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * @brief Record method for event decorations (recommended) + * @param label String label of the decoration + * @param deco Decoration payload (template) + */ + template<typename DECO> + StatusCode record(const std::string& label, const DECO& deco); + + + /** + * @brief Retrieve method for event decorations (recommended) + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + template<typename DECO> + StatusCode retrieve(const std::string & label, DECO &deco); + + + /** + * @brief Contains method for event decorations (recommended) + * @param label String label of the decoration + * @return True if the decoration exists + */ + virtual bool contains(const std::string& label) =0; + + // * * * * * * * * * * * * * * * * * * * * * * * * + //2. Element Level Decorations + // * * * * * * * * * * * * * * * * * * * * * * * * + + /** + * @brief Record method for element decorations (recommended) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @param deco Decoration payload (template) + */ + template<typename DECO> + StatusCode record(const IAthenaBarCode &abc, const std::string& label, const DECO& deco); + + + /** + * @brief Retrieve method for element decorations (recommended) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + template<typename DECO> + StatusCode retrieve(const IAthenaBarCode &abc, const std::string & label, DECO &deco); + + /** + * @brief Contains method for element decorations (recommended) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @return True if the decoration exists + */ + virtual bool contains(const IAthenaBarCode& abc,const std::string& label) =0; + + + + + // * * * * * * * * * * * * * * * * * * * * * * * * + // Pure Virtual Methods + // * * * * * * * * * * * * * * * * * * * * * * * * + + //For Element decoration + virtual StatusCode recordAny(const IAthenaBarCode& abc,const std::string& label, const boost::any& value)=0; + virtual StatusCode retrieveAny(const IAthenaBarCode& abc,const std::string& label, const boost::any*& value) =0; + + //For Event decoration: + virtual StatusCode recordAny(const std::string& label, const boost::any& value)=0; + virtual StatusCode retrieveAny(const std::string& label, const boost::any*& value) =0; + + + // * * * * * * * * * * * * * * * * * * * * * * * * + //Legacy interface + // * * * * * * * * * * * * * * * * * * * * * * * * + + + /** + * @brief Legacy Retrieve method for element decorations (deprecated) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + template<typename DECO> + StatusCode getElementDecoration(const IAthenaBarCode &abc, const std::string & label, DECO &deco) { + return retrieve(abc,label,deco); + } + + /** + * @brief Legacy Retrieve method for element decorations (deprecated) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + + template<typename DECO> + StatusCode getInMemElementDecoration(const IAthenaBarCode &abc, const std::string & label, DECO &deco) { + return retrieve(abc,label,deco); + } + + /** + * @brief Legacy Record method for element decorations (deprecated) + * @param label String label of the decoration + * @param deco (output) Decoration payload + */ + template<typename DECO> + StatusCode decorateElement(const IAthenaBarCode &abc, const std::string& label, DECO& deco) { + return record(abc,label,deco); + } + + /** + * @brief Legacy Record method for event decorations (deprecated) + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + template<typename DECO> + StatusCode decorateEvent(const std::string& label, const DECO& deco) { + return record(label,deco); + } + + /** + * @brief Legacy Retrieve method for event decorations (deprecated) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + template<typename DECO> + StatusCode getEventDecoration(const std::string & label, DECO &deco) { + return retrieve(label,deco); + } + + /** + * @brief Legacy Retrieve method for event decorations (deprecated) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @param[out] deco (output) Decoration payload + */ + template<typename DECO> + StatusCode getInMemEventDecoration(const std::string & label, DECO &deco) { + return retrieve(label,deco); + } + + /** + * @brief Legacy Contains method for Event decorations (deprecated) + * @param label String label of the decoration + * @return True if the decoration exists + */ + bool containsEventDecoration(const std::string &label) { + return contains(label); + } + /** + * @brief Legacy Contains method for Event decorations (deprecated) + * @param label String label of the decoration + * @return True if the decoration exists + */ + + bool containsInMemEventDecoration(const std::string &label) { + return contains(label); + } + + /** + * @brief Legacy Contains method for Event decorations (deprecated) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @return True if the decoration exists + */ + bool containsElementDecoration(const IAthenaBarCode &abc, const std::string &label="") { + return contains(abc,label); + } + + /** + * @brief Legacy Contains method for Event decorations (deprecated) + * @param abc A data-object implmenting the IAthenaBarCode interface + * @param label String label of the decoration + * @return True if the decoration exists + */ + bool containsInMemElementDecoration(const IAthenaBarCode &abc, const std::string &label="") { + return contains(abc,label); + } + + + + virtual int vdecorateElement(const IAthenaBarCode &abc, const std::string& label, + const std::type_info &decoinfo, void* & deco) =0; + + virtual int vgetElementDecoration(const IAthenaBarCode &abc, const std::string& label, + const std::type_info &decoinfo, void *&deco) = 0; + + + + int vgetInMemElementDecoration(const IAthenaBarCode &abc, const std::string& label, + const std::type_info &decoinfo, void *&deco, + bool /*quiet*/) { + return vgetElementDecoration(abc,label,decoinfo,deco); + } + + +}; + + + + +template<typename DECO> +inline StatusCode IUserDataSvc::record(const std::string& label, const DECO& deco) { + const boost::any value(deco); + return this->recordAny(label, value); + +} + +template<typename DECO> +inline StatusCode IUserDataSvc::retrieve(const std::string & label, DECO &deco) { + const boost::any* value; + StatusCode sc=this->retrieveAny(label, value); + if (sc.isFailure()) return sc; + if (typeid(DECO) != value->type()) return StatusCode::FAILURE; + + deco=boost::any_cast<DECO>(*value); + return StatusCode::SUCCESS; +} + + +template<typename DECO> +inline StatusCode IUserDataSvc::record(const IAthenaBarCode &abc, const std::string& label, const DECO& deco) { + boost::any value(deco); + return this->recordAny(abc,label, value); +} + + +template<typename DECO> +inline StatusCode IUserDataSvc::retrieve(const IAthenaBarCode &abc, const std::string & label, DECO &deco) { + const boost::any* value=0; + StatusCode sc=this->retrieveAny(abc,label, value); + if (sc.isFailure()) return sc; + if (typeid(DECO) != value->type()) return StatusCode::FAILURE; + const DECO* decoPtr=boost::any_cast<DECO>(value); + deco=*decoPtr; //Deep copy! + return StatusCode::SUCCESS; + +} + + +inline const InterfaceID& +IUserDataSvc::interfaceID() { + static const InterfaceID IID("IUserDataSvc", 1, 0); + return IID; +} + +#endif // IUSERDATASVC_H + + +//Old methods, not implemented in the new version: + +//virtual bool containsElementDecoration(const IAthenaBarCode &abc, const std::string &label="") = 0; + //virtual bool containsInMemElementDecoration(const IAthenaBarCode &abc, const std::string &label="") = 0; + + //Functions to iterate over existing element level decorations in this event + //Slow, not suggested to use for production purpose + //virtual std::vector<AthenaBarCode_t> getElListOfABC() =0; + //virtual std::vector<std::string> getElListOfLabel(const AthenaBarCode_t &abc) =0; + //virtual std::vector<AthenaBarCode_t> getInMemElListOfABC() =0; + //virtual std::vector<std::string> getInMemElListOfLabel(const AthenaBarCode_t &abc) =0; + + +/* + virtual int + vdecorate(const std::string& label, const std::type_info &decoinfo, + void* & deco, void* & defaultobj, void* & tobedeleted, + const UserDataAssociation::DecoLevel& level, const CLID& clid, + const std::string & key) = 0; + + virtual int + vdecorateElement(const IAthenaBarCode &abc, const std::string& label, + const std::type_info &decoinfo, void* & deco, void* & defaultobj, + void* & tobedeleted)=0; + + virtual int + vgetDecoration(const std::string& label, const std::type_info &decoinfo, + void *&deco, const UserDataAssociation::DecoLevel& level, + const CLID& clid, const std::string & key) = 0; + + virtual int + vgetInMemDecoration(const std::string& label, const std::type_info &decoinfo, + void *&deco, const UserDataAssociation::DecoLevel& level, + const CLID& clid, const std::string & key) = 0; + + virtual int + vgetElementDecoration(const IAthenaBarCode &abc, const std::string& label, + const std::type_info &decoinfo, void *&deco) = 0; + + + + */ diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/IValgrindSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/IValgrindSvc.h new file mode 100644 index 00000000..9ca6b909 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/IValgrindSvc.h @@ -0,0 +1,84 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IVALGRINDSVC_H +#define ATHENAKERNEL_IVALGRINDSVC_H + +// STL includes +#include <iosfwd> + +// HepMC / CLHEP includes + +// FrameWork includes +#include "GaudiKernel/IService.h" + +// Forward declaration + +/** + * @class IValgrindSvc + * @brief Abstract interface for ValgrindSvc. FIXME + * @author Sebastien Binet + */ +class IValgrindSvc : virtual public IService +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** Destructor: + */ + virtual ~IValgrindSvc(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + static const InterfaceID& interfaceID(); + + /// Start callgrind instrumentation + virtual void callgrindStartInstrumentation() = 0; + + /// Stop callgrind instrumentation + virtual void callgrindStopInstrumentation() = 0; + + /// Dump callgrind profiling stats + virtual void callgrindDumpStats( std::ostream& out ) = 0; + + /// Toggle callgrind event collection + virtual void callgrindToggleCollect() = 0; + + /// Do a leak check now + virtual void valgrindDoLeakCheck() = 0; + + /// Number of created callgrind profiles + virtual unsigned int profileCount() = 0; + + /////////////////////////////////////////////////////////////////// + // Private methods: + /////////////////////////////////////////////////////////////////// + private: + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +inline const InterfaceID& IValgrindSvc::interfaceID() +{ + static const InterfaceID IID_IValgrindSvc("IValgrindSvc", 2, 0); + return IID_IValgrindSvc; +} + +#endif //> ATHENAKERNEL_IVALGRINDSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/MsgStreamMember.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/MsgStreamMember.h new file mode 100644 index 00000000..b651fa4c --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/MsgStreamMember.h @@ -0,0 +1,85 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_MSGSTREAMEMBER_H +#define ATHENAKERNEL_MSGSTREAMEMBER_H 1 +/** @file MsgStreamMember.h + * @brief MsgStreamMember is designed to be a data member of a Gaudi component + * that sets up and give access safely and efficiently to a + * MsgStream object + * + * $Id: MsgStreamMember.h,v 1.1 2008-07-14 22:10:14 calaf Exp $ + * @author Paolo Calafiura - Atlas collaboration + */ +#include <string> + +//strictly speaking this could be in the cxx file, by putting it here we allow +//clients to use MsgStreamMember as a self-contained replacement for MsgStream +#include "GaudiKernel/MsgStream.h" + +#include "AthenaKernel/getMessageSvc.h" /* IMessageSvcHolder */ +class MsgStream; +namespace Athena { + + + /** @class MsgStreamMember + * @brief designed to be a data member of a Gaudi component + * that sets up and give access safely and efficiently to a + * MsgStream object. The main advantage over a plain MsgStream + * is that MsgStreamMember can delay the instantiation of the + * MsgStream (and of IMessageSvc) till the last possible moment + * and will manage IMessageSvc ref count for you. + * + */ + class MsgStreamMember { + public: + /// standard constructor (looks like MsgStream's) + /// In + /// We take ownership (addRef) ims here, and release it in the destructor + /// This makes it work with e.g. Algorithm::msgSvc which is propertly + /// released in ~Algorithm. Notice that m_stream is set lazily in get() + /// @param label: the label to be printed by the stream (usually name()) + MsgStreamMember(IMessageSvc *ims, const std::string& label) : + m_ims(ims), m_label(label), m_stream(0) {} + + /// this constructor will take IMessageSvc* from getMessageSvc() + /// slow, meant to be used from a class without access to IMessageSvc* + /// m_ims and m_stream set lazily in get() + /// @param label: the label to be printed by the stream (usually name()) + MsgStreamMember(const std::string& label) : + m_ims(), m_label(label), m_stream(0) {} + + /// allows to create the MsgStream immediately + /// @param o: if o is @c Athena::Options::Eager it will create a MsgStream + /// @param label: the label to be printed by the stream (usually name()) + /// @c MsgStream instance there and then. + MsgStreamMember(const Options::CreateOptions o, const std::string& label); + + MsgStreamMember() : m_ims(), m_label(""), m_stream(0) {} + MsgStreamMember(const MsgStreamMember& rhs) : + m_ims(rhs.m_ims), m_label(rhs.m_label), m_stream(0) {} + + MsgStreamMember& operator= (const MsgStreamMember& rhs); + + /// we own the stream + ~MsgStreamMember(); + + /// upon first access sets m_ims as needed + MsgStream& get() const; + + private: + mutable IMessageSvcHolder m_ims; //mutable to have op() const + /// the label to be printed by the stream (usually name()) + std::string m_label; + mutable MsgStream* m_stream; //mutable to have op() const + }; +} +template <typename T> +MsgStream& operator << (const Athena::MsgStreamMember& stream, const T& rhs) { + return (stream.get() << rhs); +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/POSIXTimeKeeper.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/POSIXTimeKeeper.h new file mode 100644 index 00000000..8b14004d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/POSIXTimeKeeper.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_POSIXTIMEKEEPER_H +# define ATHENAKERNEL_POSIXTIMEKEEPER_H + +#include <sys/times.h> + +#ifndef ATHENAKERNEL_TIMEKEEPER_H + #include "AthenaKernel/TimeKeeper.h" +#endif + + +/** @class POSIXTimeKeeper + * @brief specialize TimeKeeper for POSIX systems + * (and other Unix-like ones). Derived from CERNLIB TIMEL/TIMEX + * N.B. times are in 1/100 CPU sec units + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> + * $Id: POSIXTimeKeeper.h,v 1.4 2007-06-14 01:57:23 calaf Exp $ + */ + +class POSIXTimeKeeper : virtual public TimeKeeper { +public: + /// ITimeKeeper Implementation + //@{ + //INH virtual bool nextIter(); ///< main user entry point + //INH virtual time_t timeL() const; ///< time remaining before limit + virtual time_t timeX() const; ///< time used so far + //INH virtual bool timeOver() const; ///< is there time for another iter? + //@} + + /// TimeKeeper Implementation + //@{ + virtual time_t allocTime() const = 0; ///< allocated CPU time for job + virtual void updateTime(); + virtual const std::string& unitLabel() const; + //@} + +protected: + POSIXTimeKeeper(); + virtual ~POSIXTimeKeeper(); + +private: + tms m_tms; //the POSIX struct holding CPU usage info +}; + +#endif // ATHENAKERNEL_POSIXTIMEKEEPERSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.h new file mode 100644 index 00000000..44d75570 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.h @@ -0,0 +1,484 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/RCUObject.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + * + * Read-copy-update (RCU) is a style of synchronization that is appropriate + * to a read-often, update-seldom case. More precisely: + * + * - Reads are frequent and low overhead is important. + * - Updates are infrequent, and extra overhead doesn't matter much. + * - Exact time ordering between reads and updates is not important. + * That is, if a read happens at about the same time as an update, + * it doesn't matter if the read sees the data before or after + * the update (as long as the reader sees something that is consistent). + * + * For a more detailed introduction see, for example: + * + * <https://lwn.net/Articles/262464> + * <https://lwn.net/Articles/573424> + * + * There are many different styles of RCU implemenation; the one we implement + * here is close to the `quiescent-state-based RCU' (QSBR) variant discussed + * in the second article above. Here, readers take out no locks whatsoever. + * It follows then that the updater cannot directly change the object + * that is being read. Instead, it makes an updated copy of the object + * and then publishes it by atomically changing a pointer to the object. + * The remaining question is then when can the old object be deleted. + * It is necessary to delay this until until no thread can be reading + * the old version of the object. + * + * In this implementation, the updater does not wait for this to happen. + * Instead, after the update, each event slot (other than the updater) + * is marked as being in a `grace' period (via an array of flags + * in RCUObject). A grace period ends for a given event slot when + * the object is declared `quiescent'; that is, it is at that time + * not referencing the object. Once the grace periods for all event + * slots have finished, then old versions of the object can be deleted. + * + * It is possible to explicitly declare an object as quiescent, either + * by calling the quiescent() method or by using RCUReadQuiesce. + * Objects can also be registered with the Athena RCUSvc, which will + * declare objects quiescent at the end of an event. + * + * The current implementation is very simple, and is suitable for a small + * number of objects that change infrequently. + * + * - If objects are being updated ~ every event and one is relying + * on RCUSvc to mark them as quiescent, then it's possible that we'll + * never be out of the grace period for all event slots simultaneously, + * preventing objects from being cleaned up. + * + * - If there are a large number of infrequently-changing objects, + * then RCUSvc may waste time marking as quiescent objects that + * have not changed. + * + * If either of these becomes an issue, they can be addressed with a more + * elaborate implementation. + * + * Usage: + * + * The usual usage is to create an RCUObject instance via the RCUSvc. + * RCUObject is templated on the type of the controlled object. + * + *@code + * ServiceHandle<Athena::RCUSvc> rcusvc ("Athean::RCUSvc", "test"); + * std::unique_ptr<Athena::RCUObject<Payload> > = + * rcusvc->newrcu<Payload>(); + @endcode + * + * @c newrcu may also take additional arguments that will be passed + * to the constructor for @c Payload. This will register the object + * with the service. One can alternately create a @c RCUObject directly, + * passing it the number of event slots. + * + * To read the controlled object, create a @c RCURead object: + * + *@code + * const Athena::RCUObject<Payload>& rcuobj = ...; + * { + * Athena::RCURead<Payload> r (rcuobj); + * ret = r->someMethodOnPayload(); + * } + @endcode + * + * and to update use @c RCUUpdate: + * + *@code + * Athena::RCUObject<Payload>& rcuobj = ...; + * { + * Athena::RCUUpdate<Payload> u (rcuobj); + * auto newPayload = std::make_unique<Payload> (*u); + * newPayload->updateSomeStuff(); + * u.update (std::move (newPayload)); + * } + @endcode + * + * To explicitly declare an object as quiescent, call the @c quiescent method. + * This takes an @c EventContext object, or it can be defaulted, in which + * case the current global context object will be used. You can also + * use @c RCUReadQuiesce instead of @c RCURead to automatically call + * @c quiescent when the read is complete (when the @c RCUReadQuiesce + * object is destroyed). + */ + + +#ifndef ATHENAKERNEL_RCUOBJECT_H +#define ATHENAKERNEL_RCUOBJECT_H + + +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/ThreadLocalContext.h" +#include "GaudiKernel/EventContext.h" +#include "boost/dynamic_bitset.hpp" +#include <atomic> +#include <deque> +#include <vector> +#include <memory> +#include <mutex> + + +namespace Athena { + + +class IRCUSvc; +template <class T> class RCURead; +template <class T> class RCUReadQuiesce; +template <class T> class RCUUpdate; + + + +/** + * @brief Base object class for RCU-style synchronization for Athena. + */ +class IRCUObject +{ +public: + /** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * + * The service will call @c quiescent at the end of each event. + */ + IRCUObject (IRCUSvc& svc); + + + /** + * @brief Constructor, with event slot count. + * @param nslots Number of active event slots. + * + * This version does not register with a service. + */ + IRCUObject (size_t nslots); + + + /** + * @brief Destructor. + * + * Remove this object from the service if it has been registered. + */ + virtual ~IRCUObject(); + + + /** + * @brief Declare the current event slot of this object to be quiescent. + * + * This will take out a lock and possibly trigger object cleanup. + */ + void quiescent(); + + + /** + * @brief Declare the event slot @c ctx of this object to be quiescent. + * @param ctx The event context. + * + * This will take out a lock and possibly trigger object cleanup. + */ + void quiescent (const EventContext& ctx); + + +protected: + typedef std::mutex mutex_t; + typedef std::lock_guard<mutex_t> lock_t; + + + /** + * @brief Declare that the grace period for a slot is ending. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * @returns true if any slot is still in a grace period. + * false if no slots are in a grace period. + * + * The caller must be holding the mutex for this object. + */ + bool endGrace (lock_t& /*lock*/, const EventContext& ctx); + + + /** + * @brief Declare that all slots are in a grace period. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * + * The caller must be holding the mutex for this object. + */ + void setGrace (lock_t& /*lock*/); + + + /** + * @brief Return the mutex for this object. + */ + mutex_t& mutex(); + + + /** + * @brief Delete all old objects. + * @param Lock object (external locking). + * + * The caller must be holding the mutex for this object. + */ + virtual void clearOld (lock_t& /*lock*/) = 0; + + +private: + /// The mutex for this object. + std::mutex m_mutex; + + /// The service with which we're registered, or null. + IRCUSvc* m_svc; + + /// Bit[i] set means that slot i is in a grace period. + boost::dynamic_bitset<> m_grace; +}; + + +/** + * @brief Wrapper object controlled by RCU synchonization. + * + * See the comments at the top of the file for complete comments. + */ +template <class T> +class RCUObject + : public IRCUObject +{ +public: + typedef RCURead<T> Read_t; + typedef RCUReadQuiesce<T> ReadQuiesce_t; + typedef RCUUpdate<T> Update_t; + + + /** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * @param args... Additional arguments to pass to the @c T constructor. + * + * The service will call @c quiescent at the end of each event. + */ + template <typename... Args> + RCUObject (IRCUSvc& svc, Args&&... args); + + + /** + * @brief Constructor, with number of slots. + * @param nslots Number of event slots. + * @param args... Additional arguments to pass to the @c T constructor. + */ + template <typename... Args> + RCUObject (size_t nslots, Args&&... args); + + + /** + * @brief Return a reader for this @c RCUObject. + */ + Read_t reader() const; + + + /** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * + * This version will read the global event context. + */ + ReadQuiesce_t readerQuiesce(); + + + /** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * @param ctx The event context. + */ + ReadQuiesce_t readerQuiesce (const EventContext& ctx); + + + /** + * @brief Return an updater for this @c RCUObject. + * + * This version will read the global event context. + */ + Update_t updater(); + + + /** + * @brief Return an updater for this @c RCUObject. + * @param ctx The event context. + */ + Update_t updater (const EventContext& ctx); + + +private: + /** + * @brief Delete all old objects. + * @param Lock object (external locking). + * + * The caller must be holding the mutex for this object. + */ + virtual void clearOld (lock_t& /*lock*/) override; + + +private: + template <class U> friend class RCUReadQuiesce; + template <class U> friend class RCURead; + template <class U> friend class RCUUpdate; + + /// Pointer to the current object. + std::atomic<const T*> m_obj; + + /// List of all allocated objects. + /// The current object is the one at the front; + /// the others are pending cleanup. + std::deque<std::unique_ptr<T> > m_objs; +}; + + +/** + * @brief Helper to read data from a @c RCUObject. + * + * See the header comments for details. + */ +template <class T> +class RCURead +{ +public: + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + */ + RCURead (const RCUObject<T>& rcuobj); + + + /** + * @brief Access data. + */ + const T& operator*() const; + + + /** + * @brief Access data. + */ + const T* operator->() const; + + +private: + /// The data object we're reading. + const T& m_obj; +}; + + +/** + * @brief Helper to read data from a @c RCUObject. + * When this object is deleted, the @c RCUObject is declared + * quiescent for this event slot. + * + * See the header comments for details. + */ +template <class T> +class RCUReadQuiesce + : public RCURead<T> +{ +public: + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ + RCUReadQuiesce (RCUObject<T>& rcuobj); + + + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ + RCUReadQuiesce (RCUObject<T>& rcuobj, const EventContext& ctx); + + + /** + * @brief Destructor. + * + * Mark this event slot quiescent. + */ + ~RCUReadQuiesce(); + + +private: + /// The RCUObject we're referencing. + RCUObject<T>& m_rcuobj; + + /// The current event context. + const EventContext& m_ctx; +}; + + +/** + * @brief Helper to update data in a @c RCUObject. + * + * See the header comments for details. + */ +template <class T> +class RCUUpdate +{ +public: + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ + RCUUpdate (RCUObject<T>& rcuobj); + + + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ + RCUUpdate (RCUObject<T>& rcuobj, const EventContext& ctx); + + + /** + * @brief Access data. + */ + const T& operator*() const; + + + /** + * @brief Access data. + */ + const T* operator->() const; + + + /** + * @brief Publish a new version of the data object. + * @param ptr The new data object. + */ + void update (std::unique_ptr<T> ptr); + +private: + /// The object we're referencing. + RCUObject<T>& m_rcuobj; + + /// The event context. + const EventContext& m_ctx; + + /// Lock for synchonization. + std::lock_guard<std::mutex> m_g; +}; + + +} // namespace Athena + + +#include "AthenaKernel/RCUObject.icc" + + +#endif // not ATHENAKERNEL_RCUOBJECT_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.icc b/EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.icc new file mode 100644 index 00000000..711487e5 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/RCUObject.icc @@ -0,0 +1,365 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/RCUObject.icc + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + */ + + +namespace Athena { + + +/** + * @brief Declare the current event slot of this object to be quiescent. + * + * This will take out a lock and possibly trigger object cleanup. + */ +inline +void IRCUObject::quiescent() +{ + quiescent (Gaudi::Hive::currentContext()); +} + + +/** + * @brief Declare the event slot @c ctx of this object to be quiescent. + * @param ctx The event context. + * + * This will take out a lock and possibly trigger object cleanup. + */ +inline +void IRCUObject::quiescent (const EventContext& ctx) +{ + std::lock_guard<std::mutex> g (m_mutex); + if (endGrace(g, ctx)) return; + clearOld(g); +} + + +/** + * @brief Declare that the grace period for a slot is ending. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * @returns true if any slot is still in a grace period. + * false if no slots are in a grace period. + * + * The caller must be holding the mutex for this object. + */ +inline +bool IRCUObject::endGrace (lock_t& /*lock*/, const EventContext& ctx) +{ + EventContext::ContextID_t slot = ctx.slot(); + if (slot == EventContext::INVALID_CONTEXT_ID) return false; + if (slot >= m_grace.size()) std::abort(); + m_grace[slot] = false; + return m_grace.any(); +} + + +/** + * @brief Declare that all slots are in a grace period. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * + * The caller must be holding the mutex for this object. + */ +inline +void IRCUObject::setGrace (lock_t& /*lock*/) +{ + m_grace.set(); +} + + +/** + * @brief Return the mutex for this object. + */ +inline +typename IRCUObject::mutex_t& IRCUObject::mutex() +{ + return m_mutex; +} + + +//************************************************************************* + + +/** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * @param args... Additional arguments to pass to the @c T constructor. + * + * The service will call @c quiescent at the end of each event. + */ +template <class T> +template <typename... Args> +inline +RCUObject<T>::RCUObject (IRCUSvc& svc, Args&&... args) + : IRCUObject (svc) +{ + m_objs.push_back (CxxUtils::make_unique<T>(std::forward<Args>(args)...)); + m_obj = m_objs.front().get(); +} + + +/** + * @brief Constructor, with number of slots. + * @param nslots Number of event slots. + * @param args... Additional arguments to pass to the @c T constructor. + */ +template <class T> +template <typename... Args> +inline +RCUObject<T>::RCUObject (size_t nslots, Args&&... args) + : IRCUObject (nslots) +{ + m_objs.push_back (CxxUtils::make_unique<T>(std::forward<Args>(args)...)); + m_obj = m_objs.front().get(); +} + + +/** + * @brief Return a reader for this @c RCUObject. + */ +template <class T> +inline +typename RCUObject<T>::Read_t RCUObject<T>::reader() const +{ + return Read_t (*this); +} + + +/** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * + * This version will read the global event context. + */ +template <class T> +inline +typename RCUObject<T>::ReadQuiesce_t RCUObject<T>::readerQuiesce() +{ + return ReadQuiesce_t (*this); +} + + +/** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * @param ctx The event context. + */ +template <class T> +inline +typename RCUObject<T>::ReadQuiesce_t +RCUObject<T>::readerQuiesce (const EventContext& ctx) +{ + return ReadQuiesce_t (*this, ctx); +} + + +/** + * @brief Return an updater for this @c RCUObject. + * + * This version will read the global event context. + */ +template <class T> +inline +typename RCUObject<T>::Update_t RCUObject<T>::updater() +{ + return Update_t (*this); +} + + +/** + * @brief Return an updater for this @c RCUObject. + * + * This version will read the global event context. + */ +template <class T> +inline +typename RCUObject<T>::Update_t +RCUObject<T>::updater (const EventContext& ctx) +{ + return Update_t (*this, ctx); +} + + +/** + * @brief Delete all old objects. + * @param Lock object (external locking). + * + * The caller must be holding the mutex for this object. + */ +template <class T> +inline +void RCUObject<T>::clearOld (lock_t& /*lock*/) +{ + while (m_objs.size() > 1) + m_objs.pop_back(); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + */ +template <class T> +inline +RCURead<T>::RCURead (const RCUObject<T>& rcuobj) + : m_obj (*rcuobj.m_obj) +{ +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T& RCURead<T>::operator*() const +{ + return m_obj; +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T* RCURead<T>::operator->() const +{ + return &m_obj; +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ +template <class T> +inline +RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj) + : RCURead<T> (rcuobj), + m_rcuobj (rcuobj), + m_ctx (Gaudi::Hive::currentContext()) +{ +} + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ +template <class T> +inline +RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj, + const EventContext& ctx) + : RCURead<T> (rcuobj), + m_rcuobj (rcuobj), + m_ctx (ctx) +{ +} + + +/** + * @brief Destructor. + * + * Mark this event slot quiescent. + */ +template <class T> +inline +RCUReadQuiesce<T>::~RCUReadQuiesce() +{ + m_rcuobj.quiescent (m_ctx); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ +template <class T> +inline +RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj) + : m_rcuobj (rcuobj), + m_ctx (Gaudi::Hive::currentContext()), + m_g (rcuobj.mutex()) +{ +} + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ +template <class T> +inline +RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj, const EventContext& ctx) + : m_rcuobj (rcuobj), + m_ctx (ctx), + m_g (rcuobj.mutex()) +{ +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T& RCUUpdate<T>::operator*() const +{ + return *m_rcuobj.m_obj; +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T* RCUUpdate<T>::operator->() const +{ + return m_rcuobj.m_obj; +} + + +/** + * @brief Publish a new version of the data object. + * @param ptr The new data object. + */ +template <class T> +void RCUUpdate<T>::update (std::unique_ptr<T> ptr) +{ + m_rcuobj.m_objs.push_front (std::move (ptr)); + m_rcuobj.m_obj = m_rcuobj.m_objs.front().get(); + m_rcuobj.setGrace(m_g); + + // Go ahead and end the grace period for the current slot. + m_rcuobj.endGrace(m_g, m_ctx); +} + + +} // namespace Athena diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/StoreID.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/StoreID.h new file mode 100644 index 00000000..cd9e8023 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/StoreID.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_STOREID_H +#define ATHENAKERNEL_STOREID_H +// $Id: StoreID.h,v 1.4 2008-01-04 21:40:11 gemmeren Exp $ + +/** + * @class StoreID + * @brief defines an enum used by address providers to decide what kind of + * StoreGateSvc they are providing addresses for. A hack, really... + */ + +class StoreID +{ + + public: + + typedef enum { + + EVENT_STORE = 0, + DETECTOR_STORE, + CONDITION_STORE, + METADATA_STORE, + SIMPLE_STORE, + SPARE_STORE, + UNKNOWN + } type; + +}; + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/TPCnvFactory.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/TPCnvFactory.h new file mode 100644 index 00000000..b5203c87 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/TPCnvFactory.h @@ -0,0 +1,208 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: TPCnvFactory.h 707243 2015-11-11 18:53:26Z ssnyder $ + +/** + * @file AthenaKernel/TPCnvFactory.h + * @author scott snyder, S. Binet + * @brief Set up plugin loading of TP converters. + * + * The definitions here are used to allow loading the TP converters directly + * via the Gaudi plugin mechanism. + * + * Usage + * ===== + * + * In a TPCnv package, create a source file with the same name as the package, + * add add this to your requirements file: + * + *@code + * apply_pattern tpcnv_library + @endcode + * + * That file should contain a declaration like this for each TP converter: + * + *@code + * #include "AthenaKernel/TPCnvFactory.h" + * #include "FooTPCnv/FooCnv_p2.h" + * DECLARE_TPCNV_FACTORY(FooCnv_p2, + * Foo, + * Foo_p2, + * Athena::TPCnvVers::Current) + @endcode + * + * The first three arguments should be the converter class, the transient class, + * and the persistent class, respectively. The fourth argument should be + * @c Athena::TPCnvVers::Current if this is the most recent version of the + * converter. You should also declare previous versions of the converter, + * using @c Old: + * + *@code + * #include "FooTPCnv/FooCnv_p1.h" + * DECLARE_TPCNV_FACTORY(FooCnv_p1, + * Foo, + * Foo_p1, + * Athena::TPCnvVers::Old) + @endcode + * + * Sometimes you need to use a different converter class for AthenaROOTAccess. + * In that case, also use @c DECLARE_ARATPCNV_FACTORY: + * + *@code + * #include "FooTPCnv/FooARACnv_p2.h" + * DECLARE_ARATPCNV_FACTORY(FooARACnv_p2, + * Foo, + * Foo_p2, + * Athena::TPCnvVers::Current) + @endcode + * + * There is a separate macro @c DECLARE_TRIGTPCNV_FACTORY to allow declaring + * separate converters to use for the trigger. + * + * Finally, in some cases you may need to use a different name for the + * plugin than the C++ class name. This is generally the case if the + * converter class is actually a typedef. In that case, use + * @c DECLARE_NAMED_TPCNV_FACTORY: + * + *@code + * #include "FooTPCnv/BarCnv_p2.h" + * // BarCnv_p2 is actually a typedef. + * DECLARE_NAMED_ARATPCNV_FACTORY(BarCnv_p2, + * BarCnv_p2, + * Bar, + * Bar_p2, + * Athena::TPCnvVers::Current) + @endcode + * + * There is also a @c DECLARE_NAMED_ARATPCNV_FACTORY. + * + * Implementation + * ============== + * + * The implementation is very simple. Let the converter, transient, + * and persistent types be C, T, and P, respectively. We always make + * plugin entries for C and _PERS_P. If the converter is current, + * we also make an entry for _TRANS_T. If the converter is for ARA, + * we add _ARA t the front of the pers and trans names; and similarly + * _TRIG for trigger-specific conversions. + * + * Thus, to find the correct converter for a transient class, we look up + * _TRANS_T; and for a persistent class we look up _PERS_P. For ARA, + * we first try the look up with _ARA in front of those names. + * To get the transient class name corresponding to a persistent class, + * we create an instance of the converter and use the @c transientTInfo + * interface. No registry is needed beyond the existing Gaudi plugin registry. + * + * One limitation: if you have multiple transient classes that use the + * same persistent class, you'll get warnings from the plugin service. + */ + + +#ifndef ATHENAKERNEL_TPCNVFACTORY_H +#define ATHENAKERNEL_TPCNVFACTORY_H 1 + +#include "Gaudi/PluginService.h" + +// Forward declaration +class ITPCnvBase; + +namespace Athena { + struct TPCnvVers { + enum Value { + Old = 0, + Current = 1 + }; + }; + + struct TPCnvType { + enum Value { + Athena = 0, + ARA = 1, + Trigger = 2 + }; + }; +} + + +#define DO_ATHTPCNV_FACTORY_REGISTER_CNAME(name, serial) \ + _register_ ## _ ## serial + + +#ifdef __COVERITY__ +// Disable this in coverity --- otherwise, coverity warns about +// 'same value on both sides' in the if statements. +#define DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, cnv_type, signature, serial) +#else +#define DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, cnv_type, signature, serial) \ + namespace { \ + class DO_ATHTPCNV_FACTORY_REGISTER_CNAME(type, serial) { \ + public: \ + typedef type::Factory s_t; \ + typedef ::Gaudi::PluginService::Details::Factory<type> f_t; \ + static s_t::FuncType creator() { return &f_t::create<s_t>; } \ + DO_ATHTPCNV_FACTORY_REGISTER_CNAME(type, serial) () { \ + using ::Gaudi::PluginService::Details::Registry; \ + std::string prefix; \ + if (cnv_type == Athena::TPCnvType::ARA) \ + prefix = "_ARA"; \ + else if (cnv_type == Athena::TPCnvType::Trigger) \ + prefix = "_TRIG"; \ + Registry::instance().add<s_t, type>(id, creator()); \ + if (is_last_version == Athena::TPCnvVers::Current) \ + Registry::instance().add<s_t, type>(prefix + "_TRANS_" + #trans_type, creator()); \ + Registry::instance().add<s_t, type>(prefix + "_PERS_" + #pers_type, creator()); \ + } \ + } DO_ATHTPCNV_FACTORY_REGISTER_CNAME(s_ ## type, serial); \ + } +#endif + +#define DO_ATHTPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, cnv_type, signature, serial) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, ::Gaudi::PluginService::Details::demangle<type>(), trans_type, pers_type, is_last_version, cnv_type, signature, serial) + + + +#define ATHTPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, signature) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, Athena::TPCnvType::Athena, signature, __LINE__) +#define ARATPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, signature) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, Athena::TPCnvType::ARA, signature, __LINE__) +#define TRIGTPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, signature) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY(type, trans_type, pers_type, is_last_version, Athena::TPCnvType::Trigger, signature, __LINE__) + +#define ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, signature) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, Athena::TPCnvType::Athena, signature, __LINE__) +#define ARATPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, signature) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, Athena::TPCnvType::ARA, signature, __LINE__) +#define TRIGTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, signature) \ + DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(type, id, trans_type, pers_type, is_last_version, Athena::TPCnvType::Trigger, signature, __LINE__) + + + +//******************************************************************** +// Macros that users should use. +// + +#define DECLARE_TPCNV_FACTORY(x,trans_type,pers_type,is_last_version) \ + ATHTPCNV_PLUGINSVC_FACTORY(x,trans_type,pers_type,is_last_version,ITPCnvBase*()) + +#define DECLARE_ARATPCNV_FACTORY(x,trans_type,pers_type,is_last_version) \ + ARATPCNV_PLUGINSVC_FACTORY(x,trans_type,pers_type,is_last_version,ITPCnvBase*()) + +#define DECLARE_TRIGTPCNV_FACTORY(x,trans_type,pers_type,is_last_version) \ + TRIGTPCNV_PLUGINSVC_FACTORY(x,trans_type,pers_type,is_last_version,ITPCnvBase*()) + +#define DECLARE_NAMED_TPCNV_FACTORY(x,n,trans_type,pers_type,is_last_version) \ + ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID(x,std::string(#n), trans_type,pers_type, is_last_version, ITPCnvBase*()) + +#define DECLARE_NAMED_ARATPCNV_FACTORY(x,n,trans_type,pers_type,is_last_version) \ + ARATPCNV_PLUGINSVC_FACTORY_WITH_ID(x,std::string(#n), trans_type,pers_type, is_last_version, ITPCnvBase*()) + +#define DECLARE_NAMED_TRIGTPCNV_FACTORY(x,n,trans_type,pers_type,is_last_version) \ + TRIGTPCNV_PLUGINSVC_FACTORY_WITH_ID(x,std::string(#n), trans_type,pers_type, is_last_version, ITPCnvBase*()) + + + +#endif //> !ATHENAKERNEL_TPCNVFACTORY_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/TimeKeeper.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/TimeKeeper.h new file mode 100644 index 00000000..82083121 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/TimeKeeper.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_TIMEKEEPER_H +# define ATHENAKERNEL_TIMEKEEPER_H + +#include <string> + +#ifndef ATHENAKERNEL_ITIMEKEEPER_H + #include "AthenaKernel/ITimeKeeper.h" +#endif + +/** @class TimeKeeper + * @brief base class implementint the core TimeKeeper functionality for + * all systems. + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> + * $Id: TimeKeeper.h,v 1.4 2007-06-14 01:57:23 calaf Exp $ + */ + +class TimeKeeper : virtual public ITimeKeeper { +public: + /// ITimeKeeper Implementation + //@{ + virtual bool nextIter(); ///< main user entry point + virtual time_t timeL() const; ///< time remaining before limit + virtual time_t timeX() const = 0; ///< time used so far + virtual bool timeOver() const; ///< is there time for another iter? + //@} + + virtual time_t allocTime() const = 0; ///< allocated job CPU time + virtual void updateTime() = 0; ///< update time usage + virtual time_t averageIterTime() const; ///< moving average of iter time + virtual const std::string& unitLabel() const = 0; + +protected: + TimeKeeper(); + virtual ~TimeKeeper(); + +private: + unsigned int m_cycles; + time_t m_setupTime; + static const unsigned int SKIPCYCLES; //define job setup time +}; + +/// \name stream status +//@{ +class MsgStream; +MsgStream& operator << (MsgStream&, const TimeKeeper&); +#include <iostream> +std::ostream& operator << (std::ostream&, const TimeKeeper&); +//@} +#endif // ATHENAKERNEL_TIMEKEEPERSVC_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/Timeout.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/Timeout.h new file mode 100644 index 00000000..7b68a97a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/Timeout.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_TIMEOUT_H +#define ATHENAKERNEL_TIMEOUT_H 1 + +/** + * @file Timeout.h + * @brief Timeout singleton + * @author Frank Winklmeier + * + * $Id: Timeout.h,v 1.2 2008-12-09 16:48:42 fwinkl Exp $ + */ + +namespace Athena { + + // Forward declarations + class TimeoutMaster; + + /** + * @class Timeout + * @brief Singleton to access the timeout flag + * + * This singleton provides a global timeout flag. It can be set + * by the TimeoutMaster and algorithms, tools, etc. can query it + * in loops to react on the timeout signal. + */ + class Timeout { + /// Only classes derived from TimeoutMaster can modify timeout flag + friend class TimeoutMaster; + + public: + /// Get reference to Timeout singleton + static Timeout& instance(); + + /// Check if the timeout was reached + bool reached() const { return m_state; } + + private: + bool m_state; ///< Timeout flag + void set() { m_state = true; } ///< Set timeout flag + void reset() { m_state = false; } ///< Reset timeout flag + + // Prevent direct instantiation + Timeout() : m_state(false) {} + Timeout(Timeout&); + Timeout& operator=(const Timeout&); + }; + + // Meyers' singleton implementation + inline Timeout& Timeout::instance() { + static Timeout theInstance; + return theInstance; + } + + + + /** + * @class TimeoutMaster + * @brief Class to modify timeout flag + * + * Only classes inheriting from TimeoutMaster are allowed + * to modify the Timeout singleton. In practice, this should be + * the responsibility of the EventLoopMgr. + */ + class TimeoutMaster { + protected: + /// Set timeout + void setTimeout(Timeout& instance) { instance.set(); } + + /// Reset timeout + void resetTimeout(Timeout& instance) { instance.reset(); } + + /// Prevent direct instantiation + TimeoutMaster() {} + TimeoutMaster(TimeoutMaster&); + TimeoutMaster& operator=(const TimeoutMaster&); + }; + +} // namespace Athena + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/Units.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/Units.h new file mode 100644 index 00000000..264a2f7a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/Units.h @@ -0,0 +1,126 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/Units.h + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2015 + * @brief Wrapper to avoid constant divisions when using units. + * + * A typical use of the unit symbols is like + * + * double pt_in_gev = pt / GeV; + * + * However, writing it like this results in a division by a constant being + * generated. It would be faster to rewrite this as multiplication by the + * inverse, but the compiler won't do that by default as the results + * are not guaranteed to be the same. + * + * Using the symbols defined here allow avoiding the divisions + * (in optimized builds) without having to write the above explicitly + * as + * + * double pt_in_gev = pt * (1./GeV); + * + * which is pretty ugly. + * + * We do this by creating a static const object wrapping the value + * of the unit and overriding operator/ to change the division + * to multiplication by inverse. + */ + + +#ifndef ATHENAKERNEL_UNITS_H +#define ATHENAKERNEL_UNITS_H + + +#include "GaudiKernel/SystemOfUnits.h" +#include "GaudiKernel/PhysicalConstants.h" + + +namespace Athena { + + +/** + * @brief Wrapper to avoid constant divisions when using units. + */ +class Unit +{ +public: + constexpr Unit(double val) : m_val(val) {} + constexpr operator double() const { return m_val; } + +private: + double m_val; +}; + + +constexpr double operator/ (double x, const Unit& u) +{ + return x * (1./static_cast<double>(u)); +} + + +constexpr float operator/ (float x, const Unit& u) +{ + return x * (1./static_cast<float>(u)); +} + + +namespace Units { + + +// Would be nice to declare this constexpr, but can't in general +// because the symbols from SystemOfUnits aren't constexpr. +// +// Include a selection of units from SystemOfUnits.h +#define UNIT(NAME) /*constexpr*/ static const Unit NAME (Gaudi::Units::NAME) +UNIT (millimeter); +UNIT (millimeter2); +UNIT (millimeter3); +UNIT (centimeter); +UNIT (centimeter2); +UNIT (centimeter3); +UNIT (meter); +UNIT (meter2); +UNIT (meter3); +UNIT (micrometer); +UNIT (um); +UNIT (mm); +UNIT (mm2); +UNIT (mm3); +UNIT (cm); +UNIT (cm2); +UNIT (cm3); +UNIT (radian); +UNIT (degree); +UNIT (rad); +UNIT (deg); +UNIT (picosecond); +UNIT (nanosecond); +UNIT (microsecond); +UNIT (millisecond); +UNIT (second); +UNIT (ns); +UNIT (s); +UNIT (ms); +UNIT (keV); +UNIT (MeV); +UNIT (GeV); +UNIT (TeV); +UNIT (gram); +UNIT (g); +UNIT (mole); +UNIT (c_light); +#undef UNIT + + +} // namespace Units +} // namespace Athena + + +#endif // not ATHENAKERNEL_ATLASUNITS_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/errorcheck.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/errorcheck.h new file mode 100644 index 00000000..01d4cb71 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/errorcheck.h @@ -0,0 +1,492 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: errorcheck.h,v 1.6 2009-04-09 15:11:16 ssnyder Exp $ +/** + * @file errorcheck.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2006 + * @brief Helpers for checking error return status codes and reporting errors. + * + * A typical sequence of code for calling something in Atlas that + * returns a StatusCode looks something like this: + * + *@code + * StatusCode sc = something(); + * if (! sc.isSuccess() ) { + * log << "Some error message" << endmsg; + * return sc; + * } + @endcode + * + * This has several undesireable properties. First, it is overly verbose. + * 80% of the code in this example is devoted to error handling; if there + * are many of these, it becomes difficult to read what the code is + * actually doing. + * + * Second, there is no standardization of the error messages produced, + * and they are sometimes difficult to trace back to the actual offending + * source code. + * + * Third, code like this typically gets written by cut-and-paste, + * which is notoriously error-prone. + * + * This header defines some helpers to address these issues. + * + * For the simple case, you can use the macro @c CHECK. This macro + * encapsulates the actions shown in the example above; it could be + * rewritten as + * + *@code + * CHECK( something() ); + @endcode + * + * The error message produced by this will contain the text of the + * expression that failed, the failed @c StatusCode, the source file + * and line, the name of the containing function, and the + * algorithm/tool/service name. Note that in order to get this + * last name, the macro uses the @c this pointer; this means that this + * macro cannot be used in contexts where @c this is not available. + * In this case, use the macro @c CHECK_WITH_CONTEXT, which allows + * an explicit specification of the context name: + * + *@code + * CHECK_WITH_CONTEXT( something(), "algname" ); + @endcode + * + * In some cases, a simple check of the @c StatusCode is not enough and + * @c CHECK cannot be used. One can still avail oneself of the standardized + * error reporting provided here with the macro + * @c REPORT_ERROR, which takes a @c StatusCode as an argument. + * Additional text can be added with the output streaming operator, + * as for @c MsgStream. (No need to use @c endmsg.) + * + *@code + * StatusCode sc = something(); + * if ( ! sc.isSuccess() && ! failure_is_ok ) { + * REPORT_ERROR (sc) << "something()"; + * return sc; + * } + @endcode + * + * This will report the same kind of error as @c CHECK would. + * + * @c CHECK will return the failing status code to the caller and log the + * appropriate type of error message. If you need to control what gets + * returned to the caller, you can use @c CHECK_RECOVERABLE and + * @c CHECK_FATAL (and the corresponding @c _WITH_CONTEXT) versions. + * If these macros detect a failure, they always return a @c RECOVERABLE + * or @c FATAL status to the caller, respectively. In addition, + * @c CHECK_CODE and @c CHECK_CODE_WITH_CONTEXT may be used to return + * an arbitrary status code to the caller. + * + * Like @c CHECK, @c REPORT_ERROR requires that @c this be available. + * If this is not the case, then as before there is also a macro + * @c REPORT_ERROR_WITH_CONTEXT that takes the context name explicitly: + * + *@code + * StatusCode sc = something(); + * if ( ! sc.isSuccess() && ! failure_is_ok ) { + * REPORT_ERROR_WITH_CONTEXT (sc, "algname") << "something()"; + * return sc; + * } + @endcode + * + * In addition, there are @c REPORT_MESSAGE and @c REPORT_MESSAGE_WITH_CONTEXT + * macros. These do not take a @c StatusCode argument, but do take + * a logging level argument, so you can emit messages other than errors. + * Example: + * + *@code + * REPORT_MESSAGE (MSG::INFO) << "Something happened." + @endcode + * + * In the case where you want to change the source line, file, function, etc., + * from what's provided by default, you can instantiate an instance of + * @c errorcheck::ReportMessage directly. This may also be used + * if you need to use multiple statements to generate the output message. + * The message will be issued when then object is destroyed. Example: + * + *@code + * { + * errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "context"); + * msg << "testing "; + * for (int i=1; i<=3; i++) + * msg << i << " "; + * } + @endcode + */ + + +#ifndef ATHENAKERNEL_ERRORCHECK_H +#define ATHENAKERNEL_ERRORCHECK_H + + +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/IMessageSvc.h" +#include <string> + +class INamedInterface; + + +// Internal out-of-line functions go in this namespace. +namespace errorcheck { + + +/** + * @brief Return the context name from a context (@c this) pointer. + * @param context The context from which to get the name. + * @return The name of this context. + * + * This is the specialization for an @c INamedInterface. + */ +std::string context_name (const INamedInterface* context); + + +/** + * @brief Return the context name from a context (@c this) pointer. + * @param context The context from which to get the name. + * @return The name of this context. + * + * This is the specialization for an unknown context type; it returns + * a blank name. + */ +std::string context_name (const void* context); + + +/** + * @brief Helper class to use to report a message. + * To report a message, create an instance of this class. + * A standard header, containing the file/line, context name, + * and so forth, is automatically put at the start of the message. + * More text may be added using the standard @c MsgStream streaming + * operators. The message is actually emitted when this object + * is destroyed. + */ +class ReportMessage + : public MsgStream +{ +public: + /** + * @brief Constructor. + * @param level The error logging level for the message. + * @param line The source line from which the report is being made. + * @param file The source file name from which the report is being made. + * @param func The name of the function from which the report is being made. + * @param context The name of the context (algorithm/tool/service/etc.) + * from which the report is being made. + * @param sc The @c StatusCode to include in the error message. + */ + ReportMessage (MSG::Level level, + int line, + const char* file, + const char* func, + const std::string& context, + StatusCode sc); + + + /** + * @brief Constructor. + * @param level The error logging level for the message. + * @param line The source line from which the report is being made. + * @param file The source file name from which the report is being made. + * @param func The name of the function from which the report is being made. + * @param context The name of the context (algorithm/tool/service/etc.) + * from which the report is being made. + */ + ReportMessage (MSG::Level level, + int line, + const char* file, + const char* func, + const std::string& context); + + + /** + * @brief Destructor. + * This will cause the message to be emitted, if it hasn't already been. + */ + ~ReportMessage(); + + + /** + * @brief Emit the message. + * We override this method from @c MsgStream in order to fix up + * the message punctuation. + */ + virtual MsgStream& doOutput(); + + /** + * @brief Convert to a @c MsgStream reference. + * + * Trying to use a @c ReportMessage like + * + *@code + * ReportMessage(...) << "foo"; + @endcode + * + * doesn't work, because (as of Gaudi 19) the @c MsgStream inserters + * are written as free functions: + * + *@code + * MsgStream& operator<< (MsgStream&, ...); + @endcode + * + * and the non-const @c MsgStream reference won't bind to the temporary. + * We can work around this problem with this method, which will convert + * the temporary to a non-const reference. So, this should work: + * + *@code + * ReportMessage(...).stream() << "foo"; + @endcode + */ + MsgStream& msgstream() { return *this; } + + + /** + * @brief If set to true, hide the source file and line number + * in the output. + * + * This is intended for use in regression tests, where + * it's undesirable to have the output change if source lines + * are added or deleted. + */ + static void hideErrorLocus (bool flag = true); + + + /** + * @brief If set to true, hide function names in the output. + * in the output. + * + * This is intended for use in regression tests, where + * function names may be formatted differently on different + * platforms. + */ + static void hideFunctionNames (bool flag = true); + + +private: + /** + * @brief Generate the common header for messages. + * @param level The error logging level for the message. + * @param line The source line from which the report is being made. + * @param file The source file name from which the report is being made. + * @param func The name of the function from which the report is being made. + */ + void format_common (MSG::Level level, + int line, + const char* file, + const char* func); + + /// The position in the output message after the standard header. + std::string::size_type m_pos; + + /// If true, hide the source file and line number in output messages. + static bool s_hide_error_locus; + + /// If true, hide the function names in output messages. + static bool s_hide_function_names; +}; + + +} // namespace errorcheck + + +// Macro to get the current function name. +// Currently, this relies on a gcc extension, and will just return +// an empty string for another compiler. A similar mechanism (__func__) +// has been proposed for the next revision of the C++ standard (cf. n1642); +// if that makes it in, it can be used instead. +#if defined(__GNUC__) +# define ERRORCHECK_FNAME __PRETTY_FUNCTION__ +#else +# define ERRORCHECK_FNAME "" +#endif + + +// Collect all the arguments describing the source location: +// line number, file name, function name. +#define ERRORCHECK_ARGS __LINE__, __FILE__, ERRORCHECK_FNAME + + +/** + * @brief Report an error, with an explicitly specified context name. + * @param SC The @c StatusCode. + * @param CONTEXT_NAME The name of the current context. + * + * Additional text may be appended with the output stream operator. + */ +#define REPORT_ERROR_WITH_CONTEXT(SC, CONTEXT_NAME) \ + errorcheck::ReportMessage (MSG::ERROR, ERRORCHECK_ARGS, CONTEXT_NAME, SC) \ + . msgstream() + + +/** + * @brief Report a message, with an explicitly specified context name. + * @param LVL The error logging level. + * @param CONTEXT_NAME The name of the current context. + * + * Additional text may be appended with the output stream operator. + */ +#define REPORT_MESSAGE_WITH_CONTEXT(LVL, CONTEXT_NAME) \ + errorcheck::ReportMessage (LVL, ERRORCHECK_ARGS, CONTEXT_NAME).msgstream() + + +/** + * @brief Report an error. @c this must be available to get the context name. + * @param SC The @c StatusCode. + * + * Additional text may be appended with the output stream operator. + */ +#define REPORT_ERROR(SC) \ + REPORT_ERROR_WITH_CONTEXT(SC, errorcheck::context_name (this)) + + +/** + * @brief Report a message. @c this must be available to get the context name. + * @param LVL The error logging level. + * + * Additional text may be appended with the output stream operator. + */ +#define REPORT_MESSAGE(LVL) \ + REPORT_MESSAGE_WITH_CONTEXT(LVL, errorcheck::context_name (this)) + + +/** + * @brief Internal macro, used when a CHECK macro detects a failure. + * + * Output an appropriate error message and return the status object. + */ +#define CHECK_FAILED(EXP, CONTEXT_NAME, SC) do { \ + errorcheck::ReportMessage (SC.isRecoverable() ? \ + MSG::ERROR : \ + MSG::FATAL, \ + ERRORCHECK_ARGS, \ + CONTEXT_NAME, \ + SC) . msgstream() \ + << #EXP; \ + return SC; \ + } while(0) + + +/** + * @brief Evaluate an expression and check for errors, + * with an explicitly specified context name. + * @param EXP The expression to evaluate. + * @param CONTEXT_NAME The name of the current context. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and the failing @c StatusCode will be returned to the caller. + */ +#define CHECK_WITH_CONTEXT(EXP, CONTEXT_NAME) do { \ + StatusCode sc__ = (EXP); \ + if (! sc__.isSuccess()) \ + CHECK_FAILED(EXP, CONTEXT_NAME, sc__); \ + } while (0) + + +/** + * @brief Evaluate an expression and check for errors. + * @c this must be available to get the context name. + * @param EXP The expression to evaluate. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and the failing @c StatusCode will be returned to the caller. + */ +#define CHECK(EXP) CHECK_WITH_CONTEXT(EXP, errorcheck::context_name(this)) + + +/** + * @brief Evaluate an expression and check for errors, + * with an explicitly specified context name. + * @param EXP The expression to evaluate. + * @param CONTEXT_NAME The name of the current context. + * @param CODE The status code to return on failure. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and @c CODE will be returned to the caller. + */ +#define CHECK_CODE_WITH_CONTEXT(EXP, CONTEXT_NAME, CODE) do { \ + StatusCode sc__ = (EXP); \ + if (! sc__.isSuccess()) { \ + sc__ = CODE; \ + CHECK_FAILED(EXP, CONTEXT_NAME, sc__); \ + } \ + } while (0) + + +/** + * @brief Evaluate an expression and check for errors. + * @c this must be available to get the context name. + * @param EXP The expression to evaluate. + * @param CODE The status code to return on failure. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and @c CODE will be returned to the caller. + */ +#define CHECK_CODE(EXP, CODE) \ + CHECK_CODE_WITH_CONTEXT(EXP, errorcheck::context_name(this), CODE) + + +/** + * @brief Evaluate an expression and check for errors, + * with an explicitly specified context name. + * @param EXP The expression to evaluate. + * @param CONTEXT_NAME The name of the current context. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and @c RECOVERABLE will be returned to the caller. + */ +#define CHECK_RECOVERABLE_WITH_CONTEXT(EXP, CONTEXT_NAME) \ + CHECK_CODE_WITH_CONTEXT(EXP, CONTEXT_NAME, StatusCode::RECOVERABLE) + + +/** + * @brief Evaluate an expression and check for errors. + * @c this must be available to get the context name. + * @param EXP The expression to evaluate. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and @c RECOVERABLE will be returned to the caller. + */ +#define CHECK_RECOVERABLE(EXP) \ + CHECK_RECOVERABLE_WITH_CONTEXT(EXP, errorcheck::context_name(this)) + + +/** + * @brief Evaluate an expression and check for errors, + * with an explicitly specified context name. + * @param EXP The expression to evaluate. + * @param CONTEXT_NAME The name of the current context. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and @c FAILURE will be returned to the caller. + */ +#define CHECK_FATAL_WITH_CONTEXT(EXP, CONTEXT_NAME) \ + CHECK_CODE_WITH_CONTEXT(EXP, CONTEXT_NAME, StatusCode::FAILURE) + + +/** + * @brief Evaluate an expression and check for errors. + * @c this must be available to get the context name. + * @param EXP The expression to evaluate. + * + * This macro will evaluate @c EXP, which should return a @c StatusCode. + * If the status is not successful, then an error message will be produced, + * and @c FAILURE will be returned to the caller. + */ +#define CHECK_FATAL(EXP) \ + CHECK_FATAL_WITH_CONTEXT(EXP, errorcheck::context_name(this)) + + +#endif // not ATHENAKERNEL_ERRORCODE_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/getMessageSvc.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/getMessageSvc.h new file mode 100644 index 00000000..7ef7c3c7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/getMessageSvc.h @@ -0,0 +1,93 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_GETMESSAGESVC_H +#define ATHENAKERNEL_GETMESSAGESVC_H 1 +/** @file getMessageSvc.h + * @brief singleton-like access to IMessageSvc via open function and helper + * + * $Id: getMessageSvc.h,v 1.6 2008-07-14 22:10:14 calaf Exp $ + * @author Paolo Calafiura - Atlas collaboration + */ +#include <cassert> +#include <string> + +class IMessageSvc; +namespace Athena { + namespace Options { + enum CreateOptions { + Eager, + Lazy + }; + } + /** @fn IMessageSvc* getMessageSvc() + * @brief returns a pointer to the Gaudi IMessageSvc interface + * @param o : if o is @c Athena::Options::Eager it will create a + * @c MessageSvc instance if it is not there already. + * The default is to be lazy and don't create anything. + * @param quiet : do not print warning if MessagesSvc cannot be found (default false) + * + * Also used via weak-linking from DetCommon code (see e.g. TrigConf::MsgStream in DetCommon) + * DO NOT MODIFY THE SIGNATURE OF THESE METHODS WITHOUT UPDATING THE DETCOMMON SIDE !!! + */ + IMessageSvc* getMessageSvc( bool quiet=false ); + IMessageSvc* getMessageSvc( const Options::CreateOptions o, bool quiet=false ); + + /// Set this to force off the warning messages from getMessageSvc + /// (in unit tests, for example). + extern bool getMessageSvcQuiet; + + //@{ + /** Wrappers for some of the IMessageSvc methods + * These can be used from libraries without explicit Gaudi dependency via weak linking. + * (see e.g. TrigConf::MsgStream in DetCommon) + * + * DO NOT MODIFY THE SIGNATURE OF THESE METHODS WITHOUT UPDATING THE DETCOMMON SIDE !!! + */ + void reportMessage(IMessageSvc* ims, const std::string &source, int type, const std::string &message); + int outputLevel(IMessageSvc* ims, const std::string &source); + void setOutputLevel(IMessageSvc* ims, const std::string &source, int level); + //@} + + /** @class IMessageSvcHolder + * @brief get a IMessageSvc* on 1st use (if not set) and release it on ~ + */ + class IMessageSvcHolder { + public: + /// will take the IMessageSvc* lazily from getMessageSvc() in get() + /// Slow, but useful for classes without direct access to IMessageSvc* + IMessageSvcHolder() : m_ims() {} + + /// allows to get the IMessageSvc immediately + /// @param o: if o is @c Athena::Options::Eager it will create a + /// @c MessageSvc instance there and then. + IMessageSvcHolder(const Options::CreateOptions o); + + /// Not terribly useful per se, since one could simply use the + /// IMessageSvc* directly, but helps implementing + /// @class Athena::MsgStreamMember + /// Notice that when ~IMessageSvcHolder is called ims ref count will go + /// back to what it was before passing it to this constructor + IMessageSvcHolder(IMessageSvc *ims); + + /// behaves like the constructor taking an IMessageSvc * + IMessageSvcHolder(const IMessageSvcHolder&); + IMessageSvcHolder& operator=(const IMessageSvcHolder&); + + /// releases the IMessageSvc + ~IMessageSvcHolder(); + /// upon first access sets m_ims as needed + IMessageSvc* get() const; + /// conversion to IMessageSvc*, same as get + operator const IMessageSvc*() const { return this->get(); } + /// conversion to IMessageSvc*, same as get + operator IMessageSvc*() { return this->get(); } + private: + mutable IMessageSvc* m_ims; //mutable to have op() const + }; +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/selection.xml b/EDM/athena/Control/AthenaKernel/AthenaKernel/selection.xml new file mode 100644 index 00000000..ba01f919 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/selection.xml @@ -0,0 +1,23 @@ +<lcgdict> + + <class name="MsgStream" /> + <class name="IProxyDict" /> + <class name="IStringPool" /> + <class name="IEventSeek"/> + <class name="IEventShare"/> + <class name="ICollectionSize"/> + <class name="IAthenaSummarySvc"/> + <class name="errorcheck::ReportMessage"/> + <class name="ICutFlowSvc"/> + + <class name="ITPCnvSvc" /> + <class name="ITPCnvBase" /> + <class name="ILockable" /> + + <class name="Ath::DsoDb" /> + <class name="Ath::DsoDb::DsoMap_t" /> + + <function name="Athena::DsoUtils::inDso" /> + <function name="Athena::PackageInfo" /> + +</lcgdict> diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/sgkey_t.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/sgkey_t.h new file mode 100644 index 00000000..09798414 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/sgkey_t.h @@ -0,0 +1,36 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/sgkey_t.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Define the type used for hashed StoreGate key+CLID pairs. + * + * These are managed by @c IProxyDict. This definition was broken + * out from there due to dependency issues. + */ + + +#ifndef ATHENAKERNEL_SGKEY_T_H +#define ATHENAKERNEL_SGKEY_T_H + + +#include <stdint.h> + + +namespace SG { + + +/// Type used for hashed StoreGate key+CLID pairs. +typedef uint32_t sgkey_t; + + +} // namespace SG + + +#endif // not ATHENAKERNEL_SGKEY_T_H diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/tools/AthenaPackageInfo.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/tools/AthenaPackageInfo.h new file mode 100644 index 00000000..2656cd8a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/tools/AthenaPackageInfo.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_TOOLS_ATHENA_PACKAGEINFO_H +#define ATHENAKERNEL_TOOLS_ATHENA_PACKAGEINFO_H 1 + +#include <iostream> +#include <string> +class MsgStream; + +namespace Athena { + +/** + * @class PackageInfo + * @author Paolo Calafiura + * @brief decodes cmt PACKAGE_VERSION macro + * + * FIXME class works fine technically, but it does not satisfy + * the use case it was designed for, namely to add package information + * to the ClassID_traits definition in SGTools/CLASS_DEF.h + * + * $Id: AthenaPackageInfo.h,v 1.4 2007-12-14 01:58:50 binet Exp $ + */ + + class PackageInfo { + private: + std::string m_name; + std::string m_version; + public: + /** + * @brief construct PackageInfo from cmt-generated PACKAGE_VERSION #define + * @param a string of the form PACKAGE-XX-YY-NN + * @throws invalid_argument + */ + PackageInfo(const std::string& cmtPackageVersion); + PackageInfo() : m_name(), m_version() {} + const std::string& name() const { return m_name; } + const std::string& version() const { return m_version; } + }; +} + +MsgStream& +operator << (MsgStream& ost, const Athena::PackageInfo& info); + +std::ostream& +operator << (std::ostream& ost, const Athena::PackageInfo& info); + +inline +bool +operator == (const Athena::PackageInfo& lhs, const Athena::PackageInfo& rhs) { + return ( (lhs.name() == rhs.name()) && (lhs.version() == rhs.version()) ); +} +inline +bool +operator != (const Athena::PackageInfo& lhs, const Athena::PackageInfo& rhs) { + return !(lhs == rhs); +} +inline +bool +operator < (const Athena::PackageInfo& lhs, const Athena::PackageInfo& rhs) { + return ( (lhs.name() < rhs.name()) || + ( (lhs.name() == rhs.name()) && (lhs.version() < rhs.version()) ) ); +} + +#endif diff --git a/EDM/athena/Control/AthenaKernel/AthenaKernel/tools/type_tools.h b/EDM/athena/Control/AthenaKernel/AthenaKernel/tools/type_tools.h new file mode 100644 index 00000000..4e5d98b4 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/AthenaKernel/tools/type_tools.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_TOOLS_TYPE_TOOLS_H +#define ATHENAKERNEL_TOOLS_TYPE_TOOLS_H +#ifndef BOOST_CONFIG_HPP + #include <boost/config.hpp> +#endif +#ifndef BOOST_TT_OBJECT_TRAITS_HPP_INLCUDED + #include <boost/type_traits/object_traits.hpp> +#endif +#ifndef BOOST_TT_TRANSFORM_TRAITS_HPP_INCLUDED + #include <boost/type_traits/transform_traits.hpp> +#endif +#ifndef SELECT_TYPE_DWA20010206_HPP + #include <boost/detail/select_type.hpp> +#endif + +namespace type_tools { + ///assign a type to an integer value + template <int v> + struct Int2Type { + enum { value = v }; + }; + + typedef Int2Type<1> true_tag; + typedef Int2Type<0> false_tag; + + + /** + * @class Parameter + * @brief an algorithm to provide an efficient way to pass a parameter: + * by value for scalars (arithmetic types and pointers), + * by reference for compound objects.Derived from Loki library + * @author Paolo Calafiura + * + */ + + template <typename T> + struct Parameter { + private: + typedef typename boost::add_reference<T>::type TRef; + typedef const TRef const_TRef; + BOOST_STATIC_CONSTANT(bool, isScalar = boost::is_scalar<T>::value); + public: + typedef typename boost::detail::if_true<(isScalar)>::template + then< + T, + //else + TRef + >::type ref_type; + + typedef typename boost::detail::if_true<(isScalar)>::template + then< + T, + //else + const T& + //FIXME const_TRef + >::type const_type; + + typedef typename boost::detail::if_true<(isScalar)>::template + then< + T, + //else + T* + >::type ptr_type; + + typedef const_type type; + }; + + + /** + * @class Copy + * @brief an algorithm to define a suitable "copy type": + * by default use copy-by-value + * @author Paolo Calafiura + * + */ + template <typename T> + struct Copy { + typedef T type; + typedef const T& const_reference; + typedef const T* const_pointer; + }; + + /// when T is pointer we "copy" into a const T* + template <typename T> + struct Copy<T*> { + typedef const T* type; + typedef const T* const_reference; + typedef const T* const* const_pointer; + }; +} +#endif + diff --git a/EDM/athena/Control/AthenaKernel/CMakeLists.txt b/EDM/athena/Control/AthenaKernel/CMakeLists.txt new file mode 100644 index 00000000..444b4172 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/CMakeLists.txt @@ -0,0 +1,92 @@ +# $Id: CMakeLists.txt 787829 2016-12-02 10:10:58Z krasznaa $ +################################################################################ +# Package: AthenaKernel +################################################################################ + +# Declare the package name: +atlas_subdir( AthenaKernel ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/CxxUtils + Control/DataModelRoot + GaudiKernel + PRIVATE + AtlasTest/TestTools ) + +# External dependencies: +find_package( Boost COMPONENTS program_options regex filesystem thread ) +find_package( ROOT COMPONENTS Core ) +find_package( UUID ) + +# Only link agains the RT library on Linux: +set( rt_library ) +if( UNIX AND NOT APPLE ) + set( rt_library rt ) +endif() + +# Libraries in the package: +atlas_add_library( AthenaKernel + AthenaKernel/*.h AthenaKernel/*.icc src/*.cxx + PUBLIC_HEADERS AthenaKernel + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot + GaudiKernel ${rt_library} + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ) + +atlas_add_dictionary( AthenaKernelDict + AthenaKernel/AthenaKernelDict.h + AthenaKernel/selection.xml + LINK_LIBRARIES GaudiKernel AthenaKernel ) + +# Test(s) in the package: +atlas_add_test( getMessageSvc_test + SOURCES test/getMessageSvc_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthenaKernel + EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" ) + +atlas_add_test( MsgStreamMember_test + SOURCES test/MsgStreamMember_test.cxx + LINK_LIBRARIES TestTools AthenaKernel + EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time |ref count" ) + +atlas_add_test( AthenaPackageInfo_test + SOURCES test/AthenaPackageInfo_test.cxx + LINK_LIBRARIES AthenaKernel ) + +atlas_add_test( DirSearchPath_test + SOURCES test/DirSearchPath_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} GaudiKernel ) + +atlas_add_test( Chrono_test + SOURCES test/Chrono_test.cxx + LINK_LIBRARIES GaudiKernel AthenaKernel ) + +atlas_add_test( errorcheck_test + SOURCES test/errorcheck_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthenaKernel + EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" ) + +atlas_add_test( type_tools_test + SOURCES test/type_tools_test.cxx + LINK_LIBRARIES AthenaKernel ) + +atlas_add_test( Units_test + SOURCES test/Units_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthenaKernel ) + +atlas_add_test( DataObjectSharedPtr_test + SOURCES test/DataObjectSharedPtr_test.cxx + LINK_LIBRARIES AthenaKernel ) + +atlas_add_test( IRCUSvc_test + SOURCES test/IRCUSvc_test.cxx + LINK_LIBRARIES AthenaKernel ) + +atlas_add_test( RCUObject_test + SOURCES test/RCUObject_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} AthenaKernel ) diff --git a/EDM/athena/Control/AthenaKernel/cmt/requirements b/EDM/athena/Control/AthenaKernel/cmt/requirements new file mode 100644 index 00000000..b741604a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/cmt/requirements @@ -0,0 +1,66 @@ +package AthenaKernel +author Paolo Calafiura <pcalafiura@lbl.gov> + +use AtlasPolicy AtlasPolicy-* +use uuid v* LCG_Interfaces +use GaudiInterface GaudiInterface-* External +use DataModelRoot DataModelRoot-* Control +# for SG::unordered_map --> move to STL when available +use CxxUtils CxxUtils-* Control +#for type_tools.h +use AtlasBoost AtlasBoost-* External + +# Add cmake compatibility (doesn't do anything on CMT side of things) +apply_pattern cmake_add_command command="find_package(Boost COMPONENTS program_options regex)" +apply_pattern cmake_add_libraries target=AthenaKernel libraries=rt + +#use Scripts to ensure that get_files will be seen by all packages +use Scripts Scripts-* Tools -no_auto_imports + +library AthenaKernel *.cxx +apply_pattern installed_library + +private +# for TClassEdit +use AtlasROOT AtlasROOT-* External +end_private + +#apply_pattern declare_python_modules files="*.py" + +#DirSearchPath uses boost::filesystem +macro_append Boost_linkopts "$(Boost_linkopts_filesystem) $(Boost_linkopts_system) $(Boost_linkopts_regex) " + +private +use TestTools TestTools-* AtlasTest + +# This ignores differences between gaudi 16 & 19. +macro extrapatterns "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" + +apply_pattern UnitTest_run unit_test=getMessageSvc extrapatterns="'$(extrapatterns)'" +apply_pattern UnitTest_run unit_test=MsgStreamMember extrapatterns="$(extrapatterns) |ref count" +apply_pattern UnitTest_run unit_test=AthenaPackageInfo +apply_pattern UnitTest_run unit_test=DirSearchPath +apply_pattern UnitTest_run unit_test=Chrono +apply_pattern UnitTest_run unit_test=errorcheck extrapatterns="'$(extrapatterns)'" +apply_pattern UnitTest_run unit_test=type_tools +apply_pattern UnitTest_run unit_test=Units +apply_pattern UnitTest_run unit_test=DataObjectSharedPtr +apply_pattern UnitTest_run unit_test=IRCUSvc +apply_pattern UnitTest_run unit_test=RCUObject + +macro_append DOXYGEN_INPUT " ../doc ../test ../AthenaKernel/tools " +macro_append DOXYGEN_FILE_PATTERNS " *.icc" + +# +# dictionary creation for UserDataAssociation +# + +use AtlasReflex AtlasReflex-* External +apply_pattern lcgdict dict=AthenaKernel \ + selectionfile="selection.xml" \ + headerfiles="../AthenaKernel/AthenaKernelDict.h" + +macro_append libraryshr_linkopts "" \ + Linux " -Wl,-lrt " + +end_private diff --git a/EDM/athena/Control/AthenaKernel/doc/MainPage.h b/EDM/athena/Control/AthenaKernel/doc/MainPage.h new file mode 100644 index 00000000..484c6605 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/doc/MainPage.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + + @mainpage AthenaKernel +This package is the repository for interfaces to ATLAS components of general interest. The package also contains tools to implement those interfaces, e.g. +service base classes and simple utilities which do not depend on other packages. +It can be seen as an extension of GaudiKernel. + +@htmlinclude used_packages.html + +@section Tests Unit Tests + - AthenaPackageInfo_test.cxx + - errorcheck_test.cxx + - getMessageSvc_test.cxx + - type_tools_test.cxx + + +@section reqs CMT requirements file +@include requirements + +@section Refs More Documentation + +More information is available from the Athena wiki +(https://twiki.cern.ch/twiki/bin/view/Atlas/AthenaFramework). + +The code can be browsed using LXR +(http://alxr.usatlas.bnl.gov/lxr/source/atlas/Control/AthenaKernel/) + + +@author Paolo Calafiura <Paolo.Calafiura@cern.ch> + +*/ diff --git a/EDM/athena/Control/AthenaKernel/share/AthenaPackageInfo_test.ref b/EDM/athena/Control/AthenaKernel/share/AthenaPackageInfo_test.ref new file mode 100644 index 00000000..b47a79c9 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/AthenaPackageInfo_test.ref @@ -0,0 +1,29 @@ +*** AthenaPackageInfo_test OK *** +Now we expect to see an error message: +----Error Message Starts--->> +PackageInfo::PackageInfo(BaD): invalid argument +PackageInfo should be constructed passing a string of the form PACKAGE-VERSION. +Usually this error occurs because CMT can not determine the version of your package. Please make sure that there is a version.cmt file in the cmt directory of your package and that version.cmt contains a single line of the form +MyPackage-01-02-03 +Notice that version.cmt is created automatically by CMT when you use 'cmt co' + +<<----Error Message Ends----- +Now we expect to see an error message: +----Error Message Starts--->> +PackageInfo::PackageInfo(BaD-): invalid argument +PackageInfo should be constructed passing a string of the form PACKAGE-VERSION. +Usually this error occurs because CMT can not determine the version of your package. Please make sure that there is a version.cmt file in the cmt directory of your package and that version.cmt contains a single line of the form +MyPackage-01-02-03 +Notice that version.cmt is created automatically by CMT when you use 'cmt co' + +<<----Error Message Ends----- +Now we expect to see an error message: +----Error Message Starts--->> +PackageInfo::PackageInfo(-BaD): invalid argument +PackageInfo should be constructed passing a string of the form PACKAGE-VERSION. +Usually this error occurs because CMT can not determine the version of your package. Please make sure that there is a version.cmt file in the cmt directory of your package and that version.cmt contains a single line of the form +MyPackage-01-02-03 +Notice that version.cmt is created automatically by CMT when you use 'cmt co' + +<<----Error Message Ends----- +*** AthenaPackageInfo_test OK *** diff --git a/EDM/athena/Control/AthenaKernel/share/Chrono_test.ref b/EDM/athena/Control/AthenaKernel/share/Chrono_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/Chrono_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthenaKernel/share/DataObjectSharedPtr_test.ref b/EDM/athena/Control/AthenaKernel/share/DataObjectSharedPtr_test.ref new file mode 100644 index 00000000..7e425e6d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/DataObjectSharedPtr_test.ref @@ -0,0 +1,3 @@ +test1 +should call dtor now +MyObj dtor diff --git a/EDM/athena/Control/AthenaKernel/share/DirSearchPath_test.ref b/EDM/athena/Control/AthenaKernel/share/DirSearchPath_test.ref new file mode 100644 index 00000000..6b56f0f7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/DirSearchPath_test.ref @@ -0,0 +1,2 @@ +*** DirSearchPath_test Starts *** +*** DirSearchPath_test OK *** diff --git a/EDM/athena/Control/AthenaKernel/share/IRCUSvc_test.ref b/EDM/athena/Control/AthenaKernel/share/IRCUSvc_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/IRCUSvc_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/AthenaKernel/share/MsgStreamMember_test.ref b/EDM/athena/Control/AthenaKernel/share/MsgStreamMember_test.ref new file mode 100644 index 00000000..2b775458 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/MsgStreamMember_test.ref @@ -0,0 +1,30 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr $Revision: 1.77 $ + running on lxplus251.cern.ch on Sat Oct 23 02:26:38 2010 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis... INFO 'CnvServices':[ 'HbookHistSvc' , 'RootHistSvc' ] +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +Initial message svc ref count 11 +Mine SUCCESS *** Mine works *** +Yours SUCCESS *** Yours works too *** +Hers SUCCESS *** reporting *** +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Foo SUCCESS bla +Wall clock time to create a MsgStreamMember (microsec)4.678 +Wall clock time to print bla using MsgStreamMember (microsec)17 +Final ref count 1013 +*** MsgStreamMember_test OK *** diff --git a/EDM/athena/Control/AthenaKernel/share/RCUObject_test.ref b/EDM/athena/Control/AthenaKernel/share/RCUObject_test.ref new file mode 100644 index 00000000..76983460 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/RCUObject_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/EDM/athena/Control/AthenaKernel/share/Units_test.ref b/EDM/athena/Control/AthenaKernel/share/Units_test.ref new file mode 100644 index 00000000..0844baf7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/Units_test.ref @@ -0,0 +1,2 @@ +test1 +divcheck diff --git a/EDM/athena/Control/AthenaKernel/share/errorcheck_test.ref b/EDM/athena/Control/AthenaKernel/share/errorcheck_test.ref new file mode 100644 index 00000000..dffdcd34 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/errorcheck_test.ref @@ -0,0 +1,37 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v2r1) + running on lxplus0023 on Thu Feb 20 14:48:29 2014 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +alg ERROR ../test/errorcheck_test.cxx:153 (StatusCode test1()): code 0: foomsg +alg INFO ../test/errorcheck_test.cxx:155 (StatusCode test1()): some message +alg INFO ../test/errorcheck_test.cxx:158 (StatusCode test1()): a... b +alg INFO ../test/errorcheck_test.cxx:162 (StatusCode test1()): foo +alg FATAL ../test/errorcheck_test.cxx:102 (StatusCode test1a()): code 0: StatusCode (StatusCode::FAILURE) +alg ERROR ../test/errorcheck_test.cxx:110 (StatusCode test1b()): code 2: StatusCode (StatusCode::FAILURE) +alg ERROR ../test/errorcheck_test.cxx:118 (StatusCode test1c()): code 2: StatusCode (StatusCode::RECOVERABLE) +alg FATAL ../test/errorcheck_test.cxx:126 (StatusCode test1d()): code 0: StatusCode (StatusCode::FAILURE) +alg FATAL ../test/errorcheck_test.cxx:134 (StatusCode test1e()): code 0: StatusCode (StatusCode::RECOVERABLE) +alg FATAL ../test/errorcheck_test.cxx:142 (StatusCode test1f()): code 123: StatusCode (StatusCode::RECOVERABLE) +algname ERROR ../test/errorcheck_test.cxx:34 (StatusCode Algtest::test1()): code 0: foomsg +algname INFO ../test/errorcheck_test.cxx:35 (StatusCode Algtest::test1()): some info +algname FATAL ../test/errorcheck_test.cxx:37 (StatusCode Algtest::test1()): code 0: StatusCode (StatusCode::FAILURE) +toolname ERROR ../test/errorcheck_test.cxx:54 (StatusCode Algtooltest::test1()): code 0: foomsg +toolname INFO ../test/errorcheck_test.cxx:55 (StatusCode Algtooltest::test1()): some info +toolname FATAL ../test/errorcheck_test.cxx:57 (StatusCode Algtooltest::test1()): code 123: StatusCode (StatusCode::RECOVERABLE) +servname ERROR ../test/errorcheck_test.cxx:74 (StatusCode Servtest::test1()): code 0: foomsg +servname INFO ../test/errorcheck_test.cxx:75 (StatusCode Servtest::test1()): some info +servname ERROR ../test/errorcheck_test.cxx:77 (StatusCode Servtest::test1()): code 2: StatusCode (StatusCode::FAILURE) + ERROR ../test/errorcheck_test.cxx:91 (StatusCode Test::test1()): code 0: foomsg + INFO ../test/errorcheck_test.cxx:92 (StatusCode Test::test1()): some info + FATAL ../test/errorcheck_test.cxx:94 (StatusCode Test::test1()): code 0: StatusCode (StatusCode::RECOVERABLE) +alg ERROR FILE:LINE (StatusCode test1()): code 0: foox +alg ERROR ../test/errorcheck_test.cxx:178 (StatusCode test1()): code 0: fooy +test2 INFO ../test/errorcheck_test.cxx:194 (void test2(std::vector<int>, const int*, int (*)(), int*)): test2 +test3 INFO ../test/errorcheck_test.cxx:203 (void test3(const std::string&, int)): test3 diff --git a/EDM/athena/Control/AthenaKernel/share/getMessageSvc_test.ref b/EDM/athena/Control/AthenaKernel/share/getMessageSvc_test.ref new file mode 100644 index 00000000..251cc441 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/share/getMessageSvc_test.ref @@ -0,0 +1,15 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr $Revision: 1.3 $ + running on lxplus231.cern.ch on Thu Jul 10 20:48:35 2008 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis... INFO 'CnvServices':[ 'HbookHistSvc' , 'RootHistSvc' ] +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +Mine SUCCESS *** Mine works *** +Yours SUCCESS *** Yours works too *** +getMessageSvc_testSUCCESS *** getMessageSvc_test OK *** diff --git a/EDM/athena/Control/AthenaKernel/share/type_tools_test.ref b/EDM/athena/Control/AthenaKernel/share/type_tools_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/AthenaKernel/src/AddressProviderSvc.cxx b/EDM/athena/Control/AthenaKernel/src/AddressProviderSvc.cxx new file mode 100644 index 00000000..0a3637d5 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/AddressProviderSvc.cxx @@ -0,0 +1,9 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/AddressProviderSvc.h" + +// a dummy place holder +void AddressProviderSvc::dummy() +{ } diff --git a/EDM/athena/Control/AthenaKernel/src/AlgorithmTimer.cxx b/EDM/athena/Control/AthenaKernel/src/AlgorithmTimer.cxx new file mode 100644 index 00000000..ad1e4da4 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/AlgorithmTimer.cxx @@ -0,0 +1,289 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file TrigTimeAlgs/AlgorithmTimer.cxx + * @brief Efficient realtime timers + * @author Frank Winklmeier (based on AthenaKernel/Algorithmtimer by W. Lavrijsen, S. Binet) + * + * $Id: AlgorithmTimer.cxx,v 1.3 2009-05-14 16:58:21 dquarrie Exp $ + */ + +#include "AthenaKernel/AlgorithmTimer.h" + +// Gaudi includes +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/Incident.h" + +// Athena includes +#include "AthenaKernel/ICoreDumpSvc.h" +#include "AthenaKernel/getMessageSvc.h" + +// #include "Utils.h" +#include <dlfcn.h> +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> + +// STL includes +#include <iostream> +#include <sstream> +#include <algorithm> +#include <string> + +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> + +#ifdef __APPLE__ +#endif + +using namespace Athena; + +// Statics +bool AlgorithmTimer::s_handlerInstalled = false; +struct sigaction AlgorithmTimer::s_oldSigHandler; +std::list<AlgorithmTimer*> AlgorithmTimer::s_registry; + +namespace Athena { + namespace AlgorithmTimerHandler + { + /** + * @brief Signal handler for AlgorithmTimer + * + * This is the signal handler registered by the first instance of AlgorithmTimer. + * On invocation the siginfo_t struct carries a pointer to the actual + * instance. The onAlarm function is made a friend of AlgorithmTimer, therefore + * it can access all relevant information. + */ + void onAlarmSignal(int sig, siginfo_t *info, void* extra) + { + /* + * Check if the signal is coming from a AlgorithmTimer instance. + */ + AlgorithmTimer* me = static_cast<AlgorithmTimer*>(info->si_value.sival_ptr); + std::list<AlgorithmTimer*>::iterator iter = find(AlgorithmTimer::s_registry.begin(), + AlgorithmTimer::s_registry.end(), + me); + + /* + * If signal from AlgorithmTimer, call user-defined callback + */ + if ( iter != AlgorithmTimer::s_registry.end() ) + { + std::cout.flush(); + std::cerr.flush(); + me->m_onAlarm(); + } + + /* + * Call old signal handler + * Need to distinguish between the two types of signal handlers + */ + if (AlgorithmTimer::s_oldSigHandler.sa_flags & SA_SIGINFO) + { + if (AlgorithmTimer::s_oldSigHandler.sa_sigaction) + AlgorithmTimer::s_oldSigHandler.sa_sigaction(sig,info,extra); + } + else + { + if (AlgorithmTimer::s_oldSigHandler.sa_handler) + AlgorithmTimer::s_oldSigHandler.sa_handler(sig); + } + } + + /** + * @brief Function called by signals delivered via threads + */ + void onAlarmThread(sigval_t sv) + { + AlgorithmTimer* me = static_cast<AlgorithmTimer*>(sv.sival_ptr); + me->m_onAlarm(); + } + } +} + +//-------------------------------------------------------------------------------- +// AlgorithmTimer +//-------------------------------------------------------------------------------- + +AlgorithmTimer::AlgorithmTimer(unsigned int milliseconds, + callbackFct_t callback, + AlgorithmTimerConfig conf) : + m_timeout (0), + m_timerid(), + m_onAlarm(callback), + m_gdb_details (0) +{ + // prevent valgrind warning + // new warning popped up, needs new glibc for this, see http://bugs.kde.org/show_bug.cgi?id=124478 + // possibly valgrind will be fixed, eventually. + std::memset (&m_sigevent, 0, sizeof (m_sigevent)); + + m_sigevent.sigev_value.sival_ptr = this; + + if (m_onAlarm == NULL) + m_onAlarm = boost::bind(&AlgorithmTimer::abortJob,this); + + if ( conf & DELIVERYBYTHREAD ) { + m_sigevent.sigev_notify = SIGEV_THREAD; + m_sigevent.sigev_signo = 0; + m_sigevent.sigev_notify_function = AlgorithmTimerHandler::onAlarmThread; + m_sigevent.sigev_notify_attributes = NULL; + } else { + m_sigevent.sigev_notify = SIGEV_SIGNAL; + m_sigevent.sigev_signo = SIGNO; + + /* + * The signal handler uses this list to make sure the signal + * indeed came from an AlgorithmTimer and not from somewhere else. + */ + s_registry.push_back(this); + + /* + * Use the same signal handler for all AlgorithmTimer instances. + * For performance reasons the signal handler stays active + * even after all AlgorithmTimer instances are deleted. + */ + if ( !s_handlerInstalled ) + installSignalHandler(); + + } + + // Create the timer + if ( conf & USEREALTIME ) + { +#ifndef __APPLE__ + timer_create(CLOCK_REALTIME, &m_sigevent, &m_timerid); +#endif + } + else + { + /* + * can use virtual time only, if defined on this system + */ +#ifndef __APPLE__ +#ifdef _POSIX_CPUTIME + timer_create(_POSIX_CPUTIME, &m_sigevent, &m_timerid); +#else + timer_create(CLOCK_REALTIME, &m_sigevent, &m_timerid); + std::cerr << "\nNo _POSIX_CPUTIME defined on this system !\n\n"; + // we could also disable this timer in this case ! + // seconds = 0; +#endif +#endif + } + // Start the timer if requested + if(milliseconds) + start(milliseconds); +} + +AlgorithmTimer::~AlgorithmTimer() +{ +#ifndef __APPLE__ + timer_delete(m_timerid); +#endif + s_registry.remove(this); +} + +void AlgorithmTimer::start(unsigned int milliseconds) +{ + // Set the timer + m_timeout = milliseconds; +#ifndef __APPLE__ + itimerspec spec; + spec.it_value.tv_sec = int(m_timeout/1000); + spec.it_value.tv_nsec = 1000000*(m_timeout%1000); + spec.it_interval.tv_sec = 0; + spec.it_interval.tv_nsec = 0; + + timer_settime(m_timerid, 0, &spec, NULL); +#endif +} + +void AlgorithmTimer::start(ScopedTimer& scope) +{ + scope.m_timer = this; + start(scope.m_timeout); +} + +unsigned int AlgorithmTimer::stop() +{ + // stop the timer, and retrieve remaining time +#ifndef __APPLE__ + itimerspec spec; + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = 0; + spec.it_interval.tv_sec = 0; + spec.it_interval.tv_nsec = 0; + + itimerspec ovalue; + timer_settime(m_timerid, 0, &spec, &ovalue); + return 1000*ovalue.it_value.tv_sec + int(ovalue.it_value.tv_nsec/1000000); +#else + return 0; +#endif +} + +unsigned int AlgorithmTimer::timeLeft() const +{ +#ifndef __APPLE__ + itimerspec spec; + timer_gettime( m_timerid, &spec ); + return 1000*spec.it_value.tv_sec + int(spec.it_value.tv_nsec/1000000); +#else + return 0; +#endif +} + +bool AlgorithmTimer::installSignalHandler() +{ + if (s_handlerInstalled) return true; + + // Install new signal handler and backup old one + struct sigaction sigact; + memset (&sigact, 0, sizeof(sigact)); // quiet coverity + sigact.sa_sigaction = AlgorithmTimerHandler::onAlarmSignal; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_SIGINFO; + int ret = sigaction(SIGNO, &sigact, &s_oldSigHandler); + + s_handlerInstalled = (ret == 0); + return s_handlerInstalled; +} + +/* + * This is currently not being used, but we'll leave it here + * for future reference. + */ +bool AlgorithmTimer::uninstallSignalHandler() +{ + if (!s_handlerInstalled) return true; + + int ret = sigaction(SIGNO, &s_oldSigHandler, 0); + + s_handlerInstalled = !(ret==0); + return (ret==0); +} + +AlgorithmTimer::callbackFct_t AlgorithmTimer::abortJob() +{ + /* + * Print stack trace and abort the job. + */ + std::ostringstream os; + os << "Timeout "; + os << " (" << this->timeout() << " msec) reached"; + + ServiceHandle<ICoreDumpSvc> coreDumpSvc("CoreDumpSvc", "AlgorithmTimer"); + if ( coreDumpSvc.retrieve().isSuccess() ) + { + coreDumpSvc->setCoreDumpInfo("Reason", os.str()); + std::cerr << coreDumpSvc->dump() << std::endl; + } + else + { + std::cerr << os.str() << std::endl; + } + abort(); +} diff --git a/EDM/athena/Control/AthenaKernel/src/AthDsoUtils.cxx b/EDM/athena/Control/AthenaKernel/src/AthDsoUtils.cxx new file mode 100644 index 00000000..26de18db --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/AthDsoUtils.cxx @@ -0,0 +1,139 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// @file DsoUtils.h +/// @brief A mixed bag of "portable" utils for DSO (Dynamic Shared Objects) +/// @author S.Binet <binet@cern.ch> +/// @author Markus Frank <Markus.Frank@cern.ch> (Win32 code) +// note: This, I believe, should be part of Reflex::SharedLibrary + +// STL includes +#include <string.h> +#include <string> + +#include "GaudiKernel/System.h" +#include "AthenaKernel/AthDsoUtils.h" + +namespace Athena { +namespace DsoUtils { + +inline +std::string +libNativeName( const std::string& libName ) +{ +#if defined(_WIN32) + return libName+".dll"; +#elif defined(__linux) || defined(__APPLE__) + return "lib"+libName+".so"; +#else + // variant of the GIGO design pattern + return libName; +#endif +} + +#if ROOT_VERSION_CODE < ROOT_VERSION(5,99,0) + +#ifdef _GNU_SOURCE +#include <dlfcn.h> +static +std::string +dsoName( const ROOT::Reflex::Member& mem ) +{ + Dl_info info; + if (dladdr ( +#if __GNUC__ < 4 + (void*)mem.Stubfunction() +#else + System::FuncPtrCast<void*>(mem.Stubfunction()) +#endif + , &info) == 0) + return ""; + + const char* pos = strrchr (info.dli_fname, '/'); + if (pos) + ++pos; + else + pos = info.dli_fname; + return pos; +} +#elif defined(_WIN32) +#include <windows.h> + +static +std::string +dsoName( const ROOT::Reflex::Member& mem ) +{ + void* addr = (void*)(mem.Stubfunction()); + if (addr) { + MEMORY_BASIC_INFORMATION mbi; + if ( VirtualQuery(addr, &mbi, sizeof(mbi)) ) { + HMODULE h_module = (HMODULE)mbi.AllocationBase; + char mod[1024]; + if( GetModuleFileName(h_module, mod, sizeof(mod)) ) { + const char* pos = strrchr (mod, '\\'); + if (pos) + ++pos; + else + pos = mod; + return pos; + } + } + } + return ""; +} + +#else // dummy implementation for unknown platforms +static std::string dsoName( const ROOT::Reflex::Member& ) +{ + return ""; +} + +#endif + +#else // ROOT ver + +static +std::string +dsoName( const RootDataMember& mem ) +{ + const char *lib = mem.GetSharedLibs(); + return lib? lib : ""; +} + +#endif //ROOT ver + +bool +inDso( const RootDataMember& mem, + const std::string& dsoname ) +{ +#ifdef _WIN32 + char sep = '\\'; +#else + char sep = '/'; +#endif + + std::string srcname = dsoName(mem); + if (srcname.empty()) { + // we do not know the name of the library, let's guess it's OK + return true; + } + + std::string::size_type pos = dsoname.find_last_of(sep); + std::string curname; + if (std::string::npos == pos) { + curname = dsoname; + } else { + curname = dsoname.substr(pos+1); + } + + return srcname == curname; +} + +} // end namespace DsoUtils + +} // end namespace Athena + + diff --git a/EDM/athena/Control/AthenaKernel/src/AthenaPackageInfo.cxx b/EDM/athena/Control/AthenaKernel/src/AthenaPackageInfo.cxx new file mode 100644 index 00000000..97e7c63d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/AthenaPackageInfo.cxx @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <iostream> +#include <stdexcept> + +#include "GaudiKernel/MsgStream.h" + +#include "AthenaKernel/tools/AthenaPackageInfo.h" +using Athena::PackageInfo; + +using namespace std; + +PackageInfo::PackageInfo(const string& cmtPackageVersion) { + string::size_type i(cmtPackageVersion.find('-')); + m_name = cmtPackageVersion.substr(0, i); + m_version = cmtPackageVersion.substr(i+1); + if (i==0 || i==string::npos || m_version.empty()) { + cerr << "PackageInfo::PackageInfo(" + << cmtPackageVersion <<"): invalid argument" << endl + << "PackageInfo should be constructed passing a string of the form " + << "PACKAGE-VERSION." << endl + << "Usually this error occurs because CMT can not determine the version " + << "of your package. Please make sure that there is a version.cmt file " + << "in the cmt directory of your package and that version.cmt contains " + << "a single line of the form" << endl << "MyPackage-01-02-03" << endl + << "Notice that version.cmt is created automatically by CMT when you use 'cmt co' " << endl + << endl; + throw invalid_argument("PackageInfo::PackageInfo"); + } +} + +MsgStream& +operator << (MsgStream& ost, const Athena::PackageInfo& info) { + return (ost << info.name() << '-' << info.version()); +} +std::ostream& +operator << (std::ostream& ost, const Athena::PackageInfo& info) { + return (ost << info.name() << '-' << info.version()); +} diff --git a/EDM/athena/Control/AthenaKernel/src/CloneService.cxx b/EDM/athena/Control/AthenaKernel/src/CloneService.cxx new file mode 100644 index 00000000..c104c611 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/CloneService.cxx @@ -0,0 +1,103 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/CloneService.h" + +#include <cassert> +#include <vector> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/ISvcManager.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Service.h" +#include "GaudiKernel/SmartIF.h" +#include "GaudiKernel/System.h" + +namespace CloneService { + /** given a pointer to a parent svc sets a reference to a cloned child */ + StatusCode clone(const IService* iParent, const std::string& childName, + Service*& child) + { + //FIXME this only creates an uninitialized SERVICE. + //FIXME it would be better if one could say parent->clone() + //FIXME (its default implementation could be this one) + + //check the parent pointer is valid + const Service* parent(0); + parent = dynamic_cast<const Service*>(iParent); + if (0 == parent) { + std::cout << " CloneService:clone ERROR: parent " << iParent->name() + << " is not a service!" << std::endl; + return StatusCode::FAILURE; + } + + + // can we access the Service locator interface? + ISvcLocator* svcLoc(parent->serviceLocator()); + assert (0 != svcLoc); + + MsgStream mlog( parent->msgSvc(), "CloneService::clone" ); + + //create the child unless it is already there + //if the service is not there and can't be created barf + IService* pIS(0); + const bool DONOTCREATE(false); + if ((svcLoc->getService(childName, pIS, DONOTCREATE)).isSuccess() && + 0 != (child = dynamic_cast<Service*>(pIS))) { + mlog << MSG::DEBUG + << "Found service " << childName + << endmsg; + } else { + // can we access the Service Manager interface? + SmartIF<ISvcManager> svcMgr(svcLoc); + if ( !svcMgr.isValid() ) { + mlog << MSG::FATAL + << "ISvcManager interface not found by serviceLocator." + << endmsg; + return StatusCode::FAILURE; + } + const std::string& parentType = System::typeinfoName(typeid(*parent)); + if (svcMgr->createService(parentType, childName, + pIS).isSuccess() && + 0 != (child = dynamic_cast<Service*>(pIS))) { + mlog << MSG::DEBUG + << "Created service " << childName << " of type " << parentType + << endmsg; + } else { + mlog << MSG::ERROR + << "Failed to create " << childName << " of type " << parentType + << endmsg; + return StatusCode::FAILURE; + } + + } + //now copy parent's properties into child + std::vector<Property*>::const_iterator iProp(parent->getProperties().begin()); + std::vector<Property*>::const_iterator eProp(parent->getProperties().end()); + while (iProp != eProp && + (child->setProperty(**iProp)).isSuccess()) ++iProp; + if (iProp != eProp) { + mlog << MSG::ERROR + << "Failed to set child property " << (**iProp).name() + << endmsg; + return StatusCode::FAILURE; + } else { + mlog << MSG::DEBUG + << childName << " properties set" + << endmsg; + } + + //finally put the service in the same state as the parent + //FIXME should we handle the case in which the parent is RUNNING? + if (Gaudi::StateMachine::INITIALIZED == parent->FSMState() && + Gaudi::StateMachine::CONFIGURED == child->FSMState()) + return child->sysInitialize(); + else { + mlog << MSG::DEBUG + << "Did not initialize " << childName + << endmsg; + return StatusCode::SUCCESS; + } + } +} diff --git a/EDM/athena/Control/AthenaKernel/src/CloneTool.cxx b/EDM/athena/Control/AthenaKernel/src/CloneTool.cxx new file mode 100644 index 00000000..bfbbd0c6 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/CloneTool.cxx @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/CloneTool.h" + +#include <cassert> +#include <vector> + +#include "GaudiKernel/IToolSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/AlgTool.h" + +namespace CloneTool { + /** given a pointer to a cloned tool sets a reference to its clone */ + StatusCode typeless_clone(const IAlgTool& cloned, + const std::string& cloneName, + const InterfaceID& cloneID, + IAlgTool*& result) + { + //FIXME this only creates an uninitialized AlgTool + //FIXME it would be better if one could say cloned.clone() + //FIXME (its default implementation could be this one) + + const AlgTool* pCloned(dynamic_cast<const AlgTool*>(&cloned)); + if (0 == pCloned) { + std::cerr << "CloneTool::FATAL: Could not dcast IAlgTool " + << cloned.name() << " to an AlgTool" << std::endl; + return StatusCode::FAILURE; + } + + // can we access the AlgTool locator interface? + IToolSvc* toolSvc(pCloned->toolSvc()); + assert (0 != toolSvc); + + MsgStream mlog( pCloned->msgSvc(), "CloneAlgTool::clone" ); + if (!toolSvc->retrieve(pCloned->type(), + cloneName, + cloneID, + result, + pCloned->parent(), //cloned's owner + /*createIf=*/true).isSuccess()) { + mlog << MSG::FATAL << "Could not clone AlgTool " + << pCloned->name() << " to " << cloneName << endmsg; + return StatusCode::FAILURE; + } + + //now copy cloned's properties into result + std::vector<Property*>::const_iterator iProp(pCloned->getProperties().begin()); + std::vector<Property*>::const_iterator eProp(pCloned->getProperties().end()); + + AlgTool* aResult=dynamic_cast<AlgTool*>(result); + if (0 == aResult) { + mlog << MSG::FATAL << "Could not dcast IAlgTool " + << result->name() << " to an AlgTool" << endmsg; + return StatusCode::FAILURE; + } + while (iProp != eProp && + (aResult->setProperty(**iProp)).isSuccess()) ++iProp; + if (iProp != eProp) { + mlog << MSG::ERROR + << "Failed to set result property " << (**iProp).name() + << endmsg; + return StatusCode::FAILURE; + } else { + mlog << MSG::DEBUG + << cloneName << " properties set" + << endmsg; + } + + //finally put the service in the same state as the cloned + //FIXME should we handle the case in which the cloned is RUNNING? + if (Gaudi::StateMachine::INITIALIZED == pCloned->FSMState() && + Gaudi::StateMachine::CONFIGURED == aResult->FSMState()) + return aResult->sysInitialize(); + else { + mlog << MSG::DEBUG + << "Did not initialize " << cloneName + << endmsg; + return StatusCode::SUCCESS; + } + } +} diff --git a/EDM/athena/Control/AthenaKernel/src/DsoDb.cxx b/EDM/athena/Control/AthenaKernel/src/DsoDb.cxx new file mode 100644 index 00000000..d9fa6a93 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/DsoDb.cxx @@ -0,0 +1,713 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// DsoDb.cxx +// Implementation file for class DsoDb +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/DsoDb.h" + +//#define ATH_DSODB_VERBOSE + +// STL includes +#include <cstdlib> /* getenv */ +#include <algorithm> +#include <iostream> +#include <fstream> +#include <set> + +// boost includes +#include "boost/filesystem.hpp" +#include "boost/filesystem/path.hpp" +#include "boost/filesystem/exception.hpp" /*filesystem_error*/ +#include "boost/tokenizer.hpp" + +#include "boost/algorithm/string.hpp" +//#include "boost/algorithm/string/predicate.hpp" +//#include "boost/algorithm/string/replace.hpp" + +#include <boost/regex.hpp> + +// ROOT includes +#include "TClassEdit.h" +#include "TVirtualMutex.h" // for R__LOCKGUARD2 +#include "TInterpreter.h" // for gCINTMutex + +// fwk includes +#include "GaudiKernel/System.h" + +namespace fs = boost::filesystem; + +namespace { + typedef std::vector<std::string> Strings_t; + const std::string RootMap = ".rootmap"; + const std::string DsoMap = ".dsomap"; + const std::string Components = ".components"; + const std::string PluginNs= "__pf__"; + +#ifdef _WIN32 + const std::string SHLIB_PREFIX = "lib"; + const std::string SHLIB_SUFFIX = ".dll"; +#else + const std::string SHLIB_PREFIX = "lib"; + const std::string SHLIB_SUFFIX = ".so"; +#endif + + + bool is_rootcint_dict(const std::string& libname) + { + if (libname == "liblistDict.so") return true; + if (libname == "libmapDict.so") return true; + if (libname == "libmap2Dict.so") return true; + if (libname == "libmultimapDict.so") return true; + if (libname == "libsetDict.so") return true; + if (libname == "libvectorDict.so") return true; + if (libname == "libCore.so") return true; + if (libname == "libMathCore.so") return true; + + static const std::string dll = ".dll"; + if (libname == dll) { + return false; + } + static const boost::regex e("\\w*?.dll"); + return !boost::algorithm::starts_with(libname, SHLIB_PREFIX) && + boost::regex_match(libname, e); + } + + inline + std::string to_string(const fs::path& p) + { +#if BOOST_FILESYSTEM_VERSION == 3 + return p.c_str(); +#else + return p.native_file_string(); +#endif + } + + std::string getlibname(const std::string& libname) + { + std::string lib = libname; + if (!boost::algorithm::starts_with(lib, "lib")) { + lib = std::string("lib") + lib; + } + if (!boost::algorithm::ends_with(lib, SHLIB_SUFFIX)) { + lib = lib + SHLIB_SUFFIX; + } + return lib; + } + + const std::set<std::string>& + s_cxx_builtins() + { + static std::set<std::string> s; + if (s.empty()) { +#define _ADD(x) s.insert(x) + + _ADD( "char"); + _ADD("unsigned char"); + _ADD( "signed char"); + + _ADD("signed"); + + _ADD("short int"); + _ADD("short signed"); + _ADD("short signed int"); + + _ADD( "short"); + _ADD("unsigned short"); + _ADD( "signed short"); + + _ADD("int"); + _ADD("unsigned int"); + + _ADD("long int"); + _ADD("long signed int"); + _ADD("signed long int"); + + _ADD("long"); + _ADD("long signed"); + _ADD("signed long"); + _ADD("unsigned long"); + _ADD("unsigned long int"); + + _ADD("long long"); + _ADD("long long int"); + _ADD("unsigned long long"); + _ADD("longlong"); + + _ADD("ulonglong"); + + _ADD("float"); + _ADD("double"); + _ADD("long double"); + _ADD("bool"); + +#undef _ADD + } + return s; + } + + const std::map<std::string, std::string>& + s_cxx_aliases() + { + static std::map<std::string, std::string> s; + if (s.empty()) { + s["ElementLinkInt_p1"] = "ElementLink_p1<unsigned int>"; + s["basic_string<char>"] = "string"; + s["std::basic_string<char>"] = "string"; + s["vector<basic_string<char> >"] = "vector<string>"; + s["INavigable4MomentumCollection"] = "DataVector<INavigable4Momentum>"; + s["IParticleContainer"] = "DataVector<IParticle>"; + } + return s; + } + + const std::map<std::string, std::string>& + s_cxx_typedefs() + { + static std::map<std::string, std::string> s; + if (s.empty()) { + s["INavigable4MomentumCollection"] = "DataVector<INavigable4Momentum>"; + s["IParticleContainer"] = "DataVector<IParticle>"; + } + return s; + } + + /** @brief helper method to massage a typename into something + * understandable by rootmap files + */ + std::string + to_rootmap_name(const std::string& type_name_) + { + std::string type_name = type_name_; + boost::algorithm::replace_all(type_name, ", ", ","); + // first, the easy case: builtins + if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) { + return type_name; + } + + // known missing aliases ? + if (s_cxx_aliases().find(type_name) != s_cxx_aliases().end()) { + return ::to_rootmap_name(s_cxx_aliases().find(type_name)->second); + } + + type_name = TClassEdit::ShortType(type_name.c_str(), + TClassEdit::kDropDefaultAlloc| + TClassEdit::kDropStd); + boost::algorithm::replace_all(type_name, "basic_string<char> >", "string>"); + boost::algorithm::replace_all(type_name, "basic_string<char>", "string"); + return type_name; + } + + /** @brief helper function to massage a typename into something + * understandable by Reflex. + */ + std::string + to_rflx_name(const std::string& type_name_) + { + std::string type_name = type_name_; + boost::algorithm::replace_all(type_name, ", ", ","); + // first the easy case: builtins + if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) { + return type_name; + } + + // known missing typedefs ? + if (s_cxx_typedefs().find(type_name) != s_cxx_typedefs().end()) { + return ::to_rflx_name(s_cxx_typedefs().find(type_name)->second); + } + type_name = TClassEdit::ShortType(type_name.c_str(), + TClassEdit::kDropDefaultAlloc); + // !! order matters !! (at least in C++03. C++11 should be good) + boost::algorithm::replace_all(type_name, + "std::string>", + "std::basic_string<char> >"); + boost::algorithm::replace_all(type_name, + "std::string", + "std::basic_string<char>"); + return type_name; + } +} + +namespace Ath { + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +/** factory for the DsoDb + */ +DsoDb* DsoDb::instance() +{ + RootType::EnableCintex(); + static DsoDb db; + return &db; +} + +// Constructors +//////////////// +DsoDb::DsoDb() : + m_pf(), + m_db(), + m_dsofiles() +{ + build_repository(); +} + +// Destructor +/////////////// +DsoDb::~DsoDb() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +bool +DsoDb::has_type(const std::string& type_name) +{ + if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) { + return true; + } + const std::string n = ::to_rootmap_name(type_name); + if ( m_db.find(n) != m_db.end() || + m_pf.find(n) != m_pf.end() ) { + return true; + } + return false; +} + +std::string +DsoDb::load_type(const std::string& type_name) +{ + RootType t = this->rflx_type(type_name); + if (t.Id()) { + return t.Name(Reflex::SCOPED|Reflex::QUALIFIED); + } + return std::string(); +} + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/// initialize the repository of dso file names +void +DsoDb::build_repository() +{ + // std::cerr << "::build_repository...\n"; + + typedef boost::tokenizer<boost::char_separator<char> > Tokenizer_t; + typedef std::vector<fs::path> Paths_t; + + std::set<std::string> dsofiles; + + std::string dsopath = System::getEnv("LD_LIBRARY_PATH"); + std::string rootsys = System::getEnv("ROOTSYS"); + + Tokenizer_t tok(dsopath, boost::char_separator<char>(":")); + + for (Tokenizer_t::iterator itr = tok.begin(), iend = tok.end(); + itr != iend; + ++itr) { + //std::cerr << "--[" << *itr << "]...\n"; + if (boost::algorithm::starts_with(*itr, rootsys)) { + continue; + } + fs::path p(*itr); + if (!boost::filesystem::exists(*itr)) { + continue; + } + Paths_t dir_content; + std::copy(fs::directory_iterator(p), + fs::directory_iterator(), + std::back_inserter(dir_content)); + std::sort(dir_content.begin(), + dir_content.end()); + for (Paths_t::iterator ipath = dir_content.begin(), + ipath_end = dir_content.end(); + ipath != ipath_end; + ++ipath) { + const fs::path& dsomap = *ipath; + + bool is_components = false; + if (dsomap.extension() == Components) + is_components = true; + else if (dsomap.extension() != RootMap) + continue; + + if (!fs::exists(dsomap)) continue; + + //std::cerr << "=== [" << dso << "] ===\n"; +#if BOOST_FILESYSTEM_VERSION == 3 + dsofiles.insert(dsomap.c_str()); + std::ifstream f(dsomap.c_str()); +#else + dsofiles.insert(dsomap.native_file_string().c_str()); + std::ifstream f(dsomap.native_file_string().c_str()); +#endif + int line_nbr = -1; + std::string lastlib; + while (f) { + line_nbr += 1; + std::string line; + std::getline(f, line); + boost::algorithm::trim(line); + + std::string libname; + std::string dso_key; + if ( line.empty() ) + continue; + + else if (line.substr (0, 8) == "Library.") { + Strings_t ll; + boost::algorithm::split(ll, line, + boost::is_any_of(" "), + boost::token_compress_on); + if (ll.size() < 2) { + std::cerr << "DsoDb:: **error** could not parse " + << dsomap << ":" << line_nbr + << "\n" + << "DsoDb:: (some) reflex-dicts may fail to be autoloaded" + << "\n"; + continue; + } + libname = ll[1]; + if (::is_rootcint_dict(libname)) { + continue; + } + dso_key = ll[0]; + libname = ::getlibname(libname); + boost::algorithm::replace_all(dso_key, "Library.", ""); + boost::algorithm::replace_all(dso_key, ":", ""); + boost::algorithm::replace_all(dso_key, "@", ":"); + boost::algorithm::replace_all(dso_key, "-", " "); + } + + else if (line[0] == '[') { + libname = line.substr (1, line.size()-2); + boost::algorithm::trim (libname); + if (::is_rootcint_dict(libname)) { + lastlib.clear(); + continue; + } + if (!libname.empty()) + lastlib = ::getlibname (libname); + continue; + } + + else if (line.substr(0, 8) == "# --End ") { + lastlib.clear(); + continue; + } + + else if (line.substr(0, 6) == "class ") { + libname = lastlib; + line.erase (0, 6); + dso_key = line; + } + + else if (is_components && line.substr(0, 3) == "lib") { + std::string::size_type pos = line.find (':'); + if (pos == std::string::npos) continue; + libname = line.substr(0, pos); + line.erase (0, pos+1); + dso_key = line; + + if (dso_key.substr(0, 6) == "_PERS_" || + dso_key.substr(0, 7) == "_TRANS_") + continue; + + if (libname.find ("AthenaPoolPoolCnv") != std::string::npos) + continue; + } + + if (libname.empty() || dso_key.empty()) continue; + + const std::string fullpath_libname = to_string(dsomap.parent_path() / fs::path(libname)); + + // std::cerr << " [" << line << "] -> [" << dso_key << "] [" << libname << "]\n"; + + DsoMap_t *db = NULL; + if (boost::algorithm::starts_with(dso_key, PluginNs) || is_components) { + db = &m_pf; + } else { + db = &m_db; + } + if (db->find(dso_key) == db->end()) { + db->insert(std::make_pair(dso_key, Strings_t())); + } + (*db)[dso_key].push_back(fullpath_libname); + } + // std::cerr << "=== [" << dso << "] === [EOF]\n"; + } + //std::cerr << "--[" << *itr << "]... [done]\n"; + } + + m_dsofiles.reserve(dsofiles.size()); + std::copy(dsofiles.begin(), dsofiles.end(), std::back_inserter(m_dsofiles)); + + // std::cerr << "::build_repository... [done]\n"; + return; +} + +std::vector<std::string> +DsoDb::capabilities(const std::string& libname_) +{ + fs::path p(libname_); + + const std::string libname = ::getlibname(to_string(p.filename())); + std::set<std::string> caps; + DsoMap_t* dbs[] = { &m_pf, &m_db }; + + for (std::size_t i = 0, imax = 2; i < imax; ++i) { + DsoMap_t* db = dbs[i]; + for (DsoMap_t::const_iterator idb = db->begin(), iend=db->end(); + idb != iend; + ++idb) { + for (Libs_t::const_iterator ilib = idb->second.begin(), + ilibend = idb->second.end(); + ilib != ilibend; + ++ilib) { + fs::path lib(*ilib); + if (to_string(lib.filename()) == libname) { + caps.insert(idb->first); + } + } + } + } + + return std::vector<std::string>(caps.begin(), caps.end()); +} + +/// list of libraries hosting duplicate reflex-types +DsoDb::DsoMap_t +DsoDb::duplicates(const std::string& libname, bool pedantic) +{ + DsoMap_t dups; + const std::string basename_lib = to_string(fs::path(libname).filename()); + std::vector<std::string> caps = this->capabilities(libname); + DsoMap_t* dbs[] = { &m_pf, &m_db }; + + for (std::size_t i = 0, imax = 2; i < imax; ++i) { + DsoMap_t dup_db; + this->get_dups(dup_db, *dbs[i], pedantic); + for (DsoMap_t::const_iterator + idb = dup_db.begin(), + idbend = dup_db.end(); + idb != idbend; + ++idb) { + if (std::find(caps.begin(), caps.end(), idb->first) != caps.end()) { + for (Libs_t::const_iterator + ilib = idb->second.begin(), + ilibend=idb->second.end(); + ilib != ilibend; + ++ilib) { + fs::path p(*ilib); + const std::string basename = to_string(p.filename()); + if (basename != libname) { + dups[idb->first].push_back(*ilib); + } + } + } + } + } + return dups; +} + +/// table of dict-duplicates: {type: [lib1, lib2, ...]} +DsoDb::DsoMap_t +DsoDb::dict_duplicates(bool pedantic) +{ + DsoMap_t dups; + get_dups(dups, m_db, pedantic); + return dups; +} + +/// table of plugin-factories-duplicates: {type: [lib1, lib2, ...]} +DsoDb::DsoMap_t +DsoDb::pf_duplicates(bool pedantic) +{ + DsoMap_t dups; + get_dups(dups, m_pf, pedantic); + return dups; +} + +/// list of all libraries we know about +/// @param `detailed` if true, prints the full path to the library +DsoDb::Libs_t +DsoDb::libs(bool detailed) +{ + std::set<std::string> libs; + DsoMap_t* dbs[] = { &m_pf, &m_db }; + + for (std::size_t i = 0, imax = 2; i < imax; ++i) { + const DsoMap_t& db = *dbs[i]; + for (DsoMap_t::const_iterator idb = db.begin(), iend=db.end(); + idb != iend; + ++idb) { + for (Libs_t::const_iterator + ilib = idb->second.begin(), + ilibend=idb->second.end(); + ilib != ilibend; + ++ilib) { + if (detailed) { + libs.insert(*ilib); + } else { + libs.insert(to_string(fs::path(*ilib).filename())); + } + } + } + } + return Libs_t(libs.begin(), libs.end()); +} + +/// return the table {type: [lib1, ...]} - concatenation of all +/// dict-entries and plugin-factories entries. +/// @param `pedantic` if true, retrieves the library's full path +DsoDb::DsoMap_t +DsoDb::content(bool pedantic) +{ + DsoMap_t db; + + DsoMap_t* dbs[] = { &m_pf, &m_db }; + for (std::size_t i = 0, imax = 2; i < imax; ++i) { + const DsoMap_t& d = *dbs[i]; + for (DsoMap_t::const_iterator idb = d.begin(), idbend=d.end(); + idb != idbend; + ++idb) { + if (pedantic) { + db[idb->first] = idb->second; + } else { + Libs_t libs; + std::set<std::string> baselibs; + for (Libs_t::const_iterator + ilib = idb->second.begin(), + ilibend= idb->second.end(); + ilib != ilibend; + ++ilib) { + const std::string baselib = to_string(fs::path(*ilib).filename()); + if (baselibs.find(baselib) == baselibs.end()) { + libs.push_back(*ilib); + baselibs.insert(baselib); + } + } + db[idb->first] = libs; + } + } + } + + return db; +} + +/// get the duplicates for a given repository of components +void +DsoDb::get_dups(DsoMap_t& dups, const DsoMap_t& db, bool pedantic) +{ + for (DsoMap_t::const_iterator idb = db.begin(), iend = db.end(); + idb != iend; + ++idb) { + if (idb->second.size() == 1) { + continue; + } + Libs_t libs; + if (pedantic) { + libs = idb->second; + } else { + std::set<std::string> baselibs; + for (Libs_t::const_iterator + ilib = idb->second.begin(), + ilend= idb->second.end(); + ilib != ilend; + ++ilib) { + fs::path p(*ilib); + const std::string baselib = to_string(p.filename()); + if (baselibs.find(baselib) == baselibs.end()) { + baselibs.insert(baselib); + libs.push_back(*ilib); + } + } + } + if (libs.size() > 1) { + dups[idb->first] = Libs_t(libs.begin(), libs.end()); + } + } +} + +/// load the reflex type after having loaded the hosting library +RootType +DsoDb::rflx_type(const std::string& type_name) +{ + const std::string rootmap_name = ::to_rootmap_name(type_name); + const std::string rflx_name = ::to_rflx_name(type_name); + + // std::cerr << "---DsoDb::rflx_type---\n" + // << " tname: [" << type_name << "]\n" + // << " root: [" << rootmap_name << "]\n" + // << " rflx: [" << rflx_name << "]\n" + // << "----------------------\n"; + + if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) { + return RootType(rflx_name); + } + + if (!this->has_type(rootmap_name)) { +#ifdef ATH_DSODB_VERBOSE + std::cerr << "DsoDb **error**: no such type [" << rootmap_name << "]" + << " in rootmap files\n"; +#endif + return RootType(); + } + DsoMap_t::const_iterator idb = m_db.find(rootmap_name); + if (idb == m_db.end()) { + // try plugin factories... + idb = m_pf.find(rootmap_name); + if (idb == m_pf.end()) { + return RootType(); + } + } + const Libs_t& libs = idb->second; + if (libs.empty()) { +#ifdef ATH_DSODB_VERBOSE + std::cerr << "DsoDb **error**: no library hosting [" << type_name << "]\n"; +#endif + return RootType(); + } + + System::ImageHandle handle; + std::string libname = ::to_string(fs::path(libs[0]).filename()); + boost::algorithm::trim(libname); + if (boost::algorithm::starts_with(libname, SHLIB_PREFIX)) { + libname = libname.substr(SHLIB_PREFIX.size(), std::string::npos); + } + if (boost::algorithm::ends_with(libname, SHLIB_SUFFIX)) { + libname = libname.substr(0, libname.size()-SHLIB_SUFFIX.size()); + } + + //MN hmm, FIX that for ROOT6 ? +#if ROOT_VERSION_CODE < ROOT_VERSION(5,99,0) + // acquire lock: cint-dict loading isn't thread-safe... + R__LOCKGUARD2(gCINTMutex); +#endif + + unsigned long err = System::loadDynamicLib( libname, &handle ); + if ( err != 1 ) { + std::cerr << "DsoDb **error**: could not load library [" + << libs[0] << "] (" << System::getLastErrorString() + << ")\n"; + return RootType(); + } + + return RootType(rflx_name); +} + +} //> end namespace Ath diff --git a/EDM/athena/Control/AthenaKernel/src/IAtRndmGenSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IAtRndmGenSvc.cxx new file mode 100644 index 00000000..99ed59df --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IAtRndmGenSvc.cxx @@ -0,0 +1,7 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/IAtRndmGenSvc.h" +//anchor instantiation of vtable +IAtRndmGenSvc::~IAtRndmGenSvc() {} diff --git a/EDM/athena/Control/AthenaKernel/src/IAthenaBarCode.cxx b/EDM/athena/Control/AthenaKernel/src/IAthenaBarCode.cxx new file mode 100644 index 00000000..3797d166 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IAthenaBarCode.cxx @@ -0,0 +1,27 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IAthenaBarCode.cxx +// Implementation file for class INavigation +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// pkg includes +#include "AthenaKernel/IAthenaBarCode.h" + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// + +IAthenaBarCode::~IAthenaBarCode() +{} + diff --git a/EDM/athena/Control/AthenaKernel/src/IAthenaIPCTool.cxx b/EDM/athena/Control/AthenaKernel/src/IAthenaIPCTool.cxx new file mode 100644 index 00000000..3daa9695 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IAthenaIPCTool.cxx @@ -0,0 +1,13 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IAthenaIPCTool.cxx +// Implementation file for class IAthenaIPCTool +// Author: P.van Gemmeren<gemmeren@anl.gov> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IAthenaIPCTool.h" diff --git a/EDM/athena/Control/AthenaKernel/src/IAthenaSerializeSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IAthenaSerializeSvc.cxx new file mode 100644 index 00000000..ab79f911 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IAthenaSerializeSvc.cxx @@ -0,0 +1,13 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IAthenaSerializeSvc.cxx +// Implementation file for class IAthenaSerializeSvc +// Author: P.van Gemmeren<gemmeren@anl.gov> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IAthenaSerializeSvc.h" diff --git a/EDM/athena/Control/AthenaKernel/src/IAthenaSummarySvc.cxx b/EDM/athena/Control/AthenaKernel/src/IAthenaSummarySvc.cxx new file mode 100644 index 00000000..fd27af0d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IAthenaSummarySvc.cxx @@ -0,0 +1,8 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/IAthenaSummarySvc.h" + +IAthenaSummarySvc::~IAthenaSummarySvc() +{} diff --git a/EDM/athena/Control/AthenaKernel/src/ICutFlowSvc.cxx b/EDM/athena/Control/AthenaKernel/src/ICutFlowSvc.cxx new file mode 100644 index 00000000..72311962 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ICutFlowSvc.cxx @@ -0,0 +1,48 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IDecisionSvc.cxx +// Implementation file for class ICutFlowSvc +// Author: Joao Firmino da Costa <joao.costa@cern.ch> + +/////////////////////////////////////////////////////////////////// + +// for size_t +#include <cstddef> + +// STL includes +#include <string> +#include <vector> +#include <map> + +// FrameWork includes +#include "GaudiKernel/INamedInterface.h" + +// AthenaKernel includes +#include "AthenaKernel/ICutFlowSvc.h" + +// STL includes + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +ICutFlowSvc::~ICutFlowSvc() +{} + + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/IDataShare.cxx b/EDM/athena/Control/AthenaKernel/src/IDataShare.cxx new file mode 100644 index 00000000..50dc9907 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IDataShare.cxx @@ -0,0 +1,47 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IDataShare.cxx +// Implementation file for class IDataShare +// Author: P.van Gemmeren<gemmeren@anl.gov> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IDataShare.h" + +// STL includes + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IDataShare::~IDataShare() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/IDecisionSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IDecisionSvc.cxx new file mode 100644 index 00000000..623966d6 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IDecisionSvc.cxx @@ -0,0 +1,48 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IDecisionSvc.cxx +// Implementation file for class IDecisionSvc +// Author: S.Binet<binet@cern.ch> +// B.Radics<radbal@cern.ch> +/////////////////////////////////////////////////////////////////// + +// for size_t +#include <cstddef> + +// STL includes +#include <string> +#include <vector> +#include <map> + +// FrameWork includes +#include "GaudiKernel/INamedInterface.h" + +// AthenaKernel includes +#include "AthenaKernel/IDecisionSvc.h" + +// STL includes + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IDecisionSvc::~IDecisionSvc() +{} + + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/IDictLoaderSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IDictLoaderSvc.cxx new file mode 100644 index 00000000..cbefe2fa --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IDictLoaderSvc.cxx @@ -0,0 +1,49 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IDictLoaderSvc.cxx +// Implementation file for class IDictLoaderSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IDictLoaderSvc.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IDictLoaderSvc::~IDictLoaderSvc() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + + diff --git a/EDM/athena/Control/AthenaKernel/src/IEventShare.cxx b/EDM/athena/Control/AthenaKernel/src/IEventShare.cxx new file mode 100644 index 00000000..8930fe92 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IEventShare.cxx @@ -0,0 +1,47 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IEventShare.cxx +// Implementation file for class IEventShare +// Author: P.van Gemmeren<gemmeren@anl.gov> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IEventShare.h" + +// STL includes + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IEventShare::~IEventShare() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/IEvtIdModifierSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IEvtIdModifierSvc.cxx new file mode 100644 index 00000000..06614ec9 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IEvtIdModifierSvc.cxx @@ -0,0 +1,49 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IEvtIdModifierSvc.cxx +// Implementation file for class IEvtIdModifierSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IEvtIdModifierSvc.h" + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IEvtIdModifierSvc::~IEvtIdModifierSvc() +{ +} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + + diff --git a/EDM/athena/Control/AthenaKernel/src/IItemListSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IItemListSvc.cxx new file mode 100644 index 00000000..0a647948 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IItemListSvc.cxx @@ -0,0 +1,48 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IItemListSvc.cxx +// Implementation file for class IItemListSvc +// Author: S.Binet<binet@cern.ch> +// B.Radics<radbal@cern.ch> +/////////////////////////////////////////////////////////////////// + +// for size_t +#include <cstddef> + +// STL includes +#include <string> +#include <vector> +#include <map> + +// FrameWork includes +#include "GaudiKernel/INamedInterface.h" + +// AthenaKernel includes +#include "AthenaKernel/IItemListSvc.h" + +// STL includes + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IItemListSvc::~IItemListSvc() +{} + + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/IJobIDSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IJobIDSvc.cxx new file mode 100644 index 00000000..ed24047f --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IJobIDSvc.cxx @@ -0,0 +1,8 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <AthenaKernel/IJobIDSvc.h> + +IJobIDSvc::~IJobIDSvc() +{} diff --git a/EDM/athena/Control/AthenaKernel/src/ILoggedMessageSvc.cxx b/EDM/athena/Control/AthenaKernel/src/ILoggedMessageSvc.cxx new file mode 100644 index 00000000..9ef746b5 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ILoggedMessageSvc.cxx @@ -0,0 +1,8 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/ILoggedMessageSvc.h" + +ILoggedMessageSvc::~ILoggedMessageSvc() {} + diff --git a/EDM/athena/Control/AthenaKernel/src/IOVRange.cxx b/EDM/athena/Control/AthenaKernel/src/IOVRange.cxx new file mode 100644 index 00000000..f7259917 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IOVRange.cxx @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHENAKERNEL_IOVRANGE_H + #include "AthenaKernel/IOVRange.h" +#endif +#ifndef GAUDIKERNEL_MSGSTREAM_H + #include "GaudiKernel/MsgStream.h" +#endif + +#include "GaudiKernel/EventIDRange.h" + +#include <stdexcept> + +/***************************************************************************** + * + * IOVRange.cxx + * IOVSvc + * + * Author: Charles Leggett + * $Id: IOVRange.cxx,v 1.5 2008-05-08 15:57:15 leggett Exp $ + * + * Validity Range object. Holds two IOVTimes (start and stop) + * + *****************************************************************************/ + +IOVRange::IOVRange( const IOVTime& start, const IOVTime& stop ): + m_start(start), m_stop(stop) { +} + +IOVRange::IOVRange( const EventIDRange& eir ): + m_start(eir.start()), m_stop(eir.stop()) { +} + +IOVRange& IOVRange::operator= (const IOVRange& r) { + if (this != &r) { + m_start = r.m_start; + m_stop = r.m_stop; + } + return *this; +} + +std::ostream& operator << (std::ostream& os, const IOVRange& rhs) { + os << (std::string) rhs; + return os; +} + +MsgStream& operator<< (MsgStream &msg, const IOVRange& rhs) { + msg << (std::string) rhs; + return msg; +} diff --git a/EDM/athena/Control/AthenaKernel/src/IOVTime.cxx b/EDM/athena/Control/AthenaKernel/src/IOVTime.cxx new file mode 100644 index 00000000..6d76528b --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IOVTime.cxx @@ -0,0 +1,210 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/***************************************************************************** + * + * IOVTime.cxx + * IOVSvc + * + * Author: Charles Leggett + * $Id: IOVTime.cxx,v 1.10 2005-10-05 13:42:31 schaffer Exp $ + * + * Basic time unit for IOVSvc. + * Hold time as a combination of run and event numbers + * + *****************************************************************************/ + +#include "AthenaKernel/IOVTime.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/EventIDBase.h" +#include <limits> + +const uint32_t IOVTime::MINRUN = + std::numeric_limits<uint32_t>::min(); + +// We remove the top bit from MAXRUN to allow use of this to set +// CondDBKey which has a sign bit +const uint32_t IOVTime::MAXRUN = + (std::numeric_limits<uint32_t>::max() >> 1); + +const uint32_t IOVTime::MINEVENT = + std::numeric_limits<uint32_t>::min(); +const uint32_t IOVTime::MAXEVENT = + (std::numeric_limits<uint32_t>::max()); + +const uint64_t IOVTime::MAXRETIME = + ( ((uint64_t) IOVTime::MAXRUN << 32) + IOVTime::MAXEVENT ); +const uint64_t IOVTime::UNDEFRETIME = + std::numeric_limits<uint64_t>::max(); + +const uint64_t IOVTime::MINTIMESTAMP = + std::numeric_limits<uint64_t>::min(); + +// Set MAXTIMESTAMP to 63 bit max +const uint64_t IOVTime::MAXTIMESTAMP = + (std::numeric_limits<uint64_t>::max() >> 1); +const uint64_t IOVTime::UNDEFTIMESTAMP = + std::numeric_limits<uint64_t>::max(); + +// +/////////////////////////////////////////////////////////////////////////// +// + +IOVTime::IOVTime(const uint32_t& run, const uint32_t& event): + m_status(IOVTime::RUN_EVT), + m_timestamp(IOVTime::UNDEFTIMESTAMP) +{ + m_time = ( (uint64_t) run << 32) + event; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +IOVTime::IOVTime(const uint32_t& run, const uint32_t& event, + const uint64_t& time): + m_status(IOVTime::BOTH), m_timestamp(time) +{ + m_time = ( (uint64_t) run << 32) + event; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +IOVTime::IOVTime(const EventIDBase& eid) +{ + m_time = 0; + m_timestamp = eid.time_stamp()*1000000000LL + eid.time_stamp_ns_offset(); + + if (eid.isRunEvent()) { + m_time = ( (uint64_t) eid.run_number() << 32) + eid.event_number(); + if (eid.isTimeStamp()) { + m_status = IOVTime::BOTH; + } else { + m_status = IOVTime::RUN_EVT; + } + } else if (eid.isLumiEvent()) { + m_time = ( (uint64_t) eid.lumi_block() << 32) + eid.event_number(); + if (eid.isTimeStamp()) { + m_status = IOVTime::BOTH; + } else { + m_status = IOVTime::RUN_EVT; + } + } else { + m_status = IOVTime::TIMESTAMP; + } + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void +IOVTime::setTimestamp( const uint64_t& timestamp ) { + if (isRunEvent()) { + m_status = IOVTime::BOTH; + } else { + m_status = IOVTime::TIMESTAMP; + } + m_timestamp = timestamp; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void +IOVTime::setRETime( const uint64_t& time ) { + if (isTimestamp()) { + m_status = IOVTime::BOTH; + } else { + m_status = IOVTime::RUN_EVT; + } + m_time = time; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void +IOVTime::setRunEvent( const uint32_t& run, const uint32_t& event ) { + if (isTimestamp()) { + m_status = IOVTime::BOTH; + } else { + m_status = IOVTime::RUN_EVT; + } + m_time = ( (uint64_t) run << 32) + event; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void +IOVTime::reset() { + m_status = IOVTime::UNDEF; + m_time = IOVTime::UNDEFRETIME; + m_timestamp = IOVTime::UNDEFTIMESTAMP; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +bool +IOVTime::isValid() const { + + // Cannot have BOTH undefined + if (m_timestamp == IOVTime::UNDEFTIMESTAMP && + m_time == IOVTime::UNDEFRETIME) { + return 0 ; + } + + // Check run/event to be < max + if (m_timestamp == IOVTime::UNDEFTIMESTAMP) { + if ( run() > IOVTime::MAXRUN || event() > IOVTime::MAXEVENT ) { + return 0; + } + } + + // Check time < max + if (m_time == IOVTime::UNDEFRETIME) { + if ( m_timestamp > IOVTime::MAXTIMESTAMP ) { + return 0; + } + } + + if (m_timestamp != IOVTime::UNDEFTIMESTAMP && + m_time != IOVTime::UNDEFRETIME) { + // May have both timestamp and run/event set + if ( run() > IOVTime::MAXRUN || event() > IOVTime::MAXEVENT ) { + return 0; + } + if ( m_timestamp > IOVTime::MAXTIMESTAMP ) { + return 0; + } + } + + return 1; + +} + +IOVTime::operator std::string () const { + std::ostringstream os; + os << "["; + if (isRunEvent()) { + os << (m_time>>32) << "," << ( m_time & 0xFFFFFFFF ); + } + if (isTimestamp()) { + if (isRunEvent()) os << ":"; + os << m_timestamp; + } + os << "]"; + return os.str(); +} + +MsgStream &operator << (MsgStream& os, const IOVTime& rhs) { + os << (std::string) rhs; + return os; +} + +std::ostream& operator << (std::ostream& os, const IOVTime& rhs) { + os << (std::string) rhs; + return os; +} + +// std::ostrstream& operator << (std::ostrstream& os, const IOVTime& rhs) { +// os << (int) rhs.m_time << ": [" << (int) (rhs.m_time>>32) << "," +// << (int) ( rhs.m_time & 0xFFFFFFFF ) << "]"; +// return os; +// } diff --git a/EDM/athena/Control/AthenaKernel/src/IProxyDict.cxx b/EDM/athena/Control/AthenaKernel/src/IProxyDict.cxx new file mode 100644 index 00000000..e3e4337c --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IProxyDict.cxx @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/src/IProxyDict.h + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2015 + * @brief Default implementations for IProxyDict. + */ + + +#include "AthenaKernel/IProxyDict.h" + + +/** + * @brief Tell the store that a handle has been bound to a proxy. + * @param handle The handle that was bound. + * The default implementation does nothing. + */ +void IProxyDict::boundHandle (IResetable* /*handle*/) +{ +} + + +/** + * @brief Tell the store that a handle has been unbound from a proxy. + * @param handle The handle that was unbound. + * The default implementation does nothing. + */ +void IProxyDict::unboundHandle (IResetable* /*handle*/) +{ +} + + +/** + * @brief Test to see if the target of an ElementLink has moved. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + * + * The default implementation here always returns false. + */ +bool IProxyDict::tryELRemap (sgkey_t /*sgkey_in*/, size_t /*index_in*/, + sgkey_t& /*sgkey_out*/, size_t& /*index_out*/) +{ + return false; +} + diff --git a/EDM/athena/Control/AthenaKernel/src/ISlimmingHdlr.cxx b/EDM/athena/Control/AthenaKernel/src/ISlimmingHdlr.cxx new file mode 100644 index 00000000..df67da4a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ISlimmingHdlr.cxx @@ -0,0 +1,51 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ISlimmingHdlr.cxx +// Implementation file for class ISlimmingHdlr +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/ISlimmingHdlr.h" + +// STL includes + +namespace Athena { + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +ISlimmingHdlr::~ISlimmingHdlr() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +} //> namespace Athena diff --git a/EDM/athena/Control/AthenaKernel/src/ITPCnvBase.cxx b/EDM/athena/Control/AthenaKernel/src/ITPCnvBase.cxx new file mode 100644 index 00000000..c12707c7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ITPCnvBase.cxx @@ -0,0 +1,43 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ITPCnvBase.cxx +// Implementation file for class ITPCnvBase +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/ITPCnvBase.h" + +// STL includes + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +ITPCnvBase::~ITPCnvBase() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + + diff --git a/EDM/athena/Control/AthenaKernel/src/ITPCnvSvc.cxx b/EDM/athena/Control/AthenaKernel/src/ITPCnvSvc.cxx new file mode 100644 index 00000000..88ae9d4a --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ITPCnvSvc.cxx @@ -0,0 +1,51 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ITPCnvSvc.cxx +// Implementation file for class ITPCnvSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/ITPCnvSvc.h" +#include "AthenaKernel/ITPCnvBase.h" +#include "AthenaKernel/TPCnvFactory.h" + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +ITPCnvSvc::~ITPCnvSvc() +{ +} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + + diff --git a/EDM/athena/Control/AthenaKernel/src/IThinningHdlr.cxx b/EDM/athena/Control/AthenaKernel/src/IThinningHdlr.cxx new file mode 100644 index 00000000..0a9b4c82 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IThinningHdlr.cxx @@ -0,0 +1,51 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IThinningHdlr.cxx +// Implementation file for class IThinningHdlr +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// AthenaKernel includes +#include "AthenaKernel/IThinningHdlr.h" + +// STL includes + +namespace Athena { + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IThinningHdlr::~IThinningHdlr() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +} //> namespace Athena diff --git a/EDM/athena/Control/AthenaKernel/src/IThinningSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IThinningSvc.cxx new file mode 100644 index 00000000..f03ef4d0 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IThinningSvc.cxx @@ -0,0 +1,143 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IThinningSvc.cxx +// Implementation file for class IThinningSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// Gaudi includes +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" + +// AthenaKernel includes +#include "AthenaKernel/IThinningSvc.h" + +// STL includes + +namespace { + + /// Dummy implementation for the IThinningHldr interface + /// + /// This dummy implementation is used when we want to record information + /// into a ThinningSvc instance about containers that the service should + /// not thin itself, but leave it up to the POOL converters to take care + /// of doing this. Like for thinning xAOD containers. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision$ + /// $Date$ + /// + class DummyThinningHdlr : public ::Athena::IThinningHdlr { + + public: + /// Dummy function + virtual void remove( const std::size_t /*idx*/ ) { return; } + /// Dummy function + virtual void commit() { return; } + /// Dummy function + virtual void rollback() { return; } + + }; // class DummyThinningHldr + +} // private namespace + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IThinningSvc::~IThinningSvc() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/** @brief helper method to decide if an index value is thinned or not + */ +bool +IThinningSvc::isThinned ( const std::size_t idx ) +{ + return idx == IThinningSvc::RemovedIdx; +} + +template <> +std::size_t +IThinningSvc::generateRemovedIdx<std::size_t>() +{ + return IThinningSvc::RemovedIdx; +} + +template <> +std::string +IThinningSvc::generateRemovedIdx<std::string>() +{ + return "--RemovedIdx--"; +} + +IThinningSvc* +IThinningSvc::instance( IThinningSvc* activeSvc, bool override ) +{ + static IThinningSvc* svc = 0; + if ( override ) { + svc = activeSvc; + } + return svc; +} + +StatusCode +IThinningSvc::typelessFilter( const void* in, + const IThinningSvc::VecFilter_t& filter, + const IThinningSvc::Operator::Type op ) { + + // Translate the filter: + IThinningSvc::Filter_t sparse_filter; + const std::size_t imax = filter.size(); + for ( std::size_t i = 0; i != imax; ++i ) { + sparse_filter[ i ] = filter[ i ]; + } + + // Call the other function: + return this->typelessFilter( in, sparse_filter, op ); +} + +StatusCode +IThinningSvc::typelessFilter( const void* in, + const IThinningSvc::Filter_t& filter, + const IThinningSvc::Operator::Type op ) { + + // Create a dummy thinning handler object: + ::DummyThinningHdlr* dummyHandler = new ::DummyThinningHdlr(); + + // Get the DataProxy of the object: + SG::DataProxy* proxy = this->proxy( in ); + + // Leave it to the service implementation to do the rest: + return this->filter_impl( dummyHandler, proxy, filter, op ); +} + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/ITimeKeeper.cxx b/EDM/athena/Control/AthenaKernel/src/ITimeKeeper.cxx new file mode 100644 index 00000000..bab8f50d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ITimeKeeper.cxx @@ -0,0 +1,10 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/ITimeKeeper.h" +const InterfaceID& +ITimeKeeper::interfaceID() { + static const InterfaceID IID("ITimeKeeper", 1, 0); + return IID; +} diff --git a/EDM/athena/Control/AthenaKernel/src/IValgrindSvc.cxx b/EDM/athena/Control/AthenaKernel/src/IValgrindSvc.cxx new file mode 100644 index 00000000..b2d4dbc0 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/IValgrindSvc.cxx @@ -0,0 +1,47 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// IValgrindSvc.cxx +// Implementation file for class IValgrindSvc +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// Gaudi includes + +// AthenaKernel includes +#include "AthenaKernel/IValgrindSvc.h" + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +IValgrindSvc::~IValgrindSvc() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/AthenaKernel/src/MsgStreamMember.cxx b/EDM/athena/Control/AthenaKernel/src/MsgStreamMember.cxx new file mode 100644 index 00000000..0b669393 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/MsgStreamMember.cxx @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file MsgStreamMember.cxx + * @brief MsgStreamMember implementation + * + * $Id: MsgStreamMember.cxx,v 1.1 2008-07-14 22:10:14 calaf Exp $ + * @author Paolo Calafiura - Atlas collaboration + */ +#include "AthenaKernel/MsgStreamMember.h" +using namespace Athena; +/// @param o: if o is @c Athena::Options::Eager it will create a +/// @c MsgStream instance there and then. +MsgStreamMember::MsgStreamMember(const Athena::Options::CreateOptions opt, + const std::string& label) : + m_ims(opt), m_label(label), m_stream (0) +{ + if (opt == Athena::Options::Eager) m_stream = new MsgStream(m_ims.get(), m_label); +} + +MsgStreamMember& MsgStreamMember::operator= (const MsgStreamMember& rhs) +{ + if (this != &rhs) { + m_ims = rhs.m_ims; + m_label = rhs.m_label; + m_stream = 0; + } + return *this; +} + +MsgStreamMember::~MsgStreamMember() { delete m_stream; } + +/// upon first access sets m_ims as needed +MsgStream& MsgStreamMember::get() const { + if (0 == m_stream) m_stream = new MsgStream(m_ims.get(), m_label); + return *m_stream; +} diff --git a/EDM/athena/Control/AthenaKernel/src/POSIXTimeKeeper.cxx b/EDM/athena/Control/AthenaKernel/src/POSIXTimeKeeper.cxx new file mode 100644 index 00000000..cb5b5214 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/POSIXTimeKeeper.cxx @@ -0,0 +1,22 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/POSIXTimeKeeper.h" + +POSIXTimeKeeper::POSIXTimeKeeper() : TimeKeeper() { updateTime(); } +POSIXTimeKeeper::~POSIXTimeKeeper() {} + +void POSIXTimeKeeper::updateTime() { + times(&m_tms); +} + +time_t POSIXTimeKeeper::timeX() const { + return m_tms.tms_utime + m_tms.tms_cutime + m_tms.tms_stime + m_tms.tms_cstime; +} + +const std::string& POSIXTimeKeeper::unitLabel() const { + static const std::string label("1/100 CPU secs"); + return label; +} + diff --git a/EDM/athena/Control/AthenaKernel/src/RCUObject.cxx b/EDM/athena/Control/AthenaKernel/src/RCUObject.cxx new file mode 100644 index 00000000..b46fd9cd --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/RCUObject.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/src/RCUObject.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + */ + + +#include "AthenaKernel/RCUObject.h" +#include "AthenaKernel/IRCUSvc.h" +#include <cstdlib> + + +namespace Athena { + + +/** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * + * The service will call @c quiescent at the end of each event. + */ +IRCUObject::IRCUObject (IRCUSvc& svc) + : m_svc (&svc), + m_grace (svc.getNumSlots()) +{ +} + + +/** + * @brief Constructor, with event slot count. + * @param nslots Number of active event slots. + * + * This version does not register with a service. + */ +IRCUObject::IRCUObject (size_t nslots) + : m_svc (nullptr), + m_grace (nslots) +{ +} + + +/** + * @brief Destructor. + * + * Remove this object from the service if it has been registered. + */ +IRCUObject::~IRCUObject() +{ + if (m_svc && m_svc->remove (this).isFailure()) + std::abort(); +} + + +} // namespace Athena diff --git a/EDM/athena/Control/AthenaKernel/src/TimeKeeper.cxx b/EDM/athena/Control/AthenaKernel/src/TimeKeeper.cxx new file mode 100644 index 00000000..8e3e0379 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/TimeKeeper.cxx @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthenaKernel/TimeKeeper.h" + +#include "GaudiKernel/MsgStream.h" + +const unsigned int TimeKeeper::SKIPCYCLES(2); + +TimeKeeper::TimeKeeper() : m_cycles(0), m_setupTime(0) {} + +TimeKeeper::~TimeKeeper() {} + +bool TimeKeeper::nextIter() { + if (m_cycles<SKIPCYCLES) m_setupTime = timeX(); + ++m_cycles; + updateTime(); + return !timeOver(); +} + +time_t TimeKeeper::timeL() const { + return allocTime() - timeX(); +} + +bool TimeKeeper::timeOver() const { + return timeL() < 2 * averageIterTime(); //FIXME use e.g. + 3 sigmas +} + +time_t TimeKeeper::averageIterTime() const { + //subtract setup time from estimate + return (m_cycles<SKIPCYCLES) ? 0 : (timeX() - m_setupTime) / (m_cycles - SKIPCYCLES + 1); +} + +std::ostream& operator << (std::ostream& ost, const TimeKeeper& tk) { + ost << "TimeKeeper status: (all times in " << tk.unitLabel() << ")" + << "\n allocated job time " << tk.allocTime() + << " - job time used so far " << tk.timeX() + << "\n average time per iteration " << tk.averageIterTime() + << " - time left " << tk.timeL() ; + if (tk.timeOver()) ost + << "\n Not enough time for another iteration"; + return ost; +} + +MsgStream& operator << (MsgStream& ost, const TimeKeeper& tk) { + ost << "TimeKeeper status: (all times in " << tk.unitLabel() << ")" + << "\n allocated job time " << tk.allocTime() + << " - job time used so far " << tk.timeX() + << "\n average time per iteration " << tk.averageIterTime() + << " - time left " << tk.timeL() ; + if (tk.timeOver()) ost + << "\n Not enough time for another iteration"; + return ost; +} diff --git a/EDM/athena/Control/AthenaKernel/src/errorcheck.cxx b/EDM/athena/Control/AthenaKernel/src/errorcheck.cxx new file mode 100644 index 00000000..7157855f --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/errorcheck.cxx @@ -0,0 +1,320 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: errorcheck.cxx,v 1.5 2009-04-09 15:11:17 ssnyder Exp $ +/** + * @file errorcheck.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2006 + * @brief Helpers for checking error return status codes and reporting errors. + */ + +#include "AthenaKernel/errorcheck.h" +#include "AthenaKernel/getMessageSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/INamedInterface.h" +#include <ctype.h> + + +namespace errorcheck { + + +/// If true, hide the source file and line number in output messages. +bool ReportMessage::s_hide_error_locus = false; + + +/// If true, hide the function names in output messages. +bool ReportMessage::s_hide_function_names = false; + + +/** + * @brief Clean `allocator' template arguments from the function f. + * @param f Name of the function to clean. + */ +std::string clean_allocator (std::string f) +{ + std::string::size_type ipos = 0; + while ((ipos = f.find (", std::allocator", ipos)) != std::string::npos) { + const char* p = f.c_str() + ipos + 16; + while (isspace (*p)) ++p; + if (*p == '<') { + ++p; + int nest = 1; + while (nest > 0 && *p) { + if (*p == '<') + ++nest; + else if (*p == '>') + --nest; + ++p; + } + if (nest == 0) { + if (ipos > 0 && f[ipos-1] != '>') { + while (isspace (*p)) ++p; + } + f.erase (ipos, p-f.c_str()-ipos); + p = f.c_str() + ipos; + } + } + ipos = p - f.c_str(); + } + return f; +} + + +std::string munge_string_name (const std::string& str_in) +{ + std::string s = str_in; + + std::string::size_type ipos = 0; + while ((ipos = s.find ("std::basic_string<", ipos)) != std::string::npos) { + std::string::size_type beg = ipos; + ipos += 18; + int inest = 1; + while (inest > 0 && ipos < s.size()) { + if (s[ipos] == '<') ++inest; + else if (s[ipos] == '>') --inest; + ++ipos; + } + s.replace (beg, ipos-beg, "std::string"); + ipos = beg+11; + } + + for (size_t i = 0; i < s.size(); i++) { + if ((i == 0 || (s[i-1] != ':' && !isalnum(s[i-1]))) && + strncmp (s.c_str()+i, "string", 6) == 0 && + !isalnum(s[i+6])) + { + s.replace (i, 6, "std::string"); + } + } + return s; +} + + +std::string munge_punct (const std::string& str_in) +{ + std::string s = str_in; + for (size_t i = 0; i < s.size()-1; i++) { + if (s[i] == ' ' && (s[i+1] == '*' || s[i+1] == '&')) + s.erase (i, 1); + } + return s; +} + + +std::string do_replace (std::string s, + const std::string pat, + const std::string rep) +{ + std::string::size_type ipos = 0; + while ((ipos = s.find (pat, ipos)) != std::string::npos) + s.replace (ipos, pat.size(), rep); + return s; +} + + +std::string munge_names (const std::string& str_in) +{ + std::string s = + do_replace (str_in, "SG::DataProxyStorageData::pointer", "void*"); + s = do_replace (s, "DPSD::pointer", "void*"); + s = do_replace (s, "SG::auxid_t", "unsigned long"); + s = do_replace (s, "auxid_t", "unsigned long"); + s = do_replace (s, "void* ", "void*"); + s = do_replace (s, "CLID", "unsigned int"); + + if (s.find ("virtual ") == 0) + s.erase (0, 8); + return s; +} + + + +/** + * @brief Constructor. + * @param level The error logging level for the message. + * @param line The source line from which the report is being made. + * @param file The source file name from which the report is being made. + * @param func The name of the function from which the report is being made. + * @param context The name of the context (algorithm/tool/service/etc.) + * from which the report is being made. + * @param sc The @c StatusCode to include in the error message. + */ +ReportMessage::ReportMessage (MSG::Level level, + int line, + const char* file, + const char* func, + const std::string& context, + StatusCode sc) + : MsgStream (Athena::getMessageSvc(), context) +{ + // The common part. + format_common (level, line, file, func); + + // The status code. + *this << ": code " << sc.getCode(); + + // Remember the end of the header. + m_pos = stream().str().size(); +} + + +/** + * @brief Constructor. + * @param level The error logging level for the message. + * @param line The source line from which the report is being made. + * @param file The source file name from which the report is being made. + * @param func The name of the function from which the report is being made. + * @param context The name of the context (algorithm/tool/service/etc.) + * from which the report is being made. + */ +ReportMessage::ReportMessage (MSG::Level level, + int line, + const char* file, + const char* func, + const std::string& context) + : MsgStream (Athena::getMessageSvc(), context) +{ + // The common part. + format_common (level, line, file, func); + + // Remember the end of the header. + m_pos = stream().str().size(); +} + + +/** + * @brief Generate the common header for messages. + * @param level The error logging level for the message. + * @param line The source line from which the report is being made. + * @param file The source file name from which the report is being made. + * @param func The name of the function from which the report is being made. + */ +void ReportMessage::format_common (MSG::Level level, + int line, + const char* file, + const char* func) +{ + // Logging level. + *this << level; + + // Write the source file/line. + if (s_hide_error_locus) + *this << "FILE:LINE"; + else + *this << file << ":" << line; + + // Include the function name if available. + if (s_hide_function_names) + *this << " (FUNC)"; + else { + if (func && func[0] != '\0') { + std::string cfunc = munge_names (munge_punct (munge_string_name (clean_allocator (func)))); + *this << " (" << cfunc << ")"; + } + } +} + + +/** + * @brief Destructor. + * This will cause the message to be emitted, if it hasn't already been. + */ +ReportMessage::~ReportMessage() +{ + // Don't do anything if the message has already been emitted + // (due to using << endmsg, for example). + if (!stream().str().empty()) + *this << endmsg; +} + + +/** + * @brief Emit the message. + * We override this method from @c MsgStream in order to fix up + * the message punctuation. + */ +MsgStream& ReportMessage::doOutput() +{ + // The deal here is this. We want + // REPORT_MESSAGE(MSG::INFO) << "foo"; + // to get a `: ' before the `foo'. + // But we don't want + // REPORT_MESSAGE(MSG::INFO); + // to have a trailing `: '. + // So, after we generate the common header part, we remember + // where we are in the string. When the message is emitted, we look + // to see if additional text has been added. If not, then we don't + // need to do anything. But if so, we insert a `: ' after the header. + if (m_pos != stream().str().size()) { + std::string tmp1 = stream().str(); + std::string tmp2 = tmp1.substr(0, m_pos) + ": " + tmp1.substr(m_pos); + stream().str (tmp2); + } + return MsgStream::doOutput(); +} + + +/** + * @brief If set to true, hide the source file and line number + * in the output. + * + * This is intended for use in regression tests, where + * it's undesirable to have the output change if source lines + * are added or deleted. + */ +void ReportMessage::hideErrorLocus (bool flag /*= true*/) +{ + s_hide_error_locus = flag; +} + + +/** + * @brief If set to true, hide function names in the output. + * in the output. + * + * This is intended for use in regression tests, where + * function names may be formatted differently on different + * platforms. + */ +void ReportMessage::hideFunctionNames (bool flag /*= true*/) +{ + s_hide_function_names = flag; +} + + +} // namespace errorcheck + + +namespace errorcheck { + + +/** + * @brief Return the context name from a context (@c this) pointer. + * @param context The context from which to get the name. + * @return The name of this context. + * + * This is the specialization for an @c INamedInterface. + */ +std::string context_name (const INamedInterface* context) +{ + return context->name(); +} + + +/** + * @brief Return the context name from a context (@c this) pointer. + * @param context The context from which to get the name. + * @return The name of this context. + * + * This is the specialization for an unknown context type; it returns + * a blank name. + */ +std::string context_name (const void* /*context*/) +{ + return ""; +} + + +} // namespace errorcheck diff --git a/EDM/athena/Control/AthenaKernel/src/getMessageSvc.cxx b/EDM/athena/Control/AthenaKernel/src/getMessageSvc.cxx new file mode 100644 index 00000000..75019ef2 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/getMessageSvc.cxx @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <iostream> +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/IMessageSvc.h" +#include "GaudiKernel/ISvcLocator.h" +#include "AthenaKernel/getMessageSvc.h" + +using namespace Athena; +using std::cerr; +using std::endl; + +/// Set this to force off the warning messages from getMessageSvc +/// (in unit tests, for example). +bool Athena::getMessageSvcQuiet = false; + +IMessageSvc* Athena::getMessageSvc( bool quiet ) { return getMessageSvc( Options::Lazy, quiet ); } +IMessageSvc* Athena::getMessageSvc( const Options::CreateOptions opt, bool quiet ) { + IMessageSvc* pSvc(0); + const bool createIf( opt == Athena::Options::Eager ); + if (!(Gaudi::svcLocator()->service("MessageSvc", pSvc, createIf)).isSuccess() && + !quiet && + !Athena::getMessageSvcQuiet) + { + cerr << "Athena::getMessageSvc: WARNING MessageSvc not found, will use std::cout" << endl; + } + return pSvc; +} + +void Athena::reportMessage (IMessageSvc* ims, const std::string &source, int type, const std::string &message) { + if (ims) ims->reportMessage(source, type, message); +} + +int Athena::outputLevel(IMessageSvc* ims, const std::string &source) { + if (ims) return ims->outputLevel(source); + else return MSG::INFO; +} + +void Athena::setOutputLevel(IMessageSvc* ims, const std::string &source, int level) { + if(ims) ims->setOutputLevel(source, level); +} + +IMessageSvcHolder::IMessageSvcHolder(IMessageSvc *ims) : m_ims(ims) { + assert(m_ims); + m_ims->addRef(); //take ownership till we go out of scope +} + +IMessageSvcHolder::IMessageSvcHolder(const IMessageSvcHolder& rhs) : + m_ims(rhs.m_ims) +{ + if (m_ims) m_ims->addRef(); //take ownership till we go out of scope +} + +IMessageSvcHolder& +IMessageSvcHolder::operator=(const IMessageSvcHolder& rhs) { + if (this != & rhs && m_ims != rhs.m_ims) { + if (m_ims) m_ims->release(); //give up our IMessageSvc* + m_ims = rhs.m_ims; + if (m_ims) m_ims->addRef(); //take ownership till we go out of scope + } + return *this; +} + +IMessageSvcHolder::IMessageSvcHolder( const Options::CreateOptions opt ) : + m_ims(0) +{ + if (opt == Athena::Options::Eager) m_ims = getMessageSvc(opt); +} + +IMessageSvcHolder::~IMessageSvcHolder() { + if (m_ims) m_ims->release(); +} + +IMessageSvc* +IMessageSvcHolder::get() const { + if (!m_ims) m_ims = getMessageSvc(); + return m_ims; +} diff --git a/EDM/athena/Control/AthenaKernel/src/ubsan_boost_suppress.cxx b/EDM/athena/Control/AthenaKernel/src/ubsan_boost_suppress.cxx new file mode 100644 index 00000000..5b8b7b78 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/src/ubsan_boost_suppress.cxx @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration. + */ + +// $Id$ +/** + * @file AthenaKernel/src/ubsan_boost_suppress.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2017 + * @brief Suppress some known ubsan warnings from boost. + */ + + +#include "CxxUtils/ubsan_suppress.h" +#include "boost/format.hpp" + + +namespace Athena { + + +int ubsan_boost_suppress() +{ + // See <https://svn.boost.org/trac/boost/ticket/11632> + CxxUtils::ubsan_suppress ([]() { boost::format("%1%") % "asd"; }); + return 0; +} + + +int ubsan_boost_suppress_ = ubsan_boost_suppress(); + + +} // namespace Athena diff --git a/EDM/athena/Control/AthenaKernel/test/AthenaKernel.xml b/EDM/athena/Control/AthenaKernel/test/AthenaKernel.xml new file mode 100644 index 00000000..cedda733 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/AthenaKernel.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AthenaKernelTest" type="makecheck" suite="Examples"> + <package>Control/AthenaKernel</package> + <timelimit>10</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov, binet@cern.ch</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/AthenaKernel/test/AthenaPackageInfo_test.cxx b/EDM/athena/Control/AthenaKernel/test/AthenaPackageInfo_test.cxx new file mode 100644 index 00000000..d9683b5d --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/AthenaPackageInfo_test.cxx @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file AthenaPackageInfo_test.cxx + * @author Paolo Calafiura + * @brief Regression tests for PackageInfo (if only it worked...) + * + * verify that constructor parses correctly PACKAGE_VERSION macro strings + * of the format PACKAGE-xx-yy-zz + * + * $Id: AthenaPackageInfo_test.cxx,v 1.5 2008-07-25 23:37:34 calaf Exp $ + */ +#undef NDEBUG +#include <cassert> +#include <iostream> +#include "AthenaKernel/tools/AthenaPackageInfo.h" +using namespace std; +using Athena::PackageInfo; +int main() { + cout << "*** AthenaPackageInfo_test OK ***" << endl; + PackageInfo info(PACKAGE_VERSION); + assert( info.name() == "AthenaKernel" ); + assert( (info.version().size() == 7 && info.version()[0] == 'r') || //r123456 + info.version().size() == 8 || //00-00-00 + info.version().size() == 11 ); //00-00-00-00 + cerr << "Now we expect to see an error message:\n" + << "----Error Message Starts--->>" << endl; + try { + PackageInfo bad("BaD"); + assert(!"BaD should never get here"); + } catch (...) {} + cerr << "<<----Error Message Ends-----" << endl; + cerr << "Now we expect to see an error message:\n" + << "----Error Message Starts--->>" << endl; + try { + PackageInfo bad("BaD-"); + assert(!"BaD- should never get here"); + } catch (...) {} + cerr << "<<----Error Message Ends-----" << endl; + cerr << "Now we expect to see an error message:\n" + << "----Error Message Starts--->>" << endl; + try { + PackageInfo bad("-BaD"); + assert(!"-BaD should never get here"); + } catch (...) {} + cerr << "<<----Error Message Ends-----" << endl; + cout << "*** AthenaPackageInfo_test OK ***" << endl; + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/Chrono_test.cxx b/EDM/athena/Control/AthenaKernel/test/Chrono_test.cxx new file mode 100644 index 00000000..f76d3aab --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/Chrono_test.cxx @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/Chrono_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2014 + * @brief Regression tests for Chrono. + */ + +#undef NDEBUG + + +#include "AthenaKernel/Chrono.h" +#include "GaudiKernel/ChronoEntity.h" +#include <iostream> +#include <stdexcept> +#include <cstdlib> +#include <cassert> + + +int count = 0; + + +class ChronoSvcTest + : public IChronoSvc +{ +public: + virtual ChronoEntity* chronoStart ( const std::string& /*t*/ ) + {++count; return 0;} + virtual ChronoEntity* chronoStop ( const std::string& /*t*/ ) + {--count; return 0;} + + virtual ChronoTime chronoDelta ( const ChronoTag& , ChronoType ) { std::abort(); } + virtual void chronoPrint ( const ChronoTag& ) { std::abort(); } + virtual ChronoStatus chronoStatus ( const ChronoTag& ) { std::abort(); } + virtual const ChronoEntity* chrono ( const ChronoTag& ) const { std::abort(); } + virtual unsigned long addRef() { std::abort(); } + virtual unsigned long release() { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &, void**) { std::abort(); } + +}; + + +void testit (bool throw_p) +{ + assert (count == 1); + if (throw_p) + throw std::runtime_error("test"); +} + + +void test1() +{ + std::cout << "test1\n"; + ChronoSvcTest svc; + + { + Athena::Chrono chrono ("test", &svc); + testit(false); + } + assert (count == 0); + + try { + Athena::Chrono chrono ("test", &svc); + testit(true); + } + catch (const std::runtime_error&) + { + } + assert (count == 0); +} + + +int main() +{ + test1(); + return 0; +} + + diff --git a/EDM/athena/Control/AthenaKernel/test/DataObjectSharedPtr_test.cxx b/EDM/athena/Control/AthenaKernel/test/DataObjectSharedPtr_test.cxx new file mode 100644 index 00000000..3f23b6b1 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/DataObjectSharedPtr_test.cxx @@ -0,0 +1,56 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/test/DataObjectSharedPtr_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Regression tests for DataObjectSharedPtr. + */ + + +#undef NDEBUG +#include "AthenaKernel/DataObjectSharedPtr.h" +#include <iostream> + + +class MyObj : public DataObject +{ +public: + virtual ~MyObj() override { std::cout << "MyObj dtor\n"; } +}; + + +int f (SG::DataObjectSharedPtr<DataObject> ptr) +{ + return ptr->refCount(); +} + + +void test1() +{ + std::cout << "test1\n"; + { + SG::DataObjectSharedPtr<MyObj> ptr (new MyObj); + assert (ptr->refCount() == 1); + { + SG::DataObjectSharedPtr<MyObj> ptr2 (ptr); + assert (ptr->refCount() == 2); + } + assert (ptr->refCount() == 1); + + assert (f (ptr) == 2); + assert (ptr->refCount() == 1); + + std::cout << "should call dtor now\n"; + } +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/DirSearchPath_test.cxx b/EDM/athena/Control/AthenaKernel/test/DirSearchPath_test.cxx new file mode 100644 index 00000000..a178da99 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/DirSearchPath_test.cxx @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** unit test for DirSearchPath class + * --------------------------------------------------------------------- + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + */ + +// $Id: DirSearchPath_test.cxx,v 1.2 2008-03-17 22:02:25 calaf Exp $ + +//<<<<<< INCLUDES >>>>>> +#undef NDEBUG +#include <cassert> +#include <iostream> +#include "boost/filesystem/operations.hpp" +#include "GaudiKernel/DirSearchPath.h" + +using namespace std; +using namespace boost::filesystem; + + +int main() { + cout << "*** DirSearchPath_test Starts ***" << endl; + const bool SHOULDNEVERGETHERE(false); + DirSearchPath bad("foo:fo: : *"); + try { + //make sure /tmp is there + path tmp("/tmp"); + if (!exists(tmp)) create_directory(tmp); + + //create a test dir tree under /tmp + path testRoot("/tmp/DirSearchPath_test"); + if (exists(testRoot) && !testRoot.empty()) remove_all(testRoot); + if (!exists(testRoot)) create_directory(testRoot); + path testSub1(testRoot / path("sub1")); + create_directory(testSub1); + path testSub2(testRoot / path("sub2")); + create_directory(testSub2); + path testSub2Sub3(testSub2 / path("sub3")); + create_directory(testSub2Sub3); + + //add work areas to path + DirSearchPath searchPath(" :/tmp: bla"); + //now look for something + string fullFileName; + assert(searchPath.find("DirSearchPath_test", fullFileName)); + assert(searchPath.add("/tmp/DirSearchPath_test")); + assert(searchPath.find("sub1", fullFileName)); + assert(searchPath.find("sub2", fullFileName)); + assert(!searchPath.find("sub3", fullFileName)); + assert(searchPath.find("sub2/sub3", fullFileName)); + assert(searchPath.add(testSub2)); + assert(searchPath.find("sub3", fullFileName)); + if (!testRoot.empty()) remove_all(testRoot); + } catch (const filesystem_error& err) { + cerr << err.what() << endl; + assert(SHOULDNEVERGETHERE); + } + cout << "*** DirSearchPath_test OK ***" << endl; + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/IRCUSvc_test.cxx b/EDM/athena/Control/AthenaKernel/test/IRCUSvc_test.cxx new file mode 100644 index 00000000..c376a7c7 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/IRCUSvc_test.cxx @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file IRCUOSVC_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief Regression tests for RCUObject. + */ + +#undef NDEBUG + +#include "AthenaKernel/IRCUSvc.h" +#include <cassert> +#include <iostream> +#include <cstdlib> + + +using Athena::IRCUSvc; +using Athena::IRCUObject; +using Athena::RCUObject; +using Athena::RCURead; + + +class TestRCUSvc + : public IRCUSvc +{ +public: + virtual StatusCode remove (IRCUObject* /*obj*/) override { return StatusCode::SUCCESS; } + virtual size_t getNumSlots() const override { return 1; } + virtual void add (IRCUObject* obj) override + { m_added = obj; } + + virtual unsigned long addRef() override { std::abort(); } + virtual unsigned long release() override { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override { std::abort(); } + + IRCUObject* m_added = nullptr; +}; + + +struct Payload +{ + Payload (int a, int b) : + m_a(a), m_b(b) + {} + Payload& operator= (const Payload&) = default; + + int m_a; + int m_b; +}; + + +void test1() +{ + std::cout << "test1\n"; + TestRCUSvc svc; + assert (svc.m_added == nullptr); + std::unique_ptr<RCUObject<Payload> > obj = svc.newrcu<Payload> (10, 20); + RCURead<Payload> r (*obj); + assert (r->m_a == 10); + assert (r->m_b == 20); + assert (svc.m_added == obj.get()); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/MsgStreamMember_test.cxx b/EDM/athena/Control/AthenaKernel/test/MsgStreamMember_test.cxx new file mode 100644 index 00000000..29247cda --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/MsgStreamMember_test.cxx @@ -0,0 +1,111 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file MsgStreamMember_test.cxx + * @brief Example/Regression test for @class Athena::MsgStreamMember + * + * @author Paolo Calafiura + * $Id: MsgStreamMember_test.cxx,v 1.1 2008-07-14 22:10:14 calaf Exp $ + */ +#undef NDEBUG +#include <cassert> +#include "TestTools/initGaudi.h" +#include "AthenaKernel/MsgStreamMember.h" + +using namespace Athena; +class Mine { +public: + Mine() : + //this is how you would set m_stream in a (data)obj w/o access to IMessageSvc* + m_stream(name()) {} + const std::string& name() const { + static const std::string n("Mine"); + return n; + } + void printIt() { + m_stream << MSG::ALWAYS << "*** Mine works ***" <<endmsg; + } +private: + MsgStreamMember m_stream; +}; +class Yours { +public: + Yours(IMessageSvc* ims) : + //this would be the typical way to construct m_stream in e.g. a Service + m_stream(ims, name()) {} + const std::string& name() const { + static const std::string n("Yours"); + return n; + } + + void printIt() { + m_stream << MSG::ALWAYS << "*** Yours works too ***" <<endmsg; + } +private: + Athena::MsgStreamMember m_stream; +}; + +class Hers { +public: + Hers(IMessageSvc* ims) { + //this would be another (less preferred) way to construct m_stream + m_stream = MsgStreamMember(ims, name()); + } + const std::string& name() const { + static const std::string n("Hers"); + return n; + } + + void printIt() { + m_stream << MSG::ALWAYS << "*** reporting ***" <<endmsg; + } +private: + Athena::MsgStreamMember m_stream; +}; + +int main() { + ISvcLocator* pDum; + assert( Athena_test::initGaudi(pDum) ); + IMessageSvc *pMS(Athena::getMessageSvc()); + assert( pMS ); + //usual nasty trick to get the ref count + pMS->addRef(); + unsigned int refCount(pMS->release()); + std::cout << "Initial message svc ref count " << refCount << std::endl; + { + Mine my; + my.printIt(); + Yours you(pMS); + Yours alsoYours(you); + alsoYours.printIt(); + Hers her(pMS); + her.printIt(); + } //my, you, etc destructors called + + MsgStreamMember mm(Athena::Options::Eager, "Foo"); + + longlong t0(System::currentTime(System::microSec)); + for (int i=0; i<1000; ++i) MsgStreamMember(Athena::Options::Eager, "Foo"); + + // pMS->addRef(); + // std::cout << "ref count after eager creation " << pMS->release() << std::endl; + longlong t1(System::currentTime(System::microSec)); + for (int i=0; i<10; ++i) mm << MSG::ALWAYS << "bla" << endmsg; + + longlong t2(System::currentTime(System::microSec)); + + std::cout << "Wall clock time to create a MsgStreamMember (microsec)" << (t1-t0) * 1e-3 <<std::endl; + std::cout << "Wall clock time to print bla using MsgStreamMember (microsec)" << (t2-t1) * 0.1 <<std::endl; + + + pMS->addRef(); + unsigned int refCountAfter(pMS->release()); + std::cout << "Final ref count " << refCountAfter << std::endl; + + ///FIXME Gaudi bug#74192 assert(refCountAfter == refCount); + + std::cout << "*** MsgStreamMember_test OK ***" <<std::endl; + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/RCUObject_test.cxx b/EDM/athena/Control/AthenaKernel/test/RCUObject_test.cxx new file mode 100644 index 00000000..fa78f316 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/RCUObject_test.cxx @@ -0,0 +1,265 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file RCUObject_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief Regression tests for RCUObject. + */ + +#undef NDEBUG + +#include "AthenaKernel/RCUObject.h" +#include "AthenaKernel/IRCUSvc.h" +#include "boost/thread/shared_mutex.hpp" +#include "boost/thread/shared_lock_guard.hpp" +#include <cassert> +#include <iostream> +#include <thread> +#include <mutex> +#include <atomic> + + +using Athena::IRCUObject; +using Athena::RCUObject; +using Athena::IRCUSvc; +using Athena::RCURead; +using Athena::RCUReadQuiesce; +using Athena::RCUUpdate; + + +const int nslots = 4; + + +class TestRCUSvc + : public IRCUSvc +{ +public: + virtual StatusCode remove (IRCUObject* obj) override + { + m_removed = obj; + return StatusCode::SUCCESS; + } + virtual size_t getNumSlots() const override + { return nslots; } + virtual void add (IRCUObject* /*obj*/) override + { } + + virtual unsigned long addRef() override { std::abort(); } + virtual unsigned long release() override { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override { std::abort(); } + + IRCUObject* m_removed = nullptr; +}; + + +struct Payload +{ + Payload (int x=0) + : a(x), b(x), c(x), d(x) + { + ++ninstance; + } + Payload& operator= (const Payload&) = default; + ~Payload() + { + --ninstance; + if (dolog) { + std::lock_guard<std::mutex> g (m_mutex); + m_dlog.push_back(a); + } + } + static + std::vector<int> getlog() + { + std::lock_guard<std::mutex> g (m_mutex); + std::vector<int> log; + log.swap (m_dlog); + return log; + } + void check(int x) const + { + assert (a == x); + assert (b == x); + assert (c == x); + assert (d == x); + } + void check() const + { + check(a); + } + int a, b, c, d; + + static std::atomic<int> ninstance; + static bool dolog; + +private: + static std::vector<int> m_dlog; + static std::mutex m_mutex; +}; + +std::atomic<int> Payload::ninstance; +bool Payload::dolog = true; +std::vector<int> Payload::m_dlog; +std::mutex Payload::m_mutex; + + +void test1() +{ + std::cout << "test1\n"; + + TestRCUSvc svc; + { + RCUObject<Payload>* optr = nullptr; + { + RCUObject<Payload> rcuo (svc, 3); + RCURead<Payload> r (rcuo); + r->check(3); + + optr = &rcuo; + assert (svc.m_removed == nullptr); + } + assert (svc.m_removed == optr); + } + Payload::getlog(); +} + + +void test2() +{ + std::cout << "test2\n"; + TestRCUSvc svc; + + + RCUObject<Payload> rcuo (svc); + { + RCURead<Payload> r (rcuo); + r->check(0); + } + { + EventContext ctx (0, 1); + RCUUpdate<Payload> u (rcuo, ctx); + u->check(0); + u.update (std::make_unique<Payload> (2)); + u->check(2); + } + { + RCURead<Payload> r (rcuo); + r->check(2); + } + { + EventContext ctx (0, 2); + RCUReadQuiesce<Payload> r (rcuo, ctx); + r->check(2); + } + assert (Payload::getlog().empty()); + rcuo.quiescent (EventContext (0, 0)); + assert (Payload::getlog().empty()); + Gaudi::Hive::setCurrentContextId(3); + rcuo.quiescent (); + assert (Payload::getlog() == std::vector<int>{0}); +} + + +class ThreadedTest +{ +public: + ThreadedTest (TestRCUSvc& svc); + void runtest(); + + struct testThread + { + testThread (ThreadedTest& test, int iworker) + : m_test(test), m_iworker(iworker) {} + void operator()(); + + ThreadedTest& m_test; + int m_iworker; + }; + +private: + boost::shared_mutex m_sm; + RCUObject<Payload> m_rcuobj; +}; + + +ThreadedTest::ThreadedTest (TestRCUSvc& svc) + : m_rcuobj(svc) +{ +} + +void ThreadedTest::runtest() +{ + std::thread threads[nslots]; + m_sm.lock(); + for (int i=0; i < nslots; i++) + threads[i] = std::thread (testThread (*this, i)); + // Try to get the threads starting as much at the same time as possible. + m_sm.unlock(); + for (int i=0; i < nslots; i++) + threads[i].join(); + for (int i=0; i < nslots; i++) + m_rcuobj.quiescent (EventContext (0, i)); +} + + +void ThreadedTest::testThread::operator()() +{ + boost::shared_lock_guard<boost::shared_mutex> guard (m_test.m_sm); + Gaudi::Hive::setCurrentContextId (m_iworker); + + for (int i=0; i < 10000; i++) { + if (i%5 == 0) { + auto r = m_test.m_rcuobj.reader(); + r->check(); + } + else if (i%29 == 0) { + if (i%2 == 0) { + auto r = m_test.m_rcuobj.readerQuiesce (EventContext (0, m_iworker)); + r->check(); + } + else { + auto r = m_test.m_rcuobj.readerQuiesce(); + r->check(); + } + } + else if (i%17 == 0) { + EventContext ctx (0, m_iworker); + RCUObject<Payload>::Update_t u (m_test.m_rcuobj, ctx); + u.update (std::make_unique<Payload> (u->a)); + } + + if (i%13 == 0) + m_test.m_rcuobj.quiescent (EventContext (0, m_iworker)); + } +} + + +void test3() +{ + std::cout << "test3\n"; + + Payload::dolog = false; + assert (Payload::ninstance == 0); + { + TestRCUSvc svc; + ThreadedTest test (svc); + for (int i=0; i < 1000; i++) + test.runtest(); + assert (Payload::ninstance == 1); + } + assert (Payload::ninstance == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} + diff --git a/EDM/athena/Control/AthenaKernel/test/Units_test.cxx b/EDM/athena/Control/AthenaKernel/test/Units_test.cxx new file mode 100644 index 00000000..0fc7bfc2 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/Units_test.cxx @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file Units_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2015 + * @brief Regression tests for Units package. + */ + + +#undef NDEBUG + + +#include "AthenaKernel/Units.h" +#include "GaudiKernel/SystemOfUnits.h" +#include "TestTools/FLOATassert.h" +#include <cassert> +#include <string.h> +#include <stdio.h> +#include <unistd.h> + + +template <class NUM> +void testunits() +{ +#define TESTUNIT(NAME) \ + { \ + using Athena::Units::NAME; \ + volatile NUM val = 123.5; \ + NUM val2 = val * NAME; \ + NUM val3 = val2 / NAME; \ + assert (std::abs (val3 - val) < 1e-6*val); \ + } + + TESTUNIT(GeV); + TESTUNIT(cm3); + TESTUNIT(gram); + TESTUNIT(micrometer); +} + + +void test1() +{ + std::cout << "test1\n"; + testunits<float>(); + testunits<double>(); +} + + +void divcheck() +{ + std::cout << "divcheck\n"; + pid_t pid = getpid(); + char cmd[128]; + snprintf (cmd, sizeof(cmd), "objdump -d /proc/%d/exe", pid); + FILE* fdump = popen (cmd, "r"); + assert (fdump != nullptr); + bool readingtest = false; + char linebuf[2048]; + while (fgets (linebuf, sizeof(linebuf), fdump)) { + size_t len = strlen (linebuf); + if (len < 6) continue; + if (linebuf[len-1] == '\n') { + --len; + linebuf[len] = '\0'; + } + + if (readingtest && (strstr (linebuf, "\tdiv") != 0 || + strstr (linebuf, "tfdiv") != 0)) + { + printf ("Unexpected div: %s\n", linebuf); + } + + if (linebuf[0] != '0') continue; + if (linebuf[len-1] != ':' || linebuf[len-2] != '>') continue; + char* pos = strchr (linebuf, '<'); + if (!pos) continue; + if (strstr (linebuf, "test") != 0) + readingtest = true; + else + readingtest = false; + } + + pclose (fdump); +} + + +int main() +{ + test1(); + divcheck(); + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/errorcheck_test.cxx b/EDM/athena/Control/AthenaKernel/test/errorcheck_test.cxx new file mode 100644 index 00000000..a57eac03 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/errorcheck_test.cxx @@ -0,0 +1,219 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: errorcheck_test.cxx,v 1.6 2009-04-09 15:11:18 ssnyder Exp $ +/** + * @file errorcheck_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2006 + * @brief Regression tests for errorcheck. + */ + +#undef NDEBUG + +#include "AthenaKernel/errorcheck.h" +#include "TestTools/initGaudi.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/Algorithm.h" +#include "GaudiKernel/AlgTool.h" +#include "GaudiKernel/Service.h" +#include "GaudiKernel/Bootstrap.h" +#include <cassert> + + +class Algtest + : public Algorithm +{ +public: + Algtest() + : Algorithm ("algname", Gaudi::svcLocator()) {} + virtual StatusCode execute() { return StatusCode (StatusCode::SUCCESS); } + StatusCode test1(); +}; + + +StatusCode Algtest::test1() +{ + REPORT_ERROR (StatusCode (StatusCode::FAILURE)) << "foomsg"; + REPORT_MESSAGE (MSG::INFO) << "some info"; + CHECK( StatusCode (StatusCode::SUCCESS) ); + CHECK( StatusCode (StatusCode::FAILURE) ); + return StatusCode (StatusCode::SUCCESS); +} + + +class Algtooltest + : public AlgTool +{ +public: + Algtooltest (IInterface* parent) + : AlgTool ("tooltype", "toolname", parent) {} + StatusCode test1(); +}; + + +StatusCode Algtooltest::test1() +{ + REPORT_ERROR (StatusCode (StatusCode::FAILURE)) << "foomsg"; + REPORT_MESSAGE (MSG::INFO) << "some info"; + CHECK_CODE( StatusCode (StatusCode::SUCCESS), 123 ); + CHECK_CODE( StatusCode (StatusCode::RECOVERABLE), 123 ); + return StatusCode (StatusCode::SUCCESS); +} + + +class Servtest + : public Service +{ +public: + Servtest() + : Service ("servname", Gaudi::svcLocator()) {} + StatusCode test1(); +}; + + +StatusCode Servtest::test1() +{ + REPORT_ERROR (StatusCode (StatusCode::FAILURE)) << "foomsg"; + REPORT_MESSAGE (MSG::INFO) << "some info"; + CHECK_RECOVERABLE( StatusCode (StatusCode::SUCCESS) ); + CHECK_RECOVERABLE( StatusCode (StatusCode::FAILURE) ); + return StatusCode (StatusCode::SUCCESS); +} + + +class Test +{ +public: + StatusCode test1(); +}; + + +StatusCode Test::test1() +{ + REPORT_ERROR (StatusCode (StatusCode::FAILURE)) << "foomsg"; + REPORT_MESSAGE (MSG::INFO) << "some info"; + CHECK_FATAL( StatusCode (StatusCode::SUCCESS) ); + CHECK_FATAL( StatusCode (StatusCode::RECOVERABLE) ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1a() +{ + CHECK_WITH_CONTEXT( StatusCode (StatusCode::SUCCESS), "alg" ); + CHECK_WITH_CONTEXT( StatusCode (StatusCode::FAILURE), "alg" ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1b() +{ + CHECK_RECOVERABLE_WITH_CONTEXT( StatusCode (StatusCode::SUCCESS), "alg" ); + CHECK_RECOVERABLE_WITH_CONTEXT( StatusCode (StatusCode::FAILURE), "alg" ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1c() +{ + CHECK_RECOVERABLE_WITH_CONTEXT( StatusCode (StatusCode::SUCCESS), "alg" ); + CHECK_RECOVERABLE_WITH_CONTEXT( StatusCode (StatusCode::RECOVERABLE),"alg" ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1d() +{ + CHECK_FATAL_WITH_CONTEXT( StatusCode (StatusCode::SUCCESS), "alg" ); + CHECK_FATAL_WITH_CONTEXT( StatusCode (StatusCode::FAILURE), "alg" ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1e() +{ + CHECK_FATAL_WITH_CONTEXT( StatusCode (StatusCode::SUCCESS), "alg" ); + CHECK_FATAL_WITH_CONTEXT( StatusCode (StatusCode::RECOVERABLE), "alg" ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1f() +{ + CHECK_CODE_WITH_CONTEXT( StatusCode (StatusCode::SUCCESS), "alg", 123 ); + CHECK_CODE_WITH_CONTEXT( StatusCode (StatusCode::RECOVERABLE), "alg", 123 ); + return StatusCode (StatusCode::SUCCESS); +} + + +StatusCode test1() +{ + Algtest algtest; algtest.addRef(); + Algtooltest algtooltest (&algtest); algtooltest.addRef(); + Servtest servtest; servtest.addRef(); + Test test; + REPORT_ERROR_WITH_CONTEXT (StatusCode (StatusCode::FAILURE), "alg") + << "foomsg"; + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "alg") + << "some message"; + { + errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "alg"); + msg << "a... "; + msg << "b"; + } + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "alg") << "foo" << endmsg; + assert( test1a().isFailure() ); + assert( test1b().isFailure() ); + assert( test1c().isFailure() ); + assert( test1d().isFailure() ); + assert( test1e().isFailure() ); + assert( test1f().isFailure() ); + assert( algtest.test1().isFailure() ); + assert( algtooltest.test1().isFailure() ); + assert( servtest.test1().isFailure() ); + assert( test.test1().isFailure() ); + + errorcheck::ReportMessage::hideErrorLocus(); + REPORT_ERROR_WITH_CONTEXT (StatusCode (StatusCode::FAILURE), "alg") + << "foox"; + errorcheck::ReportMessage::hideErrorLocus (false); + REPORT_ERROR_WITH_CONTEXT (StatusCode (StatusCode::FAILURE), "alg") + << "fooy"; + return StatusCode (StatusCode::SUCCESS); +} + + +namespace errorcheck { +std::string clean_allocator (std::string f); +} + + +void test2 (std::vector<int> = std::vector<int>(), + const int* = 0, + int (*)() = 0, + int [] = 0) +{ + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "test2") << "test2" << endmsg; + + assert (errorcheck::clean_allocator ("void test2(std::vector<int, std::allocator<int> >, const int*, int (*)(), int*)") == + "void test2(std::vector<int>, const int*, int (*)(), int*)"); +} + + +void test3 (const std::string& = "", int = 0) +{ + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "test3") << "test3" << endmsg; +} + + +int main() +{ + ISvcLocator* loc; + assert( Athena_test::initGaudi (loc) ); + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/getMessageSvc_test.cxx b/EDM/athena/Control/AthenaKernel/test/getMessageSvc_test.cxx new file mode 100644 index 00000000..3418be56 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/getMessageSvc_test.cxx @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file getMessageSvc_test.cxx + * @author Paolo Calafiura + * @brief Regression test for getMessageSvc() + * + * get a MsgSvc pointer out of thin air and use it + * + * $Id: getMessageSvc_test.cxx,v 1.5 2008-07-14 22:10:14 calaf Exp $ + */ +#undef NDEBUG +#include <cassert> +#include "GaudiKernel/MsgStream.h" +#include "TestTools/initGaudi.h" +#include "AthenaKernel/getMessageSvc.h" + +class Mine { +public: + void printIt() { + MsgStream mlog(m_ims, "Mine"); + mlog << MSG::ALWAYS << "*** Mine works ***" <<endmsg; + } +private: + Athena::IMessageSvcHolder m_ims; +}; +class Yours { +public: + Yours(IMessageSvc* ims) : m_ims(ims) {} + void printIt() { + MsgStream mlog(m_ims.get(), "Yours"); + mlog << MSG::ALWAYS << "*** Yours works too ***" <<endmsg; + } +private: + Athena::IMessageSvcHolder m_ims; +}; + +int main() { + ISvcLocator* pDum; + assert( Athena_test::initGaudi(pDum) ); + IMessageSvc *pMS(Athena::getMessageSvc()); + assert( pMS ); + //usual nasty trick to get the ref count + pMS->addRef(); + unsigned int refCount(pMS->release()); + //check it is a singleton + IMessageSvc *another(Athena::getMessageSvc()); + assert(another == pMS); + assert(refCount == pMS->release()); + + { + Mine my; + my.printIt(); + //this simulates what would happen in a Gaudi component + Yours you(pMS); + you.printIt(); + } //my, you destructors called + pMS->addRef(); + // assert(pMS->release() == refCount); + + MsgStream log(pMS, "getMessageSvc_test"); + log << MSG::ALWAYS << "*** getMessageSvc_test OK ***" <<endmsg; + return 0; +} diff --git a/EDM/athena/Control/AthenaKernel/test/type_tools_test.cxx b/EDM/athena/Control/AthenaKernel/test/type_tools_test.cxx new file mode 100644 index 00000000..540e2152 --- /dev/null +++ b/EDM/athena/Control/AthenaKernel/test/type_tools_test.cxx @@ -0,0 +1,21 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: type_tools_test.cxx,v 1.1 2006-03-13 18:44:32 ssnyder Exp $ +/** + * @file type_tools_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2006 + * @brief Regression tests for type_tools. + * + * This is a null test for now, but it sufficies to shut up + * checkreq's complaint that boost isn't used. + */ + +#include "AthenaKernel/tools/type_tools.h" + +int main() +{ + return 0; +} diff --git a/EDM/athena/Control/CLIDComps/CMakeLists.txt b/EDM/athena/Control/CLIDComps/CMakeLists.txt new file mode 100644 index 00000000..728b9f72 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/CMakeLists.txt @@ -0,0 +1,54 @@ +# $Id: CMakeLists.txt 787831 2016-12-02 10:18:34Z krasznaa $ +################################################################################ +# Package: CLIDComps +################################################################################ + +# Declare the package name: +atlas_subdir( CLIDComps ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PRIVATE + Control/AthenaKernel + Control/SGTools + AtlasTest/TestTools + GaudiKernel ) + +# External dependencies: +find_package( Boost COMPONENTS program_options ) + +# Component(s) in the package: +atlas_add_component( CLIDComps + src/*.h src/*.cxx src/components/*.cxx + NOCLIDDB + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} AthenaKernel SGTools GaudiKernel ) + +# Executable(s) in the package: +atlas_add_executable( genCLIDDB + util/genCLIDDB.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} GaudiKernel AthenaKernel ) +if( TARGET genCLIDDB AND TARGET CLIDComps ) + add_dependencies( genCLIDDB CLIDCompsComponentsList ) +endif() + +# Test(s) in the package: +atlas_add_test( ClassIDSvc_test + SOURCES test/ClassIDSvc_test.cxx + LINK_LIBRARIES AthenaKernel SGTools GaudiKernel TestTools + EXTRA_PATTERNS "WARNING Could not resolve clid DB|^JobOptionsSvc +INFO|DEBUG Property update for OutputLevel" + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_runtime( share/Gaudi_clid.db ) +atlas_install_scripts( share/clid test/_clid_unittest.py ) +atlas_install_joboptions( share/*.opts ) + +# Make sure that the jobOptions are installed before building genCLIDDB. +# Otherwise the build system may try to use it before everything needed +# by it is in place. +if( TARGET genCLIDDB ) + add_dependencies( genCLIDDB CLIDCompsJobOptInstall ) +endif() diff --git a/EDM/athena/Control/CLIDComps/cmt/requirements b/EDM/athena/Control/CLIDComps/cmt/requirements new file mode 100644 index 00000000..42e28366 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/cmt/requirements @@ -0,0 +1,28 @@ +package CLIDComps + +author Paolo Calafiura <Paolo.Calafiura@cern.ch> + +use AtlasPolicy AtlasPolicy-* + +private +use AtlasBoost AtlasBoost-* External +use GaudiInterface GaudiInterface-* External +use AthenaKernel AthenaKernel-* Control +use SGTools SGTools-* Control +end_private + +library CLIDComps *.cxx -s=components *.cxx +apply_pattern component_library_no_genCLIDDB + +apply_pattern declare_scripts files="clid ../test/_clid_unittest.py" +apply_pattern declare_python_modules files="*.py" +apply_pattern declare_runtime files="Gaudi_clid.db" + +private +use TestTools TestTools-* AtlasTest +apply_pattern install_runtime +apply_pattern UnitTest_run unit_test=ClassIDSvc \ + extrapatterns="WARNING Could not resolve clid DB|^JobOptionsSvc +INFO" +macro_append DOXYGEN_INPUT " ../test ../share " +macro_append DOXYGEN_FILE_PATTERNS " *.icc clid " +end_private diff --git a/EDM/athena/Control/CLIDComps/python/__init__.py b/EDM/athena/Control/CLIDComps/python/__init__.py new file mode 100644 index 00000000..908f6426 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/python/__init__.py @@ -0,0 +1,6 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' +__author__ = 'pcalafiura@lbl.gov' + +__all__ = [ 'clidGenerator' ] diff --git a/EDM/athena/Control/CLIDComps/python/clidGenerator.py b/EDM/athena/Control/CLIDComps/python/clidGenerator.py new file mode 100644 index 00000000..ebb34f35 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/python/clidGenerator.py @@ -0,0 +1,167 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +## @file clidGenerator.py +# @author CETull@lbl.gov +# @brief Athena CLID Generator Class +# +import string, re, os, csv + +## Athena CLID Generator Class +class clidGenerator (object): + "Athena CLID Generator" + __clidGenerator_type = "Basic" + __clidGenerator_version = "$Revision: 1.4 $" + # CLID Mask: Determines bits used for CLID + __mask = 0x0FFFFFFF + # CLID Repositories - Dictionaries of CLID<=>Name + __clidRep = {} # Lookup by CLID + __clidPkg = {} # Lookup by CLID + __clidTid = {} # Lookup by CLID + __nameRep = {} # Lookup by ClassName + __tidRep = {} # Lookup by typeid-name + # CLID DataBase (Default = clid.db) +# __cliddb = os.getenv('CLIDDB') + def __init__(self, db, debug=False): + self.setCLIDDB(db, debug) + self.readdb() + + def cleardb(self): + clidGenerator.__clidRep = {} # Lookup by CLID + clidGenerator.__nameRep = {} # Lookup by ClassName + + def readdb(self): + "Read CLID DataBase file" + try: + for cliddb in self.__cliddbs: + if os.path.isfile(cliddb): + for row in csv.reader (open(cliddb, 'r'), + delimiter=';'): + row = [i.strip() for i in row] + if len(row) >= 3: + clid = int(row[0]) + class_name = row[1] + pkg_name = row[2] + if len(row) > 3: tid_name = row[3] + else: tid_name = class_name + + self.__clidRep[clid] = class_name + self.__clidPkg[clid] = pkg_name + self.__clidTid[clid] = tid_name + self.__nameRep[class_name] = clid + self.__tidRep [tid_name] = clid + + else: + print "No CLID DataBase file <%s> " % cliddb + except Exception, err: + print "Error reading from CLID DataBase files <%s>:\n%s " % ( + self.__cliddbs, + err) + + def setCLIDDB(self, db, debug): + "Initializes a CLID Generator object with a CLID Database" + if db: + self.__cliddbs = search_files(db, os.getenv('DATAPATH')) + if debug: print "Using specified CLID DataBase files %s " % self.__cliddbs + elif os.getenv('CLIDDB'): + # CLID DataBase (Default = clid.db) + self.__cliddbs.append(os.getenv('CLIDDB')) + if debug: print "Using DataBase file from CLIDDB env variable %s " % self.__cliddbs + else: + self.__cliddbs = search_files('clid.db', os.getenv('DATAPATH')) + if debug: print "Using DataBase file from DATAPATH %s " % self.__cliddbs + + def writedb(self,db): + "Read CLID DataBase file" + output = open(db,'w') + for k in self.__clidRep.keys(): + output.write("%d "%k+self.__clidRep[k]+"\n") + output.close() + def genClidFromName(self,className): + """Generate CLID from ClassName: A recursive hash with a bit + mask and validity range. Will check collisions against and + update CLID Repository.""" + n = self.demangleClassName(className) + c = self.getClidFromName(className) + if c: + return c + c = hash(className) & self.__mask + if c < 10001 or c > self.__mask: + c = self.genClidFromName(className+'_') + if self.isCollection(className): + c += 0x40000000 + if self.__clidRep.has_key(c): + if n != self.__clidRep[c]: + c = self.genClidFromName(className+'_') + else: + self.__clidRep[c] = n + self.__clidTid[c] = n # make typeid name the same than class-name + self.__nameRep[n] = c + self.__tidRep [n] = c # idem + return c + def getClidFromName(self,className): + "Get the CLID in the repository of class name <className>" + if self.__nameRep.has_key(className): + return self.__nameRep[className] + else: + return None + def getClidFromTid(self,tidName): + "Get the CLID in the repository of typeid name <tidName>" + if tidName in self.__tidRep: + return self.__tidRep[tidName] + else: + return None + def getNameFromClid(self,clid): + "Get the class name in the repository with CLID <clid>" + if self.__clidRep.has_key(clid): + return self.__clidRep[clid] + else: + return None + def getTidFromClid(self,clid): + "Get the typeid name in the repository with CLID <clid>" + if clid in self.__clidTid: + return self.__clidTid[clid] + else: + return None + def getPackageFromClid(self,clid): + "Get the name of the package defining <clid>" + if self.__clidPkg.has_key(clid): + return self.__clidPkg[clid] + else: + return None + def demangleClassName(self,s): + return s +# pat = re.compile('\s*(.?)__*\s*') +# n = pat.findall(s) +# if n: +# return n[0] +# else: +# return s + + def isCollection(self,className): + collMatch = re.search(r'.*?Collection_*|.*?Container_*',className) + return collMatch + + def findPattern(self,s): + """Find the regular expression pattern s in dictionary.""" +# pat = re.compile('^'+s+'$') + pat = re.compile(s) + results = {} + for k in self.__clidRep.keys(): + if pat.match(str(k)) or pat.match(self.__clidRep[k]): + results[k] = self.__clidRep[k] + return results + +def search_file(filename, search_path, pathsep=os.pathsep): + """Given a search path, find file with requested name """ + for path in string.split(search_path, pathsep): + candidate = os.path.join(path, filename) + if os.path.exists(candidate): return os.path.abspath(candidate) + return None + +def search_files(filename, search_path, pathsep=os.pathsep): + """Given a search path, find file with requested name """ + clidFiles = [] + for path in string.split(search_path, pathsep): + candidate = os.path.join(path, filename) + if os.path.exists(candidate): clidFiles.append(os.path.abspath(candidate)) + return clidFiles diff --git a/EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.ref b/EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.ref new file mode 100644 index 00000000..562f85b4 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.ref @@ -0,0 +1,53 @@ +Warning in <TEnvRec::ChangeValue>: duplicate entry <Root.ErrorIgnoreLevel=Print> for level 1; ignored + + +Initializing Gaudi ApplicationMgr using job opts ../share/ClassIDSvc_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/work/c/calaf/public/sepTut/Control/CLIDComps/run/../share/ClassIDSvc_test.txt +JobOptionsSvc INFO # (1,1): ClassIDSvc.OutputLevel = 2 +JobOptionsSvc INFO # (2,1): ClassIDSvc.OutputFileName = "CLIDTestOut.db" +JobOptionsSvc INFO # (3,1): ClassIDSvc.CLIDDBFiles = ["notthere.db", "clid.db"] +JobOptionsSvc INFO Job options successfully read in from ../share/ClassIDSvc_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v3r1) + running on lxplus0223.cern.ch on Wed Sep 3 19:19:27 2014 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +*** ClassIDSvc basic test starts *** +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-06-12 +ClassIDSvc DEBUG Service base class initialized successfully +ClassIDSvc WARNING Could not resolve clid DB path notthere.db using DATAPATH [/afs/cern.ch/work/c/calaf/public/sepTut/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasOffline/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasSimulation/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasAnalysis/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasTrigger/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasReconstruction/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasEvent/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasConditions/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/AtlasCore/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/DetCommon/rel_4/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/GAUDI/rel_4/InstallArea/share:/afs/cern.ch/atlas/offline/external/LCGCMT/LCGCMT_67b/InstallArea/share:/afs/cern.ch/atlas/software/builds/nightlies/devval/GAUDI/rel_4/PartPropSvc/share:/afs/cern.ch/atlas/offline/ReleaseData/v19:/afs/cern.ch/atlas/offline/ReleaseData/v19/testfile:/afs/cern.ch/atlas/project/magfield/CTB] ----- SKIPPING +ClassIDSvc INFO getRegistryEntries: read 49 CLIDRegistry entries for module ALL +Now we expect to see an error message: +----Error Message Starts--->> +ClassIDSvc FATAL setTypeNameForID: input id 128 is out of allowed range 256 : 2147483647 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +ClassIDSvc FATAL setTypeNameForID: input id 4294967294 is out of allowed range 256 : 2147483647 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +ClassIDSvc ERROR uncheckedSetTypePackageForID: CLIDComps-00-06-12 can not set type name <Ble> for CLID 7890: Known name for this ID <Bla> It was set by APack-00-39-98 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +ClassIDSvc ERROR uncheckedSetTypePackageForID: CLIDComps-00-06-12 can not set CLID <9945> for type name Bli: Known CLID for this name <9942> It was set by CLIDComps-00-06-12 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +ClassIDSvc ERROR uncheckedSetTypePackageForID: APack-00-39-98 can not set type name <Bl a> for CLID 7890: Known name for this ID <Bla> It was set by APack-00-39-98 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +ClassIDSvc ERROR uncheckedSetTypePackageForID: APack-00-39-98 can not set type name <B l a> for CLID 7890: Known name for this ID <Bla> It was set by APack-00-39-98 +<<---Error Message Ends------- +ClassIDSvc INFO finalize: wrote 1233 entries to output CLIDDB file: CLIDTestOut.db +*** ClassIDSvc basic test OK *** +*** ClassIDSvc incident test starts *** +*** ClassIDSvc incident test OK *** diff --git a/EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.txt b/EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.txt new file mode 100644 index 00000000..5ec353a1 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/ClassIDSvc_test.txt @@ -0,0 +1,3 @@ +ClassIDSvc.OutputLevel = 2; +ClassIDSvc.OutputFileName = "CLIDTestOut.db"; +ClassIDSvc.CLIDDBFiles = { "notthere.db", "clid.db" }; diff --git a/EDM/athena/Control/CLIDComps/share/Gaudi_clid.db b/EDM/athena/Control/CLIDComps/share/Gaudi_clid.db new file mode 100644 index 00000000..a91add94 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/Gaudi_clid.db @@ -0,0 +1,24 @@ +0; NULL; Gaudi-v19; +1; DataObject; Gaudi-v19 +3; Catalog; Gaudi-v19 +32; H1D; Gaudi-v19 +33; H1DVar; Gaudi-v19 +34; ProfileH; Gaudi-v19 +35; ProfileHVar; Gaudi-v19 +36; H2D; Gaudi-v19 +37; H2DF; Gaudi-v19 +38; H2DVar; Gaudi-v19 +39; ProfileH2; Gaudi-v19 +40; StatisticsFile; Gaudi-v19 +41; StatisticsDirectory; Gaudi-v19 +42; RowWiseTuple; Gaudi-v19 +43; ColumnWiseTuple; Gaudi-v19 +50; H3D; Gaudi-v19 +51; H3DF; Gaudi-v19 +52; H3DVar; Gaudi-v19 +100; Run; Gaudi-v19 +110; Event; Gaudi-v19 +111; Collision; Gaudi-v19 +190; ContainedObject; Gaudi-v19 +300; RefTable1to1; Gaudi-v19 +301; RefTable1toN; Gaudi-v19 diff --git a/EDM/athena/Control/CLIDComps/share/PYTHONSTARTUP b/EDM/athena/Control/CLIDComps/share/PYTHONSTARTUP new file mode 100644 index 00000000..2632388f --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/PYTHONSTARTUP @@ -0,0 +1,8 @@ +# +print """======================================== +This is your local PYTHONSTARTUP file.""" +import clidGen +c = clidGen.clidGenerator("") +id = c.genClidFromName("Craig") +print id,"Craig" +# diff --git a/EDM/athena/Control/CLIDComps/share/clid b/EDM/athena/Control/CLIDComps/share/clid new file mode 100644 index 00000000..9ab951d0 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/clid @@ -0,0 +1,87 @@ +exec python -tx "$0" "$@" + +## @file clid +# @brief CLI to Athena CLID DB. "clid -h" for help +# @author cetull@lbl.gov, pcalafiura@lbl.gov + +import string, re +import sys, os +from CLIDComps.clidGenerator import clidGenerator +from optparse import OptionParser + +# +def help_examples(prog): + print "Usage Examples: " + print ' ',prog,' -m LArCell' + print ' ',prog,' 2001' + print ' ',prog,' --cliddb=clid.db -f "Cr"' + + + +# +# options and their arguments. +# +parser = OptionParser(usage="%prog [options] [class name] OR [clid] (Enter %prog -h for help)", version="%prog - Athena CLID Generator v 2.0") +parser.add_option("-b", "--cliddb", dest="cliddb", + help="Reconcile generated CLID with CLID DataBase CLIDDB", + metavar="CLIDDB") +parser.add_option("-d", "--debug", action="store_true", dest="debug", + help="Print debug information during execution", default=False) +parser.add_option("-f", "--find", + action="append", dest="relist", + help="Find entry whose ClassName or CLID matches regex. \n (See Python re module for syntax of REGEX.)", + metavar="REGEX") +parser.add_option("-m", "--macro", action="store_true", dest="macro", + help="Print StoreGate CLASS_DEF macro line", default=False) +parser.add_option("-s", "--silent", action="store_true", dest="silent", + help=" Be more silent on output. Print _only_ result. \n (N.B. Overrides -m option.)", default=False) +# +#load options +# +(options, args) = parser.parse_args() +#print options +#print args +if len(args) != 1 and options.relist == None: + parser.error("takes exactly 1 argument") + +# +# Initialize +# +if options.cliddb: + cgen = clidGenerator(options.cliddb, options.debug) +else: + cgen = clidGenerator("", options.debug) + +if options.debug: print "repository = ",cgen._clidGenerator__clidRep + +# +# Process ClassName arguments +# +for a in args: + try: + i = int(a) + except: + n = a + c = cgen.genClidFromName(a) + else: + n = cgen.getNameFromClid(i) + c = i + if not n: + n = ">>>Not Found in CLIDDB<<<" + if options.debug: + print c,n,'(',hash(n),hash(n)&cgen._clidGenerator__mask,"%8x"%c,')' + else: + if options.macro: print "CLASS_DEF(",n,",",c,", 1 )" + else: + if options.silent: print c + else: + print c, n, cgen.getPackageFromClid(c) + +# +# Process RegEx list +# +if options.relist: + for p in options.relist: + print '>>> Searching CLIDDB for (',p,') <<<' + print cgen.findPattern(p) + diff --git a/EDM/athena/Control/CLIDComps/share/cvs2cliddb.csh b/EDM/athena/Control/CLIDComps/share/cvs2cliddb.csh new file mode 100644 index 00000000..f9264b91 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/cvs2cliddb.csh @@ -0,0 +1,74 @@ +#!/bin/csh -f +# +# 05feb03 - cetull@lbl.gov +# WARNING: This shell script makes heavy use of regexp magic. Edit only +# if you are very comfortable with regular expressions. +# +if (${#argv} > 1) then + echo "usage: $0 [TOPDIRS=$CMTPATH]" + exit -1; +else if (${#argv} == 0) then + set TOPDIRS=$CMTPATH +else + set TOPDIRS=$1 +endif + +set TOP_DIRS="`echo $TOPDIRS | sed -e 's/:/ /g'`" + + +touch clid.junk || exit "No write access to $PWD" && exit -1 +touch clid.cvs1 || exit "No write access to $PWD" && exit -1 +foreach TOPDIR ( $TOP_DIRS ) + if (! -d $TOPDIR) then + echo "No such directory $TOPDIR" + exit -2 + endif + + + echo "Looking under ${TOPDIR}" + echo -n "Please wait, this may take a while." + + foreach f ( `find $TOPDIR -type f \( -name '*.h' -o -name '*.icc' -o -name '*.cxx' \) -print` ) + echo -n '.' + egrep -n 'CLASS_DEF' $f clid.junk | sed -e 's/[ ]//g' >> clid.cvs1 + egrep -n 'CLID.*=' $f clid.junk | sed -e 's/[ ]//g' >> clid.cvs1 + end + echo "" +end +# +touch clid.cvs +egrep ':CLASS_DEF2*(.*,[0-9]*,[0-9]*)' clid.cvs1 >> clid.cvs +egrep 'CLID&*CLID_.*=[0-9]*;' clid.cvs1 >> clid.cvs +# +touch clid.tmp +egrep ':CLASS_DEF2*\(' clid.cvs \ + | sed -e 's/.*:CLASS_DEF2*(\(.*\),\([0-9]*\),[0-9]*).*/\2 \1/' \ + >> clid.tmp +egrep 'CLID&*CLID_.*=[0-9]*;' clid.cvs \ + | sed -e 's/.*CLID&*CLID_\(.*\)=\([0-9]*\);.*/\2 \1/' \ + >> clid.tmp +sort -n clid.tmp | uniq > clid.sort +# +sed -e 's/.* //' clid.sort | sort | uniq \ + >> clid.names +sed -e 's/ .*//' clid.sort | sort | uniq \ + >> clid.ids +# +sed -e 's/.* //' clid.sort | sort | uniq -c | egrep -v ' 1 ' \ + >> clid.duplicatenames +sed -e 's/ .*//' clid.sort | sort | uniq -c | egrep -v ' 1 ' \ + >> clid.duplicateids +# +touch clid.duplicates +foreach f ( `sed -e 's/ *[0-9]* *//' clid.duplicate{ids,names}` ) + echo =========================== $f >> clid.duplicates + egrep $f clid.cvs >> clid.duplicates +end +# +echo '' +echo 'File clid.sort contains a candidate clid.db' +echo 'File clid.duplicatenames contains a list of duplicated names with count' +echo 'File clid.duplicateids contains a list of duplicated CLIDs with count' +echo 'File clid.duplicates contains the lines for duplicate names and CLIDs' +echo '' +# diff --git a/EDM/athena/Control/CLIDComps/share/minimalPrintout.opts b/EDM/athena/Control/CLIDComps/share/minimalPrintout.opts new file mode 100644 index 00000000..275a2138 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/share/minimalPrintout.opts @@ -0,0 +1,11 @@ +//Joboptions to minimize printout when running genCLIDDB +//based on example in POOLRootAccess/basic.opts +//Author: Will Buttinger + +#pragma print off //do not print +ApplicationMgr.OutputLevel = 0; //NIL ... so ApplicationMgr is silent +ApplicationMgr.EventLoop = "MinimalEventLoopMgr"; //for minimal service creation + +//Quieten the ClassIDSvc too +MessageSvc.setWarning = {"ClassIDSvc"}; + diff --git a/EDM/athena/Control/CLIDComps/src/ClassIDSvc.cxx b/EDM/athena/Control/CLIDComps/src/ClassIDSvc.cxx new file mode 100644 index 00000000..e8f96e3c --- /dev/null +++ b/EDM/athena/Control/CLIDComps/src/ClassIDSvc.cxx @@ -0,0 +1,588 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <algorithm> /* distance */ +#include <cstdlib> /* getenv */ +#include <fstream> +#include <iostream> +#include <iterator> +#include <boost/lexical_cast.hpp> +#include <boost/tokenizer.hpp> +#include <boost/algorithm/string/trim.hpp> +#include <boost/algorithm/string/replace.hpp> + +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/Incident.h" +#include "GaudiKernel/ModuleIncident.h" +#include "GaudiKernel/System.h" +#include "GaudiKernel/MsgStream.h" +#include "SGTools/CLIDRegistry.h" +#include "AthenaKernel/errorcheck.h" + +#include "ClassIDSvc.h" +using namespace std; + +namespace { + inline + void massage (string& s) { + boost::trim(s); + boost::replace_all(s, string(";"), string()); + } + +// HACK LIFTED FROM AthenaBaseComps/AthMsgStreamMacros.h to remove dep loop +#define ATH_MSG_LVL(lvl, x) \ + do { \ + if (msg().level() <= lvl) { \ + msg() << lvl << x << endmsg; \ + } \ + } while (0) + +#define ATH_MSG_VERBOSE(x) ATH_MSG_LVL(MSG::VERBOSE, x) +#define ATH_MSG_DEBUG(x) ATH_MSG_LVL(MSG::DEBUG, x) +#define ATH_MSG_INFO(x) ATH_MSG_LVL(MSG::INFO, x) + +} + + +/// Standard Constructor +ClassIDSvc::ClassIDSvc(const std::string& name,ISvcLocator* svc) + : Service(name,svc), m_outputFileName("NULL"), + m_clidDBPath(System::getEnv("DATAPATH")), + m_msg (msgSvc(), name), + m_regMutex() +{ + // Property Default values + m_DBFiles.push_back("clid.db"); + + // Get user's input + declareProperty("CLIDDBFiles", m_DBFiles, + "list of db files with (CLID, class_name) entries. Loaded at init in svc maps. Files are looked up in DATAPATH"); + declareProperty("OutputFileName", m_outputFileName, + "path to clid.db file in which write at finalize entries in m_clidMap. Default ('NULL') is not to write output clid.db"); + +} + +// Query the interfaces. +// Input: riid, Requested interface ID +// ppvInterface, Pointer to requested interface +// Return: StatusCode indicating SUCCESS or FAILURE. +// N.B. Don't forget to release the interface after use!!! + +StatusCode +ClassIDSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( IClassIDSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IClassIDSvc*)this; + } + else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + +StatusCode +ClassIDSvc::initialize() +{ + ATH_MSG_VERBOSE( "Initializing " << name() << " - package version " << + PACKAGE_VERSION ) ; + + CHECK( Service::initialize() ); + + // set up the incident service: + IIncidentSvc* pIncSvc(0); + const bool CREATEIF(true); + CHECK( service("IncidentSvc", pIncSvc, CREATEIF) ); + assert( 0 != pIncSvc ); + + const int PRIORITY = 100; + pIncSvc->addListener(this, ModuleLoadedIncident::TYPE(), PRIORITY); + pIncSvc->release(); + + return fillDB(); +} + +bool ClassIDSvc::getRegistryEntries(const std::string& moduleName) { + + std::lock_guard<std::recursive_mutex> lock(m_regMutex); + + //not only this is fast, but is necessary to prevent recursion + if (!CLIDRegistry::hasNewEntries()) return true; + + bool allOK(true); + //to speed up processing we only take entries added to CLIDRegistry + //since last call (thanks Niels!) + std::pair<CLIDRegistry::const_iterator, CLIDRegistry::const_iterator> er = + CLIDRegistry::newEntries(); + CLIDRegistry::const_iterator iEntry=er.first, endEntry=er.second; + while (allOK && (iEntry < endEntry)) { + const CLID& clid = boost::get<0>(*iEntry); + const std::string& typeName = boost::get<1>(*iEntry); + const Athena::PackageInfo& pkgInfo = boost::get<2>(*iEntry); + const std::string& typeInfoName = boost::get<3>(*iEntry); +#ifndef NDEBUG + ATH_MSG_VERBOSE( + "reading [" + << clid << ", " + << typeName << ", " + << pkgInfo << ", " + << typeInfoName << "]"); +#endif + allOK &= setTypePackageForID(clid, + typeName, + pkgInfo, + typeInfoName).isSuccess(); + ++iEntry; + } + + if (allOK) { + int nE = distance(er.first, er.second); + ATH_MSG_INFO( " getRegistryEntries: read " << nE + << " CLIDRegistry entries for module " << moduleName ); + } else { + msg() << MSG::ERROR + << " getRegistryEntries: can not read CLIDRegistry entries for module " + << moduleName << endmsg; + } + + return allOK; +} + + +inline +void ClassIDSvc::maybeRescan() const +{ + const_cast<ClassIDSvc*>(this)->getRegistryEntries ("ALL"); +} + + +void ClassIDSvc::handle(const Incident &inc) { + const ModuleLoadedIncident& modInc(dynamic_cast<const ModuleLoadedIncident&>(inc)); + + getRegistryEntries(modInc.module()); +} + + +StatusCode +ClassIDSvc::finalize() +{ + if (m_outputFileName != "NULL") { + ofstream outfile( m_outputFileName.c_str()); + if ( !outfile ) { + msg() << MSG::ERROR << "unable to open output CLIDDB file: " + << m_outputFileName << endmsg; + return StatusCode::RECOVERABLE; + } else { + // ostream_iterator< pair<CLID, string> > os(outfile, ':'); + // copy(m_clidMap.begin(), m_clidMap,end(), os); + CLIDMap::const_iterator i(m_clidMap.begin()), iE(m_clidMap.end()); + while (i != iE) { + const CLID clid = i->first; + const std::string& typeName = i->second.first; + const std::string& tiName = i->second.second; + outfile << clid << "; " << typeName; + Athena::PackageInfo existInfo; + if (getPackageInfoForID(i->first, existInfo).isSuccess()) { + outfile << "; " << existInfo; + outfile << "; " << tiName; + } + outfile << endl; + ++i; + } + ATH_MSG_INFO( "finalize: wrote " << m_clidMap.size() << + " entries to output CLIDDB file: " << m_outputFileName ); + } + outfile.close(); + } //outputfilename != NULL + return Service::finalize(); +} + +/// get next available CLID +/// @throws std::runtime_error if no CLID can be allocated +CLID +ClassIDSvc::nextAvailableID() const { + maybeRescan(); + CLID valid(CLIDRegistry::MINCLID); + while (valid <= CLIDRegistry::MAXCLID && isIDInUse(valid)) ++valid; + if (valid > CLIDRegistry::MAXCLID) throw runtime_error("ClassIDSvc::nextAvailableID: none in range"); + return valid; +} + +bool +ClassIDSvc::isIDInUse(const CLID& id ) const { + maybeRescan(); + return 0 != m_clidMap.count(id); +} + +bool +ClassIDSvc::isNameInUse(const string& name ) const { + maybeRescan(); + return 0 != m_nameMap.count(name); +} + +/// get type name associated with clID (if any) +StatusCode +ClassIDSvc::getTypeNameOfID(const CLID& id, std::string& typeName) const { + maybeRescan(); + StatusCode sc(StatusCode::FAILURE); + CLIDMap::const_iterator iID = m_clidMap.find(id); + if (iID != m_clidMap.end()) { + typeName = iID->second.first; +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getTypeNameOfID(" << id << ") type name is " << typeName); +#endif + sc = StatusCode::SUCCESS; + } else { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getTypeNameOfID(" << id << ") no associated type name found "); +#endif + } + return sc; +} + +/// get type name associated with clID (if any) +StatusCode +ClassIDSvc::getTypeInfoNameOfID(const CLID& id, + std::string& typeInfoName) const { + maybeRescan(); + StatusCode sc(StatusCode::FAILURE); + CLIDMap::const_iterator iID = m_clidMap.find(id); + if (iID != m_clidMap.end()) { + typeInfoName = iID->second.second; +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getTypeInfoNameOfID(" << id << ") type-info name is " << typeInfoName); +#endif + sc = StatusCode::SUCCESS; + } else { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getTypeInfoNameOfID(" << id << ") no associated type-info name found "); +#endif + } + return sc; +} + +/// get PackageInfo associated with clID (if any) +StatusCode +ClassIDSvc::getPackageInfoForID(const CLID& id, Athena::PackageInfo& info) const { + maybeRescan(); + StatusCode sc(StatusCode::FAILURE); + PackageMap::const_iterator iID = m_packageMap.find(id); + if (iID != m_packageMap.end()) { + info = iID->second; +#ifndef NDEBUG + ATH_MSG_VERBOSE("getPackageInfoForID(" << id << + ") package name is " << info.name() << + " package version is " << info.version()); +#endif + sc = StatusCode::SUCCESS; + } else { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getPackageInfoForID(" << id << + ") no associated type name found "); +#endif + } + return sc; +} +/// get id associated with type name (if any) +StatusCode +ClassIDSvc::getIDOfTypeName(const std::string& typeName, CLID& id) const { + maybeRescan(); + StatusCode sc(StatusCode::FAILURE); + NameMap::const_iterator iID = m_nameMap.find(typeName); + if (iID != m_nameMap.end()) { + id = iID->second; +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") CLID is " << id); +#endif + sc = StatusCode::SUCCESS; + } else { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") no associated CLID found " ); +#endif + } + return sc; +} + +/// get id associated with type-info name (if any) +StatusCode +ClassIDSvc::getIDOfTypeInfoName(const std::string& typeInfoName, + CLID& id) const { + maybeRescan(); + StatusCode sc(StatusCode::FAILURE); + NameMap::const_iterator iID = m_tiNameMap.find(typeInfoName); + if (iID != m_tiNameMap.end()) { + id = iID->second; +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getIDOfTypeInfoName(" << typeInfoName << ") CLID is " << id); +#endif + sc = StatusCode::SUCCESS; + } else { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "getIDOfTypeInfoName(" << typeInfoName << ") no associated CLID found "); +#endif + } + return sc; +} + +/// associate type name with clID +StatusCode +ClassIDSvc::setTypePackageForID(const CLID& id, + const std::string& typeName, + const Athena::PackageInfo& info, + const std::string& typeInfoName) { + if (id < CLIDRegistry::MINCLID || id > CLIDRegistry::MAXCLID) { + msg() << MSG::FATAL << "setTypeNameForID: input id " << id + << " is out of allowed range " << CLIDRegistry::MINCLID + << " : " << CLIDRegistry::MAXCLID << endmsg; + return StatusCode::FAILURE; + } + return uncheckedSetTypePackageForID(id, typeName, info, typeInfoName); +} + +StatusCode +ClassIDSvc::uncheckedSetTypePackageForID(const CLID& id, + const std::string& typeName, + const Athena::PackageInfo& info, + const std::string& typeInfoName) { + StatusCode sc(StatusCode::SUCCESS); + //process "raw" typeName + string procName(typeName); + massage(procName); + //first the id->name map + string knownName("_____++++"); + if (getTypeNameOfID(id, knownName).isSuccess() && procName != knownName) { + msg() << MSG::FATAL << "uncheckedSetTypePackageForID: " << info << + " can not set type name <" << procName << "> for CLID " << + id << ": Known name for this ID <" << knownName << '>'; + Athena::PackageInfo existInfo; + if (getPackageInfoForID(id, existInfo).isSuccess()) { + msg() << MSG::FATAL + << " It was set by " << existInfo; + } + msg() << MSG::ERROR << endmsg; + sc = StatusCode::FAILURE; + } else if (procName == knownName) { +#ifndef NDEBUG + ATH_MSG_VERBOSE("uncheckedSetTypePackageForID: type name <" << procName << + "> already set for CLID " << id); + Athena::PackageInfo existInfo; + if (getPackageInfoForID(id, existInfo).isSuccess()) { + ATH_MSG_VERBOSE( " It was set by " << existInfo ); + } +#endif + } + if (!sc.isSuccess()) return StatusCode::FAILURE; + + //now the name->id map + CLID knownID(0); + if (getIDOfTypeName(procName, knownID).isSuccess() && id != knownID) { + msg() << MSG::ERROR << "uncheckedSetTypePackageForID: " << info << + " can not set CLID <" << id << "> for type name " << + procName << ": Known CLID for this name <" << knownID << '>' ; + Athena::PackageInfo existInfo; + if (getPackageInfoForID(knownID, existInfo).isSuccess()) { + msg() << MSG::ERROR + << " It was set by " << existInfo; + } + msg() << MSG::ERROR << endmsg; + sc = StatusCode::FAILURE; + } else if (id == knownID) { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "uncheckedSetTypePackageForID: CLID <" << id << + "> already set for type name " << procName ); + Athena::PackageInfo existInfo; + if (getPackageInfoForID(id, existInfo).isSuccess()) { + ATH_MSG_VERBOSE( " It was set by " << existInfo); + } +#endif + } +// //finally the id->package map +// Athena::PackageInfo knownInfo; +// if (getPackageInfoForID(id, knownInfo).isSuccess() && info != knownInfo) { +// msg() << MSG::ERROR +// << "uncheckedSetTypePackageForID: can not set package info <" << info +// << "> for CLID " << id +// << ": Known info for this CLID <" << knownInfo << '>' << endmsg; +// sc = StatusCode::FAILURE; +// } else if (info == knownInfo) { +// #ifndef NDEBUG +// msg() << MSG::VERBOSE +// << "uncheckedSetTypePackageForID: package info <" << info +// << "> already set for CLID " << id<< endmsg; +// #endif +// } else { + const std::string procTiName = typeInfoName.empty() + ? procName + : typeInfoName; + m_clidMap[id] = std::make_pair(procName, procTiName); + m_nameMap[procName] = id; + // FIXME: should we also check for ti-name<=>clid duplicates ? + m_tiNameMap[procTiName] = id; + m_packageMap[id] = info; +#ifndef NDEBUG + ATH_MSG_VERBOSE("uncheckedSetTypePackageForID: set type name <" << + procName << "> for CLID " << id); +#endif + // } + return sc; +} +bool +ClassIDSvc::processCLIDDB(const char* fileName) { + maybeRescan(); + bool allOK(true); + ifstream ifile(fileName); + if (!ifile) { + msg() << MSG::WARNING << "processCLIDDB: unable to open " << fileName <<endmsg; + } else { +#ifndef NDEBUG + unsigned int newEntries(0); +#endif + string line; + while (allOK && std::getline(ifile, line)) { + //not yet if ("#" == line.substr(0,0)) continue; //skip comments + //split the record in 2 fields: + // cout << "record " << line << endl; + typedef boost::tokenizer<boost::char_separator<char> > Tokenizer; + Tokenizer tokens(line, boost::char_separator<char>(";")); + Tokenizer::iterator iToken(tokens.begin()), tEnd(tokens.end()); + long id(-1); + const std::size_t columns = distance (iToken, tEnd); + if (columns == 2 || columns == 3 || columns == 4) { + string massTok(*iToken++); + massage(massTok); + try { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + id = boost::lexical_cast<long>(massTok); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + // cout << "id " << id << endl; + } catch (boost::bad_lexical_cast e) { + msg() << MSG::ERROR << "processCLIDDB: Can't cast [" + << massTok << "] to long (clid)" << endmsg; + allOK=false; + break; + } + string typeName(*iToken++); + massage(typeName); + // cout << "typeName " << typeName << endl; + + + string sinfo; + if (columns>=3) { + sinfo=*iToken++; + massage(sinfo); + } else { sinfo = "UNKNOWN-00-00-00"; } + Athena::PackageInfo info(sinfo); + + // cout << "info " << info << endl; + + string typeInfoName; + if (columns>=4) { + massage(typeInfoName = *iToken++); + } else { typeInfoName = typeName; } + + // cout << "typeInfo " << typeInfoName << endl; + + if ((allOK = !typeName.empty())) { + if (uncheckedSetTypePackageForID(id, + typeName, + info, + typeInfoName).isSuccess()) { +#ifndef NDEBUG + ATH_MSG_VERBOSE( "processCLIDDB(" << fileName << + ")\n added entry for CLID <" << id << + "> type name <" << typeName << '>' ); + ++newEntries; +#endif + } + } + } + } //while records + if (!allOK) { + msg() << MSG::ERROR << "processCLIDDB: processing record " << line + << " from CLIDDB file: " << fileName << endmsg; + } else { +#ifndef NDEBUG + ATH_MSG_DEBUG( "processCLIDDB: read " << newEntries << + " entries from CLIDDB file: " << fileName); +#endif + } + ifile.close(); + } //input file open + + return allOK; +} + +void +ClassIDSvc::dump() const { + ATH_MSG_INFO("dump: in memory"); + CLIDMap::const_iterator i(m_clidMap.begin()), iE(m_clidMap.end()); + while (i != iE) { + const CLID clid = i->first; + const std::string& typeName = i->second.first; + msg() << MSG::INFO + << "CLID: "<< clid + << " - type name: " << typeName; + Athena::PackageInfo info; + if (getPackageInfoForID(clid, info).isSuccess()) { + msg() << MSG::INFO + << "- Package "<< info; + } + msg() << MSG::INFO << '\n'; + ++i; + } + ATH_MSG_INFO("------------------------------"); +} + +StatusCode +ClassIDSvc::fillDB() { + std::lock_guard<std::recursive_mutex> lock(m_regMutex); + // Process the various clid dbs according to user's request + vector< string >::const_iterator f(m_DBFiles.begin()), fE(m_DBFiles.end()); + bool allOK(true); + while (f != fE) { +#if BOOST_FILESYSTEM_VERSION == 3 + DirSearchPath::path clidDB((*f++).c_str()); + const char* clidDBFileName(clidDB.c_str()); +#else + DirSearchPath::path clidDB(*f++, boost::filesystem::no_check); + const char* clidDBFileName(clidDB.native_file_string().c_str()); +#endif + if (clidDB.is_complete()) { + allOK = processCLIDDB(clidDBFileName); + } else { + std::list<DirSearchPath::path> paths(m_clidDBPath.find_all(clidDBFileName)); + if (paths.empty()) { + msg() << MSG::WARNING + << "Could not resolve clid DB path " << clidDBFileName + << " using DATAPATH [" << System::getEnv("DATAPATH") + << "] ----- SKIPPING" << endmsg; + } else { + std::list<DirSearchPath::path>::const_iterator p(paths.begin()), pe(paths.end()); +#if BOOST_FILESYSTEM_VERSION == 3 + while (p!=pe) allOK &= processCLIDDB((*p++).c_str()); +#else + while (p!=pe) allOK &= processCLIDDB((*p++).native_file_string().c_str()); +#endif + } + } + } + + maybeRescan(); //scan registry if we had no CLIDDB to process + return allOK ? + StatusCode::SUCCESS : + StatusCode::FAILURE; +} + +StatusCode +ClassIDSvc::reinitialize() { + ATH_MSG_INFO("RE-initializing " << name() + << " - package version " << PACKAGE_VERSION ) ; + return fillDB(); +} diff --git a/EDM/athena/Control/CLIDComps/src/ClassIDSvc.h b/EDM/athena/Control/CLIDComps/src/ClassIDSvc.h new file mode 100644 index 00000000..8682d4a7 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/src/ClassIDSvc.h @@ -0,0 +1,145 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CLIDCOMPS_CLASSIDSVC_H +# define CLIDCOMPS_CLASSIDSVC_H +/** @file ClassIDSvc.h + * @brief a service to manage and verify CLID assignments in athena + + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + *$Id: ClassIDSvc.h,v 1.8 2009-01-15 19:08:43 binet Exp $ + */ + +#include <map> +#include <mutex> +#include <string> +#include <vector> +#include <utility> // for std::pair + +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/Service.h" + +#include "GaudiKernel/DirSearchPath.h" + +#include "AthenaKernel/tools/AthenaPackageInfo.h" +#include "AthenaKernel/IClassIDSvc.h" +#include "AthenaKernel/MsgStreamMember.h" + +#include "SGTools/CLIDRegistry.h" + +template <class TYPE> class SvcFactory; + +/** @class ClassIDSvc + * @brief a service to manage and verify CLID assignments in athena. + * + * @details (clid, class_name) entries are loaded at init from the list of + * files specifies in "CLIDDBFiles", and from the CLID_Registry of every + * library. Optionally the resulting m_clidMap can be dumped to + * "OutputFileName" at finalize time. + */ + + +class ClassIDSvc : virtual public IClassIDSvc, + virtual public IIncidentListener, + public Service { +private: + typedef std::pair<std::string, std::string> TypeName; //typename+typeinfoname + typedef std::map<CLID, TypeName> CLIDMap; + typedef std::map<std::string, CLID> NameMap; + typedef std::map<CLID, Athena::PackageInfo> PackageMap; +public: + /// get next available CLID + /// @throws std::runtime_error if no CLID can be allocated virtual CLID nextAvailableID() const; + CLID nextAvailableID() const; + /// check if id is used + virtual bool isIDInUse(const CLID& id) const; + /// check if id is used + virtual bool isNameInUse(const std::string& name) const; + /// get type name associated with clID (if any) + virtual StatusCode getTypeNameOfID(const CLID& id, std::string& typeName) const ; + /// get user assigned type-info name associated with clID + virtual StatusCode getTypeInfoNameOfID(const CLID& id, std::string& typeInfoName) const ; + /// get type name associated with clID (if any) + virtual StatusCode getPackageInfoForID(const CLID& id, Athena::PackageInfo& info) const ; + /// get id associated with type name (if any) + virtual StatusCode getIDOfTypeName(const std::string& typeName, CLID& id) const ; + /// get id associated with type-info name (if any) + virtual StatusCode getIDOfTypeInfoName(const std::string& typeInfoName, CLID& id) const ; + /// associate type name, package info and type-info name with clID + virtual StatusCode setTypePackageForID(const CLID& id, + const std::string& typeName, + const Athena::PackageInfo& info, + const std::string& typeInfoName); + + ///dump to MsgStream contents of in memory DB + void dump() const; + + /// Gaudi Service Implementation + //@{ + virtual StatusCode initialize(); + virtual StatusCode reinitialize(); + ///dump CLIDmap to outputFileName; + virtual StatusCode finalize(); + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + //@} + + ///implement IIncidentListener + void handle(const Incident &inc); + +protected: + friend class SvcFactory<ClassIDSvc>; + + // Standard Constructor + ClassIDSvc(const std::string& name, ISvcLocator* svc); + + // Standard Destructor + virtual ~ClassIDSvc() {}; + +private: + MsgStream& msg() const { return m_msg.get(); } + /// get clids from CLIDDB and from registry entries + StatusCode fillDB(); + /// load clid/names from a "db" file + bool processCLIDDB(const char* fileName); + /// load clid/names from a DLL registry + bool getRegistryEntries(const std::string& moduleName); + + /// associate type name with clID w/o checking CLID range + virtual StatusCode + uncheckedSetTypePackageForID(const CLID& id, + const std::string& typeName, + const Athena::PackageInfo& info, + const std::string& typeInfoName); + + /// Test to see if anything new has been added to the registry. + void maybeRescan() const; + + /// @name Properties + //@{ + /// "CLIDDBFiles": list of db files with (CLID, class_name) entries. Loaded at init in svc maps + std::vector<std::string> m_DBFiles; + /// "OutputFileName": path to clid.db file in which write at finalize entries in m_clidMap. Default ("NULL") is not to write output clid.db". + std::string m_outputFileName; + //@} + CLIDMap m_clidMap; + NameMap m_nameMap; + NameMap m_tiNameMap; + PackageMap m_packageMap; + + /// The path is which clid db files are to be searched (DATAPATH) + DirSearchPath m_clidDBPath; + + /// a local @c MsgStream -like object + mutable Athena::MsgStreamMember m_msg; + + ///protect db failling + std::recursive_mutex m_regMutex; +}; + +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> + +#endif // CLIDCOMPS_CLASSIDSVC_H diff --git a/EDM/athena/Control/CLIDComps/src/components/CLIDComps_entries.cxx b/EDM/athena/Control/CLIDComps/src/components/CLIDComps_entries.cxx new file mode 100644 index 00000000..6d8915ae --- /dev/null +++ b/EDM/athena/Control/CLIDComps/src/components/CLIDComps_entries.cxx @@ -0,0 +1,8 @@ +#include "../ClassIDSvc.h" +#include "GaudiKernel/DeclareFactoryEntries.h" + +DECLARE_SERVICE_FACTORY( ClassIDSvc ) + +DECLARE_FACTORY_ENTRIES(CLIDComps) { + DECLARE_SERVICE( ClassIDSvc ) +} diff --git a/EDM/athena/Control/CLIDComps/src/components/CLIDComps_load.cxx b/EDM/athena/Control/CLIDComps/src/components/CLIDComps_load.cxx new file mode 100644 index 00000000..7e7ea242 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/src/components/CLIDComps_load.cxx @@ -0,0 +1,4 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(CLIDComps) + diff --git a/EDM/athena/Control/CLIDComps/test/CLIDComps.xml b/EDM/athena/Control/CLIDComps/test/CLIDComps.xml new file mode 100644 index 00000000..ff3f8921 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/test/CLIDComps.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<atn> + <TEST name="CLIDSvcTest" type="makecheck" suite="Examples"> + <package>Control/CLIDComps</package> + <timelimit>5</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov </mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> + <TEST name="clid" type="script"> + <options>_clid_unittest.py</options> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov </mailto> + <expectations> + <errorMessage>AssertionError</errorMessage> + <successMessage>OK</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/CLIDComps/test/ClassIDSvc_test.cxx b/EDM/athena/Control/CLIDComps/test/ClassIDSvc_test.cxx new file mode 100644 index 00000000..31b421c1 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/test/ClassIDSvc_test.cxx @@ -0,0 +1,135 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file ClassIDSvc_test.cxx + * @brief unit test for ClassIDSvc + * @author ATLAS Collaboration + * $Id: ClassIDSvc_test.cxx,v 1.5 2009-01-19 17:02:55 binet Exp $ + ***************************************************************************/ + +#undef NDEBUG + +//<<<<<< INCLUDES >>>>>> + +#include <cassert> +#include <iostream> +#include "TestTools/initGaudi.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/ModuleIncident.h" +#include "GaudiKernel/IIncidentListener.h" +#include "AthenaKernel/IClassIDSvc.h" +#include "../src/ClassIDSvc.h" + +#include "SGTools/CLASS_DEF.h" +#include "SGTools/CLIDRegistry.h" +class Foo{}; +CLASS_DEF( Foo, 8101, 0) +class Bar{}; +CLASS_DEF( Bar, 8107, 0) +template <typename T> +struct Bla { + T bla; +}; +CLASS_DEF( Bla<unsigned int>, 8108, 0) + +#define ASSERTERROR( FALSEEXPR ) \ + std::cerr << "Now we expect to see an error message:" << std::endl \ + << "----Error Message Starts--->>" << std::endl; \ + assert(!FALSEEXPR); \ + std::cerr<< "<<---Error Message Ends-------" << std::endl + +using namespace std; +using namespace Athena_test; +void incident_test(ISvcLocator* pSvcLoc) { + cout << "*** ClassIDSvc incident test starts ***" <<endl; + assert(pSvcLoc); + + IClassIDSvc* pClassIDSvc(0); + assert((pSvcLoc->service("ClassIDSvc", pClassIDSvc, true)).isSuccess()); + assert(pClassIDSvc); + ModuleLoadedIncident fooInc("test", "Foo"); + IIncidentListener* il = dynamic_cast<IIncidentListener*>(pClassIDSvc); + if (!il) std::abort(); + il->handle(fooInc); + ModuleLoadedIncident barInc("test", "Bar"); + il->handle(barInc); + cout << "*** ClassIDSvc incident test OK ***" <<endl; +} +void basic_test(ISvcLocator* pSvcLoc) { + cout << "*** ClassIDSvc basic test starts ***" <<endl; + assert(pSvcLoc); + + IClassIDSvc* pClassIDSvc(0); + assert((pSvcLoc->service("ClassIDSvc", pClassIDSvc, true)).isSuccess()); + assert(pClassIDSvc); + + assert(pClassIDSvc->nextAvailableID() == CLIDRegistry::MINCLID); + Athena::PackageInfo info(PACKAGE_VERSION); + Athena::PackageInfo info2("APack-00-39-98"); + assert(pClassIDSvc->setTypePackageForID(7890, "Bla", info2).isSuccess()); + ASSERTERROR(pClassIDSvc->setTypePackageForID(CLIDRegistry::MINCLID/2, "No", + info).isSuccess()); + ASSERTERROR(pClassIDSvc->setTypePackageForID(CLIDRegistry::MAXCLID*2, "Nah", + info).isSuccess()); + //FIXME is this an issue? Should we do the reverse check type -> id? + assert(pClassIDSvc->setTypePackageForID(9942, "Bli", info).isSuccess()); + assert(pClassIDSvc->setTypePackageForID(9943, "Blu", info).isSuccess()); + ASSERTERROR(pClassIDSvc->setTypePackageForID(7890, "Ble", info).isSuccess()); + //check disabled ASSERTERROR(pClassIDSvc->setTypePackageForID(9942, "Bli", info2).isSuccess()); + ASSERTERROR(pClassIDSvc->setTypePackageForID(9945, "Bli", info).isSuccess()); + assert(pClassIDSvc->setTypePackageForID(7890, "Bla", info2).isSuccess()); + assert(pClassIDSvc->setTypePackageForID(7890, " Bla", info2).isSuccess()); + ASSERTERROR(pClassIDSvc->setTypePackageForID(7890, " Bl a ", info2).isSuccess()); + ASSERTERROR(pClassIDSvc->setTypePackageForID(7890, " B l a ", info2).isSuccess()); + assert(pClassIDSvc->setTypePackageForID(7890, "Bla ", info2).isSuccess()); + assert(pClassIDSvc->setTypePackageForID(7890, " Bla ", info2).isSuccess()); + + + string name; + assert(pClassIDSvc->getTypeNameOfID(8101, name).isSuccess()); + assert(name == "Foo"); + assert(pClassIDSvc->getTypeNameOfID(8107, name).isSuccess()); + assert(name == "Bar"); + assert(pClassIDSvc->getTypeNameOfID(7890, name).isSuccess()); + assert(name == "Bla"); + assert(pClassIDSvc->getTypeNameOfID(9942, name).isSuccess()); + assert(name == "Bli"); + assert(pClassIDSvc->getTypeNameOfID(9943, name).isSuccess()); + assert(name == "Blu"); + assert(pClassIDSvc->getTypeNameOfID(2, name).isFailure()); + + CLID id; + assert(pClassIDSvc->getIDOfTypeName("Blu", id).isSuccess()); + assert(id == 9943); + assert(pClassIDSvc->getIDOfTypeName("NotExist", id).isFailure()); + + assert(pClassIDSvc->isIDInUse(9942)); + // assert(!pClassIDSvc->isIDInUse(9945)); + assert(!pClassIDSvc->isIDInUse((unsigned)-2243341)); + + assert(pClassIDSvc->isNameInUse("Blu")); + assert(!pClassIDSvc->isNameInUse("NotExist")); + assert(!pClassIDSvc->isNameInUse("")); + + //test handling of spaces (savannah 39528) + assert( pClassIDSvc->isNameInUse("Bla<unsigned int>") ); + assert( !pClassIDSvc->isNameInUse("Bla<unsignedint>") ); + assert(pClassIDSvc->getTypeNameOfID(8108, name).isSuccess()); + assert(name == "Bla<unsigned int>"); + // dynamic_cast<ClassIDSvc*>(pClassIDSvc)->dump(); + + assert((dynamic_cast<IService*>(pClassIDSvc)->finalize()).isSuccess()); + cout << "*** ClassIDSvc basic test OK ***" <<endl; +} + +int main() { + ISvcLocator* pSvcLoc(0); + if (!initGaudi("ClassIDSvc_test.txt", pSvcLoc)) { + cerr << "ClassIDSvc_test can not be run" << endl; + return 0; + } + basic_test(pSvcLoc); + incident_test(pSvcLoc); + return 0; +} diff --git a/EDM/athena/Control/CLIDComps/test/_clid_unittest.py b/EDM/athena/Control/CLIDComps/test/_clid_unittest.py new file mode 100644 index 00000000..86f1383a --- /dev/null +++ b/EDM/athena/Control/CLIDComps/test/_clid_unittest.py @@ -0,0 +1,45 @@ +exec python -tx "$0" "$@" + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +## @file clid_unittest.py +# @brief Unit tests for clidGenerator +"""Unit tests for clidGenerator.""" + + +import os, sys, unittest +from CLIDComps.clidGenerator import clidGenerator + + +## CLIDSvc test fixture +class TestFixture( unittest.TestCase ): + def setUp( self ): + pass + + def tearDown( self ): + self.cgen.cleardb() + + +## test existence and validity of site specific information +class CLIDTestCase( TestFixture ): + def test1ClidDB( self ): + """Testing clidGenerator with Gaudi_clid.db""" + self.cgen = clidGenerator("Gaudi_clid.db") + self.assertEqual( 1, self.cgen.genClidFromName("DataObject") ) + self.assertEqual( "DataObject", self.cgen.getNameFromClid(1) ) + + def test2GenClids( self ): + """Testing clidGenerator with no clid.db""" + # get rid of expected error message + sys.stdout = open("dummyIgnore.txt", 'w') + self.cgen = clidGenerator("NOTTHERE.db") + sys.stdout = sys.__stdout__ + os.remove("dummyIgnore.txt"); + + self.assertEqual( 245732527, self.cgen.genClidFromName("DataObject") ) + self.assertEqual( 205083834, self.cgen.genClidFromName("Data<Foo23_45___Bar_, dsfl__>") ) + +## run tests if in standalone mode +if __name__ == '__main__': + unittest.main() + diff --git a/EDM/athena/Control/CLIDComps/util/genCLIDDB.cxx b/EDM/athena/Control/CLIDComps/util/genCLIDDB.cxx new file mode 100644 index 00000000..b2960708 --- /dev/null +++ b/EDM/athena/Control/CLIDComps/util/genCLIDDB.cxx @@ -0,0 +1,148 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <cassert> +#include <exception> +#include <iostream> +#include <string> +#include "GaudiKernel/IClassManager.h" +#include "GaudiKernel/IProperty.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/SmartIF.h" +#include "GaudiKernel/IAppMgrUI.h" +#include "GaudiKernel/IClassIDSvc.h" +#include "GaudiKernel/Bootstrap.h" + +#include <boost/program_options.hpp> +namespace po = boost::program_options; + +using namespace std; + +int inputError(std::string errDescr, const po::options_description& optDescr ) { + cerr << errDescr << "\n" << optDescr << endl; + return 1; +} +int gaudiError(std::string errDescr) { + cerr << errDescr << endl; + return 2; +} + +//wrote a better version! +IAppMgrUI* initGaudi(const std::string& options, ISvcLocator*& svcLocator) { + IAppMgrUI* theApp = Gaudi::createApplicationMgr(); + SmartIF<IProperty> propMgr(theApp); + if(strlen(options.c_str())) { + propMgr->setProperty("JobOptionsPath",options); + } else { + propMgr->setProperty( "JobOptionsType", "NONE" ); //no joboptions given + } + theApp->configure(); + theApp->initialize(); + svcLocator = Gaudi::svcLocator(); + return theApp; + +} + +int main(int argc, char* argv[]) { + // Declare the supported options. + po::options_description desc("clidDB_gen allowed options"); + desc.add_options() + ("help,h", "produce help message") + ("package,p", po::value<string>(), "package we want to load clids from") + ("input,i", po::value<string>(), "optional path to input clid db file") + ("output,o", po::value<string>(), "optional path to resulting clid db file") + ("jobopts,j", po::value<string>(), "name of optional job options txt file, located at ../share/jobopts") + ; + string packageName("ALL"); + string inputCLIDDB; + string outFileName; + + po::variables_map vm; + try { + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch (const exception& e) { + return inputError(e.what(), desc); + } + + if (vm.count("help")) { + cout << desc << endl; + return 0; + } + + if (vm.count("package")) { + cout << "Generating clid.db for package " + << vm["package"].as<string>() << ".\n"; + packageName = vm["package"].as<string>(); + } else { + return inputError("Please specify a package using option --package.\n", + desc); + } + + if (vm.count("output")) { + outFileName = vm["output"].as<string>(); + } else { + outFileName = packageName + "_clid.db"; + } + cout << "Resulting clid.db will be written to " + << outFileName << ".\n"; + + ISvcLocator* pSvcLoc(0); + if (vm.count("jobopts")) { + if (!initGaudi(vm["jobopts"].as<string>(), pSvcLoc)) { + return gaudiError("clidDB_gen can not run"); + } + } else { + if (!initGaudi("CLIDComps/minimalPrintout.opts",pSvcLoc)) { + return gaudiError("clidDB_gen can not run"); + } + } + if ( 0 == pSvcLoc ) { + return gaudiError( "NULL pointer to ISvcLocator" ); + } + SmartIF<IClassManager> pICM(pSvcLoc); + if (!pICM.isValid()) { + gaudiError("can not get IClassManager"); + } + + IClassIDSvc* pClassIDSvc(0); + if (!(pSvcLoc->service("ClassIDSvc", pClassIDSvc, true).isSuccess())) { + cerr << "can not get ClassIDSvc, no clid.db will be generated" << endl; + return 0; + } + if ( 0 == pClassIDSvc ) { + return gaudiError("NULL pointer to IClassIDSvc"); + } + + IProperty *pCLIDSvcProp(dynamic_cast<IProperty*>(pClassIDSvc)); + if ( 0 == pCLIDSvcProp ) { + return gaudiError("NULL pointer to IClassIDSvc's property"); + } + + if (vm.count("input")) { + cout << "Reading clid.db from " + << vm["input"].as<string>() << ".\n"; + if (!(pCLIDSvcProp->setProperty( "CLIDDBFiles", + "{\"" + vm["input"].as<string>() + "\"}" )).isSuccess()) { + return inputError("Error setting ClassIDSvc.CLIDDBFiles to " + + vm["input"].as<string>(), + desc); + } + } + + pCLIDSvcProp->setProperty( "OutputFileName", outFileName ); + + if (!pICM->loadModule(packageName).isSuccess()) { + return gaudiError("can not load module " + packageName); + } + + //fill clid db + if (!(pClassIDSvc->reinitialize()).isSuccess()) { + return gaudiError("can not reinitialize ClassIDSvc"); + } + + //write out merged clid db on service finalize + return (pClassIDSvc->finalize()).isSuccess() ? 0 : -1; +} diff --git a/EDM/athena/Control/CxxUtils/CMakeLists.txt b/EDM/athena/Control/CxxUtils/CMakeLists.txt new file mode 100644 index 00000000..9ba192f6 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CMakeLists.txt @@ -0,0 +1,78 @@ +# $Id: CMakeLists.txt 796875 2017-02-13 15:04:31Z fwinkl $ +################################################################################ +# Package: CxxUtils +################################################################################ + +# Declare the package name: +atlas_subdir( CxxUtils ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PRIVATE AtlasTest/TestTools ) + +# External dependencies: +find_package( Boost COMPONENTS program_options regex filesystem thread system ) + +# The main library of the package: +atlas_add_library( CxxUtils + Root/*.cxx + PUBLIC_HEADERS CxxUtils + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} + PRIVATE_LINK_LIBRARIES TestTools ) + +# Additional libraries in the package: +atlas_add_library( exctrace_collector src/exctrace/exctrace_collector.cxx + PUBLIC_HEADERS CxxUtils ) + +atlas_add_library( calg src/libcalg/*.c + PUBLIC_HEADERS CxxUtils ) + +atlas_add_library( AthDSoCallBacks src/AthDsoCbk.c + PUBLIC_HEADERS CxxUtils + LINK_LIBRARIES calg ) + +# Unit tests in the package: +atlas_add_test( read_athena_statm_test + SOURCES test/read_athena_statm_test.cxx + LINK_LIBRARIES CxxUtils + EXTRA_PATTERNS "read_athena_statm reports process size" ) + +atlas_add_test( PageAccessControl_test + SOURCES test/PageAccessControl_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} CxxUtils ) + +atlas_add_test( SEGVHandler_test + SOURCES test/SEGVHandler_test.cxx + LINK_LIBRARIES CxxUtils + EXTRA_PATTERNS "page fault|FIXME NOT Freeing memory" ) + +atlas_add_test( procmaps_test + SOURCES test/procmaps_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} CxxUtils ) + +atlas_add_test( copy_bounded_test + SOURCES test/copy_bounded_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} CxxUtils ) + +atlas_add_test( BitPackerUnpacker_test + SOURCES test/BitPackerUnpacker_test.cxx + LINK_LIBRARIES TestTools CxxUtils ) + +atlas_add_test( stacktrace_test + SOURCES test/stacktrace_test.cxx + LINK_LIBRARIES CxxUtils dl ) + +# Set up the "simple" tests: +foreach( test sincos_test copyif_test ArrayScanner_test Arrayrep_test + Array_test PackedArray_test pointer_list_test FloatPacker_test + hashtable_test fpcompare_test StrFormat_test + prefetch_test ClassName_test make_unique_test ones_test + exctrace1_test exctrace2_test bitscan_test ) + atlas_add_test( ${test} + SOURCES test/${test}.cxx + LINK_LIBRARIES CxxUtils ) +endforeach() diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/Array.h b/EDM/athena/Control/CxxUtils/CxxUtils/Array.h new file mode 100644 index 00000000..a34361cf --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/Array.h @@ -0,0 +1,783 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Array.h,v 1.2 2009-04-07 04:26:22 ssnyder Exp $ +/** + * @file Array.h + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Simple multidimensional arrays. + * + * This file defines several families of templated classes that act like + * multidimensional arrays. + * + * There are three families of classes: + * - @c Array<N> provides read-only access to an array. + * Indexing with [] returns an @c Array<N-1>. @c Array<0> + * is special; it doesn't support indexing, but does support + * implicit conversion to the element type, @c Arrayelt. + * The @c Array classes do not own their storage (and thus indexing + * does not require a complete copy). Rather, the complete data + * for the array are stored in an instance of @c Arrayrep. + * An @c Array holds a pointer to an @c Arrayrep and an offset + * into the data. + * + * - @c WritableArray is similar to @c Array, except that it may + * be written to as well. An @c Array may be initialized from + * a @c WritableArray, but not the other way around. + * + * - @c WritableArrayData is a @c WritableArray together with + * an @c Arrayrep. This is a convenient way of creating + * from scratch an array to which you can write. + */ + + +#ifndef CXXUTILS_ARRAY_H +#define CXXUTILS_ARRAY_H + + +#include "CxxUtils/Arrayrep.h" +#include <iterator> + + +namespace CxxUtils { + + +// Forward declaration. +template <unsigned int N> +class ArrayIterator; + + +//********************************************************************** + + +/** + * @class ArrayIteratorChooser + * @brief Helper for defining iterators over @c Array's. + * + * For @c Array<N> with @c N >= 2, we want to use @c ArrayIterator<N> as the + * iterator class. However, for @c Array<1>, we want to use just + * an @c Arrayelt*. I'm too lazy to either specialize @c ArrayIterator<1> + * or to add a new @c Array<1> specialization. So this is an easier way + * of achieving the same effect. @c Array<N> uses as its iterator + * type @c ArrayIteratorChooser<N>::const_iterator; this small class then gets + * specialized for @N == 1. We also need to provide a way to create + * the iterators (since it will be done differently in the two cases). + * This is supplied by the @c make_iterator method. + */ +template <unsigned int N> +class ArrayIteratorChooser +{ +public: + /// Iterator type for an @c Array<N>. + typedef ArrayIterator<N> const_iterator; + + + /** + * @brief Construct an @c Array<N>::const_iterator. + * @param rep @c Arrayrep from which to initialize the iterator. + * @param offs Offset of the first element referenced by the iterator + * within @a rep. + * @return The new iterator. + */ + static const_iterator make_iterator (const Arrayrep* rep, unsigned int offs); +}; + + +/** + * @class ArrayIteratorChooser<1> + * @brief Helper for defining iterators over @c Array's, specialized + * for @c N == 1. + * + * For @c N == 1, we specialize so that @c Array<N> uses + * @c Arrayelt* as its iterator type. + */ +template <> +class ArrayIteratorChooser<1> +{ +public: + /// Iterator type for an @c Array<1>. + typedef const Arrayelt* const_iterator; + + + /** + * @brief Construct an @c Array<1>::const_iterator. + * @param rep @c Arrayrep from which to initialize the iterator. + * @param offs Offset of the first element referenced by the iterator + * within @a rep. + * @return The new iterator. + */ + static const_iterator make_iterator (const Arrayrep* rep, unsigned int offs); +}; + + +//********************************************************************** + + +/** + * @class Array + * @brief Read-only multidimensional array. + * + * @c Array<N> provides read-only access to an array. + * Indexing with [] returns an @c Array<N-1>. @c Array<0> + * is special; it doesn't support indexing, but does support + * implicit conversion to the element type, @c Arrayelt. + * The @c Array classes do not own their storage (and thus indexing + * does not require a complete copy). Rather, the complete data + * for the array are stored in an instance of @c Arrayrep. + * An @c Array holds a pointer to an @c Arrayrep and an offset + * into the data. + */ +template <unsigned int N> +class Array +{ +public: + /// The number of dimensions of the array. + enum { NDIM = N }; + + /// The iterator for this container. + typedef typename ArrayIteratorChooser<N>::const_iterator const_iterator; + + + /** + * @brief Default constructor. + * + * This produces an invalid @c Array that is not associated with + * an @c Arrayrep. @c valid() will return @c false for such an array. + * The only other things that it is legal to do with an invalid array + * are to assign to it (which may make it valid) or request its + * size with size() (which will always return 0). + */ + Array (); + + /** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ + Array (const Arrayrep& rep); + + /** + * @brief Test for validity. + * @return True if the @c Array is associated with an @c Arrayrep, + * false if not. + */ + bool valid() const; + + /** + * @brief Return the array shape. + * @return The array shape. + * + * The array shape is vector with one element for each array dimension, + * giving the size of the array along that dimension. + */ + std::vector<unsigned int> shape() const; + + /** + * @brief Return the size of the array along one dimension. + * @param dim The dimension of the size to retrieve. + * Must be less than the number of dimensions. + * @return The array size along dimension @dim. + */ + unsigned int size (unsigned int dim = 0) const; + + /** + * @brief Array indexing. + * @param i The desired index. Must be less than the array size + * along this dimension. + * @return The @a i'th @c N-1 dimensional subarray in the array. + * + * Note that this operation is not available if @c N is 0. + */ + Array<N-1> operator[] (unsigned int i) const; + + /** + * @brief Return a direct pointer to array elements. + * @return A pointer to the first array elements. + * + * Subsequent elements follow in standard C indexing order. + */ + const Arrayelt* ptr () const; + + + /** + * @brief Return an iterator pointing at the beginning of the container. + * @return An iterator pointing at the beginning of the container. + */ + const_iterator begin () const; + + + /** + * @brief Return an iterator pointing past the end of the container. + * @return An iterator pointing past the end of the container. + */ + const_iterator end () const; + + + // Protected, not private, so that they can be accessed by @c WritableArray. +protected: + /** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ + Array (const Arrayrep& rep, unsigned int offs); + + // These classes need to call the above protected constructor. + friend class Array<N+1>; + friend class ArrayIterator<N+1>; + + /// Pointer to the representation. + /// Null if this instance was created using the default constructor. + const Arrayrep* m_rep; + + /// Offset in the @c Arrayrep's data of the first element of this array. + unsigned int m_offs; +}; + + +/** + * @class Array<0> + * @brief Read-only multidimensional array, specialized for @c N=0. + * + * This is a specialization of @c Array for the case @c N=0, + * i.e., a scalar. It does not support indexing, but it does support + * implicit conversions to @c Arrayelt, as well as an explicit conversion + * to an integer. + */ +template <> +class Array<0> +{ +public: + /// The number of dimensions of the array. + enum { NDIM = 0 }; + + /** + * @brief Default constructor. + * + * This produces an invalid @c Array that is not associated with + * an @c Arrayrep. @c valid() will return @c false for such an array. + * The only other thing that it is legal to do with an invalid array + * is to assign to it (which may make it valid). + */ + Array (); + + /** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ + Array (const Arrayrep& rep); + + /** + * @brief Test for validity. + * @return True if the @c Array is associated with an @c Arrayrep, + * false if not. + */ + bool valid() const; + + /** + * @brief Return the array shape. + * @return The array shape. + * + * The array shape is vector with one element for each array dimension, + * giving the size of the array along that dimension. + * For @c Array<0>, this will always be an empty array. + */ + std::vector<unsigned int> shape() const; + + /** + * @brief Return the size of the array along one dimension. + * @param dim The dimension of the size to retrieve. + * Must be less than the number of dimensions. + * @return The array size along dimension @dim. + * + * For @c Array<0>, @a dim must be 0, and the function + * will always return 0. + */ + unsigned int size (unsigned int dim=0) const; + + /** + * @brief Convert to a number. + * @return The @c Array<0> contents as a number. + */ + operator Arrayelt() const; + + /** + * @brief Convert to an integer. + * @return The @c Array<0> contents as an integer. + */ + int asint () const; + + + // Protected, not private, so that they can be accessed by @c WritableArray. +protected: + /** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ + Array (const Arrayrep& rep, unsigned int offs); + + // This class needs to call the above protected constructor. + friend class Array<1>; + + /// Pointer to this array's single element. + /// Null if this instance was created using the default constructor. + const Arrayelt* m_elt; +}; + + +//********************************************************************** + + +/** + * @class ArrayIterator + * @brief Iterator class for @c Array<N>. + * + * This serves as an iterator class for @c Array<N>, where + * @c N >= 2. It gives a @c Array<N-1> as @c value_type. + * Only @c const access is supported. + * + * This class is almost, but not quite, a random access iterator. + * @c operator* and @c operator[] returns a @c value_type instead + * of a @c reference. And @c operator-> returns a proxy. + * (The issues here are similar to those encountered with + * @c std::vector<bool>.) But it should mostly work as you expect. + */ +template <unsigned int N> +class ArrayIterator + : public std::iterator<std::random_access_iterator_tag, const Array<N-1> > +{ +public: + // Typedefs. + /// Shorthand for the base class. + typedef std::iterator<std::random_access_iterator_tag, const Array<N-1> > + base_iterator; + + /// Standard @c iterator_category typedef, from the base class. + typedef typename base_iterator::iterator_category iterator_category; + + /// Standard @c value_type typedef, from the base class. + typedef typename base_iterator::value_type value_type; + + /// Standard @c difference typedef, from the base class. + typedef typename base_iterator::difference_type difference_type; + + /// Standard @c reference typedef, from the base class. + typedef typename base_iterator::reference reference; + + + /** + * @brief Proxy to return from @c operator>. + * + * @c operator-> is required to either return an actual C++ + * pointer or another object that has a valid @c operator->. + * This makes things a bit tricky if you're using proxies. + * We have the @c ArrayIterator @c operator-> return + * an instance of this proxy class, which contains an + * instance of the @c Array proxy. The @c operator-> + * of this proxy then returns a pointer to the contained + * @c Array. This will work for most common usages. + * However, the pointer one gets from the @c operator-> + * here will only be valid until the proxy is destroyed. + */ + class pointer + { + public: + /** + * @brief Proxy constructor. + * @param i The iterator that is being dereferenced. + */ + pointer (const ArrayIterator& i); + + + /** + * @brief Dereference the proxy. + * @return A copy of the @c Array proxy. + */ + value_type operator* () const; + + + /** + * @brief Dereference the proxy. + * @return A pointer to the @c Array proxy. + * This proxy is only until the @c pointer instance + * is destroyed. + */ + const value_type* operator-> () const; + + + private: + /// The contained @c Array proxy instance. + value_type m_a; + }; + + + /** + * @brief Default constructor. + * Makes an invalid iterator. + */ + ArrayIterator (); + + + /** + * @brief Constructor from @c Arrayrep and offset. + * @param rep The underlying array representation. + * @param offs The offset in the representation of the + * first element referenced by this iterator. + */ + ArrayIterator (const Arrayrep* rep, unsigned int offs); + + // Use default copy ctor and assignment. + + /** + * @brief Equality comparison. + * @param other The other object with which to compare. + * @return True if the iterators are equal. + */ + bool operator== (const ArrayIterator& other) const; + + + /** + * @brief Inequality comparison. + * @param other The other object with which to compare. + * @return True if the iterators are not equal. + */ + bool operator!= (const ArrayIterator& other) const; + + + /** + * @brief Less-than comparison. + * @param other The other object with which to compare. + * @return True if this iterator is less than @a other. + * This will always return false for iterators + * over different arrays. + */ + bool operator< (const ArrayIterator& other) const; + + + /** + * @brief Greater-than comparison. + * @param other The other object with which to compare. + * @return True if this iterator is greater than @a other. + * This will always return false for iterators + * over different arrays. + */ + bool operator> (const ArrayIterator& other) const; + + + /** + * @brief Less-than-or-equal comparison. + * @param other The other object with which to compare. + * @return True if this iterator is less than or equal to @a other. + * This will always return false for iterators + * over different arrays. + */ + bool operator<= (const ArrayIterator& other) const; + + + /** + * @brief Greater-than-or-equal comparison. + * @param other The other object with which to compare. + * @return True if this iterator is less than or equal to @a other. + * This will always return false for iterators + * over different arrays. + */ + bool operator>= (const ArrayIterator& other) const; + + + /** + * @brief Dereference the iterator. + * @return The value that the iterator points to. + * Note that this method returns a @c value_type, not + * a @c reference. (Thus, this class does not quite + * conform to the iterator requirements.) + */ + value_type operator* () const; + + + /** + * @brief Dereference the iterator. + * @return A proxy for the iterator element. + * + * This method will return a proxy for the array, which you + * can then dereference. Note that if you get a C++ pointer + * from this, then it will be valid only until the proxy + * object gets destroyed. + */ + pointer operator-> () const; + + + /** + * @brief Advance the iterator. + * @returns This iterator. + */ + ArrayIterator<N>& operator++ (); + + + /** + * @brief Advance the iterator. + * @returns The iterator before being advanced. + */ + ArrayIterator<N> operator++ (int); + + + /** + * @brief Back up the iterator. + * @returns This iterator. + */ + ArrayIterator<N>& operator-- (); + + + /** + * @brief Back up the iterator. + * @returns The iterator before being backed up. + */ + ArrayIterator<N> operator-- (int); + + + /** + * @brief Array indexing relative to the iterator. + * @param n The array index. + * @return The array item at an offset of @a n from the + * current iterator position. + * Note that this method returns a @c value_type, not + * a @c reference. (Thus, this class does not quite + * conform to the iterator requirements.) + */ + value_type operator[] (difference_type n) const; + + + /** + * @brief Advance the iterator. + * @param n Number of steps by which to advance the iterator. + * @return This iterator. + */ + ArrayIterator<N>& operator+= (difference_type n); + + + /** + * @brief Return a new iterator pointing @a n steps ahead. + * @param n Number of steps by which to advance. + * @return The new iterator. + */ + ArrayIterator<N> operator+ (difference_type n) const; + + + /** + * @brief Back up the iterator. + * @param n Number of steps by which to advance the iterator. + * @return This iterator. + */ + ArrayIterator<N>& operator-= (difference_type n); + + + /** + * @brief Return a new iterator pointing @a n steps behind. + * @param n Number of steps by which to back up. + * @return The new iterator. + */ + ArrayIterator<N> operator- (difference_type n) const; + + + /** + * @brief Return the difference between two iterators. + * @param other The other iterator for the comparison. + * @return The number of elements difference between + * this iterator and @a other. + * Undefined if the two iterators do not point + * into the same array. + */ + difference_type operator- (const ArrayIterator& other) const; + + +private: + /// The underlying array representation. + const Arrayrep* m_rep; + + /// Offset into the representation's data array of the first element + /// referred to by this iterator. + unsigned int m_offs; +}; + + +//********************************************************************** + + +/** + * @class WritableArray + * @brief Read-write multidimensional array. + * + * This class derives from @Array<N>. It allows writing into + * the array, but otherwise works in the same way. + */ +template <unsigned int N> +class WritableArray + : public Array<N> +{ +public: + /** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ + WritableArray (Arrayrep& rep); + + /** + * @brief Array indexing. + * @param i The desired index. Must be less than the array size + * along this dimension. + * @return The @a i'th @c N-1 dimensional subarray in the array. + * + * Note that this operation is not available if @c N is 0. + */ + WritableArray<N-1> operator[] (unsigned int i) const; + + /** + * @brief Return a direct pointer to array elements. + * @return A pointer to the first array elements. + * + * Subsequent elements follow in standard C indexing order. + */ + Arrayelt* ptr (); + + +private: + /** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ + WritableArray (Arrayrep& rep, unsigned int offs); + + // This class needs to call the above protected constructor. + friend class WritableArray<N+1>; +}; + + +/** + * @class WritableArray<N> + * @brief Read-write multidimensional array, specialized for @c N=0. + * + * This class derives from @Array<0>. It allows writing into + * the (single) element, but otherwise works in the same way. + */ +template <> +class WritableArray<0> + : public Array<0> +{ +public: + /** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ + WritableArray (Arrayrep& rep); + + /** + * @brief Assignment. + * @param elt The RHS of the assignment. + * @return This object. + * + * Assign into the array. + */ + WritableArray<0>& operator= (Arrayelt elt); + + +private: + /** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ + WritableArray (Arrayrep& rep, unsigned int offs); + + // This class needs to call the above protected constructor. + friend class WritableArray<1>; +}; + + +//********************************************************************** + + +/** + * @class Array<N> + * @brief A @c WriteableArray together with an @c Arrayrep. + * + * This is a convenient way of creating from scratch an array + * to which you can write. + */ +template <unsigned int N> +class WritableArrayData + : private Arrayrep, + public WritableArray<N> +{ +public: + /** + * @brief Constructor. + * @param shape The shape of the array, as a C array. + * Should be @c N elements long. + * + * The shape is the size of the array along each dimension. + */ + WritableArrayData (const unsigned int shape[]); + + /** + * @brief Constructor. + * @param shape The shape of the array, as a std::vector. + * Should be @c N elements long. + * + * The shape is the size of the array along each dimension. + */ + WritableArrayData (const std::vector<unsigned int>& shape); +}; + + +} // namespace CxxUtils + + +#include "CxxUtils/Array.icc" + + +// Backwards compatibility. +namespace CaloRec { + using CxxUtils::Array; + using CxxUtils::WritableArray; + using CxxUtils::WritableArrayData; +} + + +#endif // not CXXUTILS_ARRAY_H + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/Array.icc b/EDM/athena/Control/CxxUtils/CxxUtils/Array.icc new file mode 100644 index 00000000..ef99032a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/Array.icc @@ -0,0 +1,786 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Array.icc,v 1.1 2009-03-20 20:44:22 ssnyder Exp $ +/** + * @file Array.icc + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Simple multidimensional arrays (inline and template implementations). + */ + + +#include "CxxUtils/unused.h" +#include <cassert> + + +namespace CxxUtils { + + +/** + * @brief Construct an @c Array<N>::const_iterator. + * @param rep @c Arrayrep from which to initialize the iterator. + * @param offs Offset of the first element referenced by the iterator + * within @a rep. + * @return The new iterator. + */ +template <unsigned int N> +inline +typename ArrayIteratorChooser<N>::const_iterator +ArrayIteratorChooser<N>::make_iterator (const Arrayrep* rep, + unsigned int offs) +{ + return const_iterator (rep, offs); +} + + +/** + * @brief Construct an @c Array<1>::const_iterator. + * @param rep @c Arrayrep from which to initialize the iterator. + * @param offs Offset of the first element referenced by the iterator + * within @a rep. + * @return The new iterator. + */ +inline +ArrayIteratorChooser<1>::const_iterator +ArrayIteratorChooser<1>::make_iterator (const Arrayrep* rep, + unsigned int offs) +{ + return rep ? &rep->m_data[offs] : 0; +} + + +//********************************************************************** + + +/** + * @brief Default constructor. + * + * This produces an invalid @c Array that is not associated with + * an @c Arrayrep. @c valid() will return @c false for such an array. + * The only other thing that it is legal to do with an invalid array + * is to assign to it (which may make it valid). + */ +template <unsigned int N> +Array<N>::Array () + : m_rep (0), + m_offs (0) +{ +} + + +/** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ +template <unsigned int N> +Array<N>::Array (const Arrayrep& rep) + : m_rep (&rep), + m_offs (0) +{ + assert (m_rep->m_shape.size() == N); + assert (m_rep->m_sizes.size() == m_rep->m_shape.size()); +} + + +/** + * @brief Test for validity. + * @return True if the @c Array is associated with an @c Arrayrep, + * false if not. + */ +template <unsigned int N> +bool Array<N>::valid() const +{ + return m_rep != 0; +} + + +/** + * @brief Return the array shape. + * @return The array shape. + * + * The array shape is vector with one element for each array dimension, + * giving the size of the array along that dimension. + */ +template <unsigned int N> +std::vector<unsigned int> Array<N>::shape() const +{ + return std::vector<unsigned int> + (m_rep->m_shape.begin() + m_rep->m_shape.size() - N, + m_rep->m_shape.end()); +} + + +/** + * @brief Return the size of the array along one dimension. + * @param dim The dimension of the size to retrieve. + * Must be less than the number of dimensions. + * + * As a special case, the size of an invalid array will always be 0. + * @return The array size along dimension @dim. + */ +template <unsigned int N> +unsigned int Array<N>::size (unsigned int dim /*=0*/) const +{ + assert (dim < N); + if (!m_rep) return 0; + return m_rep->m_shape[m_rep->m_shape.size() - N + dim]; +} + + +/** + * @brief Array indexing. + * @param i The desired index. Must be less than the array size + * along this dimension. + * @return The @a i'th @c N-1 dimensional subarray in the array. + * + * Note that this operation is not available if @c N is 0. + */ +template <unsigned int N> +inline +Array<N-1> Array<N>::operator[] (unsigned int i) const +{ + assert (i < m_rep->m_shape[m_rep->m_shape.size() - N]); + return Array<N-1> (*m_rep, m_offs + i * m_rep->m_sizes[N-1]); +} + + +/** + * @brief Return a direct pointer to array elements. + * @return A pointer to the first array elements. + * + * Subsequent elements follow in standard C indexing order. + */ +template <unsigned int N> +inline +const Arrayelt* Array<N>::ptr () const +{ + return &m_rep->m_data[m_offs]; +} + + +/** + * @brief Return an iterator pointing at the beginning of the container. + * @return An iterator pointing at the beginning of the container. + */ +template <unsigned int N> +inline +typename Array<N>::const_iterator Array<N>::begin () const +{ + return ArrayIteratorChooser<N>::make_iterator (m_rep, m_offs); +} + + +/** + * @brief Return an iterator pointing past the end of the container. + * @return An iterator pointing past the end of the container. + */ +template <unsigned int N> +inline +typename Array<N>::const_iterator Array<N>::end () const +{ + unsigned int offs = m_rep ? m_offs + size() * m_rep->m_sizes[N-1] : 0; + return ArrayIteratorChooser<N>::make_iterator (m_rep, offs); +} + + +/** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ +template <unsigned int N> +inline +Array<N>::Array (const Arrayrep& rep, unsigned int offs) + : m_rep (&rep), + m_offs (offs) +{ +} + + +/** + * @brief Default constructor. + * + * This produces an invalid @c Array that is not associated with + * an @c Arrayrep. @c valid() will return @c false for such an array. + * The only other thing that it is legal to do with an invalid array + * is to assign to it (which may make it valid). + */ +inline +Array<0>::Array () + : m_elt (0) +{ +} + + +/** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ +inline +Array<0>::Array (const Arrayrep& rep) + : m_elt (&rep.m_data[0]) +{ + assert (rep.m_shape.size() == 0); + assert (rep.m_sizes.size() == rep.m_shape.size()); +} + + +/** + * @brief Test for validity. + * @return True if the @c Array is associated with an @c Arrayrep, + * false if not. + */ +inline +bool Array<0>::valid() const +{ + return m_elt != 0; +} + + +/** + * @brief Return the array shape. + * @return The array shape. + * + * The array shape is vector with one element for each array dimension, + * giving the size of the array along that dimension. + * For @c Array<0>, this will always be an empty array. + */ +inline +std::vector<unsigned int> Array<0>::shape() const +{ + return std::vector<unsigned int> (); +} + + +/** + * @brief Return the size of the array along one dimension. + * @param dim The dimension of the size to retrieve. + * Must be less than the number of dimensions. + * @return The array size along dimension @dim. + * + * For @c Array<0>, @a dim must be 0, and the function + * will always return 1. + */ +inline +unsigned int Array<0>::size (unsigned int UNUSED(dim) /*=0*/) const +{ + assert (dim == 0); + return 1; +} + + +/** + * @brief Convert to a number. + * @return The @c Array<0> contents as a number. + */ +inline +Array<0>::operator Arrayelt() const +{ + return *m_elt; +} + + +/** + * @brief Convert to an integer. + * @return The @c Array<0> contents as an integer. + */ +inline +int Array<0>::asint() const +{ + return static_cast<int> (*m_elt); +} + + +/** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ +inline +Array<0>::Array (const Arrayrep& rep, unsigned int offs) + : m_elt (&rep.m_data[offs]) +{ +} + + +//********************************************************************** + + +/** + * @brief Proxy constructor. + * @param i The iterator that is being dereferenced. + */ +template <unsigned int N> +ArrayIterator<N>::pointer::pointer (const ArrayIterator& i) + : m_a (*i) +{ +} + + +/** + * @brief Dereference the proxy. + * @return A copy of the @c Array proxy. + */ +template <unsigned int N> +typename ArrayIterator<N>::value_type +ArrayIterator<N>::pointer::operator* () const +{ + return m_a; +} + + +/** + * @brief Dereference the proxy. + * @return A pointer to the @c Array proxy. + * This proxy is only until the @c pointer instance + * is destroyed. + */ +template <unsigned int N> +const typename ArrayIterator<N>::value_type* +ArrayIterator<N>::pointer::operator-> () const +{ + return &m_a; +} + + +/** + * @brief Default constructor. + * Makes an invalid iterator. + */ +template <unsigned int N> +ArrayIterator<N>::ArrayIterator () + : m_rep (0), + m_offs (0) +{ +} + + +/** + * @brief Constructor from @c Arrayrep and offset. + * @param rep The underlying array representation. + * @param offs The offset in the representation of the + * first element referenced by this iterator. + */ +template <unsigned int N> +ArrayIterator<N>::ArrayIterator (const Arrayrep* rep, unsigned int offs) + : m_rep (rep), + m_offs (offs) +{ +} + + +/** + * @brief Equality comparison. + * @param other The other object with which to compare. + * @return True if the iterators are equal. + */ +template <unsigned int N> +bool ArrayIterator<N>::operator== (const ArrayIterator<N>& other) const +{ + return m_rep == other.m_rep && m_offs == other.m_offs; +} + + +/** + * @brief Inequality comparison. + * @param other The other object with which to compare. + * @return True if the iterators are not equal. + */ +template <unsigned int N> +bool ArrayIterator<N>::operator!= (const ArrayIterator<N>& other) const +{ + return !(*this == other); +} + + +/** + * @brief Less-than comparison. + * @param other The other object with which to compare. + * @return True if this iterator is less than @a other. + * This will always return false for iterators + * over different arrays. + */ +template <unsigned int N> +bool ArrayIterator<N>::operator< (const ArrayIterator<N>& other) const +{ + return m_rep == other.m_rep && m_offs < other.m_offs; +} + + +/** + * @brief Greater-than comparison. + * @param other The other object with which to compare. + * @return True if this iterator is greater than @a other. + * This will always return false for iterators + * over different arrays. + */ +template <unsigned int N> +bool ArrayIterator<N>::operator> (const ArrayIterator<N>& other) const +{ + return other < *this; +} + + +/** + * @brief Less-than-or-equal comparison. + * @param other The other object with which to compare. + * @return True if this iterator is less than or equal to @a other. + * This will always return false for iterators + * over different arrays. + */ +template <unsigned int N> +bool ArrayIterator<N>::operator<= (const ArrayIterator<N>& other) const +{ + return m_rep == other.m_rep && m_offs <= other.m_offs; +} + + +/** + * @brief Greater-than-or-equal comparison. + * @param other The other object with which to compare. + * @return True if this iterator is less than or equal to @a other. + * This will always return false for iterators + * over different arrays. + */ +template <unsigned int N> +bool ArrayIterator<N>::operator>= (const ArrayIterator<N>& other) const +{ + return other <= *this; +} + + +/** + * @brief Dereference the iterator. + * @return The value that the iterator points to. + * Note that this method returns a @c value_type, not + * a @c reference. (Thus, this class does not quite + * conform to the iterator requirements.) + */ +template <unsigned int N> +typename ArrayIterator<N>::value_type ArrayIterator<N>::operator* () const +{ + assert (m_offs < m_rep->m_data.size()); + return Array<N-1> (*m_rep, m_offs); +} + + +/** + * @brief Dereference the iterator. + * @return A proxy for the iterator element. + * + * This method will return a proxy for the array, which you + * can then dereference. Note that if you get a C++ pointer + * from this, then it will be valid only until the proxy + * object gets destroyed. + */ +template <unsigned int N> +typename ArrayIterator<N>::pointer ArrayIterator<N>::operator-> () const +{ + return pointer (*this); +} + + +/** + * @brief Advance the iterator. + * @returns This iterator. + */ +template <unsigned int N> +ArrayIterator<N>& ArrayIterator<N>::operator++ () +{ + m_offs += m_rep->m_sizes[N-1]; + return *this; +} + + +/** + * @brief Advance the iterator. + * @returns The iterator before being advanced. + */ +template <unsigned int N> +ArrayIterator<N> ArrayIterator<N>::operator++ (int) +{ + ArrayIterator tmp (*this); + m_offs += m_rep->m_sizes[N-1]; + return tmp; +} + + +/** + * @brief Back up the iterator. + * @returns This iterator. + */ +template <unsigned int N> +ArrayIterator<N>& ArrayIterator<N>::operator-- () +{ + m_offs -= m_rep->m_sizes[N-1]; + return *this; +} + + +/** + * @brief Back up the iterator. + * @returns The iterator before being backed up. + */ +template <unsigned int N> +ArrayIterator<N> ArrayIterator<N>::operator-- (int) +{ + ArrayIterator tmp (*this); + m_offs -= m_rep->m_sizes[N-1]; + return tmp; +} + + +/** + * @brief Array indexing relative to the iterator. + * @param n The array index. + * @return The array item at an offset of @a n from the + * current iterator position. + * Note that this method returns a @c value_type, not + * a @c reference. (Thus, this class does not quite + * conform to the iterator requirements.) + */ +template <unsigned int N> +typename ArrayIterator<N>::value_type +ArrayIterator<N>::operator[] (difference_type n) const +{ + unsigned int offs = m_offs + n * m_rep->m_sizes[N-1]; + assert (offs < m_rep->m_data.size()); + return Array<N-1> (*m_rep, offs); +} + + +/** + * @brief Advance the iterator. + * @param n Number of steps by which to advance the iterator. + * @return This iterator. + */ +template <unsigned int N> +ArrayIterator<N>& ArrayIterator<N>::operator+= (difference_type n) +{ + m_offs += n * m_rep->m_sizes[N-1]; + return *this; +} + + +/** + * @brief Return a new iterator pointing @a n steps ahead. + * @param n Number of steps by which to advance. + * @return The new iterator. + */ +template <unsigned int N> +ArrayIterator<N> ArrayIterator<N>::operator+ (difference_type n) const +{ + return ArrayIterator (m_rep, m_offs + n * m_rep->m_sizes[N-1]); +} + + +/** + * @brief Back up the iterator. + * @param n Number of steps by which to advance the iterator. + * @return This iterator. + */ +template <unsigned int N> +ArrayIterator<N>& ArrayIterator<N>::operator-= (difference_type n) +{ + m_offs -= n * m_rep->m_sizes[N-1]; + return *this; +} + + +/** + * @brief Return a new iterator pointing @a n steps behind. + * @param n Number of steps by which to back up. + * @return The new iterator. + */ +template <unsigned int N> +ArrayIterator<N> ArrayIterator<N>::operator- (difference_type n) const +{ + return ArrayIterator (m_rep, m_offs - n * m_rep->m_sizes[N-1]); +} + + +/** + * @brief Return the difference between two iterators. + * @param other The other iterator for the comparison. + * @return The number of elements difference between + * this iterator and @a other. + * Undefined if the two iterators do not point + * into the same array. + */ +template <unsigned int N> +typename ArrayIterator<N>::difference_type +ArrayIterator<N>::operator- (const ArrayIterator& other) const +{ + return (m_offs - other.m_offs) / m_rep->m_sizes[N-1]; +} + + +//********************************************************************** + + +/** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ +template <unsigned int N> +inline +WritableArray<N>::WritableArray (Arrayrep& rep) + : Array<N> (rep) +{ +} + + +/** + * @brief Array indexing. + * @param i The desired index. Must be less than the array size + * along this dimension. + * @return The @a i'th @c N-1 dimensional subarray in the array. + * + * Note that this operation is not available if @c N is 0. + */ +template <unsigned int N> +inline +WritableArray<N-1> WritableArray<N>::operator[] (unsigned int i) const +{ + assert (i < this->m_rep->m_shape[this->m_rep->m_shape.size() - N]); + return WritableArray<N-1> (const_cast<Arrayrep&> (*this->m_rep), + this->m_offs + i * this->m_rep->m_sizes[N-1]); +} + + +/** + * @brief Return a direct pointer to array elements. + * @return A pointer to the first array elements. + * + * Subsequent elements follow in standard C indexing order. + */ +template <unsigned int N> +inline +Arrayelt* WritableArray<N>::ptr () +{ + return const_cast<Arrayelt*> (&this->m_rep->m_data[this->m_offs]); +} + + +/** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ +template <unsigned int N> +inline +WritableArray<N>::WritableArray (Arrayrep& rep, unsigned int offs) + : Array<N> (rep, offs) +{ +} + + +/** + * @brief Constructor. + * @param rep @c Arrayrep from which to initialize the array. + * + * Initialize an array from an @c Arrayrep. The new array will + * represent the entire @c Arrayrep. The dimension @c N must + * match the length of the @c Arrayrep's shape. + */ +inline +WritableArray<0>::WritableArray (Arrayrep& rep) + : Array<0> (rep) +{ +} + + +/** + * @brief Assignment. + * @param elt The RHS of the assignment. + * @return This object. + * + * Assign into the array. + */ +inline +WritableArray<0>& WritableArray<0>::operator= (Arrayelt elt) +{ + *const_cast<Arrayelt*> (m_elt) = elt; + return *this; +} + + +/** + * @brief Private constructor for array indexing. + * @param rep @c Arrayrep from which to initialize the array. + * @param offs Offset of the first element of the new array + * within @a rep. + * + * This is a private constructor used to make the @c Array + * instances returned from an indexing operation. + */ +inline +WritableArray<0>::WritableArray (Arrayrep& rep, unsigned int offs) + : Array<0> (rep, offs) +{ +} + + +//********************************************************************** + + +/** + * @brief Constructor. + * @param shape The shape of the array, as a C array. + * Should be @c N elements long. \ + * + * The shape is the size of the array along each dimension. + */ +template <unsigned int N> +WritableArrayData<N>::WritableArrayData(const unsigned int shape[]) + : Arrayrep (shape, N), + WritableArray<N> (*static_cast<Arrayrep*>(this)) +{ +} + + +/** + * @brief Constructor. + * @param shape The shape of the array, as a std::vector. + * Should be @c N elements long. + * + * The shape is the size of the array along each dimension. + */ +template <unsigned int N> +WritableArrayData<N>::WritableArrayData(const std::vector<unsigned int>& shape) + : Arrayrep (shape), + WritableArray<N> (*static_cast<Arrayrep*>(this)) +{ + assert (shape.size() == N); +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.h b/EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.h new file mode 100644 index 00000000..158e2dd3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.h @@ -0,0 +1,141 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArrayScanner.h,v 1.1 2009-03-20 20:44:22 ssnyder Exp $ +/** + * @file ArrayScanner.h + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Helper class for converting strings to Array's. + */ + + +#ifndef CXXUTILS_ARRAYSCANNER_H +#define CXXUTILS_ARRAYSCANNER_H + + +#include <istream> + + +namespace CxxUtils { + + +/** + * @class ArrayScanner + * @brief Helper class for converting strings to Array's. + * + * This class is a simple lexical analyzer used in converting strings + * to multidimensional array representations. We get a stream as input. + * This stream can contain three types of tokens: an open bracket, + * a close bracket, or a floating-point number. We provide methods + * to test if either of these three items is at the head of the stream. + * If so, the item is consumed. (An optional comma may follow a close + * bracket or a number; it is consumed when the item in front of it + * is consumed.) We can also test to see if we're at the end. + */ +class ArrayScanner +{ +public: + /** + * @brief Constructor. + * @param is The stream from which to scan. + * + * Builds a new scanner reading from stream @a is. + */ + ArrayScanner (std::istream& is); + + /** + * @brief Read opening token. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at `[', consume it and return true. + * Otherwise, return false. + */ + bool at_open(); + + /** + * @brief Read closing token. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at `]', consume it and return true. + * If there's a comma following it, consume that too. + * Otherwise, return false. + */ + bool at_close(); + + /** + * @brief Test for end-of-stream. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * Return true if we're then at the end of the stream. + * Otherwise, return false. + */ + bool at_end(); + + /** + * @brief Read number. + * @param elt[out] The number read. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at a number that can be converted to type @c T, + * read it and return true. The value is returned in @a elt. + * If there's a comma following it, consume that too. + * Otherwise, return false. + */ + template <class T> + bool at_num (T& elt); + + +private: + /** + * @brief Read a character. + * @param c The character to read. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at @a c, consume it and return true. + * Otherwise, return false. + */ + bool at_char (char c); + + /** + * @brief The non-template part of reading a number. + * @return True if successful. + * + * This is called after the attempt to read the number itself. + * This function checks that the read was in fact successful. + * If so, then it will also consume any following comma. + */ + bool at_num_common(); + + + /// The stream from which we're reading. + std::istream& m_is; +}; + + +template <class T> +bool ArrayScanner::at_num (T& elt) +{ + m_is >> elt; + return at_num_common(); +} + + +} // namespace CxxUtils + + +// Backwards compatibility. +namespace CaloRec { + using CxxUtils::ArrayScanner; +} + + +#endif // not CXXUTILS_ARRAYSCANNER_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.icc b/EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.icc new file mode 100644 index 00000000..297af632 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/ArrayScanner.icc @@ -0,0 +1,39 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArrayScanner.icc,v 1.1 2009-03-20 20:44:37 ssnyder Exp $ +/** + * @file ArrayScanner.icc + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Helper class for converting strings to Array's + * (template definitions). + */ + + +namespace CaloRec { + + +/** + * @brief Read number. + * @param elt[out] The number read. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at a number that can be converted to type @c T, + * read it and return true. The value is returned in @a elt. + * If there's a comma following it, consume that too. + * Otherwise, return false. + */ +template <class T> +bool ArrayScanner::at_num (T& elt) +{ + m_is >> elt; + return at_num_common(); +} + + +} // namespace CaloRec + + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/Arrayrep.h b/EDM/athena/Control/CxxUtils/CxxUtils/Arrayrep.h new file mode 100644 index 00000000..ba40bb33 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/Arrayrep.h @@ -0,0 +1,159 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arrayrep.h,v 1.2 2009-04-07 04:26:22 ssnyder Exp $ +/** + * @file Arrayrep.h + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Representation class for Array's. + */ + +#ifndef CXXUTILS_ARRAYREP_H +#define CXXUTILS_ARRAYREP_H + + +#include <string> +#include <vector> + + +// Presently has to be in CaloRec ns for backwards compatibility. +namespace CaloRec { + + +/// The type of an element of an @c Array. +typedef float Arrayelt; + + +/** + * @class Arrayrep + * @brief Representation class for Array's. + * + * This class is used for the implementation of multidimensional + * array constants. The user interface is provided by the + * @c Array template class. Given an @c Array<N> @c a, we want + * @c a[i] to be an @c Array<N-1>. However, we don't want to have + * to copy the array data. Thus, the @c Array class just holds + * a reference to the actual array data. Those data are stored + * in an instance of @c Arrayrep. + * + * An @c Arrayrep is defined by two vectors: one giving all the + * array elements, and the second giving the shape of the array. + * (A shape is a vector with one integer per array dimension, + * the integers giving the size of the dimensions.) + * + * We maintain one additional array as an optimization. + * @c m_sizes[0] contains the total size in elements + * of the array resulting from a single indexing operation. + * @c m_sizes[1] contains the size of the array resulting from + * two indexing operations, and so on. @c m_sizes has the same + * length as @c m_shape, but the last element is always 1. + * The function @c init_sizes will initialize the @c m_sizes + * array from the contents of @c m_shape. + * + * A scalar (0-dimensional array) is represented by @c m_shape (and + * @c m_sizes) being empty, and @c m_data having a single element. + * + * If both @c m_shape and @c m_data are empty, then the representation + * is uninitialized. + */ +struct Arrayrep +{ + /** + * @brief Default constructor. + * + * This makes an uninitialized @c Arrayrep. + */ + Arrayrep () {} + + /** + * @brief Construct from a string. + * @param str The string to convert. + * @param context An optional string to use for error reporting. + * + * Parse the string and initialize the array. + * This string should be like `[[1, 2], [3, 4]]'. + */ + explicit Arrayrep (const std::string& str, + const std::string& context = ""); + + /** + * @brief Construct an empty array of a given shape. + * @param shape The shape of the array. + * + * Initialize an array of a given shape. + * The array will contain all 0's. + */ + explicit Arrayrep (const std::vector<unsigned int>& shape); + + /** + * @brief Construct an empty array of a given shape. + * @param shape The shape of the array. + * @param n The length of the @a shape array. + * + * Initialize an array of a given shape. + * The array will contain all 0's. + * This version is more convenient to call with a constant shape. + */ + explicit Arrayrep (const unsigned int shape[], unsigned int n); + + /// The array data, stored using the C array ordering. + std::vector<Arrayelt> m_data; + + /// The array shape. + /// One entry per dimension, giving the size of each dimension. + std::vector<unsigned int> m_shape; + + /// Subarray sizes, for faster access. See above. + /// This member could be considered transient. + std::vector<unsigned int> m_sizes; + + /** + * @brief Initialize the @c m_sizes vector from the @c m_shape vector. + * @param resize_data Should @c m_data be resized appropriately? + * + * The contents of the @c m_sizes vector are initialized from + * the contents of the @c m_shape vector. If @c resize_data + * is true, then the size of @c m_data is changed to the total + * size indicated by @c m_shape. Otherwise, we verify that + * @c m_data has the correct size, and raise an assertion if not. + */ + void init_sizes (bool resize_data = false); + + /** + * @brief Creates a text representation of the array content. + * @param std::ostream where the text should be written + * + * Writes the content of the array to a ostream. The sub-arrays are + * enclosed by square-brackets and separated by commas. + */ + + void write_array(std::ostream& stream) const; + + /** + * @brief Helper function for write_array. + * @param stream where the array should be written + * @param idx Current index in @c m_data + * @param dimIndex Current index in @c m_shapes + * + * Calls itself recursively with dimIndex-1 + */ + + void write_subarray(std::ostream& stream, std::vector<Arrayelt>::size_type& idx, unsigned dimIndex) const; + +}; + + +} // namespace CaloRec + + +namespace CxxUtils { + using CaloRec::Arrayrep; + using CaloRec::Arrayelt; +} + + +#endif // not CXXUTILS_ARRAYREP_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/AthDsoCbk.h b/EDM/athena/Control/CxxUtils/CxxUtils/AthDsoCbk.h new file mode 100644 index 00000000..858d3bf6 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/AthDsoCbk.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** -*- C -*- + * AthDsoCbk.h + * Header file for the dso callbacks api + * Author: S.Binet<binet@cern.ch> + */ + +#ifndef CXXUTILS_ATHDSOCBK_H +#define CXXUTILS_ATHDSOCBK_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus */ + +/* forward declares */ + +/* type of events the dso-callback framework will dispatch */ +struct ath_dso_event +{ + const char* fname; /* the name of the dso being loaded */ + int step; /* 0: before loading the dso + 1: after loading the dso */ +}; + +/* type of the callback function the dso logger will execute + * NOTE: userdata pointer may be NULL + */ +typedef int (*ath_dso_event_cbk_t)(const struct ath_dso_event*, void *userdata); + +/* register a callback function with the dso-cbk framework + * @return 0 on success + * -1 on failure + */ +int ath_dso_cbk_register(ath_dso_event_cbk_t cbk, void *userdata); + +/* unregister a callback function with the dso-cbk framework + * @return 0 on success + * -1 on failure + */ +int ath_dso_cbk_unregister(ath_dso_event_cbk_t cbk); + +#ifdef __cplusplus +} /* extern C */ +#endif /*__cplusplus */ + +#endif /* !CXXUTILS_ATHDSOCBK_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/AthUnlikelyMacros.h b/EDM/athena/Control/CxxUtils/CxxUtils/AthUnlikelyMacros.h new file mode 100644 index 00000000..78f4172d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/AthUnlikelyMacros.h @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CXXUTILS_ATHUNLIKELYMACROS_H +#define CXXUTILS_ATHUNLIKELYMACROS_H 1 + +/* macros modeled after http://kernelnewbies.org/FAQ/LikelyUnlikely + * to help the compiler into generating instructions to optimize the + * branch prediction. + */ +#if __GNUC__ >= 4 +# define ATH_LIKELY(x) __builtin_expect(!!(x), 1) +# define ATH_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define ATH_LIKELY(x) (x) +# define ATH_UNLIKELY(x) (x) +#endif + +#endif /* !CXXUTILS_ATHUNLIKELYMACROS_H */ diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/BasicTypes.h b/EDM/athena/Control/CxxUtils/CxxUtils/BasicTypes.h new file mode 100644 index 00000000..32d921cc --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/BasicTypes.h @@ -0,0 +1,23 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/BasicTypes.h + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Jan 2010, from earlier code. + * @brief Provide simplified clock_gettime() function for MacOSX. + */ + + +#ifndef CXXUTILS_BASICTYPES_H +#define CXXUTILS_BASICTYPES_H + +#ifdef __APPLE__ +typedef unsigned int uint; +#endif + +#endif // not CXXUTILS_BASICTYPES_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.h b/EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.h new file mode 100644 index 00000000..9b49f940 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.h @@ -0,0 +1,200 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/BitPacker.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper to pack a set of values bitwise into a stream. + */ + + +#ifndef CXXUTILS_BITPACKER_H +#define CXXUTILS_BITPACKER_H + + +#include <stdint.h> +#include <cassert> + + +namespace CxxUtils { + + +/** + * @brief Pack a set of values bitwise into a stream. + * + * This helper can be used to pack a set of values into 32-bit words + * and write them to a stream. The number of bits taken by each + * value is configurable. + * + * @c STREAM should support output (operator<<) with @c uint32_t + * (satisfied by a ROOT TBuffer). + */ +template <class STREAM> +class BitPacker +{ +public: + /** + * @brief Constructor. + * @param nbits Number of bits per item to use in the packed representation. + * @param stream Output stream object. + */ + BitPacker (uint8_t nbits, STREAM& stream); + + + /** + * @brief Destructor. + * + * This may flush buffered data to the output stream. + */ + ~BitPacker(); + + + /** + * @brief Pack one value to the stream. + * @param x The value to pack. + * The upper bits should all be clear. + */ + void pack (uint32_t x); + + +private: + /// Buffer for the current words being packed. + uint32_t m_buf; + + /// Number of valid bits currently buffered. + uint8_t m_nbuf; + + /// Number of bits to use for each item. + uint8_t m_nbits; + + /// The output stream. + STREAM& m_stream; +}; + + +/** + * @brief Pack a set of values bitwise into a stream. + * + * This helper can be used to pack a set of values into 32-bit words + * and write them to a stream. This is a special case for 8-bit values. + * + * @c STREAM should support output (operator<<) with @c uint32_t + * (satisfied by a ROOT TBuffer). + */ +template <class STREAM> +class BitPacker8 +{ +public: + /** + * @brief Constructor. + * @param stream Output stream object. + */ + BitPacker8 (STREAM& stream); + + + /** + * @brief Constructor. + * @param nbits Must be 8. + * @param stream Output stream object. + */ + BitPacker8 (uint8_t nbits, STREAM& stream); + + + /** + * @brief Destructor. + * + * This may flush buffered data to the output stream. + */ + ~BitPacker8(); + + + /** + * @brief Pack one value to the stream. + * @param x The value to pack. + * The upper bits should all be clear. + */ + void pack (uint32_t x); + + +private: + /// Buffer for the current words being packed. + uint32_t m_buf; + + /// Number of valid bits currently buffered. + uint8_t m_nbuf; + + /// The output stream. + STREAM& m_stream; +}; + + +/** + * @brief Pack a set of values bitwise into a stream. + * + * This helper can be used to pack a set of values into 32-bit words + * and write them to a stream. This is a special case for 16-bit values. + * + * @c STREAM should support output (operator<<) with @c uint32_t + * (satisfied by a ROOT TBuffer). + */ +template <class STREAM> +class BitPacker16 +{ +public: + /** + * @brief Constructor. + * @param nbits Number of bits per item to use in the packed representation. + * @param stream Output stream object. + */ + BitPacker16 (STREAM& stream); + + + /** + * @brief Constructor. + * @param nbits Must be 16. + * @param stream Output stream object. + */ + BitPacker16 (uint8_t nbits, STREAM& stream); + + + /** + * @brief Destructor. + * + * This may flush buffered data to the output stream. + */ + ~BitPacker16(); + + + /** + * @brief Pack one value to the stream. + * @param x The value to pack. + * The upper bits should all be clear. + */ + void pack (uint32_t x); + + +private: + /// Buffer for the current words being packed. + uint32_t m_buf; + + /// Number of valid words currently buffered. + uint8_t m_nbuf; + + /// The output stream. + STREAM& m_stream; +}; + + +} // namespace CxxUtils + + +#include "CxxUtils/BitPacker.icc" + + +#endif // not CXXUTILS_BITPACKER_H + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.icc b/EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.icc new file mode 100644 index 00000000..39a4cd3e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/BitPacker.icc @@ -0,0 +1,196 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/BitPacker.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper to pack a set of values bitwise into a stream. + */ + + +namespace CxxUtils { + + +/** + * @brief Constructor. + * @param nbits Number of bits per item to use in the packed representation. + * @param stream Output stream object. + */ +template <class STREAM> +inline +BitPacker<STREAM>::BitPacker (uint8_t nbits, STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_nbits(nbits), + m_stream (stream) +{ + assert (m_nbits > 0 && m_nbits <= 32); +} + + +/** + * @brief Destructor. + * + * This may flush buffered data to the output stream. + */ +template <class STREAM> +inline +BitPacker<STREAM>::~BitPacker() +{ + if (m_nbuf > 0) + m_stream << m_buf; +} + + +/** + * @brief Pack one value to the stream. + * @param x The value to pack. + * The upper bits should all be clear. + */ +template <class STREAM> +inline +void BitPacker<STREAM>::pack (uint32_t dat) +{ + const uint8_t totbits = 8*sizeof(m_buf); + + m_buf |= (dat << m_nbuf); + m_nbuf += m_nbits; + if (m_nbuf >= totbits) { + m_stream << m_buf; + m_nbuf -= totbits; + if (m_nbuf == 0) + m_buf = 0; + else + m_buf = dat >> (m_nbits - m_nbuf); + } +} + + +/** + * @brief Constructor. + * @param stream Output stream object. + */ +template <class STREAM> +inline +BitPacker8<STREAM>::BitPacker8 (STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Constructor. + * @param nbits Must be 8. + * @param stream Output stream object. + */ +template <class STREAM> +inline +BitPacker8<STREAM>::BitPacker8 (uint8_t /*nbits*/, STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Destructor. + * + * This may flush buffered data to the output stream. + */ +template <class STREAM> +inline +BitPacker8<STREAM>::~BitPacker8() +{ + if (m_nbuf > 0) + m_stream << m_buf; +} + + +/** + * @brief Pack one value to the stream. + * @param x The value to pack. + * The upper bits should all be clear. + */ +template <class STREAM> +inline +void BitPacker8<STREAM>::pack (uint32_t dat) +{ + m_buf |= (dat << m_nbuf); + m_nbuf += 8; + if (m_nbuf == 32) { + m_stream << m_buf; + m_buf = 0; + m_nbuf = 0; + } +} + + +/** + * @brief Constructor. + * @param stream Output stream object. + */ +template <class STREAM> +inline +BitPacker16<STREAM>::BitPacker16 (STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Constructor. + * @param nbits Must be 16. + * @param stream Output stream object. + */ +template <class STREAM> +inline +BitPacker16<STREAM>::BitPacker16 (uint8_t /*nbits*/, STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Destructor. + * + * This may flush buffered data to the output stream. + */ +template <class STREAM> +inline +BitPacker16<STREAM>::~BitPacker16() +{ + if (m_nbuf > 0) + m_stream << m_buf; +} + + +/** + * @brief Pack one value to the stream. + * @param x The value to pack. + * The upper bits should all be clear. + */ +template <class STREAM> +inline +void BitPacker16<STREAM>::pack (uint32_t dat) +{ + m_buf |= (dat << m_nbuf); + m_nbuf += 16; + if (m_nbuf == 32) { + m_stream << m_buf; + m_buf = 0; + m_nbuf = 0; + } +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.h b/EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.h new file mode 100644 index 00000000..4184d9be --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.h @@ -0,0 +1,173 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/BitUnpacker.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper to unpack a set of values bitwise from a stream. + */ + + +#ifndef CXXUTILS_BITUNPACKER_H +#define CXXUTILS_BITUNPACKER_H + + +#include <stdint.h> +#include <cassert> + + +namespace CxxUtils { + + +/** + * @brief Helper to unpack a set of values bitwise from a stream. + * + * This helper can be used to unpack a set of values from a stream + * and return them as a set of 32-bit words. The number of bits taken by each + * value is configurable. + * + * @c STREAM should support input (operator>>) with @c uint32_t + * (satisfied by a ROOT TBuffer). + */ +template <class STREAM> +class BitUnpacker +{ +public: + /** + * @brief Constructor. + * @param nbits Number of bits per item to use in the packed representation. + * @param stream Input stream object. + */ + BitUnpacker (uint8_t nbits, STREAM& stream); + + + /** + * @brief Unpack one value from the stream. + */ + uint32_t unpack(); + + +private: + /// Buffer for the current word being unpacked. + uint32_t m_buf; + + /// Number of valid bits currently buffered. + uint8_t m_nbuf; + + /// Number of bits to use for each item. + uint8_t m_nbits; + + /// The input stream. + STREAM& m_stream; + + /// Mask with the low @c m_nbits bits set. + uint32_t m_mask; +}; + + +/** + * @brief Helper to unpack a set of values bitwise from a stream. + * + * This helper can be used to unpack a set of values from a stream + * and return them as a set of 32-bit words. This is a special case + * for 8-bit values. + * + * @c STREAM should support input (operator>>) with @c uint32_t + * (satisfied by a ROOT TBuffer). + */ +template <class STREAM> +class BitUnpacker8 +{ +public: + /** + * @brief Constructor. + * @param stream Input stream object. + */ + BitUnpacker8 (STREAM& stream); + + + /** + * @brief Constructor. + * @param nbits Must be 8. + * @param stream Input stream object. + */ + BitUnpacker8 (uint8_t nbits, STREAM& stream); + + + /** + * @brief Unpack one value from the stream. + */ + uint32_t unpack(); + + +private: + /// Buffer for the current word being unpacked. + uint32_t m_buf; + + /// Number of valid bytes currently buffered. + uint8_t m_nbuf; + + /// The input stream. + STREAM& m_stream; +}; + + +/** + * @brief Helper to unpack a set of values bitwise from a stream. + * + * This helper can be used to unpack a set of values from a stream + * and return them as a set of 32-bit words. This is a special case + * for 16-bit values. + * + * @c STREAM should support input (operator>>) with @c uint32_t + * (satisfied by a ROOT TBuffer). + */ +template <class STREAM> +class BitUnpacker16 +{ +public: + /** + * @brief Constructor. + * @param stream Input stream object. + */ + BitUnpacker16 (STREAM& stream); + + + /** + * @brief Constructor. + * @param nbits Must be 16. + * @param stream Input stream object. + */ + BitUnpacker16 (uint8_t nbits, STREAM& stream); + + + /** + * @brief Unpack one value from the stream. + */ + uint32_t unpack(); + + +private: + /// Buffer for the current word being unpacked. + uint32_t m_buf; + + /// Number of valid words currently buffered. + uint8_t m_nbuf; + + /// The input stream. + STREAM& m_stream; +}; + + +} // namespace CxxUtils + + +#include "CxxUtils/BitUnpacker.icc" + + +#endif // not CXXUTILS_BITUNPACKER_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.icc b/EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.icc new file mode 100644 index 00000000..724328c7 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/BitUnpacker.icc @@ -0,0 +1,170 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/BitUnpacker.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Helper to unpack a set of values bitwise from a stream. + */ + + +#include "CxxUtils/ones.h" + + +namespace CxxUtils { + + +/** + * @brief Constructor. + * @param nbits Number of bits per item to use in the packed representation. + * @param stream Input stream object. + */ +template <class STREAM> +inline +BitUnpacker<STREAM>::BitUnpacker (uint8_t nbits, STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_nbits(nbits), + m_stream (stream), + m_mask (CxxUtils::ones<uint32_t>(nbits)) +{ + assert (m_nbits > 0 && m_nbits <= 32); +} + + +/** + * @brief Unpack one value from the stream. + */ +template <class STREAM> +inline +uint32_t BitUnpacker<STREAM>::unpack() +{ + const uint8_t totbits = 8*sizeof(m_buf); + + if (m_nbuf == 0) { + m_stream >> m_buf; + m_nbuf = totbits; + } + + uint32_t out = m_buf & m_mask; + if (m_nbits > m_nbuf) { + uint8_t nleft = m_nbits - m_nbuf; + m_stream >> m_buf; + out |= (m_buf & CxxUtils::ones<uint32_t>(nleft)) << m_nbuf; + m_buf >>= nleft; + m_nbuf = totbits - nleft; + } + else { + if (m_nbits >= 32) + m_buf = 0; + else + m_buf >>= m_nbits; + m_nbuf -= m_nbits; + } + + return out; +} + + +/** + * @brief Constructor. + * @param stream Input stream object. + */ +template <class STREAM> +inline +BitUnpacker8<STREAM>::BitUnpacker8 (STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Constructor. + * @param nbits Must be 8. + * @param stream Input stream object. + */ +template <class STREAM> +inline +BitUnpacker8<STREAM>::BitUnpacker8 (uint8_t /*nbits*/, STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Unpack one value from the stream. + */ +template <class STREAM> +inline +uint32_t BitUnpacker8<STREAM>::unpack() +{ + if (m_nbuf == 0) { + m_stream >> m_buf; + m_nbuf = 4; + } + + uint8_t ret = m_buf & 0xff; + m_buf >>= 8; + --m_nbuf; + return ret; +} + + +/** + * @brief Constructor. + * @param stream Input stream object. + */ +template <class STREAM> +inline +BitUnpacker16<STREAM>::BitUnpacker16 (STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Constructor. + * @param nbits Must be 16. + * @param stream Input stream object. + */ +template <class STREAM> +inline +BitUnpacker16<STREAM>::BitUnpacker16 (uint8_t /*nbits*/, STREAM& stream) + : m_buf(0), + m_nbuf(0), + m_stream (stream) +{ +} + + +/** + * @brief Unpack one value from the stream. + */ +template <class STREAM> +inline +uint32_t BitUnpacker16<STREAM>::unpack() +{ + if (m_nbuf == 0) { + m_stream >> m_buf; + m_nbuf = 2; + } + + uint16_t ret = m_buf & 0xffff; + m_buf >>= 16; + --m_nbuf; + return ret; +} + + +} // namespace CxxUtils + + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/ClassName.h b/EDM/athena/Control/CxxUtils/CxxUtils/ClassName.h new file mode 100644 index 00000000..20d669e5 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/ClassName.h @@ -0,0 +1,478 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/ClassName.h + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Recursively separate out template arguments in a C++ class name. + */ + + +#ifndef CXXUTILS_CLASSNAME_H +#define CXXUTILS_CLASSNAME_H + + +#include <string> +#include <vector> +#include <map> +#include <stdexcept> + + +namespace CxxUtils { + + +/** + * @brief Recursively separate out template arguments in a C++ class name. + * + * This class allows making some simple transformations of C++ class names. + * For example, given these rules: + * + *@code + * ClassName::Rules rules; + * + * rules.add ("std::vector<$T, std::allocator<$T> >", + * "std::vector<$T>"); + * rules.add ("std::map<$K,$V, std::less<$K>, std::allocator<std::pair<const $K,$V> > >", + * "std::map<$K,$V>"); + * rules.add ("DataVector<$T, $B>", "DataVector<$T>"); + * rules.add ("std::__1", "std"); + @endcode + * + * then `rules.apply` can make transformations like this: + * + *@code + * + * std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > + * -> std::vector<std::vector<int> > + * + * std::map<int, float, std::less<int>, std::allocator<std::pair<const int, float> > > + * -> std::map<int, float> + * + * DataVector<Foo, DataModel_detail::NoBase> + * -> DataVector<Foo> + @endcode + * + * In slightly more detail: this class analyzes C++ class names. A name + * like + * + *@code + * A::B<int, double> + @endcode + * + * is broken down like this: + * + * - Name: `B`. + * - Namespace: `A`. + * - Template arguments: `int` and `double`. + * + * This is done recursively; both the namespace and template argument + * pieces can be further broken down like this. A name can also + * be marked as `const', but no other parsing of C-like declarators + * is done. + * + * Parsed names can be matched against simple patterns like this: + * + *@code + * A::B<$T> + @endcode + * + * and the variable `T` gets set to the corresponding piece of the type + * being matched. For example, given the above pattern, + * + * - `A::C<int>` matches with `T` set to `int`. + * - `A::C<const Foo<Bar> >` matches with `T` set to `const Foo<Bar>`. + * + * If the pattern were `A::B<const $T>`, then `A::B<const int>` would + * match with `T` set to `int`, but `A::B<int>` would not match. + * + * However, the root name of a pattern may not be a variable; for example, + * you can't use `A::$T<int>` as a pattern. + * + * You can also substitute variables back into a pattern; for example, + * + * - `T=int` into `A::B<$T>` gives `A::B<int>`. + * - `T=const int` into `A::B<$T>` gives `A::B<const int>`. + * - `T=const int` into `A::B<const int>` gives `A::B<const int>`. + */ +class ClassName +{ +public: + + /** + * @brief Exception to signal a malformed class name. + */ + class ExcBadClassName + : public std::runtime_error + { + public: + ExcBadClassName (const std::string& name); + }; + + + /** + * @brief Exception to signal a missing variable. + */ + class ExcMissingVariable + : public std::runtime_error + { + public: + ExcMissingVariable (const std::string& var); + }; + + + /** + * @brief A set of transformation rules to use with @c ClassName. + */ + class Rules + { + public: + /** + * @brief Return the number of defined rules. + */ + size_t size() const; + + + /** + * @brief Add a new transformation rule. + * @param pattern The pattern to match. + * @param replacement The expression with which to replace it. + * + * The pattern may contain variables that are then substituted into + * the replacement; for example, given a pattern of `A<$T, $T>` and + * a replacement of `B<$T>`, then `A<Foo<int>, Foo<int> >` would + * be transformed to `B<Foo<int> >'. + */ + void add (const ClassName& pattern, const ClassName& replacement); + + +#if __cplusplus > 201100 + /** + * @brief Add a new transformation rule (move version). + * @param pattern The pattern to match. + * @param replacement The expression with which to replace it. + * + * The pattern may contain variables that are then substituted into + * the replacement; for example, given a pattern of `A<$T, $T>` and + * a replacement of `B<$T>`, then `A<Foo<int>, Foo<int> >` would + * be transformed to `B<Foo<int> >'. + */ + void add (ClassName&& pattern, ClassName&& replacement); +#endif + + + /** + * @brief Apply the set of transformation rules to a class name object. + * @param cn The object to which the rules should be applied. + * Will be modified in place. + * + * All transformation rules are matched against @c cn. If any match, + * the object is replaced with the replacement portion of the rule + * with match results substituted. + * + * Returns true if any matches were made and false otherwise. + */ + bool applyTo (ClassName& cn) const; + + + /** + * @brief Apply transformations to a class name. + * @param name The class name to transform. + * + * Returns the transformed class name. + * + * This is just shorthand for calling `ClassName::applyRules`. + */ + std::string apply (const std::string& name) const; + + + private: + /// A pattern and replacement. + typedef std::pair<ClassName, ClassName> pat_repl_t; + + /// Map from the root of a pattern to the pattern, replacement pair. + typedef std::multimap<std::string, pat_repl_t> rulemap_t; + rulemap_t m_rules; + }; + + + /// Map used to hold variable assignments from matching. + typedef std::map<std::string, ClassName> match_t; + + + /** + * @brief Default constructor. + * + * Needed for STL compatibility. + */ + ClassName (); + + + /** + * @brief Parse a class name into component parts. + * @param name The name to parse. + * + * Raises a @c BadClassName exception if the name isn't completely parsed. + */ + ClassName (const char* name); + + + /** + * @brief Parse a class name into component parts. + * @param name The name to parse. + * + * Raises a @c BadClassName exception if the name isn't completely parsed. + */ + ClassName (const std::string& name); + + + /** + * @brief Parse a class name into component parts. + * @param name String containing the name to parse. + * @param pos Position in the string at which parsing should start. + * + * @c pos is updated to point to past the point where parsing stopped. + */ + ClassName (const std::string& name, std::string::size_type& pos); + + + /** + * @brief Swap this expression with another one. + * @param other The other expression with which to swap. + */ + void swap (ClassName& other); + + + /** + * @brief Set the const flag for this expression. + */ + void setConst(); + + + /** + * @brief Return the root name of the expression. + * + * In `A::B<C>`, the root name is `B`. + */ + std::string name() const; + + + /** + * @brief Return the namespace-qualified name of the expression. + * + * In `A::B<C>`, this is `A::B`. + */ + std::string qualifiedName() const; + + + /** + * @brief Return the full name of the expression. + */ + std::string fullName() const; + + + /** + * @brief Test two expressions for equality. + */ + bool operator== (const ClassName& other) const; + + + /** + * @brief Test two expressions for inequality. + */ + bool operator!= (const ClassName& other) const; + + + /** + * @brief Match this expression against a pattern. + * @param pattern The pattern to match. + * @param[out] matches Dictionary of pattern substitutions. + * + * Return true if @c pattern matches the current expression. + * @c pattern may contain dummy variables of the form `$T`. + * On a successful return, the map @c matches contains the + * variable assignments needed for the match. + */ + bool match (const ClassName& pattern, match_t& matches) const; + + + /** + * @brief Substitute variables into this expression. + * @param The dictionary of variables to substitute. + * + * If this expression contains variables like `$T`, they are replaced + * with the corresponding values from @c matches. If a variable is + * present in the expression but is not in @c matches, @c ExcMissingVariable + * is thrown. + * + * The substitutions are made in-place. + */ + void subst (const match_t& matches); + + + /** + * @brief Return a copy of this expression with variables substituted. + * @param The dictionary of variables to substitute. + * + * If this expression contains variables like `$T`, they are replaced + * with the corresponding values from @c matches. If a variable is + * present in the expression but is not in @c matches, @c ExcMissingVariable + * is thrown. + * + * The substitutions are made in a copy of the expression, which is returned. + */ + ClassName substCopy (const match_t& matches) const; + + + /** + * @brief Apply a set of transformation rules to this object. + * @param rules The set of rules to apply. + * + * Recursively walk this expression, trying to apply the transformation + * rules in @c rules. If any matches are found, this expression + * is modified in-place and the walk is repeated. This function terminates + * when no further matches are found. + * + * Warning: An infinite loop is possible if the replacement for a pattern + * can always be matched by another pattern. + */ + void applyRules (const Rules& rules); + + + /** + * @brief Apply a set of transformation rules a class name. + * param The name of the class to transform. + * @param rules The set of rules to apply. + * + * This is just shorthand for + * + *@code + * ClassName cn (name); + * cn.applyRules (rules); + * return cn.fullName(); + @endcode + */ + static std::string applyRules (const std::string& name, + const Rules& rules); + + +private: + /** + * @brief Parse a string into a @c ClassName. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ + void parse (const std::string& name, std::string::size_type& pos); + + + /** + * @brief Parse a primary part of the class name. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * The primary part of the class name is a string without namespace + * and template delimiters. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ + std::string parsePrimary (const std::string& name, + std::string::size_type& pos); + + + /** + * @brief Parse a namespace qualification. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * When this is called, the namespace part has already been parsed, + * and the next two characters in @c name are `::`. This reads in the + * remainder of the string as a @c ClassName, and then moves it inside + * the namespace given by the current object. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ + void parseNamespace (const std::string& name, std::string::size_type& pos); + + + /** + * @brief Parse the template part of a name. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * When this is called, the qualified name part of the name has already + * been parsed, and the next character in @c name is `::`. This reads in + * template arguments from @c name. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ + void parseTemplateArgs (const std::string& name, std::string::size_type& pos); + + + /** + * @brief Skip past spaces in a string. + * @param name The string containing the name. + * @param pos Position in the string to start skipping. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ + void skipSpaces (const std::string& name, std::string::size_type& pos); + + + /** + * @brief Match this expression against a pattern. + * @param pattern The pattern to match. + * @param[out] matches Dictionary of pattern substitutions. + * + * Return true if @c pattern matches the current expression. + * @c pattern may contain dummy variables of the form `$T`. + * On a successful return, the map @c matches contains the + * variable assignments needed for the match. + */ + bool match1 (const ClassName& pattern, match_t& matches) const; + + + /** + * @brief Apply a set of transformation rules to this object. + * @param rules The set of rules to apply. + * + * Recursively walk this expression, trying to apply the transformation + * rules in @c rules. If any matches are found, this expression + * is modified in-place. + * + * Returns true if any matches were found. + */ + bool applyRules1 (const Rules& rules); + + + /// Is this expression const? + bool m_const; + + /// The containing namespace. + /// This vector is always either 0 or 1 elements long; this is a way of + /// getting something sort of like a pointer but with completely automatic + /// management. + std::vector<ClassName> m_namespace; + + /// The primary name part of this expression. + std::string m_name; + + /// The template arguments for this name. + std::vector<ClassName> m_targs; +}; + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_CLASSNAME_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/FloatPacker.h b/EDM/athena/Control/CxxUtils/CxxUtils/FloatPacker.h new file mode 100644 index 00000000..86d183c0 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/FloatPacker.h @@ -0,0 +1,152 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/FloatPacker.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2009, from earlier code. + * @brief Pack/unpack floating-point data from/to a given number of bits. + */ + + +#ifndef CXXUTILS_FLOATPACKER_H +#define CXXUTILS_FLOATPACKER_H + + +#include <string> +#include <stdint.h> + + + +namespace CxxUtils { + + +/** + * @brief Pack/unpack floating-point data from/to a given number of bits. + * + * The format is specified by the following parameters. + * + * nbits - The total number of bits in the representation. + * scale - Scale factor to apply before storing. + * nmantissa - The number of bits to use for the mantissa and sign bit. + * is_signed - Flag to tell if we should use a sign bit. + * round - Flag to tell if we should round or truncate. + * + * From these we derive: + * + * npack = nmantissa, if is_signed is false. + * = nmantissa-1 if is_signed is true. + * nexp = nbits - nmantissa + * + * The format consists of, in order from high bits to low bits: + * - A sign bit, if is_signed is true. + * - nexp bits of exponent information. + * - npack bits of mantissa. + * + * The number is stored in normalized form, with an exponent bias + * of 2^(nexp-1). But if the (biased) exponent is zero, then the + * mantissa is stored in denormalized form. If nexp==0, this + * gives a fixed-point representation in the range [0,1). + * 0 is represented by all bits 0; if we have a sign bit, we can also + * represent -0 by all bits 0 except for the sign bit. + */ +class FloatPacker +{ +public: + /// Type into which we pack. + typedef uint32_t Packdest; + + + /** + * @brief Constructor. + * @param nbits The number of bits in the packed representation. + * @param nmantissa The number of bits to use for the mantissa + * and sign bit. + * @param scale Divide the input number by this before packing. + * @param is_signed If true, then one mantissa bit is used for a sign. + * @param round If true, numbers will be rounded. + * Otherwise, they will be truncated. + */ + FloatPacker (int nbits, + int nmantissa, + double scale = 1, + bool is_signed = true, + bool round = false); + + + /** + * @brief Check to see if an error occurred. + * @param err[out] If an error occurred, a description of it. + * @return True if an error occurred since the last call to @c errcheck. + */ + bool errcheck (std::string& err) const; + + + /** + * @brief Pack a value. + * @param src Value to pack. + * @return The packed value. + * + * For now, we convert floats to doubles before packing. + */ + Packdest pack (double src) const; + + + /** + * @brief Unpack the value @c VAL. + * @param val The packed data. It should start with the low bit, + * and any extraneous bits should have been masked off. + */ + double unpack (Packdest val) const; + + +private: + /// Number of bits in the mantissa + sign bit. + int m_nmantissa; + + /// Scale factor for stored numbers. + double m_scale; + + /// Inverse of scale. + double m_invscale; + + /// Should we use a sign bit? + bool m_is_signed; + + /// Should we round instead of truncating? + bool m_round; + + /// Number of bits in mantissa (exclusive of any sign bit). + int m_npack; + + /// Mask with that many low bits set. + Packdest m_npack_ones; + + /// Mask containing the sign bit (or 0 if there's no sign bit). + Packdest m_signmask; + + /// Number of exponent bits. + int m_nexp; + + /// Mask with that many low bits set. + Packdest m_nexp_ones; + + /// Minimum exponent value. + int m_min_exp; + + /// Maximum exponent value. + int m_max_exp; + + /// Description of the last error. + mutable std::string m_lasterr; +}; + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_FLOATPACKER_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/MD5.h b/EDM/athena/Control/CxxUtils/CxxUtils/MD5.h new file mode 100644 index 00000000..eaff18fb --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/MD5.h @@ -0,0 +1,152 @@ + +#ifndef CXXUTILS_MD5_H +#define CXXUTILS_MD5_H 1 + +// MD5.CC - source code for the C++/object oriented translation and +// modification of MD5. + +// Translation and modification (c) 1995 by Mordechai T. Abzug + +// This translation/ modification is provided "as is," without express or +// implied warranty of any kind. + +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially +// copied from the disclaimer below). + +/* based on: + + MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ +#include <string> + +// Constants for MD5Transform routine. +// Although we could use C++ style constants, defines are actually better, +// since they let us easily evade scope clashes. +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +class MD5 { + public: + MD5 (unsigned char* buffer, unsigned long len); + MD5 (); + void update (unsigned char *input, unsigned int input_length); + // Finalize MD5 check-sum + void finalize (); + + + void raw_digest (unsigned char *buff); + + std::string hex_digest (); + + private: + // next, the private data: + unsigned int m_state[4]; + unsigned int m_count[2]; // number of *bits*, mod 2^64 + unsigned char m_buffer[64]; // input buffer + unsigned char m_digest[16]; + unsigned char m_finalized; + + // last, the private methods, mostly static: + void init (); // called by all constructors + void transform (unsigned char *buffer); // does the real update work. Note + // that length is implied to be 64. + + static void encode (unsigned char *dest, unsigned int *src, unsigned int length); + static void decode (unsigned int *dest, unsigned char *src, unsigned int length); + + // ROTATE_LEFT rotates x left n bits. + static inline unsigned int rotate_left (unsigned int x, unsigned int n) + { return (x << n) | (x >> (32-n)); } + // F, G, H and I are basic MD5 functions. + static inline unsigned int F(unsigned int x, unsigned int y, unsigned int z) + { return (x & y) | (~x & z); } + static inline unsigned int G(unsigned int x, unsigned int y, unsigned int z) + { return (x & z) | (y & ~z); } + static inline unsigned int H(unsigned int x, unsigned int y, unsigned int z) + { return x ^ y ^ z; } + static inline unsigned int I(unsigned int x, unsigned int y, unsigned int z) + { return y ^ (x | ~z); } + + // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + // Rotation is separate from addition to prevent recomputation. + static inline void FF (unsigned int& a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, unsigned int s, unsigned int ac) + { + a += F(b, c, d) + x + ac; + a = rotate_left(a, s) + b; + } + static inline void GG (unsigned int& a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, unsigned int s, unsigned int ac) + { + a += G(b, c, d) + x + ac; + a = rotate_left(a, s) + b; + } + static inline void HH (unsigned int& a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, unsigned int s, unsigned int ac) + { + a += H(b, c, d) + x + ac; + a = rotate_left(a, s) + b; + } + static inline void II (unsigned int& a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, unsigned int s, unsigned int ac) + { + a += I(b, c, d) + x + ac; + a = rotate_left(a, s) + b; + } +}; + +struct MD5_digest { + unsigned long long val[2]; + + MD5_digest() {}; + MD5_digest( const std::string& msg ) { + MD5 checkSum( (unsigned char*)(msg.c_str()), msg.length()); + checkSum.raw_digest( (unsigned char*) &val ); + } + + bool operator< (const MD5_digest& rhs) const { + if (val[0] == rhs.val[0]) { + return (val[1] < rhs.val[1]); + } else { + return (val[0] < rhs.val[0]); + } + } +}; + +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/PackedArray.h b/EDM/athena/Control/CxxUtils/CxxUtils/PackedArray.h new file mode 100644 index 00000000..0ecbc35f --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/PackedArray.h @@ -0,0 +1,311 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PackedArray.h,v 1.2 2007-06-14 22:38:48 ssnyder Exp $ +/** + * @file CxxUtils/PackedArray.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2007 + * @brief An array of unsigned values of some bit size, packed tightly. + */ + +#ifndef CXXUTILS_PACKEDARRAY_H +#define CXXUTILS_PACKEDARRAY_H + + +#include <vector> +#include <cstddef> + + +namespace CxxUtils { + + +/** + * @brief An array of unsigned values of some bit size, packed tightly. + * + * When creating an instance of this class, specify the bit size of the + * entries. The entries will be packed so that each takes exactly that + * many bits. For example, if the bit size is 10, 16 entries will + * be packed into 5 32-bit words. The bitsize may be changed, but + * only if the container is empty. + * + * Any values assigned to the array that are too large to be represented + * in the specified number of bits will have the high bits silently dropped. + * + * The interface is modeled after @c std::vector, except that there are no + * iterators. They could be added if there is a need for them. + */ +class PackedArray +{ +private: + // Type of the underlying vector holding the data. + typedef std::vector<unsigned int> basetype; + +public: + // Standard STL container typedefs. + typedef size_t size_type; + typedef unsigned int value_type; + typedef basetype::allocator_type allocator_type; + + /** + * @brief proxy class for representing an lvalue to an element + * of @c PackedArray. + */ + class proxy + { + public: + /// Constructor, from a @c PackedArray and index @c n. + proxy (PackedArray& arr, size_type n) : m_arr (arr), m_n (n) {} + + /// Retrieve the element referenced by the proxy. + operator value_type() const { return m_arr.get (m_n); } + + /// Set the element referenced by the proxy to @c v. + proxy& operator= (value_type v) { m_arr.set (m_n, v); return *this; } + + private: + /// Reference to the container referenced by the proxy. + PackedArray& m_arr; + + /// Index of the element referenced by the proxy. + size_type m_n; + }; + + + /** + * @brief Constructor. + * @param bitsize The size, in bits, of each element. + * Must be greater than zero, and not larger than + * the size of an unsigned int. + * @param allocator Allocator for the underlying vector. + */ + PackedArray (int bitsize, + const allocator_type& allocator = allocator_type()); + + /** + * @brief Constructor. + * @param bitsize The size, in bits, of each element. + * Must be greater than zero, and not larger than + * the size of an unsigned int. + * @param n Initial number of entries in the container. + * @param val Value to which the initial entries are to be set. + * @param allocator Allocator for the underlying vector. + */ + PackedArray (int bitsize, + size_type n, + value_type val = 0, + const allocator_type& allocator = allocator_type()); + + /** + * @brief Set the container to multiple copies of the same value. + * @param n Number of entries to which the container is to be set. + * @param u Value to which the entries are to be set. + */ + void assign (size_type n, value_type u); + + /** + * @brief Returns the allocator of the underlying vector. + */ + allocator_type get_allocator() const; + + /** + * @brief Returns the number of elements in the collection. + */ + size_type size() const; + + /** + * @brief Returns the @c size() of the largest possible collection. + */ + size_type max_size() const; + + /** + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + */ + size_type capacity() const; + + /** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * @param c Value to which any new elements are to be set. + */ + void resize (size_type sz, value_type c = 0); + + /** + * @brief Returns @c true if the collection is empty. + */ + bool empty() const; + + /** + * @brief Attempt to preallocate enough memory for a specified number + * of elements. + * @param n Number of elements required. + */ + void reserve (size_type n); + + /** + * @brief Return the entry at index @c n. + * @param n The index of the entry to retrieve. + */ + value_type get(size_type n) const; + + /** + * @brief Set the entry at index @c n. + * @param n The index of the entry to set. + * @param val The new value for the entry at index @c n. + */ + void set(size_type n, value_type val); + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * No bounds checking is done. + * Note that we return a @c value_type rather than a reference. + */ + value_type operator[](size_type n) const; + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference. + */ + proxy operator[](size_type n); + + /** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a @c value_type rather than a reference. + */ + value_type at(size_type n) const; + + /** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference. + */ + proxy at(size_type n); + + /** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c value_type rather than a reference. + */ + value_type front() const; + + /** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c value_type rather than a reference. + */ + value_type back() const; + + /** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference. + */ + proxy front(); + + /** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference. + */ + proxy back(); + + /** + * @brief Add an element to the end of the collection. + * @param x The element to add to the collection. + */ + void push_back (value_type x); + + /** + * @brief Remove the last element from the collection. + */ + void pop_back(); + + /** + * @brief Swap this collection with another. + * @param other The collection with which to swap. + */ + void swap (PackedArray& other); + + /** + * @brief Erase all the elements in the collection. + */ + void clear(); + + /** + * @brief Change the bitsize of the container. + * @brief bitsize The new bitsize. + * + * This method may only be called when the container is empty. + */ + void set_bitsize (int bitsize); + + /** + * @brief Return the bitsize of the container. + */ + int bitsize () const; + + +private: + /// The current bitsize of the container. + int m_bitsize; + + /// The current number of entries in the container. + size_type m_size; + + /// Mask with m_bitsize bits set. + value_type m_mask; + + /// Underlying vector holding the data. + basetype m_vec; + + /// Calculate the number of entries in the base vector needed + /// to hold @n entries with the current bitsize. + size_t nbase (size_type n) const; + + /// Find the index in the base vector where entry @n starts. + size_t tondx (size_type n) const; + + /// Find the bit offset of entry @n within its entry in the base vector. + int tooff (size_type n) const; + + /// Return the entry at base index @c ndx/offset @c off. + value_type doget (size_type ndx, int off) const; + + /// Set the entry at base index @c ndx/offset @c off to @c v. + void doset (size_type ndx, int off, value_type v); + + /// Check that @c n is in range and throw @c out_of_range if not. + void range_check (size_type n) const; +}; + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_PACKEDARRAY_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/PageAccessControl.h b/EDM/athena/Control/CxxUtils/CxxUtils/PageAccessControl.h new file mode 100644 index 00000000..b910a234 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/PageAccessControl.h @@ -0,0 +1,116 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CXXUTILS_PAGEACCESSCONTROL_H +#define CXXUTILS_PAGEACCESSCONTROL_H 1 + +/** + * @file CxxUtils/PageAccessProtect.h + * @author Paolo Calafiura + * @date Jan 2009 + * @brief This class allows to protect a page containing a given address + * and to restore back its access protection to what was in + * /proc/self/maps + * NOTE that protectPage will leak memory when asked to write-protect a page + * + * $Id: PageAccessControl.h,v 1.4 2009-03-04 23:10:42 calaf Exp $ + */ + +#include <vector> +#include <sys/mman.h> /*PROT_NONE*/ + +#include "CxxUtils/procmaps.h" + +class PageAccessControl { +public: + PageAccessControl(size_t reservedSize=65535) : + m_pmaps(), + m_protectedIsSorted(false) + { + //we must reserve enough elements, or we risk vector allocating in a protected page during handle()... + m_protected.reserve(reservedSize); + } + PageAccessControl(procmaps& pmaps, size_t reservedSize=65535) : + m_pmaps(pmaps), + m_protectedIsSorted(false) + { + //we must reserve enough elements, or we risk vector allocating in a protected page during handle()... + m_protected.reserve(reservedSize); + } + + ///protect the page containing addr, record the amount of memory we protected + ///NOTE To avoid SEGV, if PROT_WRITE is requested the remainder of the page + /// containing the object at addr will be leaked with malloc before being + /// write-locked + template <typename T> + bool protectPage(T* addr, int prot) { + return protectPage(addr, sizeof(T), prot); + } + + ///forbid access to the page containing addr, setting its prot to PROT_NONE + template <typename T> + bool forbidPage(const T* addr) { + return forbidPage(addr, sizeof(T)); + } + + ///forbid access to the page containing addr, setting its prot to PROT_NONE + bool forbidPage(const void* addr, size_t objSize) { + return protectPage(addr, objSize, PROT_NONE); + } + + ///FIXME this will not work well for objects spanning across pages + bool forbidPage(const void* addr) { + return protectPage(addr, 4, PROT_NONE); + } + + ///void* version of protectPage. Used to implement all others + bool protectPage(const void* addr, size_t objSize, int prot); + + bool restorePageProt(const void * addr); + void sort(); + + /// @class Entry describes the protection of a memory region (see mprotect(2)) + struct Entry { + Entry(void* a, size_t l, int p, void* pl); + /// address of page for which protection was requested. Used as key + void* addr; + ///lenght of the protected region, from page addr to end of protected obj + size_t lenProt; + int prot; + ///pointer to the heap fragment we leaked before protecting the page + void* leak; + /// # of times this entry protection has been restored. 0 means page was + /// never accessed + int restored; + }; + + ///the list of protected pages + typedef std::vector<Entry> protected_t; + typedef protected_t::const_iterator const_iterator; + const protected_t& protectedPtrs() const { return m_protected; } + const_iterator beginProtectedPtrs() const { return m_protected.begin(); } + const_iterator endProtectedPtrs() const { return m_protected.end(); } + void reset() { m_protected.clear(); } + + ///was the page containing address accessed? + bool accessed(const void* address) const; + +private: + + /// the content of /proc/self/maps + procmaps m_pmaps; + + // can not preallocate map + // typedef std::map<void*, size_t, std::less<void*>, + // boost::pool_allocator<std::map<void*, size_t>::value_type > > protected_t; + protected_t m_protected; + bool m_protectedIsSorted; +}; +inline +bool operator <(const PageAccessControl::Entry& lhs, const PageAccessControl::Entry& rhs) { + return lhs.addr < rhs.addr; +} +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/PtrAccessSEGVHandler.h b/EDM/athena/Control/CxxUtils/CxxUtils/PtrAccessSEGVHandler.h new file mode 100644 index 00000000..9703385a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/PtrAccessSEGVHandler.h @@ -0,0 +1,54 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CXXUTILS_PTRACCESSSEGVHANDLER_H +#define CXXUTILS_PTRACCESSSEGVHANDLER_H 1 + +/** + * @file CxxUtils/PtrAccessSEGVHandler.h + * @author Paolo Calafiura + * @date Jan 2009 + * @brief This class provides a handle function that logs the + * addresses that had an access violation. It can be installed as sigaction handler using its + * C facade in cPtrAccessSIGVHandler.h. The purpose (at least the original one) is to protect + * all pages containing heap objects managed by StoreGateSvc, install the handler, and then + * see which objects have actually been accessed. + * + * $Id: PtrAccessSEGVHandler.h,v 1.2 2009-02-04 02:02:19 calaf Exp $ + */ + +#include <signal.h> /* siginfo_t */ +#include <vector> + +class PageAccessControl; + +class PtrAccessSEGVHandler { +public: + ///the list of accessed pointers + typedef std::vector<void*> accessed_t; + typedef accessed_t::const_iterator const_iterator; + const accessed_t& accessedPtrs() const { return m_accessed; } + const_iterator beginAccessedPtrs() const { return m_accessed.begin(); } + const_iterator endAccessedPtrs() const { return m_accessed.end(); } + void reset() { m_accessed.clear(); } + + PtrAccessSEGVHandler(PageAccessControl& pac, size_t reservedSize=65535) : + m_pac(pac) + { + //we must reserve enough elements, or we risk vector allocating in a protected page during handle()... + m_accessed.reserve(reservedSize); + } + + ///the actual signal handler + void handle(int signal_number,siginfo_t *sigi,void *unused); + +private: + /// used to restore protection of the page which segfaulted + PageAccessControl& m_pac; + /// the addresses accessed since last reset + accessed_t m_accessed; +}; +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/SealCommon.h b/EDM/athena/Control/CxxUtils/CxxUtils/SealCommon.h new file mode 100644 index 00000000..845a78cd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/SealCommon.h @@ -0,0 +1,216 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/SealCommon.h + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> + * @date Oct, 2008 + * @brief Collecting a few shared bits and pieces from SEAL headers. + */ + +#ifndef CXXUTILS_SEAL_COMMON_H +#define CXXUTILS_SEAL_COMMON_H + +// start copy from "SealBase/sysapi/IOTypes.h" +/** Invalid channel descriptor constant. */ +#ifdef _WIN32 +#define IOFD_INVALID (void *)-1 +#else +#define IOFD_INVALID -1 +#endif + +/** Type the system uses for channel descriptors. */ +#ifdef _WIN32 +typedef void *IOFD; +#else +typedef int IOFD; +#endif +// end copy from IOTypes + + +// platform specific defines from SealPlatform/config.h +#ifdef __linux + +/* C++ features --------------------------------------------------------- */ + +/* Define if you have standard C++ C headers like <cstdlib>. */ +#define HAVE_CXX_STDC_HEADERS 1 + +/* Signals -------------------------------------------------------------- */ + +/* Define if you have POSIX signal stuff. */ +#define HAVE_POSIX_SIGNALS 1 + +/* Define if you have POSIX real-time signal stuff. */ +#define HAVE_POSIX_RT_SIGNALS 1 + +/* Define if you have the strsignal function. */ +#define HAVE_STRSIGNAL 1 +#define HAVE_STRSIGNAL_DECL 1 + +/* Define if you have raise. */ +#define HAVE_RAISE 1 +#define HAVE_RAISE_DECL 1 + +/* Define if you have sys_siglist in <signal.h>. */ +#define HAVE_SYS_SIGLIST 1 + +/* Resource information ------------------------------------------------- */ + +/* Define if you have program_invocation_name. */ +#define HAVE_PROGRAM_INVOCATION_NAME 1 + +/* Stack tracing -------------------------------------------------------- */ + +/* Define if you have pstack (usually in /usr/proc/bin) to the full + path of that program. */ +#define PROG_PSTACK "/usr/bin/pstack" + +/* Define if you have c++filt to the full path of that program. */ +#define PROG_CXXFILT "/usr/bin/c++filt" + +/* Define if you have backtrace and backtrace_symbols_fd (glibc 2.1). */ +#define HAVE_BACKTRACE_SYMBOLS_FD 1 + +/* Dynamic linker ------------------------------------------------------- */ + +/* Define if `dlopen' exists. */ +#define HAVE_DLOPEN 1 +#define HAVE_DLOPEN_DECL 1 + +/* Define if you have the <link.h> header file. */ +#define HAVE_LINK_H 1 + +/* Define if `dladdr' exists. */ +#define HAVE_DLADDR 1 +#define HAVE_DLADDR_DECL 1 + +/* Define if `_r_debug' exists. */ +// note: leave undefined on SLC4 b/c of binutils problems +#define HAVE_R_DEBUG 1 + +/* Define if you have the <elf.h> header file. */ +#define HAVE_ELF_H 1 + +#endif // __linux + + +// platform specific defines from SealPlatform/config.h +#ifdef __APPLE__ + +/* C++ features --------------------------------------------------------- */ +#define HAVE_R_DEBUG 1 + +/* Define if you have standard C++ C headers like <cstdlib>. */ +#define HAVE_CXX_STDC_HEADERS 1 + +/* Signals -------------------------------------------------------------- */ + +/* Define if you have POSIX signal stuff. */ +#define HAVE_POSIX_SIGNALS 1 + +/* Define if you have the strsignal function. */ +#define HAVE_STRSIGNAL 1 +#define HAVE_STRSIGNAL_DECL 1 + +/* Define if you have raise. */ +#define HAVE_RAISE 1 +#define HAVE_RAISE_DECL 1 + +/* Define if you have sys_siglist in <signal.h>. */ +#define HAVE_SYS_SIGLIST 1 + +/* Stack tracing -------------------------------------------------------- */ + +/* Define if you have c++filt to the full path of that program. */ +#define PROG_CXXFILT "/usr/bin/c++filt" + +/* Define if you have backtrace and backtrace_symbols_fd (glibc 2.1). */ +#define HAVE_BACKTRACE_SYMBOLS_FD 1 + +/* Dynamic linker ------------------------------------------------------- */ + +/* Define if `dlopen' exists. */ +#define HAVE_DLOPEN 1 +#define HAVE_DLOPEN_DECL 1 + +/* Define if `dladdr' exists. */ +#define HAVE_DLADDR 1 +#define HAVE_DLADDR_DECL 1 + +/* Define if you have the <mach-o/dyld.h> header file. */ +#define HAVE_MACH_O_DYLD_H 1 + +#endif // __APPLE__ + + +#if HAVE_LOAD +# define PATH "LIBPATH" +#elif HAVE_DLOPEN +# if defined __APPLE__ && defined __MACH__ +# define PATH "DYLD_LIBRARY_PATH" +# else +# define PATH "LD_LIBRARY_PATH" +# endif +#elif HAVE_SHL_LOAD +# define PATH "SHLIB_PATH" +#elif defined _WIN32 +# define PATH "PATH" +#else +# define PATH 0 +#endif +// end copy from SealBase/sysapi/SharedLibrary.h + + +// start copy from SealPlatform/system.h +#if HAVE_CXX_STDC_HEADERS +# define STDC std +#else +# define STDC +#endif +// end copy from SealPlatform/system.h + + +// start copy from SealBase/sysapi/ElfAbi.h +# ifndef _WIN32 +# if HAVE_LOADER_H +# include <loader.h> +# endif +# if HAVE_LINK_H +# include <link.h> +# include <limits.h> +# include <sys/stat.h> +# include <unistd.h> +# endif +# if HAVE_SGIDEFS_H // irix n32, 64 +# include <sgidefs.h> +# include <objlist.h> +# include <obj_list.h> +# include <obj.h> +# endif +# if HAVE_ELF_H +# include <elf.h> +# endif +# endif // ! _WIN32 + +//<<<<<< PUBLIC DEFINES >>>>>> + +#if /* irix */ (defined ABI64 || defined _ABI64 || \ + (defined _MIPS_SIM && _MIPS_SIM == _MIPS_SIM_ABI64)) \ + /* solaris */ || (defined sparcv9 || defined _sparcv9 \ + || defined __sparcv9 || defined __sparcv9__) \ + /* tru64 */ || (defined arch64 || defined _arch64 || \ + defined __arch64 || defined __arch64__) +# define ELF_ABI 64 +#else +# define ELF_ABI 32 +#endif +#ifndef ElfW +# define ElfW(type) ElfW1(Elf,ELF_ABI,type) +# define ElfW1(e,w,t) ElfW2(Elf,w,_##t) +# define ElfW2(e,w,t) e ## w ## t +#endif +// end copy from SealBase/sysapi/ElfAbi.h + +#endif // CXXUTILS_SEAL_COMMON_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/SealDebug.h b/EDM/athena/Control/CxxUtils/CxxUtils/SealDebug.h new file mode 100644 index 00000000..5da0b704 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/SealDebug.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/SealDebug.h + * @author Lassi Tuura (original author) + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS) + * @date Oct, 2008 + * @brief This are the SEAL debug aids, adapted to build in Atlas, + * after the drop of that project. + * + * Search for `wlav' to find changes from the SEAL version. I + * also dropped all ASSERT macro's in favor of assert. Removed + * logstream references. + * + * sss: Add stacktraceLine. + */ + +#ifndef CXXUTILS_SEAL_DEBUG_H // wlav SEAL_BASE_DEBUG_H +#define CXXUTILS_SEAL_DEBUG_H // wlav SEAL_BASE_DEBUG_H + +//<<<<<< INCLUDES >>>>>> + +#include "CxxUtils/SealCommon.h" // sss -- needed for IOFD +//# include "SealBase/Macros.h" wlav +//# include "SealBase/sysapi/IOTypes.h" wlav +# include <cstddef> + +// wlav copied from SealBase/sysapi/DebugAids.h +// Windows doesn't have this, so fake a suitable substitute +# ifdef _WIN32 +# define STDERR_HANDLE GetStdHandle (STD_ERROR_HANDLE) +# else +# define STDERR_HANDLE STDERR_FILENO +# endif + +// Define a suitable wrapper to write to system file descriptors. +// This is needed because on Windows we are using HANDLEs, not the +// compiler's crippled posixy interface. +# ifdef _WIN32 +# define MYWRITE(fd,data,n) do { DWORD written; WriteFile(fd,data,n,\ + &written,0); } while (0) +# else +# define MYWRITE(fd,data,n) write(fd,data,n) +# endif + + +//namespace seal { wlav +namespace Athena { // wlav +//<<<<<< PUBLIC DEFINES >>>>>> +//<<<<<< PUBLIC CONSTANTS >>>>>> +//<<<<<< PUBLIC TYPES >>>>>> +//<<<<<< PUBLIC VARIABLES >>>>>> +//<<<<<< CLASS DECLARATIONS >>>>>> + +/** Utilities for debugging support. */ +class DebugAids +{ +public: + // Miscellaneous functions + static IOFD stacktraceFd (IOFD fd = IOFD_INVALID); + static void stacktrace (IOFD fd = IOFD_INVALID); + static void coredump (int sig, ...); + // sss + static void stacktraceLine (IOFD fd, + unsigned long addr); + static void setStackTraceAddr2Line (const char* path); + +private: + static IOFD s_stackTraceFd; +}; + +//<<<<<< PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> + +//} // namespace seal wlav +} // namespace Athena wlav +#endif // CXXUTILS_SEAL_DEBUG_H wlav SEAL_BASE_DEBUG_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/SealSharedLib.h b/EDM/athena/Control/CxxUtils/CxxUtils/SealSharedLib.h new file mode 100644 index 00000000..0e1295bb --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/SealSharedLib.h @@ -0,0 +1,216 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/SealSharedLib.h + * @author Lassi Tuura (original author) + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS) + * @date Oct, 2008 + * + * Search for `wlav' to find changes from the SEAL version. I + * also dropped all ASSERT macro's in favor of assert. + */ + +#ifndef CXXUTILS_SEAL_SHAREDLIB_H // wlav SEAL_BASE_SHARED_LIBRARY_H +#define CXXUTILS_SEAL_SHAREDLIB_H // wlav SEAL_BASE_SHARED_LIBRARY_H + +//<<<<<< INCLUDES >>>>>> + +//# include "SealBase/SharedLibraryError.h" wlav +//# include "SealBase/Callback.h" wlav +# include <string> +# include <list> +# include <exception> // wlav + +//namespace seal { wlav +namespace Athena { // wlav + +//<<<<<< PUBLIC DEFINES >>>>>> +//<<<<<< PUBLIC CONSTANTS >>>>>> +//<<<<<< PUBLIC TYPES >>>>>> +//<<<<<< PUBLIC VARIABLES >>>>>> +//<<<<<< PUBLIC FUNCTIONS >>>>>> +//<<<<<< CLASS DECLARATIONS >>>>>> + + +// wlav from SealBase/Callback.h +template <class T1> +class Callback1Rep +{ +public: + Callback1Rep (void) : m_refs (0) { } + virtual ~Callback1Rep (void) { } + + virtual void call (T1) = 0; + virtual bool equal (const Callback1Rep *x) const = 0; + + void ref (void) { ++m_refs; } + void unref (void) { if (--m_refs == 0) delete this; } + +private: + int m_refs; +}; + +template <class T1> +class Callback1 +{ +public: + Callback1 (Callback1Rep<T1> *implementation = 0); + Callback1 (const Callback1 &x); + ~Callback1 (void); + Callback1 & operator= (const Callback1 &x); + + bool operator== (const Callback1 &x) const; + /**/ operator bool (void) const; + void operator() (T1) const; + +private: + Callback1Rep<T1> *m_rep; +}; + +template <class T1, class T2> +class CallbackImpF11 : public Callback1Rep<T1> +{ + typedef CallbackImpF11 self; +public: + CallbackImpF11 (void (*function) (T1, T2), + const T2 &fill_2) + : m_function (function), + m_fill_2 (fill_2) + { } + + virtual void call (T1 a) + { (*m_function) (a, m_fill_2); } + + virtual bool equal (const Callback1Rep<T1> *other) const + { const self *x = dynamic_cast<const self *> (other); + return x && x->m_function == m_function && x->m_fill_2 == m_fill_2; } + +private: + void (*m_function) (T1, T2); + T2 m_fill_2; +}; + +template <class T1> +inline +Callback1<T1>::Callback1 (Callback1Rep<T1> *implementation /* = 0 */) + : m_rep (implementation) +{ if (m_rep) m_rep->ref (); } + +template <class T1> +inline +Callback1<T1>::Callback1 (const Callback1<T1> &x) + : m_rep (x.m_rep) +{ if (m_rep) m_rep->ref (); } + +template <class T1> +inline +Callback1<T1>::~Callback1 (void) +{ if (m_rep) m_rep->unref (); } + +template <class T1> +inline Callback1<T1> & +Callback1<T1>::operator= (const Callback1<T1> &x) +{ + if (m_rep != x.m_rep) + { + if (m_rep) m_rep->unref (); + m_rep = x.m_rep; + if (m_rep) m_rep->ref (); + } + return *this; +} + +template <class T1> +inline bool +Callback1<T1>::operator== (const Callback1<T1> &x) const +{ return m_rep == x.m_rep || (m_rep && x.m_rep && m_rep->equal (x.m_rep)); } + +template <class T1> +inline +Callback1<T1>::operator bool (void) const +{ return m_rep ? true : false; } // FIXME: for Sun CC 4.2 (no bool) + +template <class T1> +inline void +Callback1<T1>::operator() (T1 a) const +{ m_rep->call (a); } + +template <class T1, class T2> +inline Callback1Rep<T1> * +CreateCallback (void (*function) (T1, T2), + const T2 &fill_2) +{ return new CallbackImpF11<T1,T2> (function, fill_2); } + + +// wlav modified from SealBase/SharedLibraryError.h +/** Error in a shared library operation. */ +class SharedLibraryError : public std::exception +{ +public: + SharedLibraryError( const char *context, const std::string &cause ); + virtual ~SharedLibraryError() throw() {} + + virtual const char* what() const throw(); + +private: + std::string m_context; + std::string m_cause; +}; + + +/** Shared library services. */ +class SharedLibrary +{ +public: + typedef void * Data; + typedef void (*Function) (void); + + /** Information about a currently loaded shared library. */ + struct LibraryInfo + { + unsigned long m_text_start; //< Start of text segment + unsigned long m_text_end; //< End of text segment + unsigned long m_data_start; //< Start of data segment + unsigned long m_data_end; //< End of data segment + unsigned long m_bss_start; //< Start of common + unsigned long m_bss_end; //< End of common + const char *m_filename; //< Filename + }; + + typedef Callback1<const LibraryInfo &> InfoHandler; + + static std::string path (void); + static void path (const std::string &path); + static std::string libname (const std::string &name); + static std::string symname (const std::string &name); + + static SharedLibrary * self (void); + static SharedLibrary * load (const std::string &name); + static void loaded (const InfoHandler &handler); + + void release (void); + void abandon (void); + + Data data (const std::string &name, bool mangle = true) const; + Function function (const std::string &name, bool mangle = true) const; + +protected: + SharedLibrary (void *handle); + ~SharedLibrary (void); + +private: + void *m_handle; + + // undefined semantics + SharedLibrary (const SharedLibrary &); + SharedLibrary &operator= (const SharedLibrary &); +}; + +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> + +//} // namespace seal wlav +} // namespace Athena wlav +#endif // CXXUTILS_SEAL_SHAREDLIB_H wlav SEAL_BASE_SHARED_LIBRARY_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/SealSignal.h b/EDM/athena/Control/CxxUtils/CxxUtils/SealSignal.h new file mode 100644 index 00000000..533a1279 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/SealSignal.h @@ -0,0 +1,319 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/SealSignal.h + * @author Lassi Tuura (original author) + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS) + * @date Oct, 2008 + * @brief This is the signal handler from SEAL, adapted to build in Atlas, + * after the drop of that project. + * + * Search for `wlav' or `sss' to find changes from the SEAL version. I + * also dropped all ASSERT macro's in favor of assert. + */ + +#ifndef CXXUTILS_SEAL_SIGNAL_H // wlav SEAL_BASE_SIGNAL_H +#define CXXUTILS_SEAL_SIGNAL_H // wlav SEAL_BASE_SIGNAL_H + +//<<<<<< INCLUDES >>>>>> + +//# include "SealBase/sysapi/IOTypes.h" wlav + +// These should be hidden, but we can't do that for now: the clients +// must be able to operate on sigset_t and pid_t. Note that we do not +// want to have <csignal> -- we need all the extra POSIX stuff. +# include <signal.h> +# include <sys/types.h> +# include <climits> + +//<<<<<< PUBLIC DEFINES >>>>>> + +// Hacks for fields we might not have in siginfo_t. Just print zero. +#ifdef si_utime // sss +# define HAVE_SIGINFO_SI_UTIME 1 // sss +#endif // sss +#ifdef si_int // sss +# define HAVE_SIGINFO_SI_INT 1 // sss +#endif // sss +# if !HAVE_SIGINFO_SI_UTIME // darwin +# define si_utime si_signo ? 0 : 0 +# define si_stime si_signo ? 0 : 0 +# endif +# if !HAVE_SIGINFO_SI_INT +# if HAVE_SIGINFO_SI_VALUE // darwin +# define si_int si_value.sigval_int +# define si_ptr si_value.sigval_ptr +# else // (none known) +# define si_int si_signo ? 0 : 0 +# define si_ptr si_signo ? (void *) 0 : (void *) 0 +# endif +# endif + +//<<<<<< PUBLIC CONSTANTS >>>>>> +//<<<<<< PUBLIC TYPES >>>>>> +//<<<<<< PUBLIC VARIABLES >>>>>> +//<<<<<< PUBLIC FUNCTIONS >>>>>> +//<<<<<< CLASS DECLARATIONS >>>>>> + +# if !HAVE_POSIX_SIGNALS +// Forward declare POSIX signal handling stuff for platforms that +// don't have them. This allows them to be mentioned in the Signal +// interface and minimally used in the clients. Special kludge for +// Windows. +# ifdef _WIN32 +typedef struct _EXCEPTION_RECORD siginfo_t; +#define SIGHUP 1 /* Hangup (POSIX). */ +#define SIGQUIT 3 /* Quit (POSIX). */ +#define SIGTRAP 5 /* Trace trap (POSIX). */ +#define SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ +#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ +#define SIGPIPE 13 /* Broken pipe (POSIX). */ +#define SIGALRM 14 /* Alarm clock (POSIX). */ +#define SIGCHLD 17 /* Child status has changed (POSIX). */ +#define SIGCONT 18 /* Continue (POSIX). */ +#define SIGSTOP 19 /* Stop, unblockable (POSIX). */ +#define SIGTSTP 20 /* Keyboard stop (POSIX). */ +#define SIGTTIN 21 /* Background read from tty (POSIX). */ +#define SIGTTOU 22 /* Background write to tty (POSIX). */ +# else +struct siginfo_t {}; +# endif + +typedef int sigset_t; + +# define sigemptyset(x) (0) +# define sigfillset(x) (0) +# define sigaddset(x,y) (0) +# define sigdelset(x,y) (0) +# define sigismember(x,y) (0) +# endif + +//namespace seal { wlav +namespace Athena { // wlav + +// wlav copied from SealBase/BitTraits.h +/** Describe the bit features of an integral type @c T. */ +template <class T> +struct BitTraits +{ + /// Number of bits in @c T. + enum { Bits = sizeof (T) * CHAR_BIT }; + + /// Number of 8-bit bytes in @c T. + enum { Bytes = Bits / 8 + ((Bits % 8) > 0) }; + + /// Number of base-10 digits in @c T (without leading sign). + enum { Digits = (Bits * 30103) / 100000 + 1 }; + // 30103 =~ M_LN2 / M_LN10 * 100000 + + /// Number of base-16 digits in @c T (without leading sign). + enum { HexDigits = Bits / 4 + ((Bits % 4) > 0) }; +}; + + +/** Utilities for handling signals and fatal errors. + + FIXME: POSIX single-threaded vs. multi-threaded signals? + - all threads should block all the signals + - one thread should do sigwait. + + The fatal error handling is largely inspired by code in DDD, the + Data Display Debugger, and by the examples in GNU libc manual. */ +class Signal +{ +public: + /** Option that instructs #fatal() to call #coredump() on SIGUSR1. + This is merely a request to drop a @c core; no attempt is made + to guarantee success. Failure may result for example for lack + of permissions, for lack of disk space, or due to low resource + limits. Please note that @c core files can only be created on + unixen. Note also that dropping a core is a security risk and + should never be enabled in setuid or setgid programs or for + production applications. */ + static const int USR1_DUMP_CORE = 1; + + /** Option to make SIGHUP, SIGTERM and SIGQUIT fatal instead of + just #quit() signals. */ + static const int FATAL_ON_QUIT = 2; + + /** Option to make SIGINT fatal. It will still just quit, not + crash. */ + static const int FATAL_ON_INT = 4; + + /** Option to make #fatal() dump a core file before crashing. */ + static const int FATAL_DUMP_CORE = 8; + + /** Option to make #fataldump() (invoked by #fatal()) to dump the + signal name (as reported by #name()). */ + static const int FATAL_DUMP_SIG = 16; + + /** Option to make #fataldump() (invoked by #fatal()) to dump + stack backtrace for the offending code location. */ + static const int FATAL_DUMP_STACK = 32; + + /** Option to make #fataldump() (invoked by #fatal()) to dump the + list of currently loaded shared libraries. */ + static const int FATAL_DUMP_LIBS = 64; + + /** Option to make #fataldump() (invoked by #fatal()) to dump the + machine context (registers etc.) from the fault position. */ + static const int FATAL_DUMP_CONTEXT = 128; + + /** Option to make #fatal() exit via #quit(). This will cause all + the application clean-up hook to run. */ + static const int FATAL_AUTO_EXIT = 256; + + /** Default options to #handleFatal(). */ + static const int FATAL_DEFAULT = (USR1_DUMP_CORE + | FATAL_ON_INT + | FATAL_DUMP_CORE + | FATAL_DUMP_SIG + | FATAL_DUMP_STACK + | FATAL_DUMP_LIBS + | FATAL_DUMP_CONTEXT + | FATAL_AUTO_EXIT); + + /** Application clean-up hook invoked before #quit() exits from + program termination signals (SIGHUP, SIGTERM or SIGQUIT). + + The handler should return @c true if the signal handler should + proceed to exit the application. Note that certain options to + #handlFatal() cause this hook to be invoked for fatal signals. + If such behaviour is enabled, be sure to check the #crashed() + status before deciding to let the application to continue. + + The quit hook should take care of resetting terminal modes, + killing child processes, removing lock files, and so forth. */ + typedef bool (*QuitHook) (int sig, siginfo_t *info, void *x); + + /** Application hook to run in fatal(). The hook should return @c + true if the signal handler should proceed to die. @a sig is + the signal number, or its negative if core was dumped and, as + far as can determined, successfully produced. + + The fatal hooks should, if possible, perform clean-ups similar + to #QuitHook. The application may achieve this by actually + using the quit by setting #FATAL_AUTO_EXIT for #handleFatal(), + or it could reuse an internal function in both handlers. */ + typedef bool (*FatalHook) (int sig, siginfo_t *info, void *x); + + /** Application hook to jump back to the main program from a fatal + signal, for example using #siglongjmp. It must never return. + @a sig is the signal number, or its negative if core was + dumped and, as far as can determined, successfully produced. */ + typedef void (*FatalReturn) (int sig, siginfo_t *info, void *x); + + /** Signal handler type. This is defined explicitly and does not + necessarily match the system's concept of signal handler type. + If necessary, suitable trampolines are used internally to make + sure the arguments make sense. + + @param sig The signal number. + @param info Pointer to signal info. This pointer will + be null on platforms that do not support + POSIX signals. + @param extra Extra argument, e.g. the fault address. + This pointer will be null on platforms + that do not support POSIX signals. */ + typedef void (*HandlerType) (int sig, siginfo_t *info, void *extra); + + + // Generic signal operations + // - Signal names + static const char * name (int sig); + + // - Signal handlers and masks + static HandlerType handler (int sig, sigset_t *mask = 0); + static HandlerType handle (int sig, HandlerType handler, + const sigset_t *blockMask = 0); + static void revert (int sig); + static void ignore (int sig); + + static void block (int sig, bool sense); + static void block (const sigset_t *mask, bool sense); + static void mask (const sigset_t *mask, sigset_t *old = 0); + + // - Sending and receiving signals + static int raise (int sig); + static int kill (pid_t process, int sig); + static int queue (int sig, int value = 0); + static int queue (int sig, void *value); + static int queue (pid_t process, int sig, int value = 0); + static int queue (pid_t process, int sig, void *value); + + static bool pending (int sig); + static void pending (sigset_t *mask); + static void suspend (const sigset_t *mask); + static bool wait (int sig, + siginfo_t *info = 0, + long msecs = -1); + static int wait (const sigset_t *mask, + siginfo_t *info = 0, + long msecs = -1); + + // Assisted handling of program termination signals + static void handleQuit (QuitHook hook = 0); + static QuitHook handleQuitHook (void); + + static void quit (int sig, siginfo_t *info, void *x); + + // Assisted handling of fatal signals + static void handleFatal (const char *applicationName = 0, + IOFD fd = IOFD_INVALID, + FatalHook hook = 0, + FatalReturn mainreturn = 0, + unsigned options = FATAL_DEFAULT); + static IOFD handleFatalFd (void); + static FatalHook handleFatalHook (void); + static FatalReturn handleFatalReturn (void); + static unsigned handleFatalOptions (void); + + static void fatal (int sig, siginfo_t *info, void *x); + static bool fatalDump (int sig, siginfo_t *info, void *x); + static int fatalLevel (void); + static bool crashed (void); + + static void dumpInfo (IOFD fd, char *buf, int sig, + const siginfo_t *info); + static void dumpMemory (IOFD fd, char *buf, + const void *data, size_t n); + static unsigned long dumpContext (IOFD fd, char *buf, + const void *context); + + static const char * describe (int sig, int code); + +private: + static void trampoline (int sig); + + static bool s_crashed; + static int s_inFatal; + static unsigned long s_lastSP; + static const char *s_applicationName; + static IOFD s_fatalFd; + static FatalHook s_fatalHook; + static FatalReturn s_fatalReturn; + static unsigned s_fatalOptions; + static QuitHook s_quitHook; +#if !HAVE_POSIX_SIGNALS + static HandlerType s_trampolines [NSIG]; +#endif +}; + +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> + +//} // namespace seal wlav +} // namespace Athena wlav + + +extern "C" { + /// Install fatal handler with default options. + /// This is meant to be easy to call from pyton via ctypes. + void CxxUtils_installFatalHandler(); +} + + +#endif // CXXUTILS_SEAL_SIGNAL_H wlav SEAL_BASE_SIGNAL_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/StrFormat.h b/EDM/athena/Control/CxxUtils/CxxUtils/StrFormat.h new file mode 100644 index 00000000..20b36be7 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/StrFormat.h @@ -0,0 +1,34 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StrFormat.h 599890 2014-06-02 13:52:58Z ssnyder $ +/** + * @file CxxUtils/StrFormat.h + * @author Sebastien Binet <binet@cern.ch> + * @date Jun 2010 + * @brief Provide helper functions to create formatted strings + */ + + +#ifndef CXXUTILS_STRFORMAT_H +#define CXXUTILS_STRFORMAT_H 1 + +// stl includes +#include <string> + +namespace CxxUtils { + + /** @brief return a `std::string` according to a format `fmt` and varargs + */ + std::string strformat(const char* fmt, ...) +#ifdef __GNUC__ + __attribute__ ((format (printf, 1, 2))) +#endif + ; + +} //> namespace CxxUtils + +#endif // not CXXUTILS_STRFORMAT_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/StringUtils.h b/EDM/athena/Control/CxxUtils/CxxUtils/StringUtils.h new file mode 100644 index 00000000..b3e15598 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/StringUtils.h @@ -0,0 +1,141 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StringUtils.cxx,v 1.0 2014-05-25 16:54 cburgard Exp $ +/** + * @file StringUtils.cxx + * @author carsten burgard <cburgarc@cern.ch> + * @date May, 2014 + * @brief namespace for misc string utility + * + * This file provides a set of StringUtils that go beyond the + * capabilities of typical string utility functions (such as provided + * by boost). This includes fail-proof trimming of strings with + * multibyte characters and control sequences and parsing helpers that + * understand and respect parenthesis. + * + * Also implemented are functions that allow easy conversion between + * HTML-type strings, LaTeX-type strings, unicode strings and plain + * ascii strings. The aim of these methods is converting symbols and + * mathematical expressions in strings, including subscript and + * superscript and special mathematical or greek symbols - they are + * not intended as a replacement for conversion of entire documents + * and do not respect text or background colors, sectioning commands, + * annotations, document meta-information, non-textual elements, + * custom macro definitions, javascript, or any other features beyond + * basic text markup. + */ + +#ifndef CXXUTILS_STRINGUTILS_H +#define CXXUTILS_STRINGUTILS_H + +#include <string> +#include <ostream> +#include <boost/regex.hpp> + +namespace CxxUtils { + + namespace StringUtils { + + typedef std::string::size_type size_type; + + const std::string beginNormal = "\033[0m"; + const std::string beginBoldWhite = "\033[1m"; + const std::string beginBoldPink = "\033[1;35m"; + const std::string beginBoldBlue = "\033[1;34m"; + const std::string beginBoldYellow = "\033[1;33m"; + const std::string beginBoldGreen = "\033[1;32m"; + const std::string beginBoldRed = "\033[1;31m"; + const std::string beginPink = "\033[35m"; + const std::string beginBlue = "\033[34m"; + const std::string beginYellow = "\033[33m"; + const std::string beginGreen = "\033[32m"; + const std::string beginRed = "\033[31m"; + + + const std::string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const std::string whitespace = " \t\n\r"; + + const boost::regex generic_latex_regex("\\\\([abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+)[ ]*"); + const boost::regex generic_xml_regex("<\\s*([abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+)([^>])*>"); + const boost::regex generic_html_entity_regex("&[abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+;"); + + enum SPECIALSCRIPT { + NORMALSCRIPT = 0, + SUPERSCRIPT = 1, + SUBSCRIPT = 2 + }; + + enum FORMAT { + ASCII = 0, + UNICODE = 1, + LATEX = 2, + HTML = 3 + }; + + size_t getStringWidth(const std::string& str); + void writeFixedWidth(std::ostream& os, const std::string& input, size_t width, const std::string& align); + + size_type findParenthesisMatch (const std::string& str, + size_type nextpos, + const std::string& paropen, + const std::string& parclose); + size_type rfindParenthesisMatch(const std::string& str, + size_type nextpos, + const std::string& paropen, + const std::string& parclose); + + size_type findFree (const std::string& haystack, + const std::string& needle, + const std::string& paropen, + const std::string& parclose, + size_type startpos = 0); + size_type rfindFree(const std::string& haystack, + const std::string& needle, + const std::string& paropen, + const std::string& parclose, + size_type startpos); + + size_type findFreeOf (const std::string& haystack, + const std::string& needles, + const std::string& paropen, + const std::string& parclose, + size_type startpos = 0); + size_type rfindFreeOf(const std::string& haystack, + const std::string& needles, + const std::string& paropen, + const std::string& parclose, + size_type startpos); + + std::string replaceSymbols(const std::string& str, StringUtils::FORMAT inputFormat, StringUtils::FORMAT outputFormat); + size_type findBeginSpecialScript(const std::string& str, + StringUtils::SPECIALSCRIPT scripttype, + size_type pos = 0); + size_type findEndSpecialScript(const std::string& str, + StringUtils::SPECIALSCRIPT scripttype, + size_type pos = 0); + + StringUtils::FORMAT guessFormat(const std::string& input); + std::string convertText(const std::string& input, StringUtils::FORMAT inputFormat, StringUtils::FORMAT outputFormat); + std::string convertText(const std::string& input, StringUtils::FORMAT outputFormat); + + std::string stripUnprintableCharacters(const std::string& str, bool allowNonAscii = true); + std::string replaceSpecialScript(const std::string& str, StringUtils::SPECIALSCRIPT inputType, StringUtils::SPECIALSCRIPT outputType); + + inline bool isOnlyWhitespace(const std::string&str){ + return (str.find_first_not_of(StringUtils::whitespace) == std::string::npos); + } + + inline std::string trim(const std::string& str){ + size_t start = str.find_first_not_of(StringUtils::whitespace); + size_t end = str.find_last_not_of(StringUtils::whitespace); + return str.substr(start,end-start+1); + } + } + +} + +#endif //CXXUTILS_STRINGUTILS_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/algorithms.h b/EDM/athena/Control/CxxUtils/CxxUtils/algorithms.h new file mode 100644 index 00000000..0e8a37df --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/algorithms.h @@ -0,0 +1,55 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// algorithms.h +// Header file for CxxUtils::copy_if - copied from gcc4.4 +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef CXXUTILS_ALGORITHMS_H +#define CXXUTILS_ALGORITHMS_H + +/** + * @brief Copy the elements of a sequence for which a predicate is true. + * @ingroup mutating_algorithms + * @param first An input iterator. + * @param last An input iterator. + * @param result An output iterator. + * @param pred A predicate. + * @return An iterator designating the end of the resulting sequence. + * + * Copies each element in the range @p [first,last) for which + * @p pred returns true to the range beginning at @p result. + * + * copy_if() is stable, so the relative order of elements that are + * copied is unchanged. + * + * <i>Example</i>: + * @code + * CxxUtils::copy_if( in.begin(), in.end(), + * std::back_inserter(out), filter ); + * @endcode + * where in and out are STL-like containers and filter is a predicate + */ + +namespace CxxUtils { + +template<typename InputIterator, typename OutputIterator, + typename Predicate> +OutputIterator +copy_if(InputIterator first, InputIterator last, + OutputIterator result, Predicate pred) +{ + for (; first != last; ++first) + if (pred(*first)) { + *result = *first; + ++result; + } + return result; +} + +}//> end CxxUtils namespace + +#endif //> CXXUTILS_ALGORITHMS_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/bitscan.h b/EDM/athena/Control/CxxUtils/CxxUtils/bitscan.h new file mode 100644 index 00000000..b4d9e7c9 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/bitscan.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/bitscan.h + * @author Frank Winklmeier + * @brief Bit scanning functions + * + * Fast helper functions to count number of leading/traling zeros. + * Supports 32 and 64 bit input types. + * + * Inspired by boost/multiprecision/detail/bitscan.hpp + * https://en.wikipedia.org/wiki/Find_first_set + */ + +#ifndef CXXUTILS_BITSCAN_H +#define CXXUTILS_BITSCAN_H + +#include <stdint.h> + +namespace CxxUtils { + + /** + * Count number of trailing zeros + * + * @param x Number to check + * @return Number of trailing zeros, 0 if x==0 + */ + inline unsigned count_trailing_zeros(unsigned x) { +#if defined (__GNUC__) || defined(__clang__) + return (x!=0 ? __builtin_ctz(x) : 0); +#else + return detail::ctz_portable(x); +#endif + } + + inline unsigned count_trailing_zeros(unsigned long x) { +#if defined (__GNUC__) || defined(__clang__) + return (x!=0 ? __builtin_ctzl(x) : 0); +#else + return detail::ctz_portable(x); +#endif + } + + /** + * Count number of leading zeros + * + * @param x Number to check + * @return Number of leading zeros, input size in bits if x==0 + */ + inline unsigned count_leading_zeros(uint32_t x) { +#if defined (__GNUC__) || defined(__clang__) + return (x!=0 ? __builtin_clz(x) : 32); +#else + return detail::clz_portable(x); +#endif + } + + inline unsigned count_leading_zeros(uint64_t x) { +#if defined (__GNUC__) || defined(__clang__) + return (x!=0 ? __builtin_clzl(x) : 64); +#else + return detail::clz_portable(x); +#endif + } + + /** + * Portable implementations + * + * These could be replaced by faster algorithms if needed + */ + namespace detail { + + template <typename T> + inline unsigned ctz_portable(T x) { + unsigned n(0); + if (x!=0) { + for (;(x & 0x1) == 0; ++n, x >>= 1); + } + return n; + } + + template <typename T> + inline unsigned clz_portable(T x) { + if (x==0) return sizeof(T)*8; + unsigned n; + T msb = static_cast<T>(1) << (sizeof(T)*8-1); + for (n = 0; (x & msb) == 0; ++n, x <<= 1); + return n; + } + } + + +} +#endif // CXXUTILS_BITSCAN_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/cPtrAccessSEGVHandler.h b/EDM/athena/Control/CxxUtils/CxxUtils/cPtrAccessSEGVHandler.h new file mode 100644 index 00000000..6482a6f8 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/cPtrAccessSEGVHandler.h @@ -0,0 +1,30 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CXXUTILS_CPTRACCESSSEGVHANDLER_H +#define CXXUTILS_CPTRACCESSSEGVHANDLER_H 1 + +/** + * @file CxxUtils/cPtrAccessSEGVHandler.h + * @author Paolo Calafiura + * @date Jan 2009 + * @brief a C wrapper providing access to PtrAccessSEGVHandler::handle the way sigaction wants it + * Example: + * PtrAccessSEGVHandler h(p); + * setPtrAccessSEGVHandler(h); + * struct sigaction sa; + * sa.sa_sigaction= cPtrAccessSEGVHandler; + * sigaction(SIGSEGV,&sa, NULL); + * + * $Id: cPtrAccessSEGVHandler.h,v 1.1 2009-01-30 00:50:51 calaf Exp $ + */ + +#include <signal.h> /*siginfo_t*/ +class PtrAccessSEGVHandler; + +void setPtrAccessSEGVHandler(PtrAccessSEGVHandler* h); +void cPtrAccessSEGVHandler(int signal, siginfo_t* si, void* old); +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/clock.h b/EDM/athena/Control/CxxUtils/CxxUtils/clock.h new file mode 100644 index 00000000..c33c5414 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/clock.h @@ -0,0 +1,29 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/clock.h + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Jan 2010, from earlier code. + * @brief Provide simplified clock_gettime() function for MacOSX. + */ + + +#ifndef CXXUTILS_CLOCK_H +#define CXXUTILS_CLOCK_H + +#ifdef __APPLE__ +#include <time.h> +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 + +long clock_gettime (unsigned int which_clock, struct timespec *tp); +#endif + +#endif // not CXXUTILS_CLOCK_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/copy_bounded.h b/EDM/athena/Control/CxxUtils/CxxUtils/copy_bounded.h new file mode 100644 index 00000000..3698c940 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/copy_bounded.h @@ -0,0 +1,116 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/copy_bounded.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2013 + * @brief Copy a range with bounds restriction. + */ + + +#ifndef CXXUTILS_COPY_BOUNDED_H +#define CXXUTILS_COPY_BOUNDED_H + + +#include <iterator> +#include <algorithm> +#include "boost/range/iterator.hpp" +#include "boost/range/begin.hpp" +#include "boost/range/end.hpp" + + +namespace CxxUtils { + + +/** + * @brief Copy a range with bounds restriction; generic version. + */ +template <class InputIterator, class OutputIterator, + class InputTag, class OutputTag> +inline +OutputIterator +copy_bounded1 (InputIterator begi, InputIterator endi, + OutputIterator bego, OutputIterator endo, + const InputTag&, + const OutputTag&) +{ + while (begi != endi && bego != endo) { + *bego = *begi; + ++begi; + ++bego; + } + return bego; +} + + +/** + * @brief Copy a range with bounds restriction; random_access_iterator version. + */ +template <class InputIterator, class OutputIterator> +inline +OutputIterator +copy_bounded1 (InputIterator begi, InputIterator endi, + OutputIterator bego, OutputIterator endo, + const std::random_access_iterator_tag&, + const std::random_access_iterator_tag&) +{ + size_t n = std::min (endi-begi, endo-bego); + return std::copy (begi, begi+n, bego); +} + + +/** + * @brief Copy a range with bounds restriction. + * @param begi Start of input range. + * @param endi End of input range. + * @param bego Start of output range. + * @param endo End of output range. + * + * Like std::copy(begi, endi, bego), except that it will not copy + * more than std::distance(bego, endo) elements. + * + * Copies exactly n = std::min (std::distance(begi,endi), + * std::distance(bego,endo)) elements. + * Returns bego + n. + */ +template <class InputIterator, class OutputIterator> +inline +OutputIterator +copy_bounded (InputIterator begi, InputIterator endi, + OutputIterator bego, OutputIterator endo) +{ + return copy_bounded1 + (begi, endi, bego, endo, + typename std::iterator_traits<InputIterator>::iterator_category(), + typename std::iterator_traits<OutputIterator>::iterator_category()); +} + + +/** + * @brief Copy a range with bounds restriction. + * @param input Input range + * @param output Output range + * + * copy_bounded written in terms of iterator ranges. + */ +template <class InputRange, class OutputRange> +inline +typename boost::range_iterator<OutputRange>::type +copy_bounded (const InputRange& input, OutputRange& output) +{ + return copy_bounded + (boost::begin(input), boost::end(input), + boost::begin(output), boost::end(output)); +} + + +} // namespace CxxUtils + + + +#endif // not CXXUTILS_COPY_BOUNDED_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/enable_if.h b/EDM/athena/Control/CxxUtils/CxxUtils/enable_if.h new file mode 100644 index 00000000..ef3acba8 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/enable_if.h @@ -0,0 +1,51 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/enable_if.h + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2014 + * @brief C++98 definition of enable_if. + * + * This header defines @c CxxUtils::enable_if that can be used in both + * c++98 and c++11; the standard library version is used if it's available. + * + * For the c++98 case, we can't just import @c enable_if from boost, + * since @c std::enable_if actually corresponds to @c boost::enable_if_c. + * The definition of @c enable_if is simple enough that we just copy it here. + */ + + +#ifndef CXXUTILS_ENABLE_IF_H +#define CXXUTILS_ENABLE_IF_H + + +#if __cplusplus > 201100 +# include <type_traits> +namespace Cxxutils { using std::enable_if; } +#else + +namespace CxxUtils { + + // Primary template. + /// Define a member typedef @c type only if a boolean constant is true. + template<bool, typename _Tp = void> + struct enable_if + { }; + + // Partial specialization for true. + template<typename _Tp> + struct enable_if<true, _Tp> + { typedef _Tp type; }; + + +} // namespace CxxUtils + +#endif + + +#endif // not CXXUTILS_ENABLE_IF_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/excepts.h b/EDM/athena/Control/CxxUtils/CxxUtils/excepts.h new file mode 100644 index 00000000..b86c7c75 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/excepts.h @@ -0,0 +1,26 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/excepts.h + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Mar 2010 + * @brief Declarations of feenableexcept()/fedisableexcept() functions for MacOSX. + */ + + +#ifndef CXXUTILS_EXCEPTS_H +#define CXXUTILS_EXCEPTS_H + +#ifdef __APPLE__ +int +feenableexcept (unsigned int excepts); +int +fedisableexcept (unsigned int excepts); +#endif + +#endif // not CXXUTILS_EXCEPTS_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/exctrace.h b/EDM/athena/Control/CxxUtils/CxxUtils/exctrace.h new file mode 100644 index 00000000..6f848872 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/exctrace.h @@ -0,0 +1,52 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/exctrace.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009 + * @brief Generate stack trace backs from a caught exception. + * + * When an exception is caught, we'd sometimes want to dump out the + * stack at the point where the exception was thrown. + * + * If you run with libexctrace_collector.so added to your LD_PRELOAD, + * then we'll remember the backtrace from the last exception thrown. + * You can then call CxxUtils::exctrace to print it out. + * This will behave sensibly if the collector module hasn't been + * preloaded (just print the exception, with no backtrace). + */ + + +#ifndef CXXUTILS_EXCTRACE_H +#define CXXUTILS_EXCTRACE_H + + +#include "CxxUtils/SealCommon.h" +#include "CxxUtils/SealDebug.h" +#include <exception> + + +namespace CxxUtils { + + +/** + * @brief Print out information for the last exception. + * + * Prints the supplied exception, plus the backtrace from + * the last exception, if available. + * + * @param e The exception to print. + * @param fd The file descriptor to which to write. + */ +void exctrace (const std::exception& e, IOFD fd = IOFD_INVALID); + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_EXCTRACE_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/final.h b/EDM/athena/Control/CxxUtils/CxxUtils/final.h new file mode 100644 index 00000000..91f487fc --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/final.h @@ -0,0 +1,39 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/final.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2012 + * @brief Macro to mark a method as final. + * + * Use like: + * + * virtual void foo() ATH_FINAL; + */ + + +#ifndef CXXUTILS_FINAL_H +#define CXXUTILS_FINAL_H + + +#ifndef HAVE_ATH_FINAL +# if __cplusplus > 201100 +# define HAVE_ATH_FINAL 1 +# else +# define HAVE_ATH_FINAL 0 +# endif +#endif + +#if HAVE_ATH_FINAL +# define ATH_FINAL final +#else +# define ATH_FINAL +#endif + + +#endif // not CXXUTILS_FINAL_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/fpcompare.h b/EDM/athena/Control/CxxUtils/CxxUtils/fpcompare.h new file mode 100644 index 00000000..c026c4c3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/fpcompare.h @@ -0,0 +1,372 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: fpcompare.h,v 1.4 2009-04-07 04:26:22 ssnyder Exp $ + +/** + * @file CxxUtils/fpcompare.h + * @author scott snyder + * @date Sep 2008 + * @brief Workaround x86 precision issues for FP inequality comparisons. + * + * The functions contained here can be used to work around one of the + * effects of the brain-damage of the x87 FPU. + * + * Brief summary: If you're writing a comparison function for sort, + * where the comparison depends on computed floating-point values, eg: + * + *@code + * bool compare (IParticle* a, IParticle* b) + * { return a->pt() > b->pt(); } + @endcode + * + * then you should replace the comparison with a call to one of the + * functions in this file: + * + *@code + * bool compare (IParticle* a, IParticle* b) + * { return CxxUtils::fpcompare::greater (a->pt(), b->pt()); } + @endcode + * + * Longer explanation: + * + * An expression like this (where pt() returns a double): + * + *@code + * a->pt() > b->pt() + @endcode + * + * is compiled (on x86) into a sequence like this: + * + * call a->pt() + * save result from FPU to a double stack temporary + * call b->pt() + * load the temporary back into the FPU + * do the comparison + * + * If pt() returns a result with the extra precision bits used + * (so that the value changes when rounded to a double), then + * it is possible for this comparison to return true for the + * case where a==b. This violates the assumptions that std::sort + * makes of the comparison function, and can cause a crash + * (possibly even silently wrong results!). + * + * As a fix, we force both parameters into something that has been declared + * @c volatile. That forces them to be spilled to memory, ensuring + * that they are both correctly rounded for the declared data type. + * The comparison is then done on these rounded values. + * + * We condition this on the parameter @c __FLT_EVAL_METHOD__ being 2. + * This is defined in the C standard; a value of 2 means that all + * FP calculations are done as long double. For other cases, + * we leave out the @c volatile qualifiers; this should result + * in the functions being inlined completely away. + * + * In addition to the free functions in the @c CxxUtils::fpcompare + * namespace. we define corresponding functionals in the + * @c CxxUtils::fpcompare_fn namespace. + * + * It's also worth pointing out that exactly the same issue arises + * if one uses a floating-point value as the key for a STL associative + * container. In that case, this comparison instability may cause the + * container to become corrupted. While it's probably best to avoid + * using floats for associative container keys in the first place, + * if you do have to do that, you can work around this problem by + * using one of the above functionals as the container's comparison type. + */ + + +#include <cmath> +#include <functional> + + +#ifndef CXXUTILS_FPCOMPARE_H +#define CXXUTILS_FPCOMPARE_H + + +// Decide whether we need to use volatile or not. +#if defined(__FLT_EVAL_METHOD__) && \ + (__FLT_EVAL_METHOD__ == 2 || __FLT_EVAL_METHOD__ < 0) + // __FLT_EVAL_METHOD__ < 0 means unspecified. + // Be pessimistic in that case. +# define CXXUTILS_FPCOMPARE_VOLATILE volatile +#elif defined(__i386__) && !defined(__SSE2__) + // On x86, gcc -msse -mfpmath=sse is observed to _not_ generate + // sse fp instructions, but does set __FLT_EVAL_METHOD__ to 0. + // -msse2 -mfpmath=sse does seem to work as expected. + // Special-case this for now; should follow up with a gcc bug report + // if this still happens in current releases. +# define CXXUTILS_FPCOMPARE_VOLATILE volatile +#else +# define CXXUTILS_FPCOMPARE_VOLATILE +#endif + + +namespace CxxUtils { +namespace fpcompare { + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a == @a b + */ +inline +bool equal (double a, double b) +{ + CXXUTILS_FPCOMPARE_VOLATILE double va = a; + CXXUTILS_FPCOMPARE_VOLATILE double vb = b; + return va == vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a == @a b + */ +inline +bool equal (float a, float b) +{ + CXXUTILS_FPCOMPARE_VOLATILE float va = a; + CXXUTILS_FPCOMPARE_VOLATILE float vb = b; + return va == vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a > @a b + */ +inline +bool greater (double a, double b) +{ + CXXUTILS_FPCOMPARE_VOLATILE double va = a; + CXXUTILS_FPCOMPARE_VOLATILE double vb = b; + return va > vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a > @a b + */ +inline +bool greater (float a, float b) +{ + CXXUTILS_FPCOMPARE_VOLATILE float va = a; + CXXUTILS_FPCOMPARE_VOLATILE float vb = b; + return va > vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a < @a b + */ +inline +bool less (double a, double b) +{ + CXXUTILS_FPCOMPARE_VOLATILE double va = a; + CXXUTILS_FPCOMPARE_VOLATILE double vb = b; + return va < vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a < @a b + */ +inline +bool less (float a, float b) +{ + CXXUTILS_FPCOMPARE_VOLATILE float va = a; + CXXUTILS_FPCOMPARE_VOLATILE float vb = b; + return va < vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a >= @a b + */ +inline +bool greater_equal (double a, double b) +{ + CXXUTILS_FPCOMPARE_VOLATILE double va = a; + CXXUTILS_FPCOMPARE_VOLATILE double vb = b; + return va >= vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a >= @a b + */ +inline +bool greater_equal (float a, float b) +{ + CXXUTILS_FPCOMPARE_VOLATILE float va = a; + CXXUTILS_FPCOMPARE_VOLATILE float vb = b; + return va >= vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a <= @a b + */ +inline +bool less_equal (double a, double b) +{ + CXXUTILS_FPCOMPARE_VOLATILE double va = a; + CXXUTILS_FPCOMPARE_VOLATILE double vb = b; + return va <= vb; +} + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + * @return @a a <= @a b + */ +inline +bool less_equal (float a, float b) +{ + CXXUTILS_FPCOMPARE_VOLATILE float va = a; + CXXUTILS_FPCOMPARE_VOLATILE float vb = b; + return va <= vb; +} + + +} // namespace fpcompare + + +namespace fpcompare_fn { + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct equal + : public std::binary_function<double, double, bool> +{ + bool + operator()(double a, double b) const + { return fpcompare::equal (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct equalf + : public std::binary_function<float, float, bool> +{ + bool + operator()(float a, float b) const + { return fpcompare::equal (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct greater + : public std::binary_function<double, double, bool> +{ + bool + operator()(double a, double b) const + { return fpcompare::greater (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct greaterf + : public std::binary_function<float, float, bool> +{ + bool + operator()(float a, float b) const + { return fpcompare::greater (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct less + : public std::binary_function<double, double, bool> +{ + bool + operator()(double a, double b) const + { return fpcompare::less (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct lessf + : public std::binary_function<float, float, bool> +{ + bool + operator()(float a, float b) const + { return fpcompare::less (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct greater_equal + : public std::binary_function<double, double, bool> +{ + bool + operator()(double a, double b) const + { return fpcompare::greater_equal (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct greater_equalf + : public std::binary_function<float, float, bool> +{ + bool + operator()(float a, float b) const + { return fpcompare::greater_equal (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct less_equal + : public std::binary_function<double, double, bool> +{ + bool + operator()(double a, double b) const + { return fpcompare::less_equal (a, b); } +}; + + +/** + * @brief Compare two FP numbers, working around x87 precision issues. + */ +struct less_equalf + : public std::binary_function<float, float, bool> +{ + bool + operator()(float a, float b) const + { return fpcompare::less_equal (a, b); } +}; + + +} // namespace fpcompare_fn +} // namespace CxxUtils + + +#endif // not CXXUTILS_FPCOMPARE_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/hashtable.h b/EDM/athena/Control/CxxUtils/CxxUtils/hashtable.h new file mode 100644 index 00000000..d374dee9 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/hashtable.h @@ -0,0 +1,2136 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +// $Id: hashtable.h,v 1.4 2008-12-11 18:57:44 ssnyder Exp $ +/** + * @file CxxUtils/hashtable.h + * @author scott snyder <snyder@bnl.gov>, copied from gcc4. + * @date Apr, 2007 + * @brief This is the TR1 hashtable implementation from gcc4, + * adapted to build in Atlas. Once the TR1 library is available + * on all our platforms, we can switch to using the system-supplied + * version instead. + * + * Search for `sss' to find changes from the gcc version. + */ + +// Internal header for TR1 unordered_set and unordered_map -*- C++ -*- +// Copyright (C) 2005, 2006 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +/* @file (sss --- hide from doxygen) + * This is a TR1 C++ Library header. + */ + +// This header file defines std::tr1::hashtable, which is used to +// implement std::tr1::unordered_set, std::tr1::unordered_map, +// std::tr1::unordered_multiset, and std::tr1::unordered_multimap. +// hashtable has many template parameters, partly to accommodate +// the differences between those four classes and partly to +// accommodate policy choices that go beyond what TR1 calls for. + +// ??? Arguably this should be Internal::hashtable, not std::tr1::hashtable. + +// Class template hashtable attempts to encapsulate all reasonable +// variation among hash tables that use chaining. It does not handle +// open addressing. + +// References: +// M. Austern, "A Proposal to Add Hash Tables to the Standard +// Library (revision 4)," WG21 Document N1456=03-0039, 2003. +// D. E. Knuth, The Art of Computer Programming, v. 3, Sorting and Searching. +// A. Tavori and V. Dreizin, "Generic Associative Containers", 2004. +// ??? Full citation? + +#ifndef CXXUTILS_HASHTABLE_H // sss GNU_LIBSTDCXX_TR1_HASHTABLE_ +#define CXXUTILS_HASHTABLE_H // sss GNU_LIBSTDCXX_TR1_HASHTABLE_ + +#include <algorithm> +#include <utility> // For std::pair +#include <iterator> +#include <cstddef> +#include <cstdlib> +#include <cmath> +#include <limits> +#include <string> +#include "boost/type_traits/remove_const.hpp" // sss +//#include <bits/functexcept.h> sss +//#include <tr1/type_traits> // For true_type and false_type sss + +//===================================================================== +// sss from TR1 type_traits +namespace CxxUtils_Internal { + template<typename _Tp, _Tp __v> + struct integral_constant + { + static const _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; + }; + typedef integral_constant<bool, true> true_type; + typedef integral_constant<bool, false> false_type; +} +// sss end from TR1 type_traits +//===================================================================== +//===================================================================== +// sss from TR1 functional +namespace SG { + // Definition of default hash function std::tr1::hash<>. The types for + // which std::tr1::hash<T> is defined is in clause 6.3.3. of the PDTR. + template<typename T> + struct hash; + +#define tr1_hashtable_define_trivial_hash(T) \ + template<> \ + struct hash<T> \ + : public std::unary_function<T, std::size_t> \ + { \ + std::size_t \ + operator()(T val) const \ + { return static_cast<std::size_t>(val); } \ + } + + tr1_hashtable_define_trivial_hash(bool); + tr1_hashtable_define_trivial_hash(char); + tr1_hashtable_define_trivial_hash(signed char); + tr1_hashtable_define_trivial_hash(unsigned char); + tr1_hashtable_define_trivial_hash(wchar_t); + tr1_hashtable_define_trivial_hash(short); + tr1_hashtable_define_trivial_hash(int); + tr1_hashtable_define_trivial_hash(long); + tr1_hashtable_define_trivial_hash(unsigned short); + tr1_hashtable_define_trivial_hash(unsigned int); + tr1_hashtable_define_trivial_hash(unsigned long); + +#undef tr1_hashtable_define_trivial_hash + + template<typename T> + struct hash<T*> + : public std::unary_function<T*, std::size_t> + { + std::size_t + operator()(T* p) const + { return reinterpret_cast<std::size_t>(p); } + }; + + // Fowler / Noll / Vo (FNV) Hash (type FNV-1a) + // (used by the next specializations of std::tr1::hash<>) + + // Dummy generic implementation (for sizeof(size_t) != 4, 8). + template<std::size_t = sizeof(std::size_t)> + struct Fnv_hash + { + static std::size_t + hash(const char* first, std::size_t length) + { + std::size_t result = 0; + for (; length > 0; --length) + result = (result * 131) + *first++; + return result; + } + }; + + template<> + struct Fnv_hash<4> + { + static std::size_t + hash(const char* first, std::size_t length) + { + std::size_t result = static_cast<std::size_t>(2166136261UL); + for (; length > 0; --length) + { + result ^= (std::size_t)*first++; + result *= 16777619UL; + } + return result; + } + }; + + template<> + struct Fnv_hash<8> + { + static std::size_t + hash(const char* first, std::size_t length) + { + std::size_t result = static_cast<std::size_t>(14695981039346656037ULL); + for (; length > 0; --length) + { + result ^= (std::size_t)*first++; + result *= static_cast<std::size_t>(1099511628211ULL); // sss + } + return result; + } + }; + + // XXX String and floating point hashes probably shouldn't be inline + // member functions, since are nontrivial. Once we have the framework + // for TR1 .cc files, these should go in one. + template<> + struct hash<std::string> + : public std::unary_function<std::string, std::size_t> + { + std::size_t + operator()(const std::string& s) const + { return Fnv_hash<>::hash(s.data(), s.length()); } + }; + +#ifdef _GLIBCXX_USE_WCHAR_T + template<> + struct hash<std::wstring> + : public std::unary_function<std::wstring, std::size_t> + { + std::size_t + operator()(const std::wstring& s) const + { + return Fnv_hash<>::hash(reinterpret_cast<const char*>(s.data()), + s.length() * sizeof(wchar_t)); + } + }; +#endif + + template<> + struct hash<float> + : public std::unary_function<float, std::size_t> + { + std::size_t + operator()(float fval) const + { + std::size_t result = 0; + + // 0 and -0 both hash to zero. + if (fval != 0.0f) + result = Fnv_hash<>::hash(reinterpret_cast<const char*>(&fval), + sizeof(fval)); + return result; + } + }; + + template<> + struct hash<double> + : public std::unary_function<double, std::size_t> + { + std::size_t + operator()(double dval) const + { + std::size_t result = 0; + + // 0 and -0 both hash to zero. + if (dval != 0.0) + result = Fnv_hash<>::hash(reinterpret_cast<const char*>(&dval), + sizeof(dval)); + return result; + } + }; + + // For long double, careful with random padding bits (e.g., on x86, + // 10 bytes -> 12 bytes) and resort to frexp. + template<> + struct hash<long double> + : public std::unary_function<long double, std::size_t> + { + std::size_t + operator()(long double ldval) const + { + std::size_t result = 0; + + int exponent; + ldval = std::frexp(ldval, &exponent); + ldval = ldval < 0.0l ? -(ldval + 0.5l) : ldval; + + const long double mult = std::numeric_limits<std::size_t>::max() + 1.0l; + ldval *= mult; + + // Try to use all the bits of the mantissa (really necessary only + // on 32-bit targets, at least for 80-bit floating point formats). + const std::size_t hibits = (std::size_t)ldval; + ldval = (ldval - (long double)hibits) * mult; + + const std::size_t coeff = + (std::numeric_limits<std::size_t>::max() + / std::numeric_limits<long double>::max_exponent); + + result = hibits + (std::size_t)ldval + coeff * exponent; + + return result; + } + }; +} +// sss end from TR1 functional +//===================================================================== + +//---------------------------------------------------------------------- +// General utilities + +namespace CxxUtils_Internal // sss Internal +{ + template<bool Flag, typename IfTrue, typename IfFalse> + struct IF; + + template<typename IfTrue, typename IfFalse> + struct IF<true, IfTrue, IfFalse> + { typedef IfTrue type; }; + + template <typename IfTrue, typename IfFalse> + struct IF<false, IfTrue, IfFalse> + { typedef IfFalse type; }; + + // Helper function: return distance(first, last) for forward + // iterators, or 0 for input iterators. + template<class Iterator> + inline typename std::iterator_traits<Iterator>::difference_type + distance_fw(Iterator /*first*/, Iterator /*last*/, std::input_iterator_tag) + { return 0; } + + template<class Iterator> + inline typename std::iterator_traits<Iterator>::difference_type + distance_fw(Iterator first, Iterator last, std::forward_iterator_tag) + { return std::distance(first, last); } + + template<class Iterator> + inline typename std::iterator_traits<Iterator>::difference_type + distance_fw(Iterator first, Iterator last) + { + typedef typename std::iterator_traits<Iterator>::iterator_category tag; + return distance_fw(first, last, tag()); + } + +} // namespace CxxUtils_Internal sss + +//---------------------------------------------------------------------- +// Auxiliary types used for all instantiations of hashtable: nodes +// and iterators. + +// Nodes, used to wrap elements stored in the hash table. A policy +// template parameter of class template hashtable controls whether +// nodes also store a hash code. In some cases (e.g. strings) this may +// be a performance win. + +namespace CxxUtils_Internal // sss Internal +{ + template<typename Value, bool cache_hash_code> + struct hash_node; + + template<typename Value> + struct hash_node<Value, true> + { + Value m_v; + std::size_t hash_code; + hash_node* m_next; + }; + + template<typename Value> + struct hash_node<Value, false> + { + Value m_v; + hash_node* m_next; + }; + + // Local iterators, used to iterate within a bucket but not between + // buckets. + + template<typename Value, bool cache> + struct node_iterator_base + { + node_iterator_base(hash_node<Value, cache>* p) + : m_cur(p) { } + + void + incr() + { m_cur = m_cur->m_next; } + + hash_node<Value, cache>* m_cur; + }; + + template<typename Value, bool cache> + inline bool + operator==(const node_iterator_base<Value, cache>& x, + const node_iterator_base<Value, cache>& y) + { return x.m_cur == y.m_cur; } + + template<typename Value, bool cache> + inline bool + operator!=(const node_iterator_base<Value, cache>& x, + const node_iterator_base<Value, cache>& y) + { return x.m_cur != y.m_cur; } + + template<typename Value, bool constant_iterators, bool cache> + struct node_iterator + : public node_iterator_base<Value, cache> + { + typedef Value value_type; + typedef typename IF<constant_iterators, const Value*, Value*>::type + pointer; + typedef typename IF<constant_iterators, const Value&, Value&>::type + reference; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit + node_iterator(hash_node<Value, cache>* p = 0) + : node_iterator_base<Value, cache>(p) { } + + reference + operator*() const + { return this->m_cur->m_v; } + + pointer + operator->() const + { return &this->m_cur->m_v; } + + node_iterator& + operator++() + { + this->incr(); + return *this; + } + + node_iterator + operator++(int) + { + node_iterator tmp(*this); + this->incr(); + return tmp; + } + }; + + template<typename Value, bool constant_iterators, bool cache> + struct node_const_iterator + : public node_iterator_base<Value, cache> + { + typedef Value value_type; + typedef const Value* pointer; + typedef const Value& reference; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit + node_const_iterator(hash_node<Value, cache>* p = 0) + : node_iterator_base<Value, cache>(p) { } + + node_const_iterator(const node_iterator<Value, constant_iterators, + cache>& x) + : node_iterator_base<Value, cache>(x.m_cur) { } + + reference + operator*() const + { return this->m_cur->m_v; } + + pointer + operator->() const + { return &this->m_cur->m_v; } + + node_const_iterator& + operator++() + { + this->incr(); + return *this; + } + + node_const_iterator + operator++(int) + { + node_const_iterator tmp(*this); + this->incr(); + return tmp; + } + }; + + template<typename Value, bool cache> + struct hashtable_iterator_base + { + hashtable_iterator_base(hash_node<Value, cache>* node, + hash_node<Value, cache>** bucket) + : m_cur_node(node), m_cur_bucket(bucket) + { } + + void + incr() + { + m_cur_node = m_cur_node->m_next; + if (!m_cur_node) + m_incr_bucket(); + } + + void + m_incr_bucket(); + + template <class T> + void erase_node (T& t) { t.erase_node (m_cur_node, m_cur_bucket); } // sss + + hash_node<Value, cache>* m_cur_node; + + protected: // sss + hash_node<Value, cache>** m_cur_bucket; + }; + + // Global iterators, used for arbitrary iteration within a hash + // table. Larger and more expensive than local iterators. + template<typename Value, bool cache> + void + hashtable_iterator_base<Value, cache>:: + m_incr_bucket() + { + ++m_cur_bucket; + + // This loop requires the bucket array to have a non-null sentinel. + while (!*m_cur_bucket) + ++m_cur_bucket; + m_cur_node = *m_cur_bucket; + } + + template<typename Value, bool cache> + inline bool + operator==(const hashtable_iterator_base<Value, cache>& x, + const hashtable_iterator_base<Value, cache>& y) + { return x.m_cur_node == y.m_cur_node; } + + template<typename Value, bool cache> + inline bool + operator!=(const hashtable_iterator_base<Value, cache>& x, + const hashtable_iterator_base<Value, cache>& y) + { return x.m_cur_node != y.m_cur_node; } + + template<typename Value, bool constant_iterators, bool cache> + struct hashtable_iterator + : public hashtable_iterator_base<Value, cache> + { + typedef Value value_type; + typedef typename IF<constant_iterators, const Value*, Value*>::type + pointer; + typedef typename IF<constant_iterators, const Value&, Value&>::type + reference; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + // sss -- added default ctor. + // Needed to fulfill ForwardIterator requirements. + hashtable_iterator() + : hashtable_iterator_base<Value, cache>(0, 0) { } + + hashtable_iterator(hash_node<Value, cache>* p, + hash_node<Value, cache>** b) + : hashtable_iterator_base<Value, cache>(p, b) { } + + explicit + hashtable_iterator(hash_node<Value, cache>** b) + : hashtable_iterator_base<Value, cache>(*b, b) { } + + reference + operator*() const + { return this->m_cur_node->m_v; } + + pointer + operator->() const + { return &this->m_cur_node->m_v; } + + hashtable_iterator& + operator++() + { + this->incr(); + return *this; + } + + hashtable_iterator + operator++(int) + { + hashtable_iterator tmp(*this); + this->incr(); + return tmp; + } + }; + + template<typename Value, bool constant_iterators, bool cache> + struct hashtable_const_iterator + : public hashtable_iterator_base<Value, cache> + { + typedef Value value_type; + typedef const Value* pointer; + typedef const Value& reference; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + // sss -- added default ctor. + // Needed to fulfill ForwardIterator requirements. + hashtable_const_iterator() + : hashtable_iterator_base<Value, cache>(0, 0) { } + + hashtable_const_iterator(hash_node<Value, cache>* p, + hash_node<Value, cache>** b) + : hashtable_iterator_base<Value, cache>(p, b) { } + + explicit + hashtable_const_iterator(hash_node<Value, cache>** b) + : hashtable_iterator_base<Value, cache>(*b, b) { } + + hashtable_const_iterator(const hashtable_iterator<Value, + constant_iterators, cache>& x) + : hashtable_iterator_base<Value, cache>(x/*x.m_cur_node, x.m_cur_bucket*/) { } // sss + + reference + operator*() const + { return this->m_cur_node->m_v; } + + pointer + operator->() const + { return &this->m_cur_node->m_v; } + + hashtable_const_iterator& + operator++() + { + this->incr(); + return *this; + } + + hashtable_const_iterator + operator++(int) + { + hashtable_const_iterator tmp(*this); + this->incr(); + return tmp; + } + }; +} // namespace CxxUtils_Internal sss + +// ---------------------------------------------------------------------- +// Many of class template hashtable's template parameters are policy +// classes. These are defaults for the policies. + +namespace CxxUtils_Internal // sss Internal +{ + // The two key extraction policies used by the *set and *map variants. + template<typename T> + struct identity + { + T + operator()(const T& t) const + { return t; } + }; + + template<typename Pair> + struct extract1st + { + // sss remove const to prevent warnings with gcc 4.3 + typename + boost::remove_const<typename Pair::first_type>::type + operator()(const Pair& p) const + { return p.first; } + }; + + // Default range hashing function: use division to fold a large number + // into the range [0, N). + struct mod_range_hashing + { + typedef std::size_t first_argument_type; + typedef std::size_t second_argument_type; + typedef std::size_t result_type; + + result_type + operator() (first_argument_type r, second_argument_type N) const + { return r % N; } + }; + + // Default ranged hash function H. In principle it should be a + // function object composed from objects of type H1 and H2 such that + // h(k, N) = h2(h1(k), N), but that would mean making extra copies of + // h1 and h2. So instead we'll just use a tag to tell class template + // hashtable to do that composition. + struct default_ranged_hash { }; + + // Default value for rehash policy. Bucket size is (usually) the + // smallest prime that keeps the load factor small enough. + struct prime_rehash_policy + { + prime_rehash_policy(float z = 1.0); + + float + max_load_factor() const; + + // Return a bucket size no smaller than n. + std::size_t + next_bkt(std::size_t n) const; + + // Return a bucket count appropriate for n elements + std::size_t + bkt_for_elements(std::size_t n) const; + + // n_bkt is current bucket count, n_elt is current element count, + // and n_ins is number of elements to be inserted. Do we need to + // increase bucket count? If so, return make_pair(true, n), where n + // is the new bucket count. If not, return make_pair(false, 0). + std::pair<bool, std::size_t> + need_rehash(std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const; + + float m_max_load_factor; + float m_growth_factor; + mutable std::size_t m_next_resize; + }; + + // XXX This is a hack. prime_rehash_policy's member functions, and + // certainly the list of primes, should be defined in a .cc file. + // We're temporarily putting them in a header because we don't have a + // place to put TR1 .cc files yet. There's no good reason for any of + // prime_rehash_policy's member functions to be inline, and there's + // certainly no good reason for X<> to exist at all. + // sss: Moved the prime table to hashtable.cxx. + // gcc 3.2.3 chokes on the original code. + + struct lt + { + template<typename X, typename Y> + bool + operator()(X x, Y y) + { return x < y; } + }; + + //template<int dummy> // sss + struct X + { + static const int n_primes = 256; + static const unsigned long primes[n_primes + 1]; + }; + +#if 0 // sss + template<int dummy> + const int X<dummy>::n_primes; + + template<int dummy> + const unsigned long X<dummy>::primes[n_primes + 1] = + { + 2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul, + 37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul, + 83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul, + 157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul, + 277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul, + 503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul, + 953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul, + 1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul, + 3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul, + 5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul, + 11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul, + 19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul, + 33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul, + 57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul, + 99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul, + 159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul, + 256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul, + 410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul, + 658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul, + 1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul, + 1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul, + 2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul, + 4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul, + 6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul, + 11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul, + 16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul, + 24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul, + 36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul, + 54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul, + 80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul, + 118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul, + 176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul, + 260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul, + 386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul, + 573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul, + 849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul, + 1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul, + 1725587117ul, 1866894511ul, 2019773507ul, 2185171673ul, + 2364114217ul, 2557710269ul, 2767159799ul, 2993761039ul, + 3238918481ul, 3504151727ul, 3791104843ul, 4101556399ul, + 4294967291ul, + 4294967291ul // sentinel so we don't have to test result of lower_bound + }; +#endif // sss + + inline + prime_rehash_policy:: + prime_rehash_policy(float z) + : m_max_load_factor(z), m_growth_factor(2.f), m_next_resize(0) + { } + + inline float + prime_rehash_policy:: + max_load_factor() const + { return m_max_load_factor; } + + // Return a prime no smaller than n. + inline std::size_t + prime_rehash_policy:: + next_bkt(std::size_t n) const + { + const unsigned long* const last = X/*<0>*/::primes + X/*<0>*/::n_primes; // sss + const unsigned long* p = std::lower_bound (X/*<0>*/::primes, last, n); // sss + m_next_resize = static_cast<std::size_t>(std::ceil(static_cast<float>(*p) * m_max_load_factor)); // sss + return *p; + } + + // Return the smallest prime p such that alpha p >= n, where alpha + // is the load factor. + inline std::size_t + prime_rehash_policy:: + bkt_for_elements(std::size_t n) const + { + const unsigned long* const last = X/*<0>*/::primes + X/*<0>*/::n_primes; // sss + const float min_bkts = static_cast<float>(n) / m_max_load_factor; // sss + const unsigned long* p = std::lower_bound (X/*<0>*/::primes, last, // sss + min_bkts, lt()); + m_next_resize = static_cast<std::size_t>(std::ceil(static_cast<float>(*p) * m_max_load_factor)); // sss + return *p; + } + + // Finds the smallest prime p such that alpha p > n_elt + n_ins. + // If p > n_bkt, return make_pair(true, p); otherwise return + // make_pair(false, 0). In principle this isn't very different from + // bkt_for_elements. + + // The only tricky part is that we're caching the element count at + // which we need to rehash, so we don't have to do a floating-point + // multiply for every insertion. + + inline std::pair<bool, std::size_t> + prime_rehash_policy:: + need_rehash(std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const + { + if (n_elt + n_ins > m_next_resize) + { + float min_bkts = (float(n_ins) + float(n_elt)) / m_max_load_factor; + if (min_bkts > n_bkt) + { + min_bkts = std::max (min_bkts, m_growth_factor * static_cast<float>(n_bkt)); // sss + const unsigned long* const last = X/*<0>*/::primes + X/*<0>*/::n_primes; // sss + const unsigned long* p = std::lower_bound (X/*<0>*/::primes, last, // sss + min_bkts, lt()); + m_next_resize = + static_cast<std::size_t>(std::ceil(static_cast<float>(*p) * m_max_load_factor)); // sss + return std::make_pair(true, *p); + } + else + { + m_next_resize = + static_cast<std::size_t>(std::ceil(static_cast<float>(n_bkt) * m_max_load_factor)); // sss + return std::make_pair(false, 0); + } + } + else + return std::make_pair(false, 0); + } + +} // namespace CxxUtils_Internal sss + +//---------------------------------------------------------------------- +// Base classes for std::tr1::hashtable. We define these base classes +// because in some cases we want to do different things depending on +// the value of a policy class. In some cases the policy class affects +// which member functions and nested typedefs are defined; we handle that +// by specializing base class templates. Several of the base class templates +// need to access other members of class template hashtable, so we use +// the "curiously recurring template pattern" for them. + +namespace CxxUtils_Internal // sss Internal +{ + // class template map_base. If the hashtable has a value type of the + // form pair<T1, T2> and a key extraction policy that returns the + // first part of the pair, the hashtable gets a mapped_type typedef. + // If it satisfies those criteria and also has unique keys, then it + // also gets an operator[]. + + template<typename K, typename V, typename Ex, bool unique, typename Hashtable> + struct map_base { }; + + template<typename K, typename Pair, typename Hashtable> + struct map_base<K, Pair, extract1st<Pair>, false, Hashtable> + { + typedef typename Pair::second_type mapped_type; + }; + + template<typename K, typename Pair, typename Hashtable> + struct map_base<K, Pair, extract1st<Pair>, true, Hashtable> + { + typedef typename Pair::second_type mapped_type; + + mapped_type& + operator[](const K& k) + { + Hashtable* h = static_cast<Hashtable*>(this); + typename Hashtable::iterator it = + h->insert(std::make_pair(k, mapped_type())).first; + return it->second; + } + }; + + // class template rehash_base. Give hashtable the max_load_factor + // functions iff the rehash policy is prime_rehash_policy. + template<typename RehashPolicy, typename Hashtable> + struct rehash_base { }; + + template<typename Hashtable> + struct rehash_base<prime_rehash_policy, Hashtable> + { + float + max_load_factor() const + { + const Hashtable* This = static_cast<const Hashtable*>(this); + return This->rehash_policy().max_load_factor(); + } + + void + max_load_factor(float z) + { + Hashtable* This = static_cast<Hashtable*>(this); + This->rehash_policy(prime_rehash_policy(z)); + } + }; + + // Class template hash_code_base. Encapsulates two policy issues that + // aren't quite orthogonal. + // (1) the difference between using a ranged hash function and using + // the combination of a hash function and a range-hashing function. + // In the former case we don't have such things as hash codes, so + // we have a dummy type as placeholder. + // (2) Whether or not we cache hash codes. Caching hash codes is + // meaningless if we have a ranged hash function. + // We also put the key extraction and equality comparison function + // objects here, for convenience. + + // Primary template: unused except as a hook for specializations. + + template<typename Key, typename Value, + typename ExtractKey, typename Equal, + typename H1, typename H2, typename H, + bool cache_hash_code> + struct hash_code_base; + + // Specialization: ranged hash function, no caching hash codes. H1 + // and H2 are provided but ignored. We define a dummy hash code type. + template<typename Key, typename Value, + typename ExtractKey, typename Equal, + typename H1, typename H2, typename H> + struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, false> + { + protected: + hash_code_base(const ExtractKey& ex, const Equal& eq, + const H1&, const H2&, const H& h) + : m_extract(ex), m_eq(eq), m_ranged_hash(h) { } + + typedef void* hash_code_t; + + hash_code_t + m_hash_code(const Key& /*k*/) const + { return 0; } + + std::size_t + bucket_index(const Key& k, hash_code_t, std::size_t N) const + { return m_ranged_hash (k, N); } + + std::size_t + bucket_index(const hash_node<Value, false>* p, std::size_t N) const + { return m_ranged_hash (m_extract (p->m_v), N); } + + bool + compare(const Key& k, hash_code_t, hash_node<Value, false>* n) const + { return m_eq (k, m_extract(n->m_v)); } + + void + store_code(hash_node<Value, false>*, hash_code_t) const + { } + + void + copy_code(hash_node<Value, false>*, const hash_node<Value, false>*) const + { } + + void + m_swap(hash_code_base& x) + { + std::swap(m_extract, x.m_extract); + std::swap(m_eq, x.m_eq); + std::swap(m_ranged_hash, x.m_ranged_hash); + } + + protected: + ExtractKey m_extract; + Equal m_eq; + H m_ranged_hash; + }; + + + // No specialization for ranged hash function while caching hash codes. + // That combination is meaningless, and trying to do it is an error. + + + // Specialization: ranged hash function, cache hash codes. This + // combination is meaningless, so we provide only a declaration + // and no definition. + + template<typename Key, typename Value, + typename ExtractKey, typename Equal, + typename H1, typename H2, typename H> + struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, true>; + + + // Specialization: hash function and range-hashing function, no + // caching of hash codes. H is provided but ignored. Provides + // typedef and accessor required by TR1. + + template<typename Key, typename Value, + typename ExtractKey, typename Equal, + typename H1, typename H2> + struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, + default_ranged_hash, false> + { + typedef H1 hasher; + + hasher + hash_function() const + { return m_h1; } + + protected: + hash_code_base(const ExtractKey& ex, const Equal& eq, + const H1& h1, const H2& h2, const default_ranged_hash&) + : m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { } + + typedef std::size_t hash_code_t; + + hash_code_t + m_hash_code(const Key& k) const + { return m_h1(k); } + + std::size_t + bucket_index(const Key&, hash_code_t c, std::size_t N) const + { return m_h2 (c, N); } + + std::size_t + bucket_index(const hash_node<Value, false>* p, std::size_t N) const + { return m_h2 (m_h1 (m_extract (p->m_v)), N); } + + bool + compare(const Key& k, hash_code_t, hash_node<Value, false>* n) const + { return m_eq (k, m_extract(n->m_v)); } + + void + store_code(hash_node<Value, false>*, hash_code_t) const + { } + + void + copy_code(hash_node<Value, false>*, const hash_node<Value, false>*) const + { } + + void + m_swap(hash_code_base& x) + { + std::swap(m_extract, x.m_extract); + std::swap(m_eq, x.m_eq); + std::swap(m_h1, x.m_h1); + std::swap(m_h2, x.m_h2); + } + + protected: + ExtractKey m_extract; + Equal m_eq; + H1 m_h1; + H2 m_h2; + }; + + // Specialization: hash function and range-hashing function, + // caching hash codes. H is provided but ignored. Provides + // typedef and accessor required by TR1. + template<typename Key, typename Value, + typename ExtractKey, typename Equal, + typename H1, typename H2> + struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, + default_ranged_hash, true> + { + typedef H1 hasher; + + hasher + hash_function() const + { return m_h1; } + + protected: + hash_code_base(const ExtractKey& ex, const Equal& eq, + const H1& h1, const H2& h2, const default_ranged_hash&) + : m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { } + + typedef std::size_t hash_code_t; + + hash_code_t + m_hash_code(const Key& k) const + { return m_h1(k); } + + std::size_t + bucket_index(const Key&, hash_code_t c, std::size_t N) const + { return m_h2 (c, N); } + + std::size_t + bucket_index(const hash_node<Value, true>* p, std::size_t N) const + { return m_h2 (p->hash_code, N); } + + bool + compare(const Key& k, hash_code_t c, hash_node<Value, true>* n) const + { return c == n->hash_code && m_eq(k, m_extract(n->m_v)); } + + void + store_code(hash_node<Value, true>* n, hash_code_t c) const + { n->hash_code = c; } + + void + copy_code(hash_node<Value, true>* to, + const hash_node<Value, true>* from) const + { to->hash_code = from->hash_code; } + + void + m_swap(hash_code_base& x) + { + std::swap(m_extract, x.m_extract); + std::swap(m_eq, x.m_eq); + std::swap(m_h1, x.m_h1); + std::swap(m_h2, x.m_h2); + } + + protected: + ExtractKey m_extract; + Equal m_eq; + H1 m_h1; + H2 m_h2; + }; + +} // namespace CxxUtils_Internal sss + +//namespace std sss +//{ sss +namespace SG // tr1 sss +{ +#define Internal CxxUtils_Internal // sss + //---------------------------------------------------------------------- + // Class template hashtable, class definition. + + // Meaning of class template hashtable's template parameters + + // Key and Value: arbitrary CopyConstructible types. + + // Allocator: an allocator type ([lib.allocator.requirements]) whose + // value type is Value. + + // ExtractKey: function object that takes a object of type Value + // and returns a value of type Key. + + // Equal: function object that takes two objects of type k and returns + // a bool-like value that is true if the two objects are considered equal. + + // H1: the hash function. A unary function object with argument type + // Key and result type size_t. Return values should be distributed + // over the entire range [0, numeric_limits<size_t>:::max()]. + + // H2: the range-hashing function (in the terminology of Tavori and + // Dreizin). A binary function object whose argument types and result + // type are all size_t. Given arguments r and N, the return value is + // in the range [0, N). + + // H: the ranged hash function (Tavori and Dreizin). A binary function + // whose argument types are Key and size_t and whose result type is + // size_t. Given arguments k and N, the return value is in the range + // [0, N). Default: h(k, N) = h2(h1(k), N). If H is anything other + // than the default, H1 and H2 are ignored. + + // RehashPolicy: Policy class with three members, all of which govern + // the bucket count. n_bkt(n) returns a bucket count no smaller + // than n. bkt_for_elements(n) returns a bucket count appropriate + // for an element count of n. need_rehash(n_bkt, n_elt, n_ins) + // determines whether, if the current bucket count is n_bkt and the + // current element count is n_elt, we need to increase the bucket + // count. If so, returns make_pair(true, n), where n is the new + // bucket count. If not, returns make_pair(false, <anything>). + + // ??? Right now it is hard-wired that the number of buckets never + // shrinks. Should we allow RehashPolicy to change that? + + // cache_hash_code: bool. true if we store the value of the hash + // function along with the value. This is a time-space tradeoff. + // Storing it may improve lookup speed by reducing the number of times + // we need to call the Equal function. + + // constant_iterators: bool. true if iterator and const_iterator are + // both constant iterator types. This is true for unordered_set and + // unordered_multiset, false for unordered_map and unordered_multimap. + + // unique_keys: bool. true if the return value of hashtable::count(k) + // is always at most one, false if it may be an arbitrary number. This + // true for unordered_set and unordered_map, false for unordered_multiset + // and unordered_multimap. + + template<typename Key, typename Value, + typename Allocator, + typename ExtractKey, typename Equal, + typename H1, typename H2, + typename H, typename RehashPolicy, + bool cache_hash_code, + bool constant_iterators, + bool unique_keys> + class hashtable + : public Internal::rehash_base<RehashPolicy, + hashtable<Key, Value, Allocator, ExtractKey, + Equal, H1, H2, H, RehashPolicy, + cache_hash_code, constant_iterators, + unique_keys> >, + public Internal::hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, + cache_hash_code>, + public Internal::map_base<Key, Value, ExtractKey, unique_keys, + hashtable<Key, Value, Allocator, ExtractKey, + Equal, H1, H2, H, RehashPolicy, + cache_hash_code, constant_iterators, + unique_keys> > + { + public: + typedef Allocator allocator_type; + typedef Value value_type; + typedef Key key_type; + typedef Equal key_equal; + // mapped_type, if present, comes from map_base. + // hasher, if present, comes from hash_code_base. + typedef typename Allocator::difference_type difference_type; + typedef typename Allocator::size_type size_type; + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + + typedef Internal::node_iterator<value_type, constant_iterators, + cache_hash_code> + local_iterator; + typedef Internal::node_const_iterator<value_type, constant_iterators, + cache_hash_code> + const_local_iterator; + + typedef Internal::hashtable_iterator<value_type, constant_iterators, + cache_hash_code> + iterator; + typedef Internal::hashtable_const_iterator<value_type, constant_iterators, + cache_hash_code> + const_iterator; + + private: + typedef Internal::hash_node<Value, cache_hash_code> node; + typedef typename Allocator::template rebind<node>::other + node_allocator_t; + typedef typename Allocator::template rebind<node*>::other + bucket_allocator_t; + + private: + node_allocator_t m_node_allocator; + // sss -- Some of our allocators have non-trivial state, and + // thus a non-trivial copy ctor. However, m_allocate_node + // will do a copy conversion of node_allocator_t to allocator_type + // for each node allocated. Instead, do the conversion once + // and cache it. Note: in newer gcc versions, extensions to the + // allocator model allow dispensing with the conversions. So once + // we go to c++0x, this shouldn't be an issue. + allocator_type m_payload_allocator; + node** m_buckets; + size_type m_bucket_count; + size_type m_element_count; + RehashPolicy m_rehash_policy; + + node* + m_allocate_node(const value_type& v); + + void + m_deallocate_node(node* n); + + void + m_deallocate_nodes(node**, size_type); + + node** + m_allocate_buckets(size_type n); + + void + m_deallocate_buckets(node**, size_type n); + + public: // Constructor, destructor, assignment, swap + hashtable(size_type bucket_hint, + const H1&, const H2&, const H&, + const Equal&, const ExtractKey&, + const allocator_type&); + + template<typename InIter> + hashtable(InIter first, InIter last, + size_type bucket_hint, + const H1&, const H2&, const H&, + const Equal&, const ExtractKey&, + const allocator_type&); + + hashtable(const hashtable&); + + hashtable& + operator=(const hashtable&); + + ~hashtable(); + + void swap(hashtable&); + + public: // Basic container operations + iterator + begin() + { + iterator i(m_buckets); + if (!i.m_cur_node) + i.m_incr_bucket(); + return i; + } + + const_iterator + begin() const + { + const_iterator i(m_buckets); + if (!i.m_cur_node) + i.m_incr_bucket(); + return i; + } + + iterator + end() + { return iterator(m_buckets + m_bucket_count); } + + const_iterator + end() const + { return const_iterator(m_buckets + m_bucket_count); } + + size_type + size() const + { return m_element_count; } + + bool + empty() const + { return size() == 0; } + + allocator_type + get_allocator() const + { return m_node_allocator; } + + size_type + max_size() const + { return m_node_allocator.max_size(); } + + public: // Observers + key_equal + key_eq() const + { return this->m_eq; } + + // hash_function, if present, comes from hash_code_base. + + public: // Bucket operations + size_type + bucket_count() const + { return m_bucket_count; } + + size_type + max_bucket_count() const + { return max_size(); } + + size_type + bucket_size(size_type n) const + { return std::distance(begin(n), end(n)); } + + size_type + bucket(const key_type& k) const + { + return this->bucket_index(k, this->m_hash_code(k), + this->m_bucket_count); + } + + local_iterator + begin(size_type n) + { return local_iterator(m_buckets[n]); } + + local_iterator + end(size_type) + { return local_iterator(0); } + + const_local_iterator + begin(size_type n) const + { return const_local_iterator(m_buckets[n]); } + + const_local_iterator + end(size_type) const + { return const_local_iterator(0); } + + float + load_factor() const + { + return static_cast<float>(size()) / static_cast<float>(bucket_count()); + } + // max_load_factor, if present, comes from rehash_base. + + // Generalization of max_load_factor. Extension, not found in TR1. Only + // useful if RehashPolicy is something other than the default. + const RehashPolicy& + rehash_policy() const + { return m_rehash_policy; } + + void + rehash_policy(const RehashPolicy&); + + public: // lookup + iterator + find(const key_type&); + + const_iterator + find(const key_type& k) const; + + size_type + count(const key_type& k) const; + + std::pair<iterator, iterator> + equal_range(const key_type& k); + + std::pair<const_iterator, const_iterator> + equal_range(const key_type& k) const; + + private: // Insert and erase helper functions + // ??? This dispatching is a workaround for the fact that we don't + // have partial specialization of member templates; it would be + // better to just specialize insert on unique_keys. There may be a + // cleaner workaround. + typedef typename Internal::IF<unique_keys, + std::pair<iterator, bool>, iterator>::type + Insert_Return_Type; + + typedef typename Internal::IF<unique_keys, + Internal::extract1st<Insert_Return_Type>, + Internal::identity<Insert_Return_Type> + >::type + Insert_Conv_Type; + + node* + find_node(node* p, const key_type& k, + typename hashtable::hash_code_t c) const; + + std::pair<iterator, bool> + insert(const value_type&, CxxUtils_Internal/*std::tr1*/::true_type); // sss + + iterator + insert(const value_type&, CxxUtils_Internal/*std::tr1*/::false_type); // sss + + friend struct CxxUtils_Internal::hashtable_iterator_base<Value, cache_hash_code>; // sss + void + erase_node(node*, node**); + + public: // Insert and erase + Insert_Return_Type + insert(const value_type& v) + { + return this->insert(v, CxxUtils_Internal/*std::tr1*/::integral_constant<bool,//sss + unique_keys>()); + } + + iterator + insert(iterator, const value_type& v) + { return iterator(Insert_Conv_Type()(this->insert(v))); } + + const_iterator + insert(const_iterator, const value_type& v) + { return const_iterator(Insert_Conv_Type()(this->insert(v))); } + + template<typename InIter> + void + insert(InIter first, InIter last); + + iterator + erase(iterator); + + const_iterator + erase(const_iterator); + + size_type + erase(const key_type&); + + iterator + erase(iterator, iterator); + + const_iterator + erase(const_iterator, const_iterator); + + void + clear(); + + public: + // Set number of buckets to be appropriate for container of n element. + void rehash(size_type n); + + private: + // Unconditionally change size of bucket array to n. + void m_rehash(size_type n); + }; + + //---------------------------------------------------------------------- + // Definitions of class template hashtable's out-of-line member functions. + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::node* + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + m_allocate_node(const value_type& v) + { + node* n = m_node_allocator.allocate(1); + try + { + m_payload_allocator.construct(&n->m_v, v); + n->m_next = 0; + return n; + } + catch(...) + { + m_node_allocator.deallocate(n, 1); + throw; + } + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + m_deallocate_node(node* n) + { + m_payload_allocator.destroy(&n->m_v); + m_node_allocator.deallocate(n, 1); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + m_deallocate_nodes(node** array, size_type n) + { + for (size_type i = 0; i < n; ++i) + { + node* p = array[i]; + while (p) + { + node* tmp = p; + p = p->m_next; + m_deallocate_node (tmp); + } + array[i] = 0; + } + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::node** + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + m_allocate_buckets(size_type n) + { + bucket_allocator_t alloc(m_node_allocator); + + // We allocate one extra bucket to hold a sentinel, an arbitrary + // non-null pointer. Iterator increment relies on this. + node** p = alloc.allocate(n+1); + std::fill(p, p+n, (node*) 0); + p[n] = reinterpret_cast<node*>(0x1000); + return p; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + m_deallocate_buckets(node** p, size_type n) + { + bucket_allocator_t alloc(m_node_allocator); + alloc.deallocate(p, n+1); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + hashtable(size_type bucket_hint, + const H1& h1, const H2& h2, const H& h, + const Eq& eq, const Ex& exk, + const allocator_type& a) + : Internal::rehash_base<RP,hashtable>(), + Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>(exk, eq, h1, h2, h), + Internal::map_base<K, V, Ex, u, hashtable>(), + m_node_allocator(a), + m_payload_allocator(a), + m_bucket_count(0), + m_element_count(0), + m_rehash_policy() + { + m_bucket_count = m_rehash_policy.next_bkt(bucket_hint); + m_buckets = m_allocate_buckets(m_bucket_count); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + template<typename InIter> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + hashtable(InIter f, InIter l, + size_type bucket_hint, + const H1& h1, const H2& h2, const H& h, + const Eq& eq, const Ex& exk, + const allocator_type& a) + : Internal::rehash_base<RP,hashtable>(), + Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c> (exk, eq, + h1, h2, h), + Internal::map_base<K,V,Ex,u,hashtable>(), + m_node_allocator(a), + m_bucket_count (0), + m_element_count(0), + m_rehash_policy() + { + m_bucket_count = std::max(m_rehash_policy.next_bkt(bucket_hint), + m_rehash_policy. + bkt_for_elements(Internal:: + distance_fw(f, l))); + m_buckets = m_allocate_buckets(m_bucket_count); + try + { + for (; f != l; ++f) + this->insert(*f); + } + catch(...) + { + clear(); + m_deallocate_buckets(m_buckets, m_bucket_count); + throw; + } + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + hashtable(const hashtable& ht) + : Internal::rehash_base<RP, hashtable>(ht), + Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>(ht), + Internal::map_base<K, V, Ex, u, hashtable>(ht), + m_node_allocator(ht.get_allocator()), + m_payload_allocator(ht.get_allocator()), + m_bucket_count(ht.m_bucket_count), + m_element_count(ht.m_element_count), + m_rehash_policy(ht.m_rehash_policy) + { + m_buckets = m_allocate_buckets (m_bucket_count); + try + { + for (size_t i = 0; i < ht.m_bucket_count; ++i) + { + node* n = ht.m_buckets[i]; + node** tail = m_buckets + i; + while (n) + { + *tail = m_allocate_node(n->m_v); + this->copy_code(*tail, n); + tail = &((*tail)->m_next); + n = n->m_next; + } + } + } + catch (...) + { + clear(); + m_deallocate_buckets (m_buckets, m_bucket_count); + throw; + } + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>& + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + operator=(const hashtable& ht) + { + hashtable tmp(ht); + this->swap(tmp); + return *this; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + ~hashtable() + { + clear(); + m_deallocate_buckets(m_buckets, m_bucket_count); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + swap(hashtable& x) + { + // The only base class with member variables is hash_code_base. We + // define hash_code_base::m_swap because different specializations + // have different members. + Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>::m_swap(x); + + // open LWG issue 431 + // std::swap(m_node_allocator, x.m_node_allocator); + std::swap(m_rehash_policy, x.m_rehash_policy); + std::swap(m_buckets, x.m_buckets); + std::swap(m_bucket_count, x.m_bucket_count); + std::swap(m_element_count, x.m_element_count); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + rehash_policy(const RP& pol) + { + m_rehash_policy = pol; + size_type n_bkt = pol.bkt_for_elements(m_element_count); + if (n_bkt > m_bucket_count) + m_rehash (n_bkt); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + find(const key_type& k) + { + typename hashtable::hash_code_t code = this->m_hash_code(k); + std::size_t n = this->bucket_index(k, code, this->bucket_count()); + node* p = find_node(m_buckets[n], k, code); + return p ? iterator(p, m_buckets + n) : this->end(); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::const_iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + find(const key_type& k) const + { + typename hashtable::hash_code_t code = this->m_hash_code(k); + std::size_t n = this->bucket_index(k, code, this->bucket_count()); + node* p = find_node(m_buckets[n], k, code); + return p ? const_iterator(p, m_buckets + n) : this->end(); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::size_type + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + count(const key_type& k) const + { + typename hashtable::hash_code_t code = this->m_hash_code(k); + std::size_t n = this->bucket_index(k, code, this->bucket_count()); + size_t result = 0; + for (node* p = m_buckets[n]; p ; p = p->m_next) + if (this->compare(k, code, p)) + ++result; + return result; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + std::pair<typename hashtable<K, V, A, Ex, Eq, H1, + H2, H, RP, c, ci, u>::iterator, + typename hashtable<K, V, A, Ex, Eq, H1, + H2, H, RP, c, ci, u>::iterator> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + equal_range(const key_type& k) + { + typename hashtable::hash_code_t code = this->m_hash_code(k); + std::size_t n = this->bucket_index(k, code, this->bucket_count()); + node** head = m_buckets + n; + node* p = find_node (*head, k, code); + + if (p) + { + node* p1 = p->m_next; + for (; p1 ; p1 = p1->m_next) + if (!this->compare (k, code, p1)) + break; + + iterator first(p, head); + iterator last(p1, head); + if (!p1) + last.m_incr_bucket(); + return std::make_pair(first, last); + } + else + return std::make_pair(this->end(), this->end()); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + std::pair<typename hashtable<K, V, A, Ex, Eq, H1, + H2, H, RP, c, ci, u>::const_iterator, + typename hashtable<K, V, A, Ex, Eq, H1, + H2, H, RP, c, ci, u>::const_iterator> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + equal_range(const key_type& k) const + { + typename hashtable::hash_code_t code = this->m_hash_code(k); + std::size_t n = this->bucket_index(k, code, this->bucket_count()); + node** head = m_buckets + n; + node* p = find_node(*head, k, code); + + if (p) + { + node* p1 = p->m_next; + for (; p1 ; p1 = p1->m_next) + if (!this->compare(k, code, p1)) + break; + + const_iterator first(p, head); + const_iterator last(p1, head); + if (!p1) + last.m_incr_bucket(); + return std::make_pair(first, last); + } + else + return std::make_pair(this->end(), this->end()); + } + + // Find the node whose key compares equal to k, beginning the search + // at p (usually the head of a bucket). Return nil if no node is found. + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::node* + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + find_node(node* p, const key_type& k, + typename hashtable::hash_code_t code) const + { + for ( ; p ; p = p->m_next) + if (this->compare (k, code, p)) + return p; + return 0; + } + + // Insert v if no element with its key is already present. + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + std::pair<typename hashtable<K, V, A, Ex, Eq, H1, + H2, H, RP, c, ci, u>::iterator, bool> + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + insert(const value_type& v, CxxUtils_Internal/*std::tr1*/::true_type) // sss + { + const key_type& k = this->m_extract(v); + typename hashtable::hash_code_t code = this->m_hash_code(k); + size_type n = this->bucket_index(k, code, m_bucket_count); + + if (node* p = find_node(m_buckets[n], k, code)) + return std::make_pair(iterator(p, m_buckets + n), false); + + std::pair<bool, size_t> do_rehash + = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. + node* new_node = m_allocate_node (v); + + try + { + if (do_rehash.first) + { + n = this->bucket_index(k, code, do_rehash.second); + m_rehash(do_rehash.second); + } + + new_node->m_next = m_buckets[n]; + this->store_code(new_node, code); + m_buckets[n] = new_node; + ++m_element_count; + return std::make_pair(iterator(new_node, m_buckets + n), true); + } + catch (...) + { + m_deallocate_node (new_node); + throw; + } + } + + // Insert v unconditionally. + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + insert(const value_type& v, CxxUtils_Internal/*std::tr1*/::false_type) // sss + { + std::pair<bool, std::size_t> do_rehash + = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); + if (do_rehash.first) + m_rehash(do_rehash.second); + + const key_type& k = this->m_extract(v); + typename hashtable::hash_code_t code = this->m_hash_code(k); + size_type n = this->bucket_index(k, code, m_bucket_count); + + node* new_node = m_allocate_node (v); + node* prev = find_node(m_buckets[n], k, code); + if (prev) + { + new_node->m_next = prev->m_next; + prev->m_next = new_node; + } + else + { + new_node->m_next = m_buckets[n]; + m_buckets[n] = new_node; + } + this->store_code(new_node, code); + + ++m_element_count; + return iterator(new_node, m_buckets + n); + } + + // For erase(iterator) and erase(const_iterator). + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + erase_node(node* p, node** b) + { + node* cur = *b; + if (cur == p) + *b = cur->m_next; + else + { + node* next = cur->m_next; + while (next != p) + { + cur = next; + next = cur->m_next; + } + cur->m_next = next->m_next; + } + + m_deallocate_node (p); + --m_element_count; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + template<typename InIter> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + insert(InIter first, InIter last) + { + size_type n_elt = Internal::distance_fw (first, last); + std::pair<bool, std::size_t> do_rehash + = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, n_elt); + if (do_rehash.first) + m_rehash(do_rehash.second); + + for (; first != last; ++first) + this->insert (*first); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + erase(iterator i) + { + iterator result = i; + ++result; + //erase_node(i.m_cur_node, i.m_cur_bucket); + i.erase_node(*this); // sss + return result; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::const_iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + erase(const_iterator i) + { + const_iterator result = i; + ++result; + //erase_node(i.m_cur_node, i.m_cur_bucket); + i.erase_node (*this); // sss + return result; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::size_type + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + erase(const key_type& k) + { + typename hashtable::hash_code_t code = this->m_hash_code(k); + size_type n = this->bucket_index(k, code, m_bucket_count); + size_type result = 0; + + node** slot = m_buckets + n; + while (*slot && ! this->compare(k, code, *slot)) + slot = &((*slot)->m_next); + + while (*slot && this->compare(k, code, *slot)) + { + node* n = *slot; + *slot = n->m_next; + m_deallocate_node (n); + --m_element_count; + ++result; + } + + return result; + } + + // ??? This could be optimized by taking advantage of the bucket + // structure, but it's not clear that it's worth doing. It probably + // wouldn't even be an optimization unless the load factor is large. + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + erase(iterator first, iterator last) + { + while (first != last) + first = this->erase(first); + return last; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::const_iterator + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + erase(const_iterator first, const_iterator last) + { + while (first != last) + first = this->erase(first); + return last; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + clear() + { + m_deallocate_nodes(m_buckets, m_bucket_count); + m_element_count = 0; + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + rehash(size_type n) + { + m_rehash(std::max(m_rehash_policy.next_bkt(n), + m_rehash_policy.bkt_for_elements(m_element_count + + 1))); + } + + template<typename K, typename V, + typename A, typename Ex, typename Eq, + typename H1, typename H2, typename H, typename RP, + bool c, bool ci, bool u> + void + hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: + m_rehash(size_type N) + { + node** new_array = m_allocate_buckets (N); + try + { + for (size_type i = 0; i < m_bucket_count; ++i) + while (node* p = m_buckets[i]) + { + size_type new_index = this->bucket_index (p, N); + m_buckets[i] = p->m_next; + p->m_next = new_array[new_index]; + new_array[new_index] = p; + } + m_deallocate_buckets(m_buckets, m_bucket_count); + m_bucket_count = N; + m_buckets = new_array; + } + catch (...) + { + // A failure here means that a hash function threw an exception. + // We can't restore the previous state without calling the hash + // function again, so the only sensible recovery is to delete + // everything. + m_deallocate_nodes(new_array, N); + m_deallocate_buckets(new_array, N); + m_deallocate_nodes(m_buckets, m_bucket_count); + m_element_count = 0; + throw; + } + } +#undef Internal // sss +//} sss +} // Namespace std::tr1 + +#endif /* GNU_LIBSTDCXX_TR1_HASHTABLE_ */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/arraylist.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/arraylist.h new file mode 100644 index 00000000..b0ce8a11 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/arraylist.h @@ -0,0 +1,218 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file arraylist.h + * + * @brief Automatically resizing array + * + * ArrayLists are arrays of pointers which automatically increase in + * size. + * + * To create an ArrayList, use @ref arraylist_new. + * To destroy an ArrayList, use @ref arraylist_free. + * + * To add a value to an ArrayList, use @ref arraylist_prepend, + * @ref arraylist_append, or @ref arraylist_insert. + * + * To remove a value from an ArrayList, use @ref arraylist_remove + * or @ref arraylist_remove_range. + */ + +#ifndef ALGORITHM_ARRAYLIST_H +#define ALGORITHM_ARRAYLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A value to be stored in an @ref ArrayList. + */ + +typedef void *ArrayListValue; + +/** + * An ArrayList structure. New ArrayLists can be created using the + * arraylist_new function. + * + * @see arraylist_new + */ + +typedef struct _ArrayList ArrayList; + +/** + * Definition of an @ref ArrayList. + */ + +struct _ArrayList { + + /** Entries in the array */ + + ArrayListValue *data; + + /** Length of the array */ + + int length; + + /** Private data and should not be accessed */ + + int _alloced; +}; + +/** + * Compare two values in an arraylist to determine if they are equal. + * + * @return Non-zero if the values are not equal, zero if they are equal. + */ + +typedef int (*ArrayListEqualFunc)(ArrayListValue value1, ArrayListValue value2); + +/** + * Compare two values in an arraylist. Used by @ref arraylist_sort + * when sorting values. + * + * @param value1 The first value. + * @param value2 The second value. + * @return A negative number if value1 should be sorted + * before value2, a positive number if value2 should + * be sorted before value1, zero if the two values + * are equal. + */ + +typedef int (*ArrayListCompareFunc)(ArrayListValue value1, + ArrayListValue value2); + +/** + * Allocate a new ArrayList for use. + * + * @param length Hint to the initialise function as to the amount + * of memory to allocate initially to the ArrayList. + * @return A new arraylist, or NULL if it was not possible + * to allocate the memory. + * @see arraylist_free + */ + +ArrayList *arraylist_new(int length); + +/** + * Destroy an ArrayList and free back the memory it uses. + * + * @param arraylist The ArrayList to free. + */ + +void arraylist_free(ArrayList *arraylist); + +/** + * Append a value to the end of an ArrayList. + * + * @param arraylist The ArrayList. + * @param data The value to append. + * @return Non-zero if the request was successful, zero + * if it was not possible to allocate more memory + * for the new entry. + */ + +int arraylist_append(ArrayList *arraylist, ArrayListValue data); + +/** + * Prepend a value to the beginning of an ArrayList. + * + * @param arraylist The ArrayList. + * @param data The value to prepend. + * @return Non-zero if the request was successful, zero + * if it was not possible to allocate more memory + * for the new entry. + */ + +int arraylist_prepend(ArrayList *arraylist, ArrayListValue data); + +/** + * Remove the entry at the specified location in an ArrayList. + * + * @param arraylist The ArrayList. + * @param index The index of the entry to remove. + */ + +void arraylist_remove(ArrayList *arraylist, int index); + +/** + * Remove a range of entries at the specified location in an ArrayList. + * + * @param arraylist The ArrayList. + * @param index The index of the start of the range to remove. + * @param length The length of the range to remove. + */ + +void arraylist_remove_range(ArrayList *arraylist, int index, int length); + +/** + * Insert a value at the specified index in an ArrayList. + * The index where the new value can be inserted is limited by the + * size of the ArrayList. + * + * @param arraylist The ArrayList. + * @param index The index at which to insert the value. + * @param data The value. + * @return Returns zero if unsuccessful, else non-zero + * if successful (due to an invalid index or + * if it was impossible to allocate more memory). + */ + +int arraylist_insert(ArrayList *arraylist, int index, ArrayListValue data); + +/** + * Find the index of a particular value in an ArrayList. + * + * @param arraylist The ArrayList to search. + * @param callback Callback function to be invoked to compare + * values in the list with the value to be + * searched for. + * @param data The value to search for. + * @return The index of the value if found, or -1 if not found. + */ + +int arraylist_index_of(ArrayList *arraylist, + ArrayListEqualFunc callback, + ArrayListValue data); + +/** + * Remove all entries from an ArrayList. + * + * @param arraylist The ArrayList. + */ + +void arraylist_clear(ArrayList *arraylist); + +/** + * Sort the values in an ArrayList. + * + * @param arraylist The ArrayList. + * @param compare_func Function used to compare values in sorting. + */ + +void arraylist_sort(ArrayList *arraylist, ArrayListCompareFunc compare_func); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_ARRAYLIST_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/avl-tree.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/avl-tree.h new file mode 100644 index 00000000..45de3fea --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/avl-tree.h @@ -0,0 +1,286 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** @file avl-tree.h + * + * @brief Balanced binary tree + * + * The AVL tree structure is a balanced binary tree which stores + * a collection of nodes (see @ref AVLTreeNode). Each node has + * a key and a value associated with it. The nodes are sorted + * within the tree based on the order of their keys. Modifications + * to the tree are constructed such that the tree remains + * balanced at all times (there are always roughly equal numbers + * of nodes on either side of the tree). + * + * Balanced binary trees have several uses. They can be used + * as a mapping (searching for a value based on its key), or + * as a set of keys which is always ordered. + * + * To create a new AVL tree, use @ref avl_tree_new. To destroy + * an AVL tree, use @ref avl_tree_free. + * + * To insert a new key-value pair into an AVL tree, use + * @ref avl_tree_insert. To remove an entry from an + * AVL tree, use @ref avl_tree_remove or @ref avl_tree_remove_node. + * + * To search an AVL tree, use @ref avl_tree_lookup or + * @ref avl_tree_lookup_node. + * + * Tree nodes can be queried using the + * @ref avl_tree_node_child, + * @ref avl_tree_node_parent, + * @ref avl_tree_node_key and + * @ref avl_tree_node_value functions. + */ + +#ifndef ALGORITHM_AVLTREE_H +#define ALGORITHM_AVLTREE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * An AVL tree balanced binary tree. + * + * @see avl_tree_new + */ + +typedef struct _AVLTree AVLTree; + +/** + * A key for an @ref AVLTree. + */ + +typedef void *AVLTreeKey; + +/** + * A value stored in an @ref AVLTree. + */ + +typedef void *AVLTreeValue; + +/** + * A null @ref AVLTreeValue. + */ + +#define AVL_TREE_NULL ((void *) 0) + +/** + * A node in an AVL tree. + * + * @see avl_tree_node_left_child + * @see avl_tree_node_right_child + * @see avl_tree_node_parent + * @see avl_tree_node_key + * @see avl_tree_node_value + */ + +typedef struct _AVLTreeNode AVLTreeNode; + +/** + * An @ref AVLTreeNode can have left and right children. + */ + +typedef enum { + AVL_TREE_NODE_LEFT = 0, + AVL_TREE_NODE_RIGHT = 1 +} AVLTreeNodeSide; + +/** + * Type of function used to compare keys in an AVL tree. + * + * @param value1 The first key. + * @param value2 The second key. + * @return A negative number if value1 should be sorted + * before value2, a positive number if value2 should + * be sorted before value1, zero if the two keys + * are equal. + */ + +typedef int (*AVLTreeCompareFunc)(AVLTreeValue value1, AVLTreeValue value2); + +/** + * Create a new AVL tree. + * + * @param compare_func Function to use when comparing keys in the tree. + * @return A new AVL tree, or NULL if it was not possible + * to allocate the memory. + */ + +AVLTree *avl_tree_new(AVLTreeCompareFunc compare_func); + +/** + * Destroy an AVL tree. + * + * @param tree The tree to destroy. + */ + +void avl_tree_free(AVLTree *tree); + +/** + * Insert a new key-value pair into an AVL tree. + * + * @param tree The tree. + * @param key The key to insert. + * @param value The value to insert. + * @return The newly created tree node containing the + * key and value, or NULL if it was not possible + * to allocate the new memory. + */ + +AVLTreeNode *avl_tree_insert(AVLTree *tree, AVLTreeKey key, AVLTreeValue value); + +/** + * Remove a node from a tree. + * + * @param tree The tree. + * @param node The node to remove + */ + +void avl_tree_remove_node(AVLTree *tree, AVLTreeNode *node); + +/** + * Remove an entry from a tree, specifying the key of the node to + * remove. + * + * @param tree The tree. + * @param key The key of the node to remove. + * @return Zero (false) if no node with the specified key was + * found in the tree, non-zero (true) if a node with + * the specified key was removed. + */ + +int avl_tree_remove(AVLTree *tree, AVLTreeKey key); + +/** + * Search an AVL tree for a node with a particular key. This uses + * the tree as a mapping. + * + * @param tree The AVL tree to search. + * @param key The key to search for. + * @return The tree node containing the given key, or NULL + * if no entry with the given key is found. + */ + +AVLTreeNode *avl_tree_lookup_node(AVLTree *tree, AVLTreeKey key); + +/** + * Search an AVL tree for a value corresponding to a particular key. + * This uses the tree as a mapping. Note that this performs + * identically to @ref avl_tree_lookup_node, except that the value + * at the node is returned rather than the node itself. + * + * @param tree The AVL tree to search. + * @param key The key to search for. + * @return The value associated with the given key, or + * @ref AVL_TREE_NULL if no entry with the given key is + * found. + */ + +AVLTreeValue avl_tree_lookup(AVLTree *tree, AVLTreeKey key); + +/** + * Find the root node of a tree. + * + * @param tree The tree. + * @return The root node of the tree, or NULL if the tree is + * empty. + */ + +AVLTreeNode *avl_tree_root_node(AVLTree *tree); + +/** + * Retrieve the key for a given tree node. + * + * @param node The tree node. + * @return The key to the given node. + */ + +AVLTreeKey avl_tree_node_key(AVLTreeNode *node); + +/** + * Retrieve the value at a given tree node. + * + * @param node The tree node. + * @return The value at the given node. + */ + +AVLTreeValue avl_tree_node_value(AVLTreeNode *node); + +/** + * Find the child of a given tree node. + * + * @param node The tree node. + * @param side Which child node to get (left or right) + * @return The child of the tree node, or NULL if the + * node has no child on the given side. + */ + +AVLTreeNode *avl_tree_node_child(AVLTreeNode *node, AVLTreeNodeSide side); + +/** + * Find the parent node of a given tree node. + * + * @param node The tree node. + * @return The parent node of the tree node, or NULL if + * this is the root node. + */ + +AVLTreeNode *avl_tree_node_parent(AVLTreeNode *node); + +/** + * Find the height of a subtree. + * + * @param node The root node of the subtree. + * @return The height of the subtree. + */ + +int avl_tree_subtree_height(AVLTreeNode *node); + +/** + * Convert the keys in an AVL tree into a C array. This allows + * the tree to be used as an ordered set. + * + * @param tree The tree. + * @return A newly allocated C array containing all the keys + * in the tree, in order. The length of the array + * is equal to the number of entries in the tree + * (see @ref avl_tree_num_entries). + */ + +AVLTreeValue *avl_tree_to_array(AVLTree *tree); + +/** + * Retrieve the number of entries in the tree. + * + * @param tree The tree. + * @return The number of key-value pairs stored in the tree. + */ + +int avl_tree_num_entries(AVLTree *tree); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_AVLTREE_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binary-heap.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binary-heap.h new file mode 100644 index 00000000..bd5ae630 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binary-heap.h @@ -0,0 +1,151 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file binary-heap.h + * + * @brief Binary heap. + * + * A binary heap is a heap data structure implemented using a + * binary tree. In a heap, values are ordered by priority. + * + * To create a binary heap, use @ref binary_heap_new. To destroy a + * binary heap, use @ref binary_heap_free. + * + * To insert a value into a binary heap, use @ref binary_heap_insert. + * + * To remove the first value from a binary heap, use @ref binary_heap_pop. + * + */ + +#ifndef ALGORITHM_BINARY_HEAP_H +#define ALGORITHM_BINARY_HEAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Heap type. If a heap is a min heap (@ref BINARY_HEAP_TYPE_MIN), the + * values with the lowest priority are stored at the top of the heap and + * will be the first returned. If a heap is a max heap + * (@ref BINARY_HEAP_TYPE_MAX), the values with the greatest priority are + * stored at the top of the heap. + */ + +typedef enum { + /** A minimum heap. */ + + BINARY_HEAP_TYPE_MIN, + + /** A maximum heap. */ + + BINARY_HEAP_TYPE_MAX +} BinaryHeapType; + +/** + * A value stored in a @ref BinaryHeap. + */ + +typedef void *BinaryHeapValue; + +/** + * A null @ref BinaryHeapValue. + */ + +#define BINARY_HEAP_NULL ((void *) 0) + +/** + * Type of function used to compare values in a binary heap. + * + * @param value1 The first value. + * @param value2 The second value. + * @return A negative number if value1 is less than value2, + * a positive number if value1 is greater than value2, + * zero if the two are equal. + */ + +typedef int (*BinaryHeapCompareFunc)(BinaryHeapValue value1, + BinaryHeapValue value2); + +/** + * A binary heap data structure. + */ + +typedef struct _BinaryHeap BinaryHeap; + +/** + * Create a new @ref BinaryHeap. + * + * @param heap_type The type of heap: min heap or max heap. + * @param compare_func Pointer to a function used to compare the priority + * of values in the heap. + * @return A new binary heap, or NULL if it was not possible + * to allocate the memory. + */ + +BinaryHeap *binary_heap_new(BinaryHeapType heap_type, + BinaryHeapCompareFunc compare_func); + +/** + * Destroy a binary heap. + * + * @param heap The heap to destroy. + */ + +void binary_heap_free(BinaryHeap *heap); + +/** + * Insert a value into a binary heap. + * + * @param heap The heap to insert into. + * @param value The value to insert. + * @return Non-zero if the entry was added, or zero if it + * was not possible to allocate memory for the new + * entry. + */ + +int binary_heap_insert(BinaryHeap *heap, BinaryHeapValue value); + +/** + * Remove the first value from a binary heap. + * + * @param heap The heap. + * @return The first value in the heap, or + * @ref BINARY_HEAP_NULL if the heap is empty. + */ + +BinaryHeapValue binary_heap_pop(BinaryHeap *heap); + +/** + * Find the number of values stored in a binary heap. + * + * @param heap The heap. + * @return The number of values in the heap. + */ + +int binary_heap_num_entries(BinaryHeap *heap); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_BINARY_HEAP_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binomial-heap.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binomial-heap.h new file mode 100644 index 00000000..5442bbe3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/binomial-heap.h @@ -0,0 +1,151 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file binomial-heap.h + * + * @brief Binomial heap. + * + * A binomial heap is a heap data structure implemented using a + * binomial tree. In a heap, values are ordered by priority. + * + * To create a binomial heap, use @ref binomial_heap_new. To destroy a + * binomial heap, use @ref binomial_heap_free. + * + * To insert a value into a binomial heap, use @ref binomial_heap_insert. + * + * To remove the first value from a binomial heap, use @ref binomial_heap_pop. + * + */ + +#ifndef ALGORITHM_BINOMIAL_HEAP_H +#define ALGORITHM_BINOMIAL_HEAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Heap type. If a heap is a min heap (@ref BINOMIAL_HEAP_TYPE_MIN), the + * values with the lowest priority are stored at the top of the heap and + * will be the first returned. If a heap is a max heap + * (@ref BINOMIAL_HEAP_TYPE_MAX), the values with the greatest priority + * are stored at the top of the heap. + */ + +typedef enum { + /** A minimum heap. */ + + BINOMIAL_HEAP_TYPE_MIN, + + /** A maximum heap. */ + + BINOMIAL_HEAP_TYPE_MAX +} BinomialHeapType; + +/** + * A value stored in a @ref BinomialHeap. + */ + +typedef void *BinomialHeapValue; + +/** + * A null @ref BinomialHeapValue. + */ + +#define BINOMIAL_HEAP_NULL ((void *) 0) + +/** + * Type of function used to compare values in a binomial heap. + * + * @param value1 The first value. + * @param value2 The second value. + * @return A negative number if value1 is less than value2, + * a positive number if value1 is greater than value2, + * zero if the two are equal. + */ + +typedef int (*BinomialHeapCompareFunc)(BinomialHeapValue value1, + BinomialHeapValue value2); + +/** + * A binomial heap data structure. + */ + +typedef struct _BinomialHeap BinomialHeap; + +/** + * Create a new @ref BinomialHeap. + * + * @param heap_type The type of heap: min heap or max heap. + * @param compare_func Pointer to a function used to compare the priority + * of values in the heap. + * @return A new binomial heap, or NULL if it was not possible + * to allocate the memory. + */ + +BinomialHeap *binomial_heap_new(BinomialHeapType heap_type, + BinomialHeapCompareFunc compare_func); + +/** + * Destroy a binomial heap. + * + * @param heap The heap to destroy. + */ + +void binomial_heap_free(BinomialHeap *heap); + +/** + * Insert a value into a binomial heap. + * + * @param heap The heap to insert into. + * @param value The value to insert. + * @return Non-zero if the entry was added, or zero if it + * was not possible to allocate memory for the new + * entry. + */ + +int binomial_heap_insert(BinomialHeap *heap, BinomialHeapValue value); + +/** + * Remove the first value from a binomial heap. + * + * @param heap The heap. + * @return The first value in the heap, or + * @ref BINOMIAL_HEAP_NULL if the heap is empty. + */ + +BinomialHeapValue binomial_heap_pop(BinomialHeap *heap); + +/** + * Find the number of values stored in a binomial heap. + * + * @param heap The heap. + * @return The number of values in the heap. + */ + +int binomial_heap_num_entries(BinomialHeap *heap); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_BINOMIAL_HEAP_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/bloom-filter.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/bloom-filter.h new file mode 100644 index 00000000..ae20a3df --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/bloom-filter.h @@ -0,0 +1,193 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file bloom-filter.h + * + * @brief Bloom filter + * + * A bloom filter is a space efficient data structure that can be + * used to test whether a given element is part of a set. Lookups + * will occasionally generate false positives, but never false + * negatives. + * + * To create a bloom filter, use @ref bloom_filter_new. To destroy a + * bloom filter, use @ref bloom_filter_free. + * + * To insert a value into a bloom filter, use @ref bloom_filter_insert. + * + * To query whether a value is part of the set, use + * @ref bloom_filter_query. + */ + +#ifndef ALGORITHM_BLOOM_FILTER_H +#define ALGORITHM_BLOOM_FILTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A bloom filter structure. + */ + +typedef struct _BloomFilter BloomFilter; + +/** + * A value stored in a @ref BloomFilter. + */ + +typedef void *BloomFilterValue; + +/** + * Hash function used to generate hash values for values inserted into a + * bloom filter. + * + * @param data The value to generate a hash value for. + * @return The hash value. + */ + +typedef unsigned long (*BloomFilterHashFunc)(BloomFilterValue data); + +/** + * Create a new bloom filter. + * + * @param table_size The size of the bloom filter. The greater + * the table size, the more elements can be + * stored, and the lesser the chance of false + * positives. + * @param hash_func Hash function to use on values stored in the + * filter. + * @param num_functions Number of hash functions to apply to each + * element on insertion. This running time for + * insertion and queries is proportional to this + * value. The more functions applied, the lesser + * the chance of false positives. The maximum + * number of functions is 64. + * @return A new hash table structure, or NULL if it + * was not possible to allocate the new bloom + * filter. + */ + +BloomFilter *bloom_filter_new(unsigned int table_size, + BloomFilterHashFunc hash_func, + unsigned int num_functions); + +/** + * Destroy a bloom filter. + * + * @param bloomfilter The bloom filter to destroy. + */ + +void bloom_filter_free(BloomFilter *bloomfilter); + +/** + * Insert a value into a bloom filter. + * + * @param bloomfilter The bloom filter. + * @param value The value to insert. + */ + +void bloom_filter_insert(BloomFilter *bloomfilter, BloomFilterValue value); + +/** + * Query a bloom filter for a particular value. + * + * @param bloomfilter The bloom filter. + * @param value The value to look up. + * @return Zero if the value was definitely not + * inserted into the filter. Non-zero + * indicates that it either may or may not + * have been inserted. + */ + +int bloom_filter_query(BloomFilter *bloomfilter, BloomFilterValue value); + +/** + * Read the contents of a bloom filter into an array. + * + * @param bloomfilter The bloom filter. + * @param array Pointer to the array to read into. This + * should be (table_size + 7) / 8 bytes in + * length. + */ + +void bloom_filter_read(BloomFilter *bloomfilter, unsigned char *array); + +/** + * Load the contents of a bloom filter from an array. + * The data loaded should be the output read from @ref bloom_filter_read, + * from a bloom filter created using the same arguments used to create + * the original filter. + * + * @param bloomfilter The bloom filter. + * @param array Pointer to the array to load from. This + * should be (table_size + 7) / 8 bytes in + * length. + */ + +void bloom_filter_load(BloomFilter *bloomfilter, unsigned char *array); + +/** + * Find the union of two bloom filters. Values are present in the + * resulting filter if they are present in either of the original + * filters. + * + * Both of the original filters must have been created using the + * same parameters to @ref bloom_filter_new. + * + * @param filter1 The first filter. + * @param filter2 The second filter. + * @return A new filter which is an intersection of the + * two filters, or NULL if it was not possible + * to allocate memory for the new filter, or + * if the two filters specified were created + * with different parameters. + */ + +BloomFilter *bloom_filter_union(BloomFilter *filter1, + BloomFilter *filter2); + +/** + * Find the intersection of two bloom filters. Values are only ever + * present in the resulting filter if they are present in both of the + * original filters. + * + * Both of the original filters must have been created using the + * same parameters to @ref bloom_filter_new. + * + * @param filter1 The first filter. + * @param filter2 The second filter. + * @return A new filter which is an intersection of the + * two filters, or NULL if it was not possible + * to allocate memory for the new filter, or + * if the two filters specified were created + * with different parameters. + */ + +BloomFilter *bloom_filter_intersection(BloomFilter *filter1, + BloomFilter *filter2); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_BLOOM_FILTER_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-int.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-int.h new file mode 100644 index 00000000..22269df3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-int.h @@ -0,0 +1,69 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file compare-int.h + * + * Comparison functions for pointers to integers. + * + * To find the difference between two values pointed at, use + * @ref int_compare. + * + * To find if two values pointed at are equal, use @ref int_equal. + */ + +#ifndef ALGORITHM_COMPARE_INT_H +#define ALGORITHM_COMPARE_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Compare the integer values pointed at by two pointers to determine + * if they are equal. + * + * @param location1 Pointer to the first value to compare. + * @param location2 Pointer to the second value to compare. + * @return Non-zero if the two values are equal, zero if the + * two values are not equal. + */ + +int int_equal(void *location1, void *location2); + +/** + * Compare the integer values pointed at by two pointers. + * + * @param location1 Pointer to the first value to compare. + * @param location2 Pointer to the second value to compare. + * @return A negative value if the first value is less than + * the second value, a positive value if the first + * value is greater than the second value, zero if + * they are equal. + */ + +int int_compare(void *location1, void *location2); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_COMPARE_INT_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-pointer.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-pointer.h new file mode 100644 index 00000000..28a4009d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-pointer.h @@ -0,0 +1,67 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file compare-pointer.h + * + * Comparison functions for generic (void) pointers. + * + * To find the difference between two pointers, use @ref pointer_compare. + * + * To find if two pointers are equal, use @ref pointer_equal. + */ + +#ifndef ALGORITHM_COMPARE_POINTER_H +#define ALGORITHM_COMPARE_POINTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Compare two pointers to determine if they are equal. + * + * @param location1 The first pointer. + * @param location2 The second pointer. + * @return Non-zero if the pointers are equal, zero if they + * are not equal. + */ + +int pointer_equal(void *location1, void *location2); + +/** + * Compare two pointers. + * + * @param location1 The first pointer. + * @param location2 The second pointer. + * @return A negative value if the first pointer is in a lower + * memory address than the second, a positive value if + * the first pointer is in a higher memory address than + * the second, zero if they point to the same location. + */ + +int pointer_compare(void *location1, void *location2); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_COMPARE_POINTER_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-string.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-string.h new file mode 100644 index 00000000..51826a48 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/compare-string.h @@ -0,0 +1,95 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file compare-string.h + * + * Comparison functions for strings. + * + * To find the difference between two strings, use @ref string_compare. + * + * To find if two strings are equal, use @ref string_equal. + * + * For case insensitive versions, see @ref string_nocase_compare and + * @ref string_nocase_equal. + */ + +#ifndef ALGORITHM_COMPARE_STRING_H +#define ALGORITHM_COMPARE_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Compare two strings to determine if they are equal. + * + * @param string1 The first string. + * @param string2 The second string. + * @return Non-zero if the strings are equal, zero if they are + * not equal. + */ + +int string_equal(void *string1, void *string2); + +/** + * Compare two strings. + * + * @param string1 The first string. + * @param string2 The second string. + * @return A negative value if the first string should be + * sorted before the second, a positive value if the + * first string should be sorted after the second, + * zero if the two strings are equal. + */ + +int string_compare(void *string1, void *string2); + +/** + * Compare two strings to determine if they are equal, ignoring the + * case of letters. + * + * @param string1 The first string. + * @param string2 The second string. + * @return Non-zero if the strings are equal, zero if they are + * not equal. + */ + +int string_nocase_equal(void *string1, void *string2); + +/** + * Compare two strings, ignoring the case of letters. + * + * @param string1 The first string. + * @param string2 The second string. + * @return A negative value if the first string should be + * sorted before the second, a positive value if the + * first string should be sorted after the second, + * zero if the two strings are equal. + */ + +int string_nocase_compare(void *string1, void *string2); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_COMPARE_STRING_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-int.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-int.h new file mode 100644 index 00000000..3babc81a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-int.h @@ -0,0 +1,49 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file hash-int.h + * + * Hash function for a pointer to an integer. See @ref int_hash. + */ + +#ifndef ALGORITHM_HASH_INT_H +#define ALGORITHM_HASH_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generate a hash key for a pointer to an integer. The value pointed + * at is used to generate the key. + * + * @param location The pointer. + * @return A hash key for the value at the location. + */ + +unsigned long int_hash(void *location); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_HASH_INT_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-pointer.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-pointer.h new file mode 100644 index 00000000..82660b0f --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-pointer.h @@ -0,0 +1,49 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file hash-pointer.h + * + * Hash function for a generic (void) pointer. See @ref pointer_hash. + */ + +#ifndef ALGORITHM_HASH_POINTER_H +#define ALGORITHM_HASH_POINTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generate a hash key for a pointer. The value pointed at by the pointer + * is not used, only the pointer itself. + * + * @param location The pointer + * @return A hash key for the pointer. + */ + +unsigned long pointer_hash(void *location); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_HASH_POINTER_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-string.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-string.h new file mode 100644 index 00000000..12f3de12 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-string.h @@ -0,0 +1,58 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file hash-string.h + * + * Hash functions for text strings. For more information + * see @ref string_hash or @ref string_nocase_hash. + */ + +#ifndef ALGORITHM_HASH_STRING_H +#define ALGORITHM_HASH_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generate a hash key from a string. + * + * @param string The string. + * @return A hash key for the string. + */ + +unsigned long string_hash(void *string); + +/** + * Generate a hash key from a string, ignoring the case of letters. + * + * @param string The string. + * @return A hash key for the string. + */ + +unsigned long string_nocase_hash(void *string); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_HASH_STRING_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-table.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-table.h new file mode 100644 index 00000000..e4f6e355 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/hash-table.h @@ -0,0 +1,253 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file hash-table.h + * + * @brief Hash table. + * + * A hash table stores a set of values which can be addressed by a + * key. Given the key, the corresponding value can be looked up + * quickly. + * + * To create a hash table, use @ref hash_table_new. To destroy a + * hash table, use @ref hash_table_free. + * + * To insert a value into a hash table, use @ref hash_table_insert. + * + * To remove a value from a hash table, use @ref hash_table_remove. + * + * To look up a value by its key, use @ref hash_table_lookup. + * + * To iterate over all values in a hash table, use + * @ref hash_table_iterate to initialise a @ref HashTableIterator + * structure. Each value can then be read in turn using + * @ref hash_table_iter_next and @ref hash_table_iter_has_more. + */ + +#ifndef ALGORITHM_HASH_TABLE_H +#define ALGORITHM_HASH_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A hash table structure. + */ + +typedef struct _HashTable HashTable; + +/** + * Structure used to iterate over a hash table. + */ + +typedef struct _HashTableIterator HashTableIterator; + +/** + * Internal structure representing an entry in a hash table. + */ + +typedef struct _HashTableEntry HashTableEntry; + +/** + * A key to look up a value in a @ref HashTable. + */ + +typedef void *HashTableKey; + +/** + * A value stored in a @ref HashTable. + */ + +typedef void *HashTableValue; + +/** + * Definition of a @ref HashTableIterator. + */ + +struct _HashTableIterator { + HashTable *hash_table; + HashTableEntry *next_entry; + int next_chain; +}; + +/** + * A null @ref HashTableValue. + */ + +#define HASH_TABLE_NULL ((void *) 0) + +/** + * Hash function used to generate hash values for keys used in a hash + * table. + * + * @param value The value to generate a hash value for. + * @return The hash value. + */ + +typedef unsigned long (*HashTableHashFunc)(HashTableKey value); + +/** + * Function used to compare two keys for equality. + * + * @return Non-zero if the two keys are equal, zero if the keys are + * not equal. + */ + +typedef int (*HashTableEqualFunc)(HashTableKey value1, HashTableKey value2); + +/** + * Type of function used to free keys when entries are removed from a + * hash table. + */ + +typedef void (*HashTableKeyFreeFunc)(HashTableKey value); + +/** + * Type of function used to free values when entries are removed from a + * hash table. + */ + +typedef void (*HashTableValueFreeFunc)(HashTableValue value); + +/** + * Create a new hash table. + * + * @param hash_func Function used to generate hash keys for the + * keys used in the table. + * @param equal_func Function used to test keys used in the table + * for equality. + * @return A new hash table structure, or NULL if it + * was not possible to allocate the new hash + * table. + */ + +HashTable *hash_table_new(HashTableHashFunc hash_func, + HashTableEqualFunc equal_func); + +/** + * Destroy a hash table. + * + * @param hash_table The hash table to destroy. + */ + +void hash_table_free(HashTable *hash_table); + +/** + * Register functions used to free the key and value when an entry is + * removed from a hash table. + * + * @param hash_table The hash table. + * @param key_free_func Function used to free keys. + * @param value_free_func Function used to free values. + */ + +void hash_table_register_free_functions(HashTable *hash_table, + HashTableKeyFreeFunc key_free_func, + HashTableValueFreeFunc value_free_func); + +/** + * Insert a value into a hash table, overwriting any existing entry + * using the same key. + * + * @param hash_table The hash table. + * @param key The key for the new value. + * @param value The value to insert. + * @return Non-zero if the value was added successfully, + * or zero if it was not possible to allocate + * memory for the new entry. + */ + +int hash_table_insert(HashTable *hash_table, + HashTableKey key, + HashTableValue value); + +/** + * Look up a value in a hash table by key. + * + * @param hash_table The hash table. + * @param key The key of the value to look up. + * @return The value, or @ref HASH_TABLE_NULL if there + * is no value with that key in the hash table. + */ + +HashTableValue hash_table_lookup(HashTable *hash_table, + HashTableKey key); + +/** + * Remove a value from a hash table. + * + * @param hash_table The hash table. + * @param key The key of the value to remove. + * @return Non-zero if a key was removed, or zero if the + * specified key was not found in the hash table. + */ + +int hash_table_remove(HashTable *hash_table, HashTableKey key); + +/** + * Retrieve the number of entries in a hash table. + * + * @param hash_table The hash table. + * @return The number of entries in the hash table. + */ + +int hash_table_num_entries(HashTable *hash_table); + +/** + * Initialise a @ref HashTableIterator to iterate over a hash table. + * + * @param hash_table The hash table. + * @param iter Pointer to an iterator structure to + * initialise. + */ + +void hash_table_iterate(HashTable *hash_table, HashTableIterator *iter); + +/** + * Determine if there are more keys in the hash table to iterate + * over. + * + * @param iterator The hash table iterator. + * @return Zero if there are no more values to iterate + * over, non-zero if there are more values to + * iterate over. + */ + +int hash_table_iter_has_more(HashTableIterator *iterator); + +/** + * Using a hash table iterator, retrieve the next key. + * + * @param iterator The hash table iterator. + * @return The next key from the hash table, or + * @ref HASH_TABLE_NULL if there are no more + * keys to iterate over. + */ + +HashTableValue hash_table_iter_next(HashTableIterator *iterator); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_HASH_TABLE_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/libcalg.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/libcalg.h new file mode 100644 index 00000000..9ab75d58 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/libcalg.h @@ -0,0 +1,54 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#ifndef LIBCALG_H +#define LIBCALG_H + +#ifdef __cpluscplus +extern "C" { +#endif /*__cplusplus */ + +#include <CxxUtils/libcalg/compare-int.h> +#include <CxxUtils/libcalg/compare-pointer.h> +#include <CxxUtils/libcalg/compare-string.h> + +#include <CxxUtils/libcalg/hash-int.h> +#include <CxxUtils/libcalg/hash-pointer.h> +#include <CxxUtils/libcalg/hash-string.h> + +#include <CxxUtils/libcalg/arraylist.h> +#include <CxxUtils/libcalg/avl-tree.h> +#include <CxxUtils/libcalg/binary-heap.h> +#include <CxxUtils/libcalg/binomial-heap.h> +#include <CxxUtils/libcalg/bloom-filter.h> +#include <CxxUtils/libcalg/hash-table.h> +#include <CxxUtils/libcalg/list.h> +#include <CxxUtils/libcalg/queue.h> +#include <CxxUtils/libcalg/set.h> +#include <CxxUtils/libcalg/slist.h> +#include <CxxUtils/libcalg/trie.h> + +#ifdef __cpluscplus +} +#endif /*__cplusplus */ + +#endif /* #ifndef LIBCALG_H */ + + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/list.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/list.h new file mode 100644 index 00000000..add3e78d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/list.h @@ -0,0 +1,312 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file list.h + * + * @brief Doubly-linked list. + * + * A doubly-linked list stores a collection of values. Each entry in + * the list (represented by a pointer a @ref ListEntry structure) + * contains a link to the next entry and the previous entry. + * It is therefore possible to iterate over entries in the list in either + * direction. + * + * To create an empty list, create a new variable which is a pointer to + * a @ref ListEntry structure, and initialise it to NULL. + * To destroy an entire list, use @ref list_free. + * + * To add a value to a list, use @ref list_append or @ref list_prepend. + * + * To remove a value from a list, use @ref list_remove_entry or + * @ref list_remove_data. + * + * To iterate over entries in a list, use @ref list_iterate to initialise + * a @ref ListIterator structure, with @ref list_iter_next and + * @ref list_iter_has_more to retrieve each value in turn. + * @ref list_iter_remove can be used to remove the current entry. + * + * To access an entry in the list by index, use @ref list_nth_entry or + * @ref list_nth_data. + * + * To sort a list, use @ref list_sort. + * + */ + +#ifndef ALGORITHM_LIST_H +#define ALGORITHM_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Represents an entry in a doubly-linked list. The empty list is + * represented by a NULL pointer. To initialise a new doubly linked + * list, simply create a variable of this type + * containing a pointer to NULL. + */ + +typedef struct _ListEntry ListEntry; + +/** + * Structure used to iterate over a list. + */ + +typedef struct _ListIterator ListIterator; + +/** + * A value stored in a list. + */ + +typedef void *ListValue; + +/** + * Definition of a @ref ListIterator. + */ + +struct _ListIterator { + ListEntry **prev_next; + ListEntry *current; +}; + +/** + * A null @ref ListValue. + */ + +#define LIST_NULL ((void *) 0) + +/** + * Callback function used to compare values in a list when sorting. + * + * @param value1 The first value to compare. + * @param value2 The second value to compare. + * @return A negative value if value1 should be sorted before + * value2, a positive value if value1 should be sorted + * after value2, zero if value1 and value2 are equal. + */ + +typedef int (*ListCompareFunc)(ListValue value1, ListValue value2); + +/** + * Callback function used to determine of two values in a list are + * equal. + * + * @param value1 The first value to compare. + * @param value2 The second value to compare. + * @return A non-zero value if value1 and value2 are equal, zero + * if they are not equal. + */ + +typedef int (*ListEqualFunc)(ListValue value1, ListValue value2); + +/** + * Free an entire list. + * + * @param list The list to free. + */ + +void list_free(ListEntry *list); + +/** + * Prepend a value to the start of a list. + * + * @param list Pointer to the list to prepend to. + * @param data The value to prepend. + * @return The new entry in the list, or NULL if it was not + * possible to allocate the memory for the new entry. + */ + +ListEntry *list_prepend(ListEntry **list, ListValue data); + +/** + * Append a value to the end of a list. + * + * @param list Pointer to the list to append to. + * @param data The value to append. + * @return The new entry in the list, or NULL if it was not + * possible to allocate the memory for the new entry. + */ + +ListEntry *list_append(ListEntry **list, ListValue data); + +/** + * Retrieve the previous entry in a list. + * + * @param listentry Pointer to the list entry. + * @return The previous entry in the list, or NULL if this + * was the first entry in the list. + */ + +ListEntry *list_prev(ListEntry *listentry); + +/** + * Retrieve the next entry in a list. + * + * @param listentry Pointer to the list entry. + * @return The next entry in the list, or NULL if this was the + * last entry in the list. + */ + +ListEntry *list_next(ListEntry *listentry); + +/** + * Retrieve the value at a list entry. + * + * @param listentry Pointer to the list entry. + * @return The value stored at the list entry. + */ + +ListValue list_data(ListEntry *listentry); + +/** + * Retrieve the entry at a specified index in a list. + * + * @param list The list. + * @param n The index into the list . + * @return The entry at the specified index, or NULL if out of range. + */ + +ListEntry *list_nth_entry(ListEntry *list, int n); + +/** + * Retrieve the value at a specified index in the list. + * + * @param list The list. + * @param n The index into the list. + * @return The value at the specified index, or @ref LIST_NULL if + * unsuccessful. + */ + +ListValue list_nth_data(ListEntry *list, int n); + +/** + * Find the length of a list. + * + * @param list The list. + * @return The number of entries in the list. + */ + +int list_length(ListEntry *list); + +/** + * Create a C array containing the contents of a list. + * + * @param list The list. + * @return A newly-allocated C array containing all values in the + * list, or NULL if it was not possible to allocate the + * memory. The length of the array is equal to the length + * of the list (see @ref list_length). + */ + +ListValue *list_to_array(ListEntry *list); + +/** + * Remove an entry from a list. + * + * @param list Pointer to the list. + * @param entry The list entry to remove . + * @return If the entry is not found in the list, returns zero, + * else returns non-zero. + */ + +int list_remove_entry(ListEntry **list, ListEntry *entry); + +/** + * Remove all occurrences of a particular value from a list. + * + * @param list Pointer to the list. + * @param callback Function to invoke to compare values in the list + * with the value to be removed. + * @param data The value to remove from the list. + * @return The number of entries removed from the list. + */ + +int list_remove_data(ListEntry **list, ListEqualFunc callback, ListValue data); + +/** + * Sort a list. + * + * @param list Pointer to the list to sort. + * @param compare_func Function used to compare values in the list. + */ + +void list_sort(ListEntry **list, ListCompareFunc compare_func); + +/** + * Find the entry for a particular value in a list. + * + * @param list The list to search. + * @param callback Function to invoke to compare values in the list + * with the value to be searched for. + * @param data The value to search for. + * @return The list entry of the item being searched for, or + * NULL if not found. + */ + +ListEntry *list_find_data(ListEntry *list, + ListEqualFunc callback, + ListValue data); + +/** + * Initialise a @ref ListIterator structure to iterate over a list. + * + * @param list A pointer to the list to iterate over. + * @param iter A pointer to an iterator structure to initialise. + */ + +void list_iterate(ListEntry **list, ListIterator *iter); + +/** + * Determine if there are more values in the list to iterate over. + * + * @param iterator The list iterator. + * @return Zero if there are no more values in the list to + * iterate over, non-zero if there are more values to + * read. + */ + +int list_iter_has_more(ListIterator *iterator); + +/** + * Using a list iterator, retrieve the next value from the list. + * + * @param iterator The list iterator. + * @return The next value from the list, or @ref LIST_NULL if + * there are no more values in the list. + */ + +ListValue list_iter_next(ListIterator *iterator); + +/** + * Delete the current entry in the list (the value last returned from + * list_iter_next) + * + * @param iterator The list iterator. + */ + +void list_iter_remove(ListIterator *iterator); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_LIST_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/queue.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/queue.h new file mode 100644 index 00000000..5dbcad88 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/queue.h @@ -0,0 +1,164 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file queue.h + * + * @brief Double-ended queue. + * + * A double ended queue stores a list of values in order. New values + * can be added and removed from either end of the queue. + * + * To create a new queue, use @ref queue_new. To destroy a queue, use + * @ref queue_free. + * + * To add values to a queue, use @ref queue_push_head and + * @ref queue_push_tail. + * + * To read values from the ends of a queue, use @ref queue_pop_head + * and @ref queue_pop_tail. To examine the ends without removing values + * from the queue, use @ref queue_peek_head and @ref queue_peek_tail. + * + */ + +#ifndef ALGORITHM_QUEUE_H +#define ALGORITHM_QUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A double-ended queue. + */ + +typedef struct _Queue Queue; + +/** + * A value stored in a @ref Queue. + */ + +typedef void *QueueValue; + +/** + * A null @ref QueueValue. + */ + +#define QUEUE_NULL ((void *) 0) + +/** + * Create a new double-ended queue. + * + * @return A new queue, or NULL if it was not possible to allocate + * the memory. + */ + +Queue *queue_new(void); + +/** + * Destroy a queue. + * + * @param queue The queue to destroy. + */ + +void queue_free(Queue *queue); + +/** + * Add a value to the head of a queue. + * + * @param queue The queue. + * @param data The value to add. + * @return Non-zero if the value was added successfully, or zero + * if it was not possible to allocate the memory for the + * new entry. + */ + +int queue_push_head(Queue *queue, QueueValue data); + +/** + * Remove a value from the head of a queue. + * + * @param queue The queue. + * @return Value that was at the head of the queue, or + * @ref QUEUE_NULL if the queue is empty. + */ + +QueueValue queue_pop_head(Queue *queue); + +/** + * Read value from the head of a queue, without removing it from + * the queue. + * + * @param queue The queue. + * @return Value at the head of the queue, or @ref QUEUE_NULL if the + * queue is empty. + */ + +QueueValue queue_peek_head(Queue *queue); + +/** + * Add a value to the tail of a queue. + * + * @param queue The queue. + * @param data The value to add. + * @return Non-zero if the value was added successfully, or zero + * if it was not possible to allocate the memory for the + * new entry. + */ + +int queue_push_tail(Queue *queue, QueueValue data); + +/** + * Remove a value from the tail of a queue. + * + * @param queue The queue. + * @return Value that was at the head of the queue, or + * @ref QUEUE_NULL if the queue is empty. + */ + +QueueValue queue_pop_tail(Queue *queue); + +/** + * Read a value from the tail of a queue, without removing it from + * the queue. + * + * @param queue The queue. + * @return Value at the tail of the queue, or QUEUE_NULL if the + * queue is empty. + */ + +QueueValue queue_peek_tail(Queue *queue); + +/** + * Query if any values are currently in a queue. + * + * @param queue The queue. + * @return Zero if the queue is not empty, non-zero if the queue + * is empty. + */ + +int queue_is_empty(Queue *queue); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_QUEUE_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/set.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/set.h new file mode 100644 index 00000000..5a90d7d4 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/set.h @@ -0,0 +1,264 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file set.h + * + * @brief Set of values. + * + * A set stores a collection of values. Each value can only exist once in + * the set. + * + * To create a new set, use @ref set_new. To destroy a set, use + * @ref set_free. + * + * To add a value to a set, use @ref set_insert. To remove a value + * from a set, use @ref set_remove. + * + * To find the number of entries in a set, use @ref set_num_entries. + * + * To query if a particular value is in a set, use @ref set_query. + * + * To iterate over all values in a set, use @ref set_iterate to initialise + * a @ref SetIterator structure, with @ref set_iter_next and + * @ref set_iter_has_more to read each value in turn. + * + * Two sets can be combined (union) using @ref set_union, while the + * intersection of two sets can be generated using @ref set_intersection. + */ + +#ifndef ALGORITHM_SET_H +#define ALGORITHM_SET_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Represents a set of values. Created using the @ref set_new function and + * destroyed using the @ref set_free function. + */ + +typedef struct _Set Set; + +/** + * An object used to iterate over a set. + * + * @see set_iterate + */ + +typedef struct _SetIterator SetIterator; + +/** + * Internal structure representing an entry in the set. + */ + +typedef struct _SetEntry SetEntry; + +/** + * A value stored in a @ref Set. + */ + +typedef void *SetValue; + +/** + * Definition of a @ref SetIterator. + */ + +struct _SetIterator { + Set *set; + SetEntry *next_entry; + int next_chain; +}; + +/** + * A null @ref SetValue. + */ + +#define SET_NULL ((void *) 0) + +/** + * Hash function. Generates a hash key for values to be stored in a set. + */ + +typedef unsigned long (*SetHashFunc)(SetValue value); + +/** + * Equality function. Compares two values to determine if they are + * equivalent. + */ + +typedef int (*SetEqualFunc)(SetValue value1, SetValue value2); + +/** + * Function used to free values stored in a set. See + * @ref set_register_free_function. + */ + +typedef void (*SetFreeFunc)(SetValue value); + +/** + * Create a new set. + * + * @param hash_func Hash function used on values in the set. + * @param equal_func Compares two values in the set to determine + * if they are equal. + * @return A new set, or NULL if it was not possible to + * allocate the memory for the set. + */ + +Set *set_new(SetHashFunc hash_func, SetEqualFunc equal_func); + +/** + * Destroy a set. + * + * @param set The set to destroy. + */ + +void set_free(Set *set); + +/** + * Register a function to be called when values are removed from + * the set. + * + * @param set The set. + * @param free_func Function to call when values are removed from the + * set. + */ + +void set_register_free_function(Set *set, SetFreeFunc free_func); + +/** + * Add a value to a set. + * + * @param set The set. + * @param data The value to add to the set. + * @return Non-zero (true) if the value was added to the set, + * zero (false) if it already exists in the set, or + * if it was not possible to allocate memory for the + * new entry. + */ + +int set_insert(Set *set, SetValue data); + +/** + * Remove a value from a set. + * + * @param set The set. + * @param data The value to remove from the set. + * @return Non-zero (true) if the value was found and removed + * from the set, zero (false) if the value was not + * found in the set. + */ + +int set_remove(Set *set, SetValue data); + +/** + * Query if a particular value is in a set. + * + * @param set The set. + * @param data The value to query for. + * @return Zero if the value is not in the set, non-zero if the + * value is in the set. + */ + +int set_query(Set *set, SetValue data); + +/** + * Retrieve the number of entries in a set + * + * @param set The set. + * @return A count of the number of entries in the set. + */ + +int set_num_entries(Set *set); + +/** + * Create an array containing all entries in a set. + * + * @param set The set. + * @return An array containing all entries in the set, + * or NULL if it was not possible to allocate + * memory for the array. + */ + +SetValue *set_to_array(Set *set); + +/** + * Perform a union of two sets. + * + * @param set1 The first set. + * @param set2 The second set. + * @return A new set containing all values which are in the + * first or second sets, or NULL if it was not + * possible to allocate memory for the new set. + */ + +Set *set_union(Set *set1, Set *set2); + +/** + * Perform an intersection of two sets. + * + * @param set1 The first set. + * @param set2 The second set. + * @return A new set containing all values which are in both + * set, or NULL if it was not possible to allocate + * memory for the new set. + */ + +Set *set_intersection(Set *set1, Set *set2); + +/** + * Initialise a @ref SetIterator structure to iterate over the values + * in a set. + * + * @param set The set to iterate over. + * @param iter Pointer to an iterator structure to initialise. + */ + +void set_iterate(Set *set, SetIterator *iter); + +/** + * Determine if there are more values in the set to iterate over. + * + * @param iterator The set iterator object. + * @return Zero if there are no more values in the set + * to iterate over, non-zero if there are more + * values to be read. + */ + +int set_iter_has_more(SetIterator *iterator); + +/** + * Using a set iterator, retrieve the next value from the set. + * + * @param iterator The set iterator. + * @return The next value from the set, or @ref SET_NULL if no + * more values are available. + */ + +SetValue set_iter_next(SetIterator *iterator); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_SET_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/slist.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/slist.h new file mode 100644 index 00000000..4eb85e63 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/slist.h @@ -0,0 +1,314 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file slist.h + * + * Singly-linked list. + * + * A singly-linked list stores a collection of values. Each + * entry in the list (represented by a pointer to a @ref SListEntry + * structure) contains a link to the next entry. It is only + * possible to iterate over entries in a singly linked list in one + * direction. + * + * To create a new singly-linked list, create a variable which is + * a pointer to a @ref SListEntry, and initialise it to NULL. + * + * To destroy a singly linked list, use @ref slist_free. + * + * To add a new value at the start of a list, use @ref slist_prepend. + * To add a new value at the end of a list, use @ref slist_append. + * + * To find the length of a list, use @ref slist_length. + * + * To access a value in a list by its index in the list, use + * @ref slist_nth_data. + * + * To search a list for a value, use @ref slist_find_data. + * + * To sort a list into an order, use @ref slist_sort. + * + * To find a particular entry in a list by its index, use + * @ref slist_nth_entry. + * + * To iterate over each value in a list, use @ref slist_iterate to + * initialise a @ref SListIterator structure, with @ref slist_iter_next + * and @ref slist_iter_has_more to retrieve each value in turn. + * @ref slist_iter_remove can be used to efficiently remove the + * current entry from the list. + * + * Given a particular entry in a list (@ref SListEntry): + * + * @li To find the next entry, use @ref slist_next. + * @li To access the value stored at the entry, use @ref slist_data. + * @li To remove the entry, use @ref slist_remove_entry. + * + */ + +#ifndef ALGORITHM_SLIST_H +#define ALGORITHM_SLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Represents an entry in a singly-linked list. The empty list is + * represented by a NULL pointer. To initialise a new singly linked + * list, simply create a variable of this type + * containing a pointer to NULL. + */ + +typedef struct _SListEntry SListEntry; + +/** + * Structure used to iterate over a list. + */ + +typedef struct _SListIterator SListIterator; + +/** + * Value stored in a list. + */ + +typedef void *SListValue; + +/** + * Definition of a @ref SListIterator. + */ + +struct _SListIterator { + SListEntry **prev_next; + SListEntry *current; +}; + +/** + * A null @ref SListValue. + */ + +#define SLIST_NULL ((void *) 0) + +/** + * Callback function used to compare values in a list when sorting. + * + * @return A negative value if value1 should be sorted before value2, + * a positive value if value1 should be sorted after value2, + * zero if value1 and value2 are equal. + */ + +typedef int (*SListCompareFunc)(SListValue value1, SListValue value2); + +/** + * Callback function used to determine of two values in a list are + * equal. + * + * @return A non-zero value if value1 and value2 are equal, zero if they + * are not equal. + */ + +typedef int (*SListEqualFunc)(SListValue value1, SListValue value2); + +/** + * Free an entire list. + * + * @param list The list to free. + */ + +void slist_free(SListEntry *list); + +/** + * Prepend a value to the start of a list. + * + * @param list Pointer to the list to prepend to. + * @param data The value to prepend. + * @return The new entry in the list, or NULL if it was not possible + * to allocate a new entry. + */ + +SListEntry *slist_prepend(SListEntry **list, SListValue data); + +/** + * Append a value to the end of a list. + * + * @param list Pointer to the list to append to. + * @param data The value to append. + * @return The new entry in the list, or NULL if it was not possible + * to allocate a new entry. + */ + +SListEntry *slist_append(SListEntry **list, SListValue data); + +/** + * Retrieve the next entry in a list. + * + * @param listentry Pointer to the list entry. + * @return The next entry in the list. + */ + +SListEntry *slist_next(SListEntry *listentry); + +/** + * Retrieve the value stored at a list entry. + * + * @param listentry Pointer to the list entry. + * @return The value at the list entry. + */ + +SListValue slist_data(SListEntry *listentry); + +/** + * Retrieve the entry at a specified index in a list. + * + * @param list The list. + * @param n The index into the list . + * @return The entry at the specified index, or NULL if out of range. + */ + +SListEntry *slist_nth_entry(SListEntry *list, int n); + +/** + * Retrieve the value stored at a specified index in the list. + * + * @param list The list. + * @param n The index into the list. + * @return The value stored at the specified index, or + * @ref SLIST_NULL if unsuccessful. + */ + +SListValue slist_nth_data(SListEntry *list, int n); + +/** + * Find the length of a list. + * + * @param list The list. + * @return The number of entries in the list. + */ + +int slist_length(SListEntry *list); + +/** + * Create a C array containing the contents of a list. + * + * @param list The list. + * @return A newly-allocated C array containing all values in the + * list, or NULL if it was not possible to allocate the + * memory for the array. The length of the array is + * equal to the length of the list (see @ref slist_length). + */ + +SListValue *slist_to_array(SListEntry *list); + +/** + * Remove an entry from a list. + * + * @param list Pointer to the list. + * @param entry The list entry to remove. + * @return If the entry is not found in the list, returns zero, + * else returns non-zero. + */ + +int slist_remove_entry(SListEntry **list, SListEntry *entry); + +/** + * Remove all occurrences of a particular value from a list. + * + * @param list Pointer to the list. + * @param callback Callback function to invoke to compare values in the + * list with the value to remove. + * @param data The value to remove from the list. + * @return The number of entries removed from the list. + */ + +int slist_remove_data(SListEntry **list, + SListEqualFunc callback, + SListValue data); + +/** + * Sort a list. + * + * @param list Pointer to the list to sort. + * @param compare_func Function used to compare values in the list. + */ + +void slist_sort(SListEntry **list, SListCompareFunc compare_func); + +/** + * Find the entry for a particular value in a list. + * + * @param list The list to search. + * @param callback Callback function to be invoked to determine if + * values in the list are equal to the value to be + * searched for. + * @param data The value to search for. + * @return The list entry of the value being searched for, or + * NULL if not found. + */ + +SListEntry *slist_find_data(SListEntry *list, + SListEqualFunc callback, + SListValue data); + +/** + * Initialise a @ref SListIterator structure to iterate over a list. + * + * @param list Pointer to the list to iterate over. + * @param iter Pointer to a @ref SListIterator structure to + * initialise. + */ + +void slist_iterate(SListEntry **list, SListIterator *iter); + +/** + * Determine if there are more values in the list to iterate over. + * + * @param iterator The list iterator. + * @return Zero if there are no more values in the list to + * iterate over, non-zero if there are more values to + * read. + */ + +int slist_iter_has_more(SListIterator *iterator); + +/** + * Using a list iterator, retrieve the next value from the list. + * + * @param iterator The list iterator. + * @return The next value from the list, or SLIST_NULL if + * there are no more values in the list. + */ + +SListValue slist_iter_next(SListIterator *iterator); + +/** + * Delete the current entry in the list (the value last returned from + * @ref slist_iter_next) + * + * @param iterator The list iterator. + */ + +void slist_iter_remove(SListIterator *iterator); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_SLIST_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/trie.h b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/trie.h new file mode 100644 index 00000000..7b0525eb --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/libcalg/trie.h @@ -0,0 +1,132 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file trie.h + * + * @brief Fast string lookups + * + * A trie is a data structure which provides fast mappings from strings + * to values. + * + * To create a new trie, use @ref trie_new. To destroy a trie, + * use @ref trie_free. + * + * To insert a value into a trie, use @ref trie_insert. To remove a value + * from a trie, use @ref trie_remove. + * + * To look up a value from its key, use @ref trie_lookup. + * + * To find the number of entries in a trie, use @ref trie_num_entries. + */ + +#ifndef ALGORITHM_TRIE_H +#define ALGORITHM_TRIE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A trie structure. + */ + +typedef struct _Trie Trie; + +/** + * Value stored in a @ref Trie. + */ + +typedef void *TrieValue; + +/** + * A null @ref TrieValue. + */ + +#define TRIE_NULL ((void *) 0) + +/** + * Create a new trie. + * + * @return Pointer to a new trie structure, or NULL if it + * was not possible to allocate memory for the + * new trie. + */ + +Trie *trie_new(void); + +/** + * Destroy a trie. + * + * @param trie The trie to destroy. + */ + +void trie_free(Trie *trie); + +/** + * Insert a new key-value pair into a trie. + * + * @param trie The trie. + * @param key The key to access the new value. + * @param value The value. + * @return Non-zero if the value was inserted successfully, + * or zero if it was not possible to allocate + * memory for the new entry. + */ + +int trie_insert(Trie *trie, char *key, TrieValue value); + +/** + * Look up a value from its key in a trie. + * + * @param trie The trie. + * @param key The key. + * @return The value associated with the key, or + * @ref TRIE_NULL if not found in the trie. + */ + +TrieValue trie_lookup(Trie *trie, char *key); + +/** + * Remove an entry from a trie. + * + * @param trie The trie. + * @param key The key of the entry to remove. + * @return Non-zero if the key was removed successfully, + * or zero if it is not present in the trie. + */ + +int trie_remove(Trie *trie, char *key); + +/** + * Find the number of entries in a trie. + * + * @param trie The trie. + * @return Count of the number of entries in the trie. + */ + +int trie_num_entries(Trie *trie); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef ALGORITHM_TRIE_H */ + diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/make_unique.h b/EDM/athena/Control/CxxUtils/CxxUtils/make_unique.h new file mode 100644 index 00000000..9572e82c --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/make_unique.h @@ -0,0 +1,57 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/make_unique.h + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Provide a version of the C++14 make_unique. + * + * `std::unique_ptr` is best used with `make_unique`. + * However, make_unique is not in C++11, only C++14. + * This header provides a version of `make_unique` in the `CxxUtils` + * namespace usable with either C++11 or C++14. + * + * Here, we only bother with the version of `make_unique` for single objects. + */ + + +#ifndef CXXUTILS_MAKE_UNIQUE_H +#define CXXUTILS_MAKE_UNIQUE_H + + +#if __cplusplus > 201100 + + +#include <memory> + + +namespace CxxUtils { + + +#if __cplusplus > 201103L +// C++14 --- just import the library implementation. +using std::make_unique; +#else +/// std::make_unique for single objects +// Copied from libstdc++ +template<typename Tp, typename... Args> +//inline typename _MakeUniq<_Tp>::__single_object +inline +std::unique_ptr<Tp> +make_unique(Args&&... args) +{ return std::unique_ptr<Tp>(new Tp(std::forward<Args>(args)...)); } +#endif + + + +} // namespace CxxUtils + + +#endif // __cplusplus > 201100 + +#endif // not CXXUTILS_MAKE_UNIQUE_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/no_conversion_warning.h b/EDM/athena/Control/CxxUtils/CxxUtils/no_conversion_warning.h new file mode 100644 index 00000000..e27babfd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/no_conversion_warning.h @@ -0,0 +1,19 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/no_conversion_warning.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2009 + * @brief Disable conversion warnings. + * + * Include this header first in a compilation unit to disable -Wconversion + * warnings. + */ + + +#if __GNUC__ >= 4 +# pragma GCC diagnostic ignored "-Wconversion" +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/no_sanitize_undefined.h b/EDM/athena/Control/CxxUtils/CxxUtils/no_sanitize_undefined.h new file mode 100644 index 00000000..43dd1c82 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/no_sanitize_undefined.h @@ -0,0 +1,32 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/no_sanitize_undefined.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2017 + * @brief Helper to disable undefined behavior sanitizer for a function. + * + * To disable the undefined behavior sanitizers for a given function, + * write in the function's declaration: + * + * void f NO_SANITIZE_UNDEFINED (int x) + */ + + +#ifndef CXXUTILS_NO_SANITIZE_UNDEFINED_H +#define CXXUTILS_NO_SANITIZE_UNDEFINED_H + + +#if (__GNUC__ >= 6) && !defined(__clang__) +# define NO_SANITIZE_UNDEFINED [[gnu::no_sanitize_undefined]] +#else +# define NO_SANITIZE_UNDEFINED +#endif + + +#endif // not CXXUTILS_NO_SANITIZE_UNDEFINED_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/noreturn.h b/EDM/athena/Control/CxxUtils/CxxUtils/noreturn.h new file mode 100644 index 00000000..3f5e68e1 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/noreturn.h @@ -0,0 +1,53 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/noreturn.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2014 + * @brief Macro to mark a method as not returning. + * Expands to the c++11 noreturn attribute if we're using c++11, + * otherwise to the GNU noreturn attribute if we're using gcc, + * otherwise expands to just the declaration. + * + * Use like: + * + * ATH_NORETURN (void func (int a, double b)); + * + * Be careful if the return type contains commas (in a template argument + * list) --- you may need a typedef in that case. + */ + + +#ifndef CXXUTILS_NORETURN_H +#define CXXUTILS_NORETURN_H + + +// [[noreturn] is c++11. gcc implemented it in 4.8. +#if __cplusplus > 201100 +# if defined(__GNUC__) && !(__GNUC__ > 4 || __GNUC_MINOR__ >= 8) +# define ATH_HAS_NORETURN 0 // gcc < 4.8 --- not implemented +# else +# define ATH_HAS_NORETURN 1 +# endif +#else +# define ATH_HAS_NORETURN 0 // not c++11 +#endif + + +#if ATH_HAS_NORETURN +# define ATH_NORETURN(X) [[noreturn]] X +#else +# if defined(__GNUC__) +# define ATH_NORETURN(X) X __attribute__ ((noreturn)) +# else +# define ATH_NORETURN(X) X +# endif +#endif + + +#endif // not CXXUTILS_NORETURN_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/ones.h b/EDM/athena/Control/CxxUtils/CxxUtils/ones.h new file mode 100644 index 00000000..57a23f87 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/ones.h @@ -0,0 +1,39 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/ones.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2014 + * @brief Construct a bit mask. + */ + + +#ifndef CXXUTILS_ONES_H +#define CXXUTILS_ONES_H + + +namespace CxxUtils { + + +/** + * @brief Return a bit mask with the lower @a n bits set. + */ +template <class T> +inline +T ones (unsigned int n) +{ + if (n >= sizeof(T) * 8) + return ~static_cast<T>(0); + return (static_cast<T>(1) << n) - 1; +} + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_ONES_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/override.h b/EDM/athena/Control/CxxUtils/CxxUtils/override.h new file mode 100644 index 00000000..0f14dc03 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/override.h @@ -0,0 +1,39 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/override.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2014 + * @brief Macro to mark a method as overriding one from the base class. + * + * Use like: + * + * virtual void foo() ATH_OVERRIDE; + */ + + +#ifndef CXXUTILS_OVERRIDE_H +#define CXXUTILS_OVERRIDE_H + + +#ifndef HAVE_ATH_OVERRIDE +# if __cplusplus > 201100 +# define HAVE_ATH_OVERRIDE 1 +# else +# define HAVE_ATH_OVERRIDE 0 +# endif +#endif + +#if HAVE_ATH_OVERRIDE +# define ATH_OVERRIDE override +#else +# define ATH_OVERRIDE +#endif + + +#endif // not CXXUTILS_OVERRIDE_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/page_access.h b/EDM/athena/Control/CxxUtils/CxxUtils/page_access.h new file mode 100644 index 00000000..196f4f5b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/page_access.h @@ -0,0 +1,33 @@ +// dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CXXUTILS_PAGEADDRESS_H +#define CXXUTILS_PAGEADDRESS_H 1 +#include <cstdio> +#include <sys/mman.h> /* mprotect */ +#define DEBUG 1 +namespace athena { + const size_t PAGESIZE= 0x1000; //sysconf(_SC_PAGE_SIZE) + + void* page_address(void* addr); + void* next_page_address(void* addr); + int page_protect(void* addr, int prot); +/// protect page containing addr, from page boundary to addr+sizeof(T). +/// @returns amount of mem protected (0 flags an error) +template <typename T> +size_t page_protect(T* addr, int prot) { + void* pageAddr(page_address((void*)addr)); + size_t lProtected((long)addr-(long)pageAddr+sizeof(T)); + int rc=mprotect(pageAddr, lProtected, prot); + if (rc) printf("page_protect WARNING: mprotect heap failed for address %p\n", (void*)addr); +#ifdef DEBUG + else printf("page_protect DEBUG: set protection @%i for range @%lx - @%lx containing addr=%p\n", + prot,(long unsigned int)page_address(addr),(long unsigned int)addr+sizeof(T), (void*)addr); +#endif + return (rc == 0 ? lProtected : 0); +} +} +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.h b/EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.h new file mode 100644 index 00000000..7fa02091 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.h @@ -0,0 +1,341 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/pointer_list.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009, from earlier code. + * @brief A fast way to store a variable-sized collection of pointers. + */ + + +#ifndef CXXUTILS_POINTER_LIST_H +#define CXXUTILS_POINTER_LIST_H + + +#include "boost/static_assert.hpp" +#include <iterator> + + +namespace CxxUtils { + + +/** + * @brief A fast way to store a variable-sized collection of pointers. + * + * See @c pointer_list below for a summary. + * + * Some extra detail: + * The list is a set of fixed-size blocks, each holding (by default) + * 15 pointers. At the end of each block is another pointer + * used to form a a linked list. We used to mark this last pointer + * by setting the low bit as a sentinel. But now that we control our + * own allocator we can instead just insist that the blocks have + * a size that's a power of 2 and are fully aligned. We can then + * test the low bits of the address to tell if we're looking + * at the last pointer of a block. + * + * We then need to keep pointers to the head block, and to the current + * insertion position. To insert, we see if the insertion position + * is pointing at a block end. If so, we allocate another block, chain + * to it, and reset the insertion position to the beginning of the new block. + * Then store the pointer in the insertion position and bump it. + * Iterators are just pointers to the stored pointers. We use the + * end positions to tell when to chain to a new block. The insertion + * point gives the end iterator. + * + * pointer_list is templated on the number of pointers stored in each + * block. We put it as a template parameter so that it can be accessed + * from the iterator class without having to have a reference from the + * iterator back to the containing list. + */ +class pointer_list_base +{ +public: + /** + * @brief A single block in the list. + * + * It contains some number of pointers. + * The last element of the block contains a link to the next block. + * Blocks are aligned so that we can tell if we're looking + * at the last element from the low bits of an address. + */ + struct list_block + { + public: + typedef unsigned long ulong; + + /// The element type we store. + typedef void* value_type; + + /// The elements. This structure is variable-sized; + /// it will be allocated for the correct number of elements. + value_type m_data[1]; + + /// Size in bytes of a block holding @c nelt elements + /// (excluding the end-pointer). + static size_t size (size_t nelt); + }; + + + /** + * @brief Very simple allocator for use with @c pointer_list. + * + * We allocate large chunks and divide them up into @c list_block's. + * We don't support deleting individual elements; instead, everything + * is deleted when the allocator is. The chunks are chained together + * to allow for this. + * + * The total size of a block should be a power of two, and blocks + * must be aligned to this boundary. + */ + class allocator + { + public: + /** + * @brief Constructor. + * @param nelt Number of pointers per block + * (excluding the end pointer). + * Must be one less than a power of two. + * @param nblock Number of blocks to allocate per chunk. + * @param end_mask Mask to use for end-of-block test. + * @param end_offs Offset to use for end-of-block test. + */ + allocator (size_t nelt, + size_t nblock, + unsigned long end_mask, + unsigned long end_offs); + + /// Destructor. Deletes all blocks from this allocator. + ~allocator(); + + /// Allocate a new block. + list_block* allocate(); + + /// Return the number of pointers per block + /// (excluding the end-pointer). + size_t nelt() const; + + /// Return the current number of allocated chunks. + size_t nchunks() const; + + /// Test if P is pointing at the end-pointer of a block. + bool at_end (const void* p) const; + + + private: + /// Allocate a new chunk of blocks. + void refill(); + + /// One memory allocation chunk. + struct chunk + { + /// Link to the next chunk. + chunk* m_next; + + /// Pointer to the first block contained within this chunk. + list_block* m_blocks; + }; + + /// Number of elements per block (excluding the end-pointer). + size_t m_nelt; + + /// Number of blocks per chunk. + size_t m_nblock; + + /// Most recent chunk allocated. + chunk* m_chunks; + + /// Number of blocks allocated so far from that chunk. + size_t m_nthis; + + /// Current number of allocated chunks. + size_t m_nchunks; + + /// Mask for testing for an end pointer. + unsigned long m_end_mask; + + /// Offset for testing for an end pointer. + unsigned long m_end_offs; + }; + + + /// Alias for allocator. + typedef allocator pool_type; + + /// The stored element type. + typedef list_block::value_type value_type; + + /// Constructor. @c pool gives the allocator for this container. + pointer_list_base (pool_type& pool); + + /// Add a new element to the end of the container. O(1) + void push_back (value_type p); + + /// The current size of the container. O(1). + size_t size() const; + + /// Erase the container. O(1). Note: doesn't free memory. + /// Memory currently in use will be reused when the container + /// is filled again. + void clear(); + + /// Test to see if the container is empty. + bool empty() const; + + +protected: + /// The first block in the list. + list_block* m_head; + + /// The current insertion point in the list. + value_type* m_insert; + + /// The current list size. + size_t m_size; + + /// The list allocator. + allocator& m_pool; + + /// Allocate the first block of the list. + void firstblock (); + + /// Extend the list with another block. + /// @c m_insert should be at the end of the last block. + void nextblock (); + + /// Allocate a new block. + list_block* getblock(); +}; + + +/** + * @brief A fast way to store a variable-sized collection of pointers. + * + * If you're growing a variable-sized collection of things, all the + * STL containers have some performance issues. A std::vector + * needs to reallocate and copy its data as it grows. The use of + * variable-sized allocations also means that one cannot use the + * very efficient fixed-size memory allocators. A std::list + * incurs a separate memory allocation for each element, and, if the + * elements are pointers, has a substantial size overhead. + * + * The class here is a compromise, which builds a list consisting + * of fixed-size chunks. + * + * The operations supported are rather limited. + * We support forward iteration, push_back, and erase + * (though the latter can have O(n) complexity). + * + * For best performance, we use our own allocator, an instance of which + * gets passed to the @c pointer_list constructor. Memory is not freed + * until the allocator is destroyed. + * + * This class is templated on the number of elements stored per block. + * This must be one less than a power of two. + */ +template <size_t NELT = 15> +class pointer_list + : public pointer_list_base +{ +public: + /// Stored value type. + typedef pointer_list_base::value_type value_type; + + + /** + * @brief Allocator for @c pointer_list, specialized for @c NELT. + * + * The purpose for thsi is to be able to have the static + * @c at_end_static function, which we can call from an iterator. + */ + class allocator + : public pointer_list_base::allocator + { + public: + /// Verify that @c NELT is one less than a power of two. + BOOST_STATIC_ASSERT (((NELT+1) & NELT) == 0); + + /// Constants to use to test if we're at the end of a block. + static const unsigned long END_OFFS = NELT * sizeof(value_type); + static const unsigned long END_MASK = END_OFFS | (sizeof(value_type)-1); + + /** + * @brief Constructor. + * @param nblock Number of blocks to allocate per chunk. + */ + allocator (size_t nblock = 100); + + + /// Test if P is pointing at the end-pointer of a block. + static bool at_end_static (const void* p); + }; + + + /** + * @brief Forward iterator over the list. + */ + class iterator + : public std::iterator<std::forward_iterator_tag, value_type> + { + public: + typedef typename std::iterator<std::forward_iterator_tag, value_type> + base; + typedef typename base::iterator_category iterator_category; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::reference reference; + + /// Equality comparison. + bool operator== (const iterator& other) const; + + /// Inequality comparison. + bool operator!= (const iterator& other) const; + + /// Dereference. + reference operator*() const; + + /// Advance (pre-increment). + iterator& operator++(); + + /// Advance (post-increment). + iterator operator++(int); + + + private: + /// Constructor, from a pointer into a @c pointer_list. + iterator (value_type* p); + + /// Current iteration position. + value_type* m_p; + + friend class pointer_list; + }; + + typedef allocator pool_type; + + /// Constructor. @c pool gives the allocator for this container. + pointer_list (pool_type& pool); + + /// Iterator at the beginning of the container. + iterator begin(); + + /// Iterator at the end of the container. + iterator end(); + + /// Erase one element. O(n) + void erase (iterator it); +}; + + +} // namespace CxxUtils + + +#include "CxxUtils/pointer_list.icc" + + +#endif // not CXXUTILS_POINTER_LIST_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.icc b/EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.icc new file mode 100644 index 00000000..0bb1b4c1 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/pointer_list.icc @@ -0,0 +1,320 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/pointer_list.icc + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009, from earlier code. + * @brief A fast way to store a variable-sized collection of pointers. + */ + + +#include <cassert> +#include <algorithm> + + +namespace CxxUtils { + + +/** + * @brief Size in bytes of a block holding @c nelt elements. + * (excluding the end-pointer). + * @param nelt Number of elements. + */ +inline +size_t pointer_list_base::list_block::size (size_t nelt) +{ + return sizeof(list_block) + nelt * sizeof(value_type); +} + + +//**************************************************************************** + + +/** + * @brief Allocate a new block. + */ +inline +pointer_list_base::list_block* +pointer_list_base::allocator::allocate() +{ + // Get a new chunk if needed. + if (m_nthis == m_nblock) + refill(); + return &m_chunks->m_blocks[(m_nthis++) * (m_nelt+1)]; +} + + +/** + * @brief Return the number of pointers per block (excluding the end-pointer). + */ +inline +size_t +pointer_list_base::allocator::nelt() const +{ + return m_nelt; +} + + +/** + * @brief Current number of allocated chunks. + */ +inline +size_t +pointer_list_base::allocator::nchunks() const +{ + return m_nchunks; +} + + +/** + * @brief Test to see if we're looking at the end of a block. + * @param p The pointer to test. + */ +inline +bool +pointer_list_base::allocator::at_end (const void* p) const +{ + return (reinterpret_cast<unsigned long>(p) & m_end_mask) == m_end_offs; +} + + +/** + * @brief Constructor. + * @param nblock Number of blocks to allocate per chunk. + */ +template <size_t NELT> +pointer_list<NELT>::allocator::allocator (size_t nblock /*= 100*/) + : pointer_list_base::allocator (NELT, nblock, END_MASK, END_OFFS) +{ +} + + +/** + * @brief Test to see if we're looking at the end of a block. + * @param p The pointer to test. + */ +template <size_t NELT> +inline +bool +pointer_list<NELT>::allocator::at_end_static (const void* p) +{ + return (reinterpret_cast<unsigned long>(p) & END_MASK) == END_OFFS; +} + + +//**************************************************************************** + + +/** + * @brief Equality comparison. + */ +template <size_t NELT> +inline +bool +pointer_list<NELT>::iterator::operator== (const iterator& other) const +{ + return m_p == other.m_p; +} + + +/** + * @brief Inequality comparison. + */ +template <size_t NELT> +inline +bool +pointer_list<NELT>::iterator::operator!= (const iterator& other) const +{ + return m_p != other.m_p; +} + + +/** + * @brief Dereference. + */ +template <size_t NELT> +inline +typename pointer_list<NELT>::iterator::reference +pointer_list<NELT>::iterator::operator*() const +{ + return *m_p; +} + + +/** + * @brief Advance (pre-increment). + */ +template <size_t NELT> +inline +typename pointer_list<NELT>::iterator& +pointer_list<NELT>::iterator::operator++() +{ + // Move forward. + ++m_p; + + // If we've hit the end, chain to the next block, + // if there is one. Otherwise, stay at the end; + // that will be where the end iterator points. + if (pointer_list::allocator::at_end_static (m_p)) { + list_block* next = reinterpret_cast<list_block*> (*m_p); + if (next) + m_p = &next->m_data[0]; + } + return *this; +} + + +/** + * @brief Advance (post-increment). + */ +template <size_t NELT> +inline +typename pointer_list<NELT>::iterator +pointer_list<NELT>::iterator::operator++(int) +{ + iterator ret = *this; + ++*this; + return ret; +} + + +/** + * @brief Constructor. + * @param p A value within a @c pointer_list. + */ +template <size_t NELT> +inline +pointer_list<NELT>::iterator::iterator (value_type* p) + : m_p (p) +{ +} + + +//**************************************************************************** + + +/** + * @brief Constructor. + * @param pool The allocator for this container. + */ +inline +pointer_list_base::pointer_list_base (pool_type& pool) + : m_head (0), + m_insert (0), + m_size (0), + m_pool (pool) +{ +} + + +/** + * @brief Add a new element to the end of the container. O(1) + */ +inline +void pointer_list_base::push_back (value_type p) +{ + // If the container is empty, allocate the first block. + if (!m_head) + firstblock(); + + // Otherwise, if we're at the end of the current block, allocate a new one. + else if (m_pool.at_end (m_insert)) + nextblock(); + + // Add the value to the list. + *m_insert = p; + ++m_insert; + ++m_size; + + // If we're at the end of this block, and a following block exists, + // move to the following block. + if (m_pool.at_end (m_insert)) { + value_type next = *m_insert; + if (next) + m_insert = reinterpret_cast<value_type*> (next); + } +} + + +/** + * @brief The current size of the container. O(1) + */ +inline +size_t pointer_list_base::size() const +{ + return m_size; +} + + +/** + * @brief Test to see if the container is empty. + */ +inline +bool pointer_list_base::empty() const +{ + return m_size == 0; +} + + +/** + * @brief Constructor. + * @param pool The allocator for this container. + */ +template <size_t NELT> +inline +pointer_list<NELT>::pointer_list (pool_type& pool) + : pointer_list_base (pool) +{ +} + + +/** + * @brief Iterator at the beginning of the container. + */ +template <size_t NELT> +inline +typename pointer_list<NELT>::iterator pointer_list<NELT>::begin() +{ + // Start by pointing at the first element + // (or null, if the container's empty). + return iterator (m_head ? &m_head->m_data[0] : 0); +} + + +/** + * @brief Iterator at the end of the container. + */ +template <size_t NELT> +inline +typename pointer_list<NELT>::iterator pointer_list<NELT>::end() +{ + // Point at the current insertion point. + // (This will be null if the container's empty.) + return iterator (m_insert); +} + + +/** + * @brief Erase one element. O(n) + * @param it The element to erase. + */ +template <size_t NELT> +void pointer_list<NELT>::erase (iterator it) +{ + // We just copy the elements back by one. + iterator next = it; + ++next; + next = std::copy (next, end(), it); + + // New insertion point is where the copy stopped. + m_insert = next.m_p; + + // One less element. + --m_size; +} + + +} // namespace CxxXUtils diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/prefetch.h b/EDM/athena/Control/CxxUtils/CxxUtils/prefetch.h new file mode 100644 index 00000000..0f07adaa --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/prefetch.h @@ -0,0 +1,168 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/prefetch.h + * @author scott snyder <snyder@bnl.gov>, after code from A. Salnikov + * @date Dec, 2013 + * @brief Functions to prefetch blocks of memory. + */ + + +#ifndef CXXUTILS_PREFETCH_H +#define CXXUTILS_PREFETCH_H + + +#include <cstdlib> + + +// Macro implementing prefetch on an address. +// Set to a no-op if we don't know how to implement it for this +// compiler / architecture. +// One can also predefine CXXUTILS_PREFETCH_ADDRESS for testing purposes. +#ifndef CXXUTILS_PREFETCH_ADDRESS +# ifdef __GNUC__ +// gcc provides special builtin +# define CXXUTILS_PREFETCH_ADDRESS(ADDR) __builtin_prefetch(ADDR) +# else +# define CXXUTILS_PREFETCH_ADDRESS(ADDR) do {} while(0) // no-op +# endif +#endif + + +namespace CxxUtils { + + +/** + * While it is possible to determine cache line size at run time (e.g. using + * sysconf(_SC_LEVEL1_DCACHE_LINESIZE) on Linux or sysctlbyname("hw.cachelinesize", ...) + * on Apple systems) that approach creates more problems: the location + * that stores cache line size will probably be out of cache when one needs + * to know it. This is why we use a compile time constant for cache line size. + * Cache line size is 64 for the current generation of Intel/AMD CPUs. + * + * If an object spans multiple cache lines then prefetching whole + * object should be done by prefetching at least one address from + * each of the cache lines that object occupies. How many lines are + * needed depends on three things: object size, cache line size, and + * object starting address. If CacheLineSize is lower than the + * actual line size then more prefetches than necessary will be + * generated (2, 4, or more per cache line if cache line size is + * power of 2). This may be somewhat wasteful so this number may need + * to be adjusted in the far future when _all_ CPUs have wider cache + * lines. + */ +enum { CacheLineSize = 64 }; + + +/** + * @brief Generic prefetch method + * @param[in] address memory location to prefetch + * + * This is generic method that does not have any extra behavior. It + * only prefetches the whole cache line which contains the specified + * memory location. It does not incur any additional overhead and may + * be the most efficient method for small objects which have a high + * chance of being on just a single cache line. + */ +inline +void prefetchOne (const void* address) +{ + CXXUTILS_PREFETCH_ADDRESS(address); +} + + +/** + * @brief Prefetch an N-byte block of memory. + * @param[in] ptr Starting address of the block. + */ +template <size_t N> +inline +void prefetchN (const void* ptr) +{ + const char* pp = reinterpret_cast<const char*> (ptr); + + // The compiler will unroll this loop for small N. + for (size_t i = 0; i < N; i += CacheLineSize) + prefetchOne (pp + i); + + // Issue a prefetch for the last byte as well, in case it crosses + // cache lines. + prefetchOne (pp + N - 1); +} + + +/** + * @brief Generic prefetch of the object of specific types (sizes). + * @param[in] address memory location to prefetch + * + * This method will prefetch as many cache lines as needed to store the object + * of the specified type in memory. Type is specified as a template argument. + */ +template <typename T> +inline +void prefetchObj(const T* ptr) +{ + prefetchN<sizeof(T)> (ptr); +} + +/** + * @brief Prefetch next object in sequence. + * @param iter Current iteration position. + * @param endIter End of the sequence. + * + * @c Iter is a @c ForwardIterator over pointers. + * + * Prefetches next object in a collection of pointers. Accepts two + * iterators: the first iterator is the current iteration position, + * and the second iterator is the end iterator for the whole + * sequence. The first iterator must not be equal to the end + * iterator (this is not checked). This increments the iterator and, + * if not equal to the end, prefetches the complete object referenced + * by the pointer. + */ +template <typename Iter> +inline +void prefetchNext (Iter iter, Iter endIter) +{ + if (++iter != endIter) + prefetchObj(*iter); +} + + +/** + * @brief Prefetch two objects. + * @param iter Current iteration position. + * @param endIter End of the sequence. + * + * @c Iter is a @c ForwardIterator over pointers. + * + * Prefetches the current and next objects in a collection of + * pointers. Accepts two iterators: the first iterator is the current + * iteration position, and the second is the end iterator for the + * whole sequence. If the first iterator is not equal to end the + * iterator, the object to which it points is prefetched. Then the + * iterator is incremented and, if not equal to the end iterator, the + * next objects is also prefetched. + */ +template <typename Iter> +inline +void prefetchTwo (Iter iter, Iter endIter) +{ + if (iter != endIter) { + prefetchObj(*iter); + if (++iter != endIter) { + prefetchObj(*iter); + } + } +} + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_PREFETCH_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/procmaps.h b/EDM/athena/Control/CxxUtils/CxxUtils/procmaps.h new file mode 100644 index 00000000..4978545a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/procmaps.h @@ -0,0 +1,60 @@ +// dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef PROCMAPS_H +#define PROCMAPS_H 1 +#include <boost/pool/pool_alloc.hpp> +#include <vector> +/** @class procmaps + * @brief A simple API to access /proc/self/maps info + * + * @author Paolo Calafiura - LBNL, ATLAS Collaboration + * $Id: procmaps.h,v 1.3 2009-04-01 08:23:32 binet Exp $ + **/ +class procmaps { +public: + struct Entry { + Entry(const char* line); + unsigned long begAddress; + unsigned long endAddress; + bool readable; + bool writable; + bool executable; + bool isPrivate; ///=true page is private(COW), =false page is shared + unsigned int offset; + unsigned int dev[2]; /// dev[0] major, dev[1] minor + unsigned int inode; + char pathname[32]; ///truncated if needed + }; + + procmaps(size_t entries=1024); + //not yet procmaps(int pid); + + typedef std::vector<Entry, boost::pool_allocator<Entry> > procmaps_t; + typedef procmaps_t::const_iterator const_iterator; + + ///main entry point: get info for the page range containing address + /// by default tries to reload /proc/self/maps when address is not found + const Entry* getEntry(const void* address, bool tryReloadMaps=true); + + ///access underlying entries + static const procmaps_t& pmaps() { return s_pmaps; } + const_iterator begin() const { return pmaps().begin(); } + const_iterator end() const { return pmaps().end(); } + + /// load/refresh info from /proc/self/map + void loadMaps(bool dump=false); + +private: + static bool s_pmapsLoaded; + static procmaps_t s_pmaps; +}; + +inline +bool operator<(procmaps::Entry& lhs, procmaps::Entry& rhs){ + return lhs.begAddress < rhs.begAddress; +} +#endif diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/read_athena_statm.h b/EDM/athena/Control/CxxUtils/CxxUtils/read_athena_statm.h new file mode 100644 index 00000000..f25c69a6 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/read_athena_statm.h @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/* + * @file read_statm.h + * @brief returns statm memory statistics for current process (see man proc) + * @param vm_pages total program size in unit of pages + * @param rss_pages resident set size in unit of pages + * @author Sebastien Binet, Paolo Calafiura + * $Id: read_athena_statm.h 592439 2014-04-10 17:35:29Z calaf $ + */ +struct athena_statm { + unsigned int vm_pages; + unsigned int rss_pages; +}; +#ifdef __cplusplus +extern "C" +#endif +struct athena_statm read_athena_statm(); diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/sincos.h b/EDM/athena/Control/CxxUtils/CxxUtils/sincos.h new file mode 100644 index 00000000..64469512 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/sincos.h @@ -0,0 +1,108 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: sincos.h,v 1.1 2008-11-24 04:34:07 ssnyder Exp $ + +/** + * @file CxxUtils/sincos.h + * @author scott snyder + * @date Nov 2008, from older D0 code. + * @brief Helper to simultaneously calculate sin and cos of the same angle. + */ + + +#ifndef CXXUTILS_SINCOS_H +#define CXXUTILS_SINCOS_H + + +#include <cmath> + + +namespace CxxUtils { + + +/** + * @brief Helper to simultaneously calculate sin and cos of the same angle. + * + * Instantiate an instance of this object, passing the angle to the + * constructor. The sin and cos are then available as the sn and cs + * members. In addition, the apply() method may be used to calculate + * a*sin(x) + b*cos(x). + * + * Implementation notes: + * + * The i386/x87 architecture has an instruction to do this. + * So, on that platform, we use that instruction directly. + * It seems to be a win to use it even if we're using SSE math, + * so we'll use it for x86_64 too. + * Otherwise, we'll use sincos() if it's available (it's a GNU extension). + * Otherwise, just call sin() and cos() separately. + * + * Note that the fsincos instruction only works correctly + * if the input angle is in the range -2^63 ... 2^63. + * This is not likely to be an issue for us. + * + * Why prefer using the fsincos instruction directly to calling + * the sincos() library function? + * + * - It turns out to be a little difficult to ensure that + * sincos() actually gets inlined. In general, one needs -ffast-math + * (which isn't on for standard Atlas builds), but even that's not always + * sufficient. + * + * - The library version includes extra code that we + * don't really need to handle the case where + * abs(angle) > 2^63. (Runtime penalty, though, is + * moving the FPU status word to $eax and one + * taken branch.) + * + * - Most importantly, though, the library function + * takes pointers into which the results are stored. + * Playing with this, i was unable to prevent the + * calculated values from being spilled to memory. + * With the definition used below, we don't necessarily + * spill to memory. A sequence like + * + * sincos sc (ang); + * double a = sc.apply (x, y) + * + * can be calculated entirely in the FPU register file, + * with no spills. + */ +struct sincos +{ + /// Calculate sine and cosine of x. + sincos (double x) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + // Inline assembly version. Uses x87 FPU. + { __asm __volatile__ ("fsincos\n\t" : "=t" (cs), "=u" (sn) : "0" (x)); } +#elif defined(__USE_GNU) + // Version using the GNU sincos() function. + { sincos(x, &sn, &cs); } +#else + // Generic version. + : sn (std::sin (x)), cs (std::cos (x)) {} +#endif + + /// @f$\sin(x)@f$ + double sn; + + /// @f$\cos(x)@f$ + double cs; + + /// @f$a\sin(x) + b\cos(x)@f$ + double apply (double a, double b) const { return a*sn + b*cs; } + + /// @f$a\sin^2(x) + b\sin(x)\cos(x) + c\cos^2(x)@f$ + double apply2 (double a, double b, double c) const + { return a*sn*sn + b*sn*cs + c*cs*cs; } +}; + + +} // namespace CxxUtils + + +#endif //not CXXUTILS_SINCOS_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/sincosf.h b/EDM/athena/Control/CxxUtils/CxxUtils/sincosf.h new file mode 100644 index 00000000..60f01cf2 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/sincosf.h @@ -0,0 +1,23 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/sincosf.h + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Jan 2010 + * @brief Provide sincosf function for MacOSX. + */ + + +#ifndef CXXUTILS_SINCOSF_H +#define CXXUTILS_SINCOSF_H + +#ifdef __APPLE__ +void sincosf(float x, float* sn, float* cs); +#endif + +#endif // not CXXUTILS_SINCOSF_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/ubsan_suppress.h b/EDM/athena/Control/CxxUtils/CxxUtils/ubsan_suppress.h new file mode 100644 index 00000000..466891e0 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/ubsan_suppress.h @@ -0,0 +1,48 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +// $Id$ +/** + * @file CxxUtils/ubsan_suppress.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2017 + * @brief Helper for suppressing ubsan warnings. + * + * With gcc6, not all ubsan warnings can be suppressed via the suppression + * file (for example, type mismatch errors where the object has an invalid + * vptr). + * + * However, ubsan will report warnings only once for any given source location. + * So we can effectively suppress warnings by trigging the warning + * with stderr pointing to /dev/null. You can do that by calling the + * @c ubsan_suppress function, passing it a function to call with + * stderr redirected to /dev/null. + */ + + +#ifndef CXXUTILS_UBSAN_SUPPRESS_H +#define CXXUTILS_UBSAN_SUPPRESS_H + + +namespace CxxUtils { + + +/** + * @brief Helper for suppressing ubsan warnings. + * @param func Function to call (may be a lambda). + * + * If ubsan is running, temporarily redirect stderr to /dev/null. + * Then call @c func. + * + * For example, we sometimes get a bogus ubsan warning from + * cling initialization. This can be suppressed by adding something like: + * + *@code + * CxxUtils::ubsan_suppress ([]() { TInterpreter::Instance(); }); + @endcode + */ +void ubsan_suppress (void (*func)()); + + +} + + +#endif // not CXXUTILS_UBSAN_SUPPRESS_H diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/unordered_map.h b/EDM/athena/Control/CxxUtils/CxxUtils/unordered_map.h new file mode 100644 index 00000000..dbfaa484 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/unordered_map.h @@ -0,0 +1,187 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +// $Id: unordered_map.h,v 1.1.1.1 2008-09-10 04:02:52 binet Exp $ +/** + * @file CxxUtils/unordered_map.h + * @author scott snyder <snyder@bnl.gov>, copied from gcc4. + * @date Apr, 2007 + * @brief This is the TR1 unordered_set implementation from gcc4, + * adapted to build in Atlas. Once the TR1 library is available + * on all our platforms, we can switch to using the system-supplied + * version instead. + * + * Search for `sss' to find changes from the gcc version. + */ + +// TR1 unordered_map -*- C++ -*- + +// Copyright (C) 2005 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +/* @file (sss --- hide from doxygen) + * This is a TR1 C++ Library header. + */ + +#ifndef CXXUTILS_UNORDERED_MAP_H // sss GNU_LIBSTDCXX_TR1_UNORDERED_MAP_ +#define CXXUTILS_UNORDERED_MAP_H // sss GNU_LIBSTDCXX_TR1_UNORDERED_MAP_ + +#include "CxxUtils/hashtable.h" // sss <tr1/hashtable> +//#include <tr1/functional> sss +//#include <tr1/functional> sss +#include <utility> +#include <memory> +#include <functional> + +//namespace std sss +//{ sss +namespace SG // tr1 sss +{ +#define Internal CxxUtils_Internal // sss + // XXX When we get typedef templates these class definitions + // will be unnecessary. + + template<class Key, class T, + class Hash = hash<Key>, + class Pred = std::equal_to<Key>, + class Alloc = std::allocator<std::pair<const Key, T> >, + bool cache_hash_code = false> + class unordered_map + : public hashtable <Key, std::pair<const Key, T>, + Alloc, + Internal::extract1st<std::pair<const Key, T> >, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, false, true> + { + typedef hashtable <Key, std::pair<const Key, T>, + Alloc, + Internal::extract1st<std::pair<const Key, T> >, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, false, true> + Base; + + public: + typedef typename Base::size_type size_type; + typedef typename Base::hasher hasher; + typedef typename Base::key_equal key_equal; + typedef typename Base::allocator_type allocator_type; + + explicit + unordered_map(size_type n = 10, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base(n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::extract1st<std::pair<const Key, T> >(), a) + { } + + template<typename InputIterator> + unordered_map(InputIterator f, InputIterator l, + size_type n = 10, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (f, l, n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::extract1st<std::pair<const Key, T> >(), a) + { } + }; + + template<class Key, class T, + class Hash = hash<Key>, + class Pred = std::equal_to<Key>, + class Alloc = std::allocator<std::pair<const Key, T> >, + bool cache_hash_code = false> + class unordered_multimap + : public hashtable <Key, std::pair<const Key, T>, + Alloc, + Internal::extract1st<std::pair<const Key, T> >, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, false, false> + { + typedef hashtable <Key, std::pair<const Key, T>, + Alloc, + Internal::extract1st<std::pair<const Key, T> >, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, false, false> + Base; + + public: + typedef typename Base::size_type size_type; + typedef typename Base::hasher hasher; + typedef typename Base::key_equal key_equal; + typedef typename Base::allocator_type allocator_type; + + explicit + unordered_multimap(size_type n = 10, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::extract1st<std::pair<const Key, T> >(), a) + { } + + + template<typename InputIterator> + unordered_multimap(InputIterator f, InputIterator l, + typename Base::size_type n = 0, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (f, l, n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::extract1st<std::pair<const Key, T> >(), a) + { } + }; + + template<class Key, class T, class Hash, class Pred, class Alloc, + bool cache_hash_code> + inline void + swap(unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& x, + unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& y) + { x.swap(y); } + + template<class Key, class T, class Hash, class Pred, class Alloc, + bool cache_hash_code> + inline void + swap(unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& x, + unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& y) + { x.swap(y); } + +#undef Internal // sss +//} sss +} + +#endif /* GNU_LIBSTDCXX_TR1_UNORDERED_MAP_ */ diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/unordered_set.h b/EDM/athena/Control/CxxUtils/CxxUtils/unordered_set.h new file mode 100644 index 00000000..0005c54d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/unordered_set.h @@ -0,0 +1,182 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +// $Id: unordered_set.h,v 1.1.1.1 2008-09-10 04:02:52 binet Exp $ +/** + * @file CxxUtils/unordered_set.h + * @author scott snyder <snyder@bnl.gov>, copied from gcc4. + * @date Apr, 2007 + * @brief This is the TR1 unordered_set implementation from gcc4, + * adapted to build in Atlas. Once the TR1 library is available + * on all our platforms, we can switch to using the system-supplied + * version instead. + * + * Search for `sss' to find changes from the gcc version. + */ + +// TR1 unordered_set -*- C++ -*- + +// Copyright (C) 2005 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +/* @file (sss --- hide from doxygen) + * This is a TR1 C++ Library header. + */ + +#ifndef CXXUTILS_UNORDERED_SET_H // sss GNU_LIBSTDCXX_TR1_UNORDERED_SET_ +#define CXXUTILS_UNORDERED_SET_H // sss GNU_LIBSTDCXX_TR1_UNORDERED_SET_ + +#include "CxxUtils/hashtable.h" // <tr1/hashtable> sss +//#include <tr1/functional> +#include <memory> +#include <functional> + +//namespace std sss +//{ sss +namespace SG // tr1 sss +{ +#define Internal CxxUtils_Internal // sss + + // XXX When we get typedef templates these class definitions + // will be unnecessary. + + template<class Value, + class Hash = hash<Value>, + class Pred = std::equal_to<Value>, + class Alloc = std::allocator<Value>, + bool cache_hash_code = false> + class unordered_set + : public hashtable<Value, Value, Alloc, + Internal::identity<Value>, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, true, true> + { + typedef hashtable<Value, Value, Alloc, + Internal::identity<Value>, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, true, true> + Base; + + public: + typedef typename Base::size_type size_type; + typedef typename Base::hasher hasher; + typedef typename Base::key_equal key_equal; + typedef typename Base::allocator_type allocator_type; + + explicit + unordered_set(size_type n = 10, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::identity<Value>(), a) + { } + + template<typename InputIterator> + unordered_set(InputIterator f, InputIterator l, + size_type n = 10, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (f, l, n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::identity<Value>(), a) + { } + }; + + template<class Value, + class Hash = hash<Value>, + class Pred = std::equal_to<Value>, + class Alloc = std::allocator<Value>, + bool cache_hash_code = false> + class unordered_multiset + : public hashtable <Value, Value, Alloc, + Internal::identity<Value>, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, true, false> + { + typedef hashtable<Value, Value, Alloc, + Internal::identity<Value>, Pred, + Hash, Internal::mod_range_hashing, + Internal::default_ranged_hash, + Internal::prime_rehash_policy, + cache_hash_code, true, false> + Base; + + public: + typedef typename Base::size_type size_type; + typedef typename Base::hasher hasher; + typedef typename Base::key_equal key_equal; + typedef typename Base::allocator_type allocator_type; + + explicit + unordered_multiset(size_type n = 10, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), + eql, Internal::identity<Value>(), a) + { } + + + template<typename InputIterator> + unordered_multiset(InputIterator f, InputIterator l, + typename Base::size_type n = 0, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : Base (f, l, n, hf, Internal::mod_range_hashing(), + Internal::default_ranged_hash(), eql, + Internal::identity<Value>(), a) + { } + }; + + template<class Value, class Hash, class Pred, class Alloc, + bool cache_hash_code> + inline void + swap (unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& x, + unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& y) + { x.swap(y); } + + template<class Value, class Hash, class Pred, class Alloc, + bool cache_hash_code> + inline void + swap(unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& x, + unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& y) + { x.swap(y); } + +#undef Internal // sss +//} sss +} + +#endif /* GNU_LIBSTDCXX_TR1_UNORDERED_SET_ */ diff --git a/EDM/athena/Control/CxxUtils/CxxUtils/unused.h b/EDM/athena/Control/CxxUtils/CxxUtils/unused.h new file mode 100644 index 00000000..a56f8674 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/CxxUtils/unused.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/* $Id$ */ +/** + * @file CxxUtils/unused.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2011 + * @brief Macro to mark a variable as unused. + * + * Use like: + * + * int UNUSED(v); + * + * Of course, if a variable is really unused, it's better to simply + * remove it rather than trying to paper over the warning like this. + * + * But there are some cases where in regression tests one might want + * to legitimately have an unused variable (particularly with gcc 4.6, + * where the unused warnings also catch variables assigned to but + * not read). This is really meant for these cases. + */ + +#ifndef CXXUTILS_UNUSED_H +#define CXXUTILS_UNUSED_H + + +#ifdef __GNUC__ +# define UNUSED(v) v __attribute__((unused)) +#else +# define UNUSED(v) v +#endif + + +#endif /* not CXXUTILS_UNUSED_H */ diff --git a/EDM/athena/Control/CxxUtils/Root/Array.cxx b/EDM/athena/Control/CxxUtils/Root/Array.cxx new file mode 100644 index 00000000..d6e587ff --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/Array.cxx @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// +// $Id: Array.cxx,v 1.1 2009-03-20 20:44:23 ssnyder Exp $ +/** + * @file Array.cxx + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Simple multidimensional arrays. + */ + +// Empty file, required in order to run component test. diff --git a/EDM/athena/Control/CxxUtils/Root/ArrayScanner.cxx b/EDM/athena/Control/CxxUtils/Root/ArrayScanner.cxx new file mode 100644 index 00000000..1980c0a0 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/ArrayScanner.cxx @@ -0,0 +1,125 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArrayScanner.cxx,v 1.1 2009-03-20 20:44:23 ssnyder Exp $ +/** + * @file ArrayScanner.cxx + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Helper class for converting strings to Array's. + */ + + +#include "CxxUtils/ArrayScanner.h" + + +namespace CxxUtils { + + +/** + * @brief Constructor. + * @param is The stream from which to scan. + * + * Builds a new scanner reading from stream @a is. + */ +ArrayScanner::ArrayScanner (std::istream& is) + : m_is (is) +{ +} + + +/** + * @brief Read opening token. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at `[', consume it and return true. + * Otherwise, return false. + */ +bool ArrayScanner::at_open() +{ + // Skip any opening quote marks. + at_char ('\''); + at_char ('"'); + + return at_char ('['); +} + + +/** + * @brief Read closing token. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at `]', consume it and return true. + * If there's a comma following it, consume that too. + * Otherwise, return false. + */ +bool ArrayScanner::at_close() +{ + if (at_char (']')) { + at_char (','); + + // Skip any closing quote marks. + at_char ('\''); + at_char ('"'); + return true; + } + return false; +} + + +/** + * @brief Test for end-of-stream. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * Return true if we're then at the end of the stream. + * Otherwise, return false. + */ +bool ArrayScanner::at_end() +{ + std::istream::sentry s (m_is); + return !s; +} + + +/** + * @brief Read a character. + * @param The character to read. + * @return True if successful. + * + * Consume any white space at the head of the stream. + * If we're then looking at @a c, consume it and return true. + * Otherwise, return false. + */ +bool ArrayScanner::at_char (char c) +{ + std::istream::sentry s (m_is); + if (s && m_is.peek() == c) { + m_is.get(); + return true; + } + return false; +} + + +/** + * @brief The non-template part of reading a number. + * @return True if successful. + * + * This is called after the attempt to read the number itself. + * This function checks that the read was in fact successful. + * If so, then it will also consume any following comma. + */ +bool ArrayScanner::at_num_common () +{ + bool stat = !m_is.fail(); + m_is.clear(); + at_char (','); + return stat; +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/Root/Arrayrep.cxx b/EDM/athena/Control/CxxUtils/Root/Arrayrep.cxx new file mode 100644 index 00000000..f41175cd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/Arrayrep.cxx @@ -0,0 +1,300 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arrayrep.cxx,v 1.3 2009-04-08 21:12:44 ssnyder Exp $ +/** + * @file Arrayrep.cxx + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Representation class for Array's. + */ + + +#include "CxxUtils/Arrayrep.h" +#include "CxxUtils/ArrayScanner.h" +#include <stdexcept> +#include <cassert> +#include <sstream> + + +namespace CaloRec { + + +/** + * @brief Initialize the @c m_sizes vector from the @c m_shape vector. + * @param resize_data Should @c m_data be resized appropriately? + * + * The contents of the @c m_sizes vector are initialized from + * the contents of the @c m_shape vector. If @c resize_data + * is true, then the size of @c m_data is changed to the total + * size indicated by @c m_shape. Otherwise, we verify that + * @c m_data has the correct size, and raise an assertion if not. + */ +void Arrayrep::init_sizes (bool resize_data /*= false*/) +{ + // Don't do anything if we've already done this, or if the array + // is empty. + if (m_sizes.size() < m_shape.size()) + { + // Calculate the m_sizes array. + unsigned int sz = 1; + unsigned int dim = m_shape.size(); + m_sizes.resize (dim); + m_sizes[0] = 1; + for (unsigned int i=0; i < dim; i++) { + m_sizes[i] = sz; + sz *= m_shape[dim-1 - i]; + } + + if (resize_data) { + // Resize m_data to the proper size. + m_data.resize (sz); + } + else { + // Check that m_data has the correct size. + assert (sz == m_data.size()); + } + } +} + + +/** + * @brief Construct an empty array of a given shape. + * @param shape The shape of the array. + * + * Initialize an array of a given shape. + * The array will contain all 0's. + */ +Arrayrep::Arrayrep (const std::vector<unsigned int>& shape) + : m_shape (shape) +{ + // Set up m_sizes. + init_sizes (true); +} + + +/** + * @brief Construct an empty array of a given shape. + * @param shape The shape of the array. + * @param n The length of the @a shape array. + * + * Initialize an array of a given shape. + * The array will contain all 0's. + * This version is more convenient to call with a constant shape. + */ +Arrayrep::Arrayrep (const unsigned int shape[], unsigned int n) +{ + // Copy the data into m_shape. + m_shape.reserve (n); + for (unsigned int i=0; i < n; i++) + m_shape.push_back (shape[i]); + + // Set up m_sizes. + init_sizes (true); +} + + +namespace { + + +/** + * @brief Report an error in building an @c Arrayrep from a string. + * @param context Additional context for the error. + * @param msg The error message to report. + * + * Report an error by raising a @c std::runtime_error. + */ +void error (const std::string& context, + const std::string& msg) +{ + throw std::runtime_error (msg + ": " + context); +} + + +/** + * @brief Helper function to build an @c Arrayrep from a string. + * @param rep The @c Arrayrep we're building. + * @param s The @c ArrayScanner stream from which we're reading. + * @param nest The current nesting level. + * @param context For error reporting. + * + * Read tokens from @a s and build the array information + * in @a Arrayrep. This function should be called just after + * consuming the opening bracket of an array. It calls itself + * recursively to handle subarrays. + */ +void read_array (Arrayrep& rep, + ArrayScanner& s, + unsigned int nest, + const std::string& context) +{ + // The first time we handle a subarray at a given nesting, we don't + // know the size for that dimension, so we should just take what + // we're given. After that, though, we should be sure that the + // size matches what was used before (a rectangular array). + bool know_size = false; + if (rep.m_shape.size() > nest) { + // We know what the size should be. + know_size = true; + } + else { + // We don't know the size yet. Go ahead and push a dummy + // entry in m_shape; we'll update it later. + rep.m_shape.push_back (0); + } + + // Number of array elements (each of which could be a subarray) + // which we're read. + unsigned int n = 0; + + // Are we now looking at plain elements or at a nested subarray? + if (s.at_open()) { + // A nested subarray. + // Disallow constructions like + // [[1], [[2]]] + // Maximum nesting must be the same in all subarrays. + if (rep.m_data.size() > 0 && nest >= rep.m_shape.size()) + error (context, "Bad array nesting"); + + // Read the subarrays as long as we keep seeing more. + do { + read_array (rep, s, nest+1, context); + ++n; + } while (s.at_open()); + } + else { + // Plain elements. Read them as long as we keep seeing them. + Arrayelt elt; + while (s.at_num (elt)) { + rep.m_data.push_back (elt); + ++n; + } + } + + // We should now be at a closing bracket. + if (!s.at_close()) + error (context, "Missing close bracket"); + + if (!know_size) { + // We didn't yet know the size for this dimension. Fill it in now. + rep.m_shape[nest] = n; + } + else if (rep.m_shape[nest] != n) { + // What we got doesn't match the size for this dimension we've + // seen earlier. Complain. + error (context, "Array not rectangular"); + } +} + + +} // anonymous namespace + + +/** + * @brief Construct from a string. + * @param str The string to convert. + * @param context An optional string to use for error reporting. + * + * Parse the string and initialize the array. + * This string should be like `[[1, 2], [3, 4]]'. + */ +Arrayrep::Arrayrep (const std::string& str, const std::string& context /*=""*/) +{ + // Special cases for True and False. + if (str == "True") + m_data.push_back (1); + else if (str == "False") + m_data.push_back (0); + else { + // Make the token stream from which we're reading. + std::istringstream is (str); + ArrayScanner s (is); + + // If we're looking at an open bracket, consume it, and proceed + // to read an array. + if (s.at_open()) + read_array (*this, s, 0, context); + else { + // Otherwise, we're reading a scalar. So read a single number. + Arrayelt elt; + if (!s.at_num (elt)) + error (context, "Number expected"); + m_data.push_back (elt); + } + + // We should now be at the end of the stream. + if (!s.at_end()) + error (context, "End of vector before end of string"); + } + + // Set up the m_sizes vector. + init_sizes(); +} + + + /** + * @brief Helper function for write_array. + * @param stream where the array should be written + * @param idx Current index in @c m_data + * @param dimIndex Current index in @c m_shapes + * + * Calls itself recursively with dimIndex-1 + */ + +void Arrayrep::write_array(std::ostream& stream) const { + if (!m_data.size()) {//Empty array + stream << "[ ]" << std::endl; + return; + } + + if (!m_shape.size()) {//Single element + stream << m_data[0] << std::endl; + return; + } + + //All other cases: Array of dimension>=1 + //check consistency of Array + unsigned totSize=m_shape[0]; + for (unsigned i=1;i<m_shape.size();i++) + totSize=totSize*m_shape[i]; + if (totSize!=m_data.size()) + error("","Array is inconsistent!"); + + std::vector<Arrayelt>::size_type dataIndex=0; + write_subarray(stream,dataIndex,0); + stream << "]" << std::endl; + return; +} + + + /** + * @brief Creates a text representation of the array content. + * @param std::ostream where the text should be written + * + * Writes the content of the array to a ostream. The sub-arrays are + * enclosed by square-brackets and separated by commas. + */ + +void Arrayrep::write_subarray(std::ostream& stream, std::vector<Arrayelt>::size_type& idx, unsigned dimIndex) const { + if (dimIndex<(m_shape.size()-1)) { + stream << "[\n "; + for (unsigned i=0;i<m_shape[dimIndex];i++) { + write_subarray(stream,idx,dimIndex+1); + if (i==m_shape[dimIndex]-1) + stream << "]\n "; + else + stream << "],\n "; + } + } + else { // last dimension + stream << "[" << m_data[idx++]; + for (unsigned i=1;i<m_shape[dimIndex];i++) + stream << ", " << m_data[idx++]; + } + return; +} + + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/Root/ClassName.cxx b/EDM/athena/Control/CxxUtils/Root/ClassName.cxx new file mode 100644 index 00000000..674e94c6 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/ClassName.cxx @@ -0,0 +1,655 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/ClassName.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Recursively separate out template arguments in a C++ class name. + */ + + +#include "CxxUtils/ClassName.h" +#include "boost/foreach.hpp" +#include <cassert> + + +namespace CxxUtils { + + + +/** + * @brief Exception to signal a malformed class name. + */ +ClassName::ExcBadClassName::ExcBadClassName (const std::string& name) + : std::runtime_error ("ExcBadClassName: Malformed class name: `" + + name + "'") +{ +} + + +/** + * @brief Exception to signal a missing variable. + */ +ClassName::ExcMissingVariable::ExcMissingVariable (const std::string& var) + : std::runtime_error ("ExcMissingVariable: Variable `" + var + + "' referenced in substitution but not present " + "in matches map.") +{ +} + + +/** + * @brief Return the number of defined rules. + */ +size_t ClassName::Rules::size() const +{ + return m_rules.size(); +} + + +/** + * @brief Add a new transformation rule. + * @param pattern The pattern to match. + * @param replacement The expression with which to replace it. + * + * The pattern may contain variables that are then substituted into + * the replacement; for example, given a pattern of `A<$T, $T>` and + * a replacement of `B<$T>`, then `A<Foo<int>, Foo<int> >` would + * be transformed to `B<Foo<int> >'. + */ +void ClassName::Rules::add (const ClassName& pattern, + const ClassName& replacement) +{ + m_rules.insert (std::make_pair (pattern.name(), + std::make_pair (pattern, replacement))); +} + + +#if __cplusplus > 201100 +/** + * @brief Add a new transformation rule (move version). + * @param pattern The pattern to match. + * @param replacement The expression with which to replace it. + * + * The pattern may contain variables that are then substituted into + * the replacement; for example, given a pattern of `A<$T, $T>` and + * a replacement of `B<$T>`, then `A<Foo<int>, Foo<int> >` would + * be transformed to `B<Foo<int> >'. + */ +void ClassName::Rules::add (ClassName&& pattern, + ClassName&& replacement) +{ + std::string name = pattern.name(); + m_rules.insert (std::make_pair (name, + std::make_pair (std::move(pattern), + std::move(replacement)))); +} +#endif + + +/** + * @brief Apply the set of transformation rules to a class name object. + * @param cn The object to which the rules should be applied. + * Will be modified in place. + * + * All transformation rules are matched against @c cn. If any match, + * the object is replaced with the replacement portion of the rule + * with match results substituted. + * + * Returns true if any matches were made and false otherwise. + */ +bool ClassName::Rules::applyTo (ClassName& cn) const +{ + bool ret = false; + rulemap_t::const_iterator it = m_rules.find (cn.name()); + while (it != m_rules.end() && it->first == cn.name()) { + ClassName::match_t matches; + if (cn.match (it->second.first, matches)) { + cn = it->second.second.substCopy (matches); + ret = true; + } + ++it; + } + return ret; +} + + +/** + * @brief Apply transformations to a class name. + * @param name The class name to transform. + * + * Returns the transformed class name. + * + * This is just shorthand for calling `ClassName::applyRules`. + */ +std::string ClassName::Rules::apply (const std::string& name) const +{ + return ClassName::applyRules (name, *this); +} + + +/** + * @brief Default constructor. + * + * Needed for STL compatibility. + */ +ClassName::ClassName () + : m_const(false) +{ +} + + +/** + * @brief Parse a class name into component parts. + * @param name The name to parse. + * + * Raises a @c ExcBadClassName exception if the name isn't completely parsed. + */ +ClassName::ClassName (const char* name) + : m_const(false) +{ + std::string sname = name; + std::string::size_type pos = 0; + parse (sname, pos); + skipSpaces (sname, pos); + if (pos != sname.size()) + throw ExcBadClassName (sname); +} + + +/** + * @brief Parse a class name into component parts. + * @param name The name to parse. + * + * Raises a @c ExcBadClassName exception if the name isn't completely parsed. + */ +ClassName::ClassName (const std::string& name) + : m_const(false) +{ + std::string::size_type pos = 0; + parse (name, pos); + skipSpaces (name, pos); + if (pos != name.size()) + throw ExcBadClassName (name); +} + + +/** + * @brief Parse a class name into component parts. + * @param name String containing the name to parse. + * @param pos Position in the string at which parsing should start. + * + * @c pos is updated to point to past the point where parsing stopped. + */ +ClassName::ClassName (const std::string& name, std::string::size_type& pos) + : m_const (false) +{ + parse (name, pos); +} + + +/** + * @brief Swap this expression with another one. + * @param other The other expression with which to swap. + */ +void ClassName::swap (ClassName& other) +{ + std::swap (m_const, other.m_const); + std::swap (m_namespace, other.m_namespace); + std::swap (m_name, other.m_name); + m_targs.swap (other.m_targs); +} + + +/** + * @brief Set the const flag for this expression. + */ +void ClassName::setConst() +{ + m_const = true; +} + + +/** + * @brief Return the root name of the expression. + * + * In `A::B<C>`, the root name is `B`. + */ +std::string ClassName::name() const +{ + return m_name; +} + + +/** + * @brief Return the root name of the expression. + * + * In `A::B<C>`, the root name is `B`. + */ +std::string ClassName::qualifiedName() const +{ + std::string nsname; + if (m_namespace.size() > 0) + nsname = m_namespace[0].fullName() + "::"; + return nsname + m_name; +} + + +/** + * @brief Return the full name of the expression. + */ +std::string ClassName::fullName() const +{ + std::string name = qualifiedName(); + if (m_const) + name = "const " + name; + if (m_targs.size() > 0) { + name += '<'; + BOOST_FOREACH (const ClassName& cn, m_targs) { + if (name[name.size()-1] != '<') + name += ','; + name += cn.fullName(); + } + if (name[name.size()-1] == '>') + name += ' '; + name += '>'; + } + return name; +} + + +/** + * @brief Test two expressions for equality. + */ +bool ClassName::operator== (const ClassName& other) const +{ + if (m_name != other.m_name) + return false; + + if (m_const != other.m_const) + return false; + + if (m_namespace.size() != other.m_namespace.size()) + return false; + + if (m_targs.size() != other.m_targs.size()) + return false; + + if (m_namespace.size() > 0 && m_namespace[0] != other.m_namespace[0]) + return false; + + for (size_t i = 0; i < m_targs.size(); ++i) { + if (m_targs[i] != other.m_targs[i]) + return false; + } + + return true; +} + + +/** + * @brief Test two expressions for inequality. + */ +bool ClassName::operator!= (const ClassName& other) const +{ + return !(*this==other); +} + + +/** + * @brief Match this expression against a pattern. + * @param pattern The pattern to match. + * @param[out] matches Dictionary of pattern substitutions. + * + * Return true if @c pattern matches the current expression. + * @c pattern may contain dummy variables of the form `$T`. + * On a successful return, the map @c matches contains the + * variable assignments needed for the match. + */ +bool ClassName::match (const ClassName& pattern, match_t& matches) const +{ + matches.clear(); + return match1 (pattern, matches); +} + + +/** + * @brief Substitute variables into this expression. + * @param The dictionary of variables to substitute. + * + * If this expression contains variables like `$T`, they are replaced + * with the corresponding values from @c matches. If a variable is + * present in the expression but is not in @c matches, @c ExcMissingVariable + * is thrown. + * + * The substitutions are made in-place. + */ +void ClassName::subst (const match_t& matches) +{ + if (m_name[0] == '$') { + std::string var = m_name.substr (1, std::string::npos); + match_t::const_iterator it = matches.find (var); + if (it != matches.end()) { + bool const_save = m_const; + *this = it->second; + m_const |= const_save; + } + else { + throw ExcMissingVariable (var); + } + } + + BOOST_FOREACH (ClassName& c, m_namespace) + c.subst (matches); + BOOST_FOREACH (ClassName& c, m_targs) + c.subst (matches); +} + + +/** + * @brief Return a copy of this expression with variables substituted. + * @param The dictionary of variables to substitute. + * + * If this expression contains variables like `$T`, they are replaced + * with the corresponding values from @c matches. If a variable is + * present in the expression but is not in @c matches, @c ExcMissingVariable + * is thrown. + * + * The substitutions are made in a copy of the expression, which is returned. + */ +ClassName ClassName::substCopy (const match_t& matches) const +{ + ClassName cn (*this); + cn.subst (matches); + return cn; +} + + +/** + * @brief Apply a set of transformation rules to this object. + * @param rules The set of rules to apply. + * + * Recursively walk this expression, trying to apply the transformation + * rules in @c rules. If any matches are found, this expression + * is modified in-place and the walk is repeated. This function terminates + * when no further matches are found. + * + * Warning: An infinite loop is possible if the replacement for a pattern + * can always be matched by another pattern. + */ +void ClassName::applyRules (const Rules& rules) +{ + while (applyRules1 (rules)) + ; +} + + +/** + * @brief Apply a set of transformation rules a class name. + * param The name of the class to transform. + * @param rules The set of rules to apply. + * + * This is just shorthand for + * + *@code + * ClassName cn (name); + * cn.applyRules (rules); + * return cn.fullName(); + @endcode +*/ +std::string ClassName::applyRules (const std::string& name, + const Rules& rules) +{ + ClassName cn (name); + cn.applyRules (rules); + return cn.fullName(); +} + + +/** + * @brief Parse a string into a @c ClassName. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ +void ClassName::parse (const std::string& name, std::string::size_type& pos) +{ + m_name = parsePrimary (name, pos); + if (m_name.substr (0, 6) == "const ") { + m_const = true; + m_name.erase (0, 6); + } + if (m_name.size() >= 6 && m_name.substr (m_name.size()-6, 6) == " const") { + m_const = true; + m_name.erase (m_name.size()-6, 6); + } + + skipSpaces (name, pos); + while (pos < name.size()) { + if (name[pos] == '<') + parseTemplateArgs (name, pos); + else if (name[pos] == ':' && pos+1 < name.size() && name[pos+1] == ':') + parseNamespace (name, pos); + else + break; + } + skipSpaces (name, pos); + if (name.substr (pos, pos+5) == "const") { + m_const = true; + pos += 5; + } +} + + +/** + * @brief Parse a primary part of the class name. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * The primary part of the class name is a string without namespace + * and template delimiters. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ +std::string +ClassName::parsePrimary (const std::string& name, std::string::size_type& pos) +{ + skipSpaces (name, pos); + std::string out; + size_t nest = 0; + while (pos < name.size()) { + char c = name[pos]; + if (c == '(') + ++nest; + else if (c == ')' && nest > 0) + --nest; + else if (nest == 0 && (c == '<' || c == '>' || c == ',' || c == ':')) + break; + + out += c; + ++pos; + } + return out; +} + + +/** + * @brief Parse a namespace qualification. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * When this is called, the namespace part has already been parsed, + * and the next two characters in @c name are `::`. This reads in the + * remainder of the string as a @c ClassName, and then moves it inside + * the namespace given by the current object. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ +void ClassName::parseNamespace (const std::string& name, + std::string::size_type& pos) +{ + assert (pos+1 < name.size() && name[pos] == ':' && name[pos+1] == ':'); + pos += 2; + skipSpaces (name, pos); + + ClassName ns (name, pos); + ns.swap (*this); + ClassName* p = this; + while (p->m_namespace.size() > 0) + p = &p->m_namespace[0]; +#if __cplusplus > 201100 + p->m_namespace.push_back (std::move(ns)); +#else + p->m_namespace.resize(1); + p->m_namespace[0].swap (ns); +#endif +} + + +/** + * @brief Parse the template part of a name. + * @param name The string containing the name. + * @param pos Position in the string to start parsing. + * + * When this is called, the qualified name part of the name has already + * been parsed, and the next character in @c name is `::`. This reads in + * template arguments from @c name. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ +void ClassName::parseTemplateArgs (const std::string& name, + std::string::size_type& pos) +{ + assert (pos < name.size() && name[pos] == '<'); + ++pos; + while (true) { + skipSpaces (name, pos); +#if __cplusplus > 201100 + m_targs.emplace_back (name, pos); +#else + m_targs.push_back (ClassName (name, pos)); +#endif + skipSpaces (name, pos); + if (pos == name.size()) break; + if (name[pos] == '>') { + ++pos; + break; + } + else if (name[pos] == ',') + ++pos; + else + break; + } +} + + +/** + * @brief Skip past spaces in a string. + * @param name The string containing the name. + * @param pos Position in the string to start skipping. + * + * On return, @c pos will be updated to point just past the last + * character consumed. + */ +void ClassName::skipSpaces (const std::string& name, + std::string::size_type& pos) +{ + while (pos < name.size() && name[pos] == ' ') + ++pos; +} + + +/** + * @brief Match this expression against a pattern. + * @param pattern The pattern to match. + * @param[out] matches Dictionary of pattern substitutions. + * + * Return true if @c pattern matches the current expression. + * @c pattern may contain dummy variables of the form `$T`. + * On a successful return, the map @c matches contains the + * variable assignments needed for the match. + */ +bool ClassName::match1 (const ClassName& pattern, match_t& matches) const +{ + if (pattern.m_name[0] == '$') { + std::string var = pattern.m_name.substr (1, std::string::npos); + match_t::iterator it = matches.find (var); + if (it != matches.end()) { + if (pattern.m_const && !it->second.m_const) { + ClassName cn (it->second); + cn.setConst(); + return *this == cn; + } + return *this == it->second; + } + + matches[var] = *this; + if (pattern.m_const) { + if (m_const) + matches[var].m_const = false; + else + return false; + } + return true; + } + + if (m_const != pattern.m_const) + return false; + + if (m_name != pattern.m_name) + return false; + + if (m_namespace.size() != pattern.m_namespace.size()) + return false; + + if (m_targs.size() != pattern.m_targs.size()) + return false; + + if (m_namespace.size() > 0) { + if (!m_namespace[0].match1 (pattern.m_namespace[0], matches)) + return false; + } + + for (size_t i = 0; i < m_targs.size(); i++) { + if (!m_targs[i].match1 (pattern.m_targs[i], matches)) + return false; + } + + return true; +} + + +/** + * @brief Apply a set of transformation rules to this object. + * @param rules The set of rules to apply. + * + * Recursively walk this expression, trying to apply the transformation + * rules in @c rules. If any matches are found, this expression + * is modified in-place. + * + * Returns true if any matches were found. + */ +bool ClassName::applyRules1 (const Rules& rules) +{ + bool ret = rules.applyTo (*this); + + if (m_namespace.size() > 0) + ret |= m_namespace[0].applyRules1 (rules); + + for (size_t i = 0; i < m_targs.size(); i++) + ret |= m_targs[i].applyRules1 (rules); + + return ret; +} + + +} // namespace CxxUtils + diff --git a/EDM/athena/Control/CxxUtils/Root/FloatPacker.cxx b/EDM/athena/Control/CxxUtils/Root/FloatPacker.cxx new file mode 100644 index 00000000..dee0c68e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/FloatPacker.cxx @@ -0,0 +1,485 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/FloatPacker.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2009, from earlier code. + * @brief Pack/unpack floating-point data from/to a given number of bits. + */ + +#include "CxxUtils/FloatPacker.h" +#include "CxxUtils/ones.h" +#include <limits> +#include <string> +#include <sstream> +#include <iomanip> +#ifndef __APPLE__ +#include <ieee754.h> // ??? Is this standardized? +#else +//ieee754.h doesn't exist on MacOSX +union ieee754_double +{ + long double d; + struct { + unsigned int negative:1; + unsigned int exponent:11; + /* Together these comprise the mantissa. */ + unsigned int mantissa0:20; + unsigned int mantissa1:32; + } ieee; + struct { + unsigned int negative:1; + unsigned int exponent:11; + unsigned int quiet_nan:1; + /* Together these comprise the mantissa. */ + unsigned int mantissa0:19; + unsigned int mantissa1:32; + } ieee_nan; +}; + +#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */ + +#endif +#include <stdint.h> + + +namespace { + + + +/** + * @brief We sometimes need to be able to access a double + * as ints. + */ +union double_or_int { + ieee754_double d; + uint32_t i[2]; +}; + + +const int ieee754_double_bias = 0x3ff; +const int ieee754_double_exponent_bits = 11; +const int ieee754_double_mantissa0_bits = 20; +const int ieee754_double_mantissa1_bits = 32; + + +/// Abbreviation. +typedef CxxUtils::FloatPacker::Packdest Packdest; + +/// Size of @c Packdest in bits. +const int packdest_bits = std::numeric_limits<Packdest>::digits; + + +// Handy constant: A Packdest with 1 in the high bit. +const Packdest high_packdest_bit = (1U << (packdest_bits - 1)); + +const Packdest ieee754_double_exponent_mask = + (1U << ieee754_double_exponent_bits) - 1; + + +/** + * @brief Return the largest (signed) integer that can be represented + * With @c nbits bits. + * Boundary case: nbits=0 should return -1. + * @param nbits Number of bits. + */ +inline +int max_int (int nbits) +{ + return ((1U << nbits) >> 1) - 1; +} + + +/** + * @brief Return the smallest (signed) integer that can be represented + * With @c nbits bits. + * Boundary case: nbits=0 should return -1. + * @param nbits Number of bits. + */ +inline +int min_int (int nbits) +{ + return static_cast<int>(~0U << nbits) >> 1; +} + + +/** + * @brief Renormalize a denormal number. + * @param exponent[inout] The exponent of the number. + * Should initially be the denormal flag value. + * Will be modified in place. + * @param mantissa[inout] The mantissa of the number. + * Will be modified in place. + */ +void renormalize_denormal (int& exponent, + Packdest& mantissa) +{ + if (mantissa == 0) + exponent -= packdest_bits; // Lost precision here. + else { + while ((mantissa & high_packdest_bit) == 0) { + --exponent; + mantissa <<= 1; + } + mantissa <<= 1; + } +} + + +/** + * @brief If the number given by @a exponent and @a mantissa is too small + * to be represented by a normalized number in a representation + * where @a min_exp is the exponent value flagging denormals, convert + * it to a denormal representation. + * + * @param min_exp The denormal marker exponent value. + * @param round_bits Number of bits to consider for rounding. + * @param exponent[inout] The exponent of the number. + * Will be modified in place. + * param mantissa[inout] The mantissa of the number. + * Will be modified in place. + */ +void underflow_to_denormal (int min_exp, + int round_bits, + int& exponent, + Packdest& mantissa) +{ + if (exponent <= min_exp) { + Packdest mantissa_in = mantissa; + + // Denormalize the mantissa. + mantissa = (mantissa >> 1) | high_packdest_bit; + + // Now shift it right. + int shift = min_exp - exponent; + if (shift < packdest_bits) + mantissa >>= shift; + else + mantissa = 0; // underflow to 0. + + // Flag it as denormal. + exponent = min_exp; + + // Handle rounding, if desired. + if (round_bits) { + // + // +- packdest_bits - round_bits - 1 + // |- round_bits -|v + // mantissa: .................X.... + // v- shift+1 -^ + // mantissa_in: .....X................ + // ^ + // +- packdest_bits - round_bits + shift + // + int orig_pos = packdest_bits - round_bits + shift; + if (orig_pos < packdest_bits && + ((static_cast<Packdest> (1) << orig_pos) & mantissa_in) != 0) + { + Packdest lsb = (static_cast<Packdest> (1) << + (packdest_bits - round_bits)); + Packdest lsbmask = ~ (lsb - 1); + + // ??? If we overflow here, it means we have to go back + // to a normalized representation. Just punt for now. + if ((mantissa & lsbmask) != lsbmask) + mantissa += lsb; + } + } + } +} + + +} // unnamed namespace + + +namespace CxxUtils { + + +/** + * @brief Constructor. + * @param nbits The number of bits in the packed representation. + * @param nmantissa The number of bits to use for the mantissa + * and sign bit. + * @param scale Divide the input number by this before packing. + * @param is_signed If true, then one mantissa bit is used for a sign. + * @param round If true, numbers will be rounded. + * Otherwise, they will be truncated. + */ +FloatPacker::FloatPacker (int nbits, + int nmantissa, + double scale /*= 1*/, + bool is_signed /*= true*/, + bool round /*= false*/) + : m_nmantissa (nmantissa), + m_scale (scale), + m_is_signed (is_signed), + m_round (round) +{ + // scale==0 means not to scale. + // Use that instead of 1 since it's faster to test for 0. + if (scale == 1) + scale = 0; + + if (scale == 0) + m_invscale = 0; + else + m_invscale = 1. / m_scale; + + // Set up other cached values. + m_npack = m_nmantissa; + if (m_is_signed) + --m_npack; + + m_npack_ones = ones<Packdest> (m_npack); + + // Sign bit mask. + if (m_is_signed) + m_signmask = 1U << (nbits - 1); + else + m_signmask = 0; + + // Number of exponent bits. + m_nexp = nbits - m_nmantissa; + m_nexp_ones = ones<Packdest> (m_nexp); + + // Minimum exponent value. + m_min_exp = min_int (m_nexp); + + // Maximum exponent value. + m_max_exp = max_int (m_nexp); + + if (m_npack < 1 || m_npack > nbits) + m_lasterr = "Bad number of mantissa bits."; +} + + +/** + * @brief Check to see if an error occurred. + * @param err[out] If an error occurred, a description of it. + * @return True if an error occurred since the last call to @c errcheck. + */ +bool FloatPacker::errcheck (std::string& err) const +{ + if (!m_lasterr.empty()) { + err.swap (m_lasterr); + m_lasterr.clear(); + return true; + } + return false; +} + + +/** + * @brief Pack a value. + * @param src Value to pack. + * @return The packed value. + * + * For now, we convert floats to doubles before packing. + */ +FloatPacker::Packdest FloatPacker::pack (double src) const +{ + double_or_int d; + d.d.d = src; + + // Fast-path for zero. (Purely an optimization.) + // Note: can't use a double compare here. On some architectures (eg, MIPS) + // a denormal will compare equal to zero. + if (d.i[0] == 0 && d.i[1] == 0) + return 0; + + // Check for NaN and infinity. + if (d.d.ieee.exponent == ieee754_double_exponent_mask) { + std::ostringstream os; + os << "Bad float number: " << src << " (" << std::setbase(16) << d.i[0] + << " " << d.i[1] << ")"; + m_lasterr = os.str(); + d.d.d = 0; + } + + if (m_invscale) + d.d.d *= m_invscale; + + bool was_negative = false; + if (d.d.ieee.negative != 0) { + if (m_is_signed) { + was_negative = true; + d.d.d = -d.d.d; + } + else { + // Don't complain on -0. + if (d.d.d < 0) { + std::ostringstream os; + os << "Float overflow during packing: " << src; + m_lasterr = os.str(); + } + d.d.d = 0; + } + } + + // Check for zero again. + // (Also need to preserve the sign; the scale division may + // have underflowed.) + if (d.i[0] == 0 && d.i[1] == 0) { + if (was_negative) + return m_signmask; + else + return 0; + } + + // Get packdest_bits bits of mantissa. + + Packdest mantissa = + (d.d.ieee.mantissa0 << (packdest_bits - + ieee754_double_mantissa0_bits)) | + (d.d.ieee.mantissa1 >> + (ieee754_double_mantissa1_bits - + (packdest_bits - ieee754_double_mantissa0_bits))); + + // Get the unbiased exponent. + int exponent = + static_cast<int> (d.d.ieee.exponent) - ieee754_double_bias; + + // Do rounding, if requested. + if (m_round) { + Packdest lsbmask = (1 << (packdest_bits - m_npack)); + int roundbit; + Packdest roundmask; + if (lsbmask > 1) { + roundbit = (mantissa & (lsbmask >> 1)); + roundmask = ~ static_cast<Packdest> (roundbit - 1); + } + else { + roundbit = (d.d.ieee.mantissa1 & + ((1 << ((ieee754_double_mantissa1_bits - + (packdest_bits - + ieee754_double_mantissa0_bits)) - 1)))); + roundmask = ~ static_cast<Packdest> (0); + } + + if (roundbit != 0) { + // Handle the case where it would overflow. + if ((mantissa & roundmask) == roundmask) { + mantissa >>= 1; + mantissa |= roundmask; + exponent += 1; + } + + mantissa += lsbmask; + } + } + + // If the number is too large, bitch, and reset to the largest number. + if (exponent > m_max_exp) { + std::ostringstream os; + os << "Float overflow during packing: " << src; + m_lasterr = os.str(); + exponent = m_max_exp; + mantissa = static_cast<Packdest> (~0); + } + + // Handle denormals. (We've already handled the zero case.) + if (exponent == - ieee754_double_bias) + renormalize_denormal (exponent, mantissa); + + // If the number is too small, denormalize, or underflow to 0. + underflow_to_denormal (m_min_exp, m_round ? m_npack: 0, exponent, mantissa); + + // Pack in the mantissa bits. + Packdest dest = mantissa >> (packdest_bits - m_npack); + + // The exponent, if desired. + if (m_nexp > 0) + dest |= ((exponent - m_min_exp) << m_npack); + + // And the optional sign bit. + if (was_negative) + dest |= m_signmask; + + return dest; +} + + +/** + * @brief Unpack the value @c VAL. + * @param val The packed data. It should start with the low bit, + * and any extraneous bits should have been masked off. + */ +double FloatPacker::unpack (Packdest val) const +{ + // Fast-path for 0. + if (val == 0) + return 0; + + // Break apart the packed value. + bool was_negative = false; + if ((val & m_signmask) != 0) + was_negative = true; + + double d; + + // Fast path for fixed-point representations. + if (m_nexp == 0) { + Packdest mantissa = (val & m_npack_ones); + d = mantissa / ((double)m_npack_ones + 1); + if (was_negative) + d *= -1; + } + else { + // Get the mantissa. + Packdest mantissa = (val & m_npack_ones) << (packdest_bits - m_npack); + + // General case. + // Get the exponent. + int exponent = ((val >> m_npack) & m_nexp_ones); + exponent += m_min_exp; // unbias. + + ieee754_double dd; + + // Handle denormals. + if (exponent == m_min_exp) { + // Maybe it was -0? + if (mantissa == 0) { + dd.d = 0; + if (was_negative) + dd.ieee.negative = 1; + return dd.d; + } + + renormalize_denormal (exponent, mantissa); + } + + // Complain about overflow. + if (exponent >= max_int (ieee754_double_exponent_bits)) { + std::ostringstream os; + os << "Overflow while unpacking float; exponent: " << exponent; + m_lasterr = os.str(); + exponent = max_int (ieee754_double_exponent_bits) + 1; + mantissa = 0; // Infinity. + } + + // Underflow into denormal. + underflow_to_denormal ( - ieee754_double_bias, 0, + exponent, mantissa); + + // Pack into a double. + dd.ieee.negative = was_negative ? 1 : 0; + dd.ieee.exponent = exponent + ieee754_double_bias; + dd.ieee.mantissa0 = + (mantissa >> (packdest_bits - ieee754_double_mantissa0_bits)); + dd.ieee.mantissa1 = + (mantissa << (ieee754_double_mantissa0_bits - + (packdest_bits - ieee754_double_mantissa1_bits))); + d = dd.d; + } + + // Set the result. + if (m_scale) + d *= m_scale; + return d; +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/Root/MD5.cxx b/EDM/athena/Control/CxxUtils/Root/MD5.cxx new file mode 100644 index 00000000..cdd83b2d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/MD5.cxx @@ -0,0 +1,226 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CxxUtils/MD5.h" + +#include <cassert> +#include <string> +#include <cstdio> +#include <iostream> +#include <string.h> + +// MD5 simple initialization method +MD5::MD5() { + init(); + memset (m_buffer, 0, sizeof(m_buffer)); + memset (m_digest, 0, sizeof(m_digest)); +} + +// MD5 simple initialization method +MD5::MD5(unsigned char* buffer, unsigned long len) { + init(); + update(buffer, len); + finalize(); +} + +// MD5 block update operation. Continues an MD5 message-digest +// operation, processing another message block, and updating the +// context. +void MD5::update (unsigned char *input, unsigned int input_length) { + unsigned int idx, index, space; + if ( m_finalized ) { // so we can't update! + std::cerr << "MD5::update: Can't update a finalized digest!" << std::endl; + return; + } + // Compute number of bytes mod 64 + index = (unsigned int)((m_count[0] >> 3) & 0x3F); + // Update number of bits + if ( (m_count[0] += ((unsigned int) input_length << 3))<((unsigned int) input_length << 3) ) + m_count[1]++; + + m_count[1] += ((unsigned int)input_length >> 29); + space = 64 - index; // how much space is left in buffer + // Transform as many times as possible. + if (input_length >= space) { // ie. we have enough to fill the buffer + // fill the rest of the buffer and transform + memcpy (m_buffer + index, input, space); + transform (m_buffer); + // now, transform each 64-byte piece of the input, bypassing the buffer + for (idx = space; idx + 63 < input_length; idx += 64) + transform (input+idx); + + index = 0; // so we can buffer remaining + } + else { + idx = 0; // so we can buffer the whole input + } + + // and here we do the buffering: + memcpy(m_buffer+index, input+idx, input_length-idx); +} + +// MD5 finalization. Ends an MD5 message-digest operation, writing the +// the message digest and zeroizing the context. +void MD5::finalize () { + unsigned char bits[8]; + unsigned int index, padLen; + static unsigned char PADDING[64]={ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (m_finalized){ + std::cerr << "MD5::finalize: Already finalized this digest!" << std::endl; + return; + } + // Save number of bits + encode (bits, m_count, 8); + // Pad out to 56 mod 64. + index = (unsigned int) ((m_count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + update (PADDING, padLen); + // Append length (before padding) + update (bits, 8); + // Store state in digest + encode (m_digest, m_state, 16); + // Zeroize sensitive information + memset (m_buffer, 0, sizeof(*m_buffer)); + m_finalized=1; +} + +void MD5::raw_digest(unsigned char *s){ + if (m_finalized){ + memcpy(s, m_digest, 16); + return; + } + std::cerr << "MD5::raw_digest: Can't get digest if you haven't "<< + "finalized the digest!" << std::endl; +} + +std::string MD5::hex_digest() { + char s[33]; + if (!m_finalized){ + std::cerr << "MD5::hex_digest: Can't get digest if you haven't "<< + "finalized the digest!" <<std::endl; + return ""; + } + for (int i=0; i<16; i++) + sprintf(s+i*2, "%02x", m_digest[i]); + s[32]='\0'; + return s; +} + +// PRIVATE METHODS: +void MD5::init(){ + m_finalized=0; // we just started! + // Nothing counted, so count=0 + m_count[0] = 0; + m_count[1] = 0; + // Load magic initialization constants. + m_state[0] = 0x67452301; + m_state[1] = 0xefcdab89; + m_state[2] = 0x98badcfe; + m_state[3] = 0x10325476; +} + +// MD5 basic transformation. Transforms state based on block. +void MD5::transform (unsigned char* block){ + unsigned int a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], x[16]; + decode (x, block, 64); + assert(!m_finalized); // not just a user error, since the method is private + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + m_state[0] += a; + m_state[1] += b; + m_state[2] += c; + m_state[3] += d; + // Zeroize sensitive information. + memset ( (unsigned char *) x, 0, sizeof(x)); +} + +// Encodes input (unsigned int) into output (unsigned char). Assumes len is +// a multiple of 4. +void MD5::encode (unsigned char *output, unsigned int *input, unsigned int len) { + for (unsigned int i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char) (input[i] & 0xff); + output[j+1] = (unsigned char) ((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char) ((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char) ((input[i] >> 24) & 0xff); + } +} + +// Decodes input (unsigned char) into output (unsigned int). Assumes len is +// a multiple of 4. +void MD5::decode (unsigned int *output, unsigned char *input, unsigned int len){ + for (unsigned int i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((unsigned int)input[j]) | (((unsigned int)input[j+1]) << 8) | + (((unsigned int)input[j+2]) << 16) | (((unsigned int)input[j+3]) << 24); +} diff --git a/EDM/athena/Control/CxxUtils/Root/PackedArray.cxx b/EDM/athena/Control/CxxUtils/Root/PackedArray.cxx new file mode 100644 index 00000000..01b0ce40 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/PackedArray.cxx @@ -0,0 +1,492 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PackedArray.cxx,v 1.2 2008-12-12 04:26:19 ssnyder Exp $ +/** + * @file CxxUtils/src/PackedArray.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2007 + * @brief An array of unsigned values of some bit size, packed tightly. + */ + + +#include "CxxUtils/PackedArray.h" +#include <stdexcept> +#include <climits> +#include <cassert> + + +namespace { + + +/// Number of bits per entry in the base vector. +const int nper = sizeof (unsigned int) * CHAR_BIT; + + +/** + * @brief Return a mask with the lower @c sz bits set. + * @param sz Number of mask bits to set. + */ +inline +CxxUtils::PackedArray::value_type mask (size_t sz) +{ + return (1<<sz) - 1; +} + + +} // anonymous namespace + + +namespace CxxUtils { + + +/** + * @brief Calculate the number of entries in the base vector needed + * to hold @n entries with the current bitsize. + * @param n Number of packed entries desired. + */ +inline +PackedArray::size_type PackedArray::nbase (size_type n) const +{ + return (n * m_bitsize + nper-1) / nper; +} + + +/** + * @brief Find the index in the base vector where entry @n starts. + * @param n Packed entry desired. + */ +inline +PackedArray::size_type PackedArray::tondx (size_type n) const +{ + return (n * m_bitsize) / nper; +} + + +/** + * @brief Find the bit offset of entry @n within its entry in the base vector. + * @param n Packed entry desired. + */ +inline +int PackedArray::tooff (size_type n) const +{ + return (n * m_bitsize) % nper; +} + + +/** + * @brief Return the entry at base index @c ndx/offset @c off. + * @param ndx Index of the entry in the base vector at which the + * packed entry starts. + * @param off Bit offset within that entry where the packed entry starts. + */ +inline +PackedArray::value_type PackedArray::doget (size_type ndx, int off) const +{ + // Get the bits from the first entry. + value_type v = m_vec[ndx] >> off; + + // If the packed entry wraps between two base entries, collect the bits + // from the next base entry. + if (m_bitsize > nper - off) { + int bits = m_bitsize - (nper - off); + v |= ((m_vec[ndx+1] & mask(bits)) << (nper - off)); + } + + // Mask down to the proper number of bits. + return v & m_mask; +} + + +/** + * @brief Set the entry at base index @c ndx/offset @c off. + * @param ndx Index of the entry in the base vector at which the + * packed entry starts. + * @param off Bit offset within that entry where the packed entry starts. + * @param v Value to which the entry should be set. + */ +inline +void PackedArray::doset (size_type ndx, int off, value_type v) +{ + // Set the bits in the first entry. + m_vec[ndx] = (m_vec[ndx] & ~(m_mask<<off)) | ((v&m_mask) << off); + + // If the packed entry wraps between two base entries, set the bits + // in the next entry. + if (m_bitsize > nper - off) { + value_type mask2 = mask (m_bitsize - (nper - off)); + m_vec[ndx+1] = (m_vec[ndx+1] & ~mask2) | ((v >> (nper - off)) & mask2); + } +} + + +/** + * @brief Check that @c n is in range and throw @c out_of_range if not. + * @param n Index to check. + */ +void PackedArray::range_check (size_type n) const +{ + if (n >= m_size) { + throw std::out_of_range ("PackedArray"); + } +} + + +/** + * @brief Constructor. + * @param bitsize The size, in bits, of each element. + * Must be greater than zero, and not larger than + * the size of an unsigned int. + * @param allocator Allocator for the underlying vector. + */ +PackedArray::PackedArray (int bitsize, + const allocator_type& allocator/*=allocator_type()*/) + : m_bitsize (bitsize), + m_size (0), + m_mask (mask (bitsize)), + m_vec (allocator) +{ + assert (m_bitsize > 0 && m_bitsize <= nper); +} + + +/** + * @brief Constructor. + * @param bitsize The size, in bits, of each element. + * Must be greater than zero, and not larger than + * the size of an unsigned int. + * @param n Initial number of entries in the container. + * @param val Value to which the initial entries are to be set. + * @param allocator Allocator for the underlying vector. + */ +PackedArray::PackedArray (int bitsize, + size_type n, + value_type val /*= 0*/, + const allocator_type& allocator/*=allocator_type()*/) + : m_bitsize (bitsize), + m_size (n), + m_mask (mask (bitsize)), + m_vec (nbase(n), 0, allocator) +{ + assert (m_bitsize > 0 && m_bitsize <= nper); + if (val != 0) { + for (size_type i = 0; i < n; i++) + set (i, val); + } +} + + +/** + * @brief Set the container to multiple copies of the same value. + * @param n Number of entries to which the container is to be set. + * @param val Value to which the entries are to be set. + */ +void PackedArray::assign (size_type n, value_type u /*= 0*/) +{ + m_size = n; + m_vec.clear(); + m_vec.resize (nbase(n)); + if (u != 0) { + for (size_type i = 0; i < n; i++) + set (i, u); + } +} + + +/** + * @brief Returns the allocator of the underlying vector. + */ +PackedArray::allocator_type PackedArray::get_allocator() const +{ + return m_vec.get_allocator(); +} + + +/** + * @brief Returns the number of elements in the collection. + */ +PackedArray::size_type PackedArray::size() const +{ + return m_size; +} + + +/** + * @brief Returns the @c size() of the largest possible collection. + */ +PackedArray::size_type PackedArray::max_size() const +{ + return m_vec.max_size(); +} + + +/** + * @brief Returns the total number of elements that the collection can hold + * before needing to allocate more memory. + */ +PackedArray::size_type PackedArray::capacity() const +{ + return m_vec.capacity() * nper / m_bitsize; +} + + +/** + * @brief Resizes the collection to the specified number of elements. + * @param sz The new size of the collection. + * @param c Value to which any new elements are to be set. + */ +void PackedArray::resize (size_type sz, value_type c /*= 0*/) +{ + m_vec.resize (nbase (sz)); + if (sz > m_size) { + // Making the container bigger. Need to fill the remaining values. + if (c != 0) { + // Set them to something non-zero. + for (size_t i = m_size; i < sz; i++) + set (i, c); + } + else { + // Filling the new entries with 0. + // New elements in the base vector will have been set to 0. + // However, we also need to zero out any remaining packed elements + // (or piece thereof) in the last base element that was occupied + // before the resize. + int off = tooff (m_size); + // Don't need to do anything if packed entries exactly fit + // in the allocated base size. + if (off != 0) { + size_t ndx = tondx (m_size); + m_vec[ndx] &= mask (off); + } + } + } + m_size = sz; +} + + +/** + * @brief Returns @c true if the collection is empty. + */ +bool PackedArray::empty() const +{ + return m_size == 0; +} + + +/** + * @brief Attempt to preallocate enough memory for a specified number + * of elements. + * @param n Number of elements required. + */ +void PackedArray::reserve (size_type n) +{ + m_vec.reserve (nbase (n)); +} + + +/** + * @brief Return the entry at index @c n. + * @param n The index of the entry to retrieve. + */ +PackedArray::value_type PackedArray::get (size_type n) const +{ + return doget (tondx (n), tooff (n)); +} + + +/** + * @brief Set the entry at index @c n. + * @param n The index of the entry to set. + * @param val The new value for the entry at index @c n. + */ +void PackedArray::set (size_type n, value_type val) +{ + return doset (tondx (n), tooff (n), val); +} + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * No bounds checking is done. + * Note that we return a @c value_type rather than a reference. + */ +PackedArray::value_type PackedArray::operator[] (size_type n) const +{ + return doget (tondx (n), tooff (n)); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * No bounds checking is done. + * Note that we return a proxy object rather than a reference. + */ +PackedArray::proxy PackedArray::operator[] (size_type n) +{ + return proxy (*this, n); +} + + +/** + * @brief Access an element, as an rvalue. + * @param n Array index to access. + * @return The element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a @c value_type rather than a reference. + */ +PackedArray::value_type PackedArray::at (size_type n) const +{ + range_check (n); + return doget (tondx (n), tooff (n)); +} + + +/** + * @brief Access an element, as an lvalue. + * @param n Array index to access. + * @return Proxy to the element at @a n. + * + * Will raise @c std::out_of_range if the index is out-of-bounds. + * Note that we return a proxy object rather than a reference. + */ +PackedArray::proxy PackedArray::at (size_type n) +{ + range_check (n); + return proxy (*this, n); +} + + +/** + * @brief Access the first element in the collection as an rvalue. + * @return The first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c value_type rather than a reference. + */ +PackedArray::value_type PackedArray::front () const +{ + return doget (0, 0); +} + + +/** + * @brief Access the last element in the collection as an rvalue. + * @return The last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a @c value_type rather than a reference. + */ +PackedArray::value_type PackedArray::back () const +{ + return doget (tondx (m_size-1), tooff (m_size-1)); +} + + +/** + * @brief Access the first element in the collection as an lvalue. + * @return Proxy to the first element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference. + */ +PackedArray::proxy PackedArray::front () +{ + return proxy (*this, 0); +} + + +/** + * @brief Access the last element in the collection as an lvalue. + * @return Proxy to the last element in the collection. + * + * No checking is done to ensure that the container is not empty. + * Note that we return a proxy object rather than a reference. + */ +PackedArray::proxy PackedArray::back () +{ + return proxy (*this, m_size-1); +} + + +/** + * @brief Add an element to the end of the collection. + * @param x The element to add to the collection. + */ +void PackedArray::push_back (value_type x) +{ + ++m_size; + size_t nb = nbase (m_size); + if (nb != m_vec.size()) + m_vec.resize (nb); + doset (tondx (m_size-1), tooff (m_size-1), x); +} + + +/** + * @brief Remove the last element from the collection. + */ +void PackedArray::pop_back () +{ + --m_size; + size_t nb = nbase (m_size); + if (nb != m_vec.size()) + m_vec.resize (nb); +} + + +/** + * @brief Swap this collection with another. + * @param other The collection with which to swap. + */ +void PackedArray::swap (PackedArray& other) +{ + std::swap (m_bitsize, other.m_bitsize); + std::swap (m_size, other.m_size); + std::swap (m_mask, other.m_mask); + std::swap (m_vec, other.m_vec); +} + + +/** + * @brief Erase all the elements in the collection. + */ +void PackedArray::clear () +{ + m_size = 0; + m_vec.clear(); +} + + +/** + * @brief Change the bitsize of the container. + * @brief bitsize The new bitsize. + * + * This method may only be called when the container is empty. + */ +void PackedArray::set_bitsize (int bitsize) +{ + assert (m_size == 0); + assert (bitsize > 0 && bitsize <= nper); + m_bitsize = bitsize; + m_mask = mask (bitsize); +} + + +/** + * @brief Return the bitsize of the container. + */ +int PackedArray::bitsize () const +{ + return m_bitsize; +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/Root/PageAccessControl.cxx b/EDM/athena/Control/CxxUtils/Root/PageAccessControl.cxx new file mode 100644 index 00000000..2d4a797a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/PageAccessControl.cxx @@ -0,0 +1,128 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#define DEBUG 1 +#include <algorithm> /* sort etc */ +#include <sys/mman.h> /* mprotect */ +#include "CxxUtils/PageAccessControl.h" +#include "CxxUtils/page_access.h" +#include <iostream> +using athena::page_address; +using athena::next_page_address; + +PageAccessControl::Entry::Entry(void* a, size_t l, int p, void* pl): + addr(page_address(a)), lenProt(l), prot(p), leak(pl), restored(0) {} + + +void +PageAccessControl::sort() { + if (!m_protectedIsSorted) { + std::sort(m_protected.begin(), m_protected.end()); + m_protectedIsSorted=true; + } +} +bool +PageAccessControl::restorePageProt(const void * caddr) { + void* addr(const_cast<void*>(caddr)); + int rc(-1); + sort(); + Entry ea(addr,0,0,0); + protected_t::iterator entry= + std::lower_bound(m_protected.begin(), m_protected.end(), ea); + if (entry != m_protected.end() && + entry->addr == ea.addr) { + //found it. Restore page prot + rc=mprotect( page_address(entry->addr), entry->lenProt, entry->prot); + if (rc==0) { +#ifdef DEBUG + printf("PageAccessControl::restorePageProt DEBUG: restored protection %i for page %p containing address %p \n", + entry->prot, + page_address(entry->addr), + entry->addr); + printf(" FIXME NOT Freeing memory at %p \n", entry->leak ); +#endif + // free(entry->leak); + entry->leak=0; + ++(entry->restored); + } + } else printf("WARNING no entry in procmap for addr=%p, page protection not restored \n",addr); + return (rc == 0); +} + +bool +PageAccessControl::protectPage(const void* caddr, size_t objSize, int prot) { + void* addr(const_cast<void*>(caddr)); + int rc(-1); + const procmaps::Entry *e=m_pmaps.getEntry(addr,true); + //this is the length of the range we are going to protect + if (0 != e) { + void *pageAddr = page_address(addr); + size_t lenProt = (size_t)addr - (size_t)(pageAddr) + objSize; + size_t nextProt = (size_t)addr + objSize; + size_t nextUnprot = (size_t)(next_page_address((void*)(nextProt-1))); + int pageProt(PROT_NONE); + if (e->readable) pageProt |= PROT_READ; + if (e->writable) pageProt |= PROT_WRITE; + if (e->executable) pageProt |= PROT_EXEC; + if (pageProt != prot) { + //fill up the space from nextProt to nextUnprot to avoid allocations + //in the locked pages, and SEGVs... +// void *leak(0); +// if (0 == (prot & PROT_WRITE)) { +// size_t lenLeak(nextUnprot-nextProt-1); +// leak=malloc(lenLeak); +// if ((size_t)leak<nextUnprot && (size_t)leak + lenLeak>=nextUnprot) { +// //we do not want to allocate our buffer memory past the current +// //page, so trim it down +// free(leak); +// lenLeak=nextUnprot - (size_t)leak -1; +// leak=malloc(lenLeak); +// } +// if (leak < pageAddr || +// (size_t)leak >= nextUnprot) { +// //leak has been allocated into previous/next page +// //better get rid of it as it will likely +// //be locked by another protectPage +// free(leak); +// leak=0; +// } else { +// #ifdef DEBUG +// printf("PageAccessControl::protectPage DEBUG: fill up space from %p to 0x%x to avoid allocations in locked pages\n", +// leak, (int)leak+lenLeak); +// #endif +// } +// } + + if (0 == (rc = mprotect( pageAddr, + lenProt, + prot))) { + m_protected.push_back(Entry(pageAddr,lenProt, pageProt, 0)); + m_protectedIsSorted=false; //FIXME we should use a mapvector +#ifdef DEBUG + printf("PageAccessControl::protectPage DEBUG: set protection %i for page range %p - 0x%lx containing address range=%p - 0x%lx\n", + prot, + pageAddr, + (long unsigned int)(nextUnprot - 1), + addr, + (long unsigned int)(nextProt -1) ); +#endif + } + } else rc=0; + } else printf("PageAccessControl::protectPage WARNING: no entry in procmap for addr=%p, page protection not restored \n",addr); + return (rc == 0); +} + +bool PageAccessControl::accessed(const void* address) const { + bool acc(false); + //fixme: poor man implementation + Entry eaxx(const_cast<void*>(address),0,0,0); + PageAccessControl::const_iterator ia(beginProtectedPtrs()), + ea(endProtectedPtrs()); + while (!acc && ia != ea) { + // std::cout << address << "page addr " << eaxx.addr << " ia " << ia->addr << " res " << ia->restored << std::endl; + acc = (eaxx.addr == ia->addr && 0 != ia->restored); + ++ia; + } + return acc; +} diff --git a/EDM/athena/Control/CxxUtils/Root/PtrAccessSEGVHandler.cxx b/EDM/athena/Control/CxxUtils/Root/PtrAccessSEGVHandler.cxx new file mode 100644 index 00000000..782cea18 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/PtrAccessSEGVHandler.cxx @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#define DEBUG 1 + +#include "CxxUtils/PtrAccessSEGVHandler.h" +#include "CxxUtils/PageAccessControl.h" +#include <cstdio> + +void +PtrAccessSEGVHandler::handle(int /*signal_number*/,siginfo_t *sigi,void * /*unused*/) { + void *addr=sigi->si_addr; +#ifdef DEBUG + printf("page fault @address=%p\n",sigi->si_addr); +#ifdef __ARCH_SI_TRAPNO + printf("page fault trapno=%d\n",sigi->si_trapno); +#endif + printf("page fault signo=%d\n",sigi->si_signo); + printf("page fault errno=%d\n",sigi->si_errno); + printf("this page fault failed because "); + if (SEGV_MAPERR == sigi->si_code) + printf("you tried to access an invalid address\n"); + else if (SEGV_ACCERR == sigi->si_code) { + printf("you tried to access a protected address\n"); + } else printf(" an unknown reason. Page fault code=%d\n",sigi->si_code); +#endif + //record the access and restore page protection + if (SEGV_ACCERR == sigi->si_code) { + m_pac.restorePageProt(addr); + m_accessed.push_back(addr); + } else abort(); +} diff --git a/EDM/athena/Control/CxxUtils/Root/SealDebug.cxx b/EDM/athena/Control/CxxUtils/Root/SealDebug.cxx new file mode 100644 index 00000000..ee7e226d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/SealDebug.cxx @@ -0,0 +1,982 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/src/SealDebug.cxx + * @author Lassi Tuura (original author) + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS) + * @date Oct, 2008 + * + * Search for `wlav' to find changes from the SEAL version. All + * includes were modified, all ASSERT macro's were dropped in + * favor of assert, only stack trace functionality was kept. + * + * To comply with coverity rules, changed sprintf -> snprintf + * (wlav, 03/11/11) + */ + +//<<<<<< INCLUDES >>>>>> + +#include "CxxUtils/SealCommon.h" // wlav +#include "CxxUtils/SealDebug.h" // wlav +#include "CxxUtils/SealSignal.h" // wlav +#include "CxxUtils/SealSharedLib.h" // wlav + +// wlav copied from SealBase/sysapi/DebugAids.h +#include <cstring> +# include <cctype> +# include <cstdio> +# include <cstdlib> +# include <iostream> +# include <iomanip> +# include <sstream> // wlav +# include <climits> // wlav + +# ifdef _WIN32 +# include <windows.h> +# include <winnt.h> +# include <imagehlp.h> +//# include <io.h> +# else +# include <unistd.h> +# include <sys/wait.h> +# if HAVE_BACKTRACE_SYMBOLS_FD // GNU +# include <execinfo.h> +# include <sys/uio.h> +# include <cxxabi.h> +# endif +# if HAVE_DLADDR // Linux, Solaris +# include <dlfcn.h> +# endif +# if HAVE_EXCEPTION_H + // This is yucky. KCC's <exception.h> that has nothing to do with the + // header we are looking for (it redirect to <exception>). This ugly + // workaround allows us to find the (IRIX) header we are looking for. +# if defined __KCC && defined __sgi +# include </usr/include/exception.h> +# elif defined __sgi +# include <exception.h> +# endif +# endif +# if HAVE_EXCPT_H // IRIX +# include <excpt.h> +# undef try // Defined on SGI to structured exception handling goop +# undef catch // Defined on SGI to structured exception handling goop +# endif +# if HAVE_RLD_INTERFACE_H // Tru64 (IRIX) +# include <rld_interface.h> +# endif +# if HAVE_PDSC_H // Tru64 +# include <pdsc.h> +# endif +# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) // GCC 3.4+ C++ ABI +# include <sys/uio.h> +# endif +# endif + +// Windows doesn't have this, so fake a suitable substitute +# ifdef _WIN32 +# define STDERR_HANDLE GetStdHandle (STD_ERROR_HANDLE) +# else +# define STDERR_HANDLE STDERR_FILENO +# endif + +// Define a suitable wrapper to write to system file descriptors. +// This is needed because on Windows we are using HANDLEs, not the +// compiler's crippled posixy interface. +# ifdef _WIN32 +# define MYWRITE(fd,data,n) do { DWORD written; WriteFile(fd,data,n,\ + &written,0); } while (0) +# else +# define MYWRITE(fd,data,n) write(fd,data,n) +# endif + +// Helper to write literals +# define MYWRITELIT(fd,str) MYWRITE(fd,str,sizeof(str)-1) + +//<<<<<< PUBLIC CONSTANTS >>>>>> +//<<<<<< PUBLIC TYPES >>>>>> +//<<<<<< PUBLIC VARIABLES >>>>>> + +#if HAVE_BACKTRACE_SYMBOLS_FD +/** The maximum stack trace depth for systems where we request the + stack depth separately (GNU libc-based systems). */ +static const int MAX_BACKTRACE_DEPTH = 128; +#endif + + +#if HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR +// sss +#include <unistd.h> +#include <errno.h> +namespace { + + +std::string addr2LinePath = "/usr/bin/addr2line"; + + +struct BacktraceInit +{ + BacktraceInit() + { + // backtrace() has a one-time initialization that uses malloc(). + // so call it once now. + void* trace[1]; + backtrace (trace, 1); + + // Also test for eu-addr2line. + if (access ("/usr/bin/eu-addr2line", F_OK) == 0) + addr2LinePath = "/usr/bin/eu-addr2line"; + } +}; +BacktraceInit backtraceInit; + + +// This is like popen, except that it returns a fd rather +// than a FILE*. The PID is returned in pid. +// This is to avoid memory allocation. +int stacktracePopenFD (const char* cmd, pid_t& child_pid) +{ + int stat; + int fds[2]; + + // The glibc popen() uses pipe2() here with O_CLOEXEC. + // pipe2() is linux-specific, though, so avoid it here. + stat = pipe (fds); + if (stat < 0) return stat; + + int parent_end = fds[0]; + int child_end = fds[1]; + + child_pid = fork(); + if (child_pid == 0) { + int child_std_end = 1; + close (parent_end); + if (child_end != child_std_end) { + dup2 (child_end, child_std_end); + close (child_end); + } + + /* POSIX.2: "popen() shall ensure that any streams from previous + popen() calls that remain open in the parent process are closed + in the new child process." + + For our specific case here, we ignore this. */ + + execl ("/bin/sh", "sh", "-c", cmd, (char *) 0); + _exit (127); + } + + close (child_end); + if (child_pid < 0) { + close (parent_end); + return child_pid; + } + + return parent_end; +} + + +int stacktracePcloseFD (int fd, pid_t child_pid) +{ + int stat = close (fd); + if (stat < 0) return stat; + + /* POSIX.2 Rationale: "Some historical implementations either block + or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting + for the child process to terminate. Since this behavior is not + described in POSIX.2, such implementations are not conforming." */ + pid_t wait_pid; + int wstatus; + do { + wait_pid = waitpid (child_pid, &wstatus, 0); + } while (wait_pid == -1 && errno == EINTR); + + if (wait_pid == -1) + return -1; + return wstatus; +} + + +int stacktraceReadline (int fd, char* buf, int buflen) +{ + int len = 0; + while (len < buflen-1) { + int stat = read (fd, buf, 1); + if (stat < 0) return stat; + if (stat == 0) break; + if (*buf == '\n') break; + ++len; + ++buf; + } + *buf = '\0'; + return len; +} + + +} // anonymous namespace +// sss +#endif + + +//namespace seal { wlav +namespace Athena { // wlav +//<<<<<< PRIVATE DEFINES >>>>>> +//<<<<<< PRIVATE CONSTANTS >>>>>> +//<<<<<< PRIVATE TYPES >>>>>> +//<<<<<< PRIVATE VARIABLE DEFINITIONS >>>>>> +//<<<<<< PUBLIC VARIABLE DEFINITIONS >>>>>> +//<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>> + +/** The default output file descriptor for #stacktrace(). */ +IOFD DebugAids::s_stackTraceFd = IOFD_INVALID; + +//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>> + +#ifdef _WIN32 +// /** WIN32 function to grab the current PC address from the SEH context. +// We need this to grab the exception context so we can walk the stack +// in #Debug::stacktrace(). We use SEH (as compiler-independently as +// we can) as only XP 64-bit has RtlGetContext() function. */ +// static LONG CALLBACK +// GrabExceptionContext (PEXCEPTION_POINTERS info) +// { +// *((CONTEXT *) info->ExceptionRecord->ExceptionInformation[0]) +// = *info->ContextRecord; +// return EXCEPTION_EXECUTE_HANDLER; +// } + +/** Helper function to translate the virtual PC address @a addr into a + logical address. If the address translates to a known module (DLL + or executable) memory mapping range, fills @a name (of maximum + length @a length) with the name of the module, sets @a section to + the index of the memory mapping section within the module, @a + offset to a @a addr's relative offset within @a section, and + returns @c true. Otherwise returns @a false and @a name, @a + section and @a offset will have undefined values. Used to + translate PC addresses to module addresses during the stack walk. */ +bool +GetLogicalAddress (PVOID addr, PTSTR name, DWORD length, + DWORD §ion, DWORD &offset) +{ + MEMORY_BASIC_INFORMATION info; + + if (! VirtualQuery (addr, &info, sizeof (info))) + return false; + + DWORD module = (DWORD) info.AllocationBase; + if (! GetModuleFileName ((HMODULE) module, name, length)) + return false; + + PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER) module; + PIMAGE_NT_HEADERS ntheader + = (PIMAGE_NT_HEADERS) (module + dosheader->e_lfanew); + PIMAGE_SECTION_HEADER sect = IMAGE_FIRST_SECTION (ntheader); + DWORD rva = (DWORD) addr - module; + + for (unsigned i = 0; i < ntheader->FileHeader.NumberOfSections; ++i,++sect) + { + DWORD sect_start = sect->VirtualAddress; + DWORD sect_end = sect_start + std::max (sect->SizeOfRawData, + sect->Misc.VirtualSize); + + if ((rva >= sect_start) && (rva <= sect_end)) + { + section = i+1; + offset = rva - sect_start; + return true; + } + } + + assert (false); + return false; +} +#endif + +/** + * Write out stack trace line to FD. + * IP is the instruction pointer. + * (sss) + */ +void DebugAids::stacktraceLine (IOFD fd, + unsigned long addr) +{ + iovec bufs [7]; + int nbufs = 0; + const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits; + char addrbuf [addrbuf_size]; + +#if HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR + const int diffbuf_size = 15 + BitTraits<unsigned long>::HexDigits; + char diffbuf [diffbuf_size]; + static const char trailer [] = "]\n"; + Dl_info info; + + if (dladdr ((void*)addr, &info) && info.dli_fname && info.dli_fname[0]) + { + const char *libname = info.dli_fname; + + unsigned long symaddr = (unsigned long) info.dli_saddr; + bool gte = (addr >= symaddr); + unsigned long diff = (gte ? addr - symaddr : symaddr - addr); + + // RS start + int length = 0; + + const int relbuf_size = 7 + BitTraits<unsigned long>::HexDigits; + char relbuf [relbuf_size]; + + // difference of two pointers + unsigned long libaddr = (unsigned long) info.dli_fbase; + unsigned long relative_address = (addr >= libaddr) ? addr - libaddr : libaddr - addr; + if (strstr (info.dli_fname, ".so") == 0) + relative_address = addr; + + // need popen for addr2line ... + int pfd; + pid_t child_pid; + char line[ LINE_MAX ]; + char dembuf[ LINE_MAX ]; + const char* symname = dembuf; + size_t demlen = 0; + + // did we find valid entry ? + size_t len = strlen(info.dli_fname); + if ( len > 0 && len + 80 < LINE_MAX) + { + if (getenv ("LD_PRELOAD")) + unsetenv ("LD_PRELOAD"); + + if ( addr2LinePath == "/usr/bin/eu-addr2line" ) + { + snprintf (line, LINE_MAX, "%s -f -e %s %p | /usr/bin/c++filt | /usr/bin/tr \\\\012 \\\\040 ", + addr2LinePath.c_str(), + info.dli_fname, + (void*)relative_address); + } + else + { + snprintf (line, LINE_MAX, "%s -f -C -e %s %p", + addr2LinePath.c_str(), + info.dli_fname, + (void*)relative_address); + } + + pfd = stacktracePopenFD( line, child_pid ); + + length = 1; + line[0] = ' '; + + // did we succeed to open the pipe? + if ( pfd >= 0 ) + { + demlen = stacktraceReadline (pfd, dembuf, sizeof(dembuf)); + + length = stacktraceReadline (pfd, line+1, sizeof(line)-1); + if (length >= 0) ++length; + + int stat = stacktracePcloseFD (pfd, child_pid); + + // don't print anything, if nothing is found + if ( stat || line[1] == '?' || length < 0) + { + line[1] = '\0'; + length = 0; + } + + if ( stat || demlen <= 0 || dembuf[0] == '?') { + symname = info.dli_sname; + if (!symname) symname = "???"; + demlen = strlen (symname); + } + + } + } + // RS end + + bufs [nbufs].iov_base = addrbuf; + bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr); + ++nbufs; + + bufs [nbufs].iov_base = (void *) symname; // discard const + bufs [nbufs].iov_len = demlen; + ++nbufs; + + // RS start + bufs [nbufs].iov_base = line; + bufs [nbufs].iov_len = length; + ++nbufs; + // RS end + + bufs [nbufs].iov_base = diffbuf; + bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %c 0x%lx [", + gte ? '+' : '-', diff); + ++nbufs; + + bufs [nbufs].iov_base = (void *) libname; // discard const + bufs [nbufs].iov_len = strlen (libname); + ++nbufs; + + // RS start + bufs [nbufs].iov_base = relbuf; + bufs [nbufs].iov_len = snprintf( relbuf, relbuf_size, " D[%p]", (void*)relative_address ); + ++nbufs; + // RS end + + bufs [nbufs].iov_base = (void *) trailer; // discard const + bufs [nbufs].iov_len = 2; + ++nbufs; + + } + else +#endif + { + bufs [nbufs].iov_base = addrbuf; + bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr); + ++nbufs; + + bufs [nbufs].iov_base = (void *) "<unknown function>\n"; //no const + bufs [nbufs].iov_len = 19; + ++nbufs; + } + + writev (fd, bufs, nbufs); +} + + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) // FIXME: Check +extern "C" { + typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); + struct _Unwind_Context; + typedef enum + { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 + } _Unwind_Reason_Code; + typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *); + extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *); + extern _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *); + extern _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); +} + +/** IA64-ABI specific stack walking routine. This is mostly available + on platforms with GCC 3.4+, but also with other compilers that have + adopted the same ABI standard. This walker seems to be limited to + walking only through frames with DWARF2 exception data, so it may + not be able to go through all C libraries. It does seem to be + able to signal frames on a number of platforms however. */ +_Unwind_Reason_Code +unwindWalkStack (_Unwind_Context *ctx, void *data) +{ + IOFD fd = *(IOFD *) data; + iovec bufs [5]; + int nbufs = 0; + const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits; + char addrbuf [addrbuf_size]; + const int diffbuf_size = 10 + 2 * BitTraits<unsigned long>::HexDigits; + char diffbuf [diffbuf_size]; + static const char trailer [] = "]\n"; + unsigned long ip = _Unwind_GetIP (ctx); + unsigned long ir = _Unwind_GetRegionStart (ctx); + +# if HAVE_DLADDR + Dl_info info; + if (dladdr ((void *) ir, &info) && info.dli_fname && info.dli_fname[0]) + { + const char *libname = info.dli_fname; + const char *symname = (info.dli_sname && info.dli_sname[0] + ? info.dli_sname : "?"); + unsigned long symaddr = (unsigned long) info.dli_saddr; + bool gte = (ip >= symaddr); + unsigned long diff = (gte ? ip - symaddr : symaddr - ip); + + bufs [nbufs].iov_base = addrbuf; + bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip); + ++nbufs; + + bufs [nbufs].iov_base = (char *) symname; // discard const + bufs [nbufs].iov_len = strlen (symname); + ++nbufs; + + bufs [nbufs].iov_base = diffbuf; + bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %s 0x%lx [", + gte ? "+" : "-", diff); + ++nbufs; + + bufs [nbufs].iov_base = (char *) libname; // discard const + bufs [nbufs].iov_len = strlen (libname); + ++nbufs; + + bufs [nbufs].iov_base = (char *) trailer; // discard const + bufs [nbufs].iov_len = 2; + ++nbufs; + } + else +# endif // HAVE_DLADDR + { + bufs [nbufs].iov_base = addrbuf; + bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip); + ++nbufs; + + bufs [nbufs].iov_base = diffbuf; + bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " <?%08lx> + 0x%lx\n", + ir, ip - ir); + ++nbufs; + } + + writev (fd, bufs, nbufs); + return _URC_NO_REASON; +} +#endif // GCC 3.4+ + +//<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>> + +// Change the path of the binary used for symbolization. +void DebugAids::setStackTraceAddr2Line (const char* path) +{ + addr2LinePath = path; +} + + +#if HAVE_U_STACK_TRACE +// HP-UX stack walker (http://devresource.hp.com/STK/partner/unwind.pdf) +extern "C" void U_STACK_TRACE (void); +#endif + +#if HAVE_XL_TRBK +// AIX stack walker (from xlf FORTRAN 90 runtime). +extern "C" void xl__trbk (void); +#endif + +//<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>> + +/** Set and return the file descriptor for stack trace output. + + If @a fd is the default invalid descriptor value, returns the + current value without changing the setting. This value is only + effective for #stacktrace(), but can be overridden by the + argument given to that function. */ +IOFD +DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */) +{ + if (s_stackTraceFd == IOFD_INVALID) + s_stackTraceFd = STDERR_HANDLE; + + IOFD old = s_stackTraceFd; + if (fd != IOFD_INVALID) + s_stackTraceFd = fd; + return old; +} + +/** Produce a stack trace. + + Prints the current stack trace to file descriptor @a fd or if the + default invalid descriptor, the currently registered stack trace + descriptor as registered with #stacktraceFd(). Avoids unnecessary + memory allocation so it should be safe to call this function even + in dire situations. On some systems the implementation always + outputs to the standard error and has no means for redirection. + On these systems an attempt is made to redirect standard error + momentarily elsewhere and then redirect standard error to the + desired file descriptor, invoke the output, and redirect standard + error back to its original location. If the redirection fails or + the system has no stack tracing support, no stack trace is + produced. */ +void +DebugAids::stacktrace (IOFD fd /* = IOFD_INVALID */) +{ + if (s_stackTraceFd == IOFD_INVALID) + s_stackTraceFd = STDERR_HANDLE; + + if (fd == IOFD_INVALID) + fd = s_stackTraceFd; + + std::cerr.flush (); + fflush (stderr); + +#ifdef _WIN32 + // FIXME: Autoload all these functions so users don't need to + // link in imagehlp.dll. + if (! SymInitialize (GetCurrentProcess (), NULL, TRUE)) + { + MYWRITELIT (fd, ("failed to dump stack trace:" + " cannot get symbolic information\n")); + return; + } + + union SYMBUFFER { + IMAGEHLP_SYMBOL sym; + BYTE buffer [ sizeof (IMAGEHLP_SYMBOL) + 512 ]; + }; + + unsigned level = 0; + CONTEXT context; + STACKFRAME frame; + SYMBUFFER symbol; + IMAGEHLP_MODULE module; + char modulename [MAX_PATH]; + DWORD section; + DWORD offset; + const int buf_size = 2*40+6; // ample for two 128+ bit numbers + char buf [buf_size]; + // DWORD exceptargs [] = { (DWORD) &context }; + + // FIXME: XP 64-bit adds: RtlCaptureContext (&context); + // This is documented to *not* work, but apparently it does. + context.ContextFlags = CONTEXT_FULL; + if (! GetThreadContext (GetCurrentThread (), &context)) + return; + + // LPTOP_LEVEL_EXCEPTION_FILTER oldseh + // = SetUnhandledExceptionFilter (&GrabExceptionContext); + // RaiseException (0, 0, 1, exceptargs); + // SetUnhandledExceptionFilter (oldseh); + + memset (&module, 0, sizeof (module)); + memset (&frame, 0, sizeof (frame)); + + module.SizeOfStruct = sizeof (module); + + frame.AddrPC.Offset = context.Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Esp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Ebp; + frame.AddrFrame.Mode = AddrModeFlat; + + while (true) + { + if (! StackWalk (IMAGE_FILE_MACHINE_I386, + GetCurrentProcess (), + GetCurrentThread (), + &frame, + &context, + NULL, + SymFunctionTableAccess, + SymGetModuleBase, + NULL) + || frame.AddrFrame.Offset == 0) + break; + + // FIXME: Throw away everything above stacktrace? Keep looping + // below until the name includes something we understand? + + // Print stack frame too? If we know how many arguments there + // are (from demangling function name -- see below, could count + // commas), args are: *((ULONG *)frame.AddrFrame.Offset+2+ARG). + MYWRITE (fd, buf, snprintf (buf, buf_size, "(%2u) 0x%08lx 0x%08lx ", + level, frame.AddrPC.Offset, + frame.AddrFrame.Offset)); + + memset (&symbol, 0, sizeof (symbol)); + symbol.sym.SizeOfStruct = sizeof (symbol); + symbol.sym.MaxNameLength = sizeof (symbol) - sizeof (symbol.sym); + + offset = 0; + if (SymGetSymFromAddr (GetCurrentProcess (), frame.AddrPC.Offset, + &offset, &symbol.sym)) + { + // FIXME: Demangle name with: + // UnDecorateSymbolName (name, undecname, sizeof (undecname), + // UNDNAME_COMPLETE + // | UNDNAME_NO_THISTYPE + // | UNDNAME_NO_SPECIAL_SYMS + // | UNDNAME_NO_MEMBER_TYPE + // | UNDNAME_NO_MS_KEYWORDS + // | UNDNAME_NO_ACCESS_SPECIFIERS); + MYWRITE (fd, symbol.sym.Name, STDC::strlen (symbol.sym.Name)); + MYWRITE (fd, buf, snprintf (buf, buf_size, " + %lx", offset)); + + if (SymGetModuleInfo (GetCurrentProcess(), frame.AddrPC.Offset, + &module)) + { + MYWRITELIT (fd, " ["); + MYWRITE (fd, module.ImageName, + STDC::strlen (module.ImageName)); + MYWRITELIT (fd, "]"); + } + } + else + { + GetLogicalAddress ((PVOID) frame.AddrPC.Offset, + modulename, sizeof (modulename), + section, offset); + MYWRITE (fd, buf, snprintf (buf, buf_size, "%04lx:%08lx [", section, offset)); + MYWRITE (fd, modulename, STDC::strlen (modulename)); + MYWRITELIT (fd, "]"); + } + MYWRITELIT (fd, "\n"); + ++level; + } + SymCleanup (GetCurrentProcess ()); + +#elif (HAVE_U_STACK_TRACE || HAVE_XL_TRBK) // hp-ux, aix + // FIXME: deal with inability to duplicate the file handle + int stderrfd = dup (STDERR_FILENO); + if (stderrfd == -1) + return; + + int newfd = dup2 (fd, STDERR_FILENO); + if (newfd == -1) + { + close (stderrfd); + return; + } + +# if HAVE_U_STACK_TRACE // hp-ux + U_STACK_TRACE (); +# elif HAVE_XL_TRBK // aix + xl__trbk (); +# else +# error "oops, you shouldn't have gotten here!" +# endif + + fflush (stderr); + dup2 (stderrfd, STDERR_FILENO); + close (newfd); +#elif HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR // linux + // we could have used backtrace_symbols_fd, except its output + // format is pretty bad, so recode that here :-( + void *trace [MAX_BACKTRACE_DEPTH]; + int depth = backtrace (trace, MAX_BACKTRACE_DEPTH); + + for (int n = 0; n < depth; ++n/*, nbufs = 0*/) + { + unsigned long addr = (unsigned long) trace [n]; + stacktraceLine (fd, addr); + } + +#elif HAVE_EXCPT_H && HAVE_PDSC_H && HAVE_RLD_INTERFACE_H // tru64 + // Tru64 stack walk. Uses the exception handling library and the + // run-time linker's core functions (loader(5)). FIXME: Tru64 + // should have _RLD_DLADDR like IRIX below. Verify and update. + + const int buffer_size = 100 + BitTraits<unsigned long>::HexDigits * 2 + 11; + char buffer [buffer_size]; + sigcontext context; + int rc = 0; + + exc_capture_context (&context); + while (!rc && context.sc_pc) + { + // FIXME: Elf32? + pdsc_crd *func, *base, *crd + = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base); + Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func); + // const char *name = _rld_address_to_name(addr); + const char *name = "<unknown function>"; + snprintf (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n", + context.sc_pc, name, context.sc_pc - addr); + write (fd, buffer, STDC::strlen(buffer)); + rc = exc_virtual_unwind(0, &context); + } + +#elif HAVE_EXCEPTION_H && defined __sgi // irix + // IRIX stack walk -- like Tru64 but with a little different names. + // NB: The guard above is to protect against unrelated <exception.h> + // provided by some compilers (e.g. KCC 4.0f). + // NB: libexc.h has trace_back_stack and trace_back_stack_and_print + // but their output isn't pretty and nowhere as complete as ours. + char buffer [340]; + sigcontext context; + + exc_setjmp (&context); + while (context.sc_pc >= 4) + { + // Do two lookups, one using exception handling tables and + // another using _RLD_DLADDR, and use the one with a smaller + // offset. For signal handlers we seem to get things wrong: + // _sigtramp's exception range is huge while based on Dl_info + // the offset is small -- but both supposedly describe the + // same thing. Go figure. + char *name = 0; + const char *libname = 0; + const char *symname = 0; + Elf32_Addr offset = ~0L; + + // Do the exception/dwarf lookup + Elf32_Addr pc = context.sc_pc; + Dwarf_Fde fde = find_fde_name (&pc, &name); + Dwarf_Addr low_pc = context.sc_pc; + Dwarf_Unsigned udummy; + Dwarf_Signed sdummy; + Dwarf_Ptr pdummy; + Dwarf_Off odummy; + Dwarf_Error err; + + symname = name; + + // Determine offset using exception descriptor range information. + if (dwarf_get_fde_range (fde, &low_pc, &udummy, &pdummy, &udummy, + &odummy, &sdummy, &odummy, &err) == DW_DLV_OK) + offset = context.sc_pc - low_pc; + + // Now do a dladdr() lookup. If the found symbol has the same + // address, trust the more accurate offset from dladdr(); + // ignore the looked up mangled symbol name and prefer the + // demangled name produced by find_fde_name(). If we find a + // smaller offset, trust the dynamic symbol as well. Always + // trust the library name even if we can't match it with an + // exact symbol. + Elf32_Addr addr = context.sc_pc; + Dl_info info; + + if (_rld_new_interface (_RLD_DLADDR, addr, &info)) + { + if (info.dli_fname && info.dli_fname [0]) + libname = info.dli_fname; + + Elf32_Addr symaddr = (Elf32_Addr) info.dli_saddr; + if (symaddr == low_pc) + offset = addr - symaddr; + else if (info.dli_sname + && info.dli_sname [0] + && addr - symaddr < offset) + { + offset = addr - symaddr; + symname = info.dli_sname; + } + } + + // Print out the result + if (libname && symname) + write (fd, buffer, snprintf + (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx [%.200s]\n", + addr, symname, offset, libname)); + else if (symname) + write (fd, buffer, snprintf + (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n", + addr, symname, offset)); + else + write (fd, buffer, snprintf + (buffer, buffer_size, " 0x%012lx <unknown function>\n", addr)); + + // Free name from find_fde_name(). + free (name); + + // Check for termination. exc_unwind() sets context.sc_pc to + // 0 or an error (< 4). However it seems we can't unwind + // through signal stack frames though this is not mentioned in + // the docs; it seems that for those we need to check for + // changed pc after find_fde_name(). That seems to indicate + // end of the post-signal stack frame. (FIXME: Figure out how + // to unwind through signal stack frame, e.g. perhaps using + // sigcontext_t's old pc? Or perhaps we can keep on going + // down without doing the symbol lookup?) + if (pc != context.sc_pc) + break; + + exc_unwind (&context, fde); + } + +#elif defined PROG_PSTACK // solaris +# ifdef PROG_CXXFILT +# define CXXFILTER " | " PROG_CXXFILT +# else +# define CXXFILTER +# endif + // 64 should more than plenty for a space and a pid. + const int buffer_size = sizeof(PROG_PSTACK) + 1 + BitTraits<unsigned long>::Digits + + 3 + sizeof(PROG_CXXFILT) + BitTraits<int>::Digits + 1; + char buffer [buffer_size]; + snprintf (buffer, buffer_size, "%s %lu%s 1>&%d", PROG_PSTACK, (unsigned long) getpid (), + "" CXXFILTER, fd); + system (buffer); +# undef CXXFILTER + +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + // FIXME: Check for _Unwind*, compilers other than GCC support this API + _Unwind_Backtrace (unwindWalkStack, &fd); +#endif + + // FIXME: mpatrol has some generic unix unwind code. + // FIXME: from unix faq: ask debugger to dump stack trace + // with something like: + // - gdb: echo "thread apply all where\nwhere\ndetach" | gdb $prog $pid + // - dbx: echo "where\ndetach" | dbx -a $program_path $pid + // - dbx (aix): echo "where\ndetach" | dbx -p $program_path $pid +} + +/** Drop a core dump and continue. + + Creates a core file for the current program state and continues + execution. @a sig should be the number of the signal from which + the program should appear to have died; this should a fatal signal + that does cause a core file to be created (or @c SIGUSR1). + + This works by forking the process and then killing the child with + the given signal; the signal is automatically unblocked in the + child to make sure the sure the signal is delivered. Thus the + function returns only once, in the parent process. + + This function can be safely installed directly as a signal + handler. #Signal::handleFatal() will do so for @c SIGUSR1 with + suitable options. + + Note that this function does not change core dump resource limits, + not even for the forked child process. If core files are disabled + through resource limits, no core file will be created despite your + explicit request to create one. + + This concept was taken from DDD, the Data Display Debugger. */ +void +DebugAids::coredump (int sig, ...) +{ +#ifndef _WIN32 + // FIXME: Forking vs. threads -- need to sort out what is safe. + // FIXME: Provide a resource limits interface so that core + // resource limits can be raised? + + pid_t corepid; + int status; + + ::unlink ("core"); + if ((corepid = ::fork ()) == 0) + { + // In child: re-raise the signal, thus killing the process and + // producing a core dump. Make sure 1) the signal is not + // blocked so that we won't return to the caller, 2) we have a + // signal that is fatal, 3) the signal falls to its default + // handler to produce the dump. + +#ifdef SIGUSR1 + // SIGUSR1 does not cause a core dump; use abort() instead + if (sig == SIGUSR1) + sig = SIGABRT; // Could be SIGIOT if SIGABRT is not defined +#endif + Signal::handle (sig, (Signal::HandlerType) SIG_DFL); + Signal::block (sig, false); + Signal::raise (sig); + + // Yikes, this shouldn't happen. ASSERT isn't right here. If + // raise() failed to deliver the signal, abort() is unlikely + // to work any better, but try it anyway. Then make sure we + // die so that we won't return to the caller from the child. + abort (); + _exit (255); + } + else if (corepid > 0) { + pid_t wait_pid; + do { + wait_pid = ::waitpid (corepid, &status, 0); + } while (wait_pid == -1 && errno == EINTR); + } +#endif // !_WIN32 +} + + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +//} // namespace seal wlav +} // namespace Athena wlav diff --git a/EDM/athena/Control/CxxUtils/Root/SealSharedLib.cxx b/EDM/athena/Control/CxxUtils/Root/SealSharedLib.cxx new file mode 100644 index 00000000..7dbab56f --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/SealSharedLib.cxx @@ -0,0 +1,735 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/src/SealSharedLib.cxx + * @author Lassi Tuura (original author) + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS) + * @date Oct, 2008 + * + * Search for `wlav' to find changes from the SEAL version. All + * includes were modified, all ASSERT macro's were dropped in + * favor of assert. + * + * To comply with coverity rules, changed sprintf -> snprintf + * (wlav, 03/11/11) + * + */ + +//<<<<<< INCLUDES >>>>>> + +#include "CxxUtils/SealCommon.h" // wlav +#include "CxxUtils/SealSharedLib.h" // wlav +#include "CxxUtils/SealDebug.h" // wlav +// wlav copied from SealBase/sysapi/SharedLibrary.h +# ifdef _WIN32 +# include <windows.h> +# include <winnt.h> +# include <imagehlp.h> +# else +# if HAVE_DLOPEN +# include <dlfcn.h> +# elif HAVE_SHL_LOAD +# include <dl.h> +# elif HAVE_LOAD +# include "utils/dlfcn.h" +# endif +# if HAVE_LOADER_H +# include <loader.h> +# endif +# if HAVE_LINK_H +# include <link.h> +# include <limits.h> +# include <sys/stat.h> +# include <unistd.h> +# endif +# if HAVE_ELF_H +# include <elf.h> +# endif +# if HAVE_SGIDEFS_H // irix n32, 64 +# include <sgidefs.h> +# include <objlist.h> +# include <obj_list.h> +# include <obj.h> +# endif +# if HAVE_MACH_O_DYLD_H // darwin +# include <mach-o/dyld.h> +# include <mach-o/getsect.h> +# endif +# endif // _WIN32 +# include <cstring> +# include <cstdio> +# include <cstdlib> +# include <errno.h> + +#include <assert.h> // wlav + +#ifndef HAVE_R_DEBUG + extern ElfW(Dyn) _DYNAMIC []; // #pragma weak? // wlav +#endif + +//namespace seal { wlav +namespace Athena { // wlav +//<<<<<< PRIVATE DEFINES >>>>>> + +#ifndef SHLIB_UNSUPPORTED +# define SHLIB_UNSUPPORTED \ + throw SharedLibraryError ("", "unsupported operation") +#endif + +//<<<<<< PRIVATE CONSTANTS >>>>>> +//<<<<<< PRIVATE TYPES >>>>>> +//<<<<<< PRIVATE VARIABLE DEFINITIONS >>>>>> +//<<<<<< PUBLIC VARIABLE DEFINITIONS >>>>>> +//<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>> +//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>> + +// wlav modified from SealBase/src/SharedLibraryError.cpp +SharedLibraryError::SharedLibraryError (const char *context, + const std::string &cause) + : m_context (context ? context : ""), + m_cause (cause) +{} + +const char* +SharedLibraryError::what() const throw() +{ + static std::string message = "Shared library operation"; + if (! m_context.empty ()) + { + message += " "; + message += m_context; + } + + message += " failed"; + + if (! m_cause.empty ()) + { + message += " because: "; + message += m_cause; + } + + return message.c_str(); +} + + +// wlav continued from SealBase/src/SharedLibrary.cpp +#ifdef _WIN32 +static BOOL CALLBACK +enumModules (LPSTR name, ULONG base_address, PVOID context) +{ + IMAGEHLP_MODULE moduleinfo; + const SharedLibrary::InfoHandler *handler + = static_cast<SharedLibrary::InfoHandler *> (context); + + memset (&moduleinfo, 0, sizeof (moduleinfo)); + moduleinfo.SizeOfStruct = sizeof (moduleinfo); + + SharedLibrary::LibraryInfo info; + + if (SymGetModuleInfo (GetCurrentProcess (), base_address, &moduleinfo)) + { + info.m_filename = moduleinfo.LoadedImageName; + info.m_text_start = moduleinfo.BaseOfImage; + info.m_text_end = moduleinfo.BaseOfImage + moduleinfo.ImageSize; + info.m_data_start = 0; + info.m_data_end = 0; + info.m_bss_start = 0; + info.m_bss_end = 0; + } + else + { + info.m_filename = name; + info.m_text_start = base_address; + info.m_text_end = 0; + info.m_data_start = 0; + info.m_data_end = 0; + info.m_bss_start = 0; + info.m_bss_end = 0; + } + (*handler) (info); + return TRUE; +} +#endif + +//<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>> +//<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>> + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +std::string +SharedLibrary::path (void) +{ + const char *pathvar = PATH; + const char *path = pathvar ? getenv (pathvar) : 0; + return path ? path : ""; +} + +void +SharedLibrary::path (const std::string &path) +{ + /* Do not free `var'; most implementations of `putenv' use the + string without copying it. On systems where `putenv' copies, + you'll see leaks from this routine. It would be possible to + check for this, but only by killing cross-compilation. + + NB: `HAVE_COPYING_PUTENV' will never be set as we are not + checking for it :-) */ + + const char *pathvar = PATH; + if (pathvar) { + const int path_size = strlen(pathvar) + 1 + path.length () + 1; + char *var = (char *) malloc (path_size); + snprintf (var, path_size, "%s=%s", pathvar, path.c_str ()); + putenv (var); +#if HAVE_COPYING_PUTENV + free (var); +#endif + } +} + +/** Return a shared library name that follows the system conventions + for naming shared library. @a name is the basic name of the + shared library, without the name prefix ("lib" on unix) or the + extension (".so", ".sl", ".dylib" or ".dll"). @a name must not + have any directory components. */ +std::string +SharedLibrary::libname (const std::string &name) +{ +#ifdef _WIN32 + return name + ".dll"; +#elif defined __hpux + return "lib" + name + ".sl"; +#else + return "lib" + name + ".so"; +#endif +} + +/** Transform 'extern "C"' symbol @a name into a name suitable for + lookup in a shared library, e.g. with #data() or #function(). + Normally the latter two automatically perform the necessary + mangling by calling this function, but the clients can also + do the mangling themselves. The @a name should be in the + form it is spelled in C source code. */ +std::string +SharedLibrary::symname (const std::string &name) +{ return name; } + +////////////////////////////////////////////////////////////////////// +/** Return a shared library object representing the application itself. + The returned object is allocated with @c new. The caller must + release the object with either #release() or #abandon(). The + method throws a #SharedLibraryError if the operation is not + supported or some failure occurs. */ +SharedLibrary * +SharedLibrary::self (void) +{ +#if HAVE_DLOPEN || HAVE_LOAD + // NB: Linux (at least RH 7.x) dynamic loader is severely broken + // when it comes to reporting error messages. The error messages + // are frequently garbled or null. If you see a crash in a call + // to dlerror(), sorry, there's nothing we can do about that. + // Our attempts have only produced even more undesirable crashes. + // Waiting for a better version of the linux dynamic loader. + void *handle = ::dlopen (0, RTLD_LAZY); + if (! handle) + { + const char *msg = ::dlerror (); + msg = msg ? msg : "dynamic linker error message lost!"; + throw SharedLibraryError ("dlopen()", msg); + } + + return new SharedLibrary (handle); +#elif HAVE_SHL_LOAD + return new SharedLibrary (PROG_HANDLE); +#elif defined _WIN32 + return new SharedLibrary (::GetModuleHandle (0)); +#else + SHLIB_UNSUPPORTED; +#endif +} + +/** Load a shared library and return an object representing it. The + returned object is allocated with @c new. The caller must release + the object with either #release() or #abandon(). The method throws + a #SharedLibraryError if the operation is not supported or some + failure occurs. Please note that on several systems failure to + properly load a library, e.g. due to missing symbols, is effectively + fatal. */ +SharedLibrary * +SharedLibrary::load (const std::string &name) +{ + assert(! name.empty ()); + + void *handle = 0; + +#if HAVE_DLOPEN || HAVE_LOAD +# ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +# endif + // See comments in "self()" about crashes in dlerror(). + if (! (handle = ::dlopen (name.c_str (), RTLD_LAZY | RTLD_GLOBAL))) + { + const char *msg = ::dlerror (); + msg = msg ? msg : "dynamic linker error message lost!"; + throw SharedLibraryError ("dlopen()", msg); + } + +#elif HAVE_SHL_LOAD + if (! (handle = ::shl_load (name.c_str (), BIND_DEFERRED, 0L))) + throw SharedLibraryError ("shl_load()", errno); + +#elif defined _WIN32 + if (! (handle = ::LoadLibrary (name.c_str ()))) + throw SharedLibraryError ("LoadLibrary()", GetLastError ()); +#else + SHLIB_UNSUPPORTED; +#endif + + return new SharedLibrary (handle); +} + +/** Iterate and provide information about all currently loaded + shared libraries. */ +void +SharedLibrary::loaded (const InfoHandler &handler) +{ + // Dynamic linker characteristics: + // AIX, Windows, SVR4 (DG/UX, DRS/NX, DYNIX/ptx, Linux, SINIX, + // Solaris, UnixWare, {Free,Open,Net}BSD if __ELF__), BSD, + // HP-UX, IRIX, Tru64 + + // Object file formats: + // XCOFF (AIX), ELF32/64 (DG/UX, DRS/NX, DYNIX/ptx, IRIX, SINIX, + // Solaris, UnixWare, {Free,Open,Net}BSD: if __ELF__), a.out + // ({Free,Open,Net}BSD if ! __ELF__, SunOS), BFD (Cygwin, HP-UX, + // Linux, LynxOS, Tru64, Windows if GCC), PE (Windows), COFF (?) + +#if HAVE_SHL_LOAD // hp-ux + shl_descriptor desc; + + for (int index = -1; shl_get_r (index, &desc) == 0; ++index) + { + LibraryInfo info; + info.m_filename = desc.filename; + info.m_text_start = desc.tstart; + info.m_text_end = desc.tend; + info.m_data_start = desc.dstart; + info.m_data_end = desc.dend; + info.m_bss_start = 0; + info.m_bss_end = 0; + + handler (info); + } + +#elif HAVE_LINK_H // bsd/svr4/elf +# if !HAVE_LINK_MAP_L_MAP_START +# define l_map_start l_addr +# define l_map_end l_addr +# endif +# if !HAVE_PROGRAM_INVOCATION_NAME + static const char *program_invocation_name = "(unknown program name)"; +# endif +# if HAVE_R_DEBUG // linux/glibc + link_map *p = _r_debug.r_map; +# else + // Dynamic linker root: + // BSD (SunOS): + // #include <sys/types.h> + // #include <link.h> + // extern struct link_dynamic _DYNAMIC; + // link_dynamic *d = &_DYNAMIC; + // if ((d->ld_version > 1) && (d->ld_version <= 3) && (d->ld_un.ld_1 != 0)) + // --> link_map *l = d->ld_un.ld_1->ld_loaded + // l->lm_name, l->lm_addr, l->lm_next + // + // BSD ({Free,Open,Net}BSD): + // #include <sys/types.h> + // #include <link.h> + // extern struct _dynamic _DYNAMIC + // _dynamic *d = &_DYNAMIC; + // if ((d->version == LD_VERSION_BSD) && d->d_un.d_sdt != 0)) + // --> so_map *l = d->d_un.d_sdt->sdt_loaded + // l->som_path, l->som_addr, l->som_next + // + // SVR4 (DG/UX, DRS/NX, DYNIX/ptx, SINIX, UnixWare) + // ElfW(Dyn) _DYNAMIC[] // Linux + // void _DYNAMIC (void) // weak, really is data, but not + // // all compilers allow weak data + // + // Solaris: + // dlinfo (self, RTLD_DI_LINKMAP, &p); + + // extern ElfW(Dyn) _DYNAMIC []; // #pragma weak? // wlav + link_map *p = 0; + for (ElfW(Dyn) *dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn) + if (dyn->d_tag == DT_DEBUG && dyn->d_un.d_ptr) + // linux: p = ((r_debug *) dyn->d_un_d.ptr)->r_map; + p = (link_map *) *((unsigned long *) dyn->d_un.d_ptr + 1); +# endif + + if (! p) + throw SharedLibraryError ("loaded", "no shared library load map"); + + // Get executable name; linux has a symlink in /proc/self/exe. + // Linux path names are arbitrarily long, so we just have create + // some random-sized buffer. We allocate this on stack to avoid + // dynamic memory allocation. If this is a problem, report a bug. + struct stat sbuf; + char exe [4096]; + + memset (exe, 0, sizeof (exe)); + if (::stat ("/proc/self/exe", &sbuf) == 0) + ::readlink ("/proc/self/exe", exe, sizeof (exe)-1); + else + STDC::strncpy (exe, program_invocation_name, sizeof (exe)-1); + + // Get shared libraries + for ( ; p; p = p->l_next) + { + LibraryInfo info; + + /* FIXME: Does this work with prelinked shared libraries? + From a mail to GCC mailing list ("fde-glibc.c bug"): + + There is a bug in gcc/config/ia64/fde-glibc.c: + ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr, + ^^^^^^^^^^^ + segment_base, gp); + + this will work only as long as the shared library in + question has first PT_LOAD segment's p_vaddr == 0. + E.g. with ELF prelinking this is almost never true + though, so what you really want is map->l_map_start + (map->l_addr will be almost always 0) or even better + map->l_phdr/map->l_phnum pair. */ + + // FIXME: use the map address (= ElfW(Ehdr)) to scan over + // the different ElfW(Phdr)s to find the various sections. + info.m_filename = (p->l_name && p->l_name[0] ? p->l_name : exe); + info.m_text_start = p->l_addr ? p->l_addr : p->l_map_start; + info.m_text_end = p->l_addr ? p->l_addr : p->l_map_end; + info.m_data_start = 0; + info.m_data_end = 0; + info.m_bss_start = 0; + info.m_bss_end = 0; + + handler (info); + } + +#elif HAVE_SGIDEFS_H // irix + /* From rld(1) man page: + + rld keeps a doubly linked list of structures and crt1.o + contains a pointer to the head of the list of obj structures + called __rld_obj_head. In an o32 executable, this points to a + linked list of objList structures (/usr/include/obj_list.h), + each of which has a `data' element which is a pointer to a + `struct obj' (/usr/include/obj.h) (even though the field is not + declared as a pointer). In an n32 executable, __rld_obj_head + points to a linked list of Elf32_Obj_Info structures + (/usr/include/objlist.h). In a 64-bit executable, + __rld_obj_head points to a linked list of Elf64_Obj_Info + structures (/usr/include/objlist.h). The `oi_magic' element of + each Elf32_Obj_Info or Elf64_Obj_Info is all-bits-on + (0xffffffff) to make it easier to determine which list type is + in use a 32-bit executable. */ + + // To get more details by reading the ELF files: + // http://reality.sgi.com/davea/software.html + extern ElfW(Obj_Info) *__rld_obj_head; + ElfW(Obj_Info) *p = __rld_obj_head; + + for ( ; p; p = (ElfW(Obj_Info) *) p->oi_next) + { + LibraryInfo info; + +# if defined _MIPS_SIM_ABI32 && _MIPS_SIM == _MIPS_SIM_ABI32 + info.m_filename = (const char *) p->o_path; + info.m_text_start = p->o_praw; // base address: o_base_address + info.m_text_end = p->o_praw; +# elif (defined _MIPS_SIM_NABI32 && _MIPS_SIM == _MIPS_SIM_NABI32) \ + || (defined _MIPS_SIM_ABI64 && _MIPS_SIM == _MIPS_SIM_ABI64) + info.m_filename = (const char *) p->oi_pathname; + info.m_text_start = p->oi_ehdr; // base address: oi_orig_ehdr + info.m_text_end = p->oi_ehdr; +# else +# error "Unsupported ABI: not o32, n32 or 64" +# endif + info.m_data_start = 0; + info.m_data_end = 0; + info.m_bss_start = 0; + info.m_bss_end = 0; + + handler (info); + } + +#elif HAVE_LOADER_H && HAVE_LDR_NEXT_MODULE_DECL // tru64 + ldr_process_t proc = ldr_my_process (); + ldr_module_t mod = LDR_NULL_MODULE; + int ret = ldr_next_module (proc, &mod); + + for (; ret == 0 && mod != LDR_NULL_MODULE; ret = ldr_next_module (proc, &mod)) + { + ldr_module_info_t info; + size_t size = 0; + LibraryInfo libinfo; + + if (ldr_inq_module(proc, mod, &info, sizeof(info), &size) < 0) + throw SharedLibraryError ("ldr_inq_module()", errno); + + libinfo.m_filename = info.lmi_name; + libinfo.m_text_start = 0; + libinfo.m_text_end = 0; + libinfo.m_data_start = 0; + libinfo.m_data_end = 0; + libinfo.m_bss_start = 0; + libinfo.m_bss_end = 0; + + for (int i = 0; i < info.lmi_nregion; ++i) + { + ldr_region_info_t rinfo; + unsigned long low; + unsigned long high; + + if (ldr_inq_region(proc, mod, i, &rinfo, sizeof(rinfo), &size) < 0) + throw SharedLibraryError ("ldr_inq_region()", errno); + + low = (unsigned long) rinfo.lri_mapaddr; + high = ((unsigned long) rinfo.lri_mapaddr) + rinfo.lri_size; + + if (!strcmp(rinfo.lri_name, ".text")) { + libinfo.m_text_start = low; + libinfo.m_text_end = high; + } else if (!strcmp(rinfo.lri_name, ".data")) { + libinfo.m_data_start = low; + libinfo.m_data_end = high; + } else if (!strcmp(rinfo.lri_name, ".bss")) { + libinfo.m_bss_start = low; + libinfo.m_bss_end = high; + } + } + + handler (libinfo); + } + + if (ret < 0) + throw SharedLibraryError ("ldr_next_module()", errno); + +#elif HAVE_LOAD && HAVE_LOAD_DECL // aix + int size = 16; + void *buffer = new ld_info [size]; + int error = ::loadquery (L_GETINFO, buffer, size); + int offset = 0; + + while (error == -1 && errno == ENOMEM) + { + delete [] (ld_info *) buffer; + buffer = new ld_info [size *= 2]; + error = ::loadquery (L_GETINFO, buffer, size); + } + + if (error == -1) + throw SharedLibraryError ("loadquery()", errno); + + while (true) + { + LibraryInfo info; + ld_info *ld = (ld_info *) ((char *) buffer + offset); + const char *path = ld->ldinfo_filename; + const char *member = path + strlen (path) + 1; + std::string filename; // FIXME: Use alloca instead? + + filename = path; + if (*member) + { + filename += '('; + filename += member; + filename += ')'; + } + + info.m_filename = filename.c_str (); + info.m_text_start = (unsigned long) ld->ldinfo_textorg; + info.m_text_end = info.m_text_start + ld->ldinfo_textsize; + info.m_data_start = (unsigned long) ld->ldinfo_dataorg; + info.m_data_end = info.m_data_start + ld->ldinfo_datasize; + info.m_bss_start = 0; + info.m_bss_end = 0; + + handler (info); + + if (ld->ldinfo_next) + offset += ld->ldinfo_next; + else + break; + } + + delete [] (ld_info *) buffer; + +#elif HAVE_MACH_O_DYLD_H // darwin + unsigned long images = _dyld_image_count (); + for (unsigned long i = 0; i < images; ++i) + { + const mach_header *hdr = _dyld_get_image_header (i); + unsigned long slide = _dyld_get_image_vmaddr_slide (i); + unsigned int size; + char *sect; + LibraryInfo info; + + info.m_filename = _dyld_get_image_name (i); + + sect = getsectdatafromheader (hdr, SEG_TEXT, SECT_TEXT, &size); + info.m_text_start = sect ? (unsigned long) sect + slide : 0; + info.m_text_end = sect ? (unsigned long) sect + slide + size : 0; + sect = getsectdatafromheader (hdr, SEG_DATA, SECT_DATA, &size); + info.m_data_start = sect ? (unsigned long) sect + slide : 0; + info.m_data_end = sect ? (unsigned long) sect + slide + size : 0; + sect = getsectdatafromheader (hdr, SEG_DATA, SECT_BSS, &size); + info.m_bss_start = sect ? (unsigned long) sect + slide : 0; + info.m_bss_end = sect ? (unsigned long) sect + slide + size : 0; + + handler (info); + } + +#elif defined _WIN32 // windows + if (! SymInitialize (GetCurrentProcess (), NULL, TRUE) + || ! SymEnumerateModules (GetCurrentProcess (), &enumModules, (void *) &handler) + || ! SymCleanup (GetCurrentProcess ())) + throw SharedLibraryError ("SymEnumerateModules()", GetLastError()); +#else + SHLIB_UNSUPPORTED; +#endif +} + +/** Protected constructor for initialising a library object. The real + initialisation happens in #load() or #self(). */ +SharedLibrary::SharedLibrary (void *handle) + : m_handle (handle) +{ assert (m_handle); } + +/** Protected destructor for cleaning up a library object. The real + destruction happens in #release() or #abadon(). */ +SharedLibrary::~SharedLibrary (void) +{ assert (! m_handle); } + +/** Release a shared library. This unloads any library the object + currently refers to, then deletes @c this. Note that releasing + the library does not guarantee that it will actually be unloaded. + If there are outstanding references to the library, explicit or + implicit, the library will remain in memory. */ +void +SharedLibrary::release (void) +{ + assert (m_handle); + +#if HAVE_DLOPEN || HAVE_LOAD + ::dlclose (m_handle); +#elif HAVE_SHL_LOAD + ::shl_unload ((shl_t) m_handle); +#elif defined _WIN32 + ::FreeLibrary ((HINSTANCE) m_handle); +#else + // cannot get here---`load' and `self' should take care of it. + assert (false); +#endif + + m_handle = 0; + delete this; +} + +/** Abandon a library. This simply destroys the shared library + object (@c this) without releasing the underlying dynamic + object. */ +void +SharedLibrary::abandon (void) +{ + assert (m_handle); + m_handle = 0; + delete this; +} + +/** Locate and return a reference to a data symbol called @a name. + If no such symbol exists, returns a null pointer. If @a mangle + is the default @c true, the symbol is mangled to the platform + convention, typically prepending an underscore if required. The + mangling does not refer to C++ name mangling, but to the mangling + required to convert C identifiers to run-time symbol names; see + #symname() for details. */ +SharedLibrary::Data +SharedLibrary::data (const std::string &name, bool mangle /* = true */) const +{ + assert (! name.empty ()); + assert (m_handle); + std::string mangled = mangle ? symname (name) : name; + Data symbol = 0; + +#if HAVE_DLOPEN || HAVE_LOAD + // See comments in "self()" about crashes in dlerror(). + const char *error = 0; + symbol = ::dlsym (m_handle, mangled.c_str ()); + if (! symbol && (error = ::dlerror ()) != 0) + throw SharedLibraryError ("dlsym()", error); + +#elif HAVE_SHL_LOAD + shl_t handle = (shl_t) m_handle; + if (::shl_findsym (&handle, mangled.c_str (), TYPE_DATA, &symbol) != 0) + throw SharedLibraryError ("shl_findsym()", errno); + assert (handle == (shl_t) m_handle); + +#elif defined _WIN32 + if (! (symbol = (Data)::GetProcAddress((HINSTANCE)m_handle, mangled.c_str()))) + throw SharedLibraryError ("GetProcAddress()", GetLastError ()); +#else + // cannot get here---`load' and `self' should take care of it. + assert (false); +#endif + return symbol; +} + +/** Locate and return a reference to a function symbol called @a name. + If no such symbol exists, returns a null pointer. If @a mangle + is the default @c true, the symbol is mangled to the platform + convention, typically prepending an underscore if required. The + mangling does not refer to C++ name mangling, but to the mangling + required to convert C identifiers to run-time symbol names; see + #symname() for details. */ +SharedLibrary::Function +SharedLibrary::function (const std::string &name, bool mangle /* = true */) const +{ + assert (! name.empty ()); + assert (m_handle); + std::string mangled = mangle ? symname (name) : name; + Function symbol = 0; + +#if HAVE_DLOPEN || HAVE_LOAD + // See comments in "self()" about crashes in dlerror(). + const char *error = 0; + union { Function func; Data data; } sym; + sym.data = ::dlsym (m_handle, mangled.c_str ()); + if (! sym.data && (error = ::dlerror ()) != 0) + throw SharedLibraryError ("dlsym()", error); + symbol = sym.func; + +#elif HAVE_SHL_LOAD + shl_t handle = (shl_t) m_handle; + if (::shl_findsym (&handle, mangled.c_str (), TYPE_PROCEDURE, &symbol) != 0) + throw SharedLibraryError ("shl_findsym()", errno); + assert (handle == (shl_t) m_handle); + +#elif defined _WIN32 + if (! (symbol = (Function) ::GetProcAddress ((HINSTANCE) m_handle, + mangled.c_str ()))) + throw SharedLibraryError ("GetProcAddress()", GetLastError ()); +#else + // cannot get here---`load' and `self' should take care of it. + assert (false); +#endif + return symbol; +} + +//} // namespace seal wlav +} // namespace Athena wlav + diff --git a/EDM/athena/Control/CxxUtils/Root/SealSignal.cxx b/EDM/athena/Control/CxxUtils/Root/SealSignal.cxx new file mode 100644 index 00000000..c372fe52 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/SealSignal.cxx @@ -0,0 +1,1624 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/src/seal_signal.cxx + * @author Lassi Tuura (original author) + * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS) + * @date Oct, 2008 + * + * Search for `wlav' to find changes from the SEAL version. All + * includes were modified, all ASSERT macro's were dropped in + * favor of assert. + * + * To comply with coverity rules, changed sprintf -> snprintf + * (wlav, 03/11/11) + * + */ + +//<<<<<< INCLUDES >>>>>> + +#include "CxxUtils/SealCommon.h" // wlav +#include "CxxUtils/SealSignal.h" // wlav +#include "CxxUtils/SealDebug.h" // wlav +#include "CxxUtils/SealSharedLib.h" // wlav +// wlav copied from SealBase/sysapi/Signal.h +/** Maximum length of a signal message. Used for local format buffers + for the signal number and name message in #Signal::fataldump() and + the currently loaded shared library message in #SignalLibDump(). + Make this long enough to fit long shared library names. */ +static const int SIGNAL_MESSAGE_BUFSIZE = 2048; +// end copy from SealBase/sysapi/Signal.h +#include <cassert> +#include <cstring> +#include <cerrno> // wlav +#include <cstdio> // wlav +#include <cstdlib> // sss +#include <sys/stat.h> +#include <unistd.h> // krasznaa + +/* http://dmawww.epfl.ch/ebt-bin/nph-dweb/dynaweb/SGI_Developer/ + T_IRIX_Prog/@Generic__BookTextView/7525 + + POSIX SVR4 BSD 4.2 + ========================================================= + sigaction(2) sigset(2) sigvec(3) + sigsetops(3) signal(2) signal(3) + sigaltstack(2) + + sigqueue(2) sigsend(2) kill(3) + kill(2) kill(2) killpg(3) + pthread_kill(3P) + + sigprocmask(2) sighold(2) sigblock(3) + pthread_sigmask(3P) sigrelse(2) sigsetmask(3) + + sigpending(2) n.a. n.a. + + sigsuspend(2) sigpause(2) sigpause(3) + + sigwait(2) n.a. n.a. + sigwaitinfo(2) + sigtimedwait(2) +*/ + + +// wlav copied from SealBase/src/ProcessInfo.cpp +/** Get the process id. */ +static pid_t +ProcessInfo__pid (void) +{ +#ifdef _WIN32 + return GetCurrentProcessId (); +#else + return ::getpid (); +#endif +} + +/** Get the parent process id. */ +static pid_t +ProcessInfo__ppid (void) +{ +#ifdef _WIN32 + PROCESS_BASIC_INFORMATION pbi; + if (NtQueryInformationProcess (GetCurrentProcess(),ProcessBasicInformation, + &pbi, sizeof (pbi), 0) == STATUS_SUCCESS) + return pbi.InheritedFromUniqueProcessId; + + // FIXME: throw systemerror! + assert (false); + return -1; +#else + return ::getppid (); +#endif +} + + +//namespace seal { wlav +namespace Athena { // wlav +//<<<<<< PRIVATE DEFINES >>>>>> +//<<<<<< PRIVATE CONSTANTS >>>>>> +//<<<<<< PRIVATE TYPES >>>>>> + +/** Dummy handler type for standard @c signal() function. */ +extern "C" { typedef void (*DummyHandlerType) (int); } + +//<<<<<< PRIVATE VARIABLE DEFINITIONS >>>>>> + +/** Shared library dump callback for #Signal::fataldump(). Allocated + at initialisation time in #Signal::handleFatal() so that we won't + need to allocate memory in the middle of a fatal handler. This + variable is deliberately private to this file (to keep #Signal + headers from referring to #SharedLibrary for the local class). */ +static SharedLibrary::InfoHandler *SignalDumpCallback = 0; + +//<<<<<< PUBLIC VARIABLE DEFINITIONS >>>>>> +//<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>> + +/** Indicator that the application has been crashed: that a fatal + signal has been delivered. */ +bool Signal::s_crashed = false; + +/** Indicator that we are currently executing inside #fatal(). Used + to protect against signals delivered during recovery attempts. */ +int Signal::s_inFatal = 0; + +/** Used to switch to a raw stack dump if we crash during a backtrace. */ +unsigned long Signal::s_lastSP = 0; + +/** The current application name. */ +const char *Signal::s_applicationName = 0; + +/** The output file descriptor for #fataldump(). */ +IOFD Signal::s_fatalFd = IOFD_INVALID; + +/** The application handler hook for fatal signals. */ +Signal::FatalHook Signal::s_fatalHook = 0; + +/** The application main return hook for fatal signals. */ +Signal::FatalReturn Signal::s_fatalReturn = 0; + +/** The current fatal signal handling options. */ +unsigned Signal::s_fatalOptions = 0; + +/** The application handler hook for quitting-related signals. */ +Signal::QuitHook Signal::s_quitHook = 0; + +#if !HAVE_POSIX_SIGNALS || !SA_SIGINFO +/** Actual signal handlers when POSIX signals are not available. + These are required so that we can send pass correct (= null) + arguments to the registered handler when the system is not passing + anything, or garbage. If this happens, #handle() will register + #trampoline() as the signal handler and register the signal in + this table, and #trampoline just looks the actual handler here. */ +Signal::HandlerType Signal::s_trampolines [NSIG]; +#endif + +//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>> + +/** Internal #Signal::fataldump() dumper to produce the list of + currently loaded shared libraries. Called for every library + detected by #SharedLibrary::loaded(). + + @param info Information about this particular library. + @param fd The file descriptor to output to. */ +static void +SignalDumpLibs (const SharedLibrary::LibraryInfo &info, IOFD fd) +{ + const int buf_size = BitTraits<unsigned long>::HexDigits + 5; + char buf [buf_size]; + MYWRITE (fd, buf, snprintf (buf, buf_size, " 0x%08lx ", info.m_text_start)); + MYWRITE (fd, info.m_filename, strlen (info.m_filename)); + MYWRITE (fd, "\n", 1); +} + +#ifdef _WIN32 +/** Windows hook to translate uncaught structured exception handling + (SEH) events into calls to #Signal::fatal(). */ +static LONG CALLBACK +SEHFatal (PEXCEPTION_POINTERS info) +{ + Signal::fatal (SIGABRT, info->ExceptionRecord, info->ContextRecord); + return EXCEPTION_EXECUTE_HANDLER; +} +#endif // _WIN32 + +//<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>> +//<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>> + +#if !HAVE_POSIX_SIGNALS +/** Internal signal handler trampoline to convert handler arguments + to look more like POSIX signals. The actual handler must have + been installed into #s_trampolines by #handle(). */ +void +Signal::trampoline (int sig) +{ + assert (sig > 0 && sig < NSIG); + assert (s_trampolines [sig]); + siginfo_t info; + memset (&info, 0, sizeof (info)); + s_trampolines [sig] (sig, &info, 0); +} +#endif + +/** Return the name of the signal number @a sig. The returned memory + is statically allocated and must not be freed. */ +const char * +Signal::name (int sig) +{ +#if HAVE_STRSIGNAL + return strsignal (sig); +#elif HAVE_SYS_SIGLIST + return sys_siglist [sig]; +#else + // This is not thread safe. But if you have threads, you probably + // have strsignal() as well (FIXME: check WIN32). + static const int buf_size = 8 + BitTraits<int>::Digits; + static char buf [NSIG] [buf_size]; + if (! buf [sig][0]) + snprintf (buf [sig], buf_size, "Signal %d", sig); + return buf [sig]; +#endif +} + +/** Return the current handler for signal number @a sig and its + blocked signals in @a mask (if non-null). */ +Signal::HandlerType +Signal::handler (int sig, sigset_t *mask /* = 0 */) +{ + assert (sig > 0 && sig < NSIG); + + // Get the handler +#if HAVE_POSIX_SIGNALS + struct sigaction old; + STDC::memset (&old, 0, sizeof (old)); + if (sigaction (sig, &old, 0) == 0) + { + if (mask) + *mask = old.sa_mask; + return (HandlerType) old.sa_handler; + } + else + return (HandlerType) SIG_ERR; +#else // ! HAVE_POSIX_SIGNALS + HandlerType old = (HandlerType) signal (sig, SIG_DFL); + signal (sig, (DummyHandlerType) old); + return old; +#endif // HAVE_POSIX_SIGNALS +} + +/** Install a new signal handler @a handler for signal number + @a sig and returns the old handler. + + This method uses the POSIX signal handling primitives if they are + available, failing which falling back to the C standard @c + signal() function. + + When POSIX signals are used, signals other than @a sig are blocked + according to @a blockMask (if null, no change is made) during the + execution of @a handler. Note that the signal itself is always + blocked during the handler execution and need not be mentioned in + the mask explicitly. System calls are made restartable although + this has little impact as this library always restarts interrupted + system calls automatically despite the signal handling settings. + + (FIXME: Expose option SA_NOCLDSTOP, SA_ONSTACK?) + (FIXME: Threads vs. signals) */ +Signal::HandlerType +Signal::handle (int sig, HandlerType handler, const sigset_t *blockMask /*=0*/) +{ + assert (sig > 0 && sig < NSIG); + // LOG (0, trace, LFsignal, "[" << sig << "] (" << name (sig) << ") = " + // << (void *) handler << '\n'); // wlav + + HandlerType oldhandler; +#if !HAVE_POSIX_SIGNALS || !SA_SIGINFO + // Switch to using trampoline if we don't have the necessary + // arguments. FIXME: multiple threads; WIN32? + oldhandler = s_trampolines [sig]; + if (handler == (HandlerType) SIG_IGN || handler == (HandlerType) SIG_DFL) + s_trampolines [sig] = 0; + else + { + s_trampolines [sig] = handler; + handler = (HandlerType) &trampoline; + } +#endif + + // Set the handler +#if HAVE_POSIX_SIGNALS + struct sigaction old, act; + STDC::memset (&act, 0, sizeof (act)); + STDC::memset (&old, 0, sizeof (old)); + act.sa_flags = SA_RESTART | SA_SIGINFO; + act.sa_sigaction = handler; + sigemptyset (&act.sa_mask); + if (blockMask) + act.sa_mask = *blockMask; + else if (sigaction (sig, &old, 0) == 0) + act.sa_mask = old.sa_mask; + else + sigemptyset (&act.sa_mask); + + // There isn't much we can do to check the return status. We get + // called in all sorts fragile places like signal handlers, and + // those are not the place for throwing exceptions or asserting. + if (sigaction (sig, &act, &old) == -1) + return (HandlerType) SIG_ERR; + oldhandler = (HandlerType) old.sa_sigaction; +#else // ! HAVE_POSIX_SIGNALS + (HandlerType) ::signal (sig, (DummyHandlerType) handler); +#endif // HAVE_POSIX_SIGNALS + return oldhandler; +} + +/** Revert the signal number @a sig back to its default behaviour. */ +void +Signal::revert (int sig) +{ handle (sig, (HandlerType) SIG_DFL); } + +/** Ignore the signal number @a sig. */ +void +Signal::ignore (int sig) +{ handle (sig, (HandlerType) SIG_IGN); } + +/** Block or unblock the signal number @a sig. The signal is blocked + if @a sense is @c true, unblocked otherwise. This function is + implemented only on systems with POSIX signals. */ +void +Signal::block (int sig, bool sense) +{ +#if HAVE_POSIX_SIGNALS + // FIXME: threads -- need to use pthread_sigmask + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, sig); + block (&mask, sense); +#endif +} + +/** Block or unblock the signals specified by @a mask. The signals + are blocked if @a sense is @c true, unblocked otherwise. This + function is implemented only on systems with POSIX signals. */ +void +Signal::block (const sigset_t *mask, bool sense) +{ +#if HAVE_POSIX_SIGNALS + // FIXME: threads -- need to use pthread_sigmask + sigprocmask (sense ? SIG_BLOCK : SIG_UNBLOCK, mask, 0); +#endif +} + +/** Set the list of currently blocked signals to @a mask and return + the old setting in @a old (if non-null). This function is + implemented only on systems with POSIX signals. */ +void +Signal::mask (const sigset_t *mask, sigset_t *old /* = 0 */) +{ +#if HAVE_POSIX_SIGNALS + // FIXME: threads -- need to use pthread_sigmask + sigprocmask (SIG_SETMASK, mask, old); +#endif +} + +////////////////////////////////////////////////////////////////////// +/** Raise the signal number @a sig. Returns the exit code from the @c + raise() system call (or @c kill() if @c raise() does not exist). */ +int +Signal::raise (int sig) +{ +#if HAVE_RAISE + return ::raise (sig); +#else + return ::kill (getpid (), sig); +#endif +} + +/** Send the signal @a sig to process identified by @a process. + Implemented only on unixen. */ +int +Signal::kill (pid_t process, int sig) +{ + // FIXME: sending signals to threads? +#ifndef _WIN32 + return ::kill (process, sig); +#else + return 0; +#endif +} + +/** Queue signal @a sig with additional data @a value for @a process. + Implemented only on systems with POSIX real-time signals. */ +#if HAVE_POSIX_RT_SIGNALS +int +Signal::queue (pid_t process, int sig, int value /* = 0 */) +{ + union sigval v; + v.sival_int = value; + return sigqueue (process, sig, v); +} +#else +int +Signal::queue (pid_t /*process*/, int /*sig*/, int /*value = 0 */) +{ + return 0; +} +#endif + +/** Queue signal @a sig with additional data @a value for @a process. + Implemented only on systems with POSIX real-time signals. */ +#if HAVE_POSIX_RT_SIGNALS +int +Signal::queue (pid_t process, int sig, void *value) +{ + union sigval v; + v.sival_ptr = value; + return sigqueue (process, sig, v); +} +#else +int +Signal::queue (pid_t /*process*/, int /*sig*/, void */*value*/) +{ + return 0; +} +#endif + +/** Queue signal @a sig for this process with additional data @a + value. Implemented only on systems with POSIX real-time + signals. */ +#if HAVE_POSIX_RT_SIGNALS +int +Signal::queue (int sig, int value /* = 0 */) +{ + return queue (getpid (), sig, value); +} +#else +int +Signal::queue (int /*sig*/, int /*value = 0 */) +{ + return 0; +} +#endif + +/** Queue signal @a sig for this process with additional data @a + value. Implemented only on systems with POSIX real-time + signals. */ +#if HAVE_POSIX_RT_SIGNALS +int +Signal::queue (int sig, void *value) +{ + return queue (getpid (), sig, value); +} +#else +int +Signal::queue (int /*sig*/, void */*value*/) +{ + return 0; +} +#endif + +/** Check if @a sig is pending for this process. */ +bool +Signal::pending (int sig) +{ sigset_t s; pending (&s); return sigismember (&s, sig); } + +/** Return in @a mask the list of signals pending for this process. */ +#if HAVE_POSIX_SIGNALS +void +Signal::pending (sigset_t *mask) +{ + assert (mask); + sigpending (mask); +} +#else +void +Signal::pending (sigset_t */*mask*/) +{ +} +#endif + +/** Temporarily replace the signal mask of the process with @a mask + and then suspend until a signal is received. */ +#if HAVE_POSIX_SIGNALS +void +Signal::suspend (const sigset_t *mask) +{ + assert (mask); + sigsuspend (mask); +} +#else +void +Signal::suspend (const sigset_t */*mask*/) +{ +} +#endif + +/** Suspend the thread waiting for signal @a sig at most @a msecs + milliseconds. If @a msecs is negative (the default), waits until + a signal is delivered. Otherwise waits up to the specified time + limit. Returns @c true if the signal was received. Note that the + signal must be blocked (in a multi-threaded application in all the + threads, not just the calling one) and not be ignored before + calling this function; if a handler is registered, it won't be + called. Implemented only on systems with POSIX real-time + signals. */ +bool +Signal::wait (int sig, siginfo_t *info /* = 0 */, long msecs /* = -1 */) +{ + sigset_t s; + sigemptyset (&s); + sigaddset (&s, sig); + return wait (&s, info, msecs) == sig; +} + +/** Suspend the thread waiting for signals specified by @a mask for at + most @a msecs milliseconds. If @a msecs is negative (the + default), waits until a signal is delivered. Otherwise waits up to + the specified time limit. Returns the number of the signal that + was received, or -1 if the time limit expired. If @a info is + given, fills it with the information that the handler would have + otherwise been given. Note that the signals must be blocked (in a + multi-threaded application in all the threads, not just the + calling one) and not be ignored before calling this function; if a + handler is registered, it won't be called. Implemented only on + systems with POSIX real-time signals. */ +#if HAVE_POSIX_RT_SIGNALS +int +Signal::wait (const sigset_t *mask, + siginfo_t *info /* = 0 */, + long msecs /* = -1 */) +{ + siginfo_t myinfo; + timespec ts; + + if (msecs < 0) + sigwaitinfo (mask, &myinfo); + else + { + ts.tv_sec = msecs / 1000; + ts.tv_nsec = (msecs % 1000) * 1000000; + if (sigtimedwait (mask, &myinfo, &ts) == -1 && errno == EINTR) + // FIXME: deal with other error codes (NB: EAGAIN == timed out) + return -1; + } + + if (info) + *info = myinfo; + + return myinfo.si_signo; +} +#else +int +Signal::wait (const sigset_t */*mask*/, + siginfo_t */*info = 0 */, + long /*msecs = -1 */) +{ + return 0; +} +#endif + +////////////////////////////////////////////////////////////////////// +/* Install #quit() as the handler for quitting-related signals. + + This method installs #quit() as the handler for quitting-related + signals such as SIGHUP, SIGTERM and SIGQUIT. Upon signal delivery + @a hook will be invoked; if it returns @c true, #quit() proceeds to + exit by re-raising the signal (in order to make the program's exit + status reflect the signal exit). If the @a hook returns @c false, + the signal is effectively ignored. Note however that certain + options to #fatal() also cause the quit hook to be invoked. */ +void +Signal::handleQuit (QuitHook hook /* = 0 */) +{ + static int hups [] = { +#ifdef SIGHUP + // hang up (lost terminal or process group leader) + SIGHUP, +#endif +#ifdef SIGTERM + // terminate (e.g. system going down) + SIGTERM, +#endif +#ifdef SIGQUIT + // user request to quit and leave debuggable state (from quit + // key on controlling terminal) + SIGQUIT, +#endif + -1 + }; + + if (hook) + s_quitHook = hook; + + for (unsigned sig = 0; hups [sig] != -1; ++sig) + handle (hups [sig], quit); +} + +/** Install default handler for fatal signals. + + This method installs a handler for fatal signals such as floating + point exceptions, illegal instructions, and memory violations. + The behaviour is more precisely determined by @a options, a + bitwise or of the option constants defined in the class + declaration. + + @a applicationName sets the application name to be used to report + the signal in #fatalDump(). @a fd sets the file descriptor to + which the fatal signal message is written; by default this will be + the standard error output. @a hook sets the pre-exit application + hook to invoke, @a mainreturn sets the hook to return to back to + the application "main loop" (i.e. ignore the signal by jumping out + of the signal back to the somewhere higher up in the application). + + Options left to default values will not change the current state. + This allows one to re-install signal handlers without disturbing + already registered information. Use this to restore handlers + after some other library has meddled with the handlers. + + This installs #fatal() as the handler for fatal signals and on + Windows for otherwise unhandled fatal structured exceptions. If + #FATAL_ON_QUIT is included in @a options, quitting related signals + (see #quit()) are also considered fatal. If #FATAL_ON_INT is set, + SIGINT is considered fatal---but see also #fatal() documentation. + If #USR1_DUMP_CORE is set, #DebugAids::coredump is registered as a + handler for SIGUSR1 (please note the security risks of this option + in its documentation). + + A multi-threaded application should call this method in each + thread. (FIXME: Calling this in one thread and blocking signals + in others won't work on Linux, and in any case will probably + produce non-sense stack traces (unless stacktrace can be fixed to + dump the stacks of all the threads). Since the handler is always + the same, I am not sure it will make the slightest difference + which thread catches the signals, and on the other hand, it is + best to dump the problems in the faulting thread if possible.) */ +void +Signal::handleFatal (const char *applicationName /* = 0 */, + IOFD fd /* = IOFD_INVALID */, + FatalHook hook /* = 0 */, + FatalReturn mainreturn /* = 0 */, + unsigned options /* = FATAL_DEFAULT */) +{ + // FIXME: Provide means to install handlers for fatal signals that + // an application has requested and app was supposed to register a + // handler before making the request? (So that if the app handler + // is not installed for some reason, an internal error hook can + // run?) Such fatal signals include: + // - SIGPIPE: read or write to broken pipe; child died + // (read or write to socket with ASYNC io?) + // - SIGLOST: lost a resource (e.g., lock on nfs server reboot) + // - SIGALRM: interval timer elapsed + // - SIGUSR1, SIGUSR2 + // - SIGPOLL: pollable streams device events + // - SIGIO: i/o possible (from async i/o) + // - SIGVTALRM: virtual timer expired + // - SIGPROF: profiling timer expired + // - SIGRTMIN - SIGRTMAX: POSIX real-time signals + // + // Some of these the application should probably just #block() + // (e.g. SIGPIPE). Some of them the app should block and then + // wait or poll for events (SIGPOLL, SIGIO, possibly SIGALRM, the + // real-time signals if they are used). + + static int hups [] = { +#ifdef SIGHUP + SIGHUP, // hang up (lost terminal or process group leader) +#endif +#ifdef SIGTERM + SIGTERM, // terminate (e.g. system going down) +#endif +#ifdef SIGQUIT + SIGQUIT, /* user request to quit and leave debuggable + state (from quit key on controlling + terminal) */ + +#endif + -1 + }; + + static int fatals [] = { +#ifdef SIGFPE + SIGFPE, // arithmetic exception +#endif +#ifdef SIGILL + SIGILL, // illegal instruction +#endif +#ifdef SIGSEGV + SIGSEGV, // illegal address +#endif +#ifdef SIGBUS + SIGBUS, // hardware exception +#endif +#ifdef SIGIOT + SIGIOT, /* IOT trap. Before SIGABRT so that if SIGIOT + == SIGABRT then SIGABRT overrides SIGIOT; + SIGABRT is in ISO C and POSIX.1, SIGIOT is + not. */ +#endif +#ifdef SIGABRT + SIGABRT, // abort + +#endif +#ifdef SIGTRAP + SIGTRAP, // trace/breakpoint reached +#endif +#ifdef SIGEMT + SIGEMT, // emulation trap (may be used by profiler?) +#endif +#ifdef SIGSYS + SIGSYS, // invalid system call +#endif +#ifdef SIGXCPU + SIGXCPU, // cpu time limit exceeded +#endif +#ifdef SIGXFSZ + SIGXFSZ, // file size limit exceeded +#endif + -1 + }; + + // Make sure `strsignal' is properly initialised. + name (1); + + // Remember app name if specified + if (applicationName && *applicationName) + s_applicationName = applicationName; + + // Automatically initialise s_fatalFd on first access + if (s_fatalFd == IOFD_INVALID) + s_fatalFd = STDERR_HANDLE; + + // Remember the fatal output fd if defined + if (fd != IOFD_INVALID) + s_fatalFd = fd; + + // Now that we know the fd, setup a callback for dumping shared + // libraries via #SignalDumpLibs. This avoids having to allocate + // memory for the callback implementation in the middle of a fatal + // signal, and on the other hand avoids a global object which + // might not be initialised yet. + delete SignalDumpCallback; + SignalDumpCallback = new SharedLibrary::InfoHandler + (CreateCallback (&SignalDumpLibs, s_fatalFd)); + + // Remember the hooks if specified + if (hook) + s_fatalHook = hook; + + if (mainreturn) + s_fatalReturn = mainreturn; + + // Remember the new options + s_fatalOptions = options; + + // Signal::fatal() requires this, otherwise weird things can happen. + // Programs not wanting to return to main should set FATAL_AUTO_EXIT. + assert (s_fatalReturn || (s_fatalOptions & FATAL_AUTO_EXIT)); + + // Install signal handlers. + if (options & FATAL_ON_QUIT) + for (unsigned sig = 0; hups [sig] != -1; ++sig) + handle (hups [sig], fatal); + + for (unsigned sig = 0; fatals [sig] != -1; ++sig) + handle (fatals [sig], fatal); + +#ifdef SIGINT + // interrupt key from controlling terminal + if (options & FATAL_ON_INT) + handle (SIGINT, fatal); +#endif + +#ifdef SIGUSR1 + // program-defined signals SIGUSR1 and SIGUSR2 + if (options & USR1_DUMP_CORE) + handle (SIGUSR1, (HandlerType) DebugAids::coredump); +#endif + +#ifdef _WIN32 + SetUnhandledExceptionFilter (&SEHFatal); +#endif +} + +/** The quit signal handler. + + This is the handler installed by #handleQuit(). Please use + #handleQuit() and this method instead of installing your own + handlers with #handle(). + + This handler first invokes the application hook if one was given + to #handleQuit(). If the hook returns @c true, the signal handler + for this signal (number @a sig) is reset to its default handler, + and the signal is re-raised. This causes the program to exit via + the signal and have a the correct exit status. + + The application should do whatever is necessary for a graceful + shutdown. Note however that this signal may arrive asynchronously + at any time, hence it probably isn't safe to allocate memory, use + the standard output streams, and so forth. What you can do is to + set a flag, return @c false to return back to your application, + detect the flag setting and drain your current event loop, and + then quit. But do note that if #FATAL_AUTO_EXIT was set in call + to #handleFatal(), #fatal() will call #quit() which in turn calls + the application hook. Thus the hook should make sure it returns + @c true if the application has crashed as noted in the + documentation for <<QuitHook>>. */ +void +Signal::quit (int sig, siginfo_t *info, void *x) +{ + // Quit if no hook has been registered: we are coming in via + // FATAL_AUTO_EXIT in fatal and the application did not call + // handleQuit. + if (! s_quitHook || (*s_quitHook) (sig, info, x)) + { + // Reactivate the default signal handling behaviour for this + // signal, which is to terminate the application one way or + // the other. Then exit through the signal. This makes the + // process exit status correct. + revert (sig); + raise (sig); + } +} + +/** The fatal signal handler. + + This is the handler installed by #handleFatal(). Please use + #handleFatal() and this method instead of installing your handlers + with #handle(). You should be able use the handler options to + specify all the control you need. + + The first thing this handler does is to reinstall itself for the + benefit of platforms with single-delivery signals. Immediately + after that it unblocks the delivery of that signal again, in case + the signal handler itself gets in trouble. The next step is to + check if the current crash level (the recursion of calls to + #fatal(), see #fatalLevel()) exceeds the predefined limit of 4; if + so, we give up and let the application die with this this signal. + The handler then determines whether the signal is fatal: + everything except SIGINT is, and SIGINT is fatal if #FATAL_ON_INT + was set. If the signal is fatal, crash indicator is set (see + #crashed()). + + If this is not a nested fatal signal, the signal is fatal, and + #FATAL_DUMP_CORE is set, the handler tries dump a core file. Then + the handler will either attempt to quit or to return to the main + program depending on #FATAL_AUTO_EXIT option setting. If it is + set or this is a nested fatal signal, the handler will attempt to + exit as follows: the application hook (or #fatalDump() in its + absence) is invoked. If the hook returns @c true, #quit() is + called; otherwise the signal handler will return (and crash or get + an infinite sequence of fatal signals). Note that if an + application hook is registered, #fataldump() is not called by + default; the application hook must invoke it itself to get the + dump. + + If #FATAL_AUTO_EXIT is not set, the application must have + registered a main return hook, which will be invoked. The hook + must not return, but do a @c siglongjmp back to the main program + (it should not throw unless all code is built with options that + allow exceptions to be thrown from signal handlers). Note that + the fatal signal may be asynchronous and may have arisen in code + left in unsafe state, so returning back to the main program may + not buy you much. It may make sense for a few things like rogue + null pointer dereferences or floating point exceptions. + + An interactive application using a main return hook should do + something like this when the @c sigsetjmp in the main loop + returns: + - disable "main loop entered" status + - inform the user about the fatal error (e.g. with a popup); + the popup window should be precreated for best stability + - reset any locks the application holds, especially for user + interface, including status bars, wait icons etc. + - suggest to run a debugger against the program right there + - in a windowing system ungrab pointer, keyboard and the server + - unblock the signal via #block(sig, false) as the operating + system may think the signal is still being processed + - add an idle processor to re-return the "main loop entered" + once all pending event queue events have been drained + - go onto processing gui events + + Using a main return will most likely leak memory like a sieve, but + in balance, the application just got a fatal signal and the leak + is unlikely to be the greatest concern. */ +void +Signal::fatal (int sig, siginfo_t *info, void *x) +{ + assert (s_fatalReturn || (s_fatalOptions & FATAL_AUTO_EXIT)); + +#if !HAVE_POSIX_SIGNALS + // Reinstall the handler for poor SVR4 systems that reset signal + // handlers upon delivery. I doubt this code ever gets run on a + // system without sigaction, but let's be ultracorrect. + handle (sig, &fatal); +#endif + + // Unblock the signal itself so that if we get this again, we'll + // enter the handler again. Otherwise if the user's hook or + // fatalDump has trouble, we'll hang until someone sends us a + // different signal. + block (sig, false); + + // Check that we aren't going too deep in fatal handlers. We + // allow a little nesting as sometimes the handlers gets tangled + // up producing a dump, but after an extra signal can finish. If + // the nesting exceeds our limit, we give up and exit with default + // signal behaviour: no hooks any more, they've had their chance. + if (++s_inFatal > 4) + { + revert (sig); + raise (sig); + } + + // Check if this signal is fatal. If so, indicate we've crashed. + bool fatal = (sig != SIGINT) || (s_fatalOptions & FATAL_ON_INT); + if (fatal) + s_crashed = true; + + // Create core file if requested (without interrupting the program) + bool haveCore = false; + if (s_inFatal == 1 && fatal && (s_fatalOptions & FATAL_DUMP_CORE)) + { + DebugAids::coredump (sig); +#ifndef _WIN32 + struct stat st; + haveCore = (::stat ("core", &st) == 0 + && S_ISREG (st.st_mode) + && st.st_size > 0); +#endif + } + + // Check if we are done -- if so, commit a suicide, it should be + // painless. s_fatalHook and s_quitHook ought to be protected + // from infinitely looping signals, either using #fatalLevel() or + // deregistering themselves on the first call. + if (s_inFatal > 1 || (s_fatalOptions & FATAL_AUTO_EXIT)) + { + if (s_fatalHook + ? (*s_fatalHook) (haveCore ? -sig : sig, info, x) + : fatalDump (haveCore ? -sig : sig, info, x)) + // Suicide: re-raise the signal; we'll die as we return. + quit (sig, info, x); + return; + } + + // Prevent possible infinite recursion... + if (!s_fatalReturn) // sss + std::abort(); // sss + + // Return to main program. + --s_inFatal; + + (*s_fatalReturn) (haveCore ? -sig : sig, info, x); +} + +/** Return the description for signal info code @a code for signal + number @a sig. The code should come from @c siginfo_t::si_code. */ +const char * +Signal::describe (int sig, int code) +{ + static struct { int sig; int code; const char *desc; } infos [] = { +#if HAVE_POSIX_SIGNALS + { -1, SI_USER, "user sent: kill, sigsend or raise" }, +# ifdef SI_KERNEL + { -1, SI_KERNEL, "kernel" }, +# endif + { -1, SI_QUEUE, "sigqueue" }, + { -1, SI_TIMER, "timer expired" }, + { -1, SI_MESGQ, "mesq state changed" }, + { -1, SI_ASYNCIO, "AIO completed" }, +# ifdef SI_SIGIO // not solaris + { -1, SI_SIGIO, "queued SIGIO" }, +# endif + +# ifdef ILL_NOOP // darwin + { SIGILL, ILL_NOOP, "noop" }, +# endif + { SIGILL, ILL_ILLOPC, "illegal opcode" }, +# ifdef ILL_ILLOPN // not darwin + { SIGILL, ILL_ILLOPN, "illegal operand" }, +# endif +# ifdef ILL_ILLADR // not darwin + { SIGILL, ILL_ILLADR, "illegal addressing mode" }, +# endif + { SIGILL, ILL_ILLTRP, "illegal trap" }, + { SIGILL, ILL_PRVOPC, "privileged opcode" }, +# ifdef ILL_PRVREG // not darwin + { SIGILL, ILL_PRVREG, "privileged register" }, +# endif +# ifdef ILL_COPROC // not darwin + { SIGILL, ILL_COPROC, "coprocessor error" }, +# endif +# ifdef ILL_BADSTK // not darwin + { SIGILL, ILL_BADSTK, "internal stack error" }, +# endif + +# ifdef FPE_NOOP // darwin + { SIGFPE, FPE_NOOP, "noop" }, +# endif +# ifdef FPE_INTDIV // not darwin + { SIGFPE, FPE_INTDIV, "integer divide by zero" }, +# endif +# ifdef FPE_INTOVF // not darwin + { SIGFPE, FPE_INTOVF, "integer overflow" }, +# endif + { SIGFPE, FPE_FLTDIV, "floating point divide by zero" }, + { SIGFPE, FPE_FLTOVF, "floating point overflow" }, + { SIGFPE, FPE_FLTUND, "floating point underflow" }, + { SIGFPE, FPE_FLTRES, "floating point inexact result" }, + { SIGFPE, FPE_FLTINV, "floating point invalid operation" }, +# ifdef FPE_FLTSUB // not darwin + { SIGFPE, FPE_FLTSUB, "subscript out of range" }, +# endif + +# ifdef SEGV_NOOP // darwin + { SIGSEGV, SEGV_NOOP, "noop" }, +# endif + { SIGSEGV, SEGV_MAPERR, "address not mapped to object" }, + { SIGSEGV, SEGV_ACCERR, "invalid permissions for mapped object" }, + +# ifdef BUS_NOOP // darwin + { SIGBUS, BUS_NOOP, "noop" }, +# endif + { SIGBUS, BUS_ADRALN, "invalid address alignment" }, +# ifdef BUS_ADRERR // not darwin + { SIGBUS, BUS_ADRERR, "non-existent physical address" }, +# endif +# ifdef BUS_OBJERR // not darwin + { SIGBUS, BUS_OBJERR, "object specific hardware error" }, +# endif + +# ifdef TRAP_BRKPT // not darwin + { SIGTRAP, TRAP_BRKPT, "process break point" }, +# endif +# ifdef TRAP_TRACE // not darwin + { SIGTRAP, TRAP_TRACE, "process trace trap" }, +# endif + +# ifdef CLD_NOOP // darwin + { SIGCHLD, CLD_NOOP, "noop" }, +# endif + { SIGCHLD, CLD_EXITED, "child has exited" }, + { SIGCHLD, CLD_KILLED, "child was killed" }, + { SIGCHLD, CLD_DUMPED, "child terminated abnormally" }, + { SIGCHLD, CLD_TRAPPED, "traced child has trapped" }, + { SIGCHLD, CLD_STOPPED, "child has stopped" }, + { SIGCHLD, CLD_CONTINUED,"stopped child has continued" }, + +# ifdef SIGPOLL // not darwin + { SIGPOLL, POLL_IN, "data input available" }, + { SIGPOLL, POLL_OUT, "output buffers available" }, + { SIGPOLL, POLL_MSG, "input message available" }, + { SIGPOLL, POLL_ERR, "i/o error" }, + { SIGPOLL, POLL_PRI, "high priority input available" }, + { SIGPOLL, POLL_HUP, "device disconnected" }, +# endif +#endif // HAVE_POSIX_SIGNALS + + { -1, -1, 0 } + }; + + for (unsigned i = 0; infos [i].desc; ++i) + if ((infos [i].sig == -1 || infos [i].sig == sig) + && infos [i].code == code) + return infos [i].desc; + + return "*unknown reason*"; +} + +/** Utility function to dump the signal info descriptor for signal @a + sig, as obtained for instance through signal handler parameters or + #wait(). The output is written directly to the file descriptor @a + fd, using @a buf as the formatting buffer. */ +void +Signal::dumpInfo (IOFD fd, char *buf, int sig, const siginfo_t *info) +{ + if (! info) + return; + +#ifdef _WIN32 +# define DOCODE(x) case x: name = #x + // NB: siginfo_t == EXCEPTION_RECORD. + const char *name = 0; + + switch (info->ExceptionCode) + { + DOCODE(STATUS_ABANDONED_WAIT_0); + DOCODE(STATUS_ACCESS_VIOLATION); + DOCODE(STATUS_ARRAY_BOUNDS_EXCEEDED); + DOCODE(STATUS_BREAKPOINT); + DOCODE(STATUS_CONTROL_C_EXIT); + DOCODE(STATUS_DATATYPE_MISALIGNMENT); + DOCODE(STATUS_FLOAT_DENORMAL_OPERAND); + DOCODE(STATUS_FLOAT_DIVIDE_BY_ZERO); + DOCODE(STATUS_FLOAT_INEXACT_RESULT); + DOCODE(STATUS_FLOAT_INVALID_OPERATION); + DOCODE(STATUS_FLOAT_OVERFLOW); + DOCODE(STATUS_FLOAT_STACK_CHECK); + DOCODE(STATUS_FLOAT_UNDERFLOW); + DOCODE(STATUS_GUARD_PAGE_VIOLATION); + DOCODE(STATUS_ILLEGAL_INSTRUCTION); + DOCODE(STATUS_INTEGER_DIVIDE_BY_ZERO); + DOCODE(STATUS_INTEGER_OVERFLOW); + DOCODE(STATUS_INVALID_DISPOSITION); + DOCODE(STATUS_IN_PAGE_ERROR); + DOCODE(STATUS_NONCONTINUABLE_EXCEPTION); + DOCODE(STATUS_NO_MEMORY); + DOCODE(STATUS_PENDING); + DOCODE(STATUS_PRIVILEGED_INSTRUCTION); + DOCODE(STATUS_SINGLE_STEP); + DOCODE(STATUS_STACK_OVERFLOW); + DOCODE(STATUS_TIMEOUT); + DOCODE(STATUS_USER_APC); + DOCODE(STATUS_WAIT_0); + } + // -> DWORD ExceptionCode + // -> DWORD ExceptionFlags + // -> EXCEPTION_RECORD *ExceptionRecord + // -> PVOID ExceptionAddress + // -> DWORD NumberParameters + // -> DWORD ExceptionInfo [MAX_PARAMETERS (15)] + if (name) + MYWRITE (fd, buf, sprintf (buf, "Exception: %s\n", name)); + else + MYWRITE (fd, buf, sprintf (buf, "Exception %lu\n", + info->ExceptionCode)); + MYWRITE (fd, buf, sprintf (buf, " addr = %08lx", info->ExceptionAddress)); + +#elif HAVE_POSIX_SIGNALS + // These should always be set. + write (fd, buf, sprintf (buf, + " signo = %d, errno = %d, code = %d (%s)\n", + info->si_signo, info->si_errno, info->si_code, + describe (sig, info->si_code))); + + // These are set if the signal was sent by kill, POSIX signal + // send or SIGCHLD. + write (fd, buf, sprintf (buf, " pid = %ld, uid = %ld\n", + (long) info->si_pid, (long) info->si_uid)); + + // Child status for SIGCHLD. + if (sig == SIGCHLD) { + // Create temporary variables, as MacOS/clang doesn't want to + // accept the on-the-fly conversion of the following variables + // without printing some warnings. + const long status = info->si_status; + const long utime = info->si_utime; + const long stime = info->si_stime; + write (fd, buf, sprintf (buf, + " status = %ld, utime = %ld, stime = %ld\n", + status, utime, stime)); + } + + // These are set if the POSIX signal sender passed them. + write (fd, buf, sprintf (buf, " value = (%d, %p)\n", + info->si_int, info->si_ptr)); + + // This is the interesting address for memory faults. + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) + write (fd, buf, sprintf (buf, " addr = %p\n", info->si_addr)); + +# ifdef SIGPOLL // not darwin + // SIGPOLL status data. + if (sig == SIGPOLL) + write (fd, buf, sprintf (buf, " band = %ld, fd = %d\n", + (long) info->si_band, info->si_fd)); +# endif +#endif // HAVE_POSIX_SIGNALS +} + +/** Utility function to dump memory section from @a data for @a n + bytes. Used to dump machine context on platforms where we don't + know any better. The output is written directly to the file + descriptor @a fd, using @a buf as the formatting buffer. */ +void +Signal::dumpMemory (IOFD fd, char *buf, const void *data, size_t n) +{ + for (size_t i = 0; i < n; ) + { + size_t m = sprintf (buf, "\n "); + for (size_t j = 0; i < n && j < 32; ++j, ++i) + m += sprintf (buf + m, "%s%02x", + j % 4 == 0 ? " " : "", + (unsigned int) (((const unsigned char *) data) [i])); + + MYWRITE (fd, buf, m); + } +} + +/** Utility function to dump the process context, as obtained for + instance through signal handler parameters, unix @c getcontext() or + Windows @c GetThreadContext(). The output is written directly to + the file descriptor @a fd, using @a buf as the formatting buffer. + + Returns SP if we can find it, else null. */ +unsigned long +Signal::dumpContext (IOFD fd, char *buf, const void *context) +{ + unsigned long sp = 0; +#if defined _WIN32 && defined _M_IX86 + const CONTEXT *uc = static_cast<const CONTEXT *> (context); + sp = uc->Esp; + MYWRITE (fd, buf, sprintf (buf, "\n" + "\n eip: %04lx:%08lx eflags: %08lx" + "\n eax: %08lx ebx: %08lx" + " ecx: %08lx edx: %08lx" + "\n esi: %08lx edi: %08lx" + " ebp: %08lx esp: %08lx" + "\n ds: %04lx es: %04lx" + " fs: %04lx ss: %04lx", + uc->SegCs, uc->Eip, uc->EFlags, + uc->Eax, uc->Ebx, uc->Ecx, uc->Edx, + uc->Esi, uc->Edi, uc->Ebp, uc->Esp, + uc->SegDs, uc->SegEs, uc->SegFs, uc->SegSs)); + + MYWRITE (fd, buf, sprintf (buf, + "\n FPU: control = %08lx" + "\n status = %08lx" + "\n tag = %08lx" + "\n ip = %04lx:%08lx" + "\n data = %04lx:%08lx" + "\n state = %08lx", + uc->FloatSave.ControlWord, + uc->FloatSave.StatusWord, + uc->FloatSave.TagWord, + uc->FloatSave.ErrorSelector, + uc->FloatSave.ErrorOffset, + uc->FloatSave.DataSelector, + uc->FloatSave.DataOffset, + uc->FloatSave.Cr0NpxState)); + + for (int i = 0; i < 8; ++i) + MYWRITE (fd, buf, sprintf (buf, + "\n %%fp%d = [%02x%02x:%02x%02x%02x%02x" + "%02x%02x%02x%02x]", + i, + uc->FloatSave.RegisterArea [i * 10 + 0], + uc->FloatSave.RegisterArea [i * 10 + 1], + uc->FloatSave.RegisterArea [i * 10 + 2], + uc->FloatSave.RegisterArea [i * 10 + 3], + uc->FloatSave.RegisterArea [i * 10 + 4], + uc->FloatSave.RegisterArea [i * 10 + 5], + uc->FloatSave.RegisterArea [i * 10 + 6], + uc->FloatSave.RegisterArea [i * 10 + 7], + uc->FloatSave.RegisterArea [i * 10 + 8], + uc->FloatSave.RegisterArea [i * 10 + 9])); + MYWRITE (fd, "\n", 1); + +#elif HAVE_POSIX_SIGNALS + // FIXME: how much of this is defined in POSIX or ABIs? + const ucontext_t *uc = static_cast<const ucontext_t *> (context); + const mcontext_t *mc = &uc->uc_mcontext; + write (fd, buf, sprintf (buf, " stack = (%x, %x, %p)", + uc->uc_stack.ss_flags, + unsigned(uc->uc_stack.ss_size), + uc->uc_stack.ss_sp)); + + write (fd, buf, sprintf (buf, "\n")); +#if defined __i386 && defined __linux +# if !defined REG_CS && defined CS +# define REG_CS CS +# define REG_DS DS +# define REG_ES ES +# define REG_FS FS +# define REG_SS SS +# define REG_EIP EIP +# define REG_EFL EFL +# define REG_EAX EAX +# define REG_EBX EBX +# define REG_ECX ECX +# define REG_EDX EDX +# define REG_ESI ESI +# define REG_EDI EDI +# define REG_EBP EBP +# define REG_ESP ESP +# define REG_UESP UESP +# define REG_TRAPNO TRAPNO +# define REG_ERR ERR +# endif + sp = mc->gregs[REG_ESP]; + write (fd, buf, sprintf (buf, + "\n eip: %04x:%08x eflags: %08x" + "\n eax: %08x ebx: %08x" + " ecx: %08x edx: %08x" + "\n esi: %08x edi: %08x" + " ebp: %08x esp: %08x" + "\n ds: %04x es: %04x" + " fs: %04x ss: %04x", + mc->gregs [REG_CS] & 0xffff, mc->gregs [REG_EIP], + mc->gregs [REG_EFL], + mc->gregs [REG_EAX], mc->gregs [REG_EBX], + mc->gregs [REG_ECX], mc->gregs [REG_EDX], + mc->gregs [REG_ESI], mc->gregs [REG_EDI], + mc->gregs [REG_EBP], mc->gregs [REG_ESP], + mc->gregs [REG_DS] & 0xffff, + mc->gregs [REG_ES] & 0xffff, + mc->gregs [REG_FS] & 0xffff, + mc->gregs [REG_SS] & 0xffff)); + + write (fd, buf, sprintf (buf, + "\n\n signal esp: %08x" + " trap: %d/%d" + " oldmask: %08lx cr2: %08lx", + mc->gregs [REG_UESP], + mc->gregs [REG_TRAPNO], mc->gregs [REG_ERR], + mc->oldmask, mc->cr2)); + + if (mc->fpregs) + { + write (fd, buf, sprintf (buf, + "\n" + "\n FPU: control = %08lx" + "\n status = %08lx" + "\n tag = %08lx" + "\n ip = %04lx:%08lx" + "\n data = %04lx:%08lx" + "\n state = %08lx", + mc->fpregs->cw, mc->fpregs->sw, mc->fpregs->tag, + mc->fpregs->cssel & 0xffff, mc->fpregs->ipoff, + mc->fpregs->datasel & 0xffff, mc->fpregs->dataoff, + mc->fpregs->status)); + + for (int i = 0; i < 8; ++i) + write (fd, buf, sprintf (buf, + "\n %%fp%d = [%04hx:%04hx%04hx%04hx%04hx]", + i, + mc->fpregs->_st [i].exponent, + mc->fpregs->_st [i].significand [0], + mc->fpregs->_st [i].significand [1], + mc->fpregs->_st [i].significand [2], + mc->fpregs->_st [i].significand [3])); + } + +#elif defined __x86_64__ && defined __linux + sp = mc->gregs[REG_RSP]; + write (fd, buf, sprintf (buf, + "\n rip: %04x:%016llx eflags: %016llx" + "\n rax: %016llx rbx: %016llx" + "\n rcx: %016llx rdx: %016llx" + "\n r08: %016llx r09: %016llx" + "\n r10: %016llx r11: %016llx" + "\n r12: %016llx r13: %016llx" + "\n r14: %016llx r15: %016llx" + "\n rsi: %016llx rdi: %016llx" + "\n rbp: %016llx rsp: %016llx" + "\n gs: %04x fs: %04x", + (unsigned)mc->gregs [REG_CSGSFS] & 0xffff, + (unsigned long long)mc->gregs [REG_RIP], + (unsigned long long)mc->gregs [REG_EFL], + (unsigned long long)mc->gregs [REG_RAX], + (unsigned long long)mc->gregs [REG_RBX], + (unsigned long long)mc->gregs [REG_RCX], + (unsigned long long)mc->gregs [REG_RDX], + (unsigned long long)mc->gregs [REG_R8], + (unsigned long long)mc->gregs [REG_R9], + (unsigned long long)mc->gregs [REG_R10], + (unsigned long long)mc->gregs [REG_R11], + (unsigned long long)mc->gregs [REG_R12], + (unsigned long long)mc->gregs [REG_R13], + (unsigned long long)mc->gregs [REG_R14], + (unsigned long long)mc->gregs [REG_R15], + (unsigned long long)mc->gregs [REG_RSI], + (unsigned long long)mc->gregs [REG_RDI], + (unsigned long long)mc->gregs [REG_RBP], + (unsigned long long)mc->gregs [REG_RSP], + (unsigned)(mc->gregs [REG_CSGSFS]>>16) & 0xffff, + (unsigned)(mc->gregs [REG_CSGSFS]>>32) & 0xffff)); + + write (fd, buf, sprintf (buf, + "\n\n" + " trap: %lld/%lld" + " oldmask: %16llx cr2: %016llx", + (unsigned long long)mc->gregs [REG_TRAPNO], + (unsigned long long)mc->gregs [REG_ERR], + (unsigned long long)mc->gregs [REG_OLDMASK], + (unsigned long long)mc->gregs [REG_CR2])); + + if (mc->fpregs) + { + write (fd, buf, sprintf (buf, + "\n" + "\n FPU: control = %04x" + "\n status = %04x" + "\n tag = %02x" + "\n op = %04x" + "\n ip = %016lx" + "\n data = %016lx" + "\n mxcsr = %08x" + "\n mxcr_mask= %08x", + mc->fpregs->cwd, + mc->fpregs->swd, + mc->fpregs->ftw, + mc->fpregs->fop, + mc->fpregs->rip, + mc->fpregs->rdp, + mc->fpregs->mxcsr, + mc->fpregs->mxcr_mask)); + + for (int i = 0; i < 8; ++i) + write (fd, buf, sprintf (buf, + "\n %%fp%d = [%04hx:%04hx%04hx%04hx%04hx]", + i, + mc->fpregs->_st [i].exponent, + mc->fpregs->_st [i].significand [0], + mc->fpregs->_st [i].significand [1], + mc->fpregs->_st [i].significand [2], + mc->fpregs->_st [i].significand [3])); + + for (int i = 0; i < 16; ++i) + write (fd, buf, sprintf (buf, + "\n %%xmm%02d = [%08x %08x %08x %08x]", + i, + mc->fpregs->_xmm[i].element[0], + mc->fpregs->_xmm[i].element[1], + mc->fpregs->_xmm[i].element[2], + mc->fpregs->_xmm[i].element[3])); + } + +#elif __APPLE__ && defined __ppc__ + write (fd, buf, sprintf (buf, "\n dar: %08lx dsisr: %08lx exception: %08lx", + (*mc)->es.dar, (*mc)->es.dsisr, (*mc)->es.exception)); + + write (fd, buf, sprintf (buf, + "\n srr0: %08x srr1: %08x cr: %08x xer: %08x" + "\n lr: %08x ctr: %08x vrsave: %08x fpscr: %08x", + (*mc)->ss.srr0, (*mc)->ss.srr1, (*mc)->ss.cr, (*mc)->ss.xer, + (*mc)->ss.lr, (*mc)->ss.ctr, (*mc)->ss.vrsave, (*mc)->fs.fpscr)); + + write (fd, buf, sprintf (buf, "\n vrvalid: %08x vscr: %08lx:%08lx:%08lx:%08lx\n", + (*mc)->vs.save_vrvalid, + (*mc)->vs.save_vscr [0], (*mc)->vs.save_vscr [1], + (*mc)->vs.save_vscr [2], (*mc)->vs.save_vscr [3])); + + for (unsigned int *regs = &(*mc)->ss.r0, i = 0; i < 32; i += 4) + write (fd, buf, sprintf (buf, "\n r%-2d %08x r%-2d %08x r%-2d %08x r%-2d %08x", + i, regs [i], i+1, regs [i+1], i+2, regs [i+2], i+3, regs [i+3])); + for (int i = 0; i < 32; ++i) + write (fd, buf, sprintf (buf, "\n fp%-2d %016qx (%f)", i, + *(unsigned long long *) &(*mc)->fs.fpregs [i], + (*mc)->fs.fpregs [i])); + for (int i = 0; i < 32; ++i) + write (fd, buf, sprintf (buf, "\n vr%-2d %08lx:%08lx:%08lx:%08lx", i, + (*mc)->vs.save_vr[i][0], (*mc)->vs.save_vr[i][1], + (*mc)->vs.save_vr[i][2], (*mc)->vs.save_vr[i][3])); +#elif __sun + for (int i = 0; i < NGREG; i++) + write (fd, buf, sprintf (buf, "%s %%r%02d = %08x", + i % 4 == 0 ? "\n" : "", i, mc->gregs [i])); +#else + dumpMemory (fd, buf, mc, sizeof (*mc)); +#endif // __i386 && __linux, __sun, other + + write (fd, "\n", 1); +#endif // HAVE_POSIX_SIGNALS + + return sp; +} + +/** Dump application state information on a fatal signal. + + Use this method to dump program state on a delivery of a fatal + signal. #fatal() uses this function automatically if no fatal + handler hook has not been registered by the application. + + This function attempts to be as maximally robust given that it + runs in a signal handler in conditions where the program by + definition is unstable. In other words, it allocates no memory + and writes its output directly to a file descriptor with direct + system calls. For this reason some initialisation is required; + use #handleFatal() to register the current application name and an + output file descriptor, preferably as early in the program as + possible. + + The dump will consist of the following items: + - if #FATAL_DUMP_SIG option is set: + - the application name if registered with #handleFatal() + - a title describing telling which fatal signal has been + received (defined by @a sig, the signal number, or its + negative if core has been dumped) + - information available from the @a info argument + - if #FATAL_DUMP_CONTEXT option is set, all the available + CPU context information like registers + - if #FATAL_DUMP_STACK option is set, the stack trace + - if #FATAL_DUMP_LIBS option is set, the list of currently + loaded shared libraries + + This always returns @c true so it is convenient for the + application fatal hook to return with a call to this function. + + Note that this function will not flush @c std::cerr or @c stderr + before producing output, for stability reasons. If the streams + have unflushed output in their buffers, that output may get mixed + with unbuffered direct output from this function. If you wish to + avoid this mixup and are willing to take the risk that those calls + might crash, install an application hook that flushes the streams + and then calls this function. */ +static char buf[SIGNAL_MESSAGE_BUFSIZE]; +bool +Signal::fatalDump (int sig, siginfo_t *info, void *extra) +{ + bool haveCore = false; + if (sig < 0) + { + sig = -sig; + haveCore = true; + } + + if (s_fatalOptions & FATAL_DUMP_SIG) + { + MYWRITE (s_fatalFd, "\n", 1); + if (s_applicationName) + { + MYWRITE (s_fatalFd, s_applicationName, + STDC::strlen (s_applicationName)); + MYWRITE (s_fatalFd, " ", 1); + } + + MYWRITE (s_fatalFd, buf, + snprintf (buf, SIGNAL_MESSAGE_BUFSIZE, "(pid=%ld ppid=%ld) received fatal signal %d" + " (%.100s)%s\n", + (long) ProcessInfo__pid (), (long) ProcessInfo__ppid (), // wlav :: -> __ (x2) + sig, name (sig), haveCore ? " (core dumped)" : "")); + + MYWRITE (s_fatalFd, buf, sprintf(buf,"signal context:\n")); + dumpInfo (s_fatalFd, buf, sig, info); + } + + unsigned long sp = 0; + if (s_fatalOptions & FATAL_DUMP_CONTEXT) + sp = dumpContext (s_fatalFd, buf, extra); + + if (s_fatalOptions & FATAL_DUMP_STACK) + { + MYWRITE (s_fatalFd, buf, sprintf(buf,"\nstack trace:\n")); + if (s_lastSP) { + MYWRITE (s_fatalFd, buf, sprintf(buf,"\n(backtrace failed; raw dump follows)\n")); + MYWRITE (s_fatalFd, buf, sprintf(buf,"%016lx:", s_lastSP)); + dumpMemory (s_fatalFd, buf, reinterpret_cast<void*>(s_lastSP), 1024); + MYWRITE (s_fatalFd, buf, sprintf(buf,"\n\n")); + } + else { + s_lastSP = sp; + DebugAids::stacktrace (s_fatalFd); + } + s_lastSP = 0; + } + + if (s_fatalOptions & FATAL_DUMP_LIBS) + { + MYWRITE (s_fatalFd, buf, sprintf(buf,"\nshared libraries present:\n")); + try { SharedLibrary::loaded (*SignalDumpCallback); } + catch (...) { ; } + } + + return true; +} + +/** Return the file descriptor #fataldump() uses for output. + Registered through #handleFatal(). */ +IOFD +Signal::handleFatalFd (void) +{ + // Automatically initialise on first access. + if (s_fatalFd == IOFD_INVALID) + s_fatalFd = STDERR_HANDLE; + + return s_fatalFd; +} + +/** Return the application fatal signal hook. Registered through + #handleFatal(). @sa #fatal() */ +Signal::FatalHook +Signal::handleFatalHook (void) +{ return s_fatalHook; } + +/** Return the application fatal signal return hook. Registered + through #handleFatal(). @sa #fatal(). */ +Signal::FatalReturn +Signal::handleFatalReturn (void) +{ return s_fatalReturn; } + +/** Return the current fatal signal handling options. Set on + invocation to #handleFatal(). */ +unsigned +Signal::handleFatalOptions (void) +{ return s_fatalOptions; } + +/** Return the current application quit signal hook. Registered + through #handleQuit(). */ +Signal::QuitHook +Signal::handleQuitHook (void) +{ return s_quitHook; } + +/** Return the depth to which #fatal() is currently recursively + entered, or zero if #fatal() is not currently active. Use this + method in application fatal hook to decide which operations are + safe to perform. For example, if the attempts to notify the user + result in further signals, it is best to avoid such attempts at + deeper recursion levels. Currently #fatal() ceases to call the + application's hooks and forces termination if the nesting level + reaches 4. */ +int +Signal::fatalLevel (void) +{ return s_inFatal; } + +/** Return the crash status indicator: @c true if a fatal signal has + been received since the program started. Set if #fatal() is + entered with a fatal signal. */ +bool +Signal::crashed (void) +{ return s_crashed; } + +//} // namespace seal wlav +} // namespace Athena wlav + + +extern "C" { + /// Install fatal handler with default options. + /// This is meant to be easy to call from pyton via ctypes. + void CxxUtils_installFatalHandler() + { + Athena::Signal::handleFatal(nullptr, 1); + } +} diff --git a/EDM/athena/Control/CxxUtils/Root/StrFormat.cxx b/EDM/athena/Control/CxxUtils/Root/StrFormat.cxx new file mode 100644 index 00000000..a59f8e3a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/StrFormat.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StrFormat.cxx 579482 2014-01-22 09:14:16Z krasznaa $ +/** + * @file CxxUtils/src/StrFormat.cxx + * @author Sebastien Binet <binet@cern.ch> + * @date Jun, 2010 + * @brief Provide helper functions to create formatted strings + */ + +#include "CxxUtils/StrFormat.h" + +// c includes +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdexcept> + +namespace { + // little helper to ensure a char* is freed + class CharLiberator + { + char* m_buf; + + public: + explicit + CharLiberator(char* buf) : m_buf(buf) + {} + CharLiberator() : m_buf (NULL) + {} + ~CharLiberator() + { + free(m_buf); + } + }; + +} + +namespace CxxUtils { + +/** @brief return a `std::string` according to a format `fmt` and varargs + */ +std::string +strformat(const char* fmt, ...) +{ + char *buf = NULL; + int nbytes = -1; + + va_list ap; + va_start(ap, fmt); /* Initialize the va_list */ + + nbytes = vasprintf(&buf, fmt, ap); + va_end(ap); /* Cleanup the va_list */ + + if (nbytes < 0) { + /*buf is undefined when allocation failed + * see: http://linux.die.net/man/3/asprintf + */ + // free(buf); + throw std::runtime_error("problem while calling vasprintf"); + } + + CharLiberator guard(buf); + + // help compiler to apply RVO + return std::string(buf); +} + +} //> namespace CxxUtils + diff --git a/EDM/athena/Control/CxxUtils/Root/StringUtils.cxx b/EDM/athena/Control/CxxUtils/Root/StringUtils.cxx new file mode 100644 index 00000000..3e82a2dd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/StringUtils.cxx @@ -0,0 +1,805 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StringUtils.cxx,v 1.0 2014-05-25 16:54 cburgard Exp $ +/** + * @file StringUtils.cxx + * @author carsten burgard <cburgarc@cern.ch> + * @date May, 2014 + * @brief namespace for misc string utility + */ + + +#include "CxxUtils/StringUtils.h" +#include "StringUtils_aux.h" + +#include <algorithm> +#include <iostream> + +namespace CxxUtils { + + namespace StringUtils { + + /// calculate the width of a string + /** + \param str input string to be analyzed + \return number of 'characters' (printable entities) in this string + + this function will return the number of 'characters' (printable + entities) in any string. for well-behaved strings, this will be + identical to std::string::size(). however, + - non-printable-characters will not be counted + - control sequences will not be counted + - multi-byte characters will only be counted once + */ + size_t getStringWidth(const std::string& str){ + size_t i=0; + size_t w=0; + while(i<str.size()){ + int c = (unsigned char)(str[i]); + // handle control sequences + if (c == '\033'){ + size_t newi = str.find_first_of("mAC",i); + if(newi == std::string::npos){ + i++; + continue; + } else if(newi+1 < str.size()){ + i = newi+1; + continue; + } else { + return w; + } + } + // increase the index by the number of bytes in this character + i+=utf8_skip_data[c]; + // only count printable characters + if(c > 31) w++; + } + return w; + } + + + /// writes a string to a given stream with a fixed width + /** + short strings will be supplemented with spaces, long strings will be truncated. + this function respects and supports std::strings with wchar_t UTF8 entries + + \param os output stream to be used + \param input string to be written + \param width length of the target string in 'characters' (printable entities) + \param align option string controlling the alignment. + + the alignment string will be searched for the following characters: + 'l': triggers left-align (flushleft) + 'r': triggers right-align (flushright) + 'c' or 'm': triggers middle-align (center) + '.': annotate strings with '...' where truncated + */ + void writeFixedWidth(std::ostream& os, const std::string& input, size_t width, const std::string& align){ + size_t w = getStringWidth(input); + char a = 'l'; + if(align.find('r') != std::string::npos) a = 'r'; + else if(align.find('c') != std::string::npos || align.find('m') != std::string::npos) a = 'c'; + if(w < width){ + // we can fit the entire string and will only append spaces + size_t n = width - w; + switch(a){ + case 'l': + os << input; + for(size_t i=0; i<n; ++i) os << ' '; + break; + case 'c': + for(size_t i=0; i<ceil(0.5*n); ++i) os << ' '; + os << input; + for(size_t i=0; i<floor(0.5*n); ++i) os << ' '; + break; + case 'r': + for(size_t i=0; i<n; ++i) os << ' '; + os << input; + break; + default: + // this should never happen + return; + } + } else { + // we can't fit the entire string and need to crop + size_t dots = ((align.find('.') == std::string::npos) ? 0 : 3); + // the skip_head and skip_tail variables hold the number of + // characters to be skipped at the front and at the back of + // the string + size_t skip_head = 0; + size_t skip_tail = 0; + if(width < 2*dots) dots = 0; + switch(a){ + case 'l': + skip_head = 0; + skip_tail = w - width + dots; + break; + case 'c': + // add leading dots + for(size_t j=0; j<dots; j++) os << '.'; + skip_head = floor(0.5*(w - width)) + dots; + skip_tail = ceil (0.5*(w - width)) + dots; + break; + case 'r': + // add leading dots + for(size_t i=0; i<dots; ++i) os << '.'; + skip_head = w - width + dots; + skip_tail = 0; + break; + default: + // this should never happen + break; + } + // here, we actually loop over the string, writing all + // accepted characters + size_t ichar = 0; + size_t iwchar =0; + while(ichar<input.size()){ + int c = (unsigned char)(input[ichar]); + // take care that control sequences are added + if (c == '\033'){ + size_t i = input.find_first_of("mAC",ichar); + if(i != std::string::npos){ + os << input.substr(ichar,i-ichar+1); + if(i+1 < input.size()){ + ichar = i+1; + continue; + } else break; + } + } + // ignore any non-printable characters + if(c < 32){ + ichar++; + continue; + } + // compute the byte size of this character + size_t size = utf8_skip_data[c]; + // add it if it's inside the accepted range + if(iwchar >= skip_head && iwchar < (w - skip_tail)){ + os << input.substr(ichar,size); + } + // increase character count and index + iwchar++; + ichar+=size; + } + if(dots > 0){ + switch(a){ + case 'l': + // add trailing dots + for(size_t i=0; i<dots; ++i) os << '.'; + break; + case 'c': + // add trailing dots + for(size_t i=0; i<dots; i++) os << '.'; + break; + default: + // this should never happen + break; + } + } + } + } + + /// finds the nearest matching parenthesis in a string from a given position + /** + \param str string to search + \param nextpos starting position of parenthesis check + \param paropen opening parenthesis (arbitrary string) + \param parclose closing parenthesis (arbitrary string) + \return position of matching parenthesis close in the string + */ + size_type findParenthesisMatch(const std::string& str, + size_type nextpos, + const std::string& paropen, + const std::string& parclose) + { + size_type openbrace = 0; + size_type closebrace = 0; + size_type bracestack = 1; + while((bracestack > 0) && (nextpos < str.size())){ + openbrace = str.find(paropen, nextpos+1); + closebrace = str.find(parclose, nextpos+1); + nextpos++; + if(openbrace < closebrace){ + bracestack++; + nextpos = openbrace; + } else { + bracestack--; + nextpos = closebrace; + } + } + return nextpos; + } + + /// reverse-finds the nearest matching parenthesis in a string from a given position + /** + \param str string to search + \param nextpos starting position of parenthesis check + \param paropen opening parenthesis (arbitrary string) + \param parclose closing parenthesis (arbitrary string) + \return position of matching parenthesis close in the string + */ + size_type rfindParenthesisMatch(const std::string& str, + size_type nextpos, + const std::string& paropen, + const std::string& parclose) + { + size_type openbrace = 0; + size_type closebrace = 0; + size_type bracestack = 1; + while((bracestack > 0) && (nextpos < str.size())){ + openbrace = str.rfind(paropen, nextpos-1); + closebrace = str.rfind(parclose, nextpos-1); + // this line is correct and important! + closebrace = std::min(closebrace, closebrace+1); + // it helps to avoid overflows of 'closebrace' that lead to wrong return values! + nextpos--; + if(openbrace < closebrace){ + bracestack++; + nextpos = closebrace; + } else { + bracestack--; + nextpos = openbrace; + } + } + return nextpos; + } + + /// finds the next "free" occurrence of needle in haystack + /** + \param haystack string to search + \param needle string to search for + \param paropen opening parenthesis, denoting the beginning of a "closed block" + \param parclose closing parenthesis, denoting the end of a "closed block" + \param startpos position to start searching at + \return position of the next free occurrence + */ + size_type findFree(const std::string& haystack, + const std::string& needle, + const std::string& paropen, + const std::string& parclose, + size_type startpos) + { + size_type needlepos = haystack.find(needle, startpos); + size_type nextparopen = haystack.find(paropen, startpos); + while(needlepos != std::string::npos && needlepos > nextparopen){ + startpos = findParenthesisMatch(haystack, nextparopen, paropen, parclose)+1; + needlepos = haystack.find(needle, startpos); + nextparopen = haystack.find(paropen, startpos); + } + return needlepos; + } + + /// reverse-finds the next "free" occurrence of needle in haystack + /** + \param haystack string to search + \param needle string to search for + \param paropen opening parenthesis, denoting the beginning of a "closed block" + \param parclose closing parenthesis, denoting the end of a "closed block" + \param startpos position to start searching at + \return position of the previous free occurrence + */ + size_type rfindFree(const std::string& haystack, + const std::string& needle, + const std::string& paropen, + const std::string& parclose, + size_type startpos) + { + size_type needlepos = haystack.rfind(needle, startpos); + size_type nextparclose = haystack.rfind(parclose, startpos); + while(needlepos != std::string::npos && needlepos < nextparclose){ + startpos = rfindParenthesisMatch(haystack, nextparclose, paropen, parclose)-1; + // this line is correct and important! + startpos = std::min(startpos+1, startpos-1); + // it helps to avoid overflows of 'startpos' that result in non-terminating function calls! + needlepos = haystack.rfind(needle, startpos); + nextparclose = haystack.rfind(parclose, startpos); + } + return needlepos; + } + + /// finds the next "free" occurrence of any needle in haystack + /** + \param haystack string to search + \param needles string with characters to search for + \param paropen opening parenthesis, denoting the beginning of a "closed block" + \param parclose closing parenthesis, denoting the end of a "closed block" + \param startpos position to start searching at + \return position of the next free occurrence + */ + size_type findFreeOf(const std::string& haystack, + const std::string& needles, + const std::string& paropen, + const std::string& parclose, + size_type startpos) + { + size_type needlepos = haystack.find_first_of(needles, startpos); + size_type nextparopen = haystack.find(paropen, startpos); + while(needlepos != std::string::npos && needlepos > nextparopen){ + startpos = findParenthesisMatch(haystack, nextparopen, paropen, parclose)+1; + needlepos = haystack.find_first_of(needles, startpos); + nextparopen = haystack.find(paropen, startpos); + } + return needlepos; + } + + /// reverse-finds the next "free" occurrence of any needle in haystack + /** + \param haystack string to search + \param needles string with characters to search for + \param paropen opening parenthesis, denoting the beginning of a "closed block" + \param parclose closing parenthesis, denoting the end of a "closed block" + \param startpos position to start searching at + \return position of the previous free occurrence + */ + size_type rfindFreeOf(const std::string& haystack, + const std::string& needles, + const std::string& paropen, + const std::string& parclose, + size_type startpos) + { + size_type needlepos = haystack.find_last_of(needles, startpos); + size_type nextparclose = haystack.rfind(parclose, startpos); + while(needlepos != std::string::npos && needlepos < nextparclose){ + startpos = rfindParenthesisMatch(haystack, nextparclose, paropen, parclose); + // this line is correct and important! + startpos = std::min(startpos+1, startpos-1); + // it helps to avoid overflows of 'startpos' that result in non-terminating function calls! + needlepos = haystack.find_last_of(needles, startpos); + nextparclose = haystack.rfind(parclose, startpos); + // this line is correct and important! + nextparclose = std::min(nextparclose, nextparclose+1); + // it helps to avoid overflows of 'nextparclose' that result wrong return values + } + return needlepos; + } + + + /// replaces unicode, latex and html symbols with one another as desired + /** + \param str input string + \param inputFormat format of the input string + \param outputFormat format of the output string + \return new string with replaced symbols + */ + std::string replaceSymbols(const std::string& str, StringUtils::FORMAT inputFormat, StringUtils::FORMAT outputFormat){ + if(inputFormat == outputFormat) return str; + size_t index = 0; + std::string output = ""; + output.reserve(2*str.size()); + while(index < str.size()){ + size_t nextIndex = std::string::npos; + size_t symbolId = 0; + for(size_t i=0; i<STRINGUTILS__N_MAP_FORMAT; ++i){ + size_t idx = str.find(map_format[i][inputFormat],index); + const std::string& symbol = map_format[i][inputFormat]; + if(idx < nextIndex){ + const size_t endindex = index + map_format[i][inputFormat].size(); + // make sure that we have not selected something that's in the middle of a word + if(((index == 0) || !( + StringUtils::letters.find(str[index-1]) != std::string::npos && + StringUtils::letters.find(symbol[0]) != std::string::npos + )) + && + ((endindex+1 == str.size()) || !( + StringUtils::letters.find(str[endindex]) != std::string::npos && + StringUtils::letters.find(symbol[symbol.size()-1]) != std::string::npos + )) + ){ + nextIndex = idx; + symbolId = i; + } + } + } + if(nextIndex != std::string::npos){ + output += str.substr(index,nextIndex-index); + output += map_format[symbolId][outputFormat]; + index = nextIndex + map_format[symbolId][inputFormat].size(); + } else { + output += str.substr(index); + break; + } + // in the case of LATEX-code, we need to take care about the + // fact that latex commands without an explicitly given + // argument eat up all the space behind them + if(inputFormat == StringUtils::LATEX && map_format[symbolId][StringUtils::LATEX][0]=='\\' + && map_format[symbolId][StringUtils::LATEX].find_first_of("{}") == std::string::npos){ + index = str.find_first_not_of("\n \t",index); + index = str.find_first_not_of("{}",index); + } else if(outputFormat == StringUtils::LATEX && map_format[symbolId][StringUtils::LATEX][0]=='\\' + && map_format[symbolId][StringUtils::LATEX].find_first_of("{}") == std::string::npos){ + output += "{}"; + } + } + return output; + } + + /// replaces unicode superscript and subscript with the corresponding ascii characters and vice-versa + /** + \param str input string + \param inputType type of script to be removed + \param outputType type of script to be inserted + \return new string with replaced characters + */ + std::string replaceSpecialScript(const std::string& str, StringUtils::SPECIALSCRIPT inputType, StringUtils::SPECIALSCRIPT outputType){ + // if the input and output type are identical + if(inputType == outputType) return str; + size_t index = 0; + // allocate the string + std::string output; + output.reserve(2*str.size()); + while(index != std::string::npos){ + size_t symbolId = 0; + size_t nextIndex = std::string::npos; + // loop over all known symbols + for(size_t i=0; i<STRINGUTILS__N_MAP_SPECIALSCRIPT; ++i){ + // see which one turns up first in the string + size_t idx = str.find(map_specialscript[i][inputType],index); + if(idx < nextIndex){ + // save it + nextIndex = idx; + symbolId = i; + } + } + if(nextIndex != std::string::npos){ + output += str.substr(index,nextIndex-index); + output += map_specialscript[symbolId][outputType]; + index = nextIndex + map_specialscript[symbolId][inputType].size(); + } else { + output += str.substr(index); + index = nextIndex; + } + } + return output; + } + + + /// finds the next entity of a certain type of special script + /** + \param str input string + \param scripttype type of script to be found + \param pos starting position for the search + \return position of next special script entity of the given type + */ + size_type findBeginSpecialScript(const std::string& str, + StringUtils::SPECIALSCRIPT scripttype, + size_type pos) + { + while(pos < str.size()){ + for(size_t i=0; i<STRINGUTILS__N_MAP_SPECIALSCRIPT; ++i){ + if(str.find(map_specialscript[i][scripttype]) != std::string::npos) return pos; + } + } + return std::string::npos; + } + + /// finds the next entity not belonging to a certain type of special script + /** + \param str input string + \param scripttype type of script to be ignored + \param pos starting position for the search + \return position of next entity not belonging to the given type of special script + */ + size_type findEndSpecialScript(const std::string& str, + StringUtils::SPECIALSCRIPT scripttype, + size_type pos) + { + while(pos < str.size()){ + bool ok = false; + for(size_t i=0; i<STRINGUTILS__N_MAP_SPECIALSCRIPT; ++i){ + if(str.find(map_specialscript[i][scripttype]) != std::string::npos) ok = true; + } + if(!ok) return pos; + pos++; + } + return std::string::npos; + } + + /// removes all non-printable characters from a string + /** + \param str input string + \param allowNonAscii true will allow non-ascii characters, falls will remove them (default true) + \return modified string + */ + std::string stripUnprintableCharacters(const std::string& str, bool allowNonAscii){ + size_t i=0; + std::string output; + output.reserve(str.size()); + while(i<str.size()){ + int c = (unsigned char)(str[i]); + // handle control sequences + if (c == '\033'){ + size_t newi = str.find_first_of("mAC",i); + if(newi == std::string::npos){ + i++; + continue; + } else if(newi+1 < str.size()){ + i = newi+1; + continue; + } else { + return output; + } + } + // find the number of bytes in this character + size_t length = utf8_skip_data[c]; + if(c > 31){ + if(c < 128 || allowNonAscii){ + output += str.substr(i,length); + } + } + i+=length; + } + return output; + } + + /// guesses the format of a string + /** + \param input input string + \return supposed StringUtils::FORMAT + */ + StringUtils::FORMAT guessFormat(const std::string& input){ + boost::match_results<std::string::const_iterator> what; + if(boost::regex_search(input.begin(), input.end(), what, StringUtils::generic_latex_regex)) return StringUtils::LATEX; + if(boost::regex_search(input.begin(), input.end(), what, StringUtils::generic_html_entity_regex)) return StringUtils::HTML; + if(boost::regex_search(input.begin(), input.end(), what, StringUtils::generic_xml_regex)) return StringUtils::HTML; + for(size_t i=0; i<input.size(); ++i){ + if((unsigned char)(input[i]) > 128){ + return StringUtils::UNICODE; + } + } + return StringUtils::ASCII; + } + + + /// reads the next LaTeX token + /** + \param latex input string + \param token reference to the string where the token will be stored + \param start starting position + */ + inline size_t readLaTeXToken(const std::string& latex, std::string& token, size_t start){ + token.clear(); + if(start+2 > latex.size()) return std::string::npos; + if(latex[start] == '{'){ + size_type endgrp = StringUtils::findParenthesisMatch(latex,start,"{","}"); + token = latex.substr(start+1,endgrp-start-1); + return endgrp+1; + } else { + token += latex[start]; + return start+1; + } + } + + /// converts a string from one format into another + /** + \param input input string + \param inputFormat alleged input format (one of HTML, LATEX, UNICODE, ASCII) + \param outputFormat desired output format (one of HTML, LATEX, UNICODE, ASCII) + \return converted string + */ + std::string convertText(const std::string& input, StringUtils::FORMAT inputFormat, StringUtils::FORMAT outputFormat){ + if(inputFormat == outputFormat) return input; + if(inputFormat == StringUtils::ASCII){ + // if the input is plain ascii, we need to do nothing more than replace a couple of symbols + return StringUtils::replaceSymbols(input,inputFormat,outputFormat); + } + if(inputFormat == StringUtils::UNICODE){ + // if the input is unicode, we need to take care of superscript and subscript; + std::string scriptreplaced;; + scriptreplaced.reserve(2*input.size()); + size_t pos = 0; + while(pos < input.size()){ + size_type startSuperScript = findBeginSpecialScript(input,StringUtils::SUPERSCRIPT,pos); + size_type startSubScript = findBeginSpecialScript(input,StringUtils::SUBSCRIPT,pos); + if(startSuperScript == std::string::npos && startSubScript == std::string::npos){ + scriptreplaced += input.substr(pos); + break; + } + if(startSuperScript < startSubScript){ + size_t endScript = findEndSpecialScript(input,StringUtils::SUPERSCRIPT,startSuperScript); + scriptreplaced += map_superscript_starters[outputFormat]; + scriptreplaced += StringUtils::replaceSpecialScript(input.substr(startSuperScript,endScript-startSuperScript),StringUtils::SUPERSCRIPT,StringUtils::NORMALSCRIPT); + scriptreplaced += map_superscript_enders[outputFormat]; + pos = endScript; + } else { + size_t endScript = findEndSpecialScript(input,StringUtils::SUBSCRIPT,startSubScript); + scriptreplaced += map_subscript_starters[outputFormat]; + scriptreplaced += StringUtils::replaceSpecialScript(input.substr(startSubScript,endScript-startSubScript),StringUtils::SUBSCRIPT,StringUtils::NORMALSCRIPT); + scriptreplaced += map_subscript_enders[outputFormat]; + pos = endScript; + } + } + // now we need to replace the symbols + std::string symbolsreplaced = StringUtils::replaceSymbols(scriptreplaced,StringUtils::UNICODE,outputFormat); + // in the end, we just strip everything else + return StringUtils::stripUnprintableCharacters(symbolsreplaced); + } + if(inputFormat == StringUtils::LATEX){ + // this is LaTeX - the parsing is a little more involved in this case + std::string retval; + size_t pos = 0; + std::string latex = StringUtils::replaceSymbols(input,StringUtils::LATEX,outputFormat); + while(pos != std::string::npos){ + // we iterate over the string and only stop at 'special symbols' - everything else we just copy + size_t nextpos = latex.find_first_of("\\${^_",pos); + if(nextpos == std::string::npos){ + // we are at the end of the string -- copy the rest + retval += latex.substr(pos); + break; + } + // copy everything up to the special symbol we found + retval += latex.substr(pos,nextpos-pos); + switch(latex[nextpos]){ + case '^': + { + // superscript + std::string token; + // read the token + size_t endtok = readLaTeXToken(latex,token,nextpos+1); + if(endtok != std::string::npos){ + if(outputFormat == StringUtils::UNICODE) + // replace it with unicode characters + retval += replaceSpecialScript(StringUtils::trim(token),StringUtils::NORMALSCRIPT,StringUtils::SUPERSCRIPT); + else if(outputFormat == StringUtils::HTML){ + // wrap it in HTML tags + retval += "<sup>"; + retval += StringUtils::trim(token); + retval += "</sup>"; + } else { + retval += token; + } + } + pos = endtok; + } + break; + case '_': + { + // subscript + std::string token; + // read the token + size_t endtok = readLaTeXToken(latex,token,nextpos+1); + if(endtok != std::string::npos){ + if(outputFormat == StringUtils::UNICODE) + // replace it with unicode characters + retval += replaceSpecialScript(StringUtils::trim(token),StringUtils::NORMALSCRIPT,StringUtils::SUBSCRIPT); + else if(outputFormat == StringUtils::HTML){ + // wrap it in HTML tags + retval += "<sub>"; + retval += StringUtils::trim(token); + retval += "</sub>"; + } else { + retval += token; + } + } + pos = endtok; + } + break; + case '\\': + { + // isolate the command + size_type endpos = latex.find_first_not_of(StringUtils::letters,nextpos+1); + if (endpos == std::string::npos) + endpos = latex.size(); + std::string cmd(latex.substr(nextpos+1,endpos-nextpos-1)); + size_type opengrp = latex.find_first_not_of(StringUtils::whitespace,endpos); + if (opengrp == std::string::npos) + opengrp = latex.size(); + std::string token; + // read the token (argument of the command) + size_t endtok = readLaTeXToken(latex,token,opengrp); + if(outputFormat==StringUtils::HTML){ + // replace command by HTML equivalent (incomplete) + if(cmd=="textbf") retval += "<b>"+token+"</b>"; + else if(cmd=="textit") retval += "<i>"+token+"</i>"; + // TODO: process some more commands + else retval += token; + } else { + // do nothing + retval += token; + } + pos = endtok; + } + break; + case '$': + { + // find the end of the math block + size_t endpos = latex.find("$",nextpos+1); + if(endpos == std::string::npos){ + // it's unterminated, break + retval += latex.substr(pos); + pos = endpos; + break; + } + // extract the content + std::string result = StringUtils::convertText(latex.substr(nextpos+1,endpos-nextpos-1),StringUtils::LATEX,outputFormat); + if(outputFormat == StringUtils::HTML){ + // typeset the "math environment" + retval += "<span class='math' style='font-style:italic'>"; + retval += result; + retval += "</span>"; + } else { + // do nothing + retval += result; + } + pos = endpos+1; + } + break; + case '{': + { + // plain latex group (no command) + std::string token; + // read the token + size_t endtok = readLaTeXToken(latex,token,nextpos); + // re-insert it to get rid of the braces + retval += convertText(token,StringUtils::LATEX,outputFormat); + pos = endtok; + } + break; + default: + // this should never happen + throw "ERROR in CxxUtils::StringUtils::converText: an unknown key character was encountered!"; + } + } + return retval; + } + if(inputFormat == StringUtils::HTML){ + // currently, this only removes html tags + std::string retval; + boost::smatch opentagmatch; + std::string::const_iterator start = input.begin(); + // std::string::const_iterator last = input.begin(); + std::string::const_iterator end = input.end(); + while (boost::regex_search(start, end, opentagmatch,StringUtils::generic_xml_regex)){ + std::string tagname(opentagmatch[1]); + retval += StringUtils::replaceSymbols(input.substr(std::distance(input.begin(),start),std::distance(start,opentagmatch[0].first)),StringUtils::HTML,outputFormat); + boost::regex closeTag("<\\s*/"+tagname+"\\s*>"); + boost::smatch closetagmatch; + if(boost::regex_search(opentagmatch[0].second,end,closetagmatch,closeTag)){ + // <tagname> content </tagname> + std::string content =input.substr(std::distance(input.begin(),opentagmatch[0].second),std::distance(opentagmatch[0].second,closetagmatch[0].first)); + std::string result = StringUtils::trim(StringUtils::convertText(content,StringUtils::HTML,outputFormat)); + if(outputFormat == StringUtils::LATEX){ + if(tagname=="b") retval += "\\textbf{"+result+"}"; + else if(tagname=="i") retval += "\\textit{"+result+"}"; + else if(tagname=="sub") retval +="\\ensuremath{_{"+result+"}}"; + else if(tagname=="sup") retval +="\\ensuremath{^{"+result+"}}"; + // TODO: process some more tags + else retval += result; + } else if(outputFormat == StringUtils::UNICODE){ + if (tagname=="sub") retval +=StringUtils::replaceSpecialScript(result,StringUtils::NORMALSCRIPT,StringUtils::SUBSCRIPT); + else if(tagname=="sup") retval +=StringUtils::replaceSpecialScript(result,StringUtils::NORMALSCRIPT,StringUtils::SUPERSCRIPT); + else retval += result; + } else { + retval += result; + } + start = closetagmatch[0].second; + } else { + // lonely <tagname> + if(tagname=="br"){ + if(outputFormat==StringUtils::LATEX) retval += "\\\\"; + else retval += "\n"; + } + start = opentagmatch[0].second; + } + } + retval+=StringUtils::replaceSymbols(input.substr(std::distance(input.begin(),start),std::distance(start,end)),StringUtils::HTML,outputFormat); + return retval; + } + throw "ERROR in StringUtils::converText - control reached end of function!"; + } + + /// converts a string into any format + /** + This variant guesses the input format via StringUtils::guessFormat; + + \param input input string + \param outputFormat desired output format + \return converted string + */ + std::string convertText(const std::string& input, StringUtils::FORMAT outputFormat){ + return StringUtils::convertText(input,StringUtils::guessFormat(input),outputFormat); + } + } +} diff --git a/EDM/athena/Control/CxxUtils/Root/StringUtils_aux.h b/EDM/athena/Control/CxxUtils/Root/StringUtils_aux.h new file mode 100644 index 00000000..65027265 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/StringUtils_aux.h @@ -0,0 +1,229 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StringUtils_aux.h,v 1.0 2014-05-25 16:54 cburgard Exp $ +/** + * @file StringUtils_aux.h + * @author carsten burgard <cburgarc@cern.ch> + * @date May, 2014 + * @brief namespace for misc string utility + * + * This is an auxiliary header file that contains const-arrays used by + * the StringUtils package. These definitions have been removed from + * the StringUtils.cxx implementation file in order to improve + * readability of the latter file. + */ + +#ifndef CXXUTILS_STRINGUTILS_AUX_H +#define CXXUTILS_STRINGUTILS_AUX_H + +// this array maps the first byte of a character in utf8 encoding to +// the total number of bytes that comprise this character +const size_t utf8_skip_data[256] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 +}; + +// this array maps ascii symbols to the corresponding subscript and +// superscript unicode symbols. The script type is defined by the enum +// StringUtils::SPECIALSCRIPT in StringUtils.h +#define STRINGUTILS__N_MAP_SPECIALSCRIPT 70 +const std::string map_specialscript[STRINGUTILS__N_MAP_SPECIALSCRIPT][3] = { + {"0","â°","0" }, + {"1","¹","â‚"} , + {"2","²","â‚‚"}, + {"3","³","₃"}, + {"4","â´","â‚„"}, + {"5","âµ","â‚…"}, + {"6","â¶","₆"}, + {"7","â·","₇"}, + {"8","â¸","₈"}, + {"9","â¹","₉"}, + {"+","âº","â‚Š"}, + {"-","â»","â‚‹"}, + {"=","â¼","â‚Œ"}, + {"(","â½","â‚"}, + {")","â¾","â‚Ž"}, + {"a","ᵃ","â‚"}, + {"b","ᵇ","b"}, + {"c","ᶜ","c"}, + {"d","ᵈ","d"}, + {"e","ᵉ","â‚‘"}, + {"f","ᶠ","f"}, + {"g","áµ","g"}, + {"h","Ê°","â‚•"}, + {"i","â±","áµ¢"}, + {"j","ʲ","â±¼"}, + {"k","áµ","â‚–"}, + {"l","Ë¡","â‚—"}, + {"m","áµ","ₘ"}, + {"n","â¿","â‚™"}, + {"o","áµ’","â‚’"}, + {"p","áµ–","â‚š"}, + {"r","ʳ","áµ£"}, + {"s","Ë¢","â‚›"}, + {"t","áµ—","â‚œ"}, + {"u","ᵘ","ᵤ"}, + {"v","áµ›","áµ¥"}, + {"w","Ê·","w"}, + {"x","Ë£","â‚“"}, + {"y","ʸ","y"}, + {"z","ᶻ","z"}, + {"A","á´¬","A"}, + {"B","á´®","B"}, + {"D","á´°","D"}, + {"E","á´±","E"}, + {"G","á´³","G"}, + {"H","á´´","H"}, + {"I","á´µ","I"}, + {"J","á´¶","J"}, + {"K","á´·","K"}, + {"L","á´¸","L"}, + {"M","á´¹","M"}, + {"N","á´º","N"}, + {"O","á´¼","O"}, + {"P","á´¾","P"}, + {"R","á´¿","R"}, + {"T","áµ€","T"}, + {"U","áµ","U"}, + {"V","â±½","V"}, + {"W","ᵂ","W"}, + {"α","áµ…","α"}, + {"β","áµ","ᵦ"}, + {"γ","ᵞ","ᵧ"}, + {"δ","ᵟ","δ"}, + {"Ï","Ï","ᵨ"}, + {"ε","ᵋ","ε"}, + {"θ","ᶿ","θ"}, + {"ι","ᶥ","ι"}, + {"Φ","ᶲ","Φ"}, + {"φ","áµ ","ᵩ"}, + {"χ","ᵡ","ᵪ"} + }; +// these arrays contain the prefixes and suffixes for subscript and superscript in various formats +const std::string map_superscript_starters[4] = { + "","","\\ensuremath{^{","<sup>" +}; +const std::string map_superscript_enders[4] = { + "","","}}","</sup>" +}; +const std::string map_subscript_starters[4] = { + "","","\\ensuremath{_{","<sub>" +}; +const std::string map_subscript_enders[4] = { + "","","}}","</sub>" +}; + + + +// this array maps special symbols in different formats to each +// other. the formats and their indices are defined by the enum +// StringUtils::FORMAT in StringUtils.h +// this list is far from complete and should be extended +// if need be. +#define STRINGUTILS__N_MAP_FORMAT 94 +const std::string map_format[STRINGUTILS__N_MAP_FORMAT][4] = { + { " " ," "," " ," " }, + { " " ," ","~" ," " }, + { "x" ,"x", "x" ,"x" }, + { "0" ,"0", "0" ,"0" }, + { "E" ,"E", "E" ,"E" }, + { "Alpha", "Α", "\\Alpha", "Α" }, + { "Beta", "Î’", "\\Beta", "Β" }, + { "Gamma", "Γ", "\\Gamma", "Γ" }, + { "Delta", "Δ", "\\Delta", "Δ" }, + { "Epsilon","Ε", "\\Epsilon","Ε" }, + { "Zeta", "Ζ", "\\Zeta", "Ζ" }, + { "Eta", "Η", "\\Eta", "Η" }, + { "Theta", "Θ", "\\Theta", "Θ" }, + { "Iota", "I", "\\Iota", "Ι" }, + { "Kappa", "Κ", "\\Kappa", "Κ" }, + { "Lambda", "Λ", "\\Lambda", "Λ" }, + { "Mu", "M", "\\Mu", "Μ" }, + { "Nu", "Î", "\\Nu", "Ν" }, + { "Xi", "Ξ", "\\Xi", "Ξ" }, + { "Omicron","Ο", "\\Omicron","Ο" }, + { "Pi", "Î ", "\\Pi", "Π" }, + { "Rho", "Ρ", "\\Rho", "Ρ" }, + { "Sigma", "Σ", "\\Sigma", "Σ" }, + { "Tau", "Τ", "\\Tau", "Τ" }, + { "Upsilon","Î¥", "\\Upsilon","Υ" }, + { "Phi", "Φ", "\\Phi", "Φ" }, + { "Chi", "Χ", "\\Chi", "Χ" }, + { "Psi", "Ψ", "\\Psi", "Ψ" }, + { "Omega", "Ω", "\\Omega", "Ω" }, + { "alpha" ,"α", "\\alpha" ,"α" }, + { "beta" ,"β", "\\beta" ,"β" }, + { "gamma" ,"γ", "\\gamma" ,"γ" }, + { "delta" ,"δ", "\\delta" ,"δ" }, + { "epsilon","ε", "\\epsilon","ε" }, + { "zeta" ,"ζ", "\\zeta" ,"ζ" }, + { "eta" ,"η", "\\eta" ,"η" }, + { "theta" ,"θ", "\\theta" ,"θ" }, + { "iota" ,"ι", "\\iota" ,"ι" }, + { "kappa" ,"κ", "\\kappa" ,"κ" }, + { "lambda" ,"λ", "\\lambda" ,"λ" }, + { "mu" ,"μ", "\\mu" ,"μ" }, + { "nu" ,"ν", "\\nu" ,"ν" }, + { "xi" ,"ξ", "\\xi" ,"ξ" }, + { "omicron","ο", "\\omicron","ο" }, + { "pi" ,"Ï€", "\\pi" ,"π" }, + { "rho" ,"Ï", "\\rho" ,"ρ" }, + { "sigma" ,"σ", "\\sigma" ,"σ" }, + { "varsigma","Ï‚", "\\varsigma","&vsigma;" }, + { "tau" ,"Ï„", "\\tau" ,"τ" }, + { "upsilon","Ï…", "\\upsilon","υ" }, + { "phi" ,"φ", "\\phi" ,"φ" }, + { "chi" ,"χ", "\\chi" ,"χ" }, + { "psi" ,"ψ", "\\psi" ,"ψ" }, + { "omega" ,"ω", "\\omega" ,"ω" }, + { "-|" ,"¬", "\\neg" ,"¬" }, + { "+/-" ,"±", "\\pm" ,"±" }, + { "*" ,"*", "\\ast" ,"*" }, + { "*" ,"·", "\\cdot" ,"·" }, + { "x" ,"×", "\\times" ,"×" }, + { "->" ,"→", "\\righarrow" ,"&rarr" }, + { "->" ,"→", "\\to" ,"&rarr" }, + { "<-" ,"â†", "\\leftarrow" ,"&larr" }, + { "<=" ,"â‡", "\\Leftarrow" ,"⇐" }, + { "=>" ,"⇒", "\\Rightarrow","⇒" }, + { "<=>" ,"⇔", "\\Leftrightarrow","⇔"}, + { "(Vx)" ,"∀", "\\forall" ,"∀" }, + { "del" ,"∂", "\\partial","∂" }, + { "(Ex)" ,"∃", "\\exists" ,"∃" }, + { "0" ,"∅","\\emptyset","∅" }, + { "Nabla" ,"∇","\\nabla" ,"∇" }, + { "inf" ,"∞","\\infty" ,"∞" }, + { "isElem" ,"∈","\\in" ,"∈" }, + { "is!Elem","∉","\\not\\in" ,"∉" }, + { "Prod|" ,"âˆ","\\prod" ,"∏" }, + { "Sum|" ,"∑","\\sum" ,"∑" }, + { "sqrt|" ,"√","\\surd" ,"√" }, + { "/\\" ,"∧","\\wedge" ,"∧" }, + { "\\/" ,"∨","\\vee" ,"∨" }, + { "/\\" ,"∩","\\cap" ,"∩" }, + { "\\/" ,"∪","\\cup" ,"∪" }, + { "Int|" ,"∫","\\int" ,"∫" }, + { "~" ,"≈","\\approx" ,"≈" }, + { "!=" ,"≠","\\neq" ,"≠" }, + { "==" ,"≡","\\equiv" ,"≡" }, + { "<=" ,"≤","\\leq" ,"≤" }, + { ">=" ,"≥","\\geq" ,"≥" }, + { ">" ,"⊂","\\subset" ,"⊂" }, + { "<" ,"⊃","\\supset" ,"⊃" }, + { "°" ,"°","^\\circ" ,"°" }, + { "floor[" ,"⌊","\\lfloor" ,"⌊" }, + { "ceil[" ,"⌈","\\lceil" ,"⌈" }, + { "]" ,"]","\\[" ,"[" }, + { "]" ,"⌋","\\rfloor" ,"⌋" }, + { "]" ,"⌉","\\rceil" ,"⌉" } +}; + +#endif //CXXUTILS_STRINGUTILS_AUX_H diff --git a/EDM/athena/Control/CxxUtils/Root/cPtrAccessSEGVHandler.cxx b/EDM/athena/Control/CxxUtils/Root/cPtrAccessSEGVHandler.cxx new file mode 100644 index 00000000..5e76b0ee --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/cPtrAccessSEGVHandler.cxx @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "CxxUtils/cPtrAccessSEGVHandler.h" +#include "CxxUtils/PtrAccessSEGVHandler.h" +namespace { + PtrAccessSEGVHandler* s_pHandler(0); +} + +void setPtrAccessSEGVHandler(PtrAccessSEGVHandler* h) { s_pHandler=h; } +void cPtrAccessSEGVHandler(int signal, siginfo_t* si, void* old) { + s_pHandler->handle(signal, si, old); +} diff --git a/EDM/athena/Control/CxxUtils/Root/clock.cxx b/EDM/athena/Control/CxxUtils/Root/clock.cxx new file mode 100644 index 00000000..021da3b1 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/clock.cxx @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/clock.cxx + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Jan, 2010 + * @brief Implementation of clock_gettime() function for MacOSX + */ + +#include "CxxUtils/clock.h" + +#ifdef __APPLE__ +#include <stdint.h> +#include <mach/mach_time.h> + +long clock_gettime (unsigned int /*which_clock*/, struct timespec *tp) +{ + uint64_t time = 0; + mach_timebase_info_data_t info; + kern_return_t err = mach_timebase_info( &info ); + + //Convert the timebase into seconds + if( err == 0 ) { + uint64_t mach_time = mach_absolute_time( ); + time = mach_time * info.numer / info.denom; + } + tp->tv_sec = time * 1e-9; + tp->tv_nsec = time - (tp->tv_sec * 1e9); + return 0; +} +#endif diff --git a/EDM/athena/Control/CxxUtils/Root/excepts.cxx b/EDM/athena/Control/CxxUtils/Root/excepts.cxx new file mode 100644 index 00000000..4fe9651c --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/excepts.cxx @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/excepts.cxx + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Jan, 2010 + * @brief Implementations of feenableexcept()/fedisableexcept() functions for MacOSX. + */ + +#include "CxxUtils/excepts.h" + +#ifdef __APPLE__ +#include <fenv.h> + +int +feenableexcept (unsigned int excepts) +{ + static fenv_t fenv; + unsigned int new_excepts = excepts & FE_ALL_EXCEPT, + old_excepts; // previous masks + + if ( fegetenv (&fenv) ) return -1; + old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // unmask + fenv.__control &= ~new_excepts; + fenv.__mxcsr &= ~(new_excepts << 7); + + return ( fesetenv (&fenv) ? -1 : old_excepts ); +} + +int +fedisableexcept (unsigned int excepts) +{ + static fenv_t fenv; + unsigned int new_excepts = excepts & FE_ALL_EXCEPT, + old_excepts; // all previous masks + + if ( fegetenv (&fenv) ) return -1; + old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // mask + fenv.__control |= new_excepts; + fenv.__mxcsr |= new_excepts << 7; + + return ( fesetenv (&fenv) ? -1 : old_excepts ); +} +#endif diff --git a/EDM/athena/Control/CxxUtils/Root/exctrace.cxx b/EDM/athena/Control/CxxUtils/Root/exctrace.cxx new file mode 100644 index 00000000..b8d6f7d3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/exctrace.cxx @@ -0,0 +1,87 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/exctrace.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009 + * @brief Generate stack trace backs from a caught exception. + * + * The backtrace for the last exception is saved as static data + * in exctrace_last_depth and exctrace_last_trace, which are defined + * in the collector module. We use dlsym to find them, so that we can + * fail gracefully if the collector isn't present. + */ + + +#include "CxxUtils/exctrace.h" +#include <cstring> +#include <cstdio> +#include <cstdlib> +#include <execinfo.h> +#include <unistd.h> +#include <dlfcn.h> + + +using std::strlen; +using std::sprintf; +using std::free; + + +// Helper to write literals +# define MYWRITELIT(fd,str) MYWRITE(fd,str,sizeof(str)-1) + + +namespace CxxUtils { + + +/** + * @brief Print out information for the last exception. + * + * Prints the supplied exception, plus the backtrace from + * the last exception, if available. + * + * @param e The exception to print. + * @param fd The file descriptor to which to write. + */ +void exctrace (const std::exception& e, IOFD fd /*= IOFD_INVALID*/) +{ + if (fd == IOFD_INVALID) + fd = Athena::DebugAids::stacktraceFd(); + + static bool init = false; + static int* exctrace_last_depth = 0; + static void** exctrace_last_trace = 0; + + if (!init) { + init = true; + exctrace_last_depth = (int*)dlsym (RTLD_DEFAULT, "exctrace_last_depth"); + exctrace_last_trace = (void**)dlsym (RTLD_DEFAULT, "exctrace_last_trace"); + } + + MYWRITELIT(fd, "Exception: "); + MYWRITE(fd, e.what(), strlen (e.what())); + + if (exctrace_last_depth && exctrace_last_trace) { + MYWRITELIT(fd, "\n"); + // Index 0 is __cxa_throw. Skip it. + for (int i = 1; i < *exctrace_last_depth; ++i) { + unsigned long ip = + reinterpret_cast<unsigned long> (exctrace_last_trace[i]); + // A function that throws may have the call to __cxa_throw + // as the last instruction in the function. In that case, the IP + // we see here will be one beyond the end of the function, + // and we'll report the wrong function. So move back the IP + // slightly for the function that threw. + if (i == 1) --ip; + Athena::DebugAids::stacktraceLine (fd, ip); + } + } + else + MYWRITELIT(fd, " (no backtrace available).\n"); +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/Root/hashtable.cxx b/EDM/athena/Control/CxxUtils/Root/hashtable.cxx new file mode 100644 index 00000000..3439e16b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/hashtable.cxx @@ -0,0 +1,67 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: hashtable.cxx,v 1.1.1.1 2008-09-10 04:02:52 binet Exp $ +/** + * @file CxxUtils/src/hashtable.cxx + * @author scott snyder <snyder@bnl.gov>, copied from gcc4. + * @date May, 2007 + * @brief Out-of-line data for hashtable. + */ + + +#include "CxxUtils/hashtable.h" + + +namespace CxxUtils_Internal { + +const int X::n_primes; + +const unsigned long X::primes[X::n_primes + 1] = + { + 2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul, + 37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul, + 83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul, + 157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul, + 277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul, + 503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul, + 953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul, + 1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul, + 3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul, + 5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul, + 11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul, + 19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul, + 33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul, + 57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul, + 99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul, + 159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul, + 256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul, + 410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul, + 658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul, + 1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul, + 1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul, + 2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul, + 4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul, + 6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul, + 11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul, + 16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul, + 24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul, + 36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul, + 54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul, + 80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul, + 118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul, + 176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul, + 260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul, + 386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul, + 573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul, + 849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul, + 1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul, + 1725587117ul, 1866894511ul, 2019773507ul, 2185171673ul, + 2364114217ul, 2557710269ul, 2767159799ul, 2993761039ul, + 3238918481ul, 3504151727ul, 3791104843ul, 4101556399ul, + 4294967291ul, + 4294967291ul // sentinel so we don't have to test result of lower_bound + }; + +} // namespace CxxUtils_Internal diff --git a/EDM/athena/Control/CxxUtils/Root/page_access.cxx b/EDM/athena/Control/CxxUtils/Root/page_access.cxx new file mode 100644 index 00000000..c5e8a167 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/page_access.cxx @@ -0,0 +1,25 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "CxxUtils/page_access.h" +namespace athena{ + + void* page_address(void* addr) { + return (void*)((long)addr & ~(PAGESIZE-1)); + } + void* next_page_address(void* addr) { + return (void*)(((long)addr & ~(PAGESIZE-1)) + PAGESIZE); + } + + int page_protect(void* addr, int prot) { + int rc=mprotect(page_address(addr), PAGESIZE, prot); + if (rc) printf("page_protect WARNING: mprotect heap failed for void *address %p\n", addr); +#ifdef DEBUG + else printf("page_protect DEBUG: set protection @%i for range @%lx - @%lx containing void* addr=%p\n", + prot,(long unsigned int)page_address(addr), + (long unsigned int)page_address(addr) + PAGESIZE, addr); +#endif + return rc; + } +} diff --git a/EDM/athena/Control/CxxUtils/Root/pointer_list.cxx b/EDM/athena/Control/CxxUtils/Root/pointer_list.cxx new file mode 100644 index 00000000..f6b03f5a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/pointer_list.cxx @@ -0,0 +1,141 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/pointer_list.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009, from earlier code. + * @brief A fast way to store a variable-sized collection of pointers. + */ + + +#include "CxxUtils/pointer_list.h" +#include <algorithm> + + +namespace CxxUtils { + + +/** + * @brief Constructor. + * @param nelt Number of pointers per block. + * (excluding the end pointer). + * @param nblock Number of blocks to allocate per chunk. + * @param end_mask Mask to use for end-of-block test. + * @param end_offs Offset to use for end-of-block test. + */ +pointer_list_base::allocator::allocator (size_t nelt, + size_t nblock, + unsigned long end_mask, + unsigned long end_offs) + : m_nelt (nelt), + m_nblock (nblock), + m_chunks (0), + m_nthis (nblock), + m_nchunks (0), + m_end_mask (end_mask), + m_end_offs (end_offs) +{ +} + + +/** + * @brief Destructor. Deletes all blocks from this allocator. + */ +pointer_list_base::allocator::~allocator() +{ + // Loop over the chunks, deleting each one. + chunk* ch = m_chunks; + while (ch) { + chunk* next = ch->m_next; + delete [] reinterpret_cast<char*> (ch); + ch = next; + } +} + + +/** + * @brief Allocate a new chunk of blocks. + */ +void pointer_list_base::allocator::refill() +{ + char* p = new char + [(sizeof(chunk) + m_nblock*list_block::size(m_nelt)) + + list_block::size(m_nelt)-1]; + chunk* ch = reinterpret_cast<chunk*> (p); + + // Align. + unsigned long pp = reinterpret_cast<unsigned long> (ch+1); + pp = (pp + m_end_mask) & ~m_end_mask; + ch->m_blocks = reinterpret_cast<list_block*> (pp); + + ch->m_next = m_chunks; + m_chunks = ch; + ++m_nchunks; + + // No blocks allocated so far from this chunk. + m_nthis = 0; +} + + +/** + * @brief Erase the container. O(1). + * Note: doesn't free memory. + * Memory currently in use will be reused when the container + * is filled again. + */ +void pointer_list_base::clear() +{ + if (m_head) + m_insert = &m_head->m_data[0]; + m_size = 0; +} + + +/** + * @brief Allocate the first block of the list. + */ +void pointer_list_base::firstblock () +{ + m_head = getblock(); + m_insert = &m_head->m_data[0]; +} + + +/** + * @brief Extend the list with another block. + * @c m_insert should be at the end of the last block. + */ +void pointer_list_base::nextblock () +{ + // There may be one already allocated. Use it if so. + list_block* newblock = + reinterpret_cast<list_block*> (*m_insert); + if (!newblock) { + newblock = getblock(); + *m_insert = newblock; + } + m_insert = &newblock->m_data[0]; +} + + +/** + * @brief Allocate a new block. + */ +pointer_list_base::list_block* pointer_list_base::getblock () +{ + list_block* b = m_pool.allocate(); + size_t maxndx = m_pool.nelt(); + + // Make sure only the last element has the sentinel bit set. + std::fill (b->m_data, b->m_data + maxndx, value_type()); + b->m_data[maxndx] = 0; + + return b; +} + + +} // namespace CxxUtils + diff --git a/EDM/athena/Control/CxxUtils/Root/procmaps.cxx b/EDM/athena/Control/CxxUtils/Root/procmaps.cxx new file mode 100644 index 00000000..13070ae7 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/procmaps.cxx @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <algorithm> +#include <cstdlib> +#include <cstring> +#include <fstream> +#include "CxxUtils/procmaps.h" +bool procmaps::s_pmapsLoaded(false); +procmaps::procmaps_t procmaps::s_pmaps; +procmaps::Entry::Entry(const char* procMapsLine) : + begAddress(0),endAddress(0), + readable(false), writable(false), executable(false), isPrivate(false), + offset(0), inode(0) +{ + dev[0]=0; dev[1]=0; + memset(pathname,' ',31); + char pageProts[5]; + memset(pageProts,' ', 4); + sscanf(procMapsLine, + "%80lx-%80lx %4s %80x %2x:%2x %80x %31s", + &this->begAddress, + &this->endAddress, + pageProts, + &this->offset, + &this->dev[0], + &this->dev[1], + &this->inode, + this->pathname + ); + //printf("pageProts %s pathname <%s> \n", pageProts, pathname); + this->readable = (pageProts[0] == 'r'); + this->writable = (pageProts[1] == 'w'); + this->executable = (pageProts[2] == 'x'); + this->isPrivate = (pageProts[3] == 'p'); +} + +procmaps::procmaps(size_t entries) { + if (!s_pmapsLoaded) { + procmaps::s_pmaps.reserve(entries); + loadMaps(false); + s_pmapsLoaded=true; + } +} + +void +procmaps::loadMaps(bool dump) { + procmaps::s_pmaps.clear(); + std::ifstream f("/proc/self/maps"); + const int LMAX=256; + char line[LMAX]; + while ( f.getline(line,LMAX) ) { + if (dump) printf("%s",line); + procmaps::s_pmaps.push_back(Entry(line)); + } +} + +const procmaps::Entry* +procmaps::getEntry(const void * address, bool refreshMaps) { + const procmaps::Entry* ret(0); + //FIXME slow linear search. We'll make it faster... + const_iterator i(this->begin()), e(this->end()); + bool found(false), done(false); + unsigned long toMatch((unsigned long)address); + while (!done && !found && i!=e) { + // printf(" begAddress %x toMatch %x endAddress %x\n", i->begAddress, toMatch, i->endAddress); + found = i->begAddress <= toMatch && toMatch <= i->endAddress; + done = !found && toMatch < i->begAddress; //entries sorted by begAddress + if (!found && !done) ++i; + } + if (found) ret=&*i; + else if (refreshMaps) { + //if ! found recurse once by calling getEntry with refreshMaps false + loadMaps(); + ret = getEntry(address,false); + } + return ret; +} diff --git a/EDM/athena/Control/CxxUtils/Root/read_athena_statm.cxx b/EDM/athena/Control/CxxUtils/Root/read_athena_statm.cxx new file mode 100644 index 00000000..b57a7f5e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/read_athena_statm.cxx @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <errno.h> +#include <stdio.h> +#include <string.h> /* strerror */ +#include <unistd.h> +#ifdef __APPLE__ +# include <mach/task_info.h> +# include <mach/mach.h> +#endif // __APPLE__ +#include "CxxUtils/read_athena_statm.h" +struct athena_statm +read_athena_statm() +{ + struct athena_statm res = {0, 0}; +#ifndef __APPLE__ + + const char *filename = "/proc/self/statm"; + FILE* fd = fopen(filename, "r"); + if (0==fd) { + fprintf(stderr, + "read_statm: problem opening file %s:\n%s\n", + filename, strerror(errno)); + return res; + } + + fscanf(fd, "%80u %80u", &res.vm_pages, &res.rss_pages); + fclose(fd); +#else + int pagesize = getpagesize(); + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + if (KERN_SUCCESS == task_info(mach_task_self(), + TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) { + // On the Mac, the virtual and resident sizes are returned in units of bytes + // whereas CoreDumpSvc expects them to be returned in units of pages + res.vm_pages = t_info.virtual_size/pagesize; + res.rss_pages = t_info.resident_size/pagesize; + } +#endif + return res; +} + diff --git a/EDM/athena/Control/CxxUtils/Root/sincosf.cxx b/EDM/athena/Control/CxxUtils/Root/sincosf.cxx new file mode 100644 index 00000000..02b98b07 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/sincosf.cxx @@ -0,0 +1,22 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/sincosf.cxx + * @author David Quarrie <David.Quarrie@cern.ch> + * @date Jan, 2010 + * @brief Implementation of sincosf function for MacOSX + */ + +#include "CxxUtils/sincosf.h" +#include <cmath> + +#ifdef __APPLE__ +void sincosf(float x, float* sn, float* cs) +{ + *sn = std::sin(x); + *cs = std::cos(x); +} +#endif diff --git a/EDM/athena/Control/CxxUtils/Root/ubsan_suppress.cxx b/EDM/athena/Control/CxxUtils/Root/ubsan_suppress.cxx new file mode 100644 index 00000000..5b98b9f3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/Root/ubsan_suppress.cxx @@ -0,0 +1,75 @@ +/** + * @file CxxUtils/Root/ubsan_suppress.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2017 + * @brief Helper for suppressing ubsan warnings. + */ + + +#include "CxxUtils/ubsan_suppress.h" +#include <unistd.h> +#include <fcntl.h> +#include <dlfcn.h> + + +namespace CxxUtils { + + +class RedirStderr +{ +public: + RedirStderr(); + ~RedirStderr(); + +private: + int m_nullfd; + int m_stderr; +}; + + +// Redirect stderr to /dev/null, remembering the original FD. +RedirStderr::RedirStderr() +{ + m_nullfd = open ("/dev/null", O_WRONLY); + m_stderr = dup (2); + dup2 (m_nullfd, 2); +} + + +// Restore stderr to its original FD. +RedirStderr::~RedirStderr() +{ + dup2 (m_stderr, 2); + close (m_nullfd); + close (m_stderr); +} + + +/** + * @brief Helper for suppressing ubsan warnings. + * @param func Function to call (may be a lambda). + * + * If ubsan is running, temporarily redirect stderr to /dev/null. + * Then call @c func. + * + * For example, we sometimes get a bogus ubsan warning from + * cling initialization. This can be suppressed by adding something like: + * + *@code + * CxxUtils::ubsan_suppress ([]() { TInterpreter::Instance(); }); + @endcode + */ +void ubsan_suppress (void (*func)()) +{ + if (dlsym (RTLD_DEFAULT, "__ubsan_handle_add_overflow") != NULL) + { + RedirStderr redir; + func(); + } + else { + func(); + } +} + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/cmt/Makefile.RootCore b/EDM/athena/Control/CxxUtils/cmt/Makefile.RootCore new file mode 100644 index 00000000..022bee9b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/cmt/Makefile.RootCore @@ -0,0 +1,24 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = CxxUtils +PACKAGE_PRELOAD = boost_system boost_regex +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = -DXAOD_STANDALONE -DXAOD_ANALYSIS +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = Asg_Boost TestTools +PACKAGE_TRYDEP = +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 1 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 0 +PACKAGE_REFLEX = 0 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/EDM/athena/Control/CxxUtils/cmt/requirements b/EDM/athena/Control/CxxUtils/cmt/requirements new file mode 100644 index 00000000..e0ab4d6e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/cmt/requirements @@ -0,0 +1,83 @@ +## Automatically generated CMT requirements file +package CxxUtils +author Sebastien Binet <binet@cern.ch> +author Scott Snyder <snyder@fnal.gov> + +## For Athena policies: it has to be the first use statement +use AtlasPolicy AtlasPolicy-* + +## Put here your package dependencies... +use AtlasBoost AtlasBoost-* External +## + +# Specify required Boost components for cmake (transparent to CMT) +apply_pattern cmake_add_command command="find_package(Boost COMPONENTS program_options regex)" + +branches CxxUtils src doc share + +# The following is a hack for MacOSX since I can't make it resolve the symbols at runtime in +# the separate library, even though everything appears to be setup correctly. +macro CxxUtils_AthDsoCbk "" target-darwin "AthDsoCbk.c" +library CxxUtils ../Root/*.cxx $(CxxUtils_AthDsoCbk) + +apply_pattern installed_library + +private + +library exctrace_collector exctrace/exctrace_collector.cxx +apply_pattern named_installed_library library=exctrace_collector +macro_remove CxxUtils_linkopts "-lexctrace_collector" + +library calg libcalg/*.c +apply_pattern named_installed_library library=calg +macro_remove CxxUtils_linkopts "-lcalg" + +## for logging dlopen calls +library AthDSoCallBacks AthDsoCbk.c +apply_pattern named_installed_library library=AthDSoCallBacks +macro_append AthDSoCallBacks_dependencies " calg " +macro_append AthDSoCallBacks_use_linkopts " -lpthread -lcalg " +macro_remove CxxUtils_linkopts "-lAthDSoCallBacks" + +## unit tests + +use TestTools TestTools-* AtlasTest + +apply_pattern UnitTest_run unit_test=read_athena_statm \ + extrapatterns="read_athena_statm reports process size" + +apply_pattern UnitTest_run unit_test=PageAccessControl +apply_pattern UnitTest_run unit_test=SEGVHandler \ + extrapatterns="page fault|FIXME NOT Freeing memory" +apply_pattern UnitTest_run unit_test=hashtable +apply_pattern UnitTest_run unit_test=fpcompare +apply_pattern UnitTest_run unit_test=procmaps +apply_pattern UnitTest_run unit_test=sincos +apply_pattern UnitTest_run unit_test=copyif +apply_pattern UnitTest_run unit_test=ArrayScanner +apply_pattern UnitTest_run unit_test=Arrayrep +apply_pattern UnitTest_run unit_test=Array +apply_pattern UnitTest_run unit_test=PackedArray +apply_pattern UnitTest_run unit_test=pointer_list +apply_pattern UnitTest_run unit_test=FloatPacker +apply_pattern UnitTest_run unit_test=stacktrace +apply_pattern UnitTest_run unit_test=StrFormat +apply_pattern UnitTest_run unit_test=copy_bounded +apply_pattern UnitTest_run unit_test=prefetch +apply_pattern UnitTest_run unit_test=ClassName +apply_pattern UnitTest_run unit_test=make_unique +apply_pattern UnitTest_run unit_test=ones +apply_pattern UnitTest_run unit_test=BitPackerUnpacker + +apply_pattern UnitTest_run unit_test=exctrace1 +apply_pattern UnitTest_run unit_test=exctrace2 +macro_append exctrace2_test_dependencies " exctrace1_test " +macro_append exctrace2_utest_dependencies " exctrace1_test " + +#apply_pattern UnitTest_run unit_test=utf8trim +#apply_pattern UnitTest_run unit_test=stringformconvert + +macro_append CxxUtils_use_linkopts " $(Boost_linkopts_regex) " + +end_private + diff --git a/EDM/athena/Control/CxxUtils/ispellwords b/EDM/athena/Control/CxxUtils/ispellwords new file mode 100644 index 00000000..8e8b30eb --- /dev/null +++ b/EDM/athena/Control/CxxUtils/ispellwords @@ -0,0 +1,1126 @@ +scott +snyder +CxxUtils +ClassName +cxx +cmt +ATN +ctors +ForwardIterator +SLC4 +binutils +config +SealCommon +sys +siginfo +climits +sincos +'describe +Winklmeier +procmaps +cPtrAccessSIGVHandler +sigaction +PtrAccessSIGVHandler +PtrAccessSEGVHandler +SG +iface +ptrs +sscanf +gcc4 +utests +nop +CaloConditions +emacs +PageAccessControl +undef +ifstream +getline +OSX +Moyse +CaloRec +WritableArrayData +WritableArray +miscompares +SEGVHandler +Gaudi +printf +protectPage +backtrace +NULs +stacktrace +DataModel +ieee754 +linenumber +sincosf +gettime +RSA +MD5 +Leggett +libcalg +dso +exctrace +linkopts +utest +libAthDsoCallbacks +libAthDsoCbk +libCxxUtils +AthDsoCbk +Grrr +cstdio +MacOSX +feenableexcept +Quarrie +slc +formatter +stdout +printfs +sname +dli +stacktraceLine +inFatal +fatalReturn +snprintf +sprintf +Lavrijsen +Wim +debuglink +demangle +filt +addr2line +eu +builtin +SealDebug +cern +seuster +deallocation +allocator +malloc +savannah +AFS +AtlasGdb +C89 +NDEBUG +linux +Seuster +Rolf +wscript +hscript +hwafize +Binet +Sebastien +xaod +hwaf +prefetchTwo +prefetchNext +SLC6's +SLC6 +ATLASLocalRootBase +runtime +syscall +coverity +coredump +noreturn +gcc +hashtable +denormals +CoreDumpSvc +Calafiura +Paolo +xAOD +SealSignal +MacOS +RootCore +Krasznahorkay +ATH +statm +athena +src +lexctrace +calg +lcalg +lpthread +lAthDSoCallBacks +FIXME +extrace1 +regex +ssnyder +ArrayScanner +param +namespace +Arrayrep +resized +resize +0's +msg +subarrays +subarray +str +dimIndex +idx +ostream +ExcBadClassName +ExcMissingVariable +cn +STL +pos +const +endcode +fullName +applyRules +ints +Packdest +nbits +inout +denormal +Renormalize +Denormalize +packdest +nmantissa +errcheck +eg +NaN +underflowed +denormalize +unbias +ie +zeroizing +Zeroize +02x +len +PackedArray +sz +bitsize +ndx +Resizes +preallocate +rvalue +lvalue +mprotect +prot +addr +procmap +nextUnprot +nextProt +SEGVs +lenLeak +pageAddr +ifdef +0x +endif +mapvector +lx +fixme +ia +eaxx +trapno +signo +errno +wlav +Tuura +Lassi +SealBase +io +Solaris +KCC's +IRIX +SGI +Tru64 +ABI +HANDLEs +posixy +libc +sss +fd +popen +pid +PID +CLOEXEC +pipe2 +glibc +POSIX +SIGHUP +SIGQUIT +SIGINT +SEH +WIN32 +RtlGetContext +XP +PEXCEPTION +GrabExceptionContext +ExceptionInformation +ExceptionRecord +ContextRecord +addr's +DLL +IP +PRELOAD +LD +08lx +DWARF2 +IA64 +DLADDR +UX +xlf +AIX +IOFD +stacktraceFd +Autoload +dll +imagehlp +exceptargs +DWORD +RtlCaptureContext +oldseh +LPTOP +SetUnhandledExceptionFilter +RaiseException +demangling +ARG +ULONG +args +2u +sizeof +undecname +UnDecorateSymbolName +UNDNAME +THISTYPE +SYMS +04lx +aix +ux +recode +nbufs +tru64 +linker's +RLD +Elf32 +rld +100s +012lx +irix +0f +KCC +libexc +lookups +Dl +sigtramp's +lookup +dladdr +fde +demangled +200s +pc +sc +exc +t's +sigcontext +solaris +lu +API +unix +mpatrol +faq +prog +ndetach +nwhere +gdb +dbx +DDD +SIGUSR1 +sig +SIGABRT +SIGIOT +utils +n32 +darwin +pragma +putenv +dylib +sl +'extern +SharedLibraryError +dlerror +dlopen +shl +LoadLibrary +SINIX +ptx +DYNIX +NX +DRS +DG +SVR4 +UnixWare +XCOFF +Cygwin +BFD +SunOS +COFF +LynxOS +bsd +struct +extern +un +ld +lm +sdt +som +Dyn +ElfW +LINKMAP +RTLD +dlinfo +ptr +dyn +symlink +phnum +phdr +prelinking +vaddr +gp +Ehdr +Elf64 +ret +prelinked +0xffffffff +objList +o32 +crt1 +ehdr +inq +ldr +bss +loadquery +alloca +SymEnumerateModules +initialisation +initialising +abadon +destructor +symname +prepending +dlsym +findsym +GetProcAddress +SignalLibDump +krasznaa +sigtimedwait +sigwaitinfo +sigwait +sigpause +sigsuspend +sigpending +sigsetmask +sigrelse +sigmask +sigblock +sighold +sigprocmask +3P +pthread +killpg +sigsend +sigqueue +sigaltstack +sigsetops +sigvec +sigset +BookTextView +systemerror +SharedLibrary +fataldump +strsignal +ONSTACK +NOCLDSTOP +restartable +blockMask +LFsignal +behaviour +unixen +multi +msecs +EAGAIN +SIGTERM +debuggable +USR1 +unhandled +mainreturn +pre +fatalDump +applicationName +bitwise +SIGPIPE +ASYNC +nfs +SIGLOST +SIGALRM +SIGUSR2 +pollable +SIGPOLL +async +SIGIO +SIGVTALRM +SIGPROF +SIGRTMAX +SIGRTMIN +IOT +breakpoint +profiler +cpu +initialised +fatalFd +initialise +SignalDumpLibs +QuitHook +handleFatal +handleQuit +gui +ungrab +precreated +popup +sigsetjmp +dereferences +siglongjmp +fatalLevel +reinstall +ultracorrect +quitHook +fatalHook +deregistering +mesq +AIO +noop +opcode +coprocessor +buf +ExceptionCode +ExceptionFlags +ExceptionAddress +PVOID +NumberParameters +ExceptionInfo +SIGCHLD +uid +stime +utime +GetThreadContext +getcontext +eflags +eip +ebx +eax +edx +ecx +edi +esi +ebp +ds +ss +fs +FPU +ip +fp +ABIs +08x +04x +cr2 +oldmask +04hx +dsisr +dar +xer +cr +srr1 +srr0 +fpscr +vrsave +lr +vscr +vrvalid +2d +016qx +vr +02d +i386 +mixup +unbuffered +unflushed +stderr +LIBS +ppid +x2 +nstack +nshared +sa +StrFormat +varargs +fmt +va +vasprintf +RVO +cburgard +StringUtils +burgard +carsten +'characters +mAC +'m +'c +flushright +'r +flushleft +'l +os +UTF8 +wchar +parclose +paropen +nextpos +'closebrace +startpos +'startpos +'nextparclose +html +unicode +outputFormat +inputFormat +versa +ascii +outputType +inputType +scripttype +allowNonAscii +LaTeX +'special +textbf +textit +TODO +unterminated +italic +'font +'math +tagname +ensuremath +br +utf8 +enum +ᵃ +â‚ +ᵇ +ᶜ +ᵈ +ᵉ +â‚‘ +ᶠ+áµ +Ê° +â± +áµ¢ +ʲ +áµ +Ë¡ +áµ +áµ’ +â‚’ +áµ– +ʳ +áµ£ +Ë¢ +áµ— +ᵘ +ᵤ +áµ› +áµ¥ +Ê· +Ë£ +â‚“ +ʸ +ᶻ +á´¬ +á´® +á´° +á´± +á´³ +á´´ +á´µ +á´¶ +á´· +á´¸ +á´¹ +á´º +á´¼ +á´¾ +á´¿ +áµ€ +áµ +ᵂ +α +áµ… +β +áµ +ᵦ +γ +ᵞ +ᵧ +δ +ᵟ +Ï +ᵨ +ε +ᵋ +θ +ᶿ +ι +ᶥ +Φ +ᶲ +φ +áµ +ᵩ +χ +ᵡ +ᵪ +italic +timebase +cxa +binet +nblock +nelt +31s +2x +4s +8x +pathname +pageProts +endAddress +toMatch +begAddress +refreshMaps +getEntry +recurse +strerror +italic +asd +icc +test1 +eq +nt +subst +DataVector +FloatPacker +DAZ +7ff00000 +npack +DEBUGIT +pv +forbidPage +pac +restorePageProt +valgrind +trapReads +0x8000 +pInt +cPtrAccessSEGVHandler +pString +pPair +loadMaps +fflush +rkprintf +prev +chk +ok +1f +3f +3e +000e +strformat +copyif +stdlib +argc +libexctrace +exe +exctrace1 +back1 +fpcompare +Sep +FAILX +x87 +TR1 +MERCHANTABILITY +Unordered +libstdc +etaoin +shrdlu +durian +typedef +abcde +bool +prefetch +test6 +pHeapEntry +calaf +VM +RSS +realloc +memusage +libc's +Vectorized +coefs +40s +italic +macosx +cbk +unregister +stl +sysconf +VMem +userdata +tid +mutex +vmem +AthLdPreload +destructors +abi +preloaded +TORTIOUS +resizing +ArrayList +onwards +list1 +sublists +AVL +node2 +node1 +'direction +'node +subtree +Rebalance +unlinked +Unlink +rebalancing +subtrees +unreference +tree2 +tree1 +'heap +'other +'vals +vals +num +BinomialTree +'roots +XORed +XORing +stricmp +strcasecmp +djb2 +tolower +unlink +'next +'prev +iter +SetEntry +entrypoint +'rover +slist +Trie +trie +NUL +decrementing +free'd +Arrayelt +templated +ArrayIterator +ArrayIteratorChooser +Arrayrep's +i'th +Typedefs +dereferenced +Dereference +ctor +dereference +RHS +elt +WriteableArray +ns +init +api +cplusplus +ATHUNLIKELYMACROS +BASICTYPES +declarators +BadClassName +CLASSNAMEPARSER +denormalized +nexp +Abzug +Mordechai +merchantible +merchantability +MD4 +MD2 +MDDRIVER +MD5C +MD5Transform +HH +GG +recomputation +typedefs +SEGV +StoreGateSvc +segfaulted +IOTypes +SealPlatform +cstdlib +siglist +pstack +LIBPATH +DYLD +SHLIB +logstream +Filename +SHAREDLIB +csignal +unblockable +tty +LN10 +LN2 +setgid +setuid +handlFatal +javascript +greek +multibyte +0m +1m +35m +34m +33m +32m +31m +abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +pred +ingroup +SIGSEGV +setPtrAccessSEGVHandler +endo +bego +endi +begi +emplace +inserter +dtor +calorimeter +CXX0X +GXX +'s +GNUC +x1 +x3 +x4 +functionals +inlined +EVAL +IParticle +x86 +sse +mfpmath +msse +msse2 +fn +unordered +doxygen +Austern +N1456 +WG21 +Dreizin +Tavori +LIBSTDCXX +tr1 +PDTR +1a +FNV +Vo +Noll +frexp +instantiations +hashtable's +H2 +H1 +h1 +h2 +bkt +T2 +T1 +iff +accessor +CopyConstructible +ExtractKey +unary +RehashPolicy +tradeoff +multimap +multiset +hasher +allocators +LWG +prepend +ArrayLists +arraylist +value2 +value1 +func +ifndef +AVLTreeNode +avl +AVLTree +AVLTreeValue +BinaryHeap +BinaryHeapValue +BinomialHeap +BinomialHeapValue +BloomFilter +bloomfilter +filter2 +filter1 +location2 +location1 +nocase +string2 +string1 +HashTableIterator +HashTable +HashTableValue +ListIterator +ListEntry +ListValue +listentry +QueueValue +SetIterator +SetValue +set2 +set1 +li +SListIterator +SListEntry +SListValue +TrieValue +Wconversion +mem +thsi +CxxXUtils +Salnikov +predefine +prefetches +CacheLineSize +prefetching +CPUs +AMD +cachelinesize +hw +sysctlbyname +LINESIZE +DCACHE +LEVEL1 +endIter +prefetched +LBNL +dev +rss +vm +proc +D0 +ang +ffast +fsincos +sn +v2df +VECPOLY +italic +italic +italic +Α +Î’ +Γ +Δ +Ε +Ζ +Η +Θ +Κ +Λ +Î +Ξ +Ο +Î +Ρ +Σ +Τ +Î¥ +Χ +Ψ +Ω +ζ +η +κ +λ +μ +ν +ξ +ο +Ï€ +σ +varsigma +Ï‚ +vsigma +Ï„ +Ï… +ψ +ω +plusmn +ast +cdot +middot +righarrow +rarr +leftarrow +larr +lArr +Rightarrow +rArr +Leftrightarrow +hArr +Vx +forall +del +emptyset +Nabla +nabla +infty +infin +isElem +isin +notin +sqrt +surd +radic +vee +asymp +neq +ne +leq +le +geq +ge +supset +circ +lfloor +ceil +lceil +rfloor +rceil +Tp +MakeUniq +typename +italic diff --git a/EDM/athena/Control/CxxUtils/share/ArrayScanner_test.ref b/EDM/athena/Control/CxxUtils/share/ArrayScanner_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/Array_test.ref b/EDM/athena/Control/CxxUtils/share/Array_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/Arrayrep_test.ref b/EDM/athena/Control/CxxUtils/share/Arrayrep_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/BitPackerUnpacker_test.ref b/EDM/athena/Control/CxxUtils/share/BitPackerUnpacker_test.ref new file mode 100644 index 00000000..bae42c55 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/BitPackerUnpacker_test.ref @@ -0,0 +1,2 @@ +test1 +test2 diff --git a/EDM/athena/Control/CxxUtils/share/ClassName_test.ref b/EDM/athena/Control/CxxUtils/share/ClassName_test.ref new file mode 100644 index 00000000..7b7fa2ad --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/ClassName_test.ref @@ -0,0 +1,5 @@ +test1 +test_eq +test_match +test_subst +test_rules diff --git a/EDM/athena/Control/CxxUtils/share/FloatPacker_test.ref b/EDM/athena/Control/CxxUtils/share/FloatPacker_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/PackedArray_test.ref b/EDM/athena/Control/CxxUtils/share/PackedArray_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/PageAccessControl_test.ref b/EDM/athena/Control/CxxUtils/share/PageAccessControl_test.ref new file mode 100644 index 00000000..789d9d1c --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/PageAccessControl_test.ref @@ -0,0 +1,6 @@ +*** PageAccessControl_test starts *** +PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x804e000 - 0x804efff containing address range=0x804e980 - 0x804e983 +PageAccessControl::restorePageProt DEBUG: restored protection 7 for page 0x804e000 containing address 0x804e000 + FIXME NOT Freeing memory at (nil) +accessing restored pointer 2 +*** PageAccessControl_test OK *** diff --git a/EDM/athena/Control/CxxUtils/share/SEGVHandler_test.ref b/EDM/athena/Control/CxxUtils/share/SEGVHandler_test.ref new file mode 100644 index 00000000..83c9076b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/SEGVHandler_test.ref @@ -0,0 +1,42 @@ +*** SEGVHandler_test starts *** +sigaction installing handler returned 0 +@pInt=0x1d2d620 +@pString=0x1d2e620 +@pPair=0x1d2f620 +PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x1d2d000 - 0x1d2dfff containing address range=0x1d2d620 - 0x1d2d623 +PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x1d2e000 - 0x1d2efff containing address range=0x1d2e620 - 0x1d2e627 +PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x1d2f000 - 0x1d2ffff containing address range=0x1d2f620 - 0x1d2f62f +page fault @address=0x1d2d620 +page fault signo=11 +page fault errno=0 +this page fault failed because you tried to access a protected address +PageAccessControl::restorePageProt DEBUG: restored protection 3 for page 0x1d2d000 containing address 0x1d2d000 + FIXME NOT Freeing memory at (nil) +accessing pInt 11 +reading again from pInt 11 +try to write 33 +read 33 +PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x1d2e000 - 0x1d2efff containing address range=0x1d2e620 - 0x1d2e627 +page fault @address=0x1d2e620 +page fault signo=11 +page fault errno=0 +this page fault failed because you tried to access a protected address +PageAccessControl::restorePageProt DEBUG: restored protection 3 for page 0x1d2e000 containing address 0x1d2e000 + FIXME NOT Freeing memory at (nil) +reading from string bar +reading again from string bar +page fault @address=0x1d2f628 +page fault signo=11 +page fault errno=0 +this page fault failed because you tried to access a protected address +PageAccessControl::restorePageProt DEBUG: restored protection 3 for page 0x1d2f000 containing address 0x1d2f000 + FIXME NOT Freeing memory at (nil) +reading double from pair 2 +reading again double from pair 2 +try to read 33 +read 33 +accessed ptrs +@0x1d2d620 +@0x1d2e620 +@0x1d2f628 +*** SEGVHandler_test OK *** diff --git a/EDM/athena/Control/CxxUtils/share/StrFormat_test.ref b/EDM/athena/Control/CxxUtils/share/StrFormat_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/copy_bounded_test.ref b/EDM/athena/Control/CxxUtils/share/copy_bounded_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/copy_bounded_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/CxxUtils/share/copyif_test.ref b/EDM/athena/Control/CxxUtils/share/copyif_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/exctrace1_test.ref b/EDM/athena/Control/CxxUtils/share/exctrace1_test.ref new file mode 100644 index 00000000..aaf3420e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/exctrace1_test.ref @@ -0,0 +1 @@ +Exception: yo mama (no backtrace available). diff --git a/EDM/athena/Control/CxxUtils/share/exctrace2_test.ref b/EDM/athena/Control/CxxUtils/share/exctrace2_test.ref new file mode 100644 index 00000000..9f203126 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/exctrace2_test.ref @@ -0,0 +1,7 @@ +Exception: yo mama + 0x08048b4e bar() ../test/exctrace1_test.cxx:7 + 0xea [../i686-slc4-gcc34-dbg/exctrace1_test.exe] + 0x08048b68 fee() ../test/exctrace1_test.cxx:13 + 0x18 [../i686-slc4-gcc34-dbg/exctrace1_test.exe] + 0x08048b87 foo() ../test/exctrace1_test.cxx:18 + 0x19 [../i686-slc4-gcc34-dbg/exctrace1_test.exe] + 0x08048c12 main ../test/exctrace1_test.cxx:29 + 0x2e [../i686-slc4-gcc34-dbg/exctrace1_test.exe] + 0x0082ddf3 __libc_start_main + 0xd3 [/lib/tls/libc.so.6] + 0x080489e1 __gxx_personality_v0 + 0x49 [../i686-slc4-gcc34-dbg/exctrace1_test.exe] diff --git a/EDM/athena/Control/CxxUtils/share/fpcompare_test.ref b/EDM/athena/Control/CxxUtils/share/fpcompare_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/hashtable_test.ref b/EDM/athena/Control/CxxUtils/share/hashtable_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/make_unique_test.ref b/EDM/athena/Control/CxxUtils/share/make_unique_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/make_unique_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/CxxUtils/share/ones_test.ref b/EDM/athena/Control/CxxUtils/share/ones_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/ones_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/CxxUtils/share/pointer_list_test.ref b/EDM/athena/Control/CxxUtils/share/pointer_list_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/prefetch_test.ref b/EDM/athena/Control/CxxUtils/share/prefetch_test.ref new file mode 100644 index 00000000..7609d92b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/prefetch_test.ref @@ -0,0 +1,88 @@ +prefetch address: 0 size: 1 + prefetch address: 0 + prefetch address: 0 +prefetch address: 0x1 size: 1 + prefetch address: 0x1 + prefetch address: 0x1 +prefetch address: 0x3f size: 1 + prefetch address: 0x3f + prefetch address: 0x3f +prefetch address: 0x40 size: 1 + prefetch address: 0x40 + prefetch address: 0x40 +prefetch address: 0 size: 2 + prefetch address: 0 + prefetch address: 0x1 +prefetch address: 0x1 size: 2 + prefetch address: 0x1 + prefetch address: 0x2 +prefetch address: 0x3e size: 2 + prefetch address: 0x3e + prefetch address: 0x3f +prefetch address: 0x3f size: 2 + prefetch address: 0x3f + prefetch address: 0x40 +prefetch address: 0x40 size: 2 + prefetch address: 0x40 + prefetch address: 0x41 +prefetch address: 0 size: 64 + prefetch address: 0 + prefetch address: 0x3f +prefetch address: 0x1 size: 64 + prefetch address: 0x1 + prefetch address: 0x40 +prefetch address: 0x3f size: 64 + prefetch address: 0x3f + prefetch address: 0x7e +prefetch address: 0x40 size: 64 + prefetch address: 0x40 + prefetch address: 0x7f +prefetch address: 0 size: 67 + prefetch address: 0 + prefetch address: 0x40 + prefetch address: 0x42 +prefetch address: 0x1 size: 67 + prefetch address: 0x1 + prefetch address: 0x41 + prefetch address: 0x43 +prefetch address: 0x3d size: 67 + prefetch address: 0x3d + prefetch address: 0x7d + prefetch address: 0x7f +prefetch address: 0x3e size: 67 + prefetch address: 0x3e + prefetch address: 0x7e + prefetch address: 0x80 +prefetch address: 0x3f size: 67 + prefetch address: 0x3f + prefetch address: 0x7f + prefetch address: 0x81 +prefetch address: 0x40 size: 67 + prefetch address: 0x40 + prefetch address: 0x80 + prefetch address: 0x82 +prefetch address: 0xa size: 32 + prefetch address: 0xa + prefetch address: 0x29 +prefetch address: 0xa size: 64 + prefetch address: 0xa + prefetch address: 0x49 +prefetch address: 0xa size: 128 + prefetch address: 0xa + prefetch address: 0x4a + prefetch address: 0x89 +prefetch address: 0xa size: 256 + prefetch address: 0xa + prefetch address: 0x4a + prefetch address: 0x8a + prefetch address: 0xca + prefetch address: 0x109 +test6 + prefetch address: 0x100 + prefetch address: 0x127 + prefetch address: 0x400 + prefetch address: 0x427 + prefetch address: 0x480 + prefetch address: 0x4a7 + prefetch address: 0x480 + prefetch address: 0x4a7 diff --git a/EDM/athena/Control/CxxUtils/share/procmaps_test.ref b/EDM/athena/Control/CxxUtils/share/procmaps_test.ref new file mode 100644 index 00000000..04cd542c --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/procmaps_test.ref @@ -0,0 +1,2 @@ +*** procmaps_test starts *** +*** procmaps_test OK *** diff --git a/EDM/athena/Control/CxxUtils/share/read_athena_statm_test.ref b/EDM/athena/Control/CxxUtils/share/read_athena_statm_test.ref new file mode 100644 index 00000000..c922c325 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/read_athena_statm_test.ref @@ -0,0 +1,3 @@ +*** read_statm_test starts *** +read_athena_statm reports process size (in pages): VM 5654 RSS 399 +*** read_statm_test OK *** diff --git a/EDM/athena/Control/CxxUtils/share/sincos_test.ref b/EDM/athena/Control/CxxUtils/share/sincos_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/CxxUtils/share/stacktrace_test.ref b/EDM/athena/Control/CxxUtils/share/stacktrace_test.ref new file mode 100644 index 00000000..55e3c685 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/stacktrace_test.ref @@ -0,0 +1,5 @@ + 0xX Athena::DebugAids::stacktrace(int) + 0xX [/libCxxUtils.so D[0xX]] + 0xX fromhere() + 0xX [/stacktrace_test.exe D[0xX]] + 0xX main + 0xX [/stacktrace_test.exe D[0xX]] + 0xX __libc_start_main + 0xX [/libc.so.6 D[0xX]] + 0xX _start + 0xX [/stacktrace_test.exe D[0xX]] diff --git a/EDM/athena/Control/CxxUtils/share/stringformconvert_test.ref b/EDM/athena/Control/CxxUtils/share/stringformconvert_test.ref new file mode 100644 index 00000000..b5e08ab4 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/stringformconvert_test.ref @@ -0,0 +1,7 @@ +The English word alphabet came into Middle English from the Late Latin word alphabetum, which in turn originated in the Greek αλφαβητος (alphabetos), from α and β, the first two letters of the Greek alphabet. -- Wikipedia +The English word alphabet came into Middle English from the Late Latin word alphabetum, which in turn originated in the Greek \alpha{}\lambda{}\phi{}\alpha{}\beta{}\eta{}\tau{}\omicron{}\varsigma{} (alphabetos), from alpha and beta, the first two letters of the Greek alphabet. -- Wikipedia +The English word alphabet came into Middle English from the Late Latin word alphabetum, which in turn originated in the Greek αλφαβητο&vsigma; (alphabetos), from alpha and beta, the first two letters of the Greek alphabet. -- Wikipedia +The English word alphabet came into Middle English from the Late Latin word alphabetum, which in turn originated in the Greek αλφαβητο&vsigma; (alphabetos), from alpha and beta, the first two letters of the Greek alphabet. -- Wikipedia +\textbf{hello world!} $3^2+4^{ 2 } = 5^{2}$ +<b>hello world!</b> <span class='math' style='font-style:italic'>3<sup>2</sup>+4<sup>2</sup> = 5<sup>2</sup></span> +hello world! 3²+4² = 5² diff --git a/EDM/athena/Control/CxxUtils/share/utf8trim_test.ref b/EDM/athena/Control/CxxUtils/share/utf8trim_test.ref new file mode 100644 index 00000000..dcd2f0e9 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/share/utf8trim_test.ref @@ -0,0 +1,14 @@ +'hello world!' has length 12, should be 12 +'Oh Süßes Nichtstun!' has length 19, should be 19 +'[1mOh Süßes Nichtstun![0m' has length 19, should be 19 +'hello world! ' +' hello world!' +' hello world! ' +' hello world! ' +'Oh Süßes' +'Oh Süßes...' +'Süßes Nichts' +'...Süßes Nichts...' +'Nichtstun!' +'...Nichtstun!' +'...[1mNichtstun![0m' diff --git a/EDM/athena/Control/CxxUtils/src/AthDsoCbk.c b/EDM/athena/Control/CxxUtils/src/AthDsoCbk.c new file mode 100644 index 00000000..9e1c688e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/AthDsoCbk.c @@ -0,0 +1,348 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/* implementation for AthDsoCbk */ + +/* CxxUtils includes */ +#include "CxxUtils/AthDsoCbk.h" +#include "CxxUtils/unused.h" + +#ifndef __linux__ + +/* stubs for macosx */ +int +ath_dso_cbk_register(ath_dso_event_cbk_t cbk, void *userdata) +{ + if( cbk || userdata ) {} + return 0; +} + +/* unregister a callback function with the dso-cbk framework */ +int +ath_dso_cbk_unregister(ath_dso_event_cbk_t cbk) +{ + if( cbk ) {} + return 0; +} + +#else /*linux*/ + +#define _GNU_SOURCE 1 + +/* stl includes */ +#include <stdlib.h> + +#include <stdio.h> +#include <pthread.h> + +#include <dlfcn.h> +#include <stdlib.h> +#include <unistd.h> /*for sysconf and page size*/ + +#include "CxxUtils/libcalg/libcalg.h" + +/* return the VMem in kilo-bytes */ +static +float fetch_vmem (void); + +/* internal structure to hold a callback and its associated userdata (if any) + */ +struct ath_dso_event_cbk_impl +{ + ath_dso_event_cbk_t cbk; + void *data; +}; +typedef struct ath_dso_event_cbk_impl ath_dso_event_cbk; + +/* list of registered callbacks */ +static ArrayList *g_dso_callbacks = NULL; + +/* default callback function */ +static +int +ath_dso_event_cbk_default(const struct ath_dso_event* event, void *userdata); + +struct dlfcn_hook +{ + void *(*dlopen) (const char *file, int mode, void *dl_caller); + int (*dlclose) (void *handle); + void *(*dlsym) (void *handle, const char *name, void *dl_caller); + void *(*dlvsym) (void *handle, const char *name, const char *version, + void *dl_caller); + char *(*dlerror) (void); + int (*dladdr) (const void *address, Dl_info *info); + int (*dladdr1) (const void *address, Dl_info *info, + void **extra_info, int flags); + int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller); + void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller); + void *pad[4]; +}; + +extern struct dlfcn_hook *_dlfcn_hook __attribute__ ((nocommon)); + +void *ath_dlopen( const char *fname, int mode, void *dl_caller ); +int ath_dlclose( void *handle ); +void *ath_dlsym( void *handle, const char *name, void *dl_caller ); +void *ath_dlvsym( void *handle, const char *name, const char *version, void *dl_caller ); +char *ath_dlerror( void ); +int ath_dladdr( const void *address, Dl_info *info ); +int ath_dladdr1( const void *address, Dl_info *info, void **extra_info, int flags ); +int ath_dlinfo( void *handle, int request, void *arg, void *dl_caller ); +void *ath_dlmopen( Lmid_t nsid, const char *file, int mode, void *dl_caller ); + +static struct dlfcn_hook ath_dl_hook = { + ath_dlopen, ath_dlclose, ath_dlsym, ath_dlvsym, ath_dlerror, + ath_dladdr, ath_dladdr1, ath_dlinfo, ath_dlmopen, { 0, 0, 0, 0 } +}; +static pthread_mutex_t ath_dl_hook_lock = PTHREAD_MUTEX_INITIALIZER; + +void* +ath_dlopen( const char *fname, int mode, void *UNUSED(dl_caller) ) +{ + struct ath_dso_event dso_evt; + int idx; + void *result; + + result = NULL; + pthread_mutex_lock(&ath_dl_hook_lock); + + _dlfcn_hook = 0; + dso_evt.fname = fname; + dso_evt.step = 0; + for (idx=0; idx != g_dso_callbacks->length; ++idx) { + ath_dso_event_cbk* cbk = g_dso_callbacks->data[idx]; + (*cbk->cbk)(&dso_evt, cbk->data); + } + + result = dlopen( fname, mode ); + + dso_evt.step = 1; + for (idx=g_dso_callbacks->length; idx != 0; --idx) { + ath_dso_event_cbk* cbk = g_dso_callbacks->data[idx-1]; + (*cbk->cbk)(&dso_evt, cbk->data); + } + + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + + return result; +} + +int +ath_dlclose( void *handle ) +{ + int result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dlclose( handle ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +void* +ath_dlsym( void *handle, const char *name, void *UNUSED(dl_caller) ) +{ + void *result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dlsym( handle, name ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +void* +ath_dlvsym( void *handle, const char *name, const char *version, void *UNUSED(dl_caller) ) +{ + void *result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dlvsym( handle, name, version ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +char* +ath_dlerror( void ) +{ + char *result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dlerror(); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +int +ath_dladdr( const void *address, Dl_info *info ) +{ + int result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dladdr( address, info ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +int +ath_dladdr1( const void *address, Dl_info *info, void **extra_info, int flags ) +{ + int result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dladdr1( address, info, extra_info, flags ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +int +ath_dlinfo( void *handle, int request, void *arg, void *UNUSED(dl_caller) ) +{ + if( dl_caller ) {} + int result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dlinfo( handle, request, arg ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +void* +ath_dlmopen( Lmid_t nsid, const char *file, int mode, void *UNUSED(dl_caller) ) +{ + if( dl_caller ) {} + void *result = 0; + pthread_mutex_lock(&ath_dl_hook_lock); + _dlfcn_hook = 0; + result = dlmopen( nsid, file, mode ); + _dlfcn_hook = &ath_dl_hook; + pthread_mutex_unlock(&ath_dl_hook_lock); + return result; +} + +void +ath_dl_hook_install() +{ + pthread_mutex_init(&ath_dl_hook_lock, NULL); + /*printf("AthDsoCbk: installing mutex in tid [%d]\n", pthread_self());*/ + /* printf ("AthDsoCbk: setting dlopen hooks\n" ); */ + _dlfcn_hook = &ath_dl_hook; +} + +void ath_dl_hook_release () +{ + _dlfcn_hook = 0; + /*printf ("AthDsoCbk: releasing library\n");*/ + pthread_mutex_destroy(&ath_dl_hook_lock); +} + +float +fetch_vmem (void) +{ + unsigned siz, rss, shd; + FILE *fp = fopen ("/proc/self/statm", "r"); + if (fp == NULL) { + return -999; + } + + /* FIXME: error handling... */ + (void)fscanf(fp, "%80u%80u%80u", &siz, &rss, &shd); + fclose (fp); + + double pg_sz = sysconf(_SC_PAGESIZE); + return (pg_sz * siz)/ (float)1024; +} + +/* default callback function */ +int +ath_dso_event_cbk_default(const struct ath_dso_event* evt, void *userdata) +{ + int pid = getpid(); + float vmem = fetch_vmem(); + if (userdata) {} + printf ("AthLdPreload: [%d] loading [%s] vmem = [%8.3f] (%d)", + pid, evt->fname, vmem, evt->step); + + return 0; +} + +/* register a callback function with the dso-cbk framework + * @return 0 on success + * -1 on failure + */ +int +ath_dso_cbk_register(ath_dso_event_cbk_t cbk, void *userdata) +{ + ath_dso_event_cbk *dso_callback = (ath_dso_event_cbk*)malloc(sizeof(ath_dso_event_cbk)); + dso_callback->cbk = cbk != NULL + ? cbk + : ath_dso_event_cbk_default; + dso_callback->data = userdata; + + if (!arraylist_append(g_dso_callbacks, dso_callback)) { + free(dso_callback); + return -1; + } + + return 0; +} + +/* unregister a callback function with the dso-cbk framework */ +int +ath_dso_cbk_unregister(ath_dso_event_cbk_t cbk) +{ + int i = 0; + for (i = 0; i != g_dso_callbacks->length; ++i) { + ath_dso_event_cbk * elem = g_dso_callbacks->data[i]; + if (elem->cbk == cbk) { + free(elem); elem = NULL; + arraylist_remove(g_dso_callbacks, i); + return 0; + } + } + /* no such callback */ + return -1; +} + +/* constructors and destructors */ + +static void setup() __attribute__ ((constructor)); +static void cleanup() __attribute__ ((destructor)); + +void +setup() +{ + static int initialized = 0; + if (!initialized) { + initialized = 1; + + /* list of registered callbacks */ + g_dso_callbacks = arraylist_new(0); + + ath_dl_hook_install(); + + } +} + +void +cleanup() +{ + static int finalized = 0; + if (!finalized) { + finalized = 1; + ath_dl_hook_release(); + + /* free list of registered callbacks */ + arraylist_free(g_dso_callbacks); + } +} + +#endif + diff --git a/EDM/athena/Control/CxxUtils/src/exctrace/exctrace_collector.cxx b/EDM/athena/Control/CxxUtils/src/exctrace/exctrace_collector.cxx new file mode 100644 index 00000000..db7acb30 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/exctrace/exctrace_collector.cxx @@ -0,0 +1,68 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/src/exctrace/exctrace_collector.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009 + * @brief Generate stack trace backs from a caught exception --- + * collector module. + * + * When preloaded, this module hooks into the __cxa_throw function + * used by the abi to throw exceptions so that it records stack + * back traces in static variables. These can later be accessed + * with @c CxxUtils::exctrace. + */ + + +#include <dlfcn.h> +#include <execinfo.h> +#include <cstdio> +#include <typeinfo> + +// Maximum stack depth. +static +const int bt_depth = 100; + +// Static buffer used to save the backtrace. +int exctrace_last_depth = 0; +void* exctrace_last_trace[bt_depth]; + +// The real __cxa_throw function. +typedef void throwfn (void*, std::type_info*, void (*dest)(void*)); +static throwfn* old_throw; + + +// The __cxa_throw hook function. +// Record a backtrace, then chain to the real throw function. +extern "C" void __cxa_throw (void* thrown_exception, + std::type_info* tinfo, + void (*dest)(void*)) +{ + exctrace_last_depth = backtrace (exctrace_last_trace, bt_depth); + old_throw (thrown_exception, tinfo, dest); +} + + +// Initialization: install the hook. +namespace CxxUtils { + + +struct extrace_init +{ + extrace_init(); +}; + + +extrace_init::extrace_init() +{ + old_throw = (throwfn*)(long)dlsym (RTLD_NEXT, "__cxa_throw"); +} + + +static extrace_init initer; + + +} // namespace CxxUtils diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/arraylist.c b/EDM/athena/Control/CxxUtils/src/libcalg/arraylist.c new file mode 100644 index 00000000..aff57ece --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/arraylist.c @@ -0,0 +1,268 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> +#include <string.h> + +#include "CxxUtils/libcalg/arraylist.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +/* Automatically resizing array */ + +ArrayList *arraylist_new(int length) +{ + ArrayList *new_arraylist; + + /* If the length is not specified, use a sensible default */ + + if (length <= 0) { + length = 16; + } + + /* Allocate the new ArrayList and fill in the fields. There are + * initially no entries. */ + + new_arraylist = (ArrayList *) malloc(sizeof(ArrayList)); + + if (new_arraylist == NULL) { + return NULL; + } + + new_arraylist->_alloced = length; + new_arraylist->length = 0; + + /* Allocate the data array */ + + new_arraylist->data = malloc(length * sizeof(ArrayListValue)); + + if (new_arraylist->data == NULL) { + free(new_arraylist); + return NULL; + } + + return new_arraylist; +} + +void arraylist_free(ArrayList *arraylist) +{ + /* Do not free if a NULL pointer is passed */ + + if (arraylist != NULL) { + free(arraylist->data); + free(arraylist); + } +} + +static int arraylist_enlarge(ArrayList *arraylist) +{ + ArrayListValue *data; + int newsize; + + /* Double the allocated size */ + + newsize = arraylist->_alloced * 2; + + /* Reallocate the array to the new size */ + + data = realloc(arraylist->data, sizeof(ArrayListValue) * newsize); + + if (data == NULL) { + return 0; + } else { + arraylist->data = data; + arraylist->_alloced = newsize; + + return 1; + } +} + +int arraylist_insert(ArrayList *arraylist, int index, ArrayListValue data) +{ + /* Sanity check the index */ + + if (index < 0 || index > arraylist->length) { + return 0; + } + + /* Increase the size if necessary */ + + if (arraylist->length + 1 > arraylist->_alloced) { + if (!arraylist_enlarge(arraylist)) { + return 0; + } + } + + /* Move the contents of the array forward from the index + * onwards */ + + memmove(&arraylist->data[index + 1], + &arraylist->data[index], + (arraylist->length - index) * sizeof(ArrayListValue)); + + /* Insert the new entry at the index */ + + arraylist->data[index] = data; + ++arraylist->length; + + return 1; +} + +int arraylist_append(ArrayList *arraylist, ArrayListValue data) +{ + return arraylist_insert(arraylist, arraylist->length, data); +} + +int arraylist_prepend(ArrayList *arraylist, ArrayListValue data) +{ + return arraylist_insert(arraylist, 0, data); +} + +void arraylist_remove_range(ArrayList *arraylist, int index, int length) +{ + /* Check this is a valid range */ + + if (index < 0 || length < 0 || index + length > arraylist->length) { + return; + } + + /* Move back the entries following the range to be removed */ + + memmove(&arraylist->data[index], + &arraylist->data[index + length], + (arraylist->length - (index + length)) * sizeof(ArrayListValue)); + + /* Decrease the counter */ + + arraylist->length -= length; +} + +void arraylist_remove(ArrayList *arraylist, int index) +{ + arraylist_remove_range(arraylist, index, 1); +} + +int arraylist_index_of(ArrayList *arraylist, + ArrayListEqualFunc callback, + ArrayListValue data) +{ + int i; + + for (i=0; i<arraylist->length; ++i) { + if (callback(arraylist->data[i], data) != 0) + return i; + } + + return -1; +} + +void arraylist_clear(ArrayList *arraylist) +{ + /* To clear the list, simply set the length to zero */ + + arraylist->length = 0; +} + +static void arraylist_sort_internal(ArrayListValue *list_data, int list_length, + ArrayListCompareFunc compare_func) +{ + ArrayListValue pivot; + ArrayListValue tmp; + int i; + int list1_length; + int list2_length; + + /* If less than two items, it is always sorted. */ + + if (list_length <= 1) { + return; + } + + /* Take the last item as the pivot. */ + + pivot = list_data[list_length-1]; + + /* Divide the list into two lists: + * + * List 1 contains data less than the pivot. + * List 2 contains data more than the pivot. + * + * As the lists are build up, they are stored sequentially after + * each other, ie. list_data[list1_length-1] is the last item + * in list 1, list_data[list1_length] is the first item in + * list 2. + */ + + list1_length = 0; + + for (i=0; i<list_length-1; ++i) { + + if (compare_func(list_data[i], pivot) < 0) { + + /* This should be in list 1. Therefore it is in the wrong + * position. Swap the data immediately following the last + * item in list 1 with this data. */ + + tmp = list_data[i]; + list_data[i] = list_data[list1_length]; + list_data[list1_length] = tmp; + + ++list1_length; + + } else { + /* This should be in list 2. This is already in the right + * position. */ + } + } + + /* The length of list 2 can be calculated. */ + + list2_length = list_length - list1_length - 1; + + /* list_data[0..list1_length-1] now contains all items which are + * before the pivot. + * list_data[list1_length..list_length-2] contains all items after + * or equal to the pivot. */ + + /* Move the pivot into place, by swapping it with the item + * immediately following the end of list 1. */ + + list_data[list_length-1] = list_data[list1_length]; + list_data[list1_length] = pivot; + + /* Recursively sort the sublists. */ + + arraylist_sort_internal(list_data, list1_length, compare_func); + + arraylist_sort_internal(&list_data[list1_length + 1], list2_length, + compare_func); +} + +void arraylist_sort(ArrayList *arraylist, ArrayListCompareFunc compare_func) +{ + /* Perform the recursive sort */ + + arraylist_sort_internal(arraylist->data, arraylist->length, compare_func); +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/avl-tree.c b/EDM/athena/Control/CxxUtils/src/libcalg/avl-tree.c new file mode 100644 index 00000000..b6fa0d63 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/avl-tree.c @@ -0,0 +1,630 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> + +#include "CxxUtils/libcalg/avl-tree.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +/* AVL Tree (balanced binary search tree) */ + +struct _AVLTreeNode { + AVLTreeNode *children[2]; + AVLTreeNode *parent; + AVLTreeKey key; + AVLTreeValue value; + int height; +}; + +struct _AVLTree { + AVLTreeNode *root_node; + AVLTreeCompareFunc compare_func; + int num_nodes; +}; + +AVLTree *avl_tree_new(AVLTreeCompareFunc compare_func) +{ + AVLTree *new_tree; + + new_tree = (AVLTree *) malloc(sizeof(AVLTree)); + + if (new_tree == NULL) { + return NULL; + } + + new_tree->root_node = NULL; + new_tree->compare_func = compare_func; + new_tree->num_nodes = 0; + + return new_tree; +} + +static void avl_tree_free_subtree(AVLTree *tree, AVLTreeNode *node) +{ + if (node == NULL) { + return; + } + + avl_tree_free_subtree(tree, node->children[AVL_TREE_NODE_LEFT]); + avl_tree_free_subtree(tree, node->children[AVL_TREE_NODE_RIGHT]); + + free(node); +} + +void avl_tree_free(AVLTree *tree) +{ + /* Destroy all nodes */ + + avl_tree_free_subtree(tree, tree->root_node); + + /* Free back the main tree data structure */ + + free(tree); +} + +int avl_tree_subtree_height(AVLTreeNode *node) +{ + if (node == NULL) { + return 0; + } else { + return node->height; + } +} + +/* Update the "height" variable of a node, from the heights of its + * children. This does not update the height variable of any parent + * nodes. */ + +static void avl_tree_update_height(AVLTreeNode *node) +{ + AVLTreeNode *left_subtree; + AVLTreeNode *right_subtree; + int left_height, right_height; + + left_subtree = node->children[AVL_TREE_NODE_LEFT]; + right_subtree = node->children[AVL_TREE_NODE_RIGHT]; + left_height = avl_tree_subtree_height(left_subtree); + right_height = avl_tree_subtree_height(right_subtree); + + if (left_height > right_height) { + node->height = left_height + 1; + } else { + node->height = right_height + 1; + } +} + +/* Find what side a node is relative to its parent */ + +static AVLTreeNodeSide avl_tree_node_parent_side(AVLTreeNode *node) +{ + if (node->parent->children[AVL_TREE_NODE_LEFT] == node) { + return AVL_TREE_NODE_LEFT; + } else { + return AVL_TREE_NODE_RIGHT; + } +} + +/* Replace node1 with node2 at its parent. */ + +static void avl_tree_node_replace(AVLTree *tree, AVLTreeNode *node1, + AVLTreeNode *node2) +{ + int side; + + /* Set the node's parent pointer. */ + + if (node2 != NULL) { + node2->parent = node1->parent; + } + + /* The root node? */ + + if (node1->parent == NULL) { + tree->root_node = node2; + } else { + side = avl_tree_node_parent_side(node1); + node1->parent->children[side] = node2; + + avl_tree_update_height(node1->parent); + } +} + +/* Rotate a section of the tree. 'node' is the node at the top + * of the section to be rotated. 'direction' is the direction in + * which to rotate the tree: left or right, as shown in the following + * diagram: + * + * Left rotation: Right rotation: + * + * B D + * / \ / \ + * A D B E + * / \ / \ + * C E A C + + * is rotated to: is rotated to: + * + * D B + * / \ / \ + * B E A D + * / \ / \ + * A C C E + */ + +static AVLTreeNode *avl_tree_rotate(AVLTree *tree, AVLTreeNode *node, + AVLTreeNodeSide direction) +{ + AVLTreeNode *new_root; + + /* The child of this node will take its place: + for a left rotation, it is the right child, and vice versa. */ + + new_root = node->children[1-direction]; + + /* Make new_root the root, update parent pointers. */ + + avl_tree_node_replace(tree, node, new_root); + + /* Rearrange pointers */ + + node->children[1-direction] = new_root->children[direction]; + new_root->children[direction] = node; + + /* Update parent references */ + + node->parent = new_root; + + if (node->children[1-direction] != NULL) { + node->children[1-direction]->parent = node; + } + + /* Update heights of the affected nodes */ + + avl_tree_update_height(new_root); + avl_tree_update_height(node); + + return new_root; +} + + +/* Balance a particular tree node. + * + * Returns the root node of the new subtree which is replacing the + * old one. */ + +static AVLTreeNode *avl_tree_node_balance(AVLTree *tree, AVLTreeNode *node) +{ + AVLTreeNode *left_subtree; + AVLTreeNode *right_subtree; + AVLTreeNode *child; + int diff; + + left_subtree = node->children[AVL_TREE_NODE_LEFT]; + right_subtree = node->children[AVL_TREE_NODE_RIGHT]; + + /* Check the heights of the child trees. If there is an unbalance + * (difference between left and right > 2), then rotate nodes + * around to fix it */ + + diff = avl_tree_subtree_height(right_subtree) + - avl_tree_subtree_height(left_subtree); + + if (diff >= 2) { + + /* Biased toward the right side too much. */ + + child = right_subtree; + + if (avl_tree_subtree_height(child->children[AVL_TREE_NODE_RIGHT]) + < avl_tree_subtree_height(child->children[AVL_TREE_NODE_LEFT])) { + + /* If the right child is biased toward the left + * side, it must be rotated right first (double + * rotation) */ + + avl_tree_rotate(tree, right_subtree, + AVL_TREE_NODE_RIGHT); + } + + /* Perform a left rotation. After this, the right child will + * take the place of this node. Update the node pointer. */ + + node = avl_tree_rotate(tree, node, AVL_TREE_NODE_LEFT); + + } else if (diff <= -2) { + + /* Biased toward the left side too much. */ + + child = node->children[AVL_TREE_NODE_LEFT]; + + if (avl_tree_subtree_height(child->children[AVL_TREE_NODE_LEFT]) + < avl_tree_subtree_height(child->children[AVL_TREE_NODE_RIGHT])) { + + /* If the left child is biased toward the right + * side, it must be rotated right left (double + * rotation) */ + + avl_tree_rotate(tree, left_subtree, + AVL_TREE_NODE_LEFT); + } + + /* Perform a right rotation. After this, the left child will + * take the place of this node. Update the node pointer. */ + + node = avl_tree_rotate(tree, node, AVL_TREE_NODE_RIGHT); + } + + /* Update the height of this node */ + + avl_tree_update_height(node); + + return node; +} + +/* Walk up the tree from the given node, performing any needed rotations */ + +static void avl_tree_balance_to_root(AVLTree *tree, AVLTreeNode *node) +{ + AVLTreeNode *rover; + + rover = node; + + while (rover != NULL) { + + /* Balance this node if necessary */ + + rover = avl_tree_node_balance(tree, rover); + + /* Go to this node's parent */ + + rover = rover->parent; + } +} + +AVLTreeNode *avl_tree_insert(AVLTree *tree, AVLTreeKey key, AVLTreeValue value) +{ + AVLTreeNode **rover; + AVLTreeNode *new_node; + AVLTreeNode *previous_node; + + /* Walk down the tree until we reach a NULL pointer */ + + rover = &tree->root_node; + previous_node = NULL; + + while (*rover != NULL) { + previous_node = *rover; + if (tree->compare_func(key, (*rover)->key) < 0) { + rover = &((*rover)->children[AVL_TREE_NODE_LEFT]); + } else { + rover = &((*rover)->children[AVL_TREE_NODE_RIGHT]); + } + } + + /* Create a new node. Use the last node visited as the parent link. */ + + new_node = (AVLTreeNode *) malloc(sizeof(AVLTreeNode)); + + if (new_node == NULL) { + return NULL; + } + + new_node->children[AVL_TREE_NODE_LEFT] = NULL; + new_node->children[AVL_TREE_NODE_RIGHT] = NULL; + new_node->parent = previous_node; + new_node->key = key; + new_node->value = value; + new_node->height = 1; + + /* Insert at the NULL pointer that was reached */ + + *rover = new_node; + + /* Rebalance the tree, starting from the previous node. */ + + avl_tree_balance_to_root(tree, previous_node); + + /* Keep track of the number of entries */ + + ++tree->num_nodes; + + return new_node; +} + +/* Find the nearest node to the given node, to replace it. + * The node returned is unlinked from the tree. + * Returns NULL if the node has no children. */ + +static AVLTreeNode *avl_tree_node_get_replacement(AVLTree *tree, + AVLTreeNode *node) +{ + AVLTreeNode *left_subtree; + AVLTreeNode *right_subtree; + AVLTreeNode *result; + AVLTreeNode *child; + int left_height, right_height; + int side; + + left_subtree = node->children[AVL_TREE_NODE_LEFT]; + right_subtree = node->children[AVL_TREE_NODE_RIGHT]; + + /* No children? */ + + if (left_subtree == NULL && right_subtree == NULL) { + return NULL; + } + + /* Pick a node from whichever subtree is taller. This helps to + * keep the tree balanced. */ + + left_height = avl_tree_subtree_height(left_subtree); + right_height = avl_tree_subtree_height(right_subtree); + + if (left_height < right_height) { + side = AVL_TREE_NODE_RIGHT; + } else { + side = AVL_TREE_NODE_LEFT; + } + + /* Search down the tree, back towards the center. */ + + result = node->children[side]; + + while (result->children[1-side] != NULL) { + result = result->children[1-side]; + } + + /* Unlink the result node, and hook in its remaining child + * (if it has one) to replace it. */ + + child = result->children[side]; + avl_tree_node_replace(tree, result, child); + + /* Update the subtree height for the result node's old parent. */ + + avl_tree_update_height(result->parent); + + return result; +} + +/* Remove a node from a tree */ + +void avl_tree_remove_node(AVLTree *tree, AVLTreeNode *node) +{ + AVLTreeNode *swap_node; + AVLTreeNode *balance_startpoint; + int i; + + /* The node to be removed must be swapped with an "adjacent" + * node, ie. one which has the closest key to this one. Find + * a node to swap with. */ + + swap_node = avl_tree_node_get_replacement(tree, node); + + if (swap_node == NULL) { + + /* This is a leaf node and has no children, therefore + * it can be immediately removed. */ + + /* Unlink this node from its parent. */ + + avl_tree_node_replace(tree, node, NULL); + + /* Start rebalancing from the parent of the original node */ + + balance_startpoint = node->parent; + + } else { + /* We will start rebalancing from the old parent of the + * swap node. Sometimes, the old parent is the node we + * are removing, in which case we must start rebalancing + * from the swap node. */ + + if (swap_node->parent == node) { + balance_startpoint = swap_node; + } else { + balance_startpoint = swap_node->parent; + } + + /* Copy references in the node into the swap node */ + + for (i=0; i<2; ++i) { + swap_node->children[i] = node->children[i]; + + if (swap_node->children[i] != NULL) { + swap_node->children[i]->parent = swap_node; + } + } + + swap_node->height = node->height; + + /* Link the parent's reference to this node */ + + avl_tree_node_replace(tree, node, swap_node); + } + + /* Destroy the node */ + + free(node); + + /* Keep track of the number of nodes */ + + --tree->num_nodes; + + /* Rebalance the tree */ + + avl_tree_balance_to_root(tree, balance_startpoint); +} + +/* Remove a node by key */ + +int avl_tree_remove(AVLTree *tree, AVLTreeKey key) +{ + AVLTreeNode *node; + + /* Find the node to remove */ + + node = avl_tree_lookup_node(tree, key); + + if (node == NULL) { + /* Not found in tree */ + + return 0; + } + + /* Remove the node */ + + avl_tree_remove_node(tree, node); + + return 1; +} + +AVLTreeNode *avl_tree_lookup_node(AVLTree *tree, AVLTreeKey key) +{ + AVLTreeNode *node; + int diff; + + /* Search down the tree and attempt to find the node which + * has the specified key */ + + node = tree->root_node; + + while (node != NULL) { + + diff = tree->compare_func(key, node->key); + + if (diff == 0) { + + /* Keys are equal: return this node */ + + return node; + + } else if (diff < 0) { + node = node->children[AVL_TREE_NODE_LEFT]; + } else { + node = node->children[AVL_TREE_NODE_RIGHT]; + } + } + + /* Not found */ + + return NULL; +} + +AVLTreeValue avl_tree_lookup(AVLTree *tree, AVLTreeKey key) +{ + AVLTreeNode *node; + + /* Find the node */ + + node = avl_tree_lookup_node(tree, key); + + if (node == NULL) { + return AVL_TREE_NULL; + } else { + return node->value; + } +} + +AVLTreeNode *avl_tree_root_node(AVLTree *tree) +{ + return tree->root_node; +} + +AVLTreeKey avl_tree_node_key(AVLTreeNode *node) +{ + return node->key; +} + +AVLTreeValue avl_tree_node_value(AVLTreeNode *node) +{ + return node->value; +} + +AVLTreeNode *avl_tree_node_child(AVLTreeNode *node, AVLTreeNodeSide side) +{ + if (side == AVL_TREE_NODE_LEFT || side == AVL_TREE_NODE_RIGHT) { + return node->children[side]; + } else { + return NULL; + } +} + +AVLTreeNode *avl_tree_node_parent(AVLTreeNode *node) +{ + return node->parent; +} + +int avl_tree_num_entries(AVLTree *tree) +{ + return tree->num_nodes; +} + +static void avl_tree_to_array_add_subtree(AVLTreeNode *subtree, + AVLTreeValue *array, + int *index) +{ + if (subtree == NULL) { + return; + } + + /* Add left subtree first */ + + avl_tree_to_array_add_subtree(subtree->children[AVL_TREE_NODE_LEFT], + array, index); + + /* Add this node */ + + array[*index] = subtree->key; + ++*index; + + /* Finally add right subtree */ + + avl_tree_to_array_add_subtree(subtree->children[AVL_TREE_NODE_RIGHT], + array, index); +} + +AVLTreeValue *avl_tree_to_array(AVLTree *tree) +{ + AVLTreeValue *array; + int index; + + /* Allocate the array */ + + array = malloc(sizeof(AVLTreeValue) * tree->num_nodes); + + if (array == NULL) { + return NULL; + } + + index = 0; + + /* Add all keys */ + + avl_tree_to_array_add_subtree(tree->root_node, array, &index); + + return array; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/binary-heap.c b/EDM/athena/Control/CxxUtils/src/libcalg/binary-heap.c new file mode 100644 index 00000000..a2561c72 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/binary-heap.c @@ -0,0 +1,232 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> + +#include "CxxUtils/libcalg/binary-heap.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +struct _BinaryHeap { + BinaryHeapType heap_type; + BinaryHeapValue *values; + int num_values; + int alloced_size; + BinaryHeapCompareFunc compare_func; +}; + +static int binary_heap_cmp(BinaryHeap *heap, BinaryHeapValue data1, BinaryHeapValue data2) +{ + if (heap->heap_type == BINARY_HEAP_TYPE_MIN) { + return heap->compare_func(data1, data2); + } else { + return -heap->compare_func(data1, data2); + } +} + +BinaryHeap *binary_heap_new(BinaryHeapType heap_type, + BinaryHeapCompareFunc compare_func) +{ + BinaryHeap *heap; + + heap = malloc(sizeof(BinaryHeap)); + + if (heap == NULL) { + return NULL; + } + + heap->heap_type = heap_type; + heap->num_values = 0; + heap->compare_func = compare_func; + + /* Initial size of 16 elements */ + + heap->alloced_size = 16; + heap->values = malloc(sizeof(BinaryHeapValue) * heap->alloced_size); + + if (heap->values == NULL) { + free(heap); + return NULL; + } + + return heap; +} + +void binary_heap_free(BinaryHeap *heap) +{ + free(heap->values); + free(heap); +} + +int binary_heap_insert(BinaryHeap *heap, BinaryHeapValue value) +{ + BinaryHeapValue *new_values; + int index; + int newsize; + int parent; + + /* Possibly realloc the heap to a larger size */ + + if (heap->num_values >= heap->alloced_size) { + + /* Double the table size */ + + newsize = heap->alloced_size * 2; + new_values = realloc(heap->values, sizeof(BinaryHeapValue) * newsize); + + if (new_values == NULL) { + return 0; + } + + heap->alloced_size = newsize; + heap->values = new_values; + } + + /* Add to the bottom of the heap and start from there */ + + index = heap->num_values; + ++heap->num_values; + + /* Percolate the value up to the top of the heap */ + + while (index > 0) { + + /* The parent index is found by halving the node index */ + + parent = (index - 1) / 2; + + /* Compare the node with its parent */ + + if (binary_heap_cmp(heap, heap->values[parent], value) < 0) { + + /* Ordered correctly - insertion is complete */ + + break; + + } else { + + /* Need to swap this node with its parent */ + + heap->values[index] = heap->values[parent]; + + /* Advance up to the parent */ + + index = parent; + } + } + + /* Save the new value in the final location */ + + heap->values[index] = value; + + return 1; +} + +BinaryHeapValue binary_heap_pop(BinaryHeap *heap) +{ + BinaryHeapValue result; + BinaryHeapValue new_value; + int index; + int next_index; + int child1, child2; + + /* Empty heap? */ + + if (heap->num_values == 0) { + return BINARY_HEAP_NULL; + } + + /* Take the value from the top of the heap */ + + result = heap->values[0]; + + /* Remove the last value from the heap; we will percolate this down + * from the top. */ + + new_value = heap->values[heap->num_values - 1]; + --heap->num_values; + + /* Percolate the new top value down */ + + index = 0; + + for (;;) { + + /* Calculate the array indexes of the children of this node */ + + child1 = index * 2 + 1; + child2 = index * 2 + 2; + + if (child1 < heap->num_values + && binary_heap_cmp(heap, + new_value, + heap->values[child1]) > 0) { + + /* Left child is less than the node. We need to swap + * with one of the children, whichever is less. */ + + if (child2 < heap->num_values + && binary_heap_cmp(heap, + heap->values[child1], + heap->values[child2]) > 0) { + next_index = child2; + } else { + next_index = child1; + } + + } else if (child2 < heap->num_values + && binary_heap_cmp(heap, + new_value, + heap->values[child2]) > 0) { + + /* Right child is less than the node. Swap with the + * right child. */ + + next_index = child2; + + } else { + /* Node is less than both its children. The heap condition + * is satisfied. We can stop percolating down. */ + + heap->values[index] = new_value; + break; + } + + /* Swap the current node with the least of the child nodes. */ + + heap->values[index] = heap->values[next_index]; + + /* Advance to the child we chose */ + + index = next_index; + } + + return result; +} + +int binary_heap_num_entries(BinaryHeap *heap) +{ + return heap->num_values; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/binomial-heap.c b/EDM/athena/Control/CxxUtils/src/libcalg/binomial-heap.c new file mode 100644 index 00000000..ca4ba92e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/binomial-heap.c @@ -0,0 +1,475 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> +#include <string.h> + +#include "CxxUtils/libcalg/binomial-heap.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +typedef struct _BinomialTree BinomialTree; + +struct _BinomialTree +{ + BinomialHeapValue value; + unsigned short order; + unsigned short refcount; + BinomialTree **subtrees; +}; + +struct _BinomialHeap +{ + BinomialHeapType heap_type; + BinomialHeapCompareFunc compare_func; + int num_values; + BinomialTree **roots; + int roots_length; +}; + +static int binomial_heap_cmp(BinomialHeap *heap, + BinomialHeapValue data1, + BinomialHeapValue data2) +{ + if (heap->heap_type == BINOMIAL_HEAP_TYPE_MIN) { + return heap->compare_func(data1, data2); + } else { + return -(heap->compare_func(data1, data2)); + } +} + +static void binomial_tree_ref(BinomialTree *tree) +{ + if (tree != NULL) { + ++tree->refcount; + } +} + +static void binomial_tree_unref(BinomialTree *tree) +{ + int i; + + if (tree == NULL) { + return; + } + + /* Subtract a reference */ + + --tree->refcount; + + /* If this removed the last reference, unreference all subtrees + * and free. */ + + if (tree->refcount == 0) { + + for (i=0; i<tree->order; ++i) { + binomial_tree_unref(tree->subtrees[i]); + } + + free(tree->subtrees); + free(tree); + } +} + +static BinomialTree *binomial_tree_merge(BinomialHeap *heap, + BinomialTree *tree1, + BinomialTree *tree2) +{ + BinomialTree *new_tree; + BinomialTree *tmp; + int i; + + /* Order tree1 and tree2 so that tree1 is the tree with the + * smallest root */ + + if (binomial_heap_cmp(heap, tree1->value, tree2->value) > 0) { + + /* Swap tree1 and tree2 */ + + tmp = tree1; + tree1 = tree2; + tree2 = tmp; + } + + /* Allocate a new tree */ + + new_tree = malloc(sizeof(BinomialTree)); + + if (new_tree == NULL) { + return NULL; + } + + new_tree->refcount = 0; + new_tree->order = tree1->order + 1; + + /* Take the smallest value of the two trees */ + + new_tree->value = tree1->value; + + /* Copy subtrees of the smallest tree. The last entry in the + * array is the larger tree */ + + new_tree->subtrees = malloc(sizeof(BinomialTree *) * new_tree->order); + + if (new_tree->subtrees == NULL) { + free(new_tree); + return NULL; + } + + memcpy(new_tree->subtrees, tree1->subtrees, + sizeof(BinomialTree *) * tree1->order); + new_tree->subtrees[new_tree->order - 1] = tree2; + + /* Add a reference to each of the subtrees we have referenced */ + + for (i=0; i<new_tree->order; ++i) { + binomial_tree_ref(new_tree->subtrees[i]); + } + + return new_tree; +} + +/* Used to perform an "undo" when an error occurs during + * binomial_heap_merge. Go through the list of roots so far and remove + * references that have been added. */ + +static void binomial_heap_merge_undo(BinomialTree **new_roots, int count) +{ + int i; + + for (i=0; i<=count; ++i) { + binomial_tree_unref(new_roots[i]); + } + + free(new_roots); +} + +/* Merge the data in the 'other' heap into the 'heap' heap. + * Returns non-zero if successful. */ + +static int binomial_heap_merge(BinomialHeap *heap, BinomialHeap *other) +{ + BinomialTree **new_roots; + int new_roots_length; + BinomialTree *vals[3]; + int num_vals; + BinomialTree *carry; + BinomialTree *new_carry; + int i; + int max; + + /* Find the maximum length of the two heaps. Add one because + * after merging we may have one more value to carry over. */ + + if (heap->roots_length > other->roots_length) { + max = heap->roots_length + 1; + } else { + max = other->roots_length + 1; + } + + /* Allocate an array for the new roots */ + + new_roots = malloc(sizeof(BinomialTree *) * max); + + if (new_roots == NULL) { + return 0; + } + + /* Go through one entry at a time. This works kind of like a + * ripple-carry adder. */ + + new_roots_length = 0; + carry = NULL; + + for (i=0; i<max; ++i) { + + /* Build up 'vals' as a list of all the values we must + * merge at this step. */ + + num_vals = 0; + + /* If there is a value in 'heap', add it */ + + if (i < heap->roots_length && heap->roots[i] != NULL) { + vals[num_vals] = heap->roots[i]; + ++num_vals; + } + + /* If there is a value in 'other', add it */ + + if (i < other->roots_length && other->roots[i] != NULL) { + vals[num_vals] = other->roots[i]; + ++num_vals; + } + + /* If there is a carried value from the previous iteration, + * add it */ + + if (carry != NULL) { + vals[num_vals] = carry; + ++num_vals; + } + + /* When num_vals == 1 or 3, we store a value. */ + + if ((num_vals & 1) != 0) { + + /* Save the last value into new_roots. */ + + new_roots[i] = vals[num_vals - 1]; + binomial_tree_ref(new_roots[i]); + new_roots_length = i + 1; + + } else { + + /* No value to store at this iteration */ + + new_roots[i] = NULL; + } + + /* When num_vals == 2 or 3, we must carry over to the + * next iteration */ + + if ((num_vals & 2) != 0) { + + /* Merge the first two values and carry to the + * next iteration */ + + new_carry = binomial_tree_merge(heap, + vals[0], + vals[1]); + + if (new_carry == NULL) { + + /* Remove references that we have added + * (freeing any BinomialTree structures + * that were created in the process) */ + + binomial_heap_merge_undo(new_roots, i); + + /* Unreference the carry variable */ + + binomial_tree_unref(carry); + + return 0; + } + + } else { + + /* Nothing to carry */ + + new_carry = NULL; + } + + /* Unreference previous carried value */ + + binomial_tree_unref(carry); + + /* Assign the new value of carry, and add a reference */ + + carry = new_carry; + + binomial_tree_ref(carry); + } + + /* Unreference all values in the old 'roots' array, freeing unused + * BinomialTree structures as necessary. */ + + for (i=0; i<heap->roots_length; ++i) { + if (heap->roots[i] != NULL) { + binomial_tree_unref(heap->roots[i]); + } + } + + /* Free the old roots array and use the new one */ + + free(heap->roots); + heap->roots = new_roots; + heap->roots_length = new_roots_length; + + /* Merged successfully */ + + return 1; +} + +BinomialHeap *binomial_heap_new(BinomialHeapType heap_type, + BinomialHeapCompareFunc compare_func) +{ + BinomialHeap *new_heap; + + /* Allocate a new heap */ + + new_heap = calloc(1, sizeof(BinomialHeap)); + + if (new_heap == NULL) { + return NULL; + } + + /* Initialise and return */ + + new_heap->heap_type = heap_type; + new_heap->compare_func = compare_func; + + return new_heap; +} + +void binomial_heap_free(BinomialHeap *heap) +{ + int i; + + /* Unreference all trees in the heap. This should free + * back all subtrees. */ + + for (i=0; i<heap->roots_length; ++i) { + binomial_tree_unref(heap->roots[i]); + } + + /* Free the heap itself */ + + free(heap->roots); + free(heap); +} + +int binomial_heap_insert(BinomialHeap *heap, BinomialHeapValue value) +{ + BinomialHeap fake_heap; + BinomialTree *new_tree; + int result; + + /* Allocate an order 0 tree for storing the new value */ + + new_tree = malloc(sizeof(BinomialTree)); + + if (new_tree == NULL) { + return 0; + } + + /* Fill in values. This has an initial reference count of 1 that + * the "fake" heap holds; this will be removed at the end of + * this function. */ + + new_tree->value = value; + new_tree->order = 0; + new_tree->refcount = 1; + new_tree->subtrees = NULL; + + /* Build a fake heap structure for merging */ + + fake_heap.heap_type = heap->heap_type; + fake_heap.compare_func = heap->compare_func; + fake_heap.num_values = 1; + fake_heap.roots = &new_tree; + fake_heap.roots_length = 1; + + /* Perform the merge */ + + result = binomial_heap_merge(heap, &fake_heap); + + if (result != 0) { + ++heap->num_values; + } + + /* Remove reference to the new tree. */ + + binomial_tree_unref(new_tree); + + return result; +} + +BinomialHeapValue binomial_heap_pop(BinomialHeap *heap) +{ + BinomialTree *least_tree; + BinomialHeap fake_heap; + BinomialHeapValue result; + int least; + int i; + + if (heap->num_values == 0) { + return BINOMIAL_HEAP_NULL; + } + + /* Find the tree with the lowest root value */ + + least = -1; + + for (i=0; i<heap->roots_length; ++i) { + + if (heap->roots[i] == NULL) { + continue; + } + + if (least < 0 + || binomial_heap_cmp(heap, + heap->roots[i]->value, + heap->roots[least]->value) < 0) { + least = i; + } + } + + /* Remove the least_tree from the heap. */ + + least_tree = heap->roots[least]; + heap->roots[least] = NULL; + + /* Construct a fake heap containing the data in the least tree */ + + fake_heap.heap_type = heap->heap_type; + fake_heap.compare_func = heap->compare_func; + fake_heap.roots = least_tree->subtrees; + fake_heap.roots_length = least_tree->order; + + /* Merge subtrees of least tree back into the heap */ + + if (binomial_heap_merge(heap, &fake_heap)) { + + /* Merge successful */ + + /* Remove reference to least tree */ + + result = least_tree->value; + binomial_tree_unref(least_tree); + + /* Update the number of values */ + + --heap->num_values; + + return result; + + } else { + + /* Add the least tree back */ + + heap->roots[least] = least_tree; + + /* Pop failed */ + + return BINOMIAL_HEAP_NULL; + } +} + +int binomial_heap_num_entries(BinomialHeap *heap) +{ + return heap->num_values; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/bloom-filter.c b/EDM/athena/Control/CxxUtils/src/libcalg/bloom-filter.c new file mode 100644 index 00000000..04743579 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/bloom-filter.c @@ -0,0 +1,290 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> +#include <string.h> + +#include "CxxUtils/libcalg/bloom-filter.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +struct _BloomFilter { + BloomFilterHashFunc hash_func; + unsigned char *table; + unsigned int table_size; + unsigned int num_functions; +}; + +/* Salt values. These salts are XORed with the output of the hash + * function to give multiple unique hashes. */ + +static const unsigned int salts[] = { + 0x5cee4612, 0xb5587b1c, 0xa250f2b0, 0xa3bf6d2a, + 0x7a81bd1a, 0x92888d7f, 0x1dc977c7, 0xedc96624, + 0x920c85d9, 0xf16066b3, 0xc6f0d4b3, 0x2b76eb86, + 0xcacb3893, 0x493d81c5, 0xf5a133ac, 0x039740bf, + 0x162b8224, 0xf841de90, 0xc3e5090d, 0x3bce93a7, + 0xf1860334, 0xe832b5f1, 0xf5b6535b, 0xe4cf4fa6, + 0x8357b769, 0x1442b07a, 0x21c5863d, 0xabc0d846, + 0x6dc0d77a, 0x23a3992c, 0xe12179ba, 0xd81d1e23, + 0xcff4727b, 0xe957ecfb, 0xee8f391a, 0x426efa23, + 0x3a34ff2c, 0x8b875d94, 0x34fd0f63, 0xf159daae, + 0xaabab8b3, 0xa83a07ba, 0x4e54fb33, 0xfb82fab8, + 0x2ae2888f, 0xd1a307a8, 0xbe33322d, 0x87c73f86, + 0x7270fa7e, 0x68673c55, 0x2c8026d0, 0xead8e422, + 0xa3ee5132, 0xecb67767, 0x1c3b1ae5, 0x47adf5b6, + 0xf4518d30, 0x46e62797, 0x9889aa76, 0x1405aadf, + 0xf62f9124, 0x5c435ac5, 0x35b8dfe3, 0x651c08c5, +}; + +BloomFilter *bloom_filter_new(unsigned int table_size, + BloomFilterHashFunc hash_func, + unsigned int num_functions) +{ + BloomFilter *filter; + + /* There is a limit on the number of functions which can be + * applied, due to the table size */ + + if (num_functions > sizeof(salts) / sizeof(*salts)) { + return NULL; + } + + /* Allocate bloom filter structure */ + + filter = malloc(sizeof(BloomFilter)); + + if (filter == NULL) { + return NULL; + } + + /* Allocate table, each entry is one bit; these are packed into + * bytes. When allocating we must round the length up to the nearest + * byte. */ + + filter->table = calloc((table_size + 7) / 8, 1); + + if (filter->table == NULL) { + free(filter); + return NULL; + } + + filter->hash_func = hash_func; + filter->num_functions = num_functions; + filter->table_size = table_size; + + return filter; +} + +void bloom_filter_free(BloomFilter *bloomfilter) +{ + free(bloomfilter->table); + free(bloomfilter); +} + +void bloom_filter_insert(BloomFilter *bloomfilter, BloomFilterValue value) +{ + unsigned long hash; + unsigned long subhash; + unsigned int index; + unsigned int i; + + /* Generate hash of the value to insert */ + + hash = bloomfilter->hash_func(value); + + /* Generate multiple unique hashes by XORing with values in the + * salt table. */ + + for (i=0; i<bloomfilter->num_functions; ++i) { + + /* Generate a unique hash */ + + subhash = hash ^ salts[i]; + + /* Find the index into the table */ + + index = subhash % bloomfilter->table_size; + + /* Insert into the table. + * index / 8 finds the byte index of the table, + * index % 8 gives the bit index within that byte to set. */ + + bloomfilter->table[index / 8] |= 1 << (index % 8); + } +} + +int bloom_filter_query(BloomFilter *bloomfilter, BloomFilterValue value) +{ + unsigned long hash; + unsigned long subhash; + unsigned int index; + unsigned int i; + unsigned char b; + int bit; + + /* Generate hash of the value to lookup */ + + hash = bloomfilter->hash_func(value); + + /* Generate multiple unique hashes by XORing with values in the + * salt table. */ + + for (i=0; i<bloomfilter->num_functions; ++i) { + + /* Generate a unique hash */ + + subhash = hash ^ salts[i]; + + /* Find the index into the table to test */ + + index = subhash % bloomfilter->table_size; + + /* The byte at index / 8 holds the value to test */ + + b = bloomfilter->table[index / 8]; + bit = 1 << (index % 8); + + /* Test if the particular bit is set; if it is not set, + * this value can not have been inserted. */ + + if ((b & bit) == 0) { + return 0; + } + } + + /* All necessary bits were set. This may indicate that the value + * was inserted, or the values could have been set through other + * insertions. */ + + return 1; +} + +void bloom_filter_read(BloomFilter *bloomfilter, unsigned char *array) +{ + unsigned int array_size; + + /* The table is an array of bits, packed into bytes. Round up + * to the nearest byte. */ + + array_size = (bloomfilter->table_size + 7) / 8; + + /* Copy into the buffer of the calling routine. */ + + memcpy(array, bloomfilter->table, array_size); +} + +void bloom_filter_load(BloomFilter *bloomfilter, unsigned char *array) +{ + unsigned int array_size; + + /* The table is an array of bits, packed into bytes. Round up + * to the nearest byte. */ + + array_size = (bloomfilter->table_size + 7) / 8; + + /* Copy from the buffer of the calling routine. */ + + memcpy(bloomfilter->table, array, array_size); +} + +BloomFilter *bloom_filter_union(BloomFilter *filter1, BloomFilter *filter2) +{ + BloomFilter *result; + unsigned int i; + unsigned int array_size; + + /* To perform this operation, both filters must be created with + * the same values. */ + + if (filter1->table_size != filter2->table_size + || filter1->num_functions != filter2->num_functions + || filter1->hash_func != filter2->hash_func) { + return NULL; + } + + /* Create a new bloom filter for the result */ + + result = bloom_filter_new(filter1->table_size, + filter1->hash_func, + filter1->num_functions); + + if (result == NULL) { + return NULL; + } + + /* The table is an array of bits, packed into bytes. Round up + * to the nearest byte. */ + + array_size = (filter1->table_size + 7) / 8; + + /* Populate the table of the new filter */ + + for (i=0; i<array_size; ++i) { + result->table[i] = filter1->table[i] | filter2->table[i]; + } + + return result; +} + +BloomFilter *bloom_filter_intersection(BloomFilter *filter1, + BloomFilter *filter2) +{ + BloomFilter *result; + unsigned int i; + unsigned int array_size; + + /* To perform this operation, both filters must be created with + * the same values. */ + + if (filter1->table_size != filter2->table_size + || filter1->num_functions != filter2->num_functions + || filter1->hash_func != filter2->hash_func) { + return NULL; + } + + /* Create a new bloom filter for the result */ + + result = bloom_filter_new(filter1->table_size, + filter1->hash_func, + filter1->num_functions); + + if (result == NULL) { + return NULL; + } + + /* The table is an array of bits, packed into bytes. Round up + * to the nearest byte. */ + + array_size = (filter1->table_size + 7) / 8; + + /* Populate the table of the new filter */ + + for (i=0; i<array_size; ++i) { + result->table[i] = filter1->table[i] & filter2->table[i]; + } + + return result; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/compare-int.c b/EDM/athena/Control/CxxUtils/src/libcalg/compare-int.c new file mode 100644 index 00000000..3a10705a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/compare-int.c @@ -0,0 +1,53 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include "CxxUtils/libcalg/compare-int.h" + +/* Comparison functions for a pointer to an integer */ + +int int_equal(void *vlocation1, void *vlocation2) +{ + int *location1; + int *location2; + + location1 = (int *) vlocation1; + location2 = (int *) vlocation2; + + return *location1 == *location2; +} + +int int_compare(void *vlocation1, void *vlocation2) +{ + int *location1; + int *location2; + + location1 = (int *) vlocation1; + location2 = (int *) vlocation2; + + if (*location1 < *location2) { + return -1; + } else if (*location1 > *location2) { + return 1; + } else { + return 0; + } +} + + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/compare-pointer.c b/EDM/athena/Control/CxxUtils/src/libcalg/compare-pointer.c new file mode 100644 index 00000000..f8bd24d8 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/compare-pointer.c @@ -0,0 +1,41 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include "CxxUtils/libcalg/compare-pointer.h" + +/* Comparison functions for a generic void pointer */ + +int pointer_equal(void *location1, void *location2) +{ + return location1 == location2; +} + +int pointer_compare(void *location1, void *location2) +{ + if (location1 < location2) { + return -1; + } else if (location1 > location2) { + return 1; + } else { + return 0; + } +} + + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/compare-string.c b/EDM/athena/Control/CxxUtils/src/libcalg/compare-string.c new file mode 100644 index 00000000..e8fc10cd --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/compare-string.c @@ -0,0 +1,103 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "CxxUtils/libcalg/compare-string.h" + +/* Comparison functions for strings */ + +int string_equal(void *string1, void *string2) +{ + return strcmp((char *) string1, (char *) string2) == 0; +} + +int string_compare(void *string1, void *string2) +{ + int result; + + result = strcmp((char *) string1, (char *) string2); + + if (result < 0) { + return -1; + } else if (result > 0) { + return 1; + } else { + return 0; + } +} + +/* Comparison functions for strings, which ignore the case of letters. */ + +int string_nocase_equal(void *string1, void *string2) +{ + return string_nocase_compare((char *) string1, (char *) string2) == 0; +} + +/* On many systems, strcasecmp or stricmp will give the same functionality + * as this function. However, it is non-standard and cannot be relied + * on to be present. */ + +int string_nocase_compare(void *string1, void *string2) +{ + char *p1; + char *p2; + int c1, c2; + + /* Iterate over each character in the strings */ + + p1 = (char *) string1; + p2 = (char *) string2; + + for (;;) { + + c1 = tolower(*p1); + c2 = tolower(*p2); + + if (c1 != c2) { + + /* Strings are different */ + + if (c1 < c2) { + return -1; + } else { + return 1; + } + } + + /* End of string */ + + if (c1 == '\0') + break; + + /* Advance to the next character */ + + ++p1; + ++p2; + } + + /* Reached the end of string and no difference found */ + + return 0; +} + + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/hash-int.c b/EDM/athena/Control/CxxUtils/src/libcalg/hash-int.c new file mode 100644 index 00000000..f9818862 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/hash-int.c @@ -0,0 +1,33 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include "CxxUtils/libcalg/hash-int.h" + +/* Hash function for a pointer to an integer */ + +unsigned long int_hash(void *vlocation) +{ + int *location; + + location = (int *) vlocation; + + return (unsigned long) *location; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/hash-pointer.c b/EDM/athena/Control/CxxUtils/src/libcalg/hash-pointer.c new file mode 100644 index 00000000..079db66f --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/hash-pointer.c @@ -0,0 +1,29 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include "CxxUtils/libcalg/hash-pointer.h" + +/* Hash function for a generic pointer */ + +unsigned long pointer_hash(void *location) +{ + return (unsigned long) location; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/hash-string.c b/EDM/athena/Control/CxxUtils/src/libcalg/hash-string.c new file mode 100644 index 00000000..db6c5f47 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/hash-string.c @@ -0,0 +1,61 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <ctype.h> + +#include "CxxUtils/libcalg/hash-string.h" + +/* String hash function */ + +unsigned long string_hash(void *string) +{ + /* This is the djb2 string hash function */ + + unsigned long result = 5381; + unsigned char *p; + + p = (unsigned char *) string; + + while (*p != '\0') { + result = ((result << 5) ^ result ) ^ (*p); + ++p; + } + + return result; +} + +/* The same function, with a tolower on every character so that + * case is ignored. This code is duplicated for performance. */ + +unsigned long string_nocase_hash(void *string) +{ + unsigned long result = 5381; + unsigned char *p; + + p = (unsigned char *) string; + + while (*p != '\0') { + result = ((result << 5) ^ result ) ^ tolower(*p); + ++p; + } + + return result; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/hash-table.c b/EDM/athena/Control/CxxUtils/src/libcalg/hash-table.c new file mode 100644 index 00000000..364755e6 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/hash-table.c @@ -0,0 +1,498 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/* Hash table implementation */ + +#include <stdlib.h> +#include <string.h> + +#include "CxxUtils/libcalg/hash-table.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +struct _HashTableEntry { + HashTableKey key; + HashTableValue value; + HashTableEntry *next; +}; + +struct _HashTable { + HashTableEntry **table; + int table_size; + HashTableHashFunc hash_func; + HashTableEqualFunc equal_func; + HashTableKeyFreeFunc key_free_func; + HashTableValueFreeFunc value_free_func; + int entries; + int prime_index; +}; + +/* This is a set of good hash table prime numbers, from: + * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html + * Each prime is roughly double the previous value, and as far as + * possible from the nearest powers of two. */ + +static const unsigned int hash_table_primes[] = { + 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, + 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843, 50331653, 100663319, 201326611, + 402653189, 805306457, 1610612741, +}; + +static const int hash_table_num_primes + = sizeof(hash_table_primes) / sizeof(int); + +/* Internal function used to allocate the table on hash table creation + * and when enlarging the table */ + +static int hash_table_allocate_table(HashTable *hash_table) +{ + int new_table_size; + + /* Determine the table size based on the current prime index. + * An attempt is made here to ensure sensible behavior if the + * maximum prime is exceeded, but in practice other things are + * likely to break long before that happens. */ + + if (hash_table->prime_index < hash_table_num_primes) { + new_table_size = hash_table_primes[hash_table->prime_index]; + } else { + new_table_size = hash_table->entries * 10; + } + + hash_table->table_size = new_table_size; + + /* Allocate the table and initialise to NULL for all entries */ + + hash_table->table = calloc(hash_table->table_size, + sizeof(HashTableEntry *)); + + return hash_table->table != NULL; +} + +/* Free an entry, calling the free functions if there are any registered */ + +static void hash_table_free_entry(HashTable *hash_table, HashTableEntry *entry) +{ + /* If there is a function registered for freeing keys, use it to free + * the key */ + + if (hash_table->key_free_func != NULL) { + hash_table->key_free_func(entry->key); + } + + /* Likewise with the value */ + + if (hash_table->value_free_func != NULL) { + hash_table->value_free_func(entry->value); + } + + /* Free the data structure */ + + free(entry); +} + +HashTable *hash_table_new(HashTableHashFunc hash_func, + HashTableEqualFunc equal_func) +{ + HashTable *hash_table; + + /* Allocate a new hash table structure */ + + hash_table = (HashTable *) malloc(sizeof(HashTable)); + + if (hash_table == NULL) { + return NULL; + } + + hash_table->hash_func = hash_func; + hash_table->equal_func = equal_func; + hash_table->key_free_func = NULL; + hash_table->value_free_func = NULL; + hash_table->entries = 0; + hash_table->prime_index = 0; + + /* Allocate the table */ + + if (!hash_table_allocate_table(hash_table)) { + free(hash_table); + + return NULL; + } + + return hash_table; +} + +void hash_table_free(HashTable *hash_table) +{ + HashTableEntry *rover; + HashTableEntry *next; + int i; + + /* Free all entries in all chains */ + + for (i=0; i<hash_table->table_size; ++i) { + rover = hash_table->table[i]; + while (rover != NULL) { + next = rover->next; + hash_table_free_entry(hash_table, rover); + rover = next; + } + } + + /* Free the table */ + + free(hash_table->table); + + /* Free the hash table structure */ + + free(hash_table); +} + +void hash_table_register_free_functions(HashTable *hash_table, + HashTableKeyFreeFunc key_free_func, + HashTableValueFreeFunc value_free_func) +{ + hash_table->key_free_func = key_free_func; + hash_table->value_free_func = value_free_func; +} + + +static int hash_table_enlarge(HashTable *hash_table) +{ + HashTableEntry **old_table; + int old_table_size; + int old_prime_index; + HashTableEntry *rover; + HashTableEntry *next; + int index; + int i; + + /* Store a copy of the old table */ + + old_table = hash_table->table; + old_table_size = hash_table->table_size; + old_prime_index = hash_table->prime_index; + + /* Allocate a new, larger table */ + + ++hash_table->prime_index; + + if (!hash_table_allocate_table(hash_table)) { + + /* Failed to allocate the new table */ + + hash_table->table = old_table; + hash_table->table_size = old_table_size; + hash_table->prime_index = old_prime_index; + + return 0; + } + + /* Link all entries from all chains into the new table */ + + for (i=0; i<old_table_size; ++i) { + rover = old_table[i]; + + while (rover != NULL) { + next = rover->next; + + /* Find the index into the new table */ + + index = hash_table->hash_func(rover->key) % hash_table->table_size; + + /* Link this entry into the chain */ + + rover->next = hash_table->table[index]; + hash_table->table[index] = rover; + + /* Advance to next in the chain */ + + rover = next; + } + } + + /* Free the old table */ + + free(old_table); + + return 1; +} + +int hash_table_insert(HashTable *hash_table, HashTableKey key, HashTableValue value) +{ + HashTableEntry *rover; + HashTableEntry *newentry; + int index; + + /* If there are too many items in the table with respect to the table + * size, the number of hash collisions increases and performance + * decreases. Enlarge the table size to prevent this happening */ + + if ((hash_table->entries * 3) / hash_table->table_size > 0) { + + /* Table is more than 1/3 full */ + + if (!hash_table_enlarge(hash_table)) { + + /* Failed to enlarge the table */ + + return 0; + } + } + + /* Generate the hash of the key and hence the index into the table */ + + index = hash_table->hash_func(key) % hash_table->table_size; + + /* Traverse the chain at this location and look for an existing + * entry with the same key */ + + rover = hash_table->table[index]; + + while (rover != NULL) { + if (hash_table->equal_func(rover->key, key) != 0) { + + /* Same key: overwrite this entry with new data */ + + /* If there is a value free function, free the old data + * before adding in the new data */ + + if (hash_table->value_free_func != NULL) { + hash_table->value_free_func(rover->value); + } + + /* Same with the key: use the new key value and free + * the old one */ + + if (hash_table->key_free_func != NULL) { + hash_table->key_free_func(rover->key); + } + + rover->key = key; + rover->value = value; + + /* Finished */ + + return 1; + } + rover = rover->next; + } + + /* Not in the hash table yet. Create a new entry */ + + newentry = (HashTableEntry *) malloc(sizeof(HashTableEntry)); + + if (newentry == NULL) { + return 0; + } + + newentry->key = key; + newentry->value = value; + + /* Link into the list */ + + newentry->next = hash_table->table[index]; + hash_table->table[index] = newentry; + + /* Maintain the count of the number of entries */ + + ++hash_table->entries; + + /* Added successfully */ + + return 1; +} + +HashTableValue hash_table_lookup(HashTable *hash_table, HashTableKey key) +{ + HashTableEntry *rover; + int index; + + /* Generate the hash of the key and hence the index into the table */ + + index = hash_table->hash_func(key) % hash_table->table_size; + + /* Walk the chain at this index until the corresponding entry is + * found */ + + rover = hash_table->table[index]; + + while (rover != NULL) { + if (hash_table->equal_func(key, rover->key) != 0) { + + /* Found the entry. Return the data. */ + + return rover->value; + } + rover = rover->next; + } + + /* Not found */ + + return HASH_TABLE_NULL; +} + +int hash_table_remove(HashTable *hash_table, HashTableKey key) +{ + HashTableEntry **rover; + HashTableEntry *entry; + int index; + int result; + + /* Generate the hash of the key and hence the index into the table */ + + index = hash_table->hash_func(key) % hash_table->table_size; + + /* Rover points at the pointer which points at the current entry + * in the chain being inspected. ie. the entry in the table, or + * the "next" pointer of the previous entry in the chain. This + * allows us to unlink the entry when we find it. */ + + result = 0; + rover = &hash_table->table[index]; + + while (*rover != NULL) { + + if (hash_table->equal_func(key, (*rover)->key) != 0) { + + /* This is the entry to remove */ + + entry = *rover; + + /* Unlink from the list */ + + *rover = entry->next; + + /* Destroy the entry structure */ + + hash_table_free_entry(hash_table, entry); + + /* Track count of entries */ + + --hash_table->entries; + + result = 1; + + break; + } + + /* Advance to the next entry */ + + rover = &((*rover)->next); + } + + return result; +} + +int hash_table_num_entries(HashTable *hash_table) +{ + return hash_table->entries; +} + +void hash_table_iterate(HashTable *hash_table, HashTableIterator *iterator) +{ + int chain; + + iterator->hash_table = hash_table; + + /* Default value of next if no entries are found. */ + + iterator->next_entry = NULL; + + /* Find the first entry */ + + for (chain=0; chain<hash_table->table_size; ++chain) { + + if (hash_table->table[chain] != NULL) { + iterator->next_entry = hash_table->table[chain]; + iterator->next_chain = chain; + break; + } + } +} + +int hash_table_iter_has_more(HashTableIterator *iterator) +{ + return iterator->next_entry != NULL; +} + +HashTableValue hash_table_iter_next(HashTableIterator *iterator) +{ + HashTableEntry *current_entry; + HashTable *hash_table; + HashTableValue result; + int chain; + + hash_table = iterator->hash_table; + + /* No more entries? */ + + if (iterator->next_entry == NULL) { + return HASH_TABLE_NULL; + } + + /* Result is immediately available */ + + current_entry = iterator->next_entry; + result = current_entry->value; + + /* Find the next entry */ + + if (current_entry->next != NULL) { + + /* Next entry in current chain */ + + iterator->next_entry = current_entry->next; + + } else { + + /* None left in this chain, so advance to the next chain */ + + chain = iterator->next_chain + 1; + + /* Default value if no next chain found */ + + iterator->next_entry = NULL; + + while (chain < hash_table->table_size) { + + /* Is there anything in this chain? */ + + if (hash_table->table[chain] != NULL) { + iterator->next_entry = hash_table->table[chain]; + break; + } + + /* Try the next chain */ + + ++chain; + } + + iterator->next_chain = chain; + } + + return result; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/list.c b/EDM/athena/Control/CxxUtils/src/libcalg/list.c new file mode 100644 index 00000000..d287cc02 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/list.c @@ -0,0 +1,542 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> + +#include "CxxUtils/libcalg/list.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +/* A doubly-linked list */ + +struct _ListEntry { + ListValue data; + ListEntry *prev; + ListEntry *next; +}; + +void list_free(ListEntry *list) +{ + ListEntry *entry; + + /* Iterate over each entry, freeing each list entry, until the + * end is reached */ + + entry = list; + + while (entry != NULL) { + ListEntry *next; + + next = entry->next; + + free(entry); + + entry = next; + } +} + +ListEntry *list_prepend(ListEntry **list, ListValue data) +{ + ListEntry *newentry; + + /* Create new entry */ + + newentry = malloc(sizeof(ListEntry)); + + if (newentry == NULL) { + return NULL; + } + + newentry->data = data; + + /* Hook into the list start */ + + if (*list != NULL) { + (*list)->prev = newentry; + } + newentry->prev = NULL; + newentry->next = *list; + *list = newentry; + + return newentry; +} + +ListEntry *list_append(ListEntry **list, ListValue data) +{ + ListEntry *rover; + ListEntry *newentry; + + /* Create new list entry */ + + newentry = malloc(sizeof(ListEntry)); + + if (newentry == NULL) { + return NULL; + } + + newentry->data = data; + newentry->next = NULL; + + /* Hooking into the list is different if the list is empty */ + + if (*list == NULL) { + + /* Create the start of the list */ + + *list = newentry; + newentry->prev = NULL; + + } else { + + /* Find the end of list */ + + for (rover=*list; rover->next != NULL; rover = rover->next); + + /* Add to the end of list */ + + newentry->prev = rover; + rover->next = newentry; + } + + return newentry; +} + +ListValue list_data(ListEntry *listentry) +{ + return listentry->data; +} + +ListEntry *list_prev(ListEntry *listentry) +{ + return listentry->prev; +} + +ListEntry *list_next(ListEntry *listentry) +{ + return listentry->next; +} + +ListEntry *list_nth_entry(ListEntry *list, int n) +{ + ListEntry *entry; + int i; + + /* Negative values are always out of range */ + + if (n < 0) { + return NULL; + } + + /* Iterate through n list entries to reach the desired entry. + * Make sure we do not reach the end of the list. */ + + entry = list; + + for (i=0; i<n; ++i) { + + if (entry == NULL) { + return NULL; + } + entry = entry->next; + } + + return entry; +} + +ListValue list_nth_data(ListEntry *list, int n) +{ + ListEntry *entry; + + /* Find the specified entry */ + + entry = list_nth_entry(list, n); + + /* If out of range, return NULL, otherwise return the data */ + + if (entry == NULL) { + return LIST_NULL; + } else { + return entry->data; + } +} + +int list_length(ListEntry *list) +{ + ListEntry *entry; + int length; + + length = 0; + entry = list; + + while (entry != NULL) { + + /* Count the number of entries */ + + ++length; + + entry = entry->next; + } + + return length; +} + +ListValue *list_to_array(ListEntry *list) +{ + ListEntry *rover; + int listlen; + ListValue *array; + int i; + + /* Allocate an array equal in size to the list length */ + + listlen = list_length(list); + + array = malloc(sizeof(ListValue) * listlen); + + if (array == NULL) { + return NULL; + } + + /* Add all entries to the array */ + + rover = list; + + for (i=0; i<listlen; ++i) { + + /* Add this node's data */ + + array[i] = rover->data; + + /* Jump to the next list node */ + + rover = rover->next; + } + + return array; +} + +int list_remove_entry(ListEntry **list, ListEntry *entry) +{ + /* If the list is empty, or entry is NULL, always fail */ + + if (*list == NULL || entry == NULL) { + return 0; + } + + /* Action to take is different if the entry is the first in the list */ + + if (entry->prev == NULL) { + + /* Unlink the first entry and update the starting pointer */ + + *list = entry->next; + + /* Update the second entry's prev pointer, if there is a second + * entry */ + + if (entry->next != NULL) { + entry->next->prev = NULL; + } + + } else { + + /* This is not the first in the list, so we must have a + * previous entry. Update its 'next' pointer to the new + * value */ + + entry->prev->next = entry->next; + + /* If there is an entry following this one, update its 'prev' + * pointer to the new value */ + + if (entry->next != NULL) { + entry->next->prev = entry->prev; + } + } + + /* Free the list entry */ + + free(entry); + + /* Operation successful */ + + return 1; +} + +int list_remove_data(ListEntry **list, ListEqualFunc callback, ListValue data) +{ + int entries_removed; + ListEntry *rover; + ListEntry *next; + + entries_removed = 0; + + /* Iterate over the entries in the list */ + + rover = *list; + + while (rover != NULL) { + + next = rover->next; + + if (callback(rover->data, data)) { + + /* This data needs to be removed. Unlink this entry + * from the list. */ + + if (rover->prev == NULL) { + + /* This is the first entry in the list */ + + *list = rover->next; + } else { + + /* Point the previous entry at its new + * location */ + + rover->prev->next = rover->next; + } + + if (rover->next != NULL) { + rover->next->prev = rover->prev; + } + + /* Free the entry */ + + free(rover); + + ++entries_removed; + } + + /* Advance to the next list entry */ + + rover = next; + } + + return entries_removed; +} + +/* Function used internally for sorting. Returns the last entry in the + * new sorted list */ + +static ListEntry *list_sort_internal(ListEntry **list, + ListCompareFunc compare_func) +{ + ListEntry *pivot; + ListEntry *rover; + ListEntry *less_list, *more_list; + ListEntry *less_list_end, *more_list_end; + + /* If there are less than two entries in this list, it is + * already sorted */ + + if (*list == NULL || (*list)->next == NULL) { + return *list; + } + + /* The first entry is the pivot */ + + pivot = *list; + + /* Iterate over the list, starting from the second entry. Sort + * all entries into the less and more lists based on comparisons + * with the pivot */ + + less_list = NULL; + more_list = NULL; + rover = (*list)->next; + + while (rover != NULL) { + ListEntry *next = rover->next; + + if (compare_func(rover->data, pivot->data) < 0) { + + /* Place this in the less list */ + + rover->prev = NULL; + rover->next = less_list; + if (less_list != NULL) { + less_list->prev = rover; + } + less_list = rover; + + } else { + + /* Place this in the more list */ + + rover->prev = NULL; + rover->next = more_list; + if (more_list != NULL) { + more_list->prev = rover; + } + more_list = rover; + } + + rover = next; + } + + /* Sort the sublists recursively */ + + less_list_end = list_sort_internal(&less_list, compare_func); + more_list_end = list_sort_internal(&more_list, compare_func); + + /* Create the new list starting from the less list */ + + *list = less_list; + + /* Append the pivot to the end of the less list. If the less list + * was empty, start from the pivot */ + + if (less_list == NULL) { + pivot->prev = NULL; + *list = pivot; + } else { + pivot->prev = less_list_end; + less_list_end->next = pivot; + } + + /* Append the more list after the pivot */ + + pivot->next = more_list; + if (more_list != NULL) { + more_list->prev = pivot; + } + + /* Work out what the last entry in the list is. If the more list was + * empty, the pivot was the last entry. Otherwise, the end of the + * more list is the end of the total list. */ + + if (more_list == NULL) { + return pivot; + } else { + return more_list_end; + } +} + +void list_sort(ListEntry **list, ListCompareFunc compare_func) +{ + list_sort_internal(list, compare_func); +} + +ListEntry *list_find_data(ListEntry *list, + ListEqualFunc callback, + ListValue data) +{ + ListEntry *rover; + + /* Iterate over entries in the list until the data is found */ + + for (rover=list; rover != NULL; rover=rover->next) { + if (callback(rover->data, data) != 0) { + return rover; + } + } + + /* Not found */ + + return NULL; +} + +void list_iterate(ListEntry **list, ListIterator *iter) +{ + /* Start iterating from the beginning of the list. */ + + iter->prev_next = list; + + /* We have not yet read the first item. */ + + iter->current = NULL; +} + +int list_iter_has_more(ListIterator *iter) +{ + if (iter->current == NULL || iter->current != *iter->prev_next) { + + /* Either we have not read the first entry, the current + * item was removed or we have reached the end of the + * list. Use prev_next to determine if we have a next + * value to iterate over. */ + + return *iter->prev_next != NULL; + + } else { + /* The current entry as not been deleted since the last + * call to list_iter_next: there is a next entry if + * current->next is not NULL */ + + return iter->current->next != NULL; + } +} + +ListValue list_iter_next(ListIterator *iter) +{ + if (iter->current == NULL || iter->current != *iter->prev_next) { + + /* Either we are reading the first entry, we have reached + * the end of the list, or the previous entry was removed. + * Get the next entry with iter->prev_next. */ + + iter->current = *iter->prev_next; + + } else { + + /* Last value returned from list_iter_next was not deleted. + * Advance to the next entry. */ + + iter->prev_next = &iter->current->next; + iter->current = iter->current->next; + } + + /* Have we reached the end of the list? */ + + if (iter->current == NULL) { + return LIST_NULL; + } else { + return iter->current->data; + } +} + +void list_iter_remove(ListIterator *iter) +{ + if (iter->current == NULL || iter->current != *iter->prev_next) { + + /* Either we have not yet read the first item, we have + * reached the end of the list, or we have already removed + * the current value. Either way, do nothing. */ + + } else { + + /* Remove the current entry */ + + *iter->prev_next = iter->current->next; + + if (iter->current->next != NULL) { + iter->current->next->prev = iter->current->prev; + } + + free(iter->current); + iter->current = NULL; + } +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/queue.c b/EDM/athena/Control/CxxUtils/src/libcalg/queue.c new file mode 100644 index 00000000..737d232e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/queue.c @@ -0,0 +1,254 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> + +#include "CxxUtils/libcalg/queue.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +/* A double-ended queue */ + +typedef struct _QueueEntry QueueEntry; + +struct _QueueEntry { + QueueValue data; + QueueEntry *prev; + QueueEntry *next; +}; + +struct _Queue { + QueueEntry *head; + QueueEntry *tail; +}; + +Queue *queue_new(void) +{ + Queue *queue; + + queue = (Queue *) malloc(sizeof(Queue)); + + if (queue == NULL) { + return NULL; + } + + queue->head = NULL; + queue->tail = NULL; + + return queue; +} + +void queue_free(Queue *queue) +{ + /* Empty the queue */ + + while (!queue_is_empty(queue)) { + queue_pop_head(queue); + } + + /* Free back the queue */ + + free(queue); +} + +int queue_push_head(Queue *queue, QueueValue data) +{ + QueueEntry *new_entry; + + /* Create the new entry and fill in the fields in the structure */ + + new_entry = malloc(sizeof(QueueEntry)); + + if (new_entry == NULL) { + return 0; + } + + new_entry->data = data; + new_entry->prev = NULL; + new_entry->next = queue->head; + + /* Insert into the queue */ + + if (queue->head == NULL) { + + /* If the queue was previously empty, both the head and tail must + * be pointed at the new entry */ + + queue->head = new_entry; + queue->tail = new_entry; + + } else { + + /* First entry in the list must have prev pointed back to this + * new entry */ + + queue->head->prev = new_entry; + + /* Only the head must be pointed at the new entry */ + + queue->head = new_entry; + } + + return 1; +} + +QueueValue queue_pop_head(Queue *queue) +{ + QueueEntry *entry; + QueueValue result; + + /* Check the queue is not empty */ + + if (queue_is_empty(queue)) { + return QUEUE_NULL; + } + + /* Unlink the first entry from the head of the queue */ + + entry = queue->head; + queue->head = entry->next; + result = entry->data; + + if (queue->head == NULL) { + + /* If doing this has unlinked the last entry in the queue, set + * tail to NULL as well. */ + + queue->tail = NULL; + } else { + + /* The new first in the queue has no previous entry */ + + queue->head->prev = NULL; + } + + /* Free back the queue entry structure */ + + free(entry); + + return result; +} + +QueueValue queue_peek_head(Queue *queue) +{ + if (queue_is_empty(queue)) { + return QUEUE_NULL; + } else { + return queue->head->data; + } +} + +int queue_push_tail(Queue *queue, QueueValue data) +{ + QueueEntry *new_entry; + + /* Create the new entry and fill in the fields in the structure */ + + new_entry = malloc(sizeof(QueueEntry)); + + if (new_entry == NULL) { + return 0; + } + + new_entry->data = data; + new_entry->prev = queue->tail; + new_entry->next = NULL; + + /* Insert into the queue tail */ + + if (queue->tail == NULL) { + + /* If the queue was previously empty, both the head and tail must + * be pointed at the new entry */ + + queue->head = new_entry; + queue->tail = new_entry; + + } else { + + /* The current entry at the tail must have next pointed to this + * new entry */ + + queue->tail->next = new_entry; + + /* Only the tail must be pointed at the new entry */ + + queue->tail = new_entry; + } + + return 1; +} + +QueueValue queue_pop_tail(Queue *queue) +{ + QueueEntry *entry; + QueueValue result; + + /* Check the queue is not empty */ + + if (queue_is_empty(queue)) { + return QUEUE_NULL; + } + + /* Unlink the first entry from the tail of the queue */ + + entry = queue->tail; + queue->tail = entry->prev; + result = entry->data; + + if (queue->tail == NULL) { + + /* If doing this has unlinked the last entry in the queue, set + * head to NULL as well. */ + + queue->head = NULL; + + } else { + + /* The new entry at the tail has no next entry. */ + + queue->tail->next = NULL; + } + + /* Free back the queue entry structure */ + + free(entry); + + return result; +} + +QueueValue queue_peek_tail(Queue *queue) +{ + if (queue_is_empty(queue)) { + return QUEUE_NULL; + } else { + return queue->tail->data; + } +} + +int queue_is_empty(Queue *queue) +{ + return queue->head == NULL; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/set.c b/EDM/athena/Control/CxxUtils/src/libcalg/set.c new file mode 100644 index 00000000..d4e9527e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/set.c @@ -0,0 +1,602 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> +#include <string.h> +#include "CxxUtils/libcalg/set.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +/* A set */ + +struct _SetEntry { + SetValue data; + SetEntry *next; +}; + +struct _Set { + SetEntry **table; + int entries; + int table_size; + int prime_index; + SetHashFunc hash_func; + SetEqualFunc equal_func; + SetFreeFunc free_func; +}; + +/* This is a set of good hash table prime numbers, from: + * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html + * Each prime is roughly double the previous value, and as far as + * possible from the nearest powers of two. */ + +static const unsigned int set_primes[] = { + 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, + 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843, 50331653, 100663319, 201326611, + 402653189, 805306457, 1610612741, +}; + +static const int set_num_primes = sizeof(set_primes) / sizeof(int); + +static int set_allocate_table(Set *set) +{ + /* Determine the table size based on the current prime index. + * An attempt is made here to ensure sensible behavior if the + * maximum prime is exceeded, but in practice other things are + * likely to break long before that happens. */ + + if (set->prime_index < set_num_primes) { + set->table_size = set_primes[set->prime_index]; + } else { + set->table_size = set->entries * 10; + } + + /* Allocate the table and initialise to NULL */ + + set->table = calloc(set->table_size, sizeof(SetEntry *)); + + return set->table != NULL; +} + +static void set_free_entry(Set *set, SetEntry *entry) +{ + /* If there is a free function registered, call it to free the + * data for this entry first */ + + if (set->free_func != NULL) { + set->free_func(entry->data); + } + + /* Free the entry structure */ + + free(entry); +} + +Set *set_new(SetHashFunc hash_func, SetEqualFunc equal_func) +{ + Set *new_set; + + /* Allocate a new set and fill in the fields */ + + new_set = (Set *) malloc(sizeof(Set)); + + if (new_set == NULL) { + return NULL; + } + + new_set->hash_func = hash_func; + new_set->equal_func = equal_func; + new_set->entries = 0; + new_set->prime_index = 0; + new_set->free_func = NULL; + + /* Allocate the table */ + + if (!set_allocate_table(new_set)) { + free(new_set); + return NULL; + } + + return new_set; +} + +void set_free(Set *set) +{ + SetEntry *rover; + SetEntry *next; + int i; + + /* Free all entries in all chains */ + + for (i=0; i<set->table_size; ++i) { + rover = set->table[i]; + + while (rover != NULL) { + next = rover->next; + + /* Free this entry */ + + set_free_entry(set, rover); + + /* Advance to the next entry in the chain */ + + rover = next; + } + } + + /* Free the table */ + + free(set->table); + + /* Free the set structure */ + + free(set); +} + +void set_register_free_function(Set *set, SetFreeFunc free_func) +{ + set->free_func = free_func; +} + +static int set_enlarge(Set *set) +{ + SetEntry *rover; + SetEntry *next; + SetEntry **old_table; + int old_table_size; + int old_prime_index; + int index; + int i; + + /* Store the old table */ + + old_table = set->table; + old_table_size = set->table_size; + old_prime_index = set->prime_index; + + /* Use the next table size from the prime number array */ + + ++set->prime_index; + + /* Allocate the new table */ + + if (!set_allocate_table(set)) { + set->table = old_table; + set->table_size = old_table_size; + set->prime_index = old_prime_index; + + return 0; + } + + /* Iterate through all entries in the old table and add them + * to the new one */ + + for (i=0; i<old_table_size; ++i) { + + /* Walk along this chain */ + + rover = old_table[i]; + + while (rover != NULL) { + + next = rover->next; + + /* Hook this entry into the new table */ + + index = set->hash_func(rover->data) % set->table_size; + rover->next = set->table[index]; + set->table[index] = rover; + + /* Advance to the next entry in the chain */ + + rover = next; + } + } + + /* Free back the old table */ + + free(old_table); + + /* Resized successfully */ + + return 1; +} + +int set_insert(Set *set, SetValue data) +{ + SetEntry *newentry; + SetEntry *rover; + int index; + + /* The hash table becomes less efficient as the number of entries + * increases. Check if the percentage used becomes large. */ + + if ((set->entries * 3) / set->table_size > 0) { + + /* The table is more than 1/3 full and must be increased in size */ + + if (!set_enlarge(set)) { + return 0; + } + } + + /* Use the hash of the data to determine an index to insert into the + * table at. */ + + index = set->hash_func(data) % set->table_size; + + /* Walk along this chain and attempt to determine if this data has + * already been added to the table */ + + rover = set->table[index]; + + while (rover != NULL) { + + if (set->equal_func(data, rover->data) != 0) { + + /* This data is already in the set */ + + return 0; + } + + rover = rover->next; + } + + /* Not in the set. We must add a new entry. */ + + /* Make a new entry for this data */ + + newentry = (SetEntry *) malloc(sizeof(SetEntry)); + + if (newentry == NULL) { + return 0; + } + + newentry->data = data; + + /* Link into chain */ + + newentry->next = set->table[index]; + set->table[index] = newentry; + + /* Keep track of the number of entries in the set */ + + ++set->entries; + + /* Added successfully */ + + return 1; +} + +int set_remove(Set *set, SetValue data) +{ + SetEntry **rover; + SetEntry *entry; + int index; + + /* Look up the data by its hash key */ + + index = set->hash_func(data) % set->table_size; + + /* Search this chain, until the corresponding entry is found */ + + rover = &set->table[index]; + + while (*rover != NULL) { + if (set->equal_func(data, (*rover)->data) != 0) { + + /* Found the entry */ + + entry = *rover; + + /* Unlink from the linked list */ + + *rover = entry->next; + + /* Update counter */ + + --set->entries; + + /* Free the entry and return */ + + set_free_entry(set, entry); + + return 1; + } + + /* Advance to the next entry */ + + rover = &((*rover)->next); + } + + /* Not found in set */ + + return 0; +} + +int set_query(Set *set, SetValue data) +{ + SetEntry *rover; + int index; + + /* Look up the data by its hash key */ + + index = set->hash_func(data) % set->table_size; + + /* Search this chain, until the corresponding entry is found */ + + rover = set->table[index]; + + while (rover != NULL) { + if (set->equal_func(data, rover->data) != 0) { + + /* Found the entry */ + + return 1; + } + + /* Advance to the next entry in the chain */ + + rover = rover->next; + } + + /* Not found */ + + return 0; +} + +int set_num_entries(Set *set) +{ + return set->entries; +} + +SetValue *set_to_array(Set *set) +{ + SetValue *array; + int array_counter; + int i; + SetEntry *rover; + + /* Create an array to hold the set entries */ + + array = malloc(sizeof(SetValue) * set->entries); + + if (array == NULL) { + return NULL; + } + + array_counter = 0; + + /* Iterate over all entries in all chains */ + + for (i=0; i<set->table_size; ++i) { + + rover = set->table[i]; + + while (rover != NULL) { + + /* Add this value to the array */ + + array[array_counter] = rover->data; + ++array_counter; + + /* Advance to the next entry */ + + rover = rover->next; + } + } + + return array; +} + +Set *set_union(Set *set1, Set *set2) +{ + SetIterator iterator; + Set *new_set; + SetValue value; + + new_set = set_new(set1->hash_func, set1->equal_func); + + if (new_set == NULL) { + return NULL; + } + + /* Add all values from the first set */ + + set_iterate(set1, &iterator); + + while (set_iter_has_more(&iterator)) { + + /* Read the next value */ + + value = set_iter_next(&iterator); + + /* Copy the value into the new set */ + + if (!set_insert(new_set, value)) { + + /* Failed to insert */ + + set_free(new_set); + return NULL; + } + } + + /* Add all values from the second set */ + + set_iterate(set2, &iterator); + + while (set_iter_has_more(&iterator)) { + + /* Read the next value */ + + value = set_iter_next(&iterator); + + /* Has this value been put into the new set already? + * If so, do not insert this again */ + + if (set_query(new_set, value) == 0) { + if (!set_insert(new_set, value)) { + + /* Failed to insert */ + + set_free(new_set); + return NULL; + } + } + } + + return new_set; +} + +Set *set_intersection(Set *set1, Set *set2) +{ + Set *new_set; + SetIterator iterator; + SetValue value; + + new_set = set_new(set1->hash_func, set2->equal_func); + + if (new_set == NULL) { + return NULL; + } + + /* Iterate over all values in set 1. */ + + set_iterate(set1, &iterator); + + while (set_iter_has_more(&iterator)) { + + /* Get the next value */ + + value = set_iter_next(&iterator); + + /* Is this value in set 2 as well? If so, it should be + * in the new set. */ + + if (set_query(set2, value) != 0) { + + /* Copy the value first before inserting, + * if necessary */ + + if (!set_insert(new_set, value)) { + set_free(new_set); + + return NULL; + } + } + } + + return new_set; +} + +void set_iterate(Set *set, SetIterator *iter) +{ + int chain; + + iter->set = set; + iter->next_entry = NULL; + + /* Find the first entry */ + + for (chain = 0; chain < set->table_size; ++chain) { + + /* There is a value at the start of this chain */ + + if (set->table[chain] != NULL) { + iter->next_entry = set->table[chain]; + break; + } + } + + iter->next_chain = chain; +} + +SetValue set_iter_next(SetIterator *iterator) +{ + Set *set; + SetValue result; + SetEntry *current_entry; + int chain; + + set = iterator->set; + + /* No more entries? */ + + if (iterator->next_entry == NULL) { + return SET_NULL; + } + + /* We have the result immediately */ + + current_entry = iterator->next_entry; + result = current_entry->data; + + /* Advance next_entry to the next SetEntry in the Set. */ + + if (current_entry->next != NULL) { + + /* Use the next value in this chain */ + + iterator->next_entry = current_entry->next; + + } else { + + /* Default value if no valid chain is found */ + + iterator->next_entry = NULL; + + /* No more entries in this chain. Search the next chain */ + + chain = iterator->next_chain + 1; + + while (chain < set->table_size) { + + /* Is there a chain at this table entry? */ + + if (set->table[chain] != NULL) { + + /* Valid chain found! */ + + iterator->next_entry = set->table[chain]; + + break; + } + + /* Keep searching until we find an empty chain */ + + ++chain; + } + + iterator->next_chain = chain; + } + + return result; +} + +int set_iter_has_more(SetIterator *iterator) +{ + return iterator->next_entry != NULL; +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/slist.c b/EDM/athena/Control/CxxUtils/src/libcalg/slist.c new file mode 100644 index 00000000..5ad40888 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/slist.c @@ -0,0 +1,504 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include <stdlib.h> + +#include "CxxUtils/libcalg/slist.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +/* A singly-linked list */ + +struct _SListEntry { + SListValue data; + SListEntry *next; +}; + +void slist_free(SListEntry *list) +{ + SListEntry *entry; + + /* Iterate over each entry, freeing each list entry, until the + * end is reached */ + + entry = list; + + while (entry != NULL) { + SListEntry *next; + + next = entry->next; + + free(entry); + + entry = next; + } +} + +SListEntry *slist_prepend(SListEntry **list, SListValue data) +{ + SListEntry *newentry; + + /* Create new entry */ + + newentry = malloc(sizeof(SListEntry)); + + if (newentry == NULL) { + return NULL; + } + + newentry->data = data; + + /* Hook into the list start */ + + newentry->next = *list; + *list = newentry; + + return newentry; +} + +SListEntry *slist_append(SListEntry **list, SListValue data) +{ + SListEntry *rover; + SListEntry *newentry; + + /* Create new list entry */ + + newentry = malloc(sizeof(SListEntry)); + + if (newentry == NULL) { + return NULL; + } + + newentry->data = data; + newentry->next = NULL; + + /* Hooking into the list is different if the list is empty */ + + if (*list == NULL) { + + /* Create the start of the list */ + + *list = newentry; + + } else { + + /* Find the end of list */ + + for (rover=*list; rover->next != NULL; rover = rover->next); + + /* Add to the end of list */ + + rover->next = newentry; + } + + return newentry; +} + +SListValue slist_data(SListEntry *listentry) +{ + return listentry->data; +} + +SListEntry *slist_next(SListEntry *listentry) +{ + return listentry->next; +} + +SListEntry *slist_nth_entry(SListEntry *list, int n) +{ + SListEntry *entry; + int i; + + /* Negative values are always out of range */ + + if (n < 0) { + return NULL; + } + + /* Iterate through n list entries to reach the desired entry. + * Make sure we do not reach the end of the list. */ + + entry = list; + + for (i=0; i<n; ++i) { + + if (entry == NULL) { + return NULL; + } + entry = entry->next; + } + + return entry; +} + +SListValue slist_nth_data(SListEntry *list, int n) +{ + SListEntry *entry; + + /* Find the specified entry */ + + entry = slist_nth_entry(list, n); + + /* If out of range, return NULL, otherwise return the data */ + + if (entry == NULL) { + return SLIST_NULL; + } else { + return entry->data; + } +} + +int slist_length(SListEntry *list) +{ + SListEntry *entry; + int length; + + length = 0; + entry = list; + + while (entry != NULL) { + + /* Count the number of entries */ + + ++length; + + entry = entry->next; + } + + return length; +} + +SListValue *slist_to_array(SListEntry *list) +{ + SListEntry *rover; + int listlen; + SListValue *array; + int i; + + /* Allocate an array equal in size to the list length */ + + listlen = slist_length(list); + + array = malloc(sizeof(SListValue) * listlen); + + if (array == NULL) { + return NULL; + } + + /* Add all entries to the array */ + + rover = list; + + for (i=0; i<listlen; ++i) { + + /* Add this node's data */ + + array[i] = rover->data; + + /* Jump to the next list node */ + + rover = rover->next; + } + + return array; +} + +int slist_remove_entry(SListEntry **list, SListEntry *entry) +{ + SListEntry *rover; + + /* If the list is empty, or entry is NULL, always fail */ + + if (*list == NULL || entry == NULL) { + return 0; + } + + /* Action to take is different if the entry is the first in the list */ + + if (*list == entry) { + + /* Unlink the first entry and update the starting pointer */ + + *list = entry->next; + + } else { + + /* Search through the list to find the preceding entry */ + + rover = *list; + + while (rover != NULL && rover->next != entry) { + rover = rover->next; + } + + if (rover == NULL) { + + /* Not found in list */ + + return 0; + + } else { + + /* rover->next now points at entry, so rover is the preceding + * entry. Unlink the entry from the list. */ + + rover->next = entry->next; + } + } + + /* Free the list entry */ + + free(entry); + + /* Operation successful */ + + return 1; +} + +int slist_remove_data(SListEntry **list, SListEqualFunc callback, SListValue data) +{ + SListEntry **rover; + SListEntry *next; + int entries_removed; + + entries_removed = 0; + + /* Iterate over the list. 'rover' points at the entrypoint into the + * current entry, ie. the list variable for the first entry in the + * list, or the "next" field of the preceding entry. */ + + rover = list; + + while (*rover != NULL) { + + /* Should this entry be removed? */ + + if (callback((*rover)->data, data) != 0) { + + /* Data found, so remove this entry and free */ + + next = (*rover)->next; + free(*rover); + *rover = next; + + /* Count the number of entries removed */ + + ++entries_removed; + } else { + + /* Advance to the next entry */ + + rover = &((*rover)->next); + } + } + + return entries_removed; +} + +/* Function used internally for sorting. Returns the last entry in the + * new sorted list */ + +static SListEntry *slist_sort_internal(SListEntry **list, + SListCompareFunc compare_func) +{ + SListEntry *pivot; + SListEntry *rover; + SListEntry *less_list, *more_list; + SListEntry *less_list_end, *more_list_end; + + /* If there are less than two entries in this list, it is + * already sorted */ + + if (*list == NULL || (*list)->next == NULL) { + return *list; + } + + /* The first entry is the pivot */ + + pivot = *list; + + /* Iterate over the list, starting from the second entry. Sort + * all entries into the less and more lists based on comparisons + * with the pivot */ + + less_list = NULL; + more_list = NULL; + rover = (*list)->next; + + while (rover != NULL) { + SListEntry *next = rover->next; + + if (compare_func(rover->data, pivot->data) < 0) { + + /* Place this in the less list */ + + rover->next = less_list; + less_list = rover; + + } else { + + /* Place this in the more list */ + + rover->next = more_list; + more_list = rover; + + } + + rover = next; + } + + /* Sort the sublists recursively */ + + less_list_end = slist_sort_internal(&less_list, compare_func); + more_list_end = slist_sort_internal(&more_list, compare_func); + + /* Create the new list starting from the less list */ + + *list = less_list; + + /* Append the pivot to the end of the less list. If the less list + * was empty, start from the pivot */ + + if (less_list == NULL) { + *list = pivot; + } else { + less_list_end->next = pivot; + } + + /* Append the more list after the pivot */ + + pivot->next = more_list; + + /* Work out what the last entry in the list is. If the more list was + * empty, the pivot was the last entry. Otherwise, the end of the + * more list is the end of the total list. */ + + if (more_list == NULL) { + return pivot; + } else { + return more_list_end; + } +} + +void slist_sort(SListEntry **list, SListCompareFunc compare_func) +{ + slist_sort_internal(list, compare_func); +} + +SListEntry *slist_find_data(SListEntry *list, + SListEqualFunc callback, + SListValue data) +{ + SListEntry *rover; + + /* Iterate over entries in the list until the data is found */ + + for (rover=list; rover != NULL; rover=rover->next) { + if (callback(rover->data, data) != 0) { + return rover; + } + } + + /* Not found */ + + return NULL; +} + +void slist_iterate(SListEntry **list, SListIterator *iter) +{ + /* Start iterating from the beginning of the list. */ + + iter->prev_next = list; + + /* We have not yet read the first item. */ + + iter->current = NULL; +} + +int slist_iter_has_more(SListIterator *iter) +{ + if (iter->current == NULL || iter->current != *iter->prev_next) { + + /* Either we have not read the first entry, the current + * item was removed or we have reached the end of the + * list. Use prev_next to determine if we have a next + * value to iterate over. */ + + return *iter->prev_next != NULL; + + } else { + + /* The current entry has not been deleted. There + * is a next entry if current->next is not NULL. */ + + return iter->current->next != NULL; + } +} + +SListValue slist_iter_next(SListIterator *iter) +{ + if (iter->current == NULL || iter->current != *iter->prev_next) { + + /* Either we are reading the first entry, we have reached + * the end of the list, or the previous entry was removed. + * Get the next entry with iter->prev_next. */ + + iter->current = *iter->prev_next; + + } else { + + /* Last value returned from slist_iter_next was not + * deleted. Advance to the next entry. */ + + iter->prev_next = &iter->current->next; + iter->current = iter->current->next; + } + + /* Have we reached the end of the list? */ + + if (iter->current == NULL) { + return SLIST_NULL; + } else { + return iter->current->data; + } +} + +void slist_iter_remove(SListIterator *iter) +{ + if (iter->current == NULL || iter->current != *iter->prev_next) { + + /* Either we have not yet read the first item, we have + * reached the end of the list, or we have already removed + * the current value. Either way, do nothing. */ + + } else { + + /* Remove the current entry */ + + *iter->prev_next = iter->current->next; + free(iter->current); + iter->current = NULL; + } +} + diff --git a/EDM/athena/Control/CxxUtils/src/libcalg/trie.c b/EDM/athena/Control/CxxUtils/src/libcalg/trie.c new file mode 100644 index 00000000..6f6f77c3 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/src/libcalg/trie.c @@ -0,0 +1,381 @@ +/* + +Copyright (c) 2005-2008, Simon Howard + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/* Trie: fast mapping of strings to values */ + +#include <stdlib.h> +#include <string.h> + +#include "CxxUtils/libcalg/trie.h" + +/* malloc() / free() testing */ + +#ifdef ALLOC_TESTING +#include "CxxUtils/libcalg/alloc-testing.h" +#endif + +typedef struct _TrieNode TrieNode; + +struct _TrieNode { + TrieValue data; + unsigned int use_count; + TrieNode *next[256]; +}; + +struct _Trie { + TrieNode *root_node; +}; + +Trie *trie_new(void) +{ + Trie *new_trie; + + new_trie = (Trie *) malloc(sizeof(Trie)); + + if (new_trie == NULL) { + return NULL; + } + + new_trie->root_node = NULL; + + return new_trie; +} + +static void trie_free_list_push(TrieNode **list, TrieNode *node) +{ + node->data = *list; + *list = node; +} + +static TrieNode *trie_free_list_pop(TrieNode **list) +{ + TrieNode *result; + + result = *list; + *list = result->data; + + return result; +} + +void trie_free(Trie *trie) +{ + TrieNode *free_list; + TrieNode *node; + int i; + + free_list = NULL; + + /* Start with the root node */ + + if (trie->root_node != NULL) { + trie_free_list_push(&free_list, trie->root_node); + } + + /* Go through the free list, freeing nodes. We add new nodes as + * we encounter them; in this way, all the nodes are freed + * non-recursively. */ + + while (free_list != NULL) { + node = trie_free_list_pop(&free_list); + + /* Add all children of this node to the free list */ + + for (i=0; i<256; ++i) { + if (node->next[i] != NULL) { + trie_free_list_push(&free_list, node->next[i]); + } + } + + /* Free the node */ + + free(node); + } + + /* Free the trie */ + + free(trie); +} + +static TrieNode *trie_find_end(Trie *trie, char *key) +{ + TrieNode *node; + char *p; + int c; + + /* Search down the trie until the end of string is reached */ + + node = trie->root_node; + + for (p=key; *p != '\0'; ++p) { + + if (node == NULL) { + /* Not found in the tree. Return. */ + + return NULL; + } + + /* Jump to the next node */ + + c = *p; + node = node->next[c]; + } + + /* This key is present if the value at the last node is not NULL */ + + return node; +} + +/* Roll back an insert operation after a failed malloc() call. */ + +static void trie_insert_rollback(Trie *trie, char *key) +{ + TrieNode *node; + TrieNode **prev_ptr; + TrieNode *next_node; + TrieNode **next_prev_ptr; + char *p; + + /* Follow the chain along. We know that we will never reach the + * end of the string because trie_insert never got that far. As a + * result, it is not necessary to check for the end of string + * delimiter (NUL) */ + + node = trie->root_node; + prev_ptr = &trie->root_node; + p = key; + + while (node != NULL) { + + /* Find the next node now. We might free this node. */ + + next_prev_ptr = &node->next[(int) *p]; + next_node = *next_prev_ptr; + ++p; + + /* Decrease the use count and free the node if it + * reaches zero. */ + + --node->use_count; + + if (node->use_count == 0) { + free(node); + + if (prev_ptr != NULL) { + *prev_ptr = NULL; + } + + next_prev_ptr = NULL; + } + + /* Update pointers */ + + node = next_node; + prev_ptr = next_prev_ptr; + } +} + +int trie_insert(Trie *trie, char *key, TrieValue value) +{ + TrieNode **rover; + TrieNode *node; + char *p; + int c; + + /* Cannot insert NULL values */ + + if (value == TRIE_NULL) { + return 0; + } + + /* Search to see if this is already in the tree */ + + node = trie_find_end(trie, key); + + /* Already in the tree? If so, replace the existing value and + * return success. */ + + if (node != NULL && node->data != TRIE_NULL) { + node->data = value; + return 1; + } + + /* Search down the trie until we reach the end of string, + * creating nodes as necessary */ + + rover = &trie->root_node; + p = key; + + for (;;) { + + node = *rover; + + if (node == NULL) { + + /* Node does not exist, so create it */ + + node = (TrieNode *) calloc(1, sizeof(TrieNode)); + + if (node == NULL) { + + /* Allocation failed. Go back and undo + * what we have done so far. */ + + trie_insert_rollback(trie, key); + + return 0; + } + + node->data = TRIE_NULL; + + /* Link in to the trie */ + + *rover = node; + } + + /* Increase the node use count */ + + ++node->use_count; + + /* Current character */ + + c = *p; + + /* Reached the end of string? If so, we're finished. */ + + if (c == '\0') { + + /* Set the data at the node we have reached */ + + node->data = value; + + break; + } + + /* Advance to the next node in the chain */ + + rover = &node->next[c]; + ++p; + } + + return 1; +} + +int trie_remove(Trie *trie, char *key) +{ + TrieNode *node; + TrieNode *next; + TrieNode **last_next_ptr; + char *p; + int c; + + /* Find the end node and remove the value */ + + node = trie_find_end(trie, key); + + if (node != NULL && node->data != TRIE_NULL) { + node->data = TRIE_NULL; + } else { + return 0; + } + + /* Now traverse the tree again as before, decrementing the use + * count of each node. Free back nodes as necessary. */ + + node = trie->root_node; + last_next_ptr = &trie->root_node; + p = key; + + for (;;) { + + /* Find the next node */ + + c = *p; + next = node->next[c]; + + /* Free this node if necessary */ + + --node->use_count; + + if (node->use_count <= 0) { + free(node); + + /* Set the "next" pointer on the previous node to NULL, + * to unlink the freed node from the tree. This only + * needs to be done once in a remove. After the first + * unlink, all further nodes are also going to be + * free'd. */ + + if (last_next_ptr != NULL) { + *last_next_ptr = NULL; + last_next_ptr = NULL; + } + } + + /* Go to the next character or finish */ + + if (c == '\0') { + break; + } else { + ++p; + } + + /* If necessary, save the location of the "next" pointer + * so that it may be set to NULL on the next iteration if + * the next node visited is freed. */ + + if (last_next_ptr != NULL) { + last_next_ptr = &node->next[c]; + } + + /* Jump to the next node */ + + node = next; + } + + /* Removed successfully */ + + return 1; +} + +TrieValue trie_lookup(Trie *trie, char *key) +{ + TrieNode *node; + + node = trie_find_end(trie, key); + + if (node != NULL) { + return node->data; + } else { + return TRIE_NULL; + } +} + +int trie_num_entries(Trie *trie) +{ + /* To find the number of entries, simply look at the use count + * of the root node. */ + + if (trie->root_node == NULL) { + return 0; + } else { + return trie->root_node->use_count; + } +} + diff --git a/EDM/athena/Control/CxxUtils/test/ArrayScanner_test.cxx b/EDM/athena/Control/CxxUtils/test/ArrayScanner_test.cxx new file mode 100644 index 00000000..3a8547d5 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/ArrayScanner_test.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArrayScanner_test.cxx,v 1.1 2009-03-20 20:44:23 ssnyder Exp $ +/** + * @file ArrayScanner_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Regression tests for ArrayScanner class. + */ + + +#undef NDEBUG + + +#include "CxxUtils/ArrayScanner.h" +#include <sstream> +#include <cassert> + + +using namespace CxxUtils; + + +void test1() +{ + float f; + std::istringstream is (" [ 3.5, 5.5, [7.5], [9.5]] "); + ArrayScanner s (is); + assert (!s.at_end()); + assert (!s.at_close()); + assert (!s.at_num (f)); + assert (s.at_open()); + + assert (!s.at_end()); + assert (!s.at_close()); + assert (!s.at_open()); + assert (s.at_num (f)); + assert (f == 3.5); + + assert (s.at_num (f)); + assert (f == 5.5); + + assert (s.at_open()); + assert (s.at_num (f)); + assert (f == 7.5); + + assert (s.at_close()); + assert (s.at_open()); + assert (s.at_num (f)); + assert (f == 9.5); + assert (!s.at_end()); + + assert (s.at_close()); + assert (s.at_close()); + assert (s.at_end()); + + std::istringstream is2 (" 3"); + ArrayScanner s2 (is2); + assert (s2.at_num (f)); + assert (f == 3); + assert (s2.at_end()); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/Array_test.cxx b/EDM/athena/Control/CxxUtils/test/Array_test.cxx new file mode 100644 index 00000000..e0273151 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/Array_test.cxx @@ -0,0 +1,232 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Array_test.cxx,v 1.2 2009-04-08 21:12:45 ssnyder Exp $ +/** + * @file Array_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Regression tests for the Array class. + */ + + +#undef NDEBUG + + +#include "CxxUtils/Array.h" +#include <cassert> + + +using namespace CxxUtils; + + +int shape[] = {2, 4, 3}; +Arrayelt data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + +#define ARSZ(x) (sizeof(x)/sizeof(x[0])) + + +void test1() +{ + Array<2> a2x; + assert (!a2x.valid()); + assert (a2x.size() == 0); + Array<0> a0x; + assert (!a0x.valid()); + + Arrayrep rep; + rep.m_shape.assign (shape, shape + ARSZ(shape)); + rep.m_data.assign (data, data + ARSZ(data)); + rep.init_sizes(); + + Array<3> a3 (rep); + assert (a3.valid()); + assert (a3.NDIM == 3); + std::vector<unsigned int> shape (a3.shape()); + assert (shape.size() == 3); + assert (shape[0] == 2); + assert (shape[1] == 4); + assert (shape[2] == 3); + assert (a3.size() == 2); + assert (a3.size(1) == 4); + assert (*a3.ptr() == 1); + + Array<2> a2 (a3[1]); + assert (a2.NDIM == 2); + shape = a2.shape(); + assert (shape.size() == 2); + assert (shape[0] == 4); + assert (shape[1] == 3); + assert (a2.size() == 4); + assert (a2.size(1) == 3); + assert (*a2.ptr() == 13); + + Array<1> a1 (a2[1]); + assert (a1.NDIM == 1); + shape = a1.shape(); + assert (shape.size() == 1); + assert (shape[0] == 3); + assert (a1.size() == 3); + assert (*a1.ptr() == 16); + + Array<0> a0 (a1[1]); + assert (a0.valid()); + assert (a0.NDIM == 0); + shape = a0.shape(); + assert (shape.size() == 0); + assert (a0.size() == 1); + assert (a0 == 17); + + assert (a3[1][1][1] == 17); + assert (*a3[1][1].ptr() == 16); + + Arrayrep rep0; + rep0.m_data.push_back (101); + Array<0> a0a (rep0); + assert (a0a == 101); +} + + +void test2() +{ + Arrayrep rep; + rep.m_shape.assign (shape, shape + ARSZ(shape)); + rep.m_data.assign (data, data + ARSZ(data)); + rep.init_sizes(); + + WritableArray<3> w3 (rep); + assert (w3[1][1][1] == 17); + w3[1][1][1] = 99; + assert (w3[1][1][1] == 99); + + *w3[1][1].ptr() = 98; + assert (w3[1][1][0] == 98); + + Array<3> a3 = w3; + assert (a3[1][1][0] == 98); + + Arrayrep rep0; + rep0.m_data.push_back (101); + WritableArray<0> w0 (rep0); + assert (w0 == 101); + w0 = 102; + assert (w0 == 102); +} + + +void test3() +{ + Arrayrep ar1 (" [[ 1.5, 2.5], [3.5, 4.5]] "); + Array<2> a1 (ar1); + assert (a1.size (0) == 2); + assert (a1.size (1) == 2); + assert (a1[0][0] == 1.5); + assert (a1[0][1] == 2.5); + assert (a1[1][0] == 3.5); + assert (a1[1][1] == 4.5); +} + + +void test4() +{ + unsigned int shape1[] = {2, 3}; + WritableArrayData<2> w1 (shape1); + w1[1][2] = 3; + w1[0][0] = 2; + assert (w1[0][0] == 2); + assert (w1[1][2] == 3); + + std::vector<unsigned int> shape2; + shape2.push_back (3); + shape2.push_back (2); + WritableArrayData<2> w2 (shape2); + w2[2][1] = 3; + w2[0][0] = 2; + assert (w2[0][0] == 2); + assert (w2[2][1] == 3); +} + + +// Test iterators. +void test5() +{ + Arrayrep rep; + rep.m_shape.assign (shape, shape + ARSZ(shape)); + rep.m_data.assign (data, data + ARSZ(data)); + rep.init_sizes(); + + Array<3> a3 (rep); + + Array<3>::const_iterator i1 = a3.begin(); + Array<3>::const_iterator i2 = a3.end(); + Array<3>::const_iterator i3; + + assert (i1 == i1); + assert (i1 != i2); + assert (i1 < i2); + assert (i1 <= i2); + assert (i1 <= i1); + assert (i2 > i1); + assert (i2 >= i1); + assert (i1 >= i1); + assert (i2 - i1 == 2); + + assert (i3 != i1); + i3 = i1; + assert (i3 == i1); + + assert ((*i1)[0][0] == 1); + assert (i1->size() == 4); + + Array<2>::const_iterator i11 = i1->begin(); + Array<2>::const_iterator i12 = i1->end(); + assert (i11 != i12); + assert (i12 - i11 == 4); + + assert (i11[0][0] == 1); + assert (i11[1][0] == 4); + + ++i11; + assert (i11[0][0] == 4); + i11++; + assert (i11[0][0] == 7); + + --i11; + assert (i11[0][0] == 4); + i11--; + assert (i11[0][0] == 1); + + i11 += 3; + assert (i11[0][0] == 10); + i11 -= 2; + assert (i11[0][0] == 4); + + Array<2>::const_iterator i13 = i11 + 2; + assert (i13[0][0] == 10); + i13 = i11 - 1; + assert (i13[0][0] == 1); + i13 += 4; + assert (i13 == i12); + + Array<1>::const_iterator j1 = i11->begin(); + Array<1>::const_iterator j2 = i11->end(); + + assert (j1 + 3 == j2); + assert (j1[0] == 4); + assert (j1[1] == 5); + assert (j1[2] == 6); + assert (j2 - j1 == 3); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/Arrayrep_test.cxx b/EDM/athena/Control/CxxUtils/test/Arrayrep_test.cxx new file mode 100644 index 00000000..1f17defc --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/Arrayrep_test.cxx @@ -0,0 +1,109 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arrayrep_test.cxx,v 1.2 2009-04-08 21:12:45 ssnyder Exp $ +/** + * @file Arrayrep_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date June, 2004 + * @brief Regression tests for the Arrayrep class. + */ + +#undef NDEBUG + +#include "CxxUtils/Arrayrep.h" +#include <stdexcept> +#include <cassert> + + +using namespace CxxUtils; + + +unsigned int shape[] = {2, 4, 3}; +Arrayelt data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + +#define ARSZ(x) (sizeof(x)/sizeof(x[0])) + + +void test1() +{ + Arrayrep ar0 (" 3.5 "); + assert (ar0.m_shape.size() == 0); + assert (ar0.m_data.size() == 1); + assert (ar0.m_data[0] == 3.5); + +#define EXPECT_EXCEPTION(s) \ + { \ + bool caught = false; \ + try { \ + Arrayrep xx (s); \ + } catch (std::runtime_error& c) { \ + caught = true; \ + } \ + assert (caught); \ + } + + EXPECT_EXCEPTION (" asd "); + EXPECT_EXCEPTION (" 3.5 3.5 "); + + Arrayrep ar1 (" [[ 1.5, 2.5], [3.5, 4.5]] "); + assert (ar1.m_shape.size() == 2); + assert (ar1.m_shape[0] == 2); + assert (ar1.m_shape[1] == 2); + assert (ar1.m_data.size() == 4); + assert (ar1.m_data[0] == 1.5); + assert (ar1.m_data[1] == 2.5); + assert (ar1.m_data[2] == 3.5); + assert (ar1.m_data[3] == 4.5); + + EXPECT_EXCEPTION (" [[ 1.5, 2.5], [3.5, 4.5, 5.5]] "); + EXPECT_EXCEPTION (" [[ 1.5, 2.5], [3.5, 4.5], [[6.5, 7.5]]]] "); + EXPECT_EXCEPTION (" [[ 1.5, 2.5], [4.5]] "); + EXPECT_EXCEPTION (" [[ 1.5, 2.5], [asd]] "); + EXPECT_EXCEPTION (" [[ 1.5, 2.5], [3.5, 4.5] "); +} + + +void test2() +{ + Arrayrep rep; + rep.init_sizes(); + rep.m_shape.assign (&shape[0], shape + ARSZ(shape)); + rep.m_data.assign (data, data + ARSZ(data)); + rep.init_sizes(); + assert (rep.m_sizes.size() == 3); + assert (rep.m_sizes[0] == 1); + assert (rep.m_sizes[1] == 3); + assert (rep.m_sizes[2] == 12); +} + + +void test3() +{ + Arrayrep rep1 (shape, ARSZ(shape)); + assert (rep1.m_shape.size() == 3); + assert (rep1.m_shape[0] == 2); + assert (rep1.m_shape[1] == 4); + assert (rep1.m_shape[2] == 3); + assert (rep1.m_data.size() == 24); + + std::vector<unsigned int> v; + v.push_back (4); + v.push_back (2); + Arrayrep rep2 (v); + assert (rep2.m_shape.size() == 2); + assert (rep2.m_shape[0] == 4); + assert (rep2.m_shape[1] == 2); + assert (rep2.m_data.size() == 8); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/BitPackerUnpacker_test.cxx b/EDM/athena/Control/CxxUtils/test/BitPackerUnpacker_test.cxx new file mode 100644 index 00000000..392a1dde --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/BitPackerUnpacker_test.cxx @@ -0,0 +1,195 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/BitPackerUnpacker_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2014 + * @brief Regression test for BitPacker/BitUnpacker class. + */ + +#undef NDEBUG + +#include "CxxUtils/BitPacker.h" +#include "CxxUtils/BitUnpacker.h" +#include "TestTools/random.h" +#include <vector> +#include <cassert> +#include <iostream> + + +template <class T> +class TestStream +{ +public: + TestStream() : pos(0) {} + TestStream& operator<< (T x) { v.push_back(x); return *this; } + TestStream& operator>> (T& x) { x = v[pos++]; return *this; } + std::vector<T> v; + size_t pos; +}; + + +void test1() +{ + std::cout << "test1\n"; + + std::vector<uint32_t> data; + data.push_back (0x1eab8); + data.push_back (0x3ff8); + data.push_back (0x15f35); + data.push_back (0xf34e); + data.push_back (0xad40); + data.push_back (0x1d54f); + data.push_back (0xe2d5); + data.push_back (0x1221b); + data.push_back (0x1791d); + data.push_back (0xe1f6); + const int n = 10; + + //*********************************************** + + TestStream<uint32_t> stream; + { + CxxUtils::BitPacker<TestStream<uint32_t> > packer (17, stream); + for (int i=0; i < n; i++) + packer.pack (data[i]); + } + + assert (stream.v.size() == 6); + assert (stream.v[0] == 0x7ff1eab8); + assert (stream.v[1] == 0x9a757cd4); + assert (stream.v[2] == 0xa9ead407); + assert (stream.v[3] == 0xdb8b57a); + assert (stream.v[4] == 0xed791d91); + assert (stream.v[5] == 0x1c3); + + { + CxxUtils::BitUnpacker<TestStream<uint32_t> > unpacker (17, stream); + for (int i=0; i < n; i++) + assert (unpacker.unpack() == data[i]); + } + + //*********************************************** + + TestStream<uint32_t> stream2; + { + CxxUtils::BitPacker<TestStream<uint32_t> > packer (16, stream2); + for (int i=0; i < n; i++) + packer.pack (data[i] & 0xffff); + } + + assert (stream2.v.size() == 5); + assert (stream2.v[0] == 0x3ff8eab8); + assert (stream2.v[1] == 0xf34e5f35); + assert (stream2.v[2] == 0xd54fad40); + assert (stream2.v[3] == 0x221be2d5); + assert (stream2.v[4] == 0xe1f6791d); + + { + CxxUtils::BitUnpacker<TestStream<uint32_t> > unpacker (16, stream2); + for (int i=0; i < n; i++) + assert (unpacker.unpack() == (data[i] & 0xffff)); + } + + //*********************************************** + + TestStream<uint32_t> stream8; + { + CxxUtils::BitPacker8<TestStream<uint32_t> > packer (stream8); + for (int i=0; i < n; i++) + packer.pack (data[i] & 0xff); + } + + assert (stream8.v.size() == 3); + assert (stream8.v[0] == 0x4e35f8b8); + assert (stream8.v[1] == 0x1bd54f40); + assert (stream8.v[2] == 0xf61d); + + { + CxxUtils::BitUnpacker8<TestStream<uint32_t> > unpacker (stream8); + for (int i=0; i < n; i++) + assert (unpacker.unpack() == (data[i] & 0xff)); + } + + //*********************************************** + + TestStream<uint32_t> stream16; + { + CxxUtils::BitPacker16<TestStream<uint32_t> > packer (stream16); + for (int i=0; i < n; i++) + packer.pack (data[i] & 0xffff); + } + + assert (stream16.v.size() == 5); + assert (stream16.v[0] == 0x3ff8eab8); + assert (stream16.v[1] == 0xf34e5f35); + assert (stream16.v[2] == 0xd54fad40); + assert (stream16.v[3] == 0x221be2d5); + assert (stream16.v[4] == 0xe1f6791d); + + { + CxxUtils::BitUnpacker16<TestStream<uint32_t> > unpacker (stream16); + for (int i=0; i < n; i++) + assert (unpacker.unpack() == (data[i] & 0xffff)); + } +} + + +template <template<class> class PACKER, template<class> class UNPACKER, class STREAM> +void testit2(int nbits) +{ + const int n = 1000; + STREAM stream; + std::vector<uint32_t> data; + for (int i=0; i < n; i++) + data.push_back (static_cast<uint32_t> (Athena_test::rng())); + + uint32_t mask; + if (nbits == 32) + mask = ~0U; + else + mask = (1U << nbits) - 1; + + { + PACKER<STREAM> packer (nbits, stream); + for (int i=0; i < n; i++) + packer.pack (data[i] & mask); + } + + { + UNPACKER<STREAM> unpacker (nbits, stream); + for (int i=0; i < n; i++) { + uint32_t val = unpacker.unpack(); + assert (val == (data[i]&mask)); + } + } +} + + +void test2() +{ + using CxxUtils::BitPacker; + using CxxUtils::BitPacker8; + using CxxUtils::BitPacker16; + using CxxUtils::BitUnpacker; + using CxxUtils::BitUnpacker8; + using CxxUtils::BitUnpacker16; + for (int nbits=1; nbits <= 32; ++nbits) { + testit2<BitPacker, BitUnpacker, TestStream<uint32_t> > (nbits); + } + testit2<BitPacker8, BitUnpacker8, TestStream<uint32_t> > (8); + testit2<BitPacker16, BitUnpacker16, TestStream<uint32_t> > (16); + + std::cout << "test2\n"; +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/ClassName_test.cxx b/EDM/athena/Control/CxxUtils/test/ClassName_test.cxx new file mode 100644 index 00000000..aec3dc1e --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/ClassName_test.cxx @@ -0,0 +1,219 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/ClassName_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Regression tests for ClassName. + */ + + +#undef NDEBUG +#include "CxxUtils/ClassName.h" +#include <iostream> +#include <cassert> + + +#include "expect_exception.icc" + + +using CxxUtils::ClassName; + + +void test1() +{ + std::cout << "test1\n"; + + { + ClassName cn ("Foo"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "Foo"); + } + + { + ClassName cn ("const Foo"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "const Foo"); + } + + { + ClassName cn ("Foo const"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "const Foo"); + } + + { + ClassName cn ("Foo::Bar::Fee"); + assert (cn.name() == "Fee"); + assert (cn.qualifiedName() == "Foo::Bar::Fee"); + assert (cn.fullName() == "Foo::Bar::Fee"); + } + + + { + ClassName cn ("Foo<Bar>"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "Foo<Bar>"); + } + + { + ClassName cn ("Foo<Bar,Fee>"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "Foo<Bar,Fee>"); + } + + { + ClassName cn ("Foo<Bar const,Fee>"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "Foo<const Bar,Fee>"); + } + + { + ClassName cn ("Foo<Bar const,Fee> const"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "Foo"); + assert (cn.fullName() == "const Foo<const Bar,Fee>"); + } + + { + ClassName cn ("A::B<C>::Foo<Bar,D<E> >"); + assert (cn.name() == "Foo"); + assert (cn.qualifiedName() == "A::B<C>::Foo"); + assert (cn.fullName() == "A::B<C>::Foo<Bar,D<E> >"); + } + + EXPECT_EXCEPTION (ClassName::ExcBadClassName, ClassName cn ("A>B")); +} + + +void test_eq() +{ + std::cout << "test_eq\n"; + + assert (ClassName ("A::B<int>") == ClassName ("A::B<int>")); + assert (ClassName ("A::B<int>") != ClassName ("X::B<int>")); + assert (ClassName ("A::B<int>") != ClassName ("A::B<i,nt>")); + assert (ClassName ("A::B<int>") != ClassName ("A::B<int>::C")); + + assert (ClassName ("A::B<int>") != ClassName ("A::B<const int>")); + assert (ClassName ("A::B<const int>") == ClassName ("A::B<const int>")); +} + + +void test_match() +{ + std::cout << "test_match\n"; + + ClassName pat1 ("A::B<int>"); + ClassName pat2 ("std::vector<$T, std::allocator<$T> >"); + + ClassName::match_t matches; + assert (pat1.match (pat1, matches)); + assert (matches.size() == 0); + assert (!ClassName ("A::B<float>").match (pat1, matches)); + + assert (ClassName ("std::vector<int, std::allocator<int> >").match + (pat2, matches)); + assert (matches.size() == 1); + assert (matches["T"].fullName() == "int"); + + assert (ClassName ("std::vector<A::B<C>, std::allocator<A::B<C> > >").match + (pat2, matches)); + assert (matches.size() == 1); + assert (matches["T"].fullName() == "A::B<C>"); + + ClassName pat3 ("A::B<$T>"); + ClassName pat4 ("A::B<const $T>"); + + assert (ClassName ("A::B<int>").match (pat3, matches)); + assert (matches["T"].fullName() == "int"); + assert (ClassName ("A::B<const int>").match (pat3, matches)); + assert (matches["T"].fullName() == "const int"); + assert (!ClassName ("A::B<int>").match (pat4, matches)); + assert (ClassName ("A::B<const int>").match (pat4, matches)); + assert (matches["T"].fullName() == "int"); +} + + +void test_subst() +{ + std::cout << "test_subst\n"; + + ClassName pat1 ("std::vector<$T, std::allocator<$T> >"); + ClassName rep1 ("std::vector<$T>"); + + ClassName cn1 ("std::vector<C::A<B>, std::allocator<C::A<B> > >"); + + ClassName::match_t matches; + assert (cn1.match (pat1, matches)); + ClassName cn1rep = rep1.substCopy (matches); + assert (cn1rep.fullName() == "std::vector<C::A<B> >"); + + matches.clear(); + matches["T"] = ClassName ("const int"); + ClassName cn2 ("Foo<$T>"); + cn2.subst (matches); + assert (cn2.fullName() == "Foo<const int>"); + ClassName cn3 ("Foo<const $T>"); + cn3.subst (matches); + assert (cn3.fullName() == "Foo<const int>"); + ClassName cn4 ("Foo<const $T>"); + matches["T"] = ClassName ("int"); + cn4.subst (matches); + assert (cn4.fullName() == "Foo<const int>"); + + ClassName cn5 ("Foo<$U>"); + EXPECT_EXCEPTION (ClassName::ExcMissingVariable, cn5.subst (matches)); +} + + +void test_rules() +{ + std::cout << "test_rules\n"; + + ClassName::Rules rules; + + rules.add ("std::vector<$T, std::allocator<$T> >", + "std::vector<$T>"); + rules.add ("std::vector<Foo>", "std::vector<Bar>"); + rules.add ("std::map<$K,$V, std::less<$K>, std::allocator<std::pair<const $K,$V> > >", + "std::map<$K,$V>"); + rules.add ("DataVector<$T, $B>", "DataVector<$T>"); + rules.add ("std::__1", "std"); + + assert (rules.size() == 5); + assert (rules.apply ("std::__1::foo") == + "std::foo"); + + assert (rules.apply ("std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > >") == + "std::vector<std::vector<int> >"); + + assert (rules.apply ("std::map<int, float, std::less<int>, std::allocator<std::pair<const int, float> > >") == + "std::map<int,float>"); + + assert (rules.apply ("DataVector<Foo, DataModel_detail::NoBase>") == + "DataVector<Foo>"); + + assert (rules.apply ("std::vector<Foo, std::allocator<Foo> >") == + "std::vector<Bar>"); +} + + +int main() +{ + test1(); + test_eq(); + test_match(); + test_subst(); + test_rules(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/CxxUtils.xml b/EDM/athena/Control/CxxUtils/test/CxxUtils.xml new file mode 100644 index 00000000..468f100d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/CxxUtils.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="CxxUtilsTest" type="makecheck" suite="Core"> + <package>Control/CxxUtils</package> + <timelimit>10</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/CxxUtils/test/FloatPacker_test.cxx b/EDM/athena/Control/CxxUtils/test/FloatPacker_test.cxx new file mode 100644 index 00000000..f9202e66 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/FloatPacker_test.cxx @@ -0,0 +1,312 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/FloatPacker_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2009, from earlier code. + * @brief Regression tests for FloatPacker. + */ + +#ifndef __APPLE__ + +#undef NDEBUG + +#include "CxxUtils/FloatPacker.h" +#include <iostream> +#include <cmath> +#include <cassert> +#include <ieee754.h> +#include <fenv.h> +#include <string.h> + + +using CxxUtils::FloatPacker; +using std::cout; +using std::abs; + + +const int ieee754_double_exponent_bits = 11; + + +bool bitwise_equal (double a, double b) +{ + return (memcmp (&a, &b, sizeof (a)) == 0); +} + + +bool almost_equal (double a, double b, int bits) +{ + return (abs ((a-b)/(a+b))) * (1<<bits) < 1; +} + + +void test1 () +{ + // Set up some special numbers for testing. + ieee754_double d; + d.d = 0; + d.ieee.negative = 1; + double neg_zero = d.d; + + d.d = 0; + d.ieee.exponent = (1<<ieee754_double_exponent_bits) - 1; + double infinity = d.d; + +#ifndef __alpha + // Can we handle denormals? + bool have_denormal = false; +#ifdef __FLT_HAS_DENORM__ + have_denormal = __FLT_HAS_DENORM__; +#endif +#ifdef __x86_64__ + { + fenv_t fenv; + fegetenv(&fenv); + if (fenv.__mxcsr & (1<<6)) // Test DAZ flag. + have_denormal = false; + } +#endif + + const double denormal = 3e-320; + const double denormal2 = 3072e-320; +#endif + + FloatPacker tf1 (12, 12); + + double unpacked; + FloatPacker::Packdest packed; + double out; + std::string err; + + unpacked = 0.125; + packed = tf1.pack (unpacked); + assert (packed == 0x100); + out = tf1.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = 0; + packed = tf1.pack (unpacked); + assert (packed == 0); + out = tf1.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = -0.125; + packed = tf1.pack (unpacked); + assert (packed == 0x900); + out = tf1.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = neg_zero; + packed = tf1.pack (unpacked); + assert (packed == 0x800); + out = tf1.unpack (packed); + assert (bitwise_equal (unpacked, out)); + assert (!tf1.errcheck (err)); + + FloatPacker tf2 (28, 24, 2, false); + + unpacked = 7.5; + packed = tf2.pack (unpacked); + assert (packed == 0x9e00000); + out = tf2.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = 7.5 + (0.5)/2/16/16/16/16/16; + packed = tf2.pack (unpacked); + assert (packed == 0x9e00001); + out = tf2.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = neg_zero; + packed = tf2.pack (unpacked); + assert (packed == 0); + out = tf2.unpack (packed); + assert (out == 0); + + unpacked = 0; + packed = tf2.pack (unpacked); + assert (packed == 0); + out = tf2.unpack (packed); + assert (bitwise_equal (unpacked, out)); + assert (!tf2.errcheck (err)); + + // This gets a warning. + unpacked = -1; + packed = tf2.pack (unpacked); + assert (packed == 0); + out = tf2.unpack (packed); + assert (bitwise_equal (0, out)); + assert (tf2.errcheck (err)); + assert (err == "Float overflow during packing: -1"); + assert (!tf2.errcheck (err)); + + // This gets a warning. + unpacked = infinity; + packed = tf2.pack (unpacked); + assert (packed == 0); + out = tf2.unpack (packed); + assert (bitwise_equal (0, out)); + assert (tf2.errcheck (err)); + + assert (err == "Bad float number: inf (0 7ff00000)"); + + // This gets a warning. + unpacked = 100000; + packed = tf2.pack (unpacked); + assert (packed == 0xfffffff); + out = tf2.unpack (packed); + assert (almost_equal (out, 512, 24)); + assert (tf2.errcheck (err)); + assert (err == "Float overflow during packing: 100000"); + + // Testing underflow to denormal. + unpacked = 0.5 / 32; + packed = tf2.pack (unpacked); + assert (packed == 0x1000000); + out = tf2.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked /= 2; + packed = tf2.pack (unpacked); + assert (packed == 0x0800000); + out = tf2.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked /= 2; + packed = tf2.pack (unpacked); + assert (packed == 0x0400000); + out = tf2.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + // Underflow to zero. + unpacked = 1e-50; + packed = tf2.pack (unpacked); + assert (packed == 0); + out = tf2.unpack (packed); + assert (bitwise_equal (0, out)); + assert (!tf2.errcheck (err)); + + FloatPacker tf3 (28, 12, 0, false); + +#ifndef __alpha + // Having problems with denormals on alpha. Just skip for now. + unpacked = denormal; + packed = tf3.pack (unpacked); + assert (packed == 0x7be1000); + out = tf3.unpack (packed); + assert (bitwise_equal (0, out)); + + unpacked = denormal2; + packed = tf3.pack (unpacked); + assert (packed == 0x7be4400); + out = tf3.unpack (packed); + if (have_denormal) + assert (almost_equal (out, unpacked, 3)); + else + assert (out == 0); +#endif + assert (!tf3.errcheck (err)); + + // Testing rounding. + FloatPacker tf6 (12, 8, 4, false, true); + + unpacked = 990./1024; // This doesn't get rounded. + packed = tf6.pack (unpacked); + assert (packed == 0x5ef); + out = tf6.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = 991./1024; // This does get rounded. + packed = tf6.pack (unpacked); + assert (packed == 0x5f0); + out = tf6.unpack (packed); + double tmp = 992./1024; + assert (bitwise_equal (tmp, out)); + + unpacked = 1023./1024; // Test mantissa overflowing after rounding. + packed = tf6.pack (unpacked); + assert (packed == 0x600); + out = tf6.unpack (packed); + tmp = 1.0; + assert (bitwise_equal (tmp, out)); + assert (!tf6.errcheck (err)); + + // Test an unpacking problem with npack==packdest_bits. + FloatPacker tf7 (32, 32, 0, false); + unpacked = 1. / 65536 / 65536; + packed = tf7.pack (unpacked); + assert (packed == 0x1); + out = tf7.unpack (packed); + assert (bitwise_equal (unpacked, out)); + assert (!tf7.errcheck (err)); + + // Test rounding during underflow_to_denormal. + FloatPacker tf8 (8, 8, 0, false, true); + unpacked = 0.5 + 1. / 256; + packed = tf8.pack (unpacked); + assert (packed == 0x81); + out = tf8.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = 0.5 + 1. / 512; + packed = tf8.pack (unpacked); + assert (packed == 0x81); + out = tf8.unpack (packed); + tmp = 0.5 + 1. / 256; + assert (bitwise_equal (tmp, out)); + assert (!tf8.errcheck (err)); + + // This gets a warning. + unpacked = 1023. / 1024; + packed = tf8.pack (unpacked); + assert (packed == 0xff); + d.d = unpacked; + assert (tf8.errcheck (err)); + assert (err == "Float overflow during packing: 0.999023"); + out = tf8.unpack (packed); + tmp = 255. / 256; + assert (bitwise_equal (tmp, out)); + assert (!tf8.errcheck (err)); + + // Test using bit 33 to control rounding. + FloatPacker tf9 (32, 32, 0, false, true); + unpacked = 0.5 + 1. / 65536 / 65536; + packed = tf9.pack (unpacked); + assert (packed == 0x80000001); + out = tf9.unpack (packed); + assert (bitwise_equal (unpacked, out)); + + unpacked = 0.5 + 1. / 65536 / 65536 / 2; + packed = tf9.pack (unpacked); + assert (packed == 0x80000001); + out = tf9.unpack (packed); + tmp = 0.5 + 1. / 65536 / 65536; + assert (bitwise_equal (tmp, out)); + assert (!tf9.errcheck (err)); + + // This gets a warning. + packed = 0xf654000; + out = tf3.unpack (packed); + assert (tf3.errcheck (err)); + assert (err == "Overflow while unpacking float; exponent: 30292"); + assert (std::isinf (out)); +} + + +#else + + +void test1() {} + + +#endif // not __APPLE__ + + +int main () +{ + test1 (); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/PackedArray_test.cxx b/EDM/athena/Control/CxxUtils/test/PackedArray_test.cxx new file mode 100644 index 00000000..ddcb1240 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/PackedArray_test.cxx @@ -0,0 +1,209 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PackedArray_test.cxx,v 1.2 2008-12-12 04:26:20 ssnyder Exp $ +/** + * @file CxxUtils/test/PackedArray_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2007 + * @brief Regression test for PackedArray class. + */ + +#undef NDEBUG + +#include "CxxUtils/PackedArray.h" +#include <cassert> +#include <vector> +#include <stdexcept> +#include <climits> +#include <cstdlib> + + +using CxxUtils::PackedArray; + + +void compare (const PackedArray& arr, const std::vector<int>& v) +{ + unsigned int bitmask = (1<<arr.bitsize()) - 1; + assert (arr.size() == v.size()); + for (size_t i = 0; i < arr.size(); i++) + assert (arr[i] == (v[i] & bitmask)); +} + + +void testit (PackedArray& arr) +{ + int bitsize = arr.bitsize(); + unsigned int bitmask = (1<<bitsize) - 1; + + std::vector<int> v; + + assert (arr.max_size() == v.max_size()); + + const PackedArray& carr = arr; + const std::vector<int>& cv = v; + assert (arr.empty()); + arr.assign (10, 17); + v.assign (10, 17); + compare (arr, v); + assert (!arr.empty()); + + arr.reserve (100); + int nper = sizeof (unsigned int) * CHAR_BIT; + assert (arr.capacity() == + (size_t)(((100 * bitsize) + nper-1) / nper) * nper / bitsize); + + unsigned int x; + for (int i=0; i < 100; i++) { + x = std::rand(); + v.push_back (x); + arr.push_back (x); + } + compare (arr, v); + + for (int i=0; i < 20; i++) { + v.pop_back(); + arr.pop_back(); + } + compare (arr, v); + + assert (carr.front() == (cv.front() & bitmask)); + assert (arr.front() == (v.front() & bitmask)); + x = std::rand(); + arr.front() = x; + v.front() = x; + assert (carr.front() == (cv.front() & bitmask)); + assert (arr.front() == (v.front() & bitmask)); + compare (arr, v); + + assert (carr.back() == (cv.back() & bitmask)); + assert (arr.back() == (v.back() & bitmask)); + x = std::rand(); + arr.back() = x; + v.back() = x; + assert (carr.back() == (cv.back() & bitmask)); + assert (arr.back() == (v.back() & bitmask)); + compare (arr, v); + + for (int i=0; i < 20; i++) { + int j = std::rand() % arr.size(); + assert (carr[j] == (cv[j] & bitmask)); + assert (arr[j] == (v[j] & bitmask)); + x = std::rand(); + arr[j] = x; + v[j] = x; + assert (carr[j] == (cv[j] & bitmask)); + assert (arr[j] == (v[j] & bitmask)); + } + compare (arr, v); + + for (int i=0; i < 20; i++) { + int j = std::rand() % arr.size(); + assert (carr.at(j) == (cv.at(j) & bitmask)); + assert (arr.at(j) == (v.at(j) & bitmask)); + x = std::rand(); + arr.at(j) = x; + v.at(j) = x; + assert (carr.at(j) == (cv.at(j) & bitmask)); + assert (arr.at(j) == (v.at(j) & bitmask)); + } + compare (arr, v); + + bool caught = false; + try { + arr.at (100000); + } + catch (const std::out_of_range& e) + { + caught = true; + } + assert (caught); + + caught = false; + try { + carr.at (100000); + } + catch (const std::out_of_range& e) + { + caught = true; + } + assert (caught); + + for (int i=0; i < 20; i++) { + int j = std::rand() % arr.size(); + assert (arr.get(j) == (v[j] & bitmask)); + x = std::rand(); + arr.set (j, x); + v[j] = x; + assert (arr.get(j) == (v[j] & bitmask)); + } + compare (arr, v); + + for (int i=0; i < 20; i++) { + int sz = arr.size(); + int inc = std::rand()%100 + 5; + arr.resize (sz + inc); + v.resize (sz + inc); + compare (arr, v); + assert (arr[sz + inc/2] == 0); + } + { + int sz = arr.size(); + arr.resize (sz-31); + v.resize (sz-31); + compare (arr, v); + } + for (int i=0; i < 20; i++) { + int sz = arr.size(); + int inc = std::rand()%100 + 5; + x = std::rand(); + arr.resize (sz + inc, x); + v.resize (sz + inc, x); + compare (arr, v); + assert (arr[sz + inc/2] == (x&bitmask)); + } + + arr.assign (10, 0); + v.assign (10, 0); + compare (arr, v); + + PackedArray arr2 (bitsize, 10, 0, arr.get_allocator()); + assert (arr2.size() == 10); + for (int i=0; i < 10; i++) + assert (arr2[i] == 0); + + x = std::rand(); + PackedArray arr3 (bitsize, 10, x); + assert (arr3.size() == 10); + for (int i=0; i < 10; i++) + assert (arr3[i] == (x & bitmask)); + + arr.swap (arr3); + assert (arr.size() == 10); + for (int i=0; i < 10; i++) + assert (arr[i] == (x & bitmask)); + compare (arr3, v); + + arr.clear(); + assert (arr.empty()); + assert (arr.size() == 0); +} + + +void test1() +{ + PackedArray arr (10); + testit (arr); + arr.set_bitsize (20); + testit (arr); + arr.set_bitsize (3); + testit (arr); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/PageAccessControl_test.cxx b/EDM/athena/Control/CxxUtils/test/PageAccessControl_test.cxx new file mode 100644 index 00000000..c144d0eb --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/PageAccessControl_test.cxx @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +#include <cassert> +#include <iostream> +#include <boost/pool/pool_alloc.hpp> +#include "CxxUtils/procmaps.h" +#include "CxxUtils/PageAccessControl.h" +// #define DEBUGIT 1 +using namespace std; +int main(void) { + cout << "*** PageAccessControl_test starts ***" <<endl; +#ifdef DEBUGIT + const bool DUMPMAPS(true); +#else + const bool DUMPMAPS(false); +#endif + procmaps pmaps(DUMPMAPS); + PageAccessControl pac(pmaps); + //protect a heap object + int* pi= new int(2); + void* pv = malloc(10); + assert(pac.forbidPage(pi)); + //FIXME assert(pac.forbidPage(pv, 10)); + //assert(pac.protectPage(pv, 10, PROT_READ)); + assert(pac.restorePageProt(pi)); + //assert(pac.restorePageProt(pv)); + cout << "accessing restored pointer " << *pi << endl; + + + +//make valgrind happy + delete pi; + free(pv); + boost::singleton_pool<boost::pool_allocator_tag, sizeof(procmaps::Entry)>::release_memory(); + + cout << "*** PageAccessControl_test OK ***" <<endl; + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/SEGVHandler_test.cxx b/EDM/athena/Control/CxxUtils/test/SEGVHandler_test.cxx new file mode 100644 index 00000000..8e9ef626 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/SEGVHandler_test.cxx @@ -0,0 +1,87 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +#include <iostream> +#include <signal.h> /*sigaction*/ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string> +#include <utility> /* pair */ +#include <cassert> +#include "CxxUtils/procmaps.h" +#include "CxxUtils/PageAccessControl.h" +#include "CxxUtils/PtrAccessSEGVHandler.h" +#include "CxxUtils/cPtrAccessSEGVHandler.h" + +using namespace std; + +int main(void) { + cout << "*** SEGVHandler_test starts ***" <<endl; + int rc=0; + struct sigaction sa, stdSEGV; + (void)sigaction(SIGSEGV,NULL,&stdSEGV); + sa = stdSEGV; + // sa.sa_sigaction=trapReads; + procmaps p; + PageAccessControl pac(p); + PtrAccessSEGVHandler h(pac); + setPtrAccessSEGVHandler(&h); + sa.sa_sigaction= cPtrAccessSEGVHandler; + sa.sa_flags=SA_SIGINFO; + rc=sigaction(SIGSEGV,&sa,NULL); + printf("sigaction installing handler returned %d\n",rc); + + size_t pagesz = getpagesize(); + char* pool = new char[4*pagesz]; + + // int *pInt=(int*)0x8000; + // int *pInt=(int*)&cPtrAccessSEGVHandler; + int *pInt=new (pool + pagesz) int(11); + printf("@pInt=%p\n",(void*)pInt); + // delete pInt; + string *pString(new (pool + 2*pagesz) string("bar")); + printf("@pString=%p\n",(void*)pString); + + pair<int,double>* pPair(new (pool + 3*pagesz) pair<int,double>(1,2.0)); + printf("@pPair=%p\n",(void*)pPair); + //now protect the pages. + assert(pac.forbidPage(pInt)); + assert(pac.forbidPage(pString)); + assert(pac.forbidPage(pPair)); + // p.loadMaps(true); //dump new memory map + //new int(12); + fflush (stdout); + //let's get some SEGVs + //rkprintf("try to read 12\n"); fflush(stdout); + printf("accessing pInt %d\n",*pInt); + printf("reading again from pInt %d\n",*pInt); + printf("try to write 33\n"); + *pInt=33; + printf("read %d\n",*pInt); + // String may have been allowed by prev. reads. Lock it down again. + assert(pac.forbidPage(pString)); + std::string strtmp = *pString; + cout << "reading from string " << strtmp << endl; + cout << "reading again from string " << *pString << endl; + double xsecond = pPair->second; + cout << "reading double from pair " << xsecond << endl; + cout << "reading again double from pair " << pPair->second << endl; + + //restore default/old handler + (void)sigaction(SIGSEGV,&stdSEGV,NULL); + printf("try to read 33\n"); + printf("read %d\n",*pInt); + PtrAccessSEGVHandler::const_iterator i(h.beginAccessedPtrs()), + e(h.endAccessedPtrs()); + cout << "accessed ptrs" << endl; + while (i != e) { + cout << '@' << hex << *i++ << endl; + } + pString->~string(); + delete [] pool; + cout << "*** SEGVHandler_test OK ***" <<endl; + return rc; +} diff --git a/EDM/athena/Control/CxxUtils/test/StrFormat_test.cxx b/EDM/athena/Control/CxxUtils/test/StrFormat_test.cxx new file mode 100644 index 00000000..5bb8e39b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/StrFormat_test.cxx @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StrFormat_test.cxx 599890 2014-06-02 13:52:58Z ssnyder $ +/** + * @file CxxUtils/test/StrFormat_test.cxx + * @author Sebastien Binet + * @date Jun 2010 + * @brief Regression tests for StrFormat + */ + + +#undef NDEBUG + + +#include "CxxUtils/StrFormat.h" +#include <iostream> +#include <cassert> +#include <stdexcept> + +using namespace std; +using namespace CxxUtils; + +#define MYASSERT(chk, expected) \ + do { \ + if (chk != expected) { \ + std::cerr << "**error**:" << __LINE__ << ": " \ + << "chk != expected\n" \ + << "** chk: [" << chk << "]\n" \ + << "** exp: [" << expected << "]\n"; \ + assert(false); \ + } \ + else if (0) { \ + std::cout << "test ok (line:" << __LINE__ \ + << ") str = [" << chk << "]\n"; \ + } \ +} while (0) + +void test1() +{ + { + std::string s = strformat("%%"); + MYASSERT(s, "%"); + } + { + std::string s = strformat("%d", 1); + MYASSERT(s, "1"); + } + { + std::string s = strformat("%i", 1); + MYASSERT(s, "1"); + } + { + std::string s = strformat("%u", 0); + MYASSERT(s, "0"); + } + { + std::string s = strformat("%0.1f", 1.); + MYASSERT(s, "1.0"); + } + { + std::string s = strformat("%0.1f", 1.); + MYASSERT(s, "1.0"); + } + { + std::string s = strformat("%8.3f", 1.); + MYASSERT(s, " 1.000"); + } + { + std::string s = strformat("%8.3e", 1.); + MYASSERT(s, "1.000e+00"); + } + { + std::string s = strformat("%8.3E", 1.); + MYASSERT(s, "1.000E+00"); + } + { + std::string tt = "foo"; + std::string s = strformat("%s", tt.c_str()); + MYASSERT(s, "foo"); + MYASSERT(s, tt); + } + { + std::string s = strformat("%s", "foo"); + MYASSERT(s, "foo"); + } +} + +int main() +{ + //std::cout << "=== strformat_test ===\n"; + test1(); + //std::cout << "=== strformat_test === [done]" << std::endl; + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/bitscan_test.cxx b/EDM/athena/Control/CxxUtils/test/bitscan_test.cxx new file mode 100644 index 00000000..07cf00ac --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/bitscan_test.cxx @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/test/bitscan_test.cxx + * @author Frank Winklmeier + * @brief Regression test for bitscan + */ + +#undef NDEBUG +#include "CxxUtils/bitscan.h" +#include <iostream> +#include <vector> +#include <bitset> + +using namespace CxxUtils; + +/** + * On GNU/CLANG this will compare the compiler builtin with the portable algorithm + */ +template <typename T> +int check(const std::vector<T>& v) +{ + int error = 0; + for (auto t : v) { + unsigned lz1 = count_leading_zeros(t); + unsigned lz2 = detail::clz_portable(t); + unsigned tz1 = count_trailing_zeros(t); + unsigned tz2 = detail::ctz_portable(t); + + bool ok = (lz1==lz2) && (tz1==tz2); + if (!ok) ++error; + std::cout << std::bitset<sizeof(T)*8>(t) << " " + << lz1 << "=" << lz2 << " " + << tz1 << "=" << tz2 + << (ok ? "" : " ERROR") + << std::endl; + } + return error; +} + + +int main() +{ + // Some test data for 32 and 64 bit + std::vector<unsigned> t1 = {0x0, 0x1, 0x80000000, + 0xcbaa3f00, 0xff1c2301, 0x1aff04}; + + std::vector<unsigned long> t2 = {0x0, 0x1, 0x8000000000000000, + 0x12345678cbaa3f00, 0x10000000, 0x1000000000}; + + int rc(0); + rc += check(t1); + std::cout << std::endl; + rc += check(t2); + + return rc; +} diff --git a/EDM/athena/Control/CxxUtils/test/copy_bounded_test.cxx b/EDM/athena/Control/CxxUtils/test/copy_bounded_test.cxx new file mode 100644 index 00000000..22dcdfef --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/copy_bounded_test.cxx @@ -0,0 +1,147 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/copy_bounded_test.cxx + * @author sss + * @date March 2013 + * @brief Regression tests for copy_bounded + */ + + +#undef NDEBUG + +// Disable this test entirely for the xAOD standalone builds: +#ifndef XAOD_STANDALONE + +#include "CxxUtils/copy_bounded.h" +#include "boost/foreach.hpp" +#include "boost/range/iterator_range.hpp" +#include "boost/range/algorithm/fill.hpp" +#include <vector> +#include <list> +#include <cassert> +#include <iostream> + + +struct arange +{ + static const int N = 10; + int x[N]; + typedef int* iterator; + typedef const int* const_iterator; + typedef int value_type; + iterator begin() { return x; } + iterator end() { return x + N; } + const_iterator begin() const { return x; } + const_iterator end() const { return x + N; } + + arange(int) :x() {} +}; + + + +template <class InputRange, class OutputRange> +void test1b (InputRange& input, OutputRange& output) +{ + typedef typename boost::range_iterator<InputRange>::type InputIterator; + typedef typename boost::range_iterator<OutputRange>::type OutputIterator; + InputIterator begi = boost::begin(input); + InputIterator endi = boost::end(input); + OutputIterator bego = boost::begin(output); + OutputIterator endo = boost::end(output); + + typedef typename std::iterator_traits<InputIterator>::value_type value_type; + + InputIterator midi = begi; + std::advance (midi, 5); + + OutputIterator mido = bego; + std::advance (mido, 5); + + boost::iterator_range<InputIterator> rangei (begi, midi); + boost::iterator_range<OutputIterator> rangeo (bego, mido); + + int i = 0; + BOOST_FOREACH (value_type& it, input) + it = i++; + + boost::range::fill (output, 0); + CxxUtils::copy_bounded (begi, endi, bego, mido); + i = 0; + BOOST_FOREACH (value_type& it, output) + assert (it == (i < 5 ? i++ : 0)); + + boost::range::fill (output, 0); + CxxUtils::copy_bounded (input, rangeo); + i = 0; + BOOST_FOREACH (value_type& it, output) + assert (it == (i < 5 ? i++ : 0)); + + boost::range::fill (output, 0); + CxxUtils::copy_bounded (begi, midi, bego, endo); + i = 0; + BOOST_FOREACH (value_type& it, output) + assert (it == (i < 5 ? i++ : 0)); + + boost::range::fill (output, 0); + CxxUtils::copy_bounded (rangei, output); + i = 0; + BOOST_FOREACH (value_type& it, output) + assert (it == (i < 5 ? i++ : 0)); + + boost::range::fill (output, 0); + CxxUtils::copy_bounded (begi, endi, bego, endo); + i = 0; + BOOST_FOREACH (value_type& it, output) + assert (it == i++); + + boost::range::fill (output, 0); + CxxUtils::copy_bounded (input, output); + i = 0; + BOOST_FOREACH (value_type& it, output) + assert (it == i++); +} + +template <class Cont1, class Cont2=Cont1> +struct test1a +{ + static void test() + { + Cont1 c1 (10); + Cont2 c2 (10); + test1b (c1, c2); + } +}; + + +void test1() +{ + std::cout << "test1\n"; + test1a<std::vector<int> >::test(); + test1a<std::list<int> >::test(); + test1a<std::vector<int>, std::list<int> >::test(); + test1a<std::list<int>, std::vector<int> >::test(); + + test1a<arange>::test(); + test1a<arange, std::list<int> >::test(); + test1a<arange, std::vector<int> >::test(); + test1a<std::list<int>, arange>::test(); + test1a<std::vector<int>, arange>::test(); +} + +#else + +void test1() {} + +#endif // not XAOD_STANDALONE + +int main() +{ + test1(); + return 0; +} + + diff --git a/EDM/athena/Control/CxxUtils/test/copyif_test.cxx b/EDM/athena/Control/CxxUtils/test/copyif_test.cxx new file mode 100644 index 00000000..fd1a5c46 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/copyif_test.cxx @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: copyif_test.cxx,v 1.1 2009-03-11 11:06:46 binet Exp $ +/** + * @file CxxUtils/test/copyif_test.cxx + * @author Sebastien Binet + * @date March 2009 + * @brief Regression tests for copy_if + */ + + +#undef NDEBUG + + +#include "CxxUtils/algorithms.h" +#include <cassert> +#include <vector> +#include <algorithm> + +using namespace std; + +namespace { + const std::size_t IMAX = 10; +} + +template<typename T> +struct greater_than +{ + T cut; + greater_than(T cut) : cut(cut) {} + + bool + operator()(T x) { return x>cut; } +}; + +void test1() +{ + std::vector<std::size_t> in(IMAX); + for (std::size_t i = 0; i!=IMAX; ++i){ + in[i] = i; + } + for (std::size_t i = 0; i!=IMAX; ++i){ + assert(in[i] == i); + } + + std::vector<std::size_t> out; + CxxUtils::copy_if(in.begin(), in.end(), + std::back_inserter(out), + greater_than<std::size_t>(4)); + assert(out.size()==5); + assert(out[0]==5); + assert(out[1]==6); + assert(out[2]==7); + assert(out[3]==8); + assert(out[4]==9); +} + +void test2() +{ + const std::size_t in[IMAX] = {0, 1,2,3,4,5,6,7,8,9}; + for (std::size_t i = 0; i!=IMAX; ++i){ + assert(in[i] == i); + } + + std::vector<std::size_t> out; + CxxUtils::copy_if(in, in+IMAX, + std::back_inserter(out), + greater_than<std::size_t>(4)); + assert(out.size()==5); + assert(out[0]==5); + assert(out[1]==6); + assert(out[2]==7); + assert(out[3]==8); + assert(out[4]==9); +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/exctrace1_test.cxx b/EDM/athena/Control/CxxUtils/test/exctrace1_test.cxx new file mode 100644 index 00000000..193dec4d --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/exctrace1_test.cxx @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/test/exctrace2_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009 + * @brief Test trace backs for caught exceptions --- without the collector. + */ + + +#include <cstdio> +#include <stdexcept> +#include "CxxUtils/exctrace.h" + +void bar() +{ + throw std::logic_error ("yo mama"); +} + +void fee() +{ + bar(); +} + +void foo() +{ + try { + fee(); + } + catch (std::exception& e) { + CxxUtils::exctrace (e); + } +} + + +int main() +{ + foo(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/exctrace2_test.cxx b/EDM/athena/Control/CxxUtils/test/exctrace2_test.cxx new file mode 100644 index 00000000..577c6805 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/exctrace2_test.cxx @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/test/exctrace2_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009 + * @brief Test trace backs for caught exceptions --- using the collector. + */ + + +#include <string> +#include "stdlib.h" + +int main (int /*argc*/, char** argv) +{ + std::string cmd = argv[0]; + std::string::size_type pos = cmd.rfind ('/'); + if (pos != std::string::npos) + cmd = cmd.substr (0, pos+1); + else + cmd = "./"; + cmd = "LD_PRELOAD=libexctrace_collector.so " + cmd; + cmd += "exctrace1_test.exe"; + + system (cmd.c_str()); + + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/expect_exception.icc b/EDM/athena/Control/CxxUtils/test/expect_exception.icc new file mode 100644 index 00000000..15ca7186 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/expect_exception.icc @@ -0,0 +1,24 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/expect_exception.icc + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2014 + * @brief Helper to check that an exception is thrown. + */ + +#define EXPECT_EXCEPTION(EXC, CODE) do { \ + bool caught = false; \ + try { \ + CODE; \ + } \ + catch (const EXC&) { \ + caught = true; \ + } \ + assert (caught); \ +} while(0) + + diff --git a/EDM/athena/Control/CxxUtils/test/fpcompare_test.cxx b/EDM/athena/Control/CxxUtils/test/fpcompare_test.cxx new file mode 100644 index 00000000..90574ae8 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/fpcompare_test.cxx @@ -0,0 +1,148 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +/** + * @file CxxUtils/test/fpcompare_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2008 + * @brief Regression tests for the fpcompare header. + */ + + +#include "CxxUtils/fpcompare.h" +#include <cmath> +#include <cassert> +#include <stdio.h> + + +struct tester +{ + tester (double x) : m_x (x) {} + double pt() const; + double ptf() const { return pt(); } + double m_x; +}; + + +double tester::pt() const +{ + return m_x * (1. / std::cosh(1.9025873924597605)); +} + + +void test1 (const tester* a, const tester* b, const tester* c) +{ + using namespace CxxUtils::fpcompare; + + assert ( equal (a->pt(), a->pt()) ); + assert ( ! equal (a->pt(), c->pt()) ); + + assert ( ! greater (a->pt(), b->pt()) ); // FAILX + assert ( greater (c->pt(), b->pt()) ); + assert ( ! greater (b->pt(), c->pt()) ); + + assert ( ! less (a->pt(), b->pt()) ); + assert ( less (a->pt(), c->pt()) ); + assert ( ! less (c->pt(), a->pt()) ); + + assert ( greater_equal (a->pt(), b->pt()) ); + assert ( greater_equal (c->pt(), b->pt()) ); + assert ( ! greater_equal (b->pt(), c->pt()) ); + + assert ( less_equal (a->pt(), b->pt()) ); // FAILX + assert ( less_equal (a->pt(), c->pt()) ); + assert ( ! less_equal (c->pt(), a->pt()) ); + + //******************************************************** + + assert ( equal (a->ptf(), a->ptf()) ); + assert ( ! equal (a->ptf(), c->ptf()) ); + + assert ( ! greater (a->ptf(), b->ptf()) ); + assert ( greater (c->ptf(), b->ptf()) ); + assert ( ! greater (b->ptf(), c->ptf()) ); + + assert ( ! less (a->ptf(), b->ptf()) ); + assert ( less (a->ptf(), c->ptf()) ); + assert ( ! less (c->ptf(), a->ptf()) ); + + assert ( greater_equal (a->ptf(), b->ptf()) ); + assert ( greater_equal (c->ptf(), b->ptf()) ); + assert ( ! greater_equal (b->ptf(), c->ptf()) ); + + assert ( less_equal (a->ptf(), b->ptf()) ); + assert ( less_equal (a->ptf(), c->ptf()) ); + assert ( ! less_equal (c->ptf(), a->ptf()) ); +} + + +void test2 (const tester* a, const tester* b, const tester* c) +{ + using namespace CxxUtils::fpcompare_fn; + + equal eq; + assert ( eq (a->pt(), a->pt()) ); + assert ( ! eq (a->pt(), c->pt()) ); + + greater gt; + assert ( ! gt (a->pt(), b->pt()) ); // FAILX + assert ( gt (c->pt(), b->pt()) ); + assert ( ! gt (b->pt(), c->pt()) ); + + less lt; + assert ( ! lt (a->pt(), b->pt()) ); + assert ( lt (a->pt(), c->pt()) ); + assert ( ! lt (c->pt(), a->pt()) ); + + greater_equal ge; + assert ( ge (a->pt(), b->pt()) ); + assert ( ge (c->pt(), b->pt()) ); + assert ( ! ge (b->pt(), c->pt()) ); + + less_equal le; + assert ( le (a->pt(), b->pt()) ); // FAILX + assert ( le (a->pt(), c->pt()) ); + assert ( ! le (c->pt(), a->pt()) ); + + //******************************************************** + + equalf eqf; + assert ( eqf (a->ptf(), a->ptf()) ); + assert ( ! eqf (a->ptf(), c->ptf()) ); + + greaterf gtf; + assert ( ! gtf (a->ptf(), b->ptf()) ); + assert ( gtf (c->ptf(), b->ptf()) ); + assert ( ! gtf (b->ptf(), c->ptf()) ); + + lessf ltf; + assert ( ! ltf (a->ptf(), b->ptf()) ); + assert ( ltf (a->ptf(), c->ptf()) ); + assert ( ! ltf (c->ptf(), a->ptf()) ); + + greater_equalf gef; + assert ( gef (a->ptf(), b->ptf()) ); + assert ( gef (c->ptf(), b->ptf()) ); + assert ( ! gef (b->ptf(), c->ptf()) ); + + less_equalf lef; + assert ( lef (a->ptf(), b->ptf()) ); + assert ( lef (a->ptf(), c->ptf()) ); + assert ( ! lef (c->ptf(), a->ptf()) ); +} + + +int main() +{ + // chosen so that a->pt() > a->pt is true when compiled + // with optimization using x87 instructions. + // The assertions marked with FAILX above fail in that case + // if the workaround is not operative. + tester a (441849.03125); + tester c (841849.03125); + test1 (&a, &a, &c); + test2 (&a, &a, &c); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/hashtable_test.cxx b/EDM/athena/Control/CxxUtils/test/hashtable_test.cxx new file mode 100644 index 00000000..9ae0a56b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/hashtable_test.cxx @@ -0,0 +1,1169 @@ +#undef NDEBUG +/** + * @file CxxUtils/test/hashtable_test.cxx + * @author scott snyder <snyder@bnl.gov>, copied from gcc4. + * @date Apr, 2007 + * @brief Regression tests for TR1 hashtable class. Adapted from + * the tests in gcc4. + */ + +// Copyright (C) 2005 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// 6.3 Unordered associative containers + +#include "CxxUtils/unordered_set.h" +#include "CxxUtils/unordered_map.h" +#include <string> +#include <cassert> + +#define VERIFY assert + + template<template<typename, typename> class Relationship, + typename Type1, typename Type2> + bool + test_relationship(bool value) + { + bool ret = true; + ret &= Relationship<Type1, Type2>::value == value; + ret &= Relationship<Type1, Type2>::type::value == value; + return ret; + } + + /// @brief relationships between types [4.6]. + template<typename, typename> + struct is_same + : public CxxUtils_Internal::false_type { }; + + template<typename _Tp> + struct is_same<_Tp, _Tp> + : public CxxUtils_Internal::true_type { }; + + + +// libstdc++/23053 +void test01() +{ + SG::unordered_set<int> s; + + const SG::unordered_set<int> &sref = s; + + sref.find(27); +} + +// libstdc++/23465 +void test02() +{ + bool test __attribute__((unused)) = true; + + for (float lf = 0.1f; lf < 101.0f; lf *= 10.0f) + for (int size = 1; size <= 6561; size *= 3) + { + SG::unordered_set<int> us1, us2; + typedef SG::unordered_set<int>::local_iterator local_iterator; + typedef SG::unordered_set<int>::size_type size_type; + + us1.max_load_factor(lf); + + for (int i = 0; i < size; ++i) + us1.insert(i); + + us2 = us1; + + VERIFY( us2.size() == us1.size() ); + VERIFY( us2.bucket_count() == us1.bucket_count() ); + + for (size_type b = 0; b < us1.bucket_count(); ++b) + { + size_type cnt = 0; + for (local_iterator it1 = us1.begin(b), it2 = us2.begin(b); + it1 != us1.end(b) && it2 != us2.end(b); ++it1, ++it2) + { + VERIFY( *it1 == *it2 ); + ++cnt; + } + VERIFY( cnt == us1.bucket_size(b) ); + } + } +} + +// libstdc++/24054 +void test03() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_multiset<std::string> Set; + + Set s; + + s.insert("etaoin"); + s.insert("etaoin"); + s.insert("etaoin"); + s.insert("shrdlu"); + + VERIFY( s.erase("") == 0 ); + VERIFY( s.size() == 4 ); + + VERIFY( s.erase("etaoin") == 3 ); + VERIFY( s.size() == 1 ); + + VERIFY( s.erase("shrdlu") == 1 ); + VERIFY( s.size() == 0 ); +} + +// libstdc++/24064 +void test04() +{ + bool test __attribute__((unused)) = true; + + using namespace std; + using namespace SG; + + unordered_map<int, char, SG::hash<int>, equal_to<int>, + allocator<pair<const int, char> >, true> m; + + for (int i = 0; i < 1000; ++i) + m[i] = static_cast<char> ('0' + i % 9); + + for (int i = 0; i < 1000; ++i) + VERIFY( ++m.find(i)->second == '1' + i % 9 ); +} + +// libstdc++/26127 +void test05() +{ + SG::unordered_set<int> s; + + s.bucket(42); + (void)s.key_eq(); + (void)s.max_load_factor(); +} + +// libstdc++/26132 +void test06() +{ + bool test __attribute__((unused)) = true; + + for (float lf = 1.0f; lf < 101.0f; lf *= 10.0f) + for (int size = 1; size <= 6561; size *= 3) + { + SG::unordered_set<int> us1; + typedef SG::unordered_set<int>::size_type size_type; + + us1.max_load_factor(10.0); + + for (int i = 0; i < size; ++i) + us1.insert(i); + + us1.max_load_factor(lf); + double imaxload __attribute__((unused)) = 1. / us1.max_load_factor(); + + for (int i = 1; i <= 6561; i *= 81) + { + const size_type n = size * 81 / i; + us1.rehash(n); + VERIFY( us1.bucket_count() > + static_cast<float>(us1.size()) * imaxload ); + VERIFY( us1.bucket_count() >= n ); + } + } +} + +// libstdc++/24061 +void test07() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_map<std::string, int> Map; + typedef Map::iterator iterator; + typedef Map::const_iterator const_iterator; + typedef Map::value_type value_type; + + Map m1; + + m1.insert(value_type("all the love in the world", 1)); + m1.insert(value_type("you know what you are?", 2)); + m1.insert(value_type("the collector", 3)); + m1.insert(value_type("the hand that feeds", 4)); + m1.insert(value_type("love is not enough", 5)); + m1.insert(value_type("every day is exactly the same", 6)); + m1.insert(value_type("with teeth", 7)); + m1.insert(value_type("only", 8)); + m1.insert(value_type("getting smaller", 9)); + m1.insert(value_type("sunspots", 10)); + VERIFY( m1.size() == 10 ); + + iterator it1 = m1.begin(); + ++it1; + iterator it2 = it1; + ++it2; + iterator it3 = m1.erase(it1); + VERIFY( m1.size() == 9 ); + VERIFY( it3 == it2 ); + VERIFY( *it3 == *it2 ); + + iterator it4 = m1.begin(); + ++it4; + ++it4; + ++it4; + iterator it5 = it4; + ++it5; + ++it5; + iterator it6 = m1.erase(it4, it5); + VERIFY( m1.size() == 7 ); + VERIFY( it6 == it5 ); + VERIFY( *it6 == *it5 ); + + const_iterator it7 = m1.begin(); + ++it7; + ++it7; + ++it7; + const_iterator it8 = it7; + ++it8; + const_iterator it9 = m1.erase(it7); + VERIFY( m1.size() == 6 ); + VERIFY( it9 == it8 ); + VERIFY( *it9 == *it8 ); + + const_iterator it10 = m1.begin(); + ++it10; + const_iterator it11 = it10; + ++it11; + ++it11; + ++it11; + ++it11; + const_iterator it12 = m1.erase(it10, it11); + VERIFY( m1.size() == 2 ); + VERIFY( it12 == it11 ); + VERIFY( *it12 == *it11 ); + VERIFY( ++it12 == m1.end() ); + + iterator it13 = m1.erase(m1.begin(), m1.end()); + VERIFY( m1.size() == 0 ); + VERIFY( it13 == it12 ); + VERIFY( it13 == m1.begin() ); +} + +// libstdc++/24061 +void test08() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_multimap<std::string, int> Mmap; + typedef Mmap::iterator iterator; + typedef Mmap::const_iterator const_iterator; + typedef Mmap::value_type value_type; + + Mmap mm1; + + mm1.insert(value_type("all the love in the world", 1)); + mm1.insert(value_type("you know what you are?", 2)); + mm1.insert(value_type("the collector", 3)); + mm1.insert(value_type("the hand that feeds", 4)); + mm1.insert(value_type("love is not enough", 5)); + mm1.insert(value_type("every day is exactly the same", 6)); + mm1.insert(value_type("with teeth", 7)); + mm1.insert(value_type("only", 8)); + mm1.insert(value_type("getting smaller", 9)); + mm1.insert(value_type("sunspots", 10)); + + mm1.insert(value_type("you know what you are?", 5)); + mm1.insert(value_type("the collector", 6)); + mm1.insert(value_type("the hand that feeds", 7)); + VERIFY( mm1.size() == 13 ); + + iterator it1 = mm1.begin(); + ++it1; + iterator it2 = it1; + ++it2; + iterator it3 = mm1.erase(it1); + VERIFY( mm1.size() == 12 ); + VERIFY( it3 == it2 ); + VERIFY( *it3 == *it2 ); + + iterator it4 = mm1.begin(); + ++it4; + ++it4; + ++it4; + iterator it5 = it4; + ++it5; + ++it5; + iterator it6 = mm1.erase(it4, it5); + VERIFY( mm1.size() == 10 ); + VERIFY( it6 == it5 ); + VERIFY( *it6 == *it5 ); + + const_iterator it7 = mm1.begin(); + ++it7; + ++it7; + ++it7; + const_iterator it8 = it7; + ++it8; + const_iterator it9 = mm1.erase(it7); + VERIFY( mm1.size() == 9 ); + VERIFY( it9 == it8 ); + VERIFY( *it9 == *it8 ); + + const_iterator it10 = mm1.begin(); + ++it10; + const_iterator it11 = it10; + ++it11; + ++it11; + ++it11; + ++it11; + const_iterator it12 = mm1.erase(it10, it11); + VERIFY( mm1.size() == 5 ); + VERIFY( it12 == it11 ); + VERIFY( *it12 == *it11 ); + + iterator it13 = mm1.erase(mm1.begin(), mm1.end()); + VERIFY( mm1.size() == 0 ); + VERIFY( it13 == mm1.end() ); + VERIFY( it13 == mm1.begin() ); +} + +// libstdc++/24061 +void test09() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_multiset<std::string> Mset; + typedef Mset::iterator iterator; + typedef Mset::const_iterator const_iterator; + + Mset ms1; + + ms1.insert("all the love in the world"); + ms1.insert("you know what you are?"); + ms1.insert("the collector"); + ms1.insert("the hand that feeds"); + ms1.insert("love is not enough"); + ms1.insert("every day is exactly the same"); + ms1.insert("with teeth"); + ms1.insert("only"); + ms1.insert("getting smaller"); + ms1.insert("sunspots"); + + ms1.insert("the hand that feeds"); + ms1.insert("love is not enough"); + ms1.insert("every day is exactly the same"); + VERIFY( ms1.size() == 13 ); + + iterator it1 = ms1.begin(); + ++it1; + iterator it2 = it1; + ++it2; + iterator it3 = ms1.erase(it1); + VERIFY( ms1.size() == 12 ); + VERIFY( it3 == it2 ); + VERIFY( *it3 == *it2 ); + + iterator it4 = ms1.begin(); + ++it4; + ++it4; + ++it4; + iterator it5 = it4; + ++it5; + ++it5; + iterator it6 = ms1.erase(it4, it5); + VERIFY( ms1.size() == 10 ); + VERIFY( it6 == it5 ); + VERIFY( *it6 == *it5 ); + + const_iterator it7 = ms1.begin(); + ++it7; + ++it7; + ++it7; + const_iterator it8 = it7; + ++it8; + const_iterator it9 = ms1.erase(it7); + VERIFY( ms1.size() == 9 ); + VERIFY( it9 == it8 ); + VERIFY( *it9 == *it8 ); + + const_iterator it10 = ms1.begin(); + ++it10; + const_iterator it11 = it10; + ++it11; + ++it11; + ++it11; + ++it11; + const_iterator it12 = ms1.erase(it10, it11); + VERIFY( ms1.size() == 5 ); + VERIFY( it12 == it11 ); + VERIFY( *it12 == *it11 ); + + iterator it13 = ms1.erase(ms1.begin(), ms1.end()); + VERIFY( ms1.size() == 0 ); + VERIFY( it13 == ms1.end() ); + VERIFY( it13 == ms1.begin() ); +} + +// libstdc++/24061 +void test10() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_set<std::string> Set; + typedef Set::iterator iterator; + typedef Set::const_iterator const_iterator; + + Set s1; + + s1.insert("all the love in the world"); + s1.insert("you know what you are?"); + s1.insert("the collector"); + s1.insert("the hand that feeds"); + s1.insert("love is not enough"); + s1.insert("every day is exactly the same"); + s1.insert("with teeth"); + s1.insert("only"); + s1.insert("getting smaller"); + s1.insert("sunspots"); + VERIFY( s1.size() == 10 ); + + iterator it1 = s1.begin(); + ++it1; + iterator it2 = it1; + ++it2; + iterator it3 = s1.erase(it1); + VERIFY( s1.size() == 9 ); + VERIFY( it3 == it2 ); + VERIFY( *it3 == *it2 ); + + iterator it4 = s1.begin(); + ++it4; + ++it4; + ++it4; + iterator it5 = it4; + ++it5; + ++it5; + iterator it6 = s1.erase(it4, it5); + VERIFY( s1.size() == 7 ); + VERIFY( it6 == it5 ); + VERIFY( *it6 == *it5 ); + + const_iterator it7 = s1.begin(); + ++it7; + ++it7; + ++it7; + const_iterator it8 = it7; + ++it8; + const_iterator it9 = s1.erase(it7); + VERIFY( s1.size() == 6 ); + VERIFY( it9 == it8 ); + VERIFY( *it9 == *it8 ); + + const_iterator it10 = s1.begin(); + ++it10; + const_iterator it11 = it10; + ++it11; + ++it11; + ++it11; + ++it11; + const_iterator it12 = s1.erase(it10, it11); + VERIFY( s1.size() == 2 ); + VERIFY( it12 == it11 ); + VERIFY( *it12 == *it11 ); + VERIFY( ++it12 == s1.end() ); + + iterator it13 = s1.erase(s1.begin(), s1.end()); + VERIFY( s1.size() == 0 ); + VERIFY( it13 == s1.end() ); + VERIFY( it13 == s1.begin() ); +} + +void test11() +{ + typedef SG::unordered_map<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + std::pair<Map::iterator, bool> tmp = m.insert(Pair("grape", 3)); + Map::iterator i = tmp.first; + VERIFY(tmp.second); + + Map::iterator i2 = m.find("grape"); + VERIFY(i2 != m.end()); + VERIFY(i2 == i); + VERIFY(i2->first == "grape"); + VERIFY(i2->second == 3); + + Map::iterator i3 = m.find("lime"); + VERIFY(i3 == m.end()); + + std::pair<Map::iterator, Map::iterator> p = m.equal_range("grape"); + VERIFY(std::distance(p.first, p.second) == 1); + VERIFY(p.first == i2); + + std::pair<Map::iterator, Map::iterator> p2 = m.equal_range("lime"); + VERIFY(p2.first == p2.second); + + VERIFY(m.count("grape") == 1); + VERIFY(m.count("lime") == 0); +} + +void test12() +{ + typedef SG::unordered_multimap<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + m.insert(Pair("grape", 3)); + m.insert(Pair("durian", 8)); + m.insert(Pair("grape", 7)); + + Map::iterator i1 = m.find("grape"); + Map::iterator i2 = m.find("durian"); + Map::iterator i3 = m.find("kiwi"); + + VERIFY(i1 != m.end()); + VERIFY(i1->first == "grape"); + VERIFY(i1->second == 3 || i2->second == 7); + VERIFY(i2 != m.end()); + VERIFY(i2->first == "durian"); + VERIFY(i2->second == 8); + VERIFY(i3 == m.end()); + + std::pair<Map::iterator, Map::iterator> p1 = m.equal_range("grape"); + VERIFY(std::distance(p1.first, p1.second) == 2); + Map::iterator tmp = p1.first; + ++tmp; + VERIFY(p1.first->first == "grape"); + VERIFY(tmp->first == "grape"); + VERIFY((p1.first->second == 3 && tmp->second == 7) || + (p1.first->second == 7 && tmp->second == 3)); + + std::pair<Map::iterator, Map::iterator> p2 = m.equal_range("durian"); + VERIFY(std::distance(p2.first, p2.second) == 1); + VERIFY(p2.first->first == "durian"); + VERIFY(p2.first->second == 8); + + std::pair<Map::iterator, Map::iterator> p3 = m.equal_range("kiwi"); + VERIFY(p3.first == p3.second); + + VERIFY(m.count("grape") == 2); + VERIFY(m.count("durian") == 1); + VERIFY(m.count("kiwi") == 0); +} + +void test13() +{ + typedef SG::unordered_multiset<std::string> Set; + Set s; + VERIFY(s.empty()); + + s.insert("grape"); + s.insert("banana"); + s.insert("grape"); + + Set::iterator i2 = s.find("banana"); + VERIFY(i2 != s.end()); + VERIFY(*i2 == "banana"); + + std::pair<Set::iterator, Set::iterator> p = s.equal_range("grape"); + VERIFY(std::distance(p.first, p.second) == 2); + Set::iterator i3 = p.first; + ++i3; + VERIFY(*p.first == "grape"); + VERIFY(*i3 == "grape"); + + Set::iterator i4 = s.find("lime"); + VERIFY(i4 == s.end()); + + VERIFY(s.count("grape") == 2); + VERIFY(s.count("banana") == 1); + VERIFY(s.count("lime") == 0); +} + +void test14() +{ + typedef SG::unordered_set<std::string> Set; + Set s; + VERIFY(s.empty()); + + std::pair<Set::iterator, bool> tmp = s.insert("grape"); + Set::iterator i = tmp.first; + + Set::iterator i2 = s.find("grape"); + VERIFY(i2 != s.end()); + VERIFY(i2 == i); + VERIFY(*i2 == "grape"); + + std::pair<Set::iterator, Set::iterator> p = s.equal_range("grape"); + VERIFY(p.first == i2); + VERIFY(std::distance(p.first, p.second) == 1); + + Set::iterator i3 = s.find("lime"); + VERIFY(i3 == s.end()); + + std::pair<Set::iterator, Set::iterator> p2 = s.equal_range("lime"); + VERIFY(p2.first == p2.second); + + VERIFY(s.count("grape") == 1); + VERIFY(s.count("lime") == 0); +} + +template<typename T> + void + do_test15() + { + bool test __attribute__((unused)) = true; + + typedef typename SG::hash<T>::argument_type argument_type; + typedef typename SG::hash<T>::result_type result_type; + + VERIFY( (test_relationship<is_same, argument_type, T>(true)) ); + VERIFY( (test_relationship<is_same, result_type, std::size_t>(true)) ); + } + +// libstdc++/24799 +void test15() +{ + do_test15<bool>(); + do_test15<char>(); + do_test15<signed char>(); + do_test15<unsigned char>(); + do_test15<short>(); + do_test15<int>(); + do_test15<long>(); + do_test15<unsigned short>(); + do_test15<unsigned int>(); + do_test15<unsigned long>(); + do_test15<int*>(); + do_test15<std::string>(); + do_test15<float>(); + do_test15<double>(); + do_test15<long double>(); + +#ifdef _GLIBCXX_USE_WCHAR_T + do_test15<wchar_t>(); + do_test15<std::wstring>(); +#endif +} + +// libstdc++/24061 +void test16() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_map<std::string, int> Map; + typedef Map::iterator iterator; + typedef Map::const_iterator const_iterator; + typedef Map::value_type value_type; + + Map m1; + + iterator it1 = m1.insert(m1.begin(), + value_type("all the love in the world", 1)); + VERIFY( m1.size() == 1 ); + VERIFY( *it1 == value_type("all the love in the world", 1) ); + + const_iterator cit1(it1); + const_iterator cit2 = m1.insert(cit1, + value_type("you know what you are?", 2)); + VERIFY( m1.size() == 2 ); + VERIFY( cit2 != cit1 ); + VERIFY( *cit2 == value_type("you know what you are?", 2) ); + + iterator it2 = m1.insert(it1, value_type("all the love in the world", 3)); + VERIFY( m1.size() == 2 ); + VERIFY( it2 == it1 ); + VERIFY( *it2 == value_type("all the love in the world", 1) ); +} + +// libstdc++/24061 +void test17() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_multimap<std::string, int> Mmap; + typedef Mmap::iterator iterator; + typedef Mmap::const_iterator const_iterator; + typedef Mmap::value_type value_type; + + Mmap mm1; + + iterator it1 = mm1.insert(mm1.begin(), + value_type("all the love in the world", 1)); + VERIFY( mm1.size() == 1 ); + VERIFY( *it1 == value_type("all the love in the world", 1) ); + + const_iterator cit1(it1); + const_iterator cit2 = mm1.insert(cit1, + value_type("you know what you are?", 2)); + VERIFY( mm1.size() == 2 ); + VERIFY( cit2 != cit1 ); + VERIFY( *cit2 == value_type("you know what you are?", 2) ); + + iterator it2 = mm1.insert(it1, value_type("all the love in the world", 3)); + VERIFY( mm1.size() == 3 ); + VERIFY( it2 != it1 ); + VERIFY( *it2 == value_type("all the love in the world", 3) ); +} + +// libstdc++/24061 +void test18() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_multiset<std::string> Mset; + typedef Mset::iterator iterator; + typedef Mset::const_iterator const_iterator; + + Mset ms1; + + iterator it1 = ms1.insert(ms1.begin(), "all the love in the world"); + VERIFY( ms1.size() == 1 ); + VERIFY( *it1 == "all the love in the world" ); + + const_iterator cit1(it1); + const_iterator cit2 = ms1.insert(cit1, "you know what you are?"); + VERIFY( ms1.size() == 2 ); + VERIFY( cit2 != cit1 ); + VERIFY( *cit2 == "you know what you are?" ); + + iterator it2 = ms1.insert(it1, "all the love in the world"); + VERIFY( ms1.size() == 3 ); + VERIFY( it2 != it1 ); + VERIFY( *it2 == "all the love in the world" ); +} + +// libstdc++/24061 +void test19() +{ + bool test __attribute__((unused)) = true; + + typedef SG::unordered_set<std::string> Set; + typedef Set::iterator iterator; + typedef Set::const_iterator const_iterator; + + Set s1; + + iterator it1 = s1.insert(s1.begin(), "all the love in the world"); + VERIFY( s1.size() == 1 ); + VERIFY( *it1 == "all the love in the world" ); + + const_iterator cit1(it1); + const_iterator cit2 = s1.insert(cit1, "you know what you are?"); + VERIFY( s1.size() == 2 ); + VERIFY( cit2 != cit1 ); + VERIFY( *cit2 == "you know what you are?" ); + + iterator it2 = s1.insert(it1, "all the love in the world"); + VERIFY( s1.size() == 2 ); + VERIFY( it2 == it1 ); + VERIFY( *it2 == "all the love in the world" ); +} + +void test20() +{ + typedef SG::unordered_map<std::string, int> Map; + //typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + m["red"] = 17; + VERIFY(m.size() == 1); + VERIFY(m.begin()->first == "red"); + VERIFY(m.begin()->second == 17); + VERIFY(m["red"] == 17); + + m["blue"] = 9; + VERIFY(m.size() == 2); + VERIFY(m["blue"] == 9); + + m["red"] = 5; + VERIFY(m.size() == 2); + VERIFY(m["red"] == 5); + VERIFY(m["blue"] == 9); +} + +void test21() +{ + typedef SG::unordered_map<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + Pair A[5] = + { + Pair("red", 5), + Pair("green", 9), + Pair("blue", 3), + Pair("cyan", 8), + Pair("magenta", 7) + }; + + m.insert(A+0, A+5); + VERIFY(m.size() == 5); + VERIFY(std::distance(m.begin(), m.end()) == 5); + + VERIFY(m["red"] == 5); + VERIFY(m["green"] == 9); + VERIFY(m["blue"] == 3); + VERIFY(m["cyan"] == 8); + VERIFY(m["magenta"] == 7); +} + +void test22() +{ + typedef SG::unordered_map<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + Pair A[9] = + { + Pair("red", 5), + Pair("green", 9), + Pair("red", 19), + Pair("blue", 3), + Pair("blue", 60), + Pair("cyan", 8), + Pair("magenta", 7), + Pair("blue", 99), + Pair("green", 33) + }; + + m.insert(A+0, A+9); + VERIFY(m.size() == 5); + VERIFY(std::distance(m.begin(), m.end()) == 5); + + VERIFY(m["red"] == 5); + VERIFY(m["green"] == 9); + VERIFY(m["blue"] == 3); + VERIFY(m["cyan"] == 8); + VERIFY(m["magenta"] == 7); +} + +void test23() +{ + typedef SG::unordered_map<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + std::pair<Map::iterator, bool> p = m.insert(Pair("abcde", 3)); + VERIFY(p.second); + VERIFY(m.size() == 1); + VERIFY(std::distance(m.begin(), m.end()) == 1); + VERIFY(p.first == m.begin()); + VERIFY(p.first->first == "abcde"); + VERIFY(p.first->second == 3); +} + +void test24() +{ + typedef SG::unordered_map<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + std::pair<Map::iterator, bool> p1 = m.insert(Pair("abcde", 3)); + std::pair<Map::iterator, bool> p2 = m.insert(Pair("abcde", 7)); + + VERIFY(p1.second); + VERIFY(!p2.second); + VERIFY(m.size() == 1); + VERIFY(p1.first == p2.first); + VERIFY(p1.first->first == "abcde"); + VERIFY(p2.first->second == 3); +} + +void test25() +{ + typedef SG::unordered_multimap<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + Pair A[5] = + { + Pair("red", 5), + Pair("green", 9), + Pair("blue", 3), + Pair("cyan", 8), + Pair("magenta", 7) + }; + + m.insert(A+0, A+5); + VERIFY(m.size() == 5); + VERIFY(std::distance(m.begin(), m.end()) == 5); + + for (int i = 0; i < 5; ++i) + VERIFY(std::find(m.begin(), m.end(), A[i]) != m.end()); +} + +void test26() +{ + typedef SG::unordered_multimap<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + Pair A[9] = + { + Pair("red", 5), + Pair("green", 9), + Pair("red", 19), + Pair("blue", 3), + Pair("blue", 60), + Pair("cyan", 8), + Pair("magenta", 7), + Pair("blue", 99), + Pair("green", 33) + }; + + m.insert(A+0, A+9); + VERIFY(m.size() == 9); + VERIFY(std::distance(m.begin(), m.end()) == 9); + + for (int i = 0; i < 9; ++i) + VERIFY(std::find(m.begin(), m.end(), A[i]) != m.end()); +} + +void test27() +{ + typedef SG::unordered_multimap<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + Map::iterator i = m.insert(Pair("abcde", 3)); + VERIFY(m.size() == 1); + VERIFY(std::distance(m.begin(), m.end()) == 1); + VERIFY(i == m.begin()); + VERIFY(i->first == "abcde"); + VERIFY(i->second == 3); +} + +void test28() +{ + typedef SG::unordered_multimap<std::string, int> Map; + typedef std::pair<const std::string, int> Pair; + + Map m; + VERIFY(m.empty()); + + m.insert(Pair("abcde", 3)); + m.insert(Pair("abcde", 7)); + + VERIFY(m.size() == 2); + VERIFY(std::distance(m.begin(), m.end()) == 2); + + Map::iterator i1 = m.begin(); + Map::iterator i2 = i1; + ++i2; + + VERIFY(i1->first == "abcde"); + VERIFY(i2->first == "abcde"); + VERIFY((i1->second == 3 && i2->second == 7) || + (i1->second == 7 && i2->second == 3)); +} + +void test29() +{ + typedef SG::unordered_multiset<std::string> Set; + Set s; + VERIFY(s.empty()); + + const int N = 10; + const std::string A[N] = { "red", "green", "blue", "violet", "cyan", + "magenta", "yellow", "orange", "pink", "gray" }; + + s.insert(A+0, A+N); + VERIFY(s.size() == static_cast<unsigned int>(N)); + VERIFY(std::distance(s.begin(), s.end()) == N); + + for (int i = 0; i < N; ++i) { + std::string str = A[i]; + Set::iterator it = std::find(s.begin(), s.end(), str); + VERIFY(it != s.end()); + } +} + +void test30() +{ + typedef SG::unordered_multiset<int> Set; + Set s; + VERIFY(s.empty()); + + const int N = 8; + const int A[N] = { 3, 7, 4, 8, 2, 4, 6, 7 }; + + s.insert(A+0, A+N); + VERIFY(s.size() == static_cast<unsigned int>(N)); + VERIFY(std::distance(s.begin(), s.end()) == N); + + VERIFY(std::count(s.begin(), s.end(), 2) == 1); + VERIFY(std::count(s.begin(), s.end(), 3) == 1); + VERIFY(std::count(s.begin(), s.end(), 4) == 2); + VERIFY(std::count(s.begin(), s.end(), 6) == 1); + VERIFY(std::count(s.begin(), s.end(), 7) == 2); + VERIFY(std::count(s.begin(), s.end(), 8) == 1); +} + +void test31() +{ + typedef SG::unordered_set<std::string> Set; + Set s; + VERIFY(s.empty()); + + const int N = 10; + const std::string A[N] = { "red", "green", "blue", "violet", "cyan", + "magenta", "yellow", "orange", "pink", "gray" }; + + s.insert(A+0, A+N); + VERIFY(s.size() == static_cast<unsigned int>(N)); + VERIFY(std::distance(s.begin(), s.end()) == N); + + for (int i = 0; i < N; ++i) { + std::string str = A[i]; + Set::iterator it = std::find(s.begin(), s.end(), str); + VERIFY(it != s.end()); + } +} + +void test32() +{ + typedef SG::unordered_set<int> Set; + Set s; + VERIFY(s.empty()); + + const int N = 8; + const int A[N] = { 3, 7, 4, 8, 2, 4, 6, 7 }; + + s.insert(A+0, A+N); + VERIFY(s.size() == 6); + VERIFY(std::distance(s.begin(), s.end()) == 6); + + VERIFY(std::count(s.begin(), s.end(), 2) == 1); + VERIFY(std::count(s.begin(), s.end(), 3) == 1); + VERIFY(std::count(s.begin(), s.end(), 4) == 1); + VERIFY(std::count(s.begin(), s.end(), 6) == 1); + VERIFY(std::count(s.begin(), s.end(), 7) == 1); + VERIFY(std::count(s.begin(), s.end(), 8) == 1); +} + +// Verify we can default-construct iterators - sss. +void test33() +{ + SG::unordered_set<int>::iterator i1; + SG::unordered_set<int>::const_iterator i2; + SG::unordered_map<int, int>::iterator i3; + SG::unordered_map<int, int>::const_iterator i4; +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test08(); + test09(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); + test17(); + test18(); + test19(); + test20(); + test21(); + test22(); + test23(); + test24(); + test25(); + test26(); + test27(); + test28(); + test29(); + test30(); + test31(); + test32(); + test33(); + return 0; +} + + +using namespace std; +using namespace SG; + +// Verify that we can instantiate hash for every required type. +//template struct SG::hash<bool>; +//template struct SG::hash<char>; +//template struct SG::hash<signed char>; +//template struct SG::hash<unsigned char>; +//template struct SG::hash<short>; +//template struct SG::hash<int>; +//template struct SG::hash<long>; +//template struct SG::hash<unsigned short>; +//template struct SG::hash<unsigned int>; +//template struct SG::hash<unsigned long>; +//template struct SG::hash<float>; +//template struct SG::hash<double>; +//template struct SG::hash<long double>; +template struct SG::hash<void*>; +//template struct SG::hash<std::string>; + +#ifdef _GLIBCXX_USE_WCHAR_T +//template struct SG::hash<wchar_t>; +//template struct SG::hash<std::wstring>; +#endif + + +template class SG::unordered_map<string, float>; +template class SG::unordered_map<string, float, + SG::hash<string>, equal_to<string>, + allocator<pair<const string, float> >, true>; + + +template class SG::unordered_multimap<string, float>; +template class SG::unordered_multimap<string, float, + SG::hash<string>, equal_to<string>, + allocator<pair<const string, float> >, true>; + + +template class SG::unordered_multiset<int>; +template class SG::unordered_multiset<int, SG::hash<int>, equal_to<int>, + allocator<int>, true>; + + +template class SG::unordered_set<int>; +template class SG::unordered_set<int, SG::hash<int>, equal_to<int>, + allocator<int>, true>; diff --git a/EDM/athena/Control/CxxUtils/test/make_unique_test.cxx b/EDM/athena/Control/CxxUtils/test/make_unique_test.cxx new file mode 100644 index 00000000..02d47c2b --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/make_unique_test.cxx @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/make_unique.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2014 + * @brief Regression tests for make_unique. + */ + + +#undef NDEBUG +#include "CxxUtils/make_unique.h" +#include <memory> +#include <iostream> +#include <cassert> + + +int count = 0; +struct C +{ + C(int x) : m_x (x) { count += x; } + ~C() { count -= m_x; } + int m_x; +}; + + +void test1() +{ + std::cout << "test1\n"; +#if __cplusplus > 201100 + { + assert (count == 0); + std::unique_ptr<C> c = CxxUtils::make_unique<C>(10); + assert (count == 10); + } + assert (count == 0); +#endif +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/ones_test.cxx b/EDM/athena/Control/CxxUtils/test/ones_test.cxx new file mode 100644 index 00000000..71fb4874 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/ones_test.cxx @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/test/ones_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2014 + * @brief Regression test for ones. + */ + + +#undef NDEBUG +#include "CxxUtils/ones.h" +#include <iostream> +#include <cassert> +#include <stdint.h> + + +template <class T> +inline +void testit (unsigned int n) +{ + T mask = CxxUtils::ones<T>(n); + T comp = 0; + for (unsigned int i=0; i < n; i++) + comp = (comp<<1) | 1; + assert (mask == comp); +} + + +void test1() +{ + std::cout << "test1\n"; + for (int i=0; i<=32; i++) + testit<uint32_t> (i); + + for (int i=0; i<=64; i++) + testit<uint64_t> (i); +} + + +int main() +{ + test1(); + return 0; +} + diff --git a/EDM/athena/Control/CxxUtils/test/pointer_list_test.cxx b/EDM/athena/Control/CxxUtils/test/pointer_list_test.cxx new file mode 100644 index 00000000..c8319668 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/pointer_list_test.cxx @@ -0,0 +1,169 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file CxxUtils/tests/pointer_list.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2009, from earlier code. + * @brief Unit test for pointer_list. + */ + +#undef NDEBUG + + +#include "CxxUtils/pointer_list.h" +#include <vector> +#include <cassert> +#include <cstdlib> + + +using namespace CxxUtils; + + +size_t toerase[] = { + 0, 1, 5, 14, 15, 16, 17, 20, 29, 30, 31, 500 +}; +const size_t n_toerase = sizeof (toerase) / sizeof (toerase[0]); + + +void testerase (pointer_list<>& l, + size_t nerase, + std::vector<int>& v) +{ + if (nerase >= n_toerase) std::abort(); + + size_t sz = l.size(); + pointer_list<>::iterator it = l.begin(); + std::advance (it, toerase[nerase]); + l.erase (it); + assert (l.size() == sz-1); + + it = l.begin(); + pointer_list<>::iterator end = l.end(); + size_t i = 0; + while (it != end) { + bool skip = false; + for (size_t j=0; j <= nerase; j++) { + if (i == toerase[j]+j) { + skip = true; + break; + } + } + if (!skip) { + assert (*it == &v[i]); + ++it; + } + ++i; + } + + assert (it == end); +} + + +void testit1 (pointer_list<>& l, size_t n) +{ + assert (l.size() == 0); + assert (l.empty()); + + std::vector<int> v (n); + for (size_t i = 0; i < n; i++) { + l.push_back (&v[i]); + assert (l.size() == i+1); + } + + pointer_list<>::iterator beg = l.begin(); + pointer_list<>::iterator end = l.end(); + size_t i = 0; + while (beg != end) { + assert (*beg == &v[i]); + ++beg; + ++i; + } + assert (beg == end); + assert (i == n); + if (n > 0) + assert (!l.empty()); + + if (n > 2) { + beg = l.begin(); + assert (*++beg == &v[1]); + assert (*beg == &v[1]); + beg = l.begin(); + assert (*beg++ == &v[0]); + assert (*beg == &v[1]); + } + + for (size_t i = 0; i < n_toerase; i++) { + if (toerase[i] >= l.size()) + break; + testerase (l, i, v); + } +} + + +void testit (int n, pointer_list<>::pool_type& pool) +{ + pointer_list<> l (pool); + testit1 (l, n); + + // Check that if we clear and refill, we don't allocate more memory. + size_t inuse = pool.nchunks(); + l.clear(); + testit1 (l, n); + assert (pool.nchunks() == inuse); +} + + +void test1() +{ + pointer_list<>::pool_type pool; + + testit (0, pool); + testit (1, pool); + testit (5, pool); + testit (14, pool); + testit (15, pool); + testit (16, pool); + testit (17, pool); + testit (29, pool); + testit (30, pool); + testit (31, pool); + testit (1000, pool); +} + + +void test2() +{ + pointer_list<>::pool_type pool; + std::vector<int> v (35); + pointer_list<> l (pool); + + for (size_t i = 0; i < 16; i++) + l.push_back (&v[i]); + pointer_list<>::iterator pos = l.begin(); + std::advance (pos, 15); + l.erase (pos); + pos = l.begin(); + std::advance (pos, 14); + l.erase (pos); + l.push_back (&v[14]); + + pos = l.begin(); + pointer_list<>::iterator end = l.end(); + size_t j = 0; + while (pos != end) { + assert (*pos == &v[j]); + ++pos; + ++j; + } +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/prefetch_test.cxx b/EDM/athena/Control/CxxUtils/test/prefetch_test.cxx new file mode 100644 index 00000000..4d1f6eda --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/prefetch_test.cxx @@ -0,0 +1,113 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//-------------------------------------------------------------------------- +// File and Version Information: +// $Id$ +// +// Description: +// Test application for the prefetch. +// +//------------------------------------------------------------------------ + +//--------------- +// C++ Headers -- +//--------------- +#include <iostream> + +//------------------------------- +// Collaborating Class Headers -- +//------------------------------- + + +// redefine CXXUTILS_PREFETCH_ADDRESS macro to do useful stuff +#define CXXUTILS_PREFETCH_ADDRESS(ADDR) std::cout << " prefetch address: " << static_cast<const void*>(ADDR) << '\n' + +#include "CxxUtils/prefetch.h" + +namespace { + +template <unsigned SIZE> +struct Data { + char x[ SIZE ]; +}; + +template <unsigned SIZE> +void prefetch(int address) +{ + const Data< SIZE >* ptr = reinterpret_cast<const Data< SIZE >*>(address); + std::cout << "prefetch address: " << static_cast<const void*>(ptr) << " size: " << sizeof(Data<SIZE>) << '\n'; + CxxUtils::prefetchObj(ptr); +} + +} + +void test1() { + // never need more than one line + prefetch<1>(0); + prefetch<1>(1); + prefetch<1>(63); + prefetch<1>(64); +} + +void test2() { + // object size is small but may need >1 line + prefetch<2>(0); + prefetch<2>(1); + prefetch<2>(62); + prefetch<2>(63); + prefetch<2>(64); +} + +void test3() { + // object size is whole line size + prefetch<64>(0); + prefetch<64>(1); + prefetch<64>(63); + prefetch<64>(64); +} + +void test4() { + // object slightly larger than line size + prefetch<67>(0); + prefetch<67>(1); + prefetch<67>(61); + prefetch<67>(62); + prefetch<67>(63); + prefetch<67>(64); +} + +void test5() { + // varying object sizes + prefetch<32>(10); + prefetch<64>(10); + prefetch<128>(10); + prefetch<256>(10); +} + + +struct Foo { int x[10]; }; + +void test6() { + std::cout << "test6\n"; + Foo* foo[10]; + for (int i=0; i < 10; i++) foo[i] = reinterpret_cast<Foo*> (i*128); + + CxxUtils::prefetchNext (foo+1, foo+10); + CxxUtils::prefetchNext (foo+9, foo+10); + CxxUtils::prefetchTwo (foo+8, foo+10); + CxxUtils::prefetchTwo (foo+9, foo+10); + CxxUtils::prefetchTwo (foo+10, foo+10); +} + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); +} + diff --git a/EDM/athena/Control/CxxUtils/test/procmaps_test.cxx b/EDM/athena/Control/CxxUtils/test/procmaps_test.cxx new file mode 100644 index 00000000..37df9bc2 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/procmaps_test.cxx @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG +#include <cassert> +#include <iostream> +#include <boost/pool/pool_alloc.hpp> +#include "CxxUtils/procmaps.h" +//#define DEBUGIT 1 +using namespace std; +void nop() {} +int main(void) { + cout << "*** procmaps_test starts ***" <<endl; +#ifdef DEBUGIT + const bool DUMPMAPS(true); +#else + const bool DUMPMAPS(false); +#endif + procmaps pmaps(DUMPMAPS); + //let's start with a code page + const procmaps::Entry* pCodeEntry(pmaps.getEntry((void *)(unsigned long)&nop)); + assert(pCodeEntry); +#ifdef DEBUGIT + cout << "code entry " << hex << pCodeEntry->begAddress << " " + << (void *)&nop << " " + << pCodeEntry->endAddress << endl; +#endif + assert(pCodeEntry->executable); + assert(pCodeEntry->readable); + assert(!pCodeEntry->writable); + assert(0 != pCodeEntry->inode); + //now with a heap page + int* pi= new int(2); + const procmaps::Entry* pHeapEntry(pmaps.getEntry(pi)); + assert(pHeapEntry); +#ifdef DEBUGIT + cout << "heap entry " << hex << pHeapEntry->begAddress << " " + << pi << " " + << pHeapEntry->endAddress << endl; +#endif + //FIXME the heap should not be executable, right? assert(!pHeapEntry->executable); + assert(pHeapEntry->readable); + assert(pHeapEntry->writable); + assert(0 == pHeapEntry->inode); + +//make valgrind happy + delete pi; + boost::singleton_pool<boost::pool_allocator_tag, sizeof(procmaps::Entry)>::release_memory(); + + cout << "*** procmaps_test OK ***" <<endl; + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/read_athena_statm_test.cxx b/EDM/athena/Control/CxxUtils/test/read_athena_statm_test.cxx new file mode 100644 index 00000000..8a9ef61a --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/read_athena_statm_test.cxx @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file read_athena_statm_test.cxx + * @brief unit test for read_athena_statm + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> -ATLAS Collaboration + * $Id: read_athena_statm_test.cxx 592256 2014-04-10 00:20:45Z calaf $ + **/ + +#undef NDEBUG + +#include <cassert> +#include <iostream> + +#include "CxxUtils/read_athena_statm.h" + +using std::cerr; +using std::cout; +using std::endl; + + + +int main() { + const std::string appName = "read_statm_test"; + cout << "*** " << appName << " starts ***" <<endl; + + athena_statm s = read_athena_statm(); + cout << "read_athena_statm reports process size (in pages): VM " << s.vm_pages + << " RSS " << s.rss_pages << endl; + //let's do something... + assert(s.vm_pages >= s.rss_pages); + //all done + cout << "*** " << appName << " OK ***" <<endl; + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/sincos_test.cxx b/EDM/athena/Control/CxxUtils/test/sincos_test.cxx new file mode 100644 index 00000000..850be2c4 --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/sincos_test.cxx @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: sincos_test.cxx,v 1.1 2008-11-24 04:34:07 ssnyder Exp $ +/** + * @file CxxUtils/test/sincos_test.cxx + * @author scott snyder + * @date Nov 2008 + * @brief Regression tests for sincos. + */ + + +#undef NDEBUG + + +#include "CxxUtils/sincos.h" +#include <cassert> +#include <cmath> + +using namespace std; + + +void fptest (double a, double b) +{ + double den = abs(a) + abs(b); + if (den == 0) den = 1; + double frac = abs(a-b)/den; + assert (frac < 1e-9); +} + + +void test1() +{ + CxxUtils::sincos a (0.1); + fptest (sin(0.1), a.sn); + fptest (cos(0.1), a.cs); + fptest (2*sin(0.1) + 3*cos(0.1), a.apply(2,3)); + fptest (2*sin(0.1)*sin(0.1) + 3*sin(0.1)*cos(0.1) + 4*cos(0.1)*cos(0.1), + a.apply2(2,3,4)); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/CxxUtils/test/stacktrace_test.cxx b/EDM/athena/Control/CxxUtils/test/stacktrace_test.cxx new file mode 100644 index 00000000..1a5031de --- /dev/null +++ b/EDM/athena/Control/CxxUtils/test/stacktrace_test.cxx @@ -0,0 +1,257 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file CxxUtils/test/stacktrace_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2010 + * @brief Test stack trace printing. + */ + + +#undef NDEBUG + +#include "CxxUtils/SealDebug.h" +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#ifndef __APPLE__ +# include <malloc.h> +#endif // not __APPLE__ +#include <dlfcn.h> +#include <cstdlib> + + +char* snip (char* buf, char* p, char fill = '\0') +{ + if (p > buf) { + if (fill) + *buf++ = fill; + char* q = buf; + while (*p) + *q++ = *p++; + *q = 0; + } + return buf; +} + + +void filter (char* buf) +{ + char* sl = 0; + while (*buf) { + if (buf[0] == '0' && buf[1] == 'x') { + buf += 2; + char* p = buf; + while (isxdigit (*p)) + ++p; + buf = snip (buf, p, 'X'); + } + + else if (buf[0] == '/') { + if (sl) + buf = snip (sl, buf); + sl = buf; + ++buf; + } + + else if (buf[0] == ' ') { + ++buf; + sl = 0; + } + + else if (buf[0] == '.' && buf[1] == '.') { + buf = snip (buf, buf+2); + } + + // Get rid of file/line number. + // Unfortunate, but we don't get these for opt builds. + else if (buf[0] == ':' && sl) { + ++buf; + while (isdigit (*buf)) + ++buf; + if (*buf == ' ') + ++buf; + buf = snip (sl, buf); + sl = 0; + } + + else + ++buf; + } +} + + +void dumptrace (FILE* fp) +{ + fseek (fp, 0, SEEK_SET); + char buf[65536]; + while (fgets (buf, sizeof (buf), fp)) { + if (strstr (buf, "libasan") != nullptr) + continue; + filter (buf); + fputs (buf, stdout); + } +} + + +bool initialized = false; +bool initializing = false; +bool finishing = false; +bool nomalloc = false; + +void *(*old_malloc)(size_t size); +void (*old_free)(void* ptr); +void *(*old_realloc)(void* ptr, size_t size); + +void initpointers() +{ + initializing = true; + old_malloc = (void* (*)(size_t)) (unsigned long) dlsym(RTLD_NEXT, "__libc_malloc"); + old_free = (void (*)(void*)) (unsigned long) dlsym(RTLD_NEXT, "__libc_free"); + old_realloc = (void* (*)(void*, size_t)) (unsigned long) dlsym(RTLD_NEXT, "__libc_realloc"); + initialized = true; + initializing = false; +} + +void* do_malloc (size_t size) +{ + /* It's possible to get recursion here, since dlsym() can trigger + * memory allocation. To deal with this, we flag the initialization + * condition specially, then use the special knowledge that it's + * OK for malloc to fail during initialization (libc degrades + * gracefully), so we just return NULL from malloc(), realloc(). + * + * This trick is borrowed from from libc's memusage. + */ + if (!initialized) { + if (initializing) + return NULL; + initpointers(); + } + + if (nomalloc) { + printf ("malloc called\n"); + std::abort(); + } + return (*old_malloc) (size); +} + +void* malloc (size_t size) +#ifndef __APPLE__ +throw() +#endif +{ + return do_malloc (size); +} + + +void* __libc_malloc (size_t size) +{ + return do_malloc (size); +} + + +void do_free (void* ptr) +{ + if (!initialized) { + if (initializing) + return; + initpointers(); + } + if (finishing) + return; + + (*old_free) (ptr); +} + + +void free (void* ptr) +#ifndef __APPLE__ +throw() +#endif +{ + return do_free (ptr); +} + + +void __libc_free (void* ptr) +{ + return do_free (ptr); +} + + +void* do_realloc (void* ptr, size_t size) +{ + if (!initialized) { + if (initializing) + return NULL; + initpointers(); + } + + if (nomalloc) { + printf ("realloc called\n"); + std::abort(); + } + return (*old_realloc) (ptr, size); +} + + +void* realloc (void* ptr, size_t size) +#ifndef __APPLE__ +throw() +#endif +{ + return do_realloc (ptr, size); +} + + +void* __libc_realloc (void* ptr, size_t size) +{ + return do_realloc (ptr, size); +} + + + +// Used to check that we don't call malloc during the stack trace. +void sethooks() +{ + nomalloc = true; +} + +#if defined(__GNUC__) || defined(__clang__) +__attribute__ ((noinline)) +#endif +void resethooks() +{ + nomalloc = false; +} + + +#if defined(__GNUC__) || defined(__clang__) +__attribute__ ((noinline)) +#endif +void fromhere() +{ + char pat[] = "stacktrace_testXXXXXX"; + umask (0600); + int fd = mkstemp (pat); + if (fd < 0) std::abort(); + FILE* fp = fdopen (fd, "w+"); + sethooks(); + Athena::DebugAids::stacktrace (fd); + resethooks(); + dumptrace (fp); + fclose (fp); +} + + +int main() +{ + initpointers(); + Athena::DebugAids::setStackTraceAddr2Line ("/usr/bin/addr2line"); + fromhere(); + finishing = true; + return 0; +} diff --git a/EDM/athena/Control/DataModel/CMakeLists.txt b/EDM/athena/Control/DataModel/CMakeLists.txt new file mode 100644 index 00000000..d1ad311f --- /dev/null +++ b/EDM/athena/Control/DataModel/CMakeLists.txt @@ -0,0 +1,20 @@ +################################################################################ +# Package: DataModel +################################################################################ + +# Declare the package name: +atlas_subdir( DataModel ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthAllocators + Control/AthContainers + Control/AthLinks + Control/CxxUtils + Control/SGTools ) + +# Component(s) in the package: +atlas_add_library( DataModel + PUBLIC_HEADERS DataModel + LINK_LIBRARIES AthAllocators AthContainers AthLinks CxxUtils SGTools ) + diff --git a/EDM/athena/Control/DataModel/DataModel/Arena.h b/EDM/athena/Control/DataModel/DataModel/Arena.h new file mode 100644 index 00000000..21366f80 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/Arena.h @@ -0,0 +1,17 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena.h 559676 2013-08-28 18:44:37Z ssnyder $ +// Moved to AthAllocators. + +#ifndef DATAMODEL_ARENA_H +#define DATAMODEL_ARENA_H + + +#include "AthAllocators/Arena.h" + + +#endif // not DATAMODEL_ARENA_H diff --git a/EDM/athena/Control/DataModel/DataModel/AssociationMap.h b/EDM/athena/Control/DataModel/DataModel/AssociationMap.h new file mode 100644 index 00000000..eccfdaa6 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/AssociationMap.h @@ -0,0 +1,12 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef DATAMODEL_ASSOCIATIONMAP_H +#define DATAMODEL_ASSOCIATIONMAP_H + +// Moved to AthLinks. + +#include "AthLinks/AssociationMap.h" + +#endif diff --git a/EDM/athena/Control/DataModel/DataModel/ClassName.h b/EDM/athena/Control/DataModel/DataModel/ClassName.h new file mode 100644 index 00000000..5171f245 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/ClassName.h @@ -0,0 +1,23 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ClassName.h 559821 2013-08-29 20:51:26Z ssnyder $ + +/** + * @file DataModel/ClassName.h + * @author scott snyder + * @date Jul 2005 + * @brief An interface for getting the name of a class as a string. + */ + + +#ifndef DATAMODEL_CLASSNAME_H +#define DATAMODEL_CLASSNAME_H + +// moved to SGTools for dependency issues +#include "SGTools/ClassName.h" + +#endif // not DATAMODEL_CLASSNAME_H diff --git a/EDM/athena/Control/DataModel/DataModel/ConstDataVector.h b/EDM/athena/Control/DataModel/DataModel/ConstDataVector.h new file mode 100644 index 00000000..123d397b --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/ConstDataVector.h @@ -0,0 +1,16 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ConstDataVector.h 559821 2013-08-29 20:51:26Z ssnyder $ +// Moved to AthContainers. + + +#ifndef DATAMODEL_CONSTDATAVECTOR_H +#define DATAMODEL_CONSTDATAVECTOR_H + +#include "AthContainers/ConstDataVector.h" + +#endif // not DATAMODEL_CONSTDATAVECTOR_H diff --git a/EDM/athena/Control/DataModel/DataModel/DataLink.h b/EDM/athena/Control/DataModel/DataModel/DataLink.h new file mode 100644 index 00000000..c06ea5a1 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/DataLink.h @@ -0,0 +1,26 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Moved to AthLinks. + +#ifndef DATAMODEL_DATALINK_H +#define DATAMODEL_DATALINK_H + +#include "AthLinks/DataLink.h" + +#endif /*DATAMODEL_DATALINK_H*/ + + + + + + + + + + + + diff --git a/EDM/athena/Control/DataModel/DataModel/DataList.h b/EDM/athena/Control/DataModel/DataModel/DataList.h new file mode 100644 index 00000000..5423e928 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/DataList.h @@ -0,0 +1,17 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataList.h 559821 2013-08-29 20:51:26Z ssnyder $ +// Moved to AthContainers. + +#ifndef DATAMODEL_DATALIST_H +#define DATAMODEL_DATALIST_H + + +#include "AthContainers/DataList.h" + + +#endif //DATAMODEL_DATALIST_H diff --git a/EDM/athena/Control/DataModel/DataModel/DataPool.h b/EDM/athena/Control/DataModel/DataModel/DataPool.h new file mode 100644 index 00000000..88f75592 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/DataPool.h @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Moved to AthAllocators. + +#ifndef DATAMODEL_DATAPOOL_H +#define DATAMODEL_DATAPOOL_H + + +#include "AthAllocators/DataPool.h" + + +#endif // not DATAMODEL_DATAPOOL_H + + + diff --git a/EDM/athena/Control/DataModel/DataModel/DataVector.h b/EDM/athena/Control/DataModel/DataModel/DataVector.h new file mode 100644 index 00000000..fd7754cc --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/DataVector.h @@ -0,0 +1,18 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataVector.h 559821 2013-08-29 20:51:26Z ssnyder $ +// Moved to AthContainers. + + +#ifndef DATAMODEL_DATAVECTOR_H +#define DATAMODEL_DATAVECTOR_H + + +#include "AthContainers/DataVector.h" + + +#endif // not DATAMODEL_DATAVECTOR_H diff --git a/EDM/athena/Control/DataModel/DataModel/ElementLink.h b/EDM/athena/Control/DataModel/DataModel/ElementLink.h new file mode 100644 index 00000000..b6d4b898 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/ElementLink.h @@ -0,0 +1,15 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Moved to AthLinks +#ifndef DATAMODEL_ELEMENTLINK_H +#define DATAMODEL_ELEMENTLINK_H + + +#include "AthLinks/ElementLink.h" + + +#endif /*DATAMODEL_ELEMENTLINK_H*/ diff --git a/EDM/athena/Control/DataModel/DataModel/ElementLinkVector.h b/EDM/athena/Control/DataModel/DataModel/ElementLinkVector.h new file mode 100644 index 00000000..efe36959 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/ElementLinkVector.h @@ -0,0 +1,15 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Moved to AthLinks +#ifndef DATAMODEL_ELEMENTLINKVECTOR_H +#define DATAMODEL_ELEMENTLINKVECTOR_H + + +#include "AthLinks/ElementLinkVector.h" + + +#endif /*DATAMODEL_ELEMENTLINKVECTOR_H*/ diff --git a/EDM/athena/Control/DataModel/DataModel/OwnershipPolicy.h b/EDM/athena/Control/DataModel/DataModel/OwnershipPolicy.h new file mode 100644 index 00000000..2edfde99 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/OwnershipPolicy.h @@ -0,0 +1,10 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef DATAMODEL_OWNERSHIPPOLICY_H +# define DATAMODEL_OWNERSHIPPOLICY_H + +#include "AthContainers/OwnershipPolicy.h" + +#endif // DATAMODEL_OWNERSHIPPOLICY_H diff --git a/EDM/athena/Control/DataModel/DataModel/UserDataStore.h b/EDM/athena/Control/DataModel/DataModel/UserDataStore.h new file mode 100644 index 00000000..81011850 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/UserDataStore.h @@ -0,0 +1,13 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//Dear emacs, this is -*-c++-*- +#ifndef DATAMODEL_USERDATASTORE_H +#define DATAMODEL_USERDATASTORE_H + +// Moved to AthContainers + +#include "AthContainers/UserDataStore.h" + +#endif diff --git a/EDM/athena/Control/DataModel/DataModel/tools/ArenaPoolSTLAllocator.h b/EDM/athena/Control/DataModel/DataModel/tools/ArenaPoolSTLAllocator.h new file mode 100644 index 00000000..e4b467d3 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/tools/ArenaPoolSTLAllocator.h @@ -0,0 +1,17 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator.h,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +// Moved to AthAllocators + +#ifndef DATAMODEL_ARENAPOOLSTLALLOCATOR +#define DATAMODEL_ARENAPOOLSTLALLOCATOR + + +#include "AthAllocators/ArenaPoolSTLAllocator.h" + + +#endif // DATAMODEL_ARENAPOOLSTLALLOCATOR diff --git a/EDM/athena/Control/DataModel/DataModel/tools/ArenaSharedHeapSTLAllocator.h b/EDM/athena/Control/DataModel/DataModel/tools/ArenaSharedHeapSTLAllocator.h new file mode 100644 index 00000000..7e840c65 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/tools/ArenaSharedHeapSTLAllocator.h @@ -0,0 +1,18 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.h 559676 2013-08-28 18:44:37Z ssnyder $ +// Moved to AthAllocators + + +#ifndef DATAMODEL_ARENASHAREDHEAPSTLALLOCATOR_H +#define DATAMODEL_ARENASHAREDHEAPSTLALLOCATOR_H + + +#include "AthAllocators/ArenaSharedHeapSTLAllocator.h" + + +#endif // not DATAMODEL_ARENASHAREDHEAPSTLALLOCATOR_H diff --git a/EDM/athena/Control/DataModel/DataModel/tools/DVLInfo.h b/EDM/athena/Control/DataModel/DataModel/tools/DVLInfo.h new file mode 100644 index 00000000..7f1c3d3c --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/tools/DVLInfo.h @@ -0,0 +1,17 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DVLInfo.h,v 1.2 2008-06-17 00:44:17 ssnyder Exp $ +// Moved to AthContainers. + +#ifndef DATAMODEL_DVLINFO_H +#define DATAMODEL_DVLINFO_H + + +#include "AthContainers/tools/DVLInfo.h" + + +#endif // not DATAMODEL_DVLINFO_H diff --git a/EDM/athena/Control/DataModel/DataModel/tools/IdentContIndex.h b/EDM/athena/Control/DataModel/DataModel/tools/IdentContIndex.h new file mode 100644 index 00000000..a3d6ea8d --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/tools/IdentContIndex.h @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef DATAMODEL_TOOLS_IDENTCONTINDEX_H +# define DATAMODEL_TOOLS_IDENTCONTINDEX_H + +// Moved to AthLinks + + +#include "AthLinks/tools/IdentContIndex.h" + + +#endif // not DATAMODEL_TOOLS_IDENTCONTINDEX_H diff --git a/EDM/athena/Control/DataModel/DataModel/unordered_map.h b/EDM/athena/Control/DataModel/DataModel/unordered_map.h new file mode 100644 index 00000000..6110bba8 --- /dev/null +++ b/EDM/athena/Control/DataModel/DataModel/unordered_map.h @@ -0,0 +1,26 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: unordered_map.h,v 1.4 2008-01-03 21:20:51 ssnyder Exp $ +/** + * @file DataModel/unordered_map.h + * @author scott snyder <snyder@bnl.gov>, copied from gcc4. + * @date Apr, 2007 + * @brief This is the TR1 unordered_set implementation from gcc4, + * adapted to build in Atlas. Once the TR1 library is available + * on all our platforms, we can switch to using the system-supplied + * version instead. + * + * This has been moved to CxxUtils, leaving this as a forwarding header + * for now. + */ + +#ifndef DATAMODEL_UNORDERED_MAP_H +#define DATAMODEL_UNORDERED_MAP_H + +#include "CxxUtils/unordered_map.h" + +#endif /* GNU_LIBSTDCXX_TR1_UNORDERED_MAP_ */ diff --git a/EDM/athena/Control/DataModel/cmt/requirements b/EDM/athena/Control/DataModel/cmt/requirements new file mode 100644 index 00000000..8786c6c3 --- /dev/null +++ b/EDM/athena/Control/DataModel/cmt/requirements @@ -0,0 +1,20 @@ +package DataModel + +author Paolo Calafiura <Paolo.Calafiura@cern.ch> +author Hong Ma <hma@bnl.gov> +author Srini Rajagopalan <srinir@bnl.gov> + +use AtlasPolicy AtlasPolicy-* +use SGTools SGTools-* Control +use AthAllocators AthAllocators-* Control +use AthLinks AthLinks-* Control +use AthContainers AthContainers-* Control +use CxxUtils CxxUtils-* Control + +# Declare this package as a cmake metalibrary so that the libraries and header files from +# package it depends on are available to its clients. Transparent to CMT +apply_pattern cmake_add_command command=metalibrary + +private +macro_append DOXYGEN_INPUT " ../doc" + diff --git a/EDM/athena/Control/DataModel/doc/MainPage.h b/EDM/athena/Control/DataModel/doc/MainPage.h new file mode 100644 index 00000000..9931a5e5 --- /dev/null +++ b/EDM/athena/Control/DataModel/doc/MainPage.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + + \mainpage + +%StoreGate is a toolkit to implement the Atlas Data Model. +It consists of three packages %StoreGate, DataModel(this one) and SGTools. + +This package contains the tools to design Data Objects to be used in Athena + +\section links DataLink and ElementLink +these are two class templates to write persistable inter-object +references. They can be used as c++ pointers and read and written +to/from disk. For details see the doc of the two classes, the +StoreGate user guide (link below) and the examples in AthExStoreGateExamples + +\section pool DataPool +a memory pool typically used by the containers above to speed-up +element allocation + +\section Documentation Documentation + +A tutorial is available from +http://atlas.web.cern.ch/Atlas/GROUPS/SOFTWARE/OO/architecture/EventDataModel/Tutorial/ + +The user guide is part of the Data Model User Guide which is +maintained as a CVS package +(http://atlassw1.phy.bnl.gov/lxr/source/atlas/AtlasDoc/doc/DataModel/). + +More information is available from the Data Model page +(http://atlas.web.cern.ch/Atlas/GROUPS/SOFTWARE/OO/architecture/EventDataModel/index.html). + +The code can be browsed using LXR +(http://atlassw1.phy.bnl.gov/lxr/source/atlas/Control/StoreGate/) + +To generate doxygen doc, run (from the cmt dir) gmake doxygen and point +your browser to .../doc/Doxygen/html/index.html + +\section Examples Examples + +The package Control/AthenaExamples/AthExStoreGateExamples contains +running examples of algorithms accessing Data Objects using StoreGateSvc. +This examples are (very close to) the ones described in the tutorial above + +\section tests Unit Tests + +The directory test contains several test programs that can be run issuing +a "gmake check" or a ../run/runUnitTests.sh + + +\author Paolo Calafiura <Paolo.Calafiura@cern.ch> +\author Hong Ma <hma@bnl.gov> +\author Srini Rajagopalan <srinir@bnl.gov> +*/ diff --git a/EDM/athena/Control/DataModel/ispellwords b/EDM/athena/Control/DataModel/ispellwords new file mode 100644 index 00000000..5b273246 --- /dev/null +++ b/EDM/athena/Control/DataModel/ispellwords @@ -0,0 +1,699 @@ +personal_ws-1.1 en 698 +assoPointer +persistency +IdentifiableContainer +multi +toContainedElement +GaudiKernel +situ +someone's +refcnt +GENERATEINDEXINGPOLICIES +elementShortRef +originalSize +unary +blk +arg +objectContainer +dataID +bkt +Amram +endif +typeid +fooB +ForwardIndexingPolicy +JetCollection +resized +constr +PackedArray +const's +RandomAccessIterator +CompareAndPrint +del +IProxyDict +deallocate +dep +DVLNoBase +cassert +creat +ASHSTLAllocator +ness +Resizes +autoselect +doinit +setElement +DataVector +theAsso +addHostDObj +gaudi +Dreizin +scott +theAssociatedObjects +cmt +objIndex +assocIndex +dir +ArenaAllocatorRegistry +allocator's +persistifiable +InhVectorIntLink +functor +nclear +crc +elmts +ssnyder +Predwrapper +MessageSvc +DNC +readback +binet +theTrack +DL's +DataPool +Faz +newAssoc +fdl +GenerateIndexingPolicy +ConstDataVector +AtlasReflex +fangled +fdv +LongRef +pCont's +gcc +Ilija +HistogramPersis +absFluff +liint +getAssociations +allo +isDefault +utest +ArenaCachingHandle +depcy +nctor +ELs +CVS +ClassName +destructor +tTrack +elt +hashtable's +PlainPtrElementLink +ELV +DList +DSO +resetWithKeyAndIndex +DataLinkVector +ElemLink +resetWithKey +typedef +pbad +dum +firstAssoc +cxx +theStore +BaseContainer +persistified +dvl +endAssociation +ispellwords +ILink +endHostDObjs +shortRefs +shortrefs +GenParticleIndexing +Elsing +DV's +BinaryPredicate +anOther +FooDequeLink +moveHostDObjs +theObjects +FooDeque +ArenaBase +AtlasSEAL +FNV +NoBase +icc +iCtr +NOGAUDI +swapElement +defaultHeader +objectPointer +src's +StoreGateSvc +hashtable +CopyConstructible +findProxy +BeginEvent +GNUC +toPersistentDL +iff +firstAssObject +bitsize +pCopyDerFluff +findAssociationObjects +DataVectorBase +fdvlcopy +line'll +func +ArenaHandleBaseAllocT +asDataList +CLID's +CLIDs +convertable +fdlcopy +hoc +DHAVE +functionalities +addArena +dataGet +namespaces +StoreGate +IOSTREAMS +oldElem +DataProxy +paolo +eltest +jobOs +AssociationLinks +DataLink +RVersion +pAssoc +hpp +TODO +valgrind +DataProxyStorageBase +srini +getObject +ASSCONT +cerr +proxying +ASSOCONT +DataListBase +AthenaPOOL +Calafiura +MapIndexingPolicy +param +AssociationVector +IProxyDictWithPool +persistify +changeState +canReclear +doxygen +setHashAndIndex +runtime +lcg +args +DataList +DataPtrs +rebinder +theAssociations +inserters +uint +ndtor +DVLCast +theAssociationObjects +assoStore +AssociationVectorCollection +isStreamable +irt +resetTo +AssociationVectorIterator +wronglmint +pairtype +pdata +RemoveDataPtr +theType +printf +setStorableObject +ArenaHeapSTLAllocator +iJet +doRemap +toPersistable +OBJCONT +deallocation +iTracks +getFirstAssociation +SGFolder +AssociationLinkCollection +objectIter +lhs +storeName +ArenaBlockAllocatorBase +rvalue +DerivedFluff +ElemLinkVector +ArenaHeaderGaudiClear +mem +hasher +dobjs +assoIter +Quarrie +hasAssociations +assoContainer +dereferencing +cinquanta +IdentContIndexingPolicy +DVLDataBucket +ElementLinkVector +vers +PDTR +nav +Hong +forwardContainer +cinq +eltSize +AtlasBoost +CINT +typeinfoName +reverseIterators +ArenaPoolAllocator +kwd +ndx +resize +indexingPolicy +tradeoff +ClusterContainer +oldInt +getDataSourcePointer +MacOSX +NavigationToken +asso +PlainPtrStorage +bool +shortref +shortRef +dieci +DataMap +Nir +OBJTYPE +asDataVector +ArenaHeapAllocator +DataLinks +gmake +mLink +castfn +AssociationBaseCollection +clid +deps +LWG +namespace +IOHandler +ArenaAllocatorCreatorInit +pdf +pAssocs +dflt +dfluff +pDL +reflextion +typename +typeName +DVLIterator +iTrack +getDataSource +initParams +LXR +DataBucket +pDV +pJets +refCount +snyder +ASSOBJECT +initGaudi +Srini's +multimap +pTransient +DataBucketTrait +dict +ElemLinkRefs +interoperate +nreserve +lastAssObject +theAssoc +TrackContainer +init +minRefCount +impl +OwnershipPolicy +otherElemLinkRefs +AssociativeIndexingPolicy +DataVector's +oper +IsSTLSequence +findProxyFromKey +newAss +mutators +addTrack +IncidentSvc +makeIndex +sgkey +StrictWeakOrdering +lastTrack +ClassID +classID +calaf +rbegin +containsAssociation +SetIndexingPolicy +ifndef +assocPointer +BaseConstReference +pos +PtrVector +ret +pre +params +BList +theAssocs +ArenaAllocatorBase +Dufus +GaudiClear +ppvInterface +reextracted +lookup +arghh +rhs +pointee +maxRefCount +config +toPersistentState +intL +Sep +hostDObjs +ClassIDSvc +ptr +BVec +intV +pvp +getDataSourcePointerFromGaudi +RNG +pTracks +Metafunction +ArenaHandleBase +shortIterFromLong +tCluster +successFlag +genreflex +DataProxyStorage +DataProxyStorageData +theJet +ElementType +ELVDEBUG +PtrList +AllocatorCreatorBase +asStorable +ArenaSharedHeapSTLAllocator +AthenaKernel +ChangeLog +getLastAssocation +nblock +dvlinfo +DVLInfo +PlainPtrDataLink +src +cout +IDtype +pcopy +jobO +Vec +resizePool +TestTools +dtors +DataPtr +tdefs +enums +ArenaSTLAllocator +findHostDObj +DataList's +toIndexedElement +stl +sizeof +svc +cptr +sss +checkreq +dobj +Vukotic +packageinfo +frexp +str +setData +MyObj +iter +DVLEltBase +AssociationType +clidsvc +CLIDSvc +backNavigation +toPersistent +theCluster +mustClear +storable +IInterface +AssociationObjectIterator +DefaultKey +TSS +inlined +Rajagopalan +makeFunc +savannah +ArenaBlock +multiset +GeneratorObjects +reverseLookup +DefaultState +Obreshkov +pred +malloc +myassert +AthExStoreGateExamples +DVLInfoBase +setOwner +txt +myCluster +FIXME +LIBSTDCXX +ArenaAllocatorCreator +Gemmeren +makeAllocator +JetTrackAssociation +IOVSvc +prev +newElement +beginAssociation +specializable +removeHostDObj +toAccessible +RefVector +EndEvent +PersistentState +tinfo +myassertion +elcnv +ctor +struct +vpvp +dereference +allocvec +getDataRef +ElementParameter +fdvl +AthenaROOTAccess +ControlTest +objectIndex +iHost +emacs +alloc +pElem +riid +accessor +setValid +DataObject +makeCurrent +dpint +symLink +decls +ElementLink +bb +anAss +DataSource +linkOffset +linkoffset +lookups +refVector's +DPSB +isValid +ibadlint +ForwardIterator +assoIndex +firstTrack +NDEBUG +NULLs +templated +endl +br +getDataPtr +venti +eg +dl +mainpage +VirtBases +DefaultIndexingPolicy +utests +reportStr +fd +FooDataVectorLink +CxxUtils +ivint +findInContainer +dv +DVLTYPE +RehashPolicy +ElementProxy +theObject +fn +JetTrackAssociationCollection +SGASSERTERROR +checkForRemap +iliint +toTransient +anotherString +ctors +AssociationLink +FolderItem +IdentContIndex +dereferences +iptrlint +intLF +DataModel +getLastAssociation +IP +indices +multithreaded +sstream +intLL +ld +destructors +Elts +ownPolicy +tryELRemap +li +rvalues +DeclareIndexingPolicy +Koenig +IndexingPolicies +nd +xyz +Austern +delArena +TrackParticleContainer +minSize +toAccessibleState +storagePolicy +NavFourMon +ArenaHandle +ConstDataList +ok +TrackParticle +ChronoStatSvc +ElemLinkRef +ns +findAssociation +Compwrapper +proxied +gccxml +RegisterDVLEltBaseInit +badI +DataPoolTest +os +stdcont +stdCont +initializer +lastAssoc +DVec +ri +BaseInfo +sg +ElemLinks +ElemLink's +targ +DirSearchPath +ELVRef +intVF +headp +BidirectionalIterator +cplusplus +Tavori +SGElvRef +dtor +enum +schaffer +intVL +vd +ForwardContainerConcept +InUse +sz +WG +ArenaPoolSTLAllocator +inline +typedefs +typedef's +Vo +getE +vp +sgname +sgName +rObj +SequenceIndexing +setStorable +trenta +AssociationMap +abc +thinning's +newElem +jobOptions +getAssociationObjects +myarena +lvalues +CategoryOrTraversal +PTAss +accessors +Mytype +raiseInvalidErrorBase +MyElement +rdata +adaptors +toPersistentNomap +DVL's +endcode +aFoo +ftemplate +ExtractKey +ArenaHandleBaseT +defaultDataSource +IdentifiedState +lvalue +ElementHolder +adaptor +preload +ifdef +AssociationBase +theContext +AssociationObject +ArenaHeader +ElementLinks +toIdentified +wrongvint +AssociationObjects +Baz +overridable +const +SGTools +NULLLINK +DefaultKeyState +getDataSourcePointerFunc +libstdc +persistable +SGgetDataSource diff --git a/EDM/athena/Control/DataModelRoot/CMakeLists.txt b/EDM/athena/Control/DataModelRoot/CMakeLists.txt new file mode 100644 index 00000000..b954732a --- /dev/null +++ b/EDM/athena/Control/DataModelRoot/CMakeLists.txt @@ -0,0 +1,25 @@ +################################################################################ +# Package: DataModelRoot +################################################################################ + +# Declare the package name: +atlas_subdir( DataModelRoot ) + +# External dependencies: +find_package( ROOT COMPONENTS Cintex Core Tree MathCore Hist RIO pthread ) + +# tag ROOTCintexLibs was not recognized in automatic conversion in cmt2cmake + +# Component(s) in the package: +atlas_add_library( DataModelRoot + src/*.cxx + PUBLIC_HEADERS DataModelRoot + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ) + +atlas_add_dictionary( DataModelRootDict + DataModelRoot/DataModelRootDict.h + DataModelRoot/selection.xml + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} DataModelRoot ) + diff --git a/EDM/athena/Control/DataModelRoot/DataModelRoot/DataModelRootDict.h b/EDM/athena/Control/DataModelRoot/DataModelRoot/DataModelRootDict.h new file mode 100644 index 00000000..6a79c17f --- /dev/null +++ b/EDM/athena/Control/DataModelRoot/DataModelRoot/DataModelRootDict.h @@ -0,0 +1,12 @@ +// dear emacs, this is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#ifndef DATAMODELROOTDICT_H + +#include "DataModelRoot/RootType.h" + +#endif diff --git a/EDM/athena/Control/DataModelRoot/DataModelRoot/RootType.h b/EDM/athena/Control/DataModelRoot/DataModelRoot/RootType.h new file mode 100644 index 00000000..f93b2357 --- /dev/null +++ b/EDM/athena/Control/DataModelRoot/DataModelRoot/RootType.h @@ -0,0 +1,269 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef DATAMODELROOT_ROOT_TYPE_H +#define DATAMODELROOT_ROOT_TYPE_H + +// ROOT +#include "TClassRef.h" +class TBaseClass; +class TDictionary; +class TDictAttributeMap; +class TMethod; +class TFunction; +class TDataMember; +class TMethodArg; + +#include "RVersion.h" + +#if ROOT_VERSION_CODE < ROOT_VERSION(5,99,0) +#include "Reflex/Kernel.h" +#include "Reflex/Type.h" +#include "Reflex/Object.h" +#include "Reflex/Member.h" + +namespace std { class type_info; } + +class RootType : public Reflex::Type { +public: + RootType(const Reflex::Type& rh) : Reflex::Type(rh) {} + RootType(const Reflex::TypeName* typName = 0, unsigned int modifiers = 0) : + Reflex::Type(typName, modifiers) {} + /// Better constructors + RootType(const std::string& name) : Reflex::Type(Reflex::Type::ByName(name)) {} + RootType(const std::type_info& info) : Reflex::Type(Reflex::Type::ByTypeInfo(info)) {} + /// Standard destructor + virtual ~RootType() {} + + void AddProperty(const char* key, const char* value) const { + this->Properties().AddProperty(key, value); + } + std::string Name() const { return this->Reflex::Type::Name(Reflex::SCOPED); } + std::string Name(int flags) const { return this->Reflex::Type::Name(flags); } + + using Type::operator=; + + /// call Cintex::Enable() + static void EnableCintex(); +}; + +typedef Reflex::Member RootDataMember; +typedef Reflex::Object RootObject; +typedef Reflex::PropertyList RootPropertyList; + +#else // ROOT 6 +#define ROOT_6 + +namespace Reflex { + + /** enum for printing names */ + enum ENTITY_HANDLING { + FINAL = (1<<0), + QUALIFIED = (1<<1), + SCOPED = (1<<2), + }; + +} // namespace Reflex + +// Standard +#include <string> + + +class TScopeAdapter; +typedef TScopeAdapter TTypeAdapter; + + +class TPropertyListAdapter { +public: + TPropertyListAdapter( TDictAttributeMap* dam ) : fAttributes( dam ) {} + +public: + Bool_t HasProperty( const std::string& key ) const; + std::string PropertyAsString(const std::string& key) const; + +private: + TDictAttributeMap* fAttributes; +}; + +class TReturnTypeAdapter { +public: + TReturnTypeAdapter( const std::string& name ) : fName( name ) {} + + std::string Name( unsigned int mod = 0 ) const; + +private: + std::string fName; +}; + + +class TMemberAdapter { +public: + TMemberAdapter( TMethod* meth ); + operator TMethod*() const; + + TMemberAdapter( TFunction* func ); + operator TFunction*() const; + + TMemberAdapter( TDataMember* mb ); + operator TDataMember*() const; + + TMemberAdapter( TMethodArg* ma ); + operator TMethodArg*() const; + + operator Bool_t() const { return fMember != 0; } + +public: + std::string Name( unsigned int mod = 0 ) const; + + const char* GetSharedLibs() const; + size_t Offset() const; + + Bool_t IsConstant() const; + Bool_t IsConstructor() const; + Bool_t IsEnum() const; + Bool_t IsPublic() const; + Bool_t IsStatic() const; + Bool_t IsTransient() const; + + size_t FunctionParameterSize( Bool_t required = false ) const; + TMemberAdapter FunctionParameterAt( size_t nth ) const; + std::string FunctionParameterNameAt( size_t nth ) const; + std::string FunctionParameterDefaultAt( size_t nth ) const; + + TReturnTypeAdapter ReturnType() const; + TScopeAdapter DeclaringScope() const; + TTypeAdapter DeclaringType() const; + TTypeAdapter TypeOf() const; + +private: + TDictionary* fMember; +}; + + +class TBaseAdapter { +public: + TBaseAdapter( TBaseClass* base ) : fBase( base ) {} + operator Bool_t() const { return fBase != 0; } + +public: + std::string Name() const; + + TScopeAdapter ToType() const; + +private: + TBaseClass* fBase; +}; + + +class TScopeAdapter { +public: + TScopeAdapter(); + TScopeAdapter( TClass* klass ); + TScopeAdapter( const std::string& name, Bool_t load = kTRUE, Bool_t quiet = kFALSE ); + TScopeAdapter( const TMemberAdapter& ); + TScopeAdapter( const std::type_info &typeinfo ); + operator TClass*() const { return fClass.GetClass(); } + operator Bool_t() const; + +public: + static TScopeAdapter ByName( + const std::string& name, Bool_t load = kTRUE, Bool_t quiet = kTRUE ); + + static TScopeAdapter TypeAt( size_t nth ); + static size_t TypeSize(); + +public: + std::string Name( unsigned int mod = Reflex::SCOPED ) const; + TScopeAdapter DeclaringScope() const; + + void *Construct() const ; + void *Construct(void *place) const; + void Destruct(void *place) const; + + const std::type_info& TypeInfo() const; + TPropertyListAdapter Properties() const; + + Bool_t IsPointer() const; + Bool_t IsTemplateInstance() const; + Bool_t IsTopScope() const; + Bool_t IsFundamental() const; + Bool_t IsEnum() const; + Bool_t IsTypedef() const; + Bool_t IsArray() const; + + TBaseAdapter BaseAt( size_t nth ) const; + size_t BaseSize() const; + + size_t SizeOf() const; + + TMemberAdapter FunctionMemberAt( size_t nth ) const; + size_t FunctionMemberSize() const; + + TMemberAdapter DataMemberAt( size_t nth ) const; + size_t DataMemberSize() const; + + TScopeAdapter TemplateArgumentAt( size_t nth ) const; + size_t TemplateArgumentSize() const; + +public: + Bool_t IsComplete() const; + + Bool_t IsClass() const; + Bool_t IsStruct() const; + Bool_t IsNamespace() const; + +// note: in Reflex, part of Type, not Scope + Bool_t IsAbstract() const; + + void* Id() const { return fClass.GetClass(); } + TClass* Class() const { return fClass.GetClass(); } + + TTypeAdapter ToType() const { return *this; } + TScopeAdapter TypeOf() const { return *this; } + +// for STL containers + bool operator==( const TScopeAdapter& rh ) const; + bool operator!=( const TScopeAdapter& rh ) const { + return ! (*this == rh); + } + bool operator<( const TScopeAdapter& rh ) const; + + // Noop in ROOT6 + static void EnableCintex() {} + +private: + std::string fName; + TClassRef fClass; + bool isFundamental = false; +}; + + +typedef TBaseAdapter RootBase; +typedef TMemberAdapter RootDataMember; +typedef TPropertyListAdapter RootPropertyList; +typedef TScopeAdapter RootScope; +typedef TTypeAdapter RootType; + + +//MN: ad-hoc simplistic reimplementation of Reflex::Object +class RootObject +{ +public: + RootObject(const RootType& type=RootType(), void* obj=0); + + void* Address() const { return m_object; } + const RootType& Type() const { return m_type; } + RootObject CastObject( const RootType &toType) const; + +private: + RootType m_type; + void* m_object = 0; + std::string m_objectName; ///not used yet +}; + + + +#endif // ROOT ver + +#endif // !DATAMODELROOT_ROOT_TYPE_H diff --git a/EDM/athena/Control/DataModelRoot/DataModelRoot/selection.xml b/EDM/athena/Control/DataModelRoot/DataModelRoot/selection.xml new file mode 100644 index 00000000..d5f599ca --- /dev/null +++ b/EDM/athena/Control/DataModelRoot/DataModelRoot/selection.xml @@ -0,0 +1,5 @@ +<lcgdict> + + <class name="RootType" /> + +</lcgdict> diff --git a/EDM/athena/Control/DataModelRoot/cmt/requirements b/EDM/athena/Control/DataModelRoot/cmt/requirements new file mode 100644 index 00000000..43b65463 --- /dev/null +++ b/EDM/athena/Control/DataModelRoot/cmt/requirements @@ -0,0 +1,21 @@ +package DataModelRoot + +author Marcin Nowak + +use AtlasPolicy AtlasPolicy-* +use AtlasROOT AtlasROOT-* External +use AtlasReflex AtlasReflex-* External -no_auto_imports + +# Add cmake compatibility (doesn't do anything on CMT side of things) +apply_pattern cmake_add_command command="find_package(ROOT COMPONENTS Cintex)" + +#======= LIBRARY +library DataModelRoot *.cxx +apply_pattern installed_library + +apply_pattern lcgdict dict=DataModelRoot \ + selectionfile="selection.xml" \ + headerfiles="../DataModelRoot/DataModelRootDict.h" + +private +apply_tag ROOTCintexLibs diff --git a/EDM/athena/Control/DataModelRoot/src/RootType.cxx b/EDM/athena/Control/DataModelRoot/src/RootType.cxx new file mode 100644 index 00000000..6643b47b --- /dev/null +++ b/EDM/athena/Control/DataModelRoot/src/RootType.cxx @@ -0,0 +1,1002 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "DataModelRoot/RootType.h" + +#ifdef ROOT_6 + +// ROOT +#include "TBaseClass.h" +#include "TClass.h" +#include "TClassEdit.h" +#include "TClassTable.h" +#include "TDataType.h" +#include "TDataMember.h" +#include "TDictAttributeMap.h" +#include "TError.h" +#include "TFunction.h" +#include "TInterpreter.h" +#include "TMethod.h" +#include "TMethodArg.h" +#include "TROOT.h" +#include "TEnum.h" + +// Standard +#include <assert.h> +#include <cxxabi.h> +#include <iostream> +using namespace std; + + +//= helpers ================================================================== +static const std::string ResolveTypedef( const std::string& tname ) +{ +// Helper; captures common code needed to find the real class name underlying +// a typedef (if any). + std::string tclean = TClassEdit::CleanType( tname.c_str() ); + + TDataType* dt = gROOT->GetType( tclean.c_str() ); + if ( dt ) return dt->GetFullTypeName(); + + return TClassEdit::ResolveTypedef( tclean.c_str(), true ); +} + +static inline const std::string UnqualifiedTypeName( const std::string name ) +{ + return TClassEdit::ShortType( + TClassEdit::CleanType( name.c_str(), 1 ).c_str(), 5 ); +} + + +//= TPropertListAdapter ====================================================== +static std::string map_property( const std::string& key ) +{ + if ( key == "ClassID" ) return "id"; + return key; +} + +//____________________________________________________________________________ +Bool_t TPropertyListAdapter::HasProperty( const std::string& key ) const +{ + if ( fAttributes ) + return fAttributes->HasKey( map_property( key ).c_str() ); + return kFALSE; +} + + +//____________________________________________________________________________ +std::string TPropertyListAdapter::PropertyAsString( const std::string& key ) const +{ + if ( fAttributes ) + return fAttributes->GetPropertyAsString( map_property( key ).c_str() ); + return ""; +} + + +//= TReturnTypeAdapter ======================================================= +std::string TReturnTypeAdapter::Name( unsigned int mod ) const +{ +// get the name of the return type that is being adapted + std::string name = fName; + + if ( mod & Reflex::FINAL ) + name = ResolveTypedef( name ); + + if ( ! ( mod & Reflex::QUALIFIED ) ) + name = UnqualifiedTypeName( fName ); + + return name; +} + + +//= TMemberAdapter =========================================================== +TMemberAdapter::TMemberAdapter( TMethod* meth ) : fMember( meth ) +{ + /* empty */ +} + +//____________________________________________________________________________ +TMemberAdapter::operator TMethod*() const +{ +// cast the adapter to a TMethod* being adapted, returns 0 on failure + return dynamic_cast< TMethod* >( const_cast< TDictionary* >( fMember ) ); +} + +//____________________________________________________________________________ +TMemberAdapter::TMemberAdapter( TFunction* func ) : fMember( func ) +{ + /* empty */ +} + +//____________________________________________________________________________ +TMemberAdapter::operator TFunction*() const +{ +// cast the adapter to a TFunction* being adapted, returns 0 on failure + return dynamic_cast< TFunction* >( const_cast< TDictionary* >( fMember ) ); +} + +//____________________________________________________________________________ +TMemberAdapter::TMemberAdapter( TDataMember* mb ) : fMember( mb ) +{ + /* empty */ +} + +//____________________________________________________________________________ +TMemberAdapter::operator TDataMember*() const +{ +// cast the adapter to a TDataMember* being adapted, returns 0 on failure + return dynamic_cast< TDataMember* >( const_cast< TDictionary* >( fMember ) ); +} + +//____________________________________________________________________________ +TMemberAdapter::TMemberAdapter( TMethodArg* ma ) : fMember( ma ) +{ + /* empty */ +} + +//____________________________________________________________________________ +TMemberAdapter::operator TMethodArg*() const +{ +// cast the adapter to a TMethodArg* being adapted, returns 0 on failure + return dynamic_cast< TMethodArg* >( const_cast< TDictionary* >( fMember ) ); +} + +//____________________________________________________________________________ +TTypeAdapter TMemberAdapter::TypeOf() const +{ + // get the type of the data member + TDataMember* dataMember = (TDataMember*)*this; + if ( dataMember ) { + // MN: the only way to get the type is through the type name + TClass *tc = TClass::GetClass( dataMember->GetTypeName() ); + //cout << "--- TMemberAdapter name=" << Name() << endl; + if( tc ) { + //cout << " type = " << tc->GetName() << endl; + return TTypeAdapter(tc); + } else { + //cout << " typename = " << dataMember->GetTypeName() << endl; + return TTypeAdapter(dataMember->GetTypeName()); + } + } + + // get type of the function/method + TMethod* method = (TMethod*)*this; + if ( method ) + return method->GetClass(); + + return TTypeAdapter(); +} + + +//____________________________________________________________________________ +std::string TMemberAdapter::Name( unsigned int mod ) const +{ +// return name of the type described by fMember + TMethodArg* arg = (TMethodArg*)*this; + + if ( arg ) { + + std::string name = arg->GetTypeNormalizedName(); + if ( mod & Reflex::FINAL ) + name = ResolveTypedef( name ); + + if ( ! ( mod & Reflex::QUALIFIED ) ) + name = UnqualifiedTypeName( name ); + + return name; + + } else if ( mod & Reflex::FINAL ) + return ResolveTypedef( fMember->GetName() ); + + if ( fMember ) + return fMember->GetName(); + return "<unknown>"; // happens for classes w/o dictionary +} + +//____________________________________________________________________________ +const char* TMemberAdapter::GetSharedLibs() const +{ +// return the shared libs corresponding to this classes (should be 'lib'?) + return gInterpreter->GetClassSharedLibs( Name().c_str() ); +} + +//____________________________________________________________________________ +size_t TMemberAdapter::Offset() const +{ +// relative offset (instance data) or global pointer (static/global data + TDataMember* dm = (TDataMember*)*this; + return dm ? dm->GetOffsetCint() : 0; +} + +//____________________________________________________________________________ +Bool_t TMemberAdapter::IsConstant() const +{ +// test if the adapted member is a const method + return fMember->Property() & kIsConstMethod; +} + +//____________________________________________________________________________ +Bool_t TMemberAdapter::IsConstructor() const +{ +// test if the adapted member is a const method + return ((TFunction*)fMember) ? (((TFunction*)fMember)->ExtraProperty() & kIsConstructor) : kFALSE; +} + +//____________________________________________________________________________ +Bool_t TMemberAdapter::IsEnum() const +{ +// test if the adapted member is of an enum type + return fMember->Property() & kIsEnum; +} + +//____________________________________________________________________________ +Bool_t TMemberAdapter::IsPublic() const +{ +// test if the adapted member represents an public (data) member + return fMember->Property() & kIsPublic; +} + +//____________________________________________________________________________ +Bool_t TMemberAdapter::IsStatic() const +{ +// test if the adapted member represents a class (data) member + return fMember->Property() & kIsStatic; +} + +//____________________________________________________________________________ +Bool_t TMemberAdapter::IsTransient() const +{ +// test if the adapted member represents transient data + TDataMember* dm = (TDataMember*)*this; + return dm ? ! dm->IsPersistent() : kTRUE; +} + + +//____________________________________________________________________________ +size_t TMemberAdapter::FunctionParameterSize( Bool_t required ) const +{ +// get the total number of parameters that the adapted function/method takes + TFunction* func = (TFunction*)fMember; + if ( ! func ) + return 0; + + if ( required == true ) + return func->GetNargs() - func->GetNargsOpt(); + + return func->GetNargs(); +} + +//____________________________________________________________________________ +TMemberAdapter TMemberAdapter::FunctionParameterAt( size_t nth ) const +{ +// get the type info of the function parameter at position nth + return (TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth ); +} + +//____________________________________________________________________________ +std::string TMemberAdapter::FunctionParameterNameAt( size_t nth ) const +{ +// get the formal name, if available, of the function parameter at position nth + const char* name = + ((TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth ))->GetName(); + + if ( name ) + return name; + return ""; +} + +//____________________________________________________________________________ +std::string TMemberAdapter::FunctionParameterDefaultAt( size_t nth ) const +{ +// get the default value, if available, of the function parameter at position nth + TMethodArg* arg = (TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth ); + const char* def = arg->GetDefault(); + + if ( ! def ) + return ""; + +// special case for strings: "some value" -> ""some value" + if ( strstr( ResolveTypedef( arg->GetTypeNormalizedName() ).c_str(), "char*" ) ) { + std::string sdef = "\""; + sdef += def; + sdef += "\""; + return sdef; + } + + return def; +} + +//____________________________________________________________________________ +TReturnTypeAdapter TMemberAdapter::ReturnType() const +{ +// get the return type of the wrapped function/method + return TReturnTypeAdapter( ((TFunction*)fMember)->GetReturnTypeNormalizedName() ); +} + +//____________________________________________________________________________ +TScopeAdapter TMemberAdapter::DeclaringScope() const +{ +// get the declaring scope (class) of the wrapped function/method + TMethod* method = (TMethod*)*this; + if ( method ) + return method->GetClass(); + +// get the declaring scope (class) of the wrapped data member + TDataMember* dataMember = (TDataMember*)*this; + if ( dataMember ) + return dataMember->GetClass(); + +// happens for free-standing functions (i.e. global scope) + return std::string( "" ); +} + +TTypeAdapter TMemberAdapter::DeclaringType() const +{ +// no distinction between scope/type + return DeclaringScope(); +} + + +//= TBaseAdapter ============================================================= +std::string TBaseAdapter::Name() const +{ +// get the name of the base class that is being adapted + return fBase->GetName(); +} + +//____________________________________________________________________________ +TScopeAdapter TBaseAdapter::ToType() const +{ +// wrap the actual class representing this base + return TScopeAdapter( fBase->GetClassPointer() ); +} + + +//= TScopeAdapter ============================================================ +//============================================================================ +TScopeAdapter::TScopeAdapter() +{ + /* empty */ +} + +TScopeAdapter::TScopeAdapter( TClass* klass ) : fClass( klass ) +{ +// wrap a class (scope) + if ( fClass.GetClass() != 0 ) + fName = fClass->GetName(); +} + + +bool is_fundamental_type(const std::string& name) +{ + const char* typname = name.c_str(); + switch(typname[0]) { + case 'b': + if ( strcmp(typname,"bool") ==0 ) return true; + break; + case 'c': + if ( strcmp(typname,"char") ==0 ) return true; + break; + case 'l': + if ( strncmp(typname,"lib",3) ==0 ) return true; + if ( strcmp(typname,"long") ==0 ) return true; + if ( strcmp(typname,"long long") ==0 ) return true; + if ( strcmp(typname,"long long int") ==0 ) return true; + break; + case 'L': + if ( strcmp(typname,"Long_t") ==0 ) return true; + if ( strcmp(typname,"Long64_t") ==0 ) return true; + break; + case 'i': + if ( strcmp(typname,"int") ==0 ) return true; + if ( strcmp(typname,"__int64") ==0 ) return true; + break; + case 'I': + if ( strcmp(typname,"Int_t") ==0 ) return true; + break; + case 'e': + if ( strncmp(typname,"enum ",5) ==0 ) return true; + break; + case 'd': + if ( strcmp(typname,"double") ==0 ) return true; + break; + case 'D': + if ( strcmp(typname,"Double_t") ==0 ) return true; + break; + case 'f': + if ( strcmp(typname,"float") ==0 ) return true; + break; + case 'F': + if ( strcmp(typname,"Float_t") ==0 ) return true; + break; + case 's': + if( strcmp(typname,"short") ==0 ) return true; + if( strcmp(typname,"short int") ==0 ) return true; + break; + case 'S': + if ( strcmp(typname,"Short_t") ==0 ) return true; + break; + case 'u': + if ( strncmp(typname,"unknown",7) ==0 ) return true; + if ( strcmp(typname,"unsigned int") ==0 ) return true; + if ( strcmp(typname,"unsigned short") ==0 ) return true; + if ( strcmp(typname,"unsigned long") ==0 ) return true; + if ( strcmp(typname,"unsigned char") ==0 ) return true; + if ( strcmp(typname,"unsigned long long") ==0 ) return true; + if ( strcmp(typname,"unsigned long long int") ==0 ) return true; + break; + } + return false; +} + + +const std::type_info& fundamental_type(const std::string& name) +{ + const char* typname = name.c_str(); + switch(typname[0]) { + case 'b': + if ( strcmp(typname,"bool") ==0 ) return typeid(bool); + break; + case 'c': + if ( strcmp(typname,"char") ==0 ) return typeid(char); + break; + case 'l': + if ( strcmp(typname,"long") ==0 ) return typeid(long); + if ( strcmp(typname,"long long") ==0 ) return typeid(long long); + if ( strcmp(typname,"long long int") ==0 ) return typeid(long long int); + break; + case 'i': + if ( strcmp(typname,"int") ==0 ) return typeid(int); + break; + case 'd': + if ( strcmp(typname,"double") ==0 ) return typeid(double); + break; + case 'f': + if ( strcmp(typname,"float") ==0 ) return typeid(float); + break; + case 's': + if( strcmp(typname,"short") ==0 ) return typeid(short); + if( strcmp(typname,"short int") ==0 ) return typeid(short int); + break; + case 'u': + if ( strcmp(typname,"unsigned char") ==0 ) return typeid(unsigned char); + if ( strcmp(typname,"unsigned long") ==0 ) return typeid(unsigned long); + if ( strcmp(typname,"unsigned long long") ==0 ) return typeid(unsigned long long); + if ( strcmp(typname,"unsigned long long int") ==0 ) return typeid(unsigned long long int); + if ( strcmp(typname,"unsigned int") ==0 ) return typeid(unsigned int); + if ( strcmp(typname,"unsigned short") ==0 ) return typeid(unsigned short); + if ( strcmp(typname,"unsigned short int") ==0 ) return typeid(unsigned short int); + break; + case 'v': + if ( strcmp(typname,"void") ==0 ) return typeid(void); + break; + } + cerr << "WARNING! RootType getting typeinfo failed for: " << typname << endl; + return typeid(void); +} + + +//____________________________________________________________________________ +TScopeAdapter::TScopeAdapter( const std::string& name, Bool_t load, Bool_t quiet ) : + fName( name ) +{ + // Bool_t load = kTRUE; Bool_t quiet = kFALSE; // MN: move to parameters later + const string anonnmsp("(anonymous)"); + + // cout << "INFO: RootType::RootType() creating for type=" << name << endl; + Int_t oldEIL = gErrorIgnoreLevel; + if( quiet ) gErrorIgnoreLevel = 3000; + + if( !load ) { + // let GetClass() have a crack at it first, to prevent accidental loading + TClass* klass = TClass::GetClass( name.c_str(), load, quiet ); + if( klass ) { + gErrorIgnoreLevel = oldEIL; + fClass = klass; + return; + } + } else { + // load + const string scoped_name = Name( Reflex::SCOPED ); + fClass = TClassRef( scoped_name.c_str() ); + if( fClass.GetClass() ) { + // cout << "INFO: RootType::RootType(): found TClass for '" << scoped_name << "'" << endl; + gErrorIgnoreLevel = oldEIL; + return; + } + } + + // now check if GetClass failed because of lack of dictionary or it is maybe not a class at all + if( gROOT->GetType(name.c_str()) ) { + isFundamental = true; + //} else if( name.substr( name.length() - anonnmsp.length() ) == anonnmsp || + } else if( TEnum::GetEnum(name.c_str()) ) { + // MN: enum, or anonymous type that could be an enum. for the moment mark it as fundamental + isFundamental = true; + // cout << "DEBUG: RootType::RootType(): ignoring " << name << endl; + } else { + // cout << "WARNING!: RootType::RootType(): Cannot get the ROOT dictionary for <" << name << ">" + // << " (load=" << load << ")" << endl; + } + + gErrorIgnoreLevel = oldEIL; +} + + +//____________________________________________________________________________ +TScopeAdapter::TScopeAdapter( const std::type_info &typeinfo ) +{ + fClass = TClassRef( TClass::GetClass(typeinfo) ); // MN: is that right? + if( fClass.GetClass() ) { + fName = fClass->GetName(); + } else { + char buff[1024]; + size_t len = sizeof(buff); + int status = 0; + fName = __cxxabiv1::__cxa_demangle(typeinfo.name(), buff, &len, &status); + isFundamental = true; + } +} + +//____________________________________________________________________________ +TScopeAdapter::TScopeAdapter( const TMemberAdapter& mb ) : + fName( mb.Name( Reflex::QUALIFIED | Reflex::SCOPED ) ), + fClass( mb.Name( Reflex::SCOPED ).c_str() ) +{ + /* empty */ +} + +//____________________________________________________________________________ +TScopeAdapter TScopeAdapter::ByName( + const std::string& name, Bool_t load, Bool_t quiet ) +{ + return TScopeAdapter(name, load, quiet); + + /* MN: causes problems in ROOT6, do we need it? + if (klass.GetClass() && klass->GetListOfAllPublicMethods()->GetSize() == 0) { + // sometimes I/O interferes, leading to zero methods: reload from CINT + ClassInfo_t* cl = gInterpreter->ClassInfo_Factory( name.c_str() ); + if ( cl ) { + gInterpreter->SetClassInfo( klass, kTRUE ); + gInterpreter->ClassInfo_Delete(cl); + } + } + return klass.GetClass(); + */ +} + +//____________________________________________________________________________ +TScopeAdapter TScopeAdapter::TypeAt( size_t nth ) +{ +// this is dreadful, but is the way checkDictionary() works ... it better make +// sure that it does not load extra classes inside its loop (seems to be how +// it should be, but is not how it is) + return TScopeAdapter( gClassTable->At( nth ) ); +} + +//____________________________________________________________________________ +size_t TScopeAdapter::TypeSize() +{ +// return total number of types in the system (this is stupid, as the number +// of types is dynamic ...) + return gClassTable ? gClassTable->Classes() : 0; +} + +//____________________________________________________________________________ +std::string TScopeAdapter::Name( unsigned int mod ) const +{ +// Return name of type described by fClass + if ( ! fClass.GetClass() || ! fClass->Property() ) { + // fundamental types have no class, and unknown classes have no property + std::string name = fName; + + if ( mod & Reflex::FINAL ) + name = ResolveTypedef( name ); + + if ( ! ( mod & Reflex::QUALIFIED ) ) + name = UnqualifiedTypeName( fName ); + + return name; + } + + std::string name = fClass->GetName(); + if ( mod & Reflex::FINAL ) + name = ResolveTypedef( name ); + + if ( ! (mod & Reflex::SCOPED) ) { + // remove scope from the name + Int_t tpl_open = 0; + for ( std::string::size_type pos = name.size() - 1; 0 < pos; --pos ) { + std::string::value_type c = name[ pos ]; + + // count '<' and '>' to be able to skip template contents + if ( c == '>' ) + ++tpl_open; + else if ( c == '<' ) + --tpl_open; + else if ( tpl_open == 0 && c == ':' && 0 < pos && name[ pos-1 ] == ':' ) { + // found scope, strip name from it + name = name.substr( pos+1, std::string::npos ); + break; + } + } + } + + return name; +} + +//____________________________________________________________________________ +TScopeAdapter TScopeAdapter::DeclaringScope() const +{ + std::string name = Name( Reflex::FINAL | Reflex::SCOPED ); + std::string::size_type pos = name.rfind( "::" ); + if ( pos == std::string::npos ) + return TScopeAdapter( /* wrap global scope */ + TClass::GetClass( gInterpreter->ClassInfo_Factory( "" ) ) ); + return TScopeAdapter( name.substr( 0, pos ) ); +} + +//____________________________________________________________________________ +void* TScopeAdapter::Construct() const +{ + return fClass.GetClass()? fClass.GetClass()->New() : 0; +} + +//____________________________________________________________________________ +void *RootType::Construct(void *place) const { + return (place && fClass.GetClass())? fClass.GetClass()->New(place) : 0; +} + +//____________________________________________________________________________ +void TScopeAdapter::Destruct(void *place) const +{ + if (place && fClass.GetClass()) fClass.GetClass()->Destructor(place); +} + + +//____________________________________________________________________________ +const type_info& TScopeAdapter::TypeInfo() const +{ + if (isFundamental) { // Fundamentals have no fClass.GetClass() + return fundamental_type(fName); + } + return *fClass.GetClass()->GetTypeInfo(); +} + + +//____________________________________________________________________________ +TPropertyListAdapter TScopeAdapter::Properties() const +{ +// Reflex properties are more or less related to ROOT attributes: the names +// may be different (see map_property() above) + return isFundamental? TPropertyListAdapter(0) : fClass->GetAttributeMap(); +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsPointer() const +{ +// the assumption here is that the adapter can be initialized with a sugared +// name, e.g. for function arguments + return *fName.rbegin() == '*'; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsTemplateInstance() const +{ +// this concept differs quite a bit between ROOT/meta and Reflex; this code +// supports both, with the addendum that the ROOT/meta idea of templates will +// not have template arguments + if ( Name( Reflex::FINAL ).find('<') != std::string::npos ) + return kTRUE; // Reflex notion of templates + + if ( gInterpreter->CheckClassTemplate( Name( Reflex::SCOPED ).c_str() ) ) + return kTRUE; + + return kFALSE; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsTopScope() const +{ +// check whether this corresponds to the global scope + return fClass->GetClassInfo() == gInterpreter->ClassInfo_Factory( "" ); +} + +Bool_t TScopeAdapter::IsFundamental() const +{ + return isFundamental; +// return fClass.GetClass()? fClass.GetClass()->Property() & kIsFundamental : false; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsEnum() const +{ + return fClass.GetClass()? fClass.GetClass()->Property() & kIsEnum : false; +} +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsTypedef() const +{ + return fClass.GetClass()? fClass.GetClass()->Property() & kIsTypedef : false; +} +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsArray() const +{ + return fClass.GetClass()? fClass.GetClass()->Property() & kIsArray : false; +} + +//____________________________________________________________________________ +size_t TScopeAdapter::BaseSize() const +{ +// get the total number of base classes that this class has + if ( fClass.GetClass() && fClass->GetListOfBases() != 0 ) + return fClass->GetListOfBases()->GetSize(); + + return 0; +} + + +//____________________________________________________________________________ +size_t TScopeAdapter::SizeOf() const +{ + if (fClass.GetClass()) { + return fClass.GetClass()->Size(); + } else { + const TDataType* fundType = gROOT->GetType(fName.c_str()); + if ( fundType ) + return fundType->Size(); + } + return 0; +} + +//____________________________________________________________________________ +TBaseAdapter TScopeAdapter::BaseAt( size_t nth ) const +{ +// get the nth base of this class + return (TBaseClass*)fClass->GetListOfBases()->At( nth ); +} + +//____________________________________________________________________________ +size_t TScopeAdapter::FunctionMemberSize() const +{ +// get the total number of methods that this class has + if ( fClass.GetClass() ) + return fClass->GetListOfMethods()->GetSize(); + + return 0; +} + +//____________________________________________________________________________ +TMemberAdapter TScopeAdapter::FunctionMemberAt( size_t nth ) const +{ +// get the nth method of this class + return (TMethod*)fClass->GetListOfMethods()->At( nth ); +} + +//____________________________________________________________________________ +size_t TScopeAdapter::DataMemberSize() const +{ +// get the total number of data members that this class has + if ( fClass.GetClass() ) + return fClass->GetListOfDataMembers()->GetSize(); + + return 0; +} + +//____________________________________________________________________________ +TMemberAdapter TScopeAdapter::DataMemberAt( size_t nth ) const +{ +// get the nth data member of this class + return (TDataMember*)fClass->GetListOfDataMembers()->At( nth ); +} + +//____________________________________________________________________________ +TScopeAdapter TScopeAdapter::TemplateArgumentAt( size_t nth ) const +{ +// this is stupid, but highly likely never called, and if it is, only once, so +// I don't see a reason for caching to prevent the extra loops + std::string name = Name( Reflex::FINAL ); + size_t tpl_open = 0, argcount = 0; + std::string::size_type last = 0; + for ( std::string::size_type pos = 0; pos < name.size(); ++pos ) { + std::string::value_type c = name[pos]; + + // count '<' and '>' to be able to keep templated args intact + if ( c == '<' ) { + ++tpl_open; + if (tpl_open == 1) last = pos+1; + continue; + } else if (c == '>') { + --tpl_open; + } + if ((c == ',' && tpl_open == 1) || (c == '>' && tpl_open == 0)) { + if ( argcount++ == nth ) { + std::string part = + TClassEdit::CleanType( name.substr(last, pos-last).c_str(), 1 ); + return part; + } + last = pos+1; // done with part + } + } + + // should never be called + assert( !"miscount between TemplateArgumentSize() and TemplateArgumentAt()" ); + return TScopeAdapter(); +} + +//____________________________________________________________________________ +size_t TScopeAdapter::TemplateArgumentSize() const +{ +// this is stupid, too, see TemplateArgumentAt() above + std::string name = Name( Reflex::FINAL ); + size_t tpl_open = 0, argcount = 0; + for ( std::string::size_type pos = 0; pos < name.size(); ++pos ) { + std::string::value_type c = name[pos]; + + // count '<' and '>' to be able to keep templated args intact + if ( c == '<' ) { + ++tpl_open; + continue; + } else if ( c == '>' ) + --tpl_open; + + if ((c == ',' && tpl_open == 1) || (c == '>' && tpl_open == 0)) + ++argcount; + } + return argcount; +} + +//____________________________________________________________________________ +TScopeAdapter::operator Bool_t() const +{ +// check the validity of this scope (class) + if( fName.empty() ) return false; + if( isFundamental ) return true; + + // MN: rewriting this method to avoid premature header parsing + TClass* klass = fClass.GetClass(); + if( !klass ) return false; + if( klass->HasDictionary() ) return true; + + // cout << "RootType: (Debug warning) Type " << fName << " has no dictionary!" << endl; + return false; + + /* + Bool_t b = kFALSE; + + Int_t oldEIL = gErrorIgnoreLevel; + gErrorIgnoreLevel = 3000; + std::string scname = Name( Reflex::SCOPED ); + TClass* klass = TClass::GetClass( scname.c_str() ); + if ( klass && klass->GetClassInfo() ) // works for normal case w/ dict + b = gInterpreter->ClassInfo_IsValid( klass->GetClassInfo() ); + else { // special case for forward declared classes + cout << "RootType: checking validity for fwd decl type: " << fName << endl; + ClassInfo_t* ci = gInterpreter->ClassInfo_Factory( scname.c_str() ); + if ( ci ) { + b = gInterpreter->ClassInfo_IsValid( ci ); + gInterpreter->ClassInfo_Delete( ci ); // we own the fresh class info + } + } + gErrorIgnoreLevel = oldEIL; + return b; + */ +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsComplete() const +{ +// verify whether the dictionary of this class is fully available + Bool_t b = kFALSE; + + Int_t oldEIL = gErrorIgnoreLevel; + gErrorIgnoreLevel = 3000; + std::string scname = Name( Reflex::SCOPED ); + TClass* klass = TClass::GetClass( scname.c_str() ); + if ( klass && klass->GetClassInfo() ) // works for normal case w/ dict + b = gInterpreter->ClassInfo_IsLoaded( klass->GetClassInfo() ); + else { // special case for forward declared classes + ClassInfo_t* ci = gInterpreter->ClassInfo_Factory( scname.c_str() ); + if ( ci ) { + b = gInterpreter->ClassInfo_IsLoaded( ci ); + gInterpreter->ClassInfo_Delete( ci ); // we own the fresh class info + } + } + gErrorIgnoreLevel = oldEIL; + return b; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsClass() const +{ +// test if this scope represents a class + if ( fClass.GetClass() ) { + // some inverted logic: we don't have a TClass, but a builtin will be recognized, so + // if it is NOT a builtin, it is a class or struct (but may be missing dictionary) + return (fClass->Property() & kIsClass) || ! (fClass->Property() & kIsFundamental); + } + +// no class can mean either is no class (i.e. builtin), or no dict but coming in +// through PyCintex/Reflex ... as a workaround, use TDataTypes that has a full +// enumeration of builtin types + return TDataType( Name( Reflex::FINAL | Reflex::SCOPED ).c_str() ).GetType() == kOther_t; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsStruct() const +{ +// test if this scope represents a struct + if ( fClass.GetClass() ) { + // same logic as for IsClass() above ... + return (fClass->Property() & kIsStruct) || ! (fClass->Property() & kIsFundamental); + } + +// same logic as for IsClass() above ... + return TDataType( Name( Reflex::FINAL | Reflex::SCOPED ).c_str() ).GetType() == kOther_t; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsNamespace() const +{ +// test if this scope represents a namespace + if ( fClass.GetClass() ) + return fClass->Property() & kIsNamespace; + + return kFALSE; +} + +//____________________________________________________________________________ +Bool_t TScopeAdapter::IsAbstract() const +{ +// test if this scope represents an abstract class + if ( fClass.GetClass() ) + return fClass->Property() & kIsAbstract; // assume set only for classes + + return kFALSE; +} + +//____________________________________________________________________________ +bool TScopeAdapter::operator==( const TScopeAdapter& rh ) const +{ +// comparison operator, used for STL containers (implementation debatable) + return fClass.GetClass() == rh.fClass.GetClass(); +} + +//____________________________________________________________________________ +bool TScopeAdapter::operator<( const TScopeAdapter& rh ) const +{ +// less-than operator, used for STL containers (makes little sense conceptually, +// but this class is used as a key in std::map<>s for some reason; choosing to +// compare on name here, as any simple comparison (e.g. GetClassInfo()) is bound +// to fall apart if classes are unloaded/updated/replaced). + return Name( Reflex::FINAL | Reflex::SCOPED ) + < rh.Name( Reflex::FINAL | Reflex::SCOPED ); +} + + +//____________________________________________________________________________ +//____________________________________________________________________________ +RootObject::RootObject(const RootType& type, void* obj) + : m_type(type), m_object(obj) +{ +} + +//____________________________________________________________________________ +RootObject +RootObject::CastObject(const RootType &toType) const +{ + return (m_type.Class() && toType.Class())? + RootObject( toType, m_type.Class()->DynamicCast(toType.Class(), m_object) ) + : RootObject(); +} + + +#else // ROOT ver + +#include "Cintex/Cintex.h" +void RootType::EnableCintex() { + ROOT::Cintex::Cintex::Enable(); +} + +#endif // ROOT ver diff --git a/EDM/athena/Control/SGMon/SGAudCore/CMakeLists.txt b/EDM/athena/Control/SGMon/SGAudCore/CMakeLists.txt new file mode 100644 index 00000000..9359d9ec --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudCore/CMakeLists.txt @@ -0,0 +1,17 @@ +################################################################################ +# Package: SGAudCore +################################################################################ + +# Declare the package name: +atlas_subdir( SGAudCore ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + GaudiKernel ) + +# Component(s) in the package: +atlas_add_library( SGAudCore + src/*.cxx + PUBLIC_HEADERS SGAudCore + LINK_LIBRARIES GaudiKernel ) + diff --git a/EDM/athena/Control/SGMon/SGAudCore/SGAudCore/ISGAudSvc.h b/EDM/athena/Control/SGMon/SGAudCore/SGAudCore/ISGAudSvc.h new file mode 100644 index 00000000..dc7a0113 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudCore/SGAudCore/ISGAudSvc.h @@ -0,0 +1,63 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ISGAudSvc.h +// Header file for class ISGAudSvc +// Author: Ilija Vukotic<ivukotic@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef SGAUDCORE_ISGAUDSVC_H +#define SGAUDCORE_ISGAUDSVC_H + +// STL includes + +// FrameWork includes +#include "GaudiKernel/IService.h" +#include "GaudiKernel/ClassID.h" + +class ISGAudSvc : virtual public IService +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /** Destructor: + */ + virtual ~ISGAudSvc(); + + virtual bool SGSetCurrentAlg(){return true;};//std::string CurrAlg + + virtual void SGAudit(const std::string& /*key*/, const CLID& /*id*/, + const int& /*fnc*/, const int& /*store_id*/) {}; + + virtual void setFakeCurrentAlg(const std::string&){}//For custom increased granularity + virtual void clearFakeCurrentAlg(){} + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + static const InterfaceID& interfaceID(); + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +inline const InterfaceID& ISGAudSvc::interfaceID() +{ + static const InterfaceID IID_ISGAudSvc("ISGAudSvc", 1, 0); + return IID_ISGAudSvc; +} + +#endif diff --git a/EDM/athena/Control/SGMon/SGAudCore/cmt/requirements b/EDM/athena/Control/SGMon/SGAudCore/cmt/requirements new file mode 100644 index 00000000..ccd97af1 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudCore/cmt/requirements @@ -0,0 +1,18 @@ +## Automatically generated CMT requirements file +package SGAudCore +author Ilija Vukotic <ivukotic@cern.ch> + +## For Athena policies: it has to be the first use statement +use AtlasPolicy AtlasPolicy-* + +## For Gaudi tools, services and objects +use GaudiInterface GaudiInterface-* External +## Put here your package dependencies... + +## + +branches SGAudCore src + +library SGAudCore *.cxx + +apply_pattern installed_library diff --git a/EDM/athena/Control/SGMon/SGAudCore/src/ISGAudSvc.cxx b/EDM/athena/Control/SGMon/SGAudCore/src/ISGAudSvc.cxx new file mode 100644 index 00000000..d9bd48e1 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudCore/src/ISGAudSvc.cxx @@ -0,0 +1,45 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ISGAudSvc.cxx +// Implementation file for class ISGAudSvc +// Author: Ilija Vukotic<ivukotic@cern.ch> +/////////////////////////////////////////////////////////////////// + +// SGAudCore includes +#include "SGAudCore/ISGAudSvc.h" + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +// Destructor +/////////////// +ISGAudSvc::~ISGAudSvc() +{} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// diff --git a/EDM/athena/Control/SGMon/SGAudSvc/CMakeLists.txt b/EDM/athena/Control/SGMon/SGAudSvc/CMakeLists.txt new file mode 100644 index 00000000..05221c18 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/CMakeLists.txt @@ -0,0 +1,29 @@ +################################################################################ +# Package: SGAudSvc +################################################################################ + +# Declare the package name: +atlas_subdir( SGAudSvc ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthenaBaseComps + Control/AthenaKernel + Control/SGMon/SGAudCore + GaudiKernel + PRIVATE + Control/StoreGate ) + +# Component(s) in the package: +atlas_add_component( SGAudSvc + src/*.cxx + src/components/*.cxx + LINK_LIBRARIES AthenaBaseComps AthenaKernel SGAudCore GaudiKernel StoreGateLib SGtests ) + +# Install files from the package: +atlas_install_headers( SGAudSvc ) +atlas_install_scripts( share/SGout2dot.py ) + +# Aliases: +atlas_add_alias( SGout2dot "SGout2dot.py" ) + diff --git a/EDM/athena/Control/SGMon/SGAudSvc/SGAudSvc/SGAudSvc.h b/EDM/athena/Control/SGMon/SGAudSvc/SGAudSvc/SGAudSvc.h new file mode 100644 index 00000000..6ca80085 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/SGAudSvc/SGAudSvc.h @@ -0,0 +1,164 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// SGAudSvc.h +// Header file for class SGAudSvc +// Author: Ilija Vukotic <ivukotic@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef SGMONITORING_SGAUDSVC_H +#define SGMONITORING_SGAUDSVC_H + +// STL includes +#include <string> +#include <iosfwd> +#include <map> +#include <set> +#include <fstream> + +// HepMC / CLHEP includes + +// FrameWork includes +#include "AthenaBaseComps/AthService.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Algorithm.h" +#include "AthenaKernel/IClassIDSvc.h" + +#include "SGAudCore/ISGAudSvc.h" + +// Forward declaration +class ISvcLocator; +template <class TYPE> class SvcFactory; +class IChronoStatSvc; +class IAlgContextSvc; +class AlgContextSvc; + +class SGAudSvc : virtual public ISGAudSvc, + virtual public IIncidentListener, + public AthService +{ + +protected: + + friend class SvcFactory<SGAudSvc>; + + +public: + + /// Constructor with parameters: + SGAudSvc( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~SGAudSvc(); + + /// Gaudi Service Implementation + //@{ + StatusCode initialize(); + StatusCode finalize(); + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + //@} + + static const InterfaceID& interfaceID(); + + +/** incident service handle for EndEvent. Calls monitor. There should be more elegant way to get number of events passed. +*/ + void handle( const Incident& incident ); + + // do the auditing, called from DataStore.cxx + virtual void SGAudit(const std::string& key, const CLID& id, + const int& fnc, const int& store_id); + + +/** +* @brief Gets name of curently running algorithm from AlgContextSvc. +*/ + bool SGGetCurrentAlg(); +/** +* @brief For implementing custom increased granularity auditing of for instance tools. +*/ + void setFakeCurrentAlg(const std::string&); +/** +* @brief For implementing custom increased granularity auditing of for instance tools. +*/ + void clearFakeCurrentAlg(); + + private: + + /// Default constructor: + SGAudSvc(); + + void SGAudRETRIEVE(std::string SGobject); + void SGAudRECORD(std::string SGobject); + + void getNobj(std::string name); + void addRead(); + void addWrite(); + + /// just counts events. called at EndEvent incident + void monitor(); + + void writeJSON(); + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// MsgStream for talking with the outside world + MsgStream m_msg; + + /// Pointer to the @c AlgContextScv + IAlgContextSvc *p_algCtxSvc; + IClassIDSvc* m_pCID; + + /// Name of the output file + std::string m_outFileName, m_allFileName, m_sumFileName; + + /// Whether to ignore fake current algs + bool m_ignoreFakeAlgs; + + /// Whether to use CLID or Data Obj Name in JSON output file + bool m_useCLID; + + /// Vector of accessed SG objects names + std::vector<std::string> m_vObj; + /// Vector of names of algorithms accessing SG + std::vector<std::string> m_vAlg; + /// map counting Reads of each object by each algorithm. + std::map<int,int> m_timesRead; + /// map counting Writes of each object by each algorithm. + std::map<int,int> m_timesWritten; + std::string m_currAlg; + std::string m_currObj; + std::string m_fakeCurrAlg; + int m_nCurrAlg; + int m_nCurrObj; + int m_nEvents; + int m_startEvent; + + // map<"alg_name", set<"cid/key"> > + typedef std::map<std::string, std::set<std::string> > DataMap; + DataMap m_read; + DataMap m_write; + + std::ofstream m_ofa, m_ofs; + bool m_inExec; +}; + + +/////////////////////////////////////////////////////////////////// +/// Inline methods: +/////////////////////////////////////////////////////////////////// + +inline const InterfaceID& SGAudSvc::interfaceID() +{ + return ISGAudSvc::interfaceID(); +} + +#endif diff --git a/EDM/athena/Control/SGMon/SGAudSvc/cmt/requirements b/EDM/athena/Control/SGMon/SGAudSvc/cmt/requirements new file mode 100644 index 00000000..3b70a375 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/cmt/requirements @@ -0,0 +1,31 @@ +package SGAudSvc + +author Ilija Vukotic <ivukotic@cern.ch> + +use AtlasPolicy AtlasPolicy-* +use AthenaKernel AthenaKernel-* Control +use AthenaBaseComps AthenaBaseComps-* Control + +## For Gaudi tools, services and objects +use GaudiInterface GaudiInterface-* External + +## Put here your package dependencies... +use SGAudCore SGAudCore-* Control/SGMon + +private +use StoreGate StoreGate-* Control + +public +branches src src/components doc share + + +## make a component library +library SGAudSvc *.cxx components/*.cxx + +apply_pattern component_library +#apply_pattern declare_joboptions files="*.py" +apply_pattern declare_python_modules files="*.py" + +apply_pattern declare_scripts files="SGout2dot.py" + +alias SGout2dot SGout2dot.py diff --git a/EDM/athena/Control/SGMon/SGAudSvc/doc/mainpage.h b/EDM/athena/Control/SGMon/SGAudSvc/doc/mainpage.h new file mode 100644 index 00000000..9f5cedb8 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/doc/mainpage.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** +@mainpage SGAudSvc +@author ivukotic@cern.ch + +@section MyPackageIntro Introduction + +This package gives a graphical representation of algorithms accessing StoreGate. +SGAudSvc instruments retrieve and record functions of StoreGate and from there gets name of object accessed. Upon getting an object name it asks AlgContexSvc for a name of current algorithm. At the end of run, ascii file is produced (default name SGAudSvc.out). +This file is further used by SGout2dot.py to produce .dot file. +To obtain ps file from dot file you may use:'dot -Tps graph1.dot -o graph1.ps'. Still it is nicer to use Graphviz to directly see the plots and if needed edit them by hand. + +Please keep in mind that data are not collected for the first three events. + + +@ref used_MyPackage + +@ref requirements_MyPackage +*/ + +/** +@page used_MyPackage Used Packages +@htmlinclude used_packages.html +*/ + +/** +@page requirements_MyPackage Requirements +@include requirements +*/ diff --git a/EDM/athena/Control/SGMon/SGAudSvc/share/SGout2dot.py b/EDM/athena/Control/SGMon/SGAudSvc/share/SGout2dot.py new file mode 100644 index 00000000..01537df5 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/share/SGout2dot.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python +#TODO : prune standalone alg and objects +# remove number of read write +# remove monitoring, L1, CTP +# arrow show be single side ! +# @file: SGout2dot.py +# @purpose: read a SGAudSvc produced file and make dot file. +# @author: Ilija Vukotic <ivukotic@cern.ch> +# @date: May 2007 +# +# @example: +# +# checkFile SGAudSvc.out + +__version__ = "$Revision: 1.2 $" +__author__ = "Ilija Vukotic <ivukotic@cern.ch>" + +import sys +import os +import shutil +import glob + +# some configuration booleans +debug=True +debugRemove=False +drawNReadWrite=False # if draw on each line the number of read and write + + +#Algorithms to be masked. Might need to be tuned +lRemove=[] +lRemove+= ["MboyMuonChamberT0"] +lRemove+= ['Stream','StreamAOD','noKey',"basic_"] +lRemove+= ["Trig","HLT","EF","L1","Mon","CTP","RoIB","GlobalManager"] +#lRemove += ['LArRawChannelCollection','TileRawChannelCollection','DetStatusAlg','DetectorStatus','_Data','_Link'] +#lRemove+= ['EventSelector','Input'] +#lRemove+= ['iPatStatistics'] +def chLabel(inpVal): + result=inpVal + result=result.replace('>','_GT_') + result=result.replace('<','_LT_') + result=result.replace('::','_') + result=result.replace('.','_') + result=result.replace('+','_') + return result + + + +def isNumb(inpVal): + result = False + try: + stripped = str(int(inpVal)) + result=True + except: + result=False + return result + +def toRemove(inpVal): + result=False + if isNumb(inpVal)==True: + if debugRemove: + print "remove ", inpVal, "is a number" + result=True + for thing in lRemove: + if inpVal.count(thing)>0: + if debugRemove: + print "remove ", inpVal ,"since it contains", thing + result=True + return result + +nArgs= len (sys.argv) +outFN="dot.dot" +inFN="" +if nArgs==1: + print "Usage: SGout2dot.py input_filename [output dot file]" + sys.exit() +if nArgs>1: + print "Input file",sys.argv[1] + inFN=sys.argv[1] +if nArgs==3: + print "Output file",sys.argv[2] + outFN=sys.argv[2] +try: + fi = open (inFN) +except: + print "No such file!" + sys.exit() + +fo = open (outFN, 'w' ) + +lines = fi.readlines() +fi.close() + +# get number of algs +line=lines.pop(0) +words=line.split(' ') +nAlgs=int(words[1]) +print '%(a)d algorithms found'%{'a':nAlgs} + +#read all algs +#note that algs to be removed cannot be masked before reading the alg <-> obj relation +algs=[] +nGoodAlgs=0 +for i in range(nAlgs): + line=lines.pop(0).strip('\n') + line=line.replace('/','_') + algs.append(line) + if toRemove(line): + print "alg %s to be removed" % line + else: + nGoodAlgs+=1 + +print " number of good algs ",nGoodAlgs," bad algs ",nAlgs-nGoodAlgs +if debug: + print algs + +# get number of objs +line=lines.pop(0) +words=line.split(' ') +nObjs=int(words[1]) +print '%(a)d objects found'%{'a':nObjs} + +# get all object names, and replace possible annoying characters +#note that objs to be removed cannot be masked before reading the alg <-> obj relation +objs=[] +nGoodObjs=0 +for i in range(nObjs): + line=lines.pop(0).strip('\n') + line=line.replace('/','_') + line=line.replace('<','LT') + line=line.replace('>','GT') + line=line.replace('+','_') + objs.append(line) + if toRemove(line): + print "obj %s to be removed" % line + else: + nGoodObjs+=1 + +print " number of good objs ",nGoodObjs," bad objs ",nObjs-nGoodObjs +if debug: + print objs + +fo.write("// %s algorithms and %s objects \n" % (nGoodAlgs,nGoodObjs)) + + +#write out dot file header +fo.write("digraph SGAudSvc{\nrankdir=LR;\n") # begining and graph stuff +fo.write("ratio=0.7;\nnodesep=0.05;\n") +fo.write("subgraph c_0{\nnode[style=filled,color=red];\n") # alg subgraph +fo.write("label=\"Algs READING\";\ncolor=red;\n") + +# get the relations betwen alg and obj +# TODO number write or read not kept at this point +objsWrittenByAlg={} #A->many O (A write O may read it as well) +objsReadByAlg={} #many O->A (A read O may do not read it ) +algsWritingObj={} #many A->O (A write O may read it as well). +algsReadingObj={} # O->many A (A does not write O) +for alg in algs: + line=lines.pop(0) + words=line.strip('\n').split('\t') + for obj in objs: + rw=words.pop(0).split(':') + reads=int(rw[0]) + writes=int(rw[1]) + if reads==0 and writes==0: + continue + if toRemove(obj) or toRemove(alg): + continue + #print alg,obj,reads, writes + + if writes==0 and reads>0: + if not obj in algsReadingObj.keys(): + algsReadingObj[obj]=[] + algsReadingObj[obj]+=[(alg,reads,writes)] + if not alg in objsReadByAlg.keys(): + objsReadByAlg[alg]=[] + objsReadByAlg[alg]+=[obj] + elif writes>0: + if not obj in algsWritingObj.keys(): + algsWritingObj[obj]=[] + algsWritingObj[obj]+=[alg] + + if not alg in objsWrittenByAlg.keys(): + objsWrittenByAlg[alg]=[] + objsWrittenByAlg[alg]+=[(obj,reads,writes)] + + +#write out all algorithms, but only the ones that have at least one connection (and are not masked) +for alg in algs: + if toRemove(alg)==False: + if alg in objsWrittenByAlg or alg in objsReadByAlg: + towrite='a_%(a)s [label=\"%(a)s\"];\n'%{'a':chLabel(alg),'b':alg} + fo.write(towrite) + else: + print "alg %s masked because not connected" % alg + +fo.write("}\n\nsubgraph c_1{\nnode[style=filled,shape=box];\ncolor=green;label=\"Objects\";\n") +#write out all objecs +for obj in objs: + if toRemove(obj)==False: + if obj in algsWritingObj or obj in algsReadingObj: + towrite='o_%(a)s [label=\"%(b)s\"];\n'%{'a':chLabel(obj),'b':obj} + fo.write(towrite) + else: + print "obj %s masked because not connected" % obj +fo.write("}\n\n") + + +if debug: + print " " + print "objsWrittenByAlg:", objsWrittenByAlg + print " " + print "objsReadByAlg:", objsReadByAlg + print " " + print "algsWritingObj:", algsWritingObj + print " " + print "algsReadingObj:", algsReadingObj + print " " + +#write the connection a to obj +for alg in objsWrittenByAlg.keys(): + for objrec in objsWrittenByAlg[alg]: + obj=objrec[0] + reads=objrec[1] + writes=objrec[2] + towrite='a_%(ALG)s -> o_%(OBJ)s [ '%{'ALG':chLabel(alg),'OBJ':chLabel(obj)} + if drawNReadWrite: + if reads==0: + towrite+='label=\"%s\" ' % writes + else: + # if read in addition to write, write both number of read and write plus double arrow + # this happen when an alg writes an object and read it back to modify it + towrite+='label=\"w:%(WRITES)s r:%(READS)s\" arrowtail=\"normal\" '%{'WRITES':writes,'READS':reads} + else: + if reads>0: # double arrow + towrite+='arrowtail=\"normal\" ' + towrite+='];\n' + fo.write(towrite) + +#write the connection obj to alg +# by definition only read no write +for obj in algsReadingObj.keys(): + for algrec in algsReadingObj[obj]: + alg=algrec[0] + reads=algrec[1] + writes=algrec[2] + + towrite='o_%(OBJ)s -> a_%(ALG)s [ '%{'ALG':chLabel(alg),'OBJ':chLabel(obj)} + if drawNReadWrite: + towrite+='label=\"%s\" ' % reads + towrite+='];\n' + fo.write(towrite) + +## # get the relations betwen alg and obj, and write them out +## for alg in algs: +## alg=chLabel(alg) +## line=lines.pop(0) +## words=line.strip('\n').split('\t') +## for obj in objs: +## rw=words.pop(0).split(':') +## reads=rw[0] +## writes=rw[1] +## #print alg,obj,reads, writes +## if toRemove(obj)==False and toRemove(alg)==False: +## if int(writes)>0 and int(reads)>0: +## towrite='a_%(ALG)s -> o_%(OBJ)s [label=\"w:%(WRITES)s r:%(READS)s\" '%{'ALG':alg,'OBJ':obj,'WRITES':writes,'READS':reads} +## towrite+='arrowtail=\"normal\"];\n' +## fo.write(towrite) +## else: +## if int(writes)>0: +## towrite='a_%(ALG)s -> o_%(OBJ)s [label=\"%(WRITES)s\"];\n'%{'ALG':alg,'OBJ':obj,'WRITES':writes} +## fo.write(towrite) +## if int(reads)>0: +## towrite='o_%(OBJ)s -> a_%(ALG)s [label=\"%(READS)s\"];\n'%{'ALG':alg,'OBJ':obj,'READS':reads} +## fo.write(towrite) + +fo.write("}") +fo.close() diff --git a/EDM/athena/Control/SGMon/SGAudSvc/share/checkFileSG.py b/EDM/athena/Control/SGMon/SGAudSvc/share/checkFileSG.py new file mode 100644 index 00000000..20095fe7 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/share/checkFileSG.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python + +# @file: checkFileSG.py +# @purpose: answers queries on a SGAudSvc produced file +# @author: Ilija Vukotic <ivukotic@cern.ch> +# @date: October 2007 +# +# @example: +# +# checkFileSG SGAudSvc.out + +__version__ = "$Revision: 1.1 $" +__author__ = "Ilija Vukotic <ivukotic@cern.ch>" + +import sys +import os +import shutil +import glob + +lRemove = ['_Data','_Link','noKey','HLTAuto','CBNT_'] + +def toSkip(inpName): + for comp in lRemove: + if inpName.count(comp)>0: + return True + return False + +def toRemove(inpVal): + result=False + if isNumb(inpVal)==True: + print "remove ", inpVal, "is a number" + result=True + for thing in lRemove: + if inpVal.count(thing)>0: + print "remove ", inpVal ,"since it contains", thing + result=True + return result + +def findMatches(iAlg, iObj, F, Fa, Fo): + n=0 + print "---- algos -----" + for alg in iAlg: #----------------> find matching algos + if alg.count(F)>0 and not toSkip(alg): + Fa.append(alg) + print alg + n+=1 + print '---- objects ----' + for obj in iObj: #---------------> find matching objects + if obj.count(F)>0 and not toSkip(obj): + Fobj.append(obj) + print obj + n+=1 + print '-----------------' + return n + +nArgs= len (sys.argv) +inFN='' +if nArgs==1: + print "Usage: checkFileSG.py input_filename " + sys.exit() +if nArgs>1: + print "Input file: ",sys.argv[1] + inFN=sys.argv[1] +try: + fi = open (inFN) +except: + print "No such file!" + sys.exit() + + +lines = fi.readlines() +fi.close() + +#=================================================================== +line=lines.pop(0) +words=line.split(' ') +nAlgs=int(words[1]) +print '%(a)d algorithms found'%{'a':nAlgs} + +algs=[] +for i in range(nAlgs): # -------------------> reading alg names + line=lines.pop(0).strip('\n') + line=line.replace('/','_') + algs.append(line) + +#print algs + +line=lines.pop(0) +words=line.split(' ') +nObjs=int(words[1]) +print '%(a)d objects found'%{'a':nObjs} + +objs=[] +for i in range(nObjs): # ----------------> reading object names + line=lines.pop(0).strip('\n') + line=line.replace('/','_') + line=line.replace('<','LT') + line=line.replace('>','GT') + objs.append(line) +#================================================================== + + +Falg=[]; Fobj=[] +LF=raw_input('Please enter algorithm or SG object name: ') + + +while (findMatches(algs, objs, LF, Falg, Fobj)!=1): #----------> getting single input + LF=raw_input('Please enter algorithm or SG object name. To exit type \'x\' : ') + if LF=='x': + sys.exit(0) + Falg=[];Fobj=[] + + + +print 'Calculating calls for:',LF,' ' +if len(Falg)>0: + #print 'algorithms', Falg + ind=algs.index(Falg[0])+1 + for i in range(ind): + line=lines.pop(0) + #print line + words=line.strip('\n').split('\t') + for obj in objs: + rw=words.pop(0).split(':') + #print rw + reads=int(rw[0]) + writes=int(rw[1]) + if (reads+writes)>0: + print 'Object:',obj, "has been accessed",reads,"times and written",writes,"times." + +else: + #print 'objects',Fobj + ind=objs.index(Fobj[0]) + for i in range(len(algs)): + line=lines.pop(0) + words=line.strip('\n').split('\t') + rw=words[ind].split(':') + reads=int(rw[0]) + writes=int(rw[1]) + if (reads+writes)>0: + print 'Algorithm',algs[i],'accessed object',reads,'times and wrote it',writes,'times' + +sys.exit(0) diff --git a/EDM/athena/Control/SGMon/SGAudSvc/src/SGAudSvc.cxx b/EDM/athena/Control/SGMon/SGAudSvc/src/SGAudSvc.cxx new file mode 100644 index 00000000..8b2e4275 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/src/SGAudSvc.cxx @@ -0,0 +1,523 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// SGAudSvc.cxx +// Implementation file for class SGAudSvc +// Author: Ilija Vukotic<ivukotic@cern.ch> +/////////////////////////////////////////////////////////////////// + + +// STL includes +#include <sstream> +#include <fstream> +#include <vector> +#include <set> +#include <utility> + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/SvcFactory.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/Incident.h" +#include "GaudiKernel/IAlgContextSvc.h" + +// StoreGate includes +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/DataHandle.h" + +// SGAudSvc includes +#include "SGAudSvc/SGAudSvc.h" +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +/*----------------------------------------------------------------------------*/ +// Constructors +//////////////// +SGAudSvc::SGAudSvc( const std::string& name, ISvcLocator* pSvcLocator ) : + AthService ( name, pSvcLocator ), + m_msg ( msgSvc(), name ), + p_algCtxSvc(0), m_pCID(0), m_useCLID(true), + m_nCurrAlg(0), + m_nCurrObj(0), + m_nEvents(0), m_startEvent(3), m_inExec(false) +{ + // + // Property declaration + // + declareProperty( "OutFileName", m_outFileName = "SGAudSvc.out", + "Name of the output file to hold SGAudSvc data" ); + + declareProperty( "FullFileName", m_allFileName = "", + "Name of the output file to hold the full SG aud data"); + + declareProperty( "SummaryFileName", m_sumFileName = "", + "Name of the output file to hold the summary output in json format"); + + declareProperty( "IgnoreFakeAlgs", m_ignoreFakeAlgs = false, + "Set to ignore any attempts to override current-alg" ); + + declareProperty( "StartEvent", m_startEvent = 3, + "Event number to start recording data" ); + + declareProperty( "UseCLID", m_useCLID = true, + "Use CLID or DataObj name in Summary File" ); +} + +/*----------------------------------------------------------------------------*/ +// Destructor +/////////////// +SGAudSvc::~SGAudSvc() +{ + m_msg << MSG::DEBUG << "Calling destructor" << endreq; +} + +/*----------------------------------------------------------------------------*/ + +// Athena Algorithm's Hooks +//////////////////////////// +StatusCode +SGAudSvc::initialize() { + + // initialize MsgStream + m_msg.setLevel( m_outputLevel.value() ); + + m_msg << MSG::INFO << "Initializing " << name() << "..." << endreq; + + if ( AthService::initialize().isFailure() ) { + m_msg << MSG::ERROR << "Could not intialize base class !!" << endreq; + return StatusCode::FAILURE; + } + + static const bool CREATEIF(true); + + if ( service("AlgContextSvc",p_algCtxSvc,CREATEIF).isFailure() ) { + m_msg << MSG::ERROR << "Unable to retrieve the AlgContextSvc" << endreq; + return StatusCode::FAILURE; + } + + assert(p_algCtxSvc); + + if ( service("ClassIDSvc",m_pCID,CREATEIF).isFailure() ) { + m_msg << MSG::ERROR << "Unable to retrieve the ClassIDSvc" << endmsg; + return StatusCode::FAILURE; + } + + if (m_allFileName != "") { + m_ofa.open(m_allFileName.c_str()); + } + + if (m_sumFileName != "") { + m_ofs.open(m_sumFileName.c_str()); + } + + // Set to be listener for end-of-event + ServiceHandle<IIncidentSvc> incSvc( "IncidentSvc", this->name() ); + if ( !incSvc.retrieve().isSuccess() ) { + m_msg << MSG::ERROR << "Unable to get the IncidentSvc" << endreq; + return StatusCode::FAILURE; + } + incSvc->addListener( this, IncidentType::BeginRun ); + incSvc->addListener( this, IncidentType::BeginEvent ); + incSvc->addListener( this, IncidentType::EndEvent ); + + return StatusCode::SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +StatusCode +SGAudSvc::finalize() { + + m_msg << MSG::INFO << "Finalizing " << name() <<"..."<< endreq; + + if (m_vAlg.size()==0) { + m_msg << MSG::WARNING<<"No data gathered. This might be because you did not run over at least 3 events."<<endreq; + return StatusCode::SUCCESS; + } + + m_msg << MSG::INFO<<"Writing output to: "<<m_outFileName<<endreq; + std::ofstream f( m_outFileName.c_str() ); + + f << "Algs: " << m_vAlg.size() << std::endl; + std::vector<std::string>::iterator i; + for (i=m_vAlg.begin();i<m_vAlg.end();i++) { + f << (*i) << std::endl; + } + + f << "Obj: "<< m_vObj.size()<<std::endl; + for (i=m_vObj.begin();i<m_vObj.end();i++) { + f << (*i) << std::endl; + } + + + for (unsigned int w=0;w<m_vAlg.size();w++){ + for(unsigned int q=0;q<m_vObj.size();q++){ + int oaHash=q*1000 + w; + if (m_timesRead.find(oaHash)==m_timesRead.end()) + f << "0:"; + else + f << m_timesRead.find(oaHash)->second << ":"; + if (m_timesWritten.find(oaHash)==m_timesWritten.end()) + f << "0\t"; + else + f << m_timesWritten.find(oaHash)->second << "\t"; + } + f << std::endl; + } + + f.close(); + + if (m_ofa.is_open()) m_ofa.close(); + + if (m_ofs.is_open()) { + + writeJSON(); + + m_ofs.close(); + } + + + return StatusCode::SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +// Query the interfaces. +StatusCode +SGAudSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( ISGAudSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = dynamic_cast<ISGAudSvc*>(this); + } else { + // Interface is not directly available : try out a base class + return AthService::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::handle( const Incident& inc ) +{ + if ( m_msg.level() <= MSG::VERBOSE ) { + m_msg << MSG::VERBOSE << "Entering handle(): " << endreq + << " Incidence type: " << inc.type() << endreq + << " from: " << inc.source() << endreq; + } + + if (inc.type() == IncidentType::BeginEvent) { + if (m_ofa.is_open()) + m_ofa << "---- BEGIN EVENT " << m_nEvents << " ----" << std::endl; + m_inExec = true; + + } + + // Performing performance-monitoring for EndEvent incident + if ( inc.type() == IncidentType::EndEvent ) { + monitor(); + + if (m_ofa.is_open()) + m_ofa << "---- END EVENT " << m_nEvents << " ----" << std::endl; + m_inExec = false; + + } + + // Performing performance-monitoring for BeginRun incident + // at this point everybody has been initialized, we can harvest performance + // data for the initialize step. + + if ( inc.type() == IncidentType::BeginRun ) { + monitor(); + } + + return; +} + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::monitor(){ + m_nEvents++; + return; +} + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::SGAudRETRIEVE(std::string SGobject){ + // if (m_nEvents<3) return; + if (SGobject=="") SGobject="noKey"; + bool isAnumb=true; + for (unsigned int i = 0; i < SGobject.length(); i++) + if (!std::isdigit(SGobject[i])){ + isAnumb=false; + break; + } + + if (!isAnumb){ + if (m_currObj==SGobject) + addRead(); + else { + getNobj(SGobject); + addRead(); + } + } + return; +} + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::SGAudRECORD(std::string SGobject){ + // if (m_nEvents<3) return; + if (SGobject=="") SGobject="noKey"; + for (unsigned int i = 0; i < SGobject.length(); i++) + if (!std::isdigit(SGobject[i])){ + //isAnumb=false; + break; + } + + if (m_currObj==SGobject) + addWrite(); + else { + getNobj(SGobject); + addWrite(); + } + + return; +} + +/*----------------------------------------------------------------------------*/ +void +SGAudSvc::SGAudit(const std::string& key, const CLID& id, + const int& typ, const int& store_id) { + + // we can sometimes get here really early, before initialization. + if (m_pCID == 0) { return; } + + bool a = SGGetCurrentAlg(); + + if (m_nEvents >= m_startEvent && store_id == 0 && a) { + if (typ == 0) { + SGAudRETRIEVE(key); + } else { + SGAudRECORD(key); + } + } + + std::string idname; + + if (m_ofa.is_open() || ( m_ofs.is_open() && ! m_useCLID ) ) { + if( ! m_pCID->getTypeNameOfID(id,idname).isSuccess()) { + std::ostringstream ost; + ost << id; + idname = ost.str(); + } + } + + if (m_ofa.is_open()) { + m_ofa << ( (typ == 1) ? "RECORD" : "RETRIEVE" ) << " clid: " << id + << " | "; + + m_ofa << idname; + + m_ofa << " key: " << key << " alg: " << m_currAlg + << " store: " << store_id + << std:: endl; + } + + // store stuff for the summary + + if (!m_ofs.is_open()) return; + + if (m_nEvents < m_startEvent || !m_inExec) return; + + if (m_currAlg == "----") return; + + std::string kk; + if (m_useCLID) { + std::ostringstream ost; + ost << id << "/" << key; + kk = ost.str(); + } else { + kk = idname + "/" + key; + } + + DataMap::iterator itr; + if (typ == 0) { + itr = m_read.find(m_currAlg); + if (itr != m_read.end()) { + itr->second.insert(kk); + } else { + m_read[m_currAlg] = std::set<std::string> ( {kk} ); + } + } else { + itr = m_write.find(m_currAlg); + if (itr != m_write.end()) { + itr->second.insert(kk); + } else { + m_write[m_currAlg] = std::set<std::string> ( {kk} ); + } + } +} + +/*----------------------------------------------------------------------------*/ + +bool +SGAudSvc::SGGetCurrentAlg(){ + + IAlgorithm *asdf = p_algCtxSvc->currentAlg(); + if (!asdf || m_nEvents==0) { // to skip before first event + m_currAlg="----"; + m_nCurrAlg=-1; + return false; + } + std::string name = asdf->name(); + + if ( !m_ignoreFakeAlgs && !m_fakeCurrAlg.empty() ) + name=m_fakeCurrAlg; + + if (name!=m_currAlg){ + std::vector<std::string>::iterator i; + int index=0; + for (i=m_vAlg.begin();i<m_vAlg.end();i++){ + if (*i==name) { + m_nCurrAlg=index; + m_currAlg=name; + return true; + } + index++; + } + m_vAlg.push_back(name); + m_nCurrAlg=index; + m_currAlg=name; + return true; + } + return true; +} + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::getNobj(std::string name){ + std::vector<std::string>::iterator i; + int index=0; + for (i=m_vObj.begin();i<m_vObj.end();i++){ + if (*i==name) { + m_nCurrObj=index; + m_currObj=name; + return; + } + index++; + } + m_vObj.push_back(name); + m_nCurrObj=index; + m_currObj=name; +return; +} + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::addRead(){ + int oaHash=m_nCurrObj*1000 + m_nCurrAlg; + if (m_timesRead.end()!=m_timesRead.find(oaHash)){ + m_timesRead.find(oaHash)->second++; + } + else{ + std::pair<int,int> p(oaHash,1); + m_timesRead.insert(p); + } + return; +} + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::addWrite(){ + int oaHash=m_nCurrObj*1000 + m_nCurrAlg; + if (m_timesWritten.end()!=m_timesWritten.find(oaHash)){ + m_timesWritten.find(oaHash)->second++; + } + else{ + std::pair<int,int> p(oaHash,1); + m_timesWritten.insert(p); + } + return; +} + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::setFakeCurrentAlg( const std::string& s ) { m_fakeCurrAlg=s; } + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::clearFakeCurrentAlg() { m_fakeCurrAlg.clear(); } + +/*----------------------------------------------------------------------------*/ + +void +SGAudSvc::writeJSON() { + + DataMap::const_iterator itr; + std::set<std::string>::const_iterator it2; + std::vector<std::string>::const_iterator ia; + + m_ofs << "{ \"algorithms\" : [" << std::endl; + for (ia = m_vAlg.begin(); ia != m_vAlg.end(); ++ia) { + m_ofs << " {" << std::endl; + m_ofs << " \"name\" : \"" << *ia << "\"," << std::endl; + m_ofs << " \"inputs\" : ["; + + itr = m_read.find(*ia); + if (itr != m_read.end()) { + for (it2 = itr->second.begin(); it2 != itr->second.end(); ++it2) { + if (it2 != itr->second.begin()) m_ofs << ","; + m_ofs << "\"" << *it2 << "\""; + } + } + m_ofs << "]," << std::endl; + + m_ofs << " \"outputs\" : ["; + + itr = m_write.find(*ia); + if (itr != m_write.end()) { + for (it2 = itr->second.begin(); it2 != itr->second.end(); ++it2) { + if (it2 != itr->second.begin()) m_ofs << ","; + m_ofs << "\"" << *it2 << "\""; + } + } + m_ofs << "]," << std::endl; + m_ofs << " }," << std::endl; + } + m_ofs << " ]" << std::endl << "}" << std::endl; + +} diff --git a/EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_entries.cxx b/EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_entries.cxx new file mode 100644 index 00000000..719c6b7d --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_entries.cxx @@ -0,0 +1,13 @@ +#include "SGAudSvc/SGAudSvc.h" +//#include "../PerfMonAuditor.h" + +#include "GaudiKernel/DeclareFactoryEntries.h" + +DECLARE_SERVICE_FACTORY( SGAudSvc ) +//DECLARE_AUDITOR_FACTORY( PerfMonAuditor ) + +DECLARE_FACTORY_ENTRIES( SGAudSvc ) { + DECLARE_SERVICE( SGAudSvc ) +// DECLARE_AUDITOR( PerfMonAuditor ) + +} diff --git a/EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_load.cxx b/EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_load.cxx new file mode 100644 index 00000000..7412b1c6 --- /dev/null +++ b/EDM/athena/Control/SGMon/SGAudSvc/src/components/SGAudSvc_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES( SGAudSvc ) diff --git a/EDM/athena/Control/SGTools/CMakeLists.txt b/EDM/athena/Control/SGTools/CMakeLists.txt new file mode 100644 index 00000000..38dc2dcc --- /dev/null +++ b/EDM/athena/Control/SGTools/CMakeLists.txt @@ -0,0 +1,120 @@ +################################################################################ +# Package: SGTools +################################################################################ + +# Declare the package name: +atlas_subdir( SGTools ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthenaKernel + Control/CxxUtils + GaudiKernel + PRIVATE + AtlasTest/TestTools + Control/SGMon/SGAudCore ) + +# External dependencies: +find_package( Boost COMPONENTS thread filesystem system ) +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) + +# Component(s) in the package: +atlas_add_library( SGTools + src/*.cxx + PUBLIC_HEADERS SGTools + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} AthenaKernel CxxUtils GaudiKernel + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} TestTools SGAudCore ) + +atlas_add_dictionary( SGToolsDict + SGTools/SGToolsDict.h + SGTools/selection.xml + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( CLIDRegistry_test + SOURCES + test/CLIDRegistry_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( VersionedKey_test + SOURCES + test/VersionedKey_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( DataBucket_test + SOURCES + test/DataBucket_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools + EXTRA_PATTERNS "^HistogramPersis.* INFO" ) + +atlas_add_test( BaseInfo_test + SOURCES + test/BaseInfo_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( safe_clid_test + SOURCES + test/safe_clid_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( crc64_test + SOURCES + test/crc64_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( exceptions_test + SOURCES + test/exceptions_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( StringPool_test + SOURCES + test/StringPool_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( ClassName_test + SOURCES + test/ClassName_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( DataProxy_test + SOURCES + test/DataProxy_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( DataStore_test + SOURCES + test/DataStore_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( TransientAddress_test + SOURCES + test/TransientAddress_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( CurrentEventStore_test + SOURCES + test/CurrentEventStore_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + +atlas_add_test( SGFolderItem_test + SOURCES + test/SGFolderItem_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthenaKernel CxxUtils GaudiKernel TestTools SGAudCore SGTools ) + diff --git a/EDM/athena/Control/SGTools/SGTools/BaseInfo.h b/EDM/athena/Control/SGTools/SGTools/BaseInfo.h new file mode 100644 index 00000000..9ffe44b3 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/BaseInfo.h @@ -0,0 +1,901 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.h,v 1.11 2008-12-15 16:22:45 ssnyder Exp $ + +/** + * @file SGTools/BaseInfo.h + * @author scott snyder + * @date Nov 2005 + * @brief Provide an interface for finding inheritance information + * at run time. + * + * The @a SG::BaseInfo<T> class provides an interface for finding + * inheritance information about class @a T. In the absence of compiler + * support for reflection, the inheritance information must be + * explicitly declared. This is done with the @a SG_BASE macro + * and friends. To declare that class @a D derives from class @a B, use + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_BASE (D, B); + @endcode + * + * You can also use multiple inheritance with the @a SG_BASES2 + * and @a SG_BASES3 macros: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct B3 {}; + * struct D : public B1, public B2, public B3 {}; + * SG_BASES3 (D, B1, B2, B3); + @endcode + * + * Supporting more than three base classes requires (straightforward) + * changes to the code here. + * + * If any of the derivations are virtual, the corresponding + * base class should be within a @a SG_VIRTUAL macro: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct D : public B1, virtual public B2 {}; + * SG_BASES2 (D, B1, SG_VIRTUAL (B2)); + @endcode + * + * Note that these macros will only work with non-templated types, + * or with specific instantiations of templated types. If you want + * a templated @a SG_BASE, you'll need to declare the specialization + * yourself. You should specialize @a SG::Bases<T>, defining types + * @a Base1, @a Base2, and @a Base3 (which should be @a SG::NoBase + * if not used). Example: + * + *@code + * template <class T> struct B {}; + * template <class T> struct D : public B<T> {}; + * namespace SG { + * template <class T> + * struct Bases<D<T> > { + * typedef B<T> Base1; + * typedef NoBase Base2; + * typedef NoBase Base3; + * }; + * } + @endcode + * + * Once these declarations are in place, what can you do with it? + * The interface is provided by the @a SG::BaseInfo<T> class. + * (This is a wrapper around a singleton, so it's not expensive + * to create instances of this class.) You can specify the base + * classes either by the Gaudi class ID or by the C++ @c std::type_info. + * Of course, you'll only be able to get information by class ID + * if the classes actually have IDs defined. + * + * Here are the available methods of @a SG::BaseInfo<T>: + * + *@code + * static bool is_base (CLID clid) + * static bool is_base (const std::type_info& tinfo) + @endcode + * Test to see if the type given by @a clid or @a tinfo + * is a base of @a T. Note that @a T counts as its own base. + * + *@code + * static bool is_virtual (CLID clid) + * static bool is_virtual (const std::type_info& tinfo) + @endcode + * Test to see if the type given by @a clid or @a tinfo + * is a virtual base of @a T. This should always be @a false + * for @a T itself. + * + *@code + * static void* cast (T* p, CLID clid) + * static void* cast (T* p, const std::type_info& tinfo) + @endcode + * Cast a pointer from @a T* to a pointer to the type given + * by @a clid or @a tinfo, which must be a base if @a T + * known to @a BaseInfo. The result is returned as a @a void*. + * If the conversion cannot be done (because the target is not + * known to be a base of @a T), then 0 is returned. + * + *@code + * static T* castTo (void* p, CLID clid) + * static T* castTo (void* p, const std::type_info& tinfo) + @endcode + * Similar, except converts from a pointer to the type given by + * @a clid or @a tinfo (which must be a base of @a T) to @a T*. + * This involves a @a dynamic_cast. Returns 0 if the cast fails. + * + *@code + * static std::vector<CLID> get_bases () + @endcode + * Return all the known bases of @a T (that have class IDs). + * @a T itself will be included in this list. + * + *@code + * static std::vector<const std::type_info*> get_ti_bases () + @endcode + * Return all the known bases of @a T. + * @a T itself will be included in this list. + * + * It is also possible to get a non-templated version of @c SG::BaseInfo<T>. + * This is called @c SG::BaseInfoBase. These objects can be found using + * @c SG::BaseInfoBase::find, by either class ID or @c std::type_info + * (in order for this to work, the corresponding @c SG::BaseInfo<T> class + * must have been used somewhere in the program). The interface + * of @c SG::BaseInfoBase is the same as @c SG::BaseInfo<T>, except + * that @c void* replaces @c T* in the @c cast methods. + * + * Initialization issues: We don't want to build the @c SG::BaseInfo<T> + * objects at static initialization time. But we do need to remember + * which ones are available. Thus, @c BaseInfoBase maintains a list + * of CLIDs and @c std::type_info's for which we may not have done + * initialization, along with a function to call to do the initialization. + * The initialization list is filled during static initialization. + * When we look for an instance, if we don't find one, we look in the + * initialization list; if there's a match there, we run the initialization + * and remove it from the list. + * + * Copy conversions: The conversion machinery above provides access to the + * standard C++ base<>derived conversions. However, sometimes you'd like + * to allow additional conversions as well, for example between a + * vector<ElementLink<T> > and DataVector<T>. For those cases, + * you can register a conversion function with the _source_ type + * that can initialize an instance of the _destination_ type + * from the _source_ type. Then, when you try to retrieve the object + * from StoreGate with the _destination_ type, your conversion function + * will be called. + * + * Your conversion function should be the method @a convert of + * a class deriving from the @a SG::CopyConversion template; + * for example, + * + *@code + * class MyCopyConversion + * : public SG::CopyConversion<std::vector<ElementLink<MyType> >, + * DataVector<MyType> > + * { + * public: + * virtual void convert (const std::vector<ElementLink<MyType> >& src, + * DataVector<MyType>& dst) const + * { + * size_t sz = src.size(); + * if (dst.size() != sz) { + * dst.clear (SG::VIEW_ELEMENTS); + * dst.reserve (sz); + * for (size_t i = 0; i < sz; i++) { + * const MyType* p = *(src[i]).cptr(); + * dst.push_back (const_cast<MyType*> (p)); + * } + * } + * } + * }; + @endcode + * + * You then declare this using the macro + * + @code + * SG_ADD_COPY_CONVERSION (std::vector<ElementLink<MyType> >, + * MyCopyConversion); + @endcode + * + * Copy conversions are enabled only for objects that have been marked as const. + */ + +#ifndef SGTOOLS_BASEINFO_H +#define SGTOOLS_BASEINFO_H + +#include "GaudiKernel/ClassID.h" +#include <vector> +#include <typeinfo> + + +//=========================================================================== +// Macros used to declare base class information. +// + +/** + * @brief Used to mark virtual derivation. + * When using the @a SG_BASE macros below, use this in the case + * of virtual derivation. Example: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct D : public B1, virtual public B2 {}; + * SG_BASES2 (D, B1, SG_VIRTUAL (B2)); + @endcode + */ +#define SG_VIRTUAL(T) Virtual<T> + + +/** + * @brief Declare that class @a D derives from class @a B. Example: + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_BASE (D, B); + @endcode + */ +#define SG_BASE(D, B) SG_BASES1(D, B) + + +/** + * @brief Declare that class @a D derives from class @a B. + * This is the same as @a SG_BASE. Example: + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_BASES1 (D, B); + @endcode + */ +#define SG_BASES1(D, B) \ + namespace SG { \ + template<> struct Bases<D >{ \ + typedef B Base1; \ + typedef NoBase Base2; \ + typedef NoBase Base3; \ + }; \ + template struct RegisterBaseInit<D >; \ + template struct BaseInit<D >; \ +} struct sg_dummy // to swallow semicolon + + +/** + * @brief Declare that class @a D derives from classes @a B1 and @a B2. + * Example: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct D : public B1, public B2 {}; + * SG_BASES2 (D, B1, B2); + @endcode + */ +#define SG_BASES2(D, B1, B2) \ + namespace SG { \ + template<> struct Bases<D >{ \ + typedef B1 Base1; \ + typedef B2 Base2; \ + typedef NoBase Base3; \ + }; \ + template struct RegisterBaseInit<D >; \ + template struct BaseInit<D >; \ +} struct sg_dummy // to swallow semicolon + + +/** + * @brief Declare that class @a D derives from classes @a B1, @a B2, and @a B3. + * Example: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct B3 {}; + * struct D : public B1, public B2, public B3 {}; + * SG_BASES3 (D, B1, B2, B3); + @endcode + */ +#define SG_BASES3(D, B1, B2, B3) \ + namespace SG { \ + template<> struct Bases<D >{ \ + typedef B1 Base1; \ + typedef B2 Base2; \ + typedef B3 Base3; \ + }; \ + template struct RegisterBaseInit<D >; \ + template struct BaseInit<D >; \ +} struct sg_dummy // to swallow semicolon + + + +/** + * @brief Add a new base class @c B to class @c D. + * + * Sometimes, the SG_BASE macro for a class isn't present in its header. + * + * One can try to put the appropriate SG_BASE macro somewhere else, + * but this doesn't always work: if the @c BaseInfoBase for @c D has + * already been created by the time the @c SG_BASE initialization + * runs, then that @c SG_BASE macro won't do anything. + * + * @c SG_ADD_BASE, however, will add a new base to an existing @c BaseInfoBase. + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_ADD_BASES (D, B); + @endcode + */ +#define SG_ADD_BASE(D, B) \ + namespace SG { \ + template struct AddBaseInit<D, B >; \ +} struct sg_dummy // to swallow semicolon + + +/** + * @brief Declare a copy conversion from class @c T using converter @c C. + * + * See the comments in the header for a detailed description. + */ +#define SG_ADD_COPY_CONVERSION(D, C) \ + namespace SG { \ + template struct AddCopyConversionInit<D, C >; \ +} struct sg_dummy // to swallow semicolon + + + +namespace SG { + + +/** + * @brief Helper metafunction to get base class types. + * + * For a class @c T, + *@code + * SG::BaseType<SG::Bases<T>::Base1>::type + @endcode + * gives the type of @c T's first base. Also, + *@code + * SG::BaseType<SG::Bases<T>::Base1>::is_virtual + @endcode + * tells whether the derivation is virtual + * (either @c true_type or @c false_type). + * + * Note that @c SG::Bases\<T>::Base1 is not the actual type + * of @c T's first base if virtual derivation was used. + */ +template <class T> +struct BaseType; + + +// Forward declaration. +template <class T> +class BaseInfoImpl; + + +struct BaseInfoBaseImpl; + + +//=========================================================================== +// Copy conversion declarations. +// + + +/** + * @brief Base class for copy conversions. + */ +class CopyConversionBase +{ +public: + /// Destructor. + virtual ~CopyConversionBase() {} + + /// Create an instance of the destination class. + virtual void* create() const = 0; + + /// Destroy an instance of the destination class. + virtual void destroy (void* p) const = 0; + + /// Convert the contents of an instance of the source class SRC + /// to an instance of the destination class DST. + virtual void convertUntyped (const void* src, void* dst) const = 0; +}; + + +/** + * @brief Base class for copy conversions, templated on source + * and destination classes. + */ +template <class SRC, class DST> +class CopyConversion + : public CopyConversionBase +{ +public: + /// The destination class. + typedef DST target_type; + + /// Create an instance of the destination class. + virtual void* create() const { return new DST; } + + /// Destroy an instance of the destination class. + virtual void destroy (void* p) const { delete reinterpret_cast<DST*>(p); } + + /// Convert the contents of an instance of the source class SRC + /// to an instance of the destination class DST. + virtual void convertUntyped (const void* src, void* dst) const + { + convert (*reinterpret_cast<const SRC*>(src), + *reinterpret_cast<DST*>(dst)); + } + + /// Convert the contents of an instance of the source class SRC + /// to an instance of the destination class DST. + /// (Type-safe version.) + virtual void convert (const SRC& src, DST& dst) const = 0; +}; + + +//=========================================================================== +// Base class declaration. +// This factors out the part of the implementation that doesn't +// depend on the template parameter @a T. +// + + +/** + * @brief The non-template portion of the @a BaseInfo implementation. + */ +class BaseInfoBase +{ +public: + /** + * @brief Return the CLID for this class. + */ + CLID clid() const; + + + /** + * @brief Return the @c std::type_info for this class. + */ + const std::type_info& typeinfo() const; + + + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + void* cast (void* p, CLID clid) const; + + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + void* cast (void* p, const std::type_info& tinfo) const; + + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + void* castTo (void* p, CLID clid) const; + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + void* castTo (void* p, const std::type_info& tinfo) const; + + + /// Type of a pointer conversion function. + typedef void* castfn_t (void* p); + + + // gcc 4.3 complains about the code genreflex generates for these. + // They're not useful from python anyway, so just suppress them. +#ifndef __REFLEX__ + /** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + castfn_t* castfn (CLID clid) const; + + + /** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + castfn_t* castfn (const std::type_info& tinfo) const; + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + castfn_t* castfnTo (CLID clid) const; + + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + castfn_t* castfnTo (const std::type_info& tinfo) const; +#endif + + + /** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ + std::vector<CLID> get_bases () const; + + /** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ + std::vector<const std::type_info*> get_ti_bases () const; + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ + bool is_base (CLID clid) const; + + /** + * @brief Return true if @a tinfo is the @a type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ + bool is_base (const std::type_info& tinfo) const; + + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ + bool is_virtual (CLID clid) const; + + /** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ + bool is_virtual (const std::type_info& tinfo) const; + + + /** + * @brief Search for a copy conversion to @c tinfo. + * @param tinfo The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ + const CopyConversionBase* copy_conversion (const std::type_info& tinfo) const; + + + /** + * @brief Search for a copy conversion to @c clid. + * @param clid The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ + const CopyConversionBase* copy_conversion (CLID clid) const; + + + /** + * @brief Add a new copy conversion. + * @param tinfo The @c std::type_info of the target class. + * @param cnv A @c CopyConversionBase instance describing the conversion. + * + * The @c BaseInfoBase takes ownership of the @c cnv object. + */ + void add_copy_conversion (const std::type_info& tinfo, + const CopyConversionBase* cnv); + + + /** + * @brief Return known copy conversions. + * + * Returns the CLIDs of all target classes that have been registered + * with this one for copy conversion. + */ + std::vector<CLID> get_copy_conversions() const; + + +#ifndef __REFLEX__ + /** + * @brief Add information about one base class. + * @param tinfo The @a std::type_info of the base. + * @param converter Converter function. This should be able to + * convert a @a T* to a pointer to this base. + * @param converterTo Converter function. This should be able to + * convert a pointer to this base to a @a T*. + * @param is_virtual True if the derivation from this base to @a T + * is via virtual derivation. + */ + void add_info (const std::type_info& tinfo, + castfn_t* converter, + castfn_t* converterTo, + bool is_virtual); +#endif + + + /** + * @brief Find the @c BaseInfoBase instance for @c clid. + * @param clid The class ID of the class for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ + static const BaseInfoBase* find (CLID clid); + + + /** + * @brief Find the @c BaseInfoBase instance for @c tinfo. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ + static const BaseInfoBase* find (const std::type_info& tinfo); + + + /// Type for an initialization function. + typedef const BaseInfoBase& init_func_t(); + + +#ifndef __REFLEX__ + /** + * @brief Register an initialization function. + * @param tinfo The @c std::type_info for the class being registered. + * @param init_func Function to initialize @c BaseInfo for the class. + */ + static void addInit (const std::type_info* tinfo, + init_func_t* init_func); +#endif + + + /** + * @brief Run initializations for this class, if needed. + */ + void maybeInit(); + + +protected: + /** + * @brief Constructor. + * @param tinfo The @c std::type_info for this class. + */ + BaseInfoBase (const std::type_info& tinfo); + + + /** + * @brief Destructor. + */ + ~BaseInfoBase(); + + +private: + /** + * @brief Helper for @c find. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ + static const BaseInfoBase* find1 (const std::type_info& tinfo); + + + /// Pointer to internal state. + BaseInfoBaseImpl* m_impl; + + BaseInfoBase (const BaseInfoBase&); + BaseInfoBase& operator= (const BaseInfoBase&); +}; + + +//=========================================================================== +// The templated @c BaseInfo class. +// + +/** + * @brief Provide an interface for finding inheritance information + * at run time. See the file comments for full details. + */ +template <class T> +class BaseInfo +{ +public: + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static void* cast (T* p, CLID clid); + + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static void* cast (T* p, const std::type_info& tinfo); + + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static T* castTo (void* p, CLID clid); + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static T* castTo (void* p, const std::type_info& tinfo); + + + /** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static BaseInfoBase::castfn_t* castfn (CLID clid); + + + /** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static BaseInfoBase::castfn_t* castfn (const std::type_info& tinfo); + + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to a @a T. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static BaseInfoBase::castfn_t* castfnTo (CLID clid); + + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @c B to a pointer + * to a @T. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static BaseInfoBase::castfn_t* castfnTo (const std::type_info& tinfo); + + + /** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ + static std::vector<CLID> get_bases (); + + + /** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ + static std::vector<const std::type_info*> get_ti_bases (); + + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ + static bool is_base (CLID clid); + + /** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param tinfo The @a std::type_info of the class to test. + */ + static bool is_base (const std::type_info& tinfo); + + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ + static bool is_virtual (CLID clid); + + /** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ + static bool is_virtual (const std::type_info& tinfo); + + + /** + * @brief Return the non-templated @c BaseInfoBase object for this type. + */ + static const BaseInfoBase& baseinfo (); + + + static void maybeInit (); + + +private: + /// Return a reference to the (singleton) implementation object + /// for this class. + static const BaseInfoImpl<T>& instance(); + + /// This holds the singleton implementation object instance. + struct instance_holder + { + instance_holder(); + BaseInfoImpl<T>* instance; + }; + static instance_holder s_instance; +}; + + +} // namespace SG + + +#include "SGTools/BaseInfo.icc" + + +#endif // not SGTOOLS_BASEINFO_H + diff --git a/EDM/athena/Control/SGTools/SGTools/BaseInfo.icc b/EDM/athena/Control/SGTools/SGTools/BaseInfo.icc new file mode 100644 index 00000000..c60567ae --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/BaseInfo.icc @@ -0,0 +1,675 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.icc,v 1.9 2008-12-15 15:12:39 ssnyder Exp $ +/** + * @file SGTools/BaseInfo.icc + * @author scott snyder + * @date Nov 2005 + * @brief Provide an interface for finding inheritance information + * at run time. + * Implementation file. + */ + + +#include <type_traits> + + +namespace SG { + + +//=========================================================================== +// Inheritance data representation classes. +// + + +/** + * @brief Marker to indicate a nonexistent base class. + */ +struct NoBase {}; + + +/** + * @brief Wrapper to indicate virtual derivation. + * @a Virtual<T> will mean that derivation from @a T is virtual. + */ +template <class T> struct Virtual {}; + + +/** + * @brief Traits class to hold derivation information for up to three + * base classes. + * + * @a Base1, etc., get typedef'd to the appropriate + * base classes. Use @a NoBase if there is no base class; use + * @a Virtual<T> to indicate virtual derivation. This class should + * be specialized for every class @a T for which we want to know + * inheritance information. + */ +template <class T> +struct Bases +{ + typedef NoBase Base1; + typedef NoBase Base2; + typedef NoBase Base3; +}; + + +// Helper metafunction to get base class types. +// Generic case. +template <class T> +struct BaseType +{ + typedef T type; + typedef std::false_type is_virtual; +}; + + +// Helper metafunction to get base class types. +// Virtual derivation case. +template <class T> +struct BaseType<Virtual<T> > +{ + typedef T type; + typedef std::true_type is_virtual; +}; + + +//=========================================================================== +// Internal implementation class for @a BaseInfo. +// This is used as a singleton, and should be accessed using the @a BaseInfo +// wrapper class. +// + +/** + * @brief Internal implementation class for @a BaseInfo. + */ +template <class T> +class BaseInfoImpl + : public BaseInfoBase +{ +public: + /** + * @brief Constructor. + */ + BaseInfoImpl(); + + + /** + * @brief Add information about base class @a B (for @a T). + * @param is_virtual True if the derivation from @a B to @a T + * is via virtual derivation. + */ +#if defined(__REFLEX__) || defined(__COVERITY__) + template <class B> + void add_base (bool is_virtual); +#else + template <class B> + void add_base (bool is_virtual) + { + // Make sure the bib for the base class exists. + BaseInfo<B>::maybeInit(); + + // Add the information for this base. + this->add_info (typeid(B), + converter<B>, converterTo<B>, is_virtual); + } +#endif + +private: + /** + * @brief Converter function. + * @param p Pointer to convert. A @a T* converted to a @a void*. + * + * Converts a @a T* to a @a B* (where @a T derives from @a B). + * The pointers are given and returned as @a void*. + */ + template <class B> + static void* converter (void* p) + { + typedef typename std::remove_const<B>::type B_nc; + typedef typename std::remove_const<T>::type T_nc; + B_nc* b = reinterpret_cast<T_nc*> (p); + return b; + } + + + /** + * @brief Converter function. + * @param p Pointer to convert. A @a B* converted to a @a void*. + * + * Converts a @a B* to a @a T* (where @a T derives from @a B). + * The pointers are given and returned as @a void*. + * Returns 0 if the conversion fails. + * + * Implementation note: to @c dynamic_cast @a B to @a T, @a B needs to have + * a vtable. If B doesn't have a vtable, then we don't attempt the + * conversion. (In principle, we could use is_virtual_base_of, and fall + * back to a static_cast if it's false. However, using is_virtual_base_of + * generates some nasty compilation warnings, so i'll avoid it for now.) + */ + template <class B> + static void* converterTo (void* p) + { + return converterToHelper<B> (p, std::is_polymorphic<B>()); + } + + + // B has a vtable. Use dynamic_cast. + template <class B> + static void* converterToHelper (void* p, std::true_type) + { + typedef typename std::remove_const<B>::type B_nc; + typedef typename std::remove_const<T>::type T_nc; + T_nc* b = dynamic_cast<T_nc*> (reinterpret_cast<B_nc*> (p)); + return b; + } + + + // B doesn't have a vtable. Don't try to convert. + template <class B> + static void* converterToHelper (void* /*p*/, std::false_type) + { + return 0; + } +}; + + +//=========================================================================== +// Initialization. +// Here we walk the class hierarchy, calling @a add_base for each base. + + +/** + * @brief Generic initializer for base @a B. + */ +template <class B> +struct BaseInfo_init +{ + template <class T> + static void init (BaseInfoImpl<T>& c, bool is_virtual) + { + // Here, we initialize the @a BaseInfo for @a T for base class @a B. + // First, we add the information for this base to the instance. + c.template add_base<B>(is_virtual); + + // Then we recurse on each possible base. + BaseInfo_init<typename Bases<B>::Base1>::init (c, is_virtual); + BaseInfo_init<typename Bases<B>::Base2>::init (c, is_virtual); + BaseInfo_init<typename Bases<B>::Base3>::init (c, is_virtual); + } +}; + + +/** + * @brief Dummy initializer. + */ +template <> +struct BaseInfo_init<NoBase> +{ + template <class T> + static void init (BaseInfoImpl<T>& /*c*/, bool /*is_virtual*/) + { + // This gets called when there is no base in a slot + // (signaled by the use of @a NoBase). + // This ends the recursion. + } +}; + + +/** + * @brief Initializer for virtual base @a B. + */ +template <class B> +struct BaseInfo_init<Virtual<B> > +{ + template <class T> + static void init (BaseInfoImpl<T>& c, bool /*is_virtual*/) + { + // Here, we initialize the @a BaseInfo for @a T for a virtual + // base class @a B. We recurse to the generic initializer + // for this base, with the @a is_virtual flag forced on. + BaseInfo_init<B>::init (c, true); + } +}; + + +/** + * @brief Constructor. + */ +template <class T> +BaseInfoImpl<T>::BaseInfoImpl () + : BaseInfoBase (typeid(T)) +{ + // This starts the walk over the bases. + // We start with @a T itself. + // The virtual flag is initially false. + BaseInfo_init<T>::init (*this, false); +} + + +//=========================================================================== +// The @a BaseInfo wrapper class. +// This will statically hold a singleton instance of @a BaseInfoImpl +// (in the instance function). + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +void* BaseInfo<T>::cast (T* p, CLID clid) +{ + typedef typename std::remove_const<T>::type T_nc; + return instance().cast (const_cast<T_nc*>(p), clid); +} + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +void* BaseInfo<T>::cast (T* p, const std::type_info& tinfo) +{ + typedef typename std::remove_const<T>::type T_nc; + return instance().cast (const_cast<T_nc*>(p), tinfo); +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +T* BaseInfo<T>::castTo (void* p, CLID clid) +{ + return reinterpret_cast<T*> (instance().castTo (p, clid)); +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +T* BaseInfo<T>::castTo (void* p, const std::type_info& tinfo) +{ + return reinterpret_cast<T*> (instance().castTo (p, tinfo)); +} + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +/** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +BaseInfoBase::castfn_t* BaseInfo<T>::castfn (CLID clid) +{ + return instance().castfn (clid); +} + + +/** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +BaseInfoBase::castfn_t* +BaseInfo<T>::castfn (const std::type_info& tinfo) +{ + return instance().castfn (tinfo); +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to a @a T. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +BaseInfoBase::castfn_t* BaseInfo<T>::castfnTo (CLID clid) +{ + return instance().castfnTo (clid); +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @c B to a pointer + * to a @T. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +BaseInfoBase::castfn_t* +BaseInfo<T>::castfnTo (const std::type_info& tinfo) +{ + return instance().castfnTo (tinfo); +} +#endif + + +/** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ +template <class T> +std::vector<CLID> BaseInfo<T>::get_bases () +{ + return instance().get_bases(); +} + + +/** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ +template <class T> +std::vector<const std::type_info*> +BaseInfo<T>::get_ti_bases () +{ + return instance().get_ti_bases(); +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_base (CLID clid) +{ + return instance().is_base (clid); +} + + +/** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param tinfo The @a std::type_info of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_base (const std::type_info& tinfo) +{ + return instance().is_base (tinfo); +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_virtual (CLID clid) +{ + return instance().is_virtual (clid); +} + + +/** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_virtual (const std::type_info& tinfo) +{ + return instance().is_virtual (tinfo); +} + + +/** + * @brief Return the non-templated @c BaseInfoBase object for this type. + */ +template <class T> +const BaseInfoBase& BaseInfo<T>::baseinfo() +{ + return instance(); +} + + +template <class T> +void BaseInfo<T>::maybeInit() +{ + BaseInfoImpl<T>* inst = s_instance.instance; + if (inst) + inst->maybeInit(); +} + + +/** + * @brief Return a reference to the (singleton) implementation object + * for this class. + */ +template <class T> +const BaseInfoImpl<T>& BaseInfo<T>::instance() +{ + BaseInfoImpl<T>* inst = s_instance.instance; + if (inst) + inst->maybeInit(); + return *inst; +} + + +/** + * @brief Constructor to get the singleton instance set up. + */ +template <class T> +BaseInfo<T>::instance_holder::instance_holder() +{ + static BaseInfoImpl<T> inst; + instance = &inst; +} + + +/// Declare the static member of @c BaseInfo. +template <class T> +typename BaseInfo<T>::instance_holder BaseInfo<T>::s_instance; + + +/** + * @brief Helper to get @c BaseInfo initialized. + */ +template <class T> +struct RegisterBaseInit +{ + RegisterBaseInit() +#ifdef __GNUC__ + // Force this function to appear as a symbol in the output file, + // even in an optimized build where it's always inlined. + // Otherwise, we get complaints from cling that it can't find the symbol + // (as of root 6.04). + __attribute__ ((used)) +#endif + ; +}; + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +template <class T> +RegisterBaseInit<T>::RegisterBaseInit() +{ + BaseInfoBase::addInit(&typeid(T), BaseInfo<T>::baseinfo); +} +#endif + + +/** + * @brief Helper to get @c BaseInfo initialized. + */ +template <class T> struct BaseInit { + static RegisterBaseInit<T> s_regbase; +}; +#ifndef __APPLE__ +template <class T> RegisterBaseInit<T> BaseInit<T>::s_regbase; +#endif + + +//********************************************************** +// SG_ADD_BASE and SG_ADD_COPY_CONVERSION implementation. + + +/** + * @brief Helper to get @c AddBaseInfo initialized. + */ +template <class D, class B> +struct RegisterAddBaseInit +{ + /// Add ourself to the init list. + RegisterAddBaseInit(); + + /// Init callback: add the new base to the BIB. + static const BaseInfoBase& doinit(); +}; + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +/** + * @brief Init callback: add the new base to the BIB. + */ +template <class D, class B> +const BaseInfoBase& RegisterAddBaseInit<D, B>::doinit() +{ + // B may either be the actual base class we want, + // or Virtual<BB>. Unwrap a surrounding Virtual<> if needed. + typedef typename BaseType<B>::type base_type; + bool is_virtual = BaseType<B>::is_virtual::value; + + // Look up the BIB. + SG::BaseInfoBase* bib = + const_cast<SG::BaseInfoBase*> (SG::BaseInfoBase::find (typeid(D))); + if (!bib) + bib = const_cast<SG::BaseInfoBase*> (&BaseInfo<D>::baseinfo()); + if (bib) { + // Add the new base to it. + SG::BaseInfoImpl<D>& impl = *static_cast<SG::BaseInfoImpl<D>*> (bib); + impl.template add_base<base_type> (is_virtual); + } + return *bib; +} + + +/** + * @brief Add ourself to the init list. + */ +template <class D, class B> +RegisterAddBaseInit<D, B>::RegisterAddBaseInit() +{ + BaseInfoBase::addInit(&typeid(D), doinit); +} +#endif + + +/** + * @brief Helper to get @c AddBaseInfo initialized. + */ +template <class D, class B> struct AddBaseInit { + static RegisterAddBaseInit<D, B> s_regbase; +}; +#ifndef __APPLE__ +template <class D, class B> +RegisterAddBaseInit<D,B> AddBaseInit<D,B>::s_regbase; +#endif + + + +/** + * @brief Helper to get the copy conversion initialized. + */ +template <class D, class B> +struct RegisterAddCopyConversionInit +{ + /// Add ourself to the init list. + RegisterAddCopyConversionInit(); + + /// Init callback: xxx + static const BaseInfoBase& doinit(); +}; + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +/** + * @brief Init callback: add the new conversion to the BIB. + */ +template <class T, class C> +const BaseInfoBase& RegisterAddCopyConversionInit<T, C>::doinit() +{ + // Look up the BIB. + SG::BaseInfoBase* bib = + const_cast<SG::BaseInfoBase*> (SG::BaseInfoBase::find (typeid(T))); + if (!bib) + bib = const_cast<SG::BaseInfoBase*> (&BaseInfo<T>::baseinfo()); + if (bib) { + typedef typename C::target_type target_type; + bib->add_copy_conversion (typeid(target_type), + new C); + } + return *bib; +} + + +/** + * @brief Add ourself to the init list. + */ +template <class T, class C> +RegisterAddCopyConversionInit<T, C>::RegisterAddCopyConversionInit() +{ + BaseInfoBase::addInit(&typeid(T), doinit); +} +#endif + + +/** + * @brief Helper to get @c AddBaseInfo initialized. + */ +template <class T, class C> struct AddCopyConversionInit { + static RegisterAddCopyConversionInit<T, C> s_regbase; +}; +#ifndef __APPLE__ +template <class T, class C> +RegisterAddCopyConversionInit<T,C> AddCopyConversionInit<T,C>::s_regbase; +#endif + + +} // namespace SG + diff --git a/EDM/athena/Control/SGTools/SGTools/BuiltinsClids.h b/EDM/athena/Control/SGTools/SGTools/BuiltinsClids.h new file mode 100644 index 00000000..73ac98b1 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/BuiltinsClids.h @@ -0,0 +1,34 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// BuiltinsClids.h +// Header file for CLIDs for C++ builtins +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef SGTOOLS_BUILTINSCLIDS_H +#define SGTOOLS_BUILTINSCLIDS_H + +// STL includes +#include <string> + +// Gaudi includes + +// SGTools includes +#include "SGTools/CLASS_DEF.h" + +CLASS_DEF( char , 81926032 , 1 ) +CLASS_DEF( bool , 134610868 , 1 ) +CLASS_DEF( int , 244260744 , 1 ) +CLASS_DEF( unsigned int , 78410462 , 1 ) +CLASS_DEF( long , 136869678 , 1 ) +CLASS_DEF( unsigned long , 47413844 , 1 ) +CLASS_DEF( unsigned long long , 70769527 , 1 ) +CLASS_DEF( long long , 16133813 , 1 ) +CLASS_DEF( float , 225912587 , 1 ) +CLASS_DEF( double , 239989609 , 1 ) +CLASS_DEF( std::string , 116449351 , 1 ) + +#endif // !SGTOOLS_BUILTINSCLIDS_H diff --git a/EDM/athena/Control/SGTools/SGTools/CLASS_DEF.h b/EDM/athena/Control/SGTools/SGTools/CLASS_DEF.h new file mode 100644 index 00000000..da8fa1da --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/CLASS_DEF.h @@ -0,0 +1,135 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_CLASS_DEF_H +#define SGTOOLS_CLASS_DEF_H +/** @file CLASS_DEF.h + * @brief macros to associate a CLID to a type + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> + * $Id: CLASS_DEF.h,v 1.3 2009-01-15 19:07:29 binet Exp $ + */ + +#include "SGTools/ClassID_traits.h" +#include "CxxUtils/unused.h" +#include <boost/preprocessor/stringize.hpp> + +#ifdef __CLING__ +# define CLIDREGISTRY_ADDENTRY(CID, NAME) \ + namespace detail { \ + const bool UNUSED(clidEntry_ ## CID) = \ + CLIDRegistry::addEntry(CID, typeid(NAME), \ + ClassID_traits< NAME >::typeNameString(), \ + ClassID_traits< NAME >::packageInfo(), \ + ClassName< NAME >::name()); \ + } +# define CLIDREGISTRY_ADDENTRY2(CID, ARG1, ARG2) \ + namespace detail { \ + const bool UNUSED(clidEntry_ ## CID) = \ + CLIDRegistry::addEntry \ + (CID, typeid(ARG1,ARG2), \ + ClassID_traits< ARG1,ARG2 >::typeNameString(), \ + ClassID_traits< ARG1,ARG2 >::packageInfo(), \ + ClassName< ARG1,ARG2 >::name()); \ + } +#else +# define CLIDREGISTRY_ADDENTRY(CID, NAME) \ + namespace detail { \ + const bool UNUSED(clidEntry_ ## CID) = \ + CLIDRegistry::addEntry<CID>(typeid(NAME), \ + ClassID_traits< NAME >::typeNameString(), \ + ClassID_traits< NAME >::packageInfo(), \ + ClassName< NAME >::name()); \ + } +# define CLIDREGISTRY_ADDENTRY2(CID, ARG1, ARG2) \ + namespace detail { \ + const bool UNUSED(clidEntry_ ## CID) = \ + CLIDRegistry::addEntry<CID> \ + (typeid(ARG1,ARG2), \ + ClassID_traits< ARG1,ARG2 >::typeNameString(), \ + ClassID_traits< ARG1,ARG2 >::packageInfo(), \ + ClassName< ARG1,ARG2 >::name()); \ + } +#endif + +/** @def CLASS_DEF(NAME, CID , VERSION) + * @brief associate a clid and a version to a type + * eg + * @code + * CLASS_DEF(std::vector<Track*>,8901, 1) + * @endcode + * @param NAME type name + * @param CID clid + * @param VERSION not yet used + */ +#define CLASS_DEF(NAME, CID , VERSION) \ + template <> \ + struct ClassID_traits< NAME > { \ + typedef std::is_base_of<DataObject, NAME> isDObj_t; \ + static const bool s_isDataObject = isDObj_t::value; \ + typedef std::integral_constant<bool, s_isDataObject> is_DataObject_tag; \ + typedef std::true_type has_classID_tag; \ + static const CLID& ID() { static CLID c(CID); return c; } \ + static const char* typeNameString() { \ + return #NAME; \ + } \ + static const std::string& typeName() { \ + static const std::string name = typeNameString(); \ + return name; \ + } \ + static Athena::PackageInfo packageInfo() { \ + static Athena::PackageInfo pi( BOOST_PP_STRINGIZE(PACKAGE_VERSION_UQ) ); \ + return pi; \ + } \ + static const std::type_info& typeInfo() { \ + return typeid (NAME); \ + } \ + typedef std::true_type has_version_tag; \ + static const int s_version = VERSION; \ + static const bool s_isConst = false; \ + }; \ + CLIDREGISTRY_ADDENTRY(CID, NAME) + + +/** @def CLASS_DEF2(ARG1, ARG2, CID , VERSION) + * @brief hack to use instead of CLASS_DEF when type name contains a comma ',' + * eg + * @code + * CLASS_DEF2(map<int,string>,8900, 1) + * @endcode + * @param ARG1 type name (1st part) + * @param ARG2 type name (2nd part) + * @param CID clid + * @param VERSION not yet used + */ +#define CLASS_DEF2(ARG1, ARG2, CID , VERSION) \ + template <> \ + struct ClassID_traits< ARG1,ARG2 > { \ + typedef std::is_base_of<DataObject, ARG1, ARG2 > isDObj_t; \ + static const bool s_isDataObject = isDObj_t::value; \ + typedef std::integral_constant<bool, s_isDataObject> is_DataObject_tag; \ + typedef std::true_type has_classID_tag; \ + static const CLID& ID() { \ + static CLID c(CID); return c; \ + } \ + static const char* typeNameString() { \ + return #ARG1 "," #ARG2; \ + } \ + static const std::string& typeName() { \ + static const std::string name = typeNameString(); \ + return name; \ + } \ + static const std::type_info& typeInfo() { \ + return typeid (ARG1,ARG2); \ + } \ + static Athena::PackageInfo packageInfo() { \ + return Athena::PackageInfo("Package-00-00-00"); \ + } \ + typedef std::true_type has_version_tag; \ + static const int s_version = VERSION; \ + static const bool s_isConst = false; \ + }; \ + CLIDREGISTRY_ADDENTRY2(CID, ARG1, ARG2) + +#endif // not SGTOOLS_CLASS_DEF_H diff --git a/EDM/athena/Control/SGTools/SGTools/CLIDRegistry.h b/EDM/athena/Control/SGTools/SGTools/CLIDRegistry.h new file mode 100644 index 00000000..b88d065e --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/CLIDRegistry.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_CLIDREGISTRY_H +# define SGTOOLS_CLIDREGISTRY_H +/** @file CLIDRegistry.h + * @brief a static registry of CLID->typeName entries. NOT for general use. + * Use ClassIDSvc instead. + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + *$Id: CLIDRegistry.h,v 1.2 2009-01-15 19:07:29 binet Exp $ + */ + +#include <vector> +#include <string> +#include <utility> /* pair */ +#include <boost/tuple/tuple.hpp> +#include <boost/static_assert.hpp> + +/* #define CLIDREG_DEBUG 1 */ +#ifdef CLIDREG_DEBUG + #include <iostream> +#endif + +#include "AthenaKernel/tools/AthenaPackageInfo.h" +#ifndef BOOST_HAS_STATIC_ASSERT +# include "CxxUtils/unused.h" +#endif + +namespace CLIDdetail { + /// @name allowed class id range + //@{ + const unsigned long MINCLID = 256; + const unsigned long MAXCLID = 2147483647; ///< 2**31 - 1 + //@} +} + +/** @class CLIDRegistry + * @brief a static registry of CLID->typeName entries. NOT for general use. + * Use ClassIDSvc instead. + */ +class CLIDRegistry { +private: + typedef boost::tuple <unsigned long, + std::string, + Athena::PackageInfo, + std::string> tuple_t; + typedef std::vector< tuple_t > CLIDRegistryImpl; +public: + typedef CLIDRegistryImpl::const_iterator const_iterator; + + ///to be called by the CLASS_DEFS + template <unsigned long CLID> + static bool addEntry(const std::type_info& ti, + const char* typeName, + const Athena::PackageInfo& pkgInfo, + const std::string& typeInfoName); + // static bool addEntry(unsigned long id, const std::string& typeName); + + /// allowed class id range (backward compatibility) + //@{ + static const unsigned long MINCLID; + static const unsigned long MAXCLID; + //@} + + /// registry accessors (used by ClassIDSvc) + //@{ + static const_iterator begin(); + static const_iterator end(); + /// are there new entries since last call? Does not move the entries ptr + static bool hasNewEntries(); + /// returns an iterator range over the entries added since last time + /// newEntries was called + static std::pair<const_iterator, const_iterator> newEntries(); + //@} + + /// Translate between CLID and type_info. + static const std::type_info* CLIDToTypeinfo (unsigned long clid); + static unsigned long typeinfoToCLID (const std::type_info& ti); + + + /// Out-of-line part of addEntry(). + static bool addEntry (unsigned long clid, + const std::type_info& ti, + const char* typeName, + const Athena::PackageInfo& pkgInfo, + const std::string& typeInfoName); + +private: + /// Add a CLID <> type_info mapping. + static void addCLIDMapping (unsigned long clid, const std::type_info& ti); + + static CLIDRegistryImpl& registry(); +}; + + +//the drudgery below is to issue a compilation error when CLID is +//out of range +template <bool x> struct ERROR_CLID_out_of_CLIDRegistry_range; +template <> struct ERROR_CLID_out_of_CLIDRegistry_range<true>{}; + +#ifndef __GCCXML__ + +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> +template <unsigned long CLID> +bool CLIDRegistry::addEntry(const std::type_info& ti, + const char* typeName, + const Athena::PackageInfo& pkgInfo, + const std::string& typeInfoName) { + //more drudgery +#ifdef BOOST_HAS_STATIC_ASSERT + static_assert (CLIDdetail::MINCLID <= CLID && CLID <= CLIDdetail::MAXCLID, + "CLID out of CLIDRegistry range"); +#else + UNUSED(typedef ::boost::static_assert_test< + sizeof(ERROR_CLID_out_of_CLIDRegistry_range< (bool)(CLIDdetail::MINCLID <= CLID && CLID <= CLIDdetail::MAXCLID) >) + > BOOST_JOIN(boost_static_assert_typedef_, __LINE__)); +#endif + + addEntry (CLID, ti, typeName, pkgInfo, typeInfoName); + return true; +} + +#endif + +#endif // SGTOOLS_CLIDREGISTRY_H diff --git a/EDM/athena/Control/SGTools/SGTools/CallBackID.h b/EDM/athena/Control/SGTools/SGTools/CallBackID.h new file mode 100644 index 00000000..11df6021 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/CallBackID.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_CALLBACKID_H +#define SGTOOLS_CALLBACKID_H + +/***************************************************************************** + * + * CallBackID.h + * IOVSvc + * + * Author: Charles Leggett + * $Id: CallBackID.h,v 1.3 2005-11-08 22:01:30 ssnyder Exp $ + * + * Provides means to identify a callback function. + * + *****************************************************************************/ + +#ifndef ATHENAKERNEL_IOVSVCDEFS_H + #include "AthenaKernel/IOVSvcDefs.h" +#endif + +class CallBackID { +public: + CallBackID():m_offset(0),p_obj(0){}; + + template<typename T> + CallBackID(StatusCode (T::*updF)(IOVSVC_CALLBACK_ARGS), const T *obj) { + set(updF,obj); + } + + template<typename T> + void set(StatusCode (T::*updF)(IOVSVC_CALLBACK_ARGS), const T *obj); + + std::string name() const { return m_name; } + std::string objName() const { return m_objName; } + int offset() const { return m_offset; } + const void* ptr() const { return p_obj; } + + bool operator==(const CallBackID& cb) const { + return ( cb.m_offset == m_offset && cb.p_obj == p_obj ); + } + bool operator<(const CallBackID& cb) const { + if ( p_obj != cb.p_obj ) { + return ( p_obj < cb.p_obj ) ; + } else { + return ( m_offset < cb.m_offset ); + } + } + +private: + long m_offset; + const void* p_obj; + + std::string m_name; + std::string m_objName; + +}; + +#ifndef SGTOOLS_CALLBACKID_ICC + #include "SGTools/CallBackID.icc" +#endif + +#endif diff --git a/EDM/athena/Control/SGTools/SGTools/CallBackID.icc b/EDM/athena/Control/SGTools/SGTools/CallBackID.icc new file mode 100644 index 00000000..72c251e9 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/CallBackID.icc @@ -0,0 +1,56 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_CALLBACKID_ICC +#define SGTOOLS_CALLBACKID_ICC + +/***************************************************************************** + * + * CallBackID.h + * IOVSvc + * + * Author: Charles Leggett + * $Id: CallBackID.icc,v 1.4 2005-11-08 22:01:30 ssnyder Exp $ + * + * Provides means to identify a callback function. + * + *****************************************************************************/ + +#ifndef _CPP_SSTREAM + #include <sstream> +#endif +#ifndef _STDIO_H + #include "stdio.h" +#endif +#ifndef GAUDIKERNEL_SYSTEM_H + #include "GaudiKernel/System.h" +#endif + +template<typename T> +void CallBackID::set( StatusCode (T::*updF)(IOVSVC_CALLBACK_ARGS), + const T *obj) +{ + union { + StatusCode (T::*updF)(IOVSVC_CALLBACK_ARGS); + long i; + } u; + u.updF = updF; + + p_obj = (void*) obj; + m_offset = u.i; + + // make allowances for various versions of gcc + #if (__GNUC__ < 3) + m_offset /= 0x10000; + #endif + + std::ostringstream ost; + ost << std::hex << "[0x" << (long)p_obj << "]+" << m_offset; + + m_objName = System::typeinfoName(typeid(*obj)); + m_name = m_objName + ost.str(); + +} + +#endif diff --git a/EDM/athena/Control/SGTools/SGTools/ClassID_traits.h b/EDM/athena/Control/SGTools/SGTools/ClassID_traits.h new file mode 100644 index 00000000..81a90cb3 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/ClassID_traits.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_CLASSID_TRAITS_H +#define SGTOOLS_CLASSID_TRAITS_H +/** @file ClassID_traits.h + * @brief a traits class that associates a CLID to a type T + * It also detects whether T inherits from Gaudi DataObject + * + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + * $Id: ClassID_traits.h,v 1.3 2009-01-15 19:07:29 binet Exp $ + */ +#include <string> +#include <typeinfo> + +#include <boost/static_assert.hpp> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/System.h" + +#include "SGTools/CLIDRegistry.h" +#include "SGTools/ClassName.h" + +#include "AthenaKernel/tools/AthenaPackageInfo.h" +#ifndef BOOST_HAS_STATIC_ASSERT +# include "CxxUtils/unused.h" +#endif +#include <type_traits> + + + +template <bool x> struct ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION; +template <> struct ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION<true>{}; + +///internal use: issues a compilation error when condition B is false +#ifdef BOOST_HAS_STATIC_ASSERT +#define MY_STATIC_ASSERT( B ) \ + static_assert (B, "You should use the CLASS_DEF macro to define CLID and VERSION"); +#else +#define MY_STATIC_ASSERT( B ) \ + UNUSED(typedef ::boost::static_assert_test< \ + sizeof(ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION< (bool)( B ) >)>\ + BOOST_JOIN(boost_static_assert_typedef_, __LINE__)) +#endif + +/** @class ClassID_traits + * @brief a traits class that associates a CLID to a type T + * It also detects whether T inherits from Gaudi DataObject + */ +template <typename T> +struct ClassID_traits { + //default only works for DataObjects + typedef std::is_base_of<DataObject, T> isDObj_t; + ///flags whether T inherits from DataObject + static const bool s_isDataObject = isDObj_t::value; + + //default traits for class ID assignment + typedef std::integral_constant<bool, s_isDataObject> is_DataObject_tag; + + ///the CLID of T + static const CLID& ID() { + MY_STATIC_ASSERT(s_isDataObject); + return T::classID(); + } + + ///the demangled type name of T + static const std::string& typeName() { + MY_STATIC_ASSERT(s_isDataObject); + static const std::string tname = System::typeinfoName(typeid(T)); + return tname; + } + + ///the type id of T + static const std::type_info& typeInfo() { + MY_STATIC_ASSERT(s_isDataObject); + return typeid(T); + } + + ///the package name of this CLASSDEF (and BY CONVENTION of the data obj too!) + static Athena::PackageInfo packageInfo() { + MY_STATIC_ASSERT(s_isDataObject); + return Athena::PackageInfo("Package-00-00-00"); + } + + typedef std::false_type has_version_tag; + typedef std::false_type has_classID_tag; + static const int s_version = 0; + + // Is this is true, these types will automatically be made + // const when added to StoreGate. + static const bool s_isConst = false; +}; + +#undef MY_STATIC_ASSERT + +#endif // not SGTOOLS_CLASSID_TRAITS_H + + + + + + diff --git a/EDM/athena/Control/SGTools/SGTools/ClassName.h b/EDM/athena/Control/SGTools/SGTools/ClassName.h new file mode 100644 index 00000000..80826d4e --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/ClassName.h @@ -0,0 +1,53 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ClassName.h,v 1.1 2009-01-15 19:07:29 binet Exp $ +/** + * @file SGTools/ClassName.h + * @author scott snyder + * @date Jul 2005 + * @brief An interface for getting the name of a class as a string. + */ + + +#ifndef SGTOOLS_CLASSNAME_H +#define SGTOOLS_CLASSNAME_H + + +#include <string> + + +/** + * @brief An interface for getting the name of a class as a string. + * + * This template class provides an interface for getting the name + * of a class as a string. By default, it uses @c typeinfoName + * from @c GaudiKernel, but it may be specialized to override + * the behavior for specific classes. + */ +template <class T> +class ClassName +{ +public: + /** + * @brief Return the name of class @c T as a string. + */ + static std::string name() +#ifdef __GNUC__ + // Force this function to appear as a symbol in the output file, + // even in an optimized build where it's always inlined. + // Otherwise, we get complaints from cling that it can't find the symbol + // (as of root 6.04). + __attribute__ ((used)) +#endif + ; +}; + + +#include "SGTools/ClassName.icc" + + +#endif // not SGTOOLS_CLASSNAME_H diff --git a/EDM/athena/Control/SGTools/SGTools/ClassName.icc b/EDM/athena/Control/SGTools/SGTools/ClassName.icc new file mode 100644 index 00000000..55e22f24 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/ClassName.icc @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ClassName.icc,v 1.1 2009-01-15 19:07:29 binet Exp $ +/** + * @file DataModel/ClassName.icc + * @author scott snyder + * @date Jul 2005 + * @brief An interface for getting the name of a class as a string. + * Implementation file. + */ + + +#include "GaudiKernel/System.h" + + +/** + * @brief Return the name of class @c T as a string. + */ +template <class T> +std::string ClassName<T>::name() +{ + return System::typeinfoName (typeid (T)); +} + +// /** +// * @brief Specialization of @c ClassName for @c std::vector. +// * +// * This overrides the default implementation of @c ClassName +// * to hide @c std::vector's second template parameter. +// */ +// #include <vector> +// template <class T> +// std::string ClassName<std::vector<T> >::name() +// { +// std::string out = "std::vector<"; +// out += ClassName<T>::name(); +// if (out[out.size()-1] == '>') +// out += ' '; +// out += '>'; +// return out; +// } + +// /** +// * @brief Specialization of @c ClassName for @c std::list. +// * +// * This overrides the default implementation of @c ClassName +// * to hide @c std::list's second template parameter. +// */ +// #include <list> +// template <class T> +// std::string ClassName<std::list<T> >::name() +// { +// std::string out = "std::list<"; +// out += ClassName<T>::name(); +// if (out[out.size()-1] == '>') +// out += ' '; +// out += '>'; +// return out; +// } + +// /** +// * @brief Specialization of @c ClassName for @c std::map. +// * +// * This overrides the default implementation of @c ClassName +// * to hide @c std::map's 4th template parameter (and optionally the 3rd too) +// */ +// #include <map> +// template <class K, class V, class C> +// std::string ClassName<std::map<K, V, C> >::name() +// { +// std::string out = "std::map<"; +// out += ClassName<K>::name()+ "," + ClassName<V>::name(); +// std::string comp = ClassName<C>::name(); +// if (comp.size() > 10 && comp.substr(0, 10) != "std::less<") { +// out += ","+ClassName<C>::name(); +// } +// if (out[out.size()-1] == '>') +// out += ' '; +// out += '>'; +// return out; +// } + + diff --git a/EDM/athena/Control/SGTools/SGTools/CurrentEventStore.h b/EDM/athena/Control/SGTools/SGTools/CurrentEventStore.h new file mode 100644 index 00000000..e8c78a3b --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/CurrentEventStore.h @@ -0,0 +1,78 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/CurrentEventStore.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2015 + * @brief Hold a pointer to the current event store. + */ + + +#ifndef SGTOOLS_CURRENTEVENTSTORE_H +#define SGTOOLS_CURRENTEVENTSTORE_H + + +class IProxyDict; +#include "SGTools/IProxyDictWithPool.h" + + +namespace SG { + + + +/** + * @brief Hold a pointer to the current event store. + * + * Athena has a notion of a `current' event store. This is used, for example, + * when @c ElementLinks are initialized without explicitly specifying the store. + * + * Be aware that the current event store is thread-specific and thus + * fetching it is relatively expensive. It would be better to move + * calls to store() outside of loops. + */ +class CurrentEventStore +{ +public: + /// Fetch the current store. + static IProxyDict* store(); + + + /// Set the current store. + /// Returns the previous store. + static IProxyDict* setStore (IProxyDict* store); + + + /** + * @brief Temporarily change the current store. + * + * The previous store will be restored when this object is destroyed. + */ + class Push + { + public: + Push (IProxyDict* store); + ~Push(); + + private: + IProxyDict* m_oldStore; + }; + + +private: + /// The current event store. + static IProxyDict* m_curStore; +}; + + +} // namespace SG + + +#include "SGTools/CurrentEventStore.icc" + + +#endif // not SGTOOLS_CURRENTEVENTSTORE_H diff --git a/EDM/athena/Control/SGTools/SGTools/CurrentEventStore.icc b/EDM/athena/Control/SGTools/SGTools/CurrentEventStore.icc new file mode 100644 index 00000000..72f29344 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/CurrentEventStore.icc @@ -0,0 +1,47 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/CurrentEventStore.icc + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2015 + * @brief Hold a pointer to the current event store. + */ + + +namespace SG { + + +/** + * @brief Fetch the current store. + */ +inline +IProxyDict* CurrentEventStore::store() +{ + return m_curStore; +} + + +/** + * @brief Temporarily change the current event store. + */ +inline +CurrentEventStore::Push::Push (IProxyDict* store) + : m_oldStore (setStore (store)) +{ +} + + +/** + * @brief Restore the current event store. + */ +inline +CurrentEventStore::Push::~Push() +{ + setStore (m_oldStore); +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/SGTools/DataBucket.h b/EDM/athena/Control/SGTools/SGTools/DataBucket.h new file mode 100644 index 00000000..cc9b301a --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataBucket.h @@ -0,0 +1,136 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_DATABUCKET_H +#define SGTOOLS_DATABUCKET_H + +#include "SGTools/DataBucketBase.h" +#include "AthenaKernel/DataObjectSharedPtr.h" + +//FIXME CLID is a tdef and can't be forward declared +#include "GaudiKernel/ClassID.h" +#include <memory> +#include <type_traits> + +/** @class DataBucket + * @brief a wrapper inheriting from DataObject (via DataBucketBase) + * that takes ownership of a data object to be put in the DataStore + * @author ATLAS Collaboration + * $Id: DataBucket.h,v 1.10 2008-06-25 22:45:49 calaf Exp $ + **/ + +namespace SG { + class IRegisterTransient; + class CopyConversionBase; + + template <class T> + class DataBucket : public DataBucketBase { + + public: + + // CONSTRUCTORS: + + DataBucket(): m_ptr(0) {} //needed by the generic converters + DataBucket(T* data); + DataBucket(std::unique_ptr<T> data); + DataBucket(SG::DataObjectSharedPtr<T> data); + + // DESTRUCTOR: + + virtual ~DataBucket(); + + // DATAOBJECT METHODS + virtual const CLID& clID() const override; + static const CLID& classID(); + + // return the pointer as a void* + virtual void* object() override + { + typedef typename std::remove_const<T>::type T_nc; + return const_cast<T_nc*>(m_ptr); + } + + /** + * @brief Return the @c type_info for the stored object. + */ + virtual const std::type_info& tinfo() const override + { + return typeid(T); + } + + // Serialize the object for reading + // StreamBuffer& serialize(StreamBuffer& s); + // Serialize the object for writing + // StreamBuffer& serialize(StreamBuffer& s) const; + + + + // AUTOMATIC CONVERSION OF TYPES + operator T*() { return ptr(); } //FIXME can we do without? + operator const T*() const { return cptr(); } + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a clid. Note that only + * derived->base conversions are allowed here. + * @param clid The class ID to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + virtual void* cast (CLID clid, + IRegisterTransient* irt = 0, + bool isConst = true) const override; + + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a std::type_info. Note that only + * derived->base conversions are allowed here. + * @param clid The @a std::type_info of the type to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + virtual void* cast (const std::type_info& tinfo, + IRegisterTransient* irt = 0, + bool isConst = true) const override; + + /** + * @brief Return a new @c DataBucket whose payload has been cloned from the + * original one. + */ + virtual DataBucket* clone() const override; + + /** + * @brief Give up ownership of the @c DataBucket contents. + * This leaks the contents and it is useful mainly for error handling. + */ + virtual void relinquish() override{ m_ptr=0;} //LEAKS m_ptr + + /** + * If the held object derives from @c ILockable, call @lock() on it. + */ + virtual void lock() override; + + + protected: + T* ptr() { return m_ptr; } + const T* cptr() const { return m_ptr; } + + private: + T* m_ptr; //we own the thing now! + + /// Objects made by copy conversion. + typedef std::pair<const CopyConversionBase*, void*> ent_t; + typedef std::vector<ent_t> vec_t; + mutable vec_t m_cnvcopies; + + DataBucket (const DataBucket&); + DataBucket& operator= (const DataBucket&); + }; +} //end namespace SG +#include "SGTools/DataBucket.icc" + +#endif // SGTOOLS_DATABUCKET_H diff --git a/EDM/athena/Control/SGTools/SGTools/DataBucket.icc b/EDM/athena/Control/SGTools/SGTools/DataBucket.icc new file mode 100644 index 00000000..23f873d2 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataBucket.icc @@ -0,0 +1,256 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <boost/type_traits/cv_traits.hpp> +#include <boost/type_traits/transform_traits.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/is_abstract.hpp> +#include <boost/type_traits/has_trivial_copy.hpp> + +#include "SGTools/ClassID_traits.h" +#include "SGTools/BaseInfo.h" +#include "SGTools/IRegisterTransient.h" +#include "AthenaKernel/ILockable.h" + +#include <type_traits> + + +// Some helper functions. +namespace SG { + + +// If T is a DataObject, increment its reference count. +// The second parameter tells whether or not T is a DataObject. +template <class T> +void db_maybe_ref (T*, std::false_type) +{ +} +template <class T> +void db_maybe_ref (T* ptr, std::true_type) +{ + ptr->addRef(); +} + + +// Release the pointer PTR. +// If T is a DataObject, then decrement the reference count; +// otherwise, just delete it. +// The second parameter tells whether or not T is a DataObject. +template <class T> +void db_free_ptr (T* ptr, std::false_type) +{ + // std::cout << "db_free_ptr: deleting ptr @" << ptr << " of type " << ClassID_traits<T>::typeName() << std::endl; + delete ptr; +} +template <class T> +void db_free_ptr (T* ptr, std::true_type) +{ + typedef typename std::remove_const<T>::type T_nc; + // std::cout << "db_free_ptr: releasing ptr @" << ptr << " of type " << ClassID_traits<T>::typeName() << std::endl; + const_cast<T_nc*>(ptr)->release(); +} + +// if T is abstract just return NULL and let clients deal with that +template <typename T> +SG::DataBucket<T>* db_clone_ptr (T*, boost::false_type) +{ return NULL; } + +// else use the copy constructor +template <typename T> +SG::DataBucket<T>* db_clone_ptr (T* ptr, boost::true_type) +{ return new SG::DataBucket<T>( new T(*ptr) ); } + +} // namespace SG + + +/////////////////////////////////////////////////////////////////////////////// +// CONSTRUCTORS +/////////////////////////////////////////////////////////////////////////////// +template <typename T> +SG::DataBucket<T>::DataBucket(T* data) + : m_ptr(data) +{ + // If T is a DataObject, increase the refcount. + typedef typename ClassID_traits<T>::is_DataObject_tag tag; + if (m_ptr) + SG::db_maybe_ref (m_ptr, tag()); +} + +template <typename T> +SG::DataBucket<T>::DataBucket(std::unique_ptr<T> data) + : m_ptr(data.release()) +{ + // If T is a DataObject, increase the refcount. + typedef typename ClassID_traits<T>::is_DataObject_tag tag; + if (m_ptr) + SG::db_maybe_ref (m_ptr, tag()); +} + +template <typename T> +SG::DataBucket<T>::DataBucket(SG::DataObjectSharedPtr<T> data) + : m_ptr(data.detach()) +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// DATAOBJECT +/////////////////////////////////////////////////////////////////////////////// +template <typename T> +const CLID& SG::DataBucket<T>::clID() const {return classID();} + +template <typename T> +const CLID& SG::DataBucket<T>::classID() { + typedef typename ::boost::remove_pointer<T>::type BareTp; + typedef typename ::boost::remove_const<BareTp>::type BareT; + return ClassID_traits<BareT>::ID(); +} + + +/** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a clid. Note that only + * derived->base conversions are allowed here. + * @param clid The class ID to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ +template <typename T> +void* +SG::DataBucket<T>::cast (CLID clid, + IRegisterTransient* irt /*= 0*/, + bool isConst /*=true*/) const +{ + void* ret = SG::BaseInfo<T>::cast (m_ptr, clid); + if (ret || !isConst) + return ret; + + // Is there a copy conversion available? + const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (clid); + if (cc) { + vec_t::iterator end = m_cnvcopies.end(); + for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) { + if (cc == it->first) { + cc->convertUntyped (m_ptr, it->second); + } + return it->second; + } + + void* newcont = cc->create(); + if (newcont) { + cc->convertUntyped (m_ptr, newcont); + m_cnvcopies.push_back (std::make_pair (cc, newcont)); + irt->registerTransient (newcont); + } + return newcont; + } + + return 0; +} + + +/** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a std::type_info. Note that only + * derived->base conversions are allowed here. + * @param clid The @a std::type_info of the type to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ +template <typename T> +void* SG::DataBucket<T>::cast (const std::type_info& tinfo, + IRegisterTransient* irt /*= 0*/, + bool isConst /*= true*/) const +{ + void* ret = SG::BaseInfo<T>::cast (m_ptr, tinfo); + if (ret || !isConst) + return ret; + + // Is there a copy conversion available? + const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (tinfo); + if (cc) { + vec_t::iterator end = m_cnvcopies.end(); + for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) { + if (cc == it->first) { + cc->convertUntyped (m_ptr, it->second); + } + return it->second; + } + + void* newcont = cc->create(); + if (newcont) { + cc->convertUntyped (m_ptr, newcont); + m_cnvcopies.push_back (std::make_pair (cc, newcont)); + irt->registerTransient (newcont); + } + return newcont; + } + + return 0; +} + +/** + * @brief Return a new @c DataBucket whose payload has been cloned from the + * original one. + */ +template <typename T> +SG::DataBucket<T>* SG::DataBucket<T>::clone() const +{ + if (!m_ptr) { return NULL; } + + typedef + boost::integral_constant< bool, !::boost::is_abstract<T>::value && + ::boost::has_trivial_copy<T>::value > + truth_type_t; + return SG::db_clone_ptr( m_ptr, truth_type_t() ); +} + +template <typename T> +SG::DataBucket<T>::~DataBucket() +{ + // Delete any copies. + vec_t::iterator end = m_cnvcopies.end(); + for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) { + it->first->destroy (it->second); + } + + // Either delete m_ptr or decrement the refcount, + // depending on whether or not T is a DataObject. + typedef typename ClassID_traits<T>::is_DataObject_tag tag; + if (m_ptr) + SG::db_free_ptr(m_ptr, tag()); +} + + +namespace { + + +template <class T> +void call_lock (T* p, std::true_type) +{ + typedef typename std::remove_const<T>::type T_nc; + ILockable* l = dynamic_cast<ILockable*> (const_cast<T_nc*>(p)); + if (l) l->lock(); +} + + +template <class T> +void call_lock (T*, std::false_type) +{ +} + + +} // anonymous namespace + + +/** + * If the held object derives from @c ILockable, call @lock() on it. + */ +template <class T> +void SG::DataBucket<T>::lock() +{ + call_lock (m_ptr, typename std::is_polymorphic<T>::type()); +} + diff --git a/EDM/athena/Control/SGTools/SGTools/DataBucketBase.h b/EDM/athena/Control/SGTools/SGTools/DataBucketBase.h new file mode 100644 index 00000000..602dc20a --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataBucketBase.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_DATABUCKETBASE_H +#define SGTOOLS_DATABUCKETBASE_H + +/** @class DataBucketBase + * @brief A non-templated base class for DataBucket, allows to access the + * transient object address as a void* + * @author ATLAS Collaboration + * $Id: DataBucketBase.h,v 1.7 2008-05-30 22:58:46 calaf Exp $ + **/ + + +#include "GaudiKernel/DataObject.h" +#include <typeinfo> + +namespace SG { + class IRegisterTransient; +} + +class DataBucketBase : public DataObject +{ + + public: + + DataBucketBase() { }; + virtual ~DataBucketBase() { }; + virtual void* object() = 0; + + /** + * @brief Return the @c type_info for the stored object. + */ + virtual const std::type_info& tinfo() const = 0; + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type @a T. Note that only + * derived->base conversions are allowed here. + * @a T must have a valid Class ID for this to work. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + template <class T> T* cast (SG::IRegisterTransient* irt = 0, + bool isConst = true) const; + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a clid. Note that only + * derived->base conversions are allowed here. + * @param clid The class ID to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + virtual void* cast (CLID clid, + SG::IRegisterTransient* irt = 0, + bool isConst = true) const = 0; + + /** + * @brief Return the contents of the @c DataBucket, + * converted to type given by @a std::type_info. Note that only + * derived->base conversions are allowed here. + * @param clid The @a std::type_info of the type to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ + virtual void* cast (const std::type_info& tinfo, + SG::IRegisterTransient* irt = 0, + bool isConst = true) const = 0; + + /** + * @brief Return a new @c DataBucket whose payload has been cloned from the + * original one. + */ + virtual DataBucketBase* clone() const = 0; + + /** + * @brief Give up ownership of the @c DataBucket contents. + * This leaks the contents and it is useful mainly for error handling. + */ + virtual void relinquish() = 0; + + /** + * If the held object derives from @c ILockable, call @lock() on it. + */ + virtual void lock() = 0; +}; + + +#include "SGTools/DataBucketBase.icc" + + +#endif + diff --git a/EDM/athena/Control/SGTools/SGTools/DataBucketBase.icc b/EDM/athena/Control/SGTools/SGTools/DataBucketBase.icc new file mode 100644 index 00000000..38f59c4d --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataBucketBase.icc @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataBucketBase.icc,v 1.3 2008-04-08 16:05:32 ssnyder Exp $ +/** + * @file SGTools/DataBucketBase.icc + * @author scott snyder + * @date Nov 2005 + * @brief A non-templated base class for DataBucket, allows to access the + * transient object address as a void* + * Implementation file. + */ + +#include "SGTools/ClassID_traits.h" +#include "boost/type_traits/remove_const.hpp" +#include <typeinfo> + + +/** + * @brief Return the contents of the @c DataBucket, + * converted to type @a T. Note that only + * derived->base conversions are allowed here. + * @a T must have a valid Class ID for this to work. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + */ +template <class T> +T* DataBucketBase::cast (SG::IRegisterTransient* irt /*= 0*/, + bool isConst /*= true*/) const +{ + return reinterpret_cast<T*> + (cast (typeid (typename boost::remove_const<T>::type), irt, isConst)); +} + diff --git a/EDM/athena/Control/SGTools/SGTools/DataBucketTraitFwd.h b/EDM/athena/Control/SGTools/SGTools/DataBucketTraitFwd.h new file mode 100644 index 00000000..8a182bc3 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataBucketTraitFwd.h @@ -0,0 +1,36 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: DataBucketTraitFwd.h,v 1.2 2008-04-08 16:05:32 ssnyder Exp $ + +/** + * @file SGTools/DataBucketTrait.h + * @author scott snyder + * @date Mar, 2008 + * @brief Forward declaration of DataBucketTrait template. + */ + + +#ifndef SGTOOLS_DATABUCKETTRAITFWD_H +#define SGTOOLS_DATABUCKETTRAITFWD_H + + +namespace SG { + + + /** + * @brief Metafunction to find the proper @c DataBucket class for @c T. + * + * See in Storable_conversions.h for full documentation. + */ + template <class T, class U = T> + struct DataBucketTrait; + + +} // namespace SG + + +#endif // not SGTOOLS_DATABUCKETTRAITFWD_H diff --git a/EDM/athena/Control/SGTools/SGTools/DataHandleBase.h b/EDM/athena/Control/SGTools/SGTools/DataHandleBase.h new file mode 100644 index 00000000..35bd0eb7 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataHandleBase.h @@ -0,0 +1,127 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// DataHandleBase.h +// Header file for class DataHandleBase +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef SGTOOLS_DATAHANDLEBASE_H +#define SGTOOLS_DATAHANDLEBASE_H 1 + +// STL includes +#include <string> + +// fwk includes +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IResetable.h" + +// SGTools includes +#include "SGTools/DataProxy.h" +#include "SGTools/ProxyMap.h" + +// Forward declaration + + +/** + * @class DataHandleBase + * @brief an iterator over instances of a given type in an @c IProxyDict (such + * as StoreGateSvc). It d-casts and caches locally the pointed-at object, to + * speed-up subsequent accesses. + * It can be reset by the store for asynchronous updates (IOVSvc) + */ +class DataHandleBase : public IResetable +{ + + /////////////////////////////////////////////////////////////////// + // Public typedefs: + /////////////////////////////////////////////////////////////////// +public: + typedef std::string ID_type; + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + /// Default constructor: + DataHandleBase(); + + /// Copy constructor: + DataHandleBase( const DataHandleBase& rhs ); + + /// Assignment operator: + DataHandleBase& operator=( const DataHandleBase& rhs ); + + /// Constructor with parameters: + + DataHandleBase(SG::DataProxy* proxy); ///< + DataHandleBase(const SG::ConstProxyIterator& itr1, + const SG::ConstProxyIterator& itr2); + + /// Destructor: + virtual ~DataHandleBase(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /// \name validity checks + //@{ + bool isConst() const; + bool isInitialized() const; ///<weaker test but it does not touch the disk! + bool isSet() const { return isInitialized(); } + //@} + + /// Get the key string with which the current object was stored. + const std::string& key() const; + + StatusCode setState(SG::DataProxy* proxy) const; + StatusCode setState(IProxyDict* store, const ID_type& name) const; + + // Note: itr1 may be modified! + StatusCode setState(SG::ConstProxyIterator& itr1, + const SG::ConstProxyIterator& itr2) const; + + /// the CLID of the object we are bound to + virtual CLID clid() const =0; + + ///get the data object key (ID) + ID_type ID() const { return isInitialized() ? m_proxy->name() : "NONE"; } + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + StatusCode setState(SG::DataProxy* proxy); + StatusCode setState(IProxyDict* store, const ID_type& name); + + /////////////////////////////////////////////////////////////////// + // Protected data: + /////////////////////////////////////////////////////////////////// +protected: + + /// iterator pointing at the beginning of the range of proxies + mutable SG::ConstProxyIterator m_itr; + + /// iterator pointing at the end of the range of proxies + mutable SG::ConstProxyIterator m_itrEnd; + + /// the proxy holding the object we are bound to + mutable SG::DataProxy* m_proxy; + + /// use the proxy-iterator or just the proxy ? + mutable bool m_useItr; + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// +//std::ostream& operator<<( std::ostream& out, const DataHandleBase& o ); + + + +#endif //> !SGTOOLS_DATAHANDLEBASE_H diff --git a/EDM/athena/Control/SGTools/SGTools/DataProxy.h b/EDM/athena/Control/SGTools/SGTools/DataProxy.h new file mode 100644 index 00000000..f30e7acb --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataProxy.h @@ -0,0 +1,285 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_DATAPROXY_H +#define SGTOOLS_DATAPROXY_H + +// includes +#include <string> +#include <set> +#include <list> +#include <typeinfo> +#include <memory> +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ClassID.h" +#include "AthenaKernel/getMessageSvc.h" /*Athena::IMessageSvcHolder*/ +#include "SGTools/TransientAddress.h" +#include "SGTools/IRegisterTransient.h" +#include "SGTools/exceptions.h" + + +// forward declarations: +class DataObject; +class IConversionSvc; +class IResetable; +class IProxyDict; + +/** @class DataProxy + * @brief DataProxy provides the registry services for StoreGate + * @author ATLAS Collaboration + * $Id: DataProxy.h,v 1.11 2008-07-14 22:16:25 calaf Exp $ + **/ + +namespace SG { + class T2pMap; + + class DataProxy : public IRegistry, public IRegisterTransient + { + + public: + enum ErrNo {ALLOK, NOCNVSVC, NOIOA, CNVFAILED, T2PREGFAILED, NERRORS}; + //FIXME private typedef IRegistry::name_type name_type; + //FIXME private typedef IRegistry::id_type id_type; + typedef std::string name_type; + typedef std::string id_type; + typedef TransientAddress::TransientClidSet CLIDCont_t; + typedef TransientAddress::TransientAliasSet AliasCont_t; + + // Constructors + DataProxy(); // default constructor + + ///build from TransientAddress + DataProxy(TransientAddress* tAddr, + IConversionSvc* pDataLoader, + bool constFlag=false, bool resetOnly=true); + + ///build from DataObject + DataProxy(DataObject* dObject, + TransientAddress* tAddr, + bool constFlag=false, bool resetOnly=true); + + // Destructor + virtual ~DataProxy(); + + ///\name IRegistry implementation + //@{ + /// Add reference to object + virtual unsigned long addRef(); + + /// release reference to object + virtual unsigned long release(); + + /// return refCount + unsigned long refCount() const; + + /// Retrieve data object key == string + virtual const name_type& name() const { return m_tAddress->name(); } + + /// Retrieve data object key == string + /// duplicated for Gaudi folks does same as name() + virtual const id_type& identifier() const {return m_tAddress->name();} + + /// Retrieve DataObject + virtual DataObject* object() const { return m_dObject; } + + /// set an IOpaqueAddress + virtual void setAddress(IOpaqueAddress* ioa); + + /// Retrieve IOpaqueAddress + virtual IOpaqueAddress* address() const { return m_tAddress->address(); } + + /// set DataSvc (Gaudi-specific); do nothing for us + virtual IDataProviderSvc* dataSvc() const { return 0; } + //@} + + /// Retrieve TransientAddress + virtual TransientAddress* transientAddress() const { return m_tAddress; } + + /// access set of proxy aliases + const AliasCont_t& alias() const { return m_tAddress->alias(); } + + /// Other methods of DataProxy (not in Interface IRegistry): + + /// Reset DataObject, Handles and IOpaqueAddress: + /// If HARD is true, then the bound objects should also + /// clear any data that depends on the identity + /// of the current event store. (See IResetable.h.) + virtual void reset (bool hard = false); + virtual void finalReset(); ///called by destructor + + /// release or reset according to resetOnly flag + /// If FORCE is true, then always release. + /// See IResetable.h for HARD. + bool requestRelease(bool force, bool hard); + + /// am I valid? + bool isValid() const; + + /// is the address valid? + bool isValidAddress() const; + + /// is the object valid? + bool isValidObject() const; + + /// set DataObject + void setObject(DataObject* obj); + + /// Access DataObject on-demand using conversion service + ///@throws runtime_error when converter fails + DataObject* accessData(); + + /** + * @brief Read in a new copy of the object referenced by this proxy. + * @param errNo If non-null, set to the resulting error code. + * + * If this proxy has an associated loader and address, then load + * a new copy of the object and return it. Any existing copy + * held by the proxy is unaffected. + * + * This will fail if the proxy does not refer to an object read from an + * input file. + */ + std::unique_ptr<DataObject> readData (ErrNo* errNo) const; + + ErrNo errNo() const { return m_errno; } + + /// Retrieve clid + CLID clID() const { return m_tAddress->clID(); } + + /// Retrieve storage type + unsigned char svcType() const { return m_storageType; } + + /// Check if it is a const object + bool isConst() const { return m_const; } + + + /** + * @brief Mark this object as const. (Lock the object.) + * + * If the object held that derives from @c ILockable, then we also + * call @c lock on the object. + */ + void setConst(); + + + /// set the reset only flag: Clear Store will reset and not delete. + void resetOnly(const bool& flag) { m_resetFlag = flag; } + + /// Check reset only: + bool isResetOnly() const { return m_resetFlag; } + + bool bindHandle(IResetable* ir); + void unbindHandle(IResetable* ir); + + /// The following kept temporarily for backward compatibility: + const CLIDCont_t& transientID() const {return m_tAddress->transientID();} + + // cache the t2p + void setT2p(T2pMap* t2p); + + /** + * @brief Register a transient object in a t2p map. + * @param trans The object to register. + * + * (@c IRegisterTransient interface.) + */ + virtual void registerTransient (void* p); + + /// Set the store of which we're a part. + void setStore (IProxyDict* store) { m_store = store; } + + /// Return the store of which we're a part. + IProxyDict* store() const { return m_store; } + + /// reset the bound DataHandles + /// If HARD is true, then the bound objects should also + /// clear any data that depends on the identity + /// of the current event store. (See IResetable.h.) + void resetBoundHandles (bool hard); + + IConversionSvc* loader() const { return m_dataLoader; } + + private: + DataProxy(const DataProxy&); + DataProxy& operator=(const DataProxy&); + + TransientAddress* m_tAddress; + + unsigned long m_refCount; + + DataObject* m_dObject; + IConversionSvc* m_dataLoader; + + /// Is the proxy currently const? + bool m_const; + /// Was the proxy created as const? + bool m_origConst; + + unsigned char m_storageType; + + ///reset and not delete: default is true + bool m_resetFlag; + + /// list of bound DataHandles + std::list<IResetable*> m_handles; + + T2pMap* m_t2p; + Athena::IMessageSvcHolder m_ims; + + /// errno-style error code for accessData + enum ErrNo m_errno; + + /// The store of which we are a part. + IProxyDict* m_store; + + /** + * @brief Lock the data object we're holding, if any. + */ + void lock(); + }; + + ///cast the proxy into the concrete data object it proxies + //@{ + template<typename DATA> + DATA* DataProxy_cast(DataProxy* proxy); + + ///const pointer version of the cast + template<typename DATA> + const DATA* DataProxy_cast(const DataProxy* proxy) + { + return DataProxy_cast<DATA>(const_cast<DataProxy*>(proxy)); + } + + ///const ref version of the cast. @throws SG::ExcBadDataProxyCast. + template<typename DATA> + DATA DataProxy_cast(const DataProxy& proxy) + { + const DATA* result = DataProxy_cast<DATA>(&proxy); + if (!result) SG::throwExcBadDataProxyCast(proxy.clID(), typeid(DATA)); + return *result; + } + + /** + * @brief Try to get the pointer back from a @a DataProxy, + * converted to be of type @a clid. + * @param proxy The @a DataProxy. + * @param clid The ID of the class to which to convert. + * + * Only works if the held object is a @a DataBucket. + * Returns 0 on failure, + */ + void* DataProxy_cast(DataProxy* proxy, CLID clid); + //@} + +} //end namespace SG + +#include "SGTools/DataProxy.icc" + +#endif // SGTOOLS_DATAPROXY + + + + diff --git a/EDM/athena/Control/SGTools/SGTools/DataProxy.icc b/EDM/athena/Control/SGTools/SGTools/DataProxy.icc new file mode 100644 index 00000000..df4505d8 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataProxy.icc @@ -0,0 +1,98 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + implementation of DataProxy_cast operator + ----------------------------------------- + ATLAS Collaboration +***************************************************************************/ + +// $Id: DataProxy.icc,v 1.6 2008-07-14 22:16:25 calaf Exp $ + +//<<<<<< INCLUDES >>>>>> +#include "SGTools/DataBucketBase.h" +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" +#ifndef NDEBUG +# include "AthenaKernel/getMessageSvc.h" +# include "GaudiKernel/MsgStream.h" +#endif + + +class DataObject; + +template <typename DATA> +DATA* SG::DataProxy_cast(SG::DataProxy* proxy) { + DATA* result(0); + + if (0 != proxy && proxy->isValid()) { + DataObject* pObject(proxy->accessData()); + + if (0 != pObject) { + const CLID& dataID(ClassID_traits<DATA>::ID()); + result = SG::Storable_cast<DATA>(pObject, true, proxy, proxy->isConst()); + if (0 == result) { + //if result is 0, probably DATA is neither the type the object was + // stored with, nor it inherits from it. + // Before giving up let's check its transient CLIDs + DataBucketBase* db(0); + if (proxy->transientAddress()->transientID(dataID) && + 0 != (db = dynamic_cast<DataBucketBase*>(pObject)) ) + { + //it is a symlink after all. Let's hard cast and keep our fingers Xed + // But first: if this is a non-const proxy, then the cast + // may have failed because it needed to go via a copying conversion + // that's not allowed for non-const objects. So try the conversion + // again as const; if that works, then don't do the hard cast. + if (!proxy->isConst() && + SG::Storable_cast<DATA>(pObject, true, proxy, true) != 0) + { +#ifndef NDEBUG + MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast"); + gLog << MSG::WARNING + << "Request for a non-const object via copying conversion; " + << "requested CLID = " << dataID + << ", proxy primary ID is " << proxy->clID() << endmsg ; +#endif + } + else { + // ok, hard cast. + result = static_cast<DATA*>(db->object()); + } + } + else { +#ifndef NDEBUG + MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast"); + gLog << MSG::WARNING + << "Request for an invalid object; requested CLID = " + << dataID + << ", proxy primary ID is " << proxy->clID() << endmsg ; +#endif + } //try symlink + } //result 0 + } else { // invalid pObject +#ifndef NDEBUG + MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast"); + gLog << MSG::WARNING + << "this proxy " << MSG::hex << proxy + << MSG::dec << " has a NULL data object ptr" << endmsg; +#endif + } + } else {// invalid proxy +#if 0 +#ifndef NDEBUG + MsgStream gLog(Athena::getMessageSvc(), "SG::DataProxy_cast"); + gLog << MSG::WARNING + << "this proxy " << MSG::hex << proxy + << MSG::dec << " [" << proxy->clID() << "/" << proxy->name() + << "] is in an invalid state" << endmsg; +#endif +#endif + } + return result; +} + + diff --git a/EDM/athena/Control/SGTools/SGTools/DataStore.h b/EDM/athena/Control/SGTools/SGTools/DataStore.h new file mode 100644 index 00000000..c28410a2 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/DataStore.h @@ -0,0 +1,218 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_DATASTORE_H +#define STOREGATE_DATASTORE_H +/** The Transient Store + * + * \author ATLAS Collaboration + **/ + + +#include "SGTools/ProxyMap.h" +#include "SGTools/T2pMap.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/DefaultKey.h" +#include "AthenaKernel/IProxyRegistry.h" +#include "CxxUtils/unordered_map.h" +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/StatusCode.h" +#include <boost/array.hpp> +#include <boost/type_traits/transform_traits.hpp> +#include <exception> +#include <list> +#include <vector> +#include <map> +#include <string> +#include <typeinfo> /*typeid*/ +#include <utility> /*std::pair*/ + + +class ISvcLocator; +class ISGAudSvc; +class MsgStream; +class IPageAccessControlSvc; + +namespace SG { + + class DataProxy; + + + /** + * @brief Hold DataProxy instances associated with a store. + * + * We have two ways of looking up a proxy. + * + * First, the proxy is stored by CLID/key in m_storeMap. This is a map + * indexed by CLID; the values are maps indexed by key. + * + * Second, m_keyMap stores proxies indexed by the hashed CLID/key. + * + * A proxy may be entered multiple times in the maps if there are + * symlinks or aliases. + * + * A proxy may be given to the store that has the hashed key set, + * but not the CLID/key. This is referred to as a `dummy' proxy. + * This can happen when we read a link to an object that's not + * described in the event's DataHeader. In this case, the proxy + * is entered only in the second map, m_keyMap. If we later look + * for a proxy by CLID/key and don't find it, we also look in m_keyMap + * to see if a dummy proxy has been entered there. If so, that point + * we fill in the CLID/key fields of the proxy and also enter + * it in m_storeMap. + */ + class DataStore : virtual public IProxyRegistry + { + + public: + + typedef IStringPool::sgkey_t sgkey_t; + typedef std::map<CLID, SG::ProxyMap> StoreMap; + typedef StoreMap::iterator StoreIterator; + typedef StoreMap::const_iterator ConstStoreIterator; + + typedef std::pair<SG::ConstProxyIterator, SG::ConstProxyIterator> constProxyRange; + + /** + * @brief Constructor. + * @param pool The string pool associated with this store. + */ + DataStore (IProxyDict& pool); + virtual ~DataStore(); + + void setStoreID(StoreID::type id) { m_storeID = id;} + virtual StoreID::type storeID() const { return m_storeID; } + + // If FORCE is true, then force deleting of all proxies, + // even if they would normally only be reset. + /// If HARD is true, then the bound objects should also + /// clear any data that depends on the identity + /// of the current event store. (See IResetable.h.) + void clearStore(bool force, bool hard, MsgStream* pmlog); + + ////////////////////////////////////////////////////////////////// + /// \name Implementation of IProxyRegistry. + //@{ + virtual StatusCode addToStore(const CLID& id, DataProxy* proxy); + /// return proxy for a given type/key pair + /// if key is empty returns the default proxy (currently last registered) + virtual DataProxy* proxy(const TransientAddress* tAddr) const; + //@} + virtual DataProxy* proxy(const CLID& id, + const std::string& key=SG::DEFAULTKEY) const; + + /// get proxy with given key. Returns 0 to flag failure + /// the key must match exactly (no wild carding for the default key) + SG::DataProxy* proxy_exact (sgkey_t sgkey) const; + + /// get proxy with given id. Returns 0 to flag failure + /// the key must match exactly (no wild carding for the default key) + virtual SG::DataProxy* proxy_exact(const CLID& id, + const std::string& key) const; + + /// remove proxy from store, unless proxy is reset only. + /// @param forceRemove remove the proxy no matter what + /// If HARD is true, then the bound objects should also + /// clear any data that depends on the identity + /// of the current event store. (See IResetable.h.) + StatusCode removeProxy(DataProxy* proxy, bool forceRemove, bool hard); + + /// add symlink to store: + StatusCode addSymLink(const CLID& linkid, DataProxy* proxy); + + /// add alias to store + StatusCode addAlias(const std::string& aliasKey, DataProxy* proxy); + + /// Count number of object of a given type in store + int typeCount(const CLID& id) const; + + /// Return an iterator over the StoreMap: + StatusCode tRange(ConstStoreIterator& f, ConstStoreIterator& e) const; + + /// Return an iterator over proxy for a given CLID: + StatusCode pRange(const CLID& id, SG::ConstProxyIterator& f, + SG::ConstProxyIterator& e) const; + + /// Return a list of all valid proxies in the store: + StatusCode proxyList(std::list<DataProxy*>& pList) const; + + + /// set IPageAccessControlSvc ptr in T2PMap + void setPac(IPageAccessControlSvc* pac) { m_t2p.setPac(pac); } + /// request an access control report, i.e. a list of proxies that have not been accessed since monitored + std::vector<DataProxy*> pacReport() const { return m_t2p.pacReport();} + + /// methods to query the T2PMap: + StatusCode t2pRegister(const void* const pTrans, DataProxy* const pPers); + void t2pRemove(const void* const pTrans); + + /// locate the persistent (proxy) for a given T* (void*): + DataProxy* locatePersistent(const void* const pTransient) const; + + // return list of keys associated with an object + void keys(const CLID& id, std::vector<std::string>& vkeys, + bool includeAlias, bool onlyValid); + + private: + + /// The string pool associated with this store. + IProxyDict& m_pool; + + StoreMap m_storeMap; + + /// Map of hashed sgkey -> DataProxy. + typedef SG::unordered_map<sgkey_t, DataProxy*> KeyMap_t; + KeyMap_t m_keyMap; + + StoreID::type m_storeID; + + // Map to hold the relation between transient and persistent object: + // we have changed to DataProxy as it is faster while recording + // to check if it already exists + T2pMap m_t2p; + + void setSGAudSvc() const; + mutable ISGAudSvc * m_pSGAudSvc; + mutable bool m_noAudSvc; + inline bool doAudit() const { + if (!m_noAudSvc) setSGAudSvc(); + return (m_pSGAudSvc); + } + + ISvcLocator* m_pSvcLoc; + StatusCode setSvcLoc(); + + + /** + * @brief Look for (and convert) a matching dummy proxy. + * @param id The CLID for which to search. + * @param key The key for which to search. + * + * In some cases, we may enter into the store a `dummy' proxy, + * which is identified only by the hashed CLID/key pair. + * (This can happen when we have a link to an object that's not + * listed in the DataHeader; in this case, we know the only hashed key + * and not the CLID or key.) + * + * This function is called after we fail to find a proxy by CLID/key. + * It additionally checks to see if there exists a dummy proxy with + * a hash matching this CLID/key. If so, the CLID/key are filled + * in in the proxy, and the proxy is entered in m_storeMap. + * + * Returns either the matching proxy or 0. + */ + DataProxy* findDummy (CLID id, const std::string& key); + }; + ////////////////////////////////////////////////////////////////// + inline void + DataStore::t2pRemove(const void* const pTrans) + { + m_t2p.t2pRemove(pTrans); + } + ////////////////////////////////////////////////////////////////// +} //end namespace SG + + +#endif // STOREGATE_DATASTORE + diff --git a/EDM/athena/Control/SGTools/SGTools/IProxyDictWithPool.h b/EDM/athena/Control/SGTools/SGTools/IProxyDictWithPool.h new file mode 100644 index 00000000..fa8cc7ff --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/IProxyDictWithPool.h @@ -0,0 +1,29 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IProxyDictWithPool.h,v 1.2 2008-04-18 03:18:24 ssnyder Exp $ +/** + * @file SGTools/IProxyDictWithPool.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2007 + * @brief Combine IProxyDict and IStringPool. + * + * Make a class that combines @c IProxyDict and @c IStringPool, + * so we can use both through a single pointer without having + * to dynamic_cast between them. + */ + + +#ifndef SGTOOLS_IPROXYDICTWITHPOOL_H +#define SGTOOLS_IPROXYDICTWITHPOOL_H + + +// Now everything's in IProxyDict. +#include "AthenaKernel/IProxyDict.h" +typedef IProxyDict IProxyDictWithPool; + + +#endif // not SGTOOLS_IPROXYDICTWITHPOOL_H diff --git a/EDM/athena/Control/SGTools/SGTools/IRegisterTransient.h b/EDM/athena/Control/SGTools/SGTools/IRegisterTransient.h new file mode 100644 index 00000000..a503640e --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/IRegisterTransient.h @@ -0,0 +1,47 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IRegisterTransient.h,v 1.2 2008-04-08 16:05:32 ssnyder Exp $ + +/** + * @file SGTools/IRegisterTransient.h + * @author scott snyder + * @date Mar, 2008 + * @brief Interface for registering a transient object in t2p map. + */ + + +#ifndef SGTOOLS_IREGISTERTRANSIENT +#define SGTOOLS_IREGISTERTRANSIENT + + +namespace SG { + + +/** + * @brief Interface for registering a transient object in t2p map. + * + * (See @c T2pMap.) + */ +class IRegisterTransient +{ +public: + /// Destructor. + virtual ~IRegisterTransient() {} + + + /** + * @brief Register a transient object in a t2p map. + * @param trans The object to register. + */ + virtual void registerTransient (void* trans) = 0; +}; + + +} // namespace SG + + +#endif // not SGTOOLS_IREGISTERTRANSIENT diff --git a/EDM/athena/Control/SGTools/SGTools/IStringPool.h b/EDM/athena/Control/SGTools/SGTools/IStringPool.h new file mode 100644 index 00000000..845ec3c5 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/IStringPool.h @@ -0,0 +1,23 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IStringPool.h,v 1.3 2008-09-03 17:19:10 ssnyder Exp $ +/** + * @file SGTools/IStringPool.h + * @author scott snyder <snyder@bnl.gov> + * @date Mar, 2007 + * @brief Abstract interface for looking up strings/CLIDs in a pool. + */ + + +#ifndef SGTOOLS_ISTRINGPOOL_H +#define SGTOOLS_ISTRINGPOOL_H + + +#include "AthenaKernel/IStringPool.h" + + +#endif // not SGTOOLS_ISTRINGPOOL_H diff --git a/EDM/athena/Control/SGTools/SGTools/ProxyMap.h b/EDM/athena/Control/SGTools/SGTools/ProxyMap.h new file mode 100644 index 00000000..08808465 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/ProxyMap.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + the DataStore proxy map + ---------------------------- + ATLAS Collaboration + ***************************************************************************/ + +// $Id: ProxyMap.h,v 1.2 2003-04-16 01:49:26 calaf Exp $ + +#ifndef SGTOOLS_PROXYMAP_H +#define SGTOOLS_PROXYMAP_H + +#ifndef _CPP_MAP + #include <map> +#endif +#ifndef _CPP_STRING + #include <string> +#endif + +namespace SG { + class DataProxy; + + typedef std::map<std::string, DataProxy*> ProxyMap; + typedef ProxyMap::iterator ProxyIterator; + typedef ProxyMap::const_iterator ConstProxyIterator; +} + +#endif // TOOLS_PROXYMAP_H diff --git a/EDM/athena/Control/SGTools/SGTools/SGFolderItem.h b/EDM/athena/Control/SGTools/SGTools/SGFolderItem.h new file mode 100644 index 00000000..d704f5bd --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/SGFolderItem.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file SGFolderItem.h + * defines a class representing a folder item (data object clid/key) + */ +#ifndef SGTOOLS_FOLDERITEM_H +#define SGTOOLS_FOLDERITEM_H +#include <string> +#include "GaudiKernel/ClassID.h" +namespace SG { + /** @class SG::FolderItem + * @brief a Folder item (data object) is identified by the clid/key pair + * + * If the @c exact flag is set, then the request is to write the object + * as exactly that class, not as any derived class. + * + * @author pcalafiura@lbl.gov - ATLAS Collaboration + * $Id: SGFolderItem.h,v 1.2 2008-03-26 22:36:54 calaf Exp $ + **/ + class FolderItem { + public: + FolderItem(CLID id=CLID_NULL, + const std::string& key="", + bool exact = false) + : m_id(id), m_key(key), m_exact(exact) {} + CLID id() const { return m_id; } + const std::string& key() const { return m_key; } + bool operator < (const FolderItem& rhs) const { + return ( id() < rhs.id() || + ( (id() == rhs.id()) && key() < rhs.key()) ); + } + bool isFolder() const; + bool exact() const { return m_exact; } + private: + CLID m_id; + std::string m_key; + bool m_exact; + }; +} //ns SG + +#endif diff --git a/EDM/athena/Control/SGTools/SGTools/SGIFolder.h b/EDM/athena/Control/SGTools/SGTools/SGIFolder.h new file mode 100644 index 00000000..0500513d --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/SGIFolder.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_IFOLDER_H +#define SGTOOLS_IFOLDER_H + +#include <set> +#include <string> + +#ifndef GAUDIKERNEL_IALGTOOL_H + #include "GaudiKernel/IAlgTool.h" +#endif + +#include "SGTools/SGFolderItem.h" + +namespace SG { + /** @class SG::IFolder + * @brief a run-time configurable list of data objects + * + * @author pcalafiura@lbl.gov - ATLAS Collaboration + * $Id: SGIFolder.h,v 1.3 2008-04-24 00:55:21 calaf Exp $ + **/ + class IFolder : public virtual IAlgTool + { + public: + /// the list we manage + typedef std::set<FolderItem> ItemList; //FIXME would be nice to move to SG::Folder + + /// \name access the ItemList + //@{ + typedef ItemList::const_iterator const_iterator; + virtual const_iterator begin() const = 0; + virtual const_iterator end() const = 0; + //@} + ///add a data object identifier to the list + virtual StatusCode add(const std::string& typeName, const std::string& skey) = 0; + ///add a data object identifier to the list + virtual StatusCode add(const CLID& clid, const std::string& skey) = 0; + + ///clear the folder contents + virtual void clear() = 0; + + ///update list of items + virtual void updateItemList(bool checkValidCLID) = 0; + + + static const InterfaceID& interfaceID() { + static const InterfaceID IID( "SG::IFolder", 1, 0 ); + return IID; + } + }; +} //ns SG + +#endif diff --git a/EDM/athena/Control/SGTools/SGTools/SGToolsDict.h b/EDM/athena/Control/SGTools/SGTools/SGToolsDict.h new file mode 100644 index 00000000..7434a922 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/SGToolsDict.h @@ -0,0 +1,25 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_SGTOOLSDICT_H +#define SGTOOLS_SGTOOLSDICT_H + +#include <vector> +#include "SGTools/DataBucket.h" +#include "SGTools/DataProxy.h" +#include "SGTools/BaseInfo.h" +#include "SGTools/CurrentEventStore.h" + +// Need to instantiate iterators +namespace SGToolsDict +{ + struct _tmp { + std::vector< SG::DataProxy*> m_sg_data_proxies; + std::vector<const SG::DataProxy*> m_const_sg_data_proxies; + }; +} + +#endif // not SGTOOLS_SGTOOLSDICT_H diff --git a/EDM/athena/Control/SGTools/SGTools/SGVersionedKey.h b/EDM/athena/Control/SGTools/SGTools/SGVersionedKey.h new file mode 100644 index 00000000..be0d1828 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/SGVersionedKey.h @@ -0,0 +1,121 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file SGVersionedKey.h + * defines a StoreGateSvc key with a version number + */ +#ifndef SGTOOLS_VERSIONEDKEY_H +#define SGTOOLS_VERSIONEDKEY_H 1 +#include <iostream> +#include <string> +class StoreGateSvc; //our friend +class SGImplSvc; //our friend +namespace SG { + template <class T> class ObjectWithVersion; + + /** @class SG::VersionedKey + * @brief a StoreGateSvc key with a version number. + * Notice that StoreGate does not order multiple instances of an object with + * a given key by version number. A generic retrieve will always return + * the first version recorded. For example, if object ("MyKey",1) is recorded + * _before__ ("MyKey", 2) a sg.retrieve(pObj,"MyKey") will return ("MyKey",1). + * StoreGateSvc provides retrieveAllVersions and retrieveHighestVersion, + * which offer a better-defined behaviour. + * + * @author pcalafiura@lbl.gov - ATLAS Collaboration + * $Id: SGVersionedKey.h,v 1.4 2008-07-10 15:51:04 dquarrie Exp $ + **/ + class VersionedKey { + friend class ::StoreGateSvc; //call copyVK +#ifdef ATHENAHIVE + friend class ::SGImplSvc; //call copyVK +#endif + public: + ///quickly determine whether a string has the right format to be a VK + static bool isVersionedKey(const char *); + ///quickly determine whether a string has the right format to be a VK + static bool isVersionedKey(const std::string&); + + ///quickly determine whether a string has the right format to be a VK + ///with auto-generated version # + static bool isAuto(const std::string&); + + /// version must be [0,98], 0 is the default version + VersionedKey(const char* key, unsigned char version); + /// version must be [0,98], 0 is the default version + VersionedKey(const std::string& key, unsigned char version); + + /// make a VersionedKey from vkey string. If vkey has the + /// VersionedKey format (;NN;key), it is simply copied, otherwise + /// it is taken to be the real key, and default version is assigned + explicit VersionedKey(const char* vkey); + /// make a VersionedKey from vkey string. If vkey has the + /// VersionedKey format (;NN;key), it is simply copied, otherwise + /// it is taken to be the real key, and default version is assigned + explicit VersionedKey(const std::string& vkey); + + VersionedKey(const VersionedKey& rhs); + + //no assignment + VersionedKey& operator= (const VersionedKey&) = delete; + + ~VersionedKey(); + + /// sets outKey to point to base key, and version to encoded version (0 is taken to mean default version). + void decode(std::string& outKey, unsigned char& version) const; + operator std::string() const { return m_versionKey; } + /// @returns version number + unsigned char version() const; + /// @returns base key + const std::string& key() const; + /// @returns access underlying encoded m_versionKey C string + const std::string& rawVersionKey() const { + return m_versionKey; + } + /// compare base keys + bool sameKey(const VersionedKey& vkey) const; + /// compare base keys + bool sameKey(const std::string& baseKey) const; + /// compare base keys + bool sameKey(const char* baseKey) const; + bool isAuto() const { return version() == VersionedKey::autoV(); } + + private: + template <class U> friend class ObjectWithVersion; + /// default constructor (invalid state, do not use) + VersionedKey(): m_versionKey() {} + + void encode(const std::string& inKey, unsigned char version); + void copyVK(const std::string& inKey); + + static char separator() {return ';';} + static const char* versionFormatString() {return ";%02u;";} + static const char* formatString() {return ";%02u;%s";} + + static unsigned char autoV() { return 99;} + static unsigned char defaultV() { return 0;} + static const char* autoVS() { return "_99_"; } + static const char* defaultVS() { return "_00_"; } + + ///the encoded version/key. Mutable so that ownership can be transferred + ///in the copy constructor + std::string m_versionKey; + mutable std::string m_baseKey; + }; +} // ns SG + +/// sort according to highest key version +bool operator < (const SG::VersionedKey& lhs, const SG::VersionedKey& rhs); + +namespace SG { + inline + std::ostream& operator <<(std::ostream& ost, const SG::VersionedKey& k) { + return ost << k.rawVersionKey(); + // return ost.write(k.rawVersionKey(), strlen(k.rawVersionKey())); + } +} + +#endif diff --git a/EDM/athena/Control/SGTools/SGTools/StlMapClids.h b/EDM/athena/Control/SGTools/SGTools/StlMapClids.h new file mode 100644 index 00000000..30fdadbf --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/StlMapClids.h @@ -0,0 +1,39 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// StlMapClids.h +// Header file for CLIDs for various std::map<T,U> +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef SGTOOLS_STLMAPCLIDS_H +#define SGTOOLS_STLMAPCLIDS_H + +// STL includes +#include <map> +#include <string> +#include <vector> + +// Gaudi includes + +// SGTools includes +#include "SGTools/CLASS_DEF.h" + +CLASS_DEF2( std::map<int,int> , 103402598 , 1 ) +CLASS_DEF2( std::map<int,float> , 256222847 , 1 ) +CLASS_DEF2( std::map<int,double> , 235483215 , 1 ) + +CLASS_DEF2( std::map<std::string,int> , 170542827 , 1 ) +CLASS_DEF2( std::map<std::string,unsigned int> , 113556225 , 1 ) +CLASS_DEF2( std::map<std::string,float> , 193758082 , 1 ) +CLASS_DEF2( std::map<std::string,double> , 252602412 , 1 ) +CLASS_DEF2( std::map<std::string,std::string> , 143489258 , 1 ) + +CLASS_DEF2( std::map<std::string,std::vector<int> > , 181049313 , 1 ) +CLASS_DEF2( std::map<std::string,std::vector<unsigned int> > , 199376827 , 1 ) +CLASS_DEF2( std::map<std::string,std::vector<float> > , 259112316 , 1 ) +CLASS_DEF2( std::map<std::string,std::vector<double> > , 78422682 , 1 ) + +#endif // !SGTOOLS_STLMAPCLIDS_H diff --git a/EDM/athena/Control/SGTools/SGTools/StlVectorClids.h b/EDM/athena/Control/SGTools/SGTools/StlVectorClids.h new file mode 100644 index 00000000..80723381 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/StlVectorClids.h @@ -0,0 +1,53 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// StlVectorClids.h +// Header file for CLIDs for various std::vector<T> +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef SGTOOLS_STLVECTORCLIDS_H +#define SGTOOLS_STLVECTORCLIDS_H + +// STL includes +#include <vector> +#include <string> +#include <stdint.h> + +// Gaudi includes + +// SGTools includes +#include "SGTools/CLASS_DEF.h" + +CLASS_DEF( std::vector<bool> , 45822813 , 1 ) +CLASS_DEF( std::vector<short> , 35706084 , 1 ) +CLASS_DEF( std::vector<int> , 22592129 , 1 ) +CLASS_DEF( std::vector<long> , 6675975 , 1 ) +CLASS_DEF( std::vector<float> , 202242136 , 1 ) +CLASS_DEF( std::vector<double> , 219400222 , 1 ) +CLASS_DEF( std::vector<std::string> , 25884436 , 1 ) +CLASS_DEF( std::vector<char> , 206378829 , 1 ) + +CLASS_DEF( std::vector<unsigned short> , 238793770 , 1 ) +CLASS_DEF( std::vector<unsigned int> , 177480351 , 1 ) +CLASS_DEF( std::vector<unsigned long> , 18868981 , 1 ) +CLASS_DEF( std::vector<unsigned long long> , 35119468 , 1 ) + +CLASS_DEF( std::vector<std::vector<char> > , 70698075 , 1 ) +CLASS_DEF( std::vector<std::vector<short> > , 24204906 , 1 ) +CLASS_DEF( std::vector<std::vector<int> > , 23262399 , 1 ) +CLASS_DEF( std::vector<std::vector<uint8_t> > , 126048273 , 1 ) +CLASS_DEF( std::vector<std::vector<unsigned short> > , 247252788 , 1 ) +CLASS_DEF( std::vector<std::vector<unsigned int> > , 213985193 , 1 ) +CLASS_DEF( std::vector<std::vector<unsigned long> > , 205717523 , 1 ) +CLASS_DEF( std::vector<std::vector<unsigned long long> > , 76977490 , 1 ) +CLASS_DEF( std::vector<std::vector<float> > , 258753314 , 1 ) +CLASS_DEF( std::vector<std::vector<double> > , 154043868 , 1 ) +CLASS_DEF( std::vector<std::vector<std::string> > , 101141770 , 1 ) + +CLASS_DEF( std::vector<std::vector<std::vector<int> > > , 85220325 , 1 ) +CLASS_DEF( std::vector<std::vector<std::vector<float> > > , 82469196 , 1 ) + +#endif // !SGTOOLS_STLVECTORCLIDS_H diff --git a/EDM/athena/Control/SGTools/SGTools/StorableConversions.h b/EDM/athena/Control/SGTools/SGTools/StorableConversions.h new file mode 100644 index 00000000..7560a638 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/StorableConversions.h @@ -0,0 +1,267 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_STORABLECONVERSIONS_H +# define SGTOOLS_STORABLECONVERSIONS_H +/** @file StorableConversions.h + * @brief convert to and from a SG storable + * $Id: StorableConversions.h,v 1.13 2008-05-22 22:54:12 calaf Exp $ + * @author ATLAS Collaboration + **/ + +//<<<<<< INCLUDES >>>>>> +#include "SGTools/DataBucket.h" +#include "SGTools/ClassID_traits.h" +#include "SGTools/DataBucketTraitFwd.h" +#include "AthenaKernel/tools/type_tools.h" +#include "AthenaKernel/DataObjectSharedPtr.h" +#include "GaudiKernel/DataObject.h" + +#ifndef NDEBUG +# include "AthenaKernel/getMessageSvc.h" +# include "GaudiKernel/MsgStream.h" +#endif + +#include "boost/type_traits/is_same.hpp" +#include "boost/mpl/identity.hpp" +#include "boost/mpl/eval_if.hpp" +#include <memory> + +// +//<<<<<< FORWARD DECLARATIONS >>>>>> + +//<<<<<< FUNCTION DECLARATIONS >>>>>> +namespace SG { + + // put a dobj pointer in a bucket as appropriate + template <typename T> + DataObject* asStorable(T* pObject); + + // get a dobj pointer from a bucket as appropriate + template <typename T> + bool fromStorable(DataObject* pDObj, T*& pTrans, bool quiet=false, + IRegisterTransient* irt = 0, + bool isConst = true); + + template <typename T> + T* Storable_cast(DataObject* pDObj, bool quiet=true, + IRegisterTransient* irt = 0, + bool isConst = true) { + T* result; + return fromStorable(pDObj, result, quiet, irt, isConst) ? result : 0; + } + template <typename T> + const T* Storable_cast(const DataObject* pDObj, bool quiet=true, + IRegisterTransient* irt = 0, + bool isConst = true) { + return Storable_cast<T>(const_cast<DataObject*>(pDObj), quiet, irt, isConst); + } + + class bad_Storable_cast : public std::bad_cast {}; + template<typename T> + T& Storable_cast(const DataObject& dObj, bool quiet=true, + IRegisterTransient* irt = 0, + bool isConst = true) + { + T* result(0); + if (!fromStorable(const_cast<DataObject*>(&dObj), + result, quiet, irt, isConst)) throw bad_Storable_cast(); + return *(const_cast<T*>(result)); + } + + + /** + * @brief Try to get the pointer back from a @a DataObject, + * converted to be of type @a clid. + * @param pDObj The @a DataObject. + * @param clid The ID of the class to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + * + * Only works if the @a DataObject is a @a DataBucket. + * Returns 0 on failure, + */ + void* fromStorable(DataObject* pDObj, CLID clid, + IRegisterTransient* irt = 0, + bool isConst = true); + + + /** + * @brief Try to get the pointer back from a @a DataObject, + * converted to be of type @a clid. + * @param pDObj The @a DataObject. + * @param clid The ID of the class to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + * + * Only works if the @a DataObject is a @a DataBucket. + * Returns 0 on failure, + */ + void* Storable_cast(DataObject* pDObj, CLID clid, + IRegisterTransient* irt = 0, + bool isConst = true); + + /** + * @brief Try to get the pointer back from a @a DataObject, + * converted to be of type @a clid. + * @param pDObj The @a DataObject. + * @param clid The ID of the class to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + * + * Only works if the @a DataObject is a @a DataBucket. + * Returns 0 on failure, + */ + const void* Storable_cast(const DataObject* pDObj, CLID clid, + IRegisterTransient* irt = 0, + bool isConst = true); +} + +////////////////////////////////////////////////////////////////// +// implementation details + + +namespace SG { + + + /** + * @brief Metafunction to find the proper @c DataBucket class for @c T. + * + * Here's what we're trying to do. + * + * The default @c DataBucket class for @c T is @c SG::DataBucket\<T>. + * + * However, if @c T is a @c DataVector or @c DataList, then we want + * to use instead @c SG::DVLDataBucket\<T>. + * + * Further, if @c T derives from @c DataVector or @c DataList (as declared + * by @c SG_BASE), then we also want to use @c SG::DVLDataBucket\<T>. + * + * Further, we don't want this code to depend on @c DataVector + * or @c SG::DVLDataBucket. That behavior is enabled only + * by including the appropriate @c DataVector/@c DataList headers. + * + * So, we handle this with the following metafunction. + * (By saying that this is a `metafunction', it means that the result + * is given by the nested type @c type.) + * The @c T argument is the type we're testing, and @c U is the top-level + * type that was given to the original invocation of @c DataBucketTrait. + * If @c T has no bases (according to @c SG::Bases), we return + * @c SG::DataBucket\<U>. Otherwise, we apply ourselves recursively + * to the first base class. + * + * Other packages can then specialize this to change the behavior. + * + * We don't really try to handle multiple bases. In principle, + * we could loop over them. But it seems that that's not really needed, + * so i don't want to pull in the extra overhead unnecessarily. + * + * This class also defines a real static function init(). + * This is called from @c fromStorable. + * It can be used to force instantiation of reflection information. + */ + template <class T, class U /* = T*/> + struct DataBucketTrait + { + // The first base of @c T (or @c SG::NoBase). + typedef typename SG::BaseType<typename SG::Bases<T>::Base1>::type base1; + + // Test to see if it's valid. + typedef typename boost::is_same<base1, SG::NoBase>::type has_base; + + // This is what we'll return in the default (no base) case. + typedef boost::mpl::identity<SG::DataBucket<U> > deflt; + + // This is what we use to recursively check the base + typedef DataBucketTrait<base1, U> recurse; + + // Calculate the output. + // (Note that it's important to use @c eval_if here; otherwise, + // applying this to @c SG::NoBase won't work.) + typedef typename boost::mpl::eval_if<has_base, deflt, recurse>::type type; + + /// Initialization hook. A no-op by default. + static void init() {} + }; + + + // put a dobj pointer in a bucket as appropriate + template <typename T> + DataObject* asStorable(T* pObject) { + typedef typename DataBucketTrait<T>::type bucket_t; + return new bucket_t (pObject); + } + + template <typename T> + DataObject* asStorable(std::unique_ptr<T> pObject) { + typedef typename DataBucketTrait<T>::type bucket_t; + return new bucket_t (std::move(pObject)); + } + + template <typename T> + DataObject* asStorable(SG::DataObjectSharedPtr<T> pObject) { + typedef typename DataBucketTrait<T>::type bucket_t; + return new bucket_t (std::move(pObject)); + } + + // get a dobj pointer from a bucket as appropriate + //the DataObject must be a DataBucket<DATA>*. + + template <typename T> + bool fromStorable(DataObject* pDObj, T*& pTrans, + bool +#ifndef NDEBUG + quiet +#endif + , IRegisterTransient* irt, + bool isConst /*= true*/) + { + typedef typename DataBucketTrait<T>::type bucket_t; + DataBucketTrait<T>::init(); + + //check inputs + if (0 == pDObj) { + pTrans=0; +#ifndef NDEBUG + MsgStream gLog(Athena::getMessageSvc(), "SG::fromStorable"); + gLog << MSG::WARNING << "null input pointer " << endmsg; +#endif + return false; + } + + // get T* from DataBucket: + SG::DataBucket<T>* bucketPtr = dynamic_cast<bucket_t*>(pDObj); + bool success(0 != bucketPtr); + if (success) + pTrans = *bucketPtr; + else { + // Try to use BaseInfo information to convert pointers. + DataBucketBase* b = dynamic_cast<DataBucketBase*>(pDObj); + if (b) { + pTrans = b->template cast<T> (irt, isConst); + if (pTrans) + success = true; + } + } + +#ifndef NDEBUG + if (!quiet && !success) { + MsgStream gLog(Athena::getMessageSvc(), "SG::fromStorable"); + gLog << MSG::WARNING + << "can't convert stored DataObject " << pDObj + << " to type (" + << ClassID_traits<T>::typeName() + << ")\n Unless you are following a symlink," + << " it probably means you have a duplicate " + << "CLID = " << pDObj->clID() + << endmsg; + } +#endif + return success; + } +} + +#endif // SGTOOLS_STORABLECONVERSIONS_H diff --git a/EDM/athena/Control/SGTools/SGTools/StringPool.h b/EDM/athena/Control/SGTools/SGTools/StringPool.h new file mode 100644 index 00000000..988389f6 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/StringPool.h @@ -0,0 +1,131 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StringPool.h,v 1.4 2008-09-03 17:19:10 ssnyder Exp $ +/** + * @file SGTools/StringPool.h + * @author scott snyder + * @date Mar 2007 + * @brief Maintain a mapping of strings to 64-bit ints. + * + * We map from strings to integer keys using a hash function. + * We keep a table of hashed strings so that we can later return the string + * given the key. + * We allow registering additional key->string mappings as well, as long + * as there aren't collisions. + * We also keep an auxiliary int that gets hashed along with the string. + */ + +#ifndef SGTOOLS_STRINGPOOL_H +#define SGTOOLS_STRINGPOOL_H + +#include <stdint.h> +#include <string> +#include <memory> + +namespace SG { + +class StringPoolImpl; + +class StringPool +{ +public: + /// Type of the integer keys. + typedef uint32_t sgkey_t; + + /// Type of auxiliary data. + typedef unsigned int sgaux_t; + + /// Number of bits we'll use in the keys. + /// Leave a few spare bits in case we want to overload them for flags later. + static const int sgkey_t_nbits = 30; + static const sgkey_t sgkey_t_max = + (static_cast<sgkey_t>(1) << sgkey_t_nbits) - 1; + + /// Constructor. + StringPool(); + + /// Destructor. + ~StringPool(); + + /// Copy/move constructors. + StringPool (const StringPool& other); + StringPool (StringPool&& other); + + /// Assignment/move operators. + StringPool& operator= (const StringPool& other); + StringPool& operator= (StringPool&& other); + + /** + * @brief Find the key for a string. + * @param str The string to look up. + * @param aux Auxiliary data to include along with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ + sgkey_t stringToKey (const std::string& str, sgaux_t aux = 0); + + /** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + const std::string* keyToString (sgkey_t key) const; + + /** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @param aux[out] Auxiliary data associated with the key. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + const std::string* keyToString (sgkey_t key, sgaux_t& aux) const; + + /** + * @brief Remember an additional mapping from key to string. + * @param key The key to enter. + * @param str The string to enter. + * @param aux Auxiliary data to include along with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + */ + bool registerKey (sgkey_t key, + const std::string& str, + sgaux_t aux = 0); + + + /** + * @brief Number of registered mappings. + */ + size_t size() const; + + /** + * @brief Debugging dump. Write to cout. + */ + void dump() const; + + + /** + * @brief Empty the pool. + */ + void clear(); + +private: + std::unique_ptr<StringPoolImpl> m_impl; +}; + + +} // namespace SG + + +#endif // not SGTOOLS_STRINGPOOL_H diff --git a/EDM/athena/Control/SGTools/SGTools/T2pMap.h b/EDM/athena/Control/SGTools/SGTools/T2pMap.h new file mode 100644 index 00000000..94e95ac9 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/T2pMap.h @@ -0,0 +1,72 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_T2PMAP_H +#define SGTOOLS_T2PMAP_H + +#include "CxxUtils/unordered_map.h" +#include "SGTools/ptrhash.h" +#include <utility> +#include <vector> +#include "AthenaKernel/IPageAccessControlSvc.h" + +namespace SG { + +class DataProxy; + +class T2pMap { + + public: + + typedef SG::unordered_map<const void*, DataProxy*, ptrhash> t2p; + + // constructor + T2pMap(IPageAccessControlSvc* pac=0) : m_pac(pac) { }; + + // Destructor + ~T2pMap() { }; + + // associate a void* (T*) with a proxy + bool t2pRegister(const void* const pTrans, DataProxy* const pPers) { + bool success(m_t2p.insert (std::make_pair (pTrans, pPers)) . second); + if (m_pac) m_pac->controlPage(pTrans); + return success; + } + + // locate a proxy in t2p map + DataProxy* locatePersistent(const void* const pTransient) const { + t2p::const_iterator i = m_t2p.find(pTransient); + + if (i == m_t2p.end()) + return 0; + else + return i->second; + } + + // clear the t2p map + void clear() { + m_t2p.clear(); + } + + // remove a void* from t2p + void t2pRemove(const void* const pTrans) { + m_t2p.erase(pTrans); + } + + /// set IPageAccessControlSvc ptr in T2PMap + void setPac(IPageAccessControlSvc* pac) { m_pac=pac; } + /// request an access control report, i.e. a list of proxies that have not been accessed since under control; + std::vector<DataProxy*> pacReport() const; + + + private: + IPageAccessControlSvc* m_pac; + t2p m_t2p; + +}; + +} +#endif diff --git a/EDM/athena/Control/SGTools/SGTools/TestStore.h b/EDM/athena/Control/SGTools/SGTools/TestStore.h new file mode 100644 index 00000000..9b05a695 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/TestStore.h @@ -0,0 +1,139 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/TestStore.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2015 + * @brief Dummy event store, for regression tests. + */ + + +#ifndef SGTOOLS_TESTSTORE_H +#define SGTOOLS_TESTSTORE_H + + +#include "AthenaKernel/IProxyDict.h" +#include "SGTools/StringPool.h" +#include "SGTools/DataProxy.h" +#include "SGTools/CurrentEventStore.h" +#include <unordered_map> + + +namespace SGTest { + + +typedef SG::sgkey_t sgkey_t; + + +struct TestStoreRemap +{ + TestStoreRemap (SG::sgkey_t the_key=0, size_t the_index = 0) + : key (the_key), index (the_index) {} + bool operator== (const TestStoreRemap& other) const + { return other.key == key && other.index == index; } + SG::sgkey_t key; + size_t index; +}; + + +struct TestStoreRemapHash +{ + size_t operator() (const TestStoreRemap& m) const + { return m.key + m.index; } +}; + + +class TestStore + : virtual public IProxyDict +{ +public: + // These are unimplemented and will abort. + virtual unsigned long addRef() override; + virtual unsigned long release() override; + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override; + virtual std::vector<const SG::DataProxy*> proxies() const override; + virtual const std::string* keyToString (sgkey_t /*key*/) const override; + virtual void registerKey (sgkey_t /*key*/, + const std::string& /*str*/, + CLID /*clid*/) override; + virtual SG::DataProxy* recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) override; + virtual StatusCode updatedObject (CLID id, const std::string& key) override; + + + // These have dummy implementations. + virtual const std::string& name() const override; + virtual SG::DataProxy* proxy(const void* const pTransient) const override; + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key) const override; + virtual SG::DataProxy* proxy_exact (SG::sgkey_t sgkey) const override; + virtual sgkey_t stringToKey (const std::string& str, CLID clid) override; + virtual const std::string* keyToString (sgkey_t key, CLID& clid) const override; + virtual bool tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out) override; + virtual StatusCode addToStore (CLID /*id*/, SG::DataProxy* proxy) override; + virtual void boundHandle (IResetable* handle) override; + virtual void unboundHandle (IResetable* handle) override; + + SG::DataProxy* record1 (const void* p, DataObject* obj, + CLID clid, const std::string& key); + + + template <class T> + void record (const T* p, const std::string& key) + { + DataObject* obj = SG::asStorable<T>(const_cast<T*>(p)); + CLID clid = ClassID_traits<T>::ID(); + record1 (p, obj, clid, key); + } + + + void remap (sgkey_t sgkey_in, sgkey_t sgkey_out, + size_t index_in = 0, size_t index_out = 0); + + + template <class T> + void remap (const std::string& key_in, const std::string& key_out, + size_t index_in = 0, size_t index_out = 0) + { + CLID clid = ClassID_traits<T>::ID(); + sgkey_t sgkey_in = stringToKey (key_in, clid); + sgkey_t sgkey_out = stringToKey (key_out, clid); + remap (sgkey_in, sgkey_out, index_in, index_out); + } + + typedef std::unordered_map<const void*, SG::DataProxy*> tmap_t; + tmap_t m_tmap; + + typedef std::unordered_map<sgkey_t, SG::DataProxy*> kmap_t; + kmap_t m_kmap; + + typedef std::unordered_map<TestStoreRemap, TestStoreRemap, TestStoreRemapHash> remap_t; + remap_t m_remap; + + SG::StringPool m_stringPool; + + std::vector<IResetable*> m_boundHandles; + + std::vector<std::string> m_updated; + bool m_failUpdatedObject = false; + + // Log failed calls to proxy(CLID, std::string). + mutable std::vector<std::pair<CLID, std::string> > m_missedProxies; +}; + + +extern TestStore store; +void initTestStore(); + + +} // namespace SGTest + + +#endif // not SGTOOLS_TESTSTORE_H diff --git a/EDM/athena/Control/SGTools/SGTools/TransientAddress.h b/EDM/athena/Control/SGTools/SGTools/TransientAddress.h new file mode 100644 index 00000000..77ffb8fd --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/TransientAddress.h @@ -0,0 +1,290 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SGTOOLS_TRANSIENTADDRESS_H +#define SGTOOLS_TRANSIENTADDRESS_H + +///< includes: +#include <string> +#include <set> + + +///< Gaudi includes: +#include "AthenaKernel/IStringPool.h" +#include "AthenaKernel/StoreID.h" +#include "GaudiKernel/ClassID.h" + +///< forward declarations: +class IOpaqueAddress; +class IAddressProvider; + +namespace SG { + + class TransientAddress + { + + public: + + typedef std::set<CLID> TransientClidSet; + typedef std::set<std::string> TransientAliasSet; + typedef IStringPool::sgkey_t sgkey_t; + + ///< Default Constructor + TransientAddress(); + + ///< Construct from clid and string key: + TransientAddress(const CLID& id, const std::string& key); + + ///< Construct from clid, key and IOpaqueAddress + TransientAddress(const CLID& id, const std::string& key, + IOpaqueAddress* addr, bool clearAddress = true); + + ///< Destructor + virtual ~TransientAddress(); + + /// Set the CLID / key. + /// This will only succeed if the clid/key are currently clear. + void setID (CLID id, const std::string& key); + + ///< Reset + void reset(); + + ///< Retrieve IOpaqueAddress + virtual IOpaqueAddress* address() const; + + ///< set IOpaqueAddress + virtual void setAddress(IOpaqueAddress* pAddress); + + ///< Retrieve primary clid + CLID clID() const; + + ///< Retrieve string key: + const std::string& name() const; + + ///< Get the primary (hashed) SG key. + sgkey_t sgkey() const; + + ///< Set the primary (hashed) SG key. + void setSGKey (sgkey_t sgkey); + + ///< check if it is a transient ID (primary or symLinked): + bool transientID (const CLID& id) const; + + ///< set transient CLID's + void setTransientID(const CLID& id); + + ///< get transient CLID's + const TransientClidSet& transientID() const; + + ///< set alias' + void setAlias(const std::string& key); + + ///< set alias' + void setAlias(const std::set<std::string>& keys); + + /// remove alias from proxy + bool removeAlias(const std::string& key); + + ///< get transient alias + const TransientAliasSet& alias() const; + + ///< set the clearAddress flag: IOA will not be deleted in proxy + void clearAddress(const bool& flag); + + ///< Return the clearAddress flag. + bool clearAddress() const; + + ///< this sets the flag whether to consult the provider to update + /// this transient address if the IOA is not valid. + void consultProvider(const bool& flag); + + ///< Check the validity of the Transient Address. + bool isValid(); + + ///< cache the pointer to the Address provider which can update + ///< this transient address + IAddressProvider* provider() const; + StoreID::type storeID() const; + void setProvider(IAddressProvider* provider, StoreID::type storeID); + + private: + + ///< clid of the concrete class (persistent clid) + CLID m_clid; + + ///< string key of this object + std::string m_name; + + ///< all transient clids. They come from symlinks + TransientClidSet m_transientID; + + ///< all alias names for a DataObject. They come from setAlias + TransientAliasSet m_transientAlias; + + ///< IOpaqueAddress: + IOpaqueAddress* m_address; + + ///< Controls if IOpaqueAddress should be deleted: + bool m_clearAddress; + + ///< Control whether the Address Provider must be consulted + bool m_consultProvider; + + ///< AddressProvider + IAddressProvider* m_pAddressProvider; + + ///< Store type, needed by updateAddress + StoreID::type m_storeID; + + ///< (hashed) SG key for primary clid / key. + sgkey_t m_sgkey; + }; + ///////////////////////////////////////////////////////////////////// + // inlined code: + ///////////////////////////////////////////////////////////////////// + + // Reset the TransientAddress + inline + void TransientAddress::reset() + { + if (m_clearAddress) setAddress(0); + } + + /// Retrieve IOpaqueAddress + inline + IOpaqueAddress* TransientAddress::address() const + { + return m_address; + } + + /// Retrieve clid + inline + CLID TransientAddress::clID() const + { + return m_clid; + } + + /// Return StoreGate key + inline + const std::string& TransientAddress::name() const + { + return m_name; + } + + /// Get the primary (hashed) SG key. + inline + TransientAddress::sgkey_t TransientAddress::sgkey() const + { + return m_sgkey; + } + + /// Set the primary (hashed) SG key. + inline + void TransientAddress::setSGKey (sgkey_t sgkey) + { + m_sgkey = sgkey; + } + + /// check if it is a transient ID: + inline + bool TransientAddress::transientID(const CLID& id) const + { + return 0 != m_transientID.count(id); + } + + /// set transient CLID's + inline + void TransientAddress::setTransientID(const CLID& id) + { + m_transientID.insert(id); + } + + /// get transient CLID's + inline + const TransientAddress::TransientClidSet& TransientAddress::transientID() const + { + return m_transientID; + } + + /// set transient Alias' + inline + void TransientAddress::setAlias(const std::string& key) + { + m_transientAlias.insert(key); + } + + /// set transient Alias' + inline + void TransientAddress::setAlias(const std::set<std::string>& keys) + { + m_transientAlias = keys; + } + + /// remove alias + inline bool TransientAddress::removeAlias(const std::string& key) + { + return (m_transientAlias.erase(key) == 1) ? true:false; + } + + /// get transient Alias' + inline + const TransientAddress::TransientAliasSet& TransientAddress::alias() const + { + return m_transientAlias; + } + + /// set the clearAddress flag: IOA will not be deleted in proxy + inline + void TransientAddress::clearAddress(const bool& flag) + { + m_clearAddress = flag; + } + + /// Return the clearAddress flag. + inline + bool TransientAddress::clearAddress() const + { + return m_clearAddress; + } + + inline + void TransientAddress::consultProvider(const bool& flag) + { + m_consultProvider = flag; + } + + ///< cache the pointer to the Address provider which can update + ///< this transient address + inline + IAddressProvider* TransientAddress::provider() const + { + return m_pAddressProvider; + } + inline + StoreID::type TransientAddress::storeID() const + { + return m_storeID; + } + + inline + void TransientAddress::setProvider(IAddressProvider* provider, + StoreID::type storeID) + { + m_pAddressProvider = provider; + m_consultProvider = true; + m_storeID=storeID; + } +} //end namespace SG + +#endif // STOREGATE_TRANSIENTADDRESS + + + + + + + + + + diff --git a/EDM/athena/Control/SGTools/SGTools/crc64.h b/EDM/athena/Control/SGTools/SGTools/crc64.h new file mode 100644 index 00000000..d9a017ca --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/crc64.h @@ -0,0 +1,56 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/** + * @file SGTools/crc64.h + * @author scott snyder, originally from David T. Jones + * @date Mar 2007 + * @brief A CRC-64 implementation. + */ + +#ifndef SGTOOLS_CRC64_H +#define SGTOOLS_CRC64_H + + +#include <string> +#include <stdint.h> + + +namespace SG { + + +/** + * @brief Find the CRC-64 of a string. + * @param str The string to hash. + */ +uint64_t crc64 (const std::string& str); + + +/** + * @brief Extend a previously-calculated CRC to include an int. + * @param crc The previously-calculated CRC. + * @param x The integer to add. + * @return The new CRC. + */ +uint64_t crc64addint (uint64_t crc, unsigned int x); + + +/** + * @brief Format a CRC-64 as a string. + * @param crc The CRC to format. + */ +std::string crc64format (uint64_t crc); + + +/** + * @brief Return a CRC-64 digest of a string. + * @param str The string to hash. + * @return The CRC-64 digest of the string. + * This is the hash code, expressed as hex as a string. + */ +std::string crc64digest (const std::string& str); + + +} // namespace SG + + + +#endif // not SGTOOLS_CRC64_H diff --git a/EDM/athena/Control/SGTools/SGTools/exceptions.h b/EDM/athena/Control/SGTools/SGTools/exceptions.h new file mode 100644 index 00000000..2de48a5c --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/exceptions.h @@ -0,0 +1,97 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/exceptions.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Exceptions that can be thrown by SGTools. + */ + + +#ifndef SGTOOLS_EXCEPTIONS_H +#define SGTOOLS_EXCEPTIONS_H + + +#include "GaudiKernel/ClassID.h" +#include <typeinfo> +#include <stdexcept> +#include <string> + + +namespace SG { + + +/** + * @brief Exception --- Bad cast of DataProxy with CLID + * + * You tried to retrieve an object in StoreGate as an incompatible type. + */ +class ExcBadDataProxyCast + : public std::bad_cast +{ +public: + /** + * @brief Constructor. + * @param id CLID of the DataProxy. + * @param tid Type to which we're trying to convert the object. + */ + ExcBadDataProxyCast (CLID id, const std::type_info& tid); + + + // Needed for c++98 compatibility. + ~ExcBadDataProxyCast() throw() {} + + + /** + * @brief Return the message for this exception. + */ + virtual const char* what() const throw(); + + +private: + /// The message for this exception. + std::string m_what; +}; + + +/** + * @brief Throw an ExcBadDataProxyCast exception. + * @param id CLID of the DataProxy. + * @param tid Type to which we're trying to convert the object. + */ +void throwExcBadDataProxyCast (CLID id, const std::type_info& tid); + + +/** + * @brief Exception --- Proxy collision for clid/key + * + * DataStore was attempting to fill in the CLID/key for a dummy proxy, + * but there was already another proxy present with that CLID/key. + * + * This should never happen. + */ +class ExcProxyCollision + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param id CLID we're trying to set on the dummy proxy. + * @param key Key we're trying to set on the dummy proxy. + * @param primary_id CLID of the existing proxy. + * @param primary_key Key of the existing proxy. + */ + ExcProxyCollision (CLID id, const std::string& key, + CLID primary_id, const std::string& primary_key); +}; + + +} // namespace SG + + +#endif // not SGTOOLS_EXCEPTIONS_H diff --git a/EDM/athena/Control/SGTools/SGTools/hashtable.h b/EDM/athena/Control/SGTools/SGTools/hashtable.h new file mode 100644 index 00000000..42d0e298 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/hashtable.h @@ -0,0 +1,17 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: hashtable.h,v 1.2 2008-09-17 01:17:05 binet Exp $ + +#ifndef SGTOOLS_HASHTABLE_H +#define SGTOOLS_HASHTABLE_H 1 + +#ifndef CXXUTILS_HASHTABLE_H + #include "CxxUtils/hashtable.h" +#endif + +#endif /* !SGTOOLS_HASHTABLE_H */ + diff --git a/EDM/athena/Control/SGTools/SGTools/ptrhash.h b/EDM/athena/Control/SGTools/SGTools/ptrhash.h new file mode 100644 index 00000000..b807abba --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/ptrhash.h @@ -0,0 +1,50 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ptrhash.h,v 1.1 2008-04-08 16:05:32 ssnyder Exp $ +/** + * @file SGTools/ptrhash.h + * @author scott snyder <snyder@bnl.gov> + * @date Mon, 2008 + * @brief Improved hash function for pointers. + */ + + +#ifndef SGTOOLS_PTRHASH_H +#define SGTOOLS_PTRHASH_H + + +namespace SG { + + +/** + * @brief Improved hash function for pointers. + * + * The default hash function for pointers used by @c unordered_map and friends + * is just the result of casting the pointer to an int. + * The problem is that most pointers one deals with are going + * to be aligned; if the pointers are to objects obtained through malloc, + * then on all systems we deal with, at least the lower three bits + * of the pointer will always be clear. Since @c unordered_map + * uses a bucket-hash scheme, this means that only 1/8 of the buckets + * will be used in such a case, resulting in lower efficiency. + * + * Here, we try to avoid this problem. + */ +struct ptrhash +{ + std::size_t operator() (const void* p) const + { + std::size_t x = reinterpret_cast<std::size_t> (p); + return (x>>3) ^ (x&7); + } +}; + + +} // namespace SG + + +#endif // not SGTOOLS_PTRHASH_H diff --git a/EDM/athena/Control/SGTools/SGTools/safe_clid.h b/EDM/athena/Control/SGTools/SGTools/safe_clid.h new file mode 100644 index 00000000..ff48a1d7 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/safe_clid.h @@ -0,0 +1,58 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: safe_clid.h,v 1.2 2005-11-08 22:01:30 ssnyder Exp $ + +/** + * @file SGTools/safe_clid.h + * @author scott snyder + * @date Nov 2005 + * @brief Find the class ID of a type, without triggering an error + * if it isn't defined. + * + * The general interface for finding the class ID for some type @a T + * is to use @a ClassID_traits<T>::ID(). However, if no class ID + * has been defined for @a T, this will result in a compilation error. + * In some cases, where the class ID can be considered optional, this + * can severely restrict the applicability of generic code. + * + * This header provides @a SG::safe_clid<T>(), which should return + * the class ID of @T, or @a CLID_NULL if @a T does not have a defined + * class ID (without causing an error). + * + * The implementation relies on the fact that when the class ID traits + * class gets specialized for a specific class ID, it defines + * @a has_classID_tag. The @a CLASS_DEF macro makes this definition, + * but if you specialize @a ClassID_traits yourself, you must remember + * to include @a has_classID_tag, or this function won't work. + */ + +#ifndef SGTOOLS_SAFECLID_H +#define SGTOOLS_SAFECLID_H + + +#include "GaudiKernel/ClassID.h" + + +namespace SG { + + +/** + * @brief Return the class ID of @a T, or @a CLID_NULL if it doesn't + * have one. Avoids compilation errors if the class ID + * is not defined. + */ +template <class T> +CLID safe_clid(); + + +} // namespace SG + + +#include "SGTools/safe_clid.icc" + + +#endif // not SGTOOLS_SAFECLID_H diff --git a/EDM/athena/Control/SGTools/SGTools/safe_clid.icc b/EDM/athena/Control/SGTools/SGTools/safe_clid.icc new file mode 100644 index 00000000..745257f0 --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/safe_clid.icc @@ -0,0 +1,121 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: safe_clid.icc,v 1.2 2007-12-14 03:12:34 binet Exp $ +/** + * @file SGTools/safe_clid.icc + * @author scott snyder + * @date Nov 2005 + * @brief Find the class ID of a type, without triggering an error + * if it isn't defined. + * Implementation file. + */ + +#include "SGTools/ClassID_traits.h" +#include "AthenaKernel/tools/type_tools.h" +#include "boost/type_traits/remove_pointer.hpp" + + +namespace SG { + + +//------------------------------------------------------------------------- +// Here's the first part. @a safe_clid has the job of calling one of the +// two @a safe_clid_1 overrides, depending on the state of the traits +// class @a has_classID_tag definition. We want the first one to be called +// when @a has_classID_tag is @a true_tag, and the second to be called +// in other cases (including the possibility that the typedef does not exist). +// There are three possibilities to consider. +// +// 1. The traits class defines @a has_classID_tag as @a true_tag. +// Here, both decl 1 and 2 match the call. It turns out +// that we can't use partial ordering to discriminate between +// these two on the basis of the tag (second) argument alone. +// That's the purpose of the first (dummy) argument. By making +// it a pointer in decl 1 and completely generic in decl 2, +// we ensure that decl 1 is a more specific match when both +// decls are allowed. +// +// 2. The traits class defines @a has_classID_tag as something +// other than @a true_tag. In this case, decl 1 doesn't match +// the call, but decl 2 will. So decl 2 will be called. +// +// 3. The traits class has no definition for @a has_classID_tag. +// In this case, the type named in decl 1 does not exist. +// However, that is @e not an error --- it just means that +// decl 1 won't be considered as a candidate overload. +// (Look up ``substitution failure is not an error'' (SFINAE).) +// So again, decl 2 gets called. Note that the requirement +// to handle this case (which comes about because the unspecialized +// version of @a ClassID_traits does not define this typedef) +// is why this may look backwards, using @a true_tag in the call, +// and the traits class typedef in the argument. + + +// Decl 1 +template <class T> +CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag); + +// Decl 2 +template <class T, class U> +CLID safe_clid_1 (T, U); + +// This is the public entry point. +template <class T> +CLID safe_clid() +{ + return safe_clid_1 ((T*)0, std::true_type()); +} + + +//------------------------------------------------------------------------- +// Here is the definition for decl 1. This gets called when the +// traits class defines @a has_classID_tag as @a true_tag. +// So we can go ahead and ask for the ID in this case. + +template <class T> +CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag) +{ + return ClassID_traits<T>::ID(); +} + + +//------------------------------------------------------------------------- +// Here is the definition for decl 2. This gets called when the traits +// class does not define @a has_classID_tag is @a true_tag. +// But there is one further decision to be made. If @a T derives +// from @a DataObject, then we can still get the class ID. +// Otherwise, we must return @a CLID_NULL. + +// This is called if @a T does not derive from @a DataObject. +// Return @a CLID_NULL. +template <class T, bool B> +struct safe_clid_2 +{ + static CLID clid() { return CLID_NULL; } +}; + +// This specialization is used if @a T does derive from @a DataObject. +// This returns the class ID. +template <class T> +struct safe_clid_2<T, true> +{ + static CLID clid() { return ClassID_traits<T>::ID(); } +}; + +// This is the definition corresponding to decl 2 above. +// We test @a s_isDataObject in the traits class. +// Note that here @a T will be a pointer to the class we're +// actually interested in, so we need to strip a pointer. +template <class T, class U> +CLID safe_clid_1 (T, U) +{ + typedef typename boost::remove_pointer<T>::type typ; + return safe_clid_2<typ, ClassID_traits<typ>::s_isDataObject>::clid(); +} + + +} // namespace SG + + diff --git a/EDM/athena/Control/SGTools/SGTools/selection.xml b/EDM/athena/Control/SGTools/SGTools/selection.xml new file mode 100644 index 00000000..595175cc --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/selection.xml @@ -0,0 +1,12 @@ +<lcgdict> + <class name="DataBucketBase" /> + <class name="SG::DataProxy" /> + <exclusion> + <class pattern="*iterator*tuple*long*unsigned*int*"/> + </exclusion> + <class name="std::vector<SG::DataProxy*>" /> + <class name="std::vector<const SG::DataProxy*>" /> + <class name="SG::BaseInfoBase" /> + <class name="SG::CurrentEventStore" /> + <class name="SG::CurrentEventStore::Push" /> +</lcgdict> diff --git a/EDM/athena/Control/SGTools/SGTools/unordered_map.h b/EDM/athena/Control/SGTools/SGTools/unordered_map.h new file mode 100644 index 00000000..8478446f --- /dev/null +++ b/EDM/athena/Control/SGTools/SGTools/unordered_map.h @@ -0,0 +1,15 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: unordered_map.h,v 1.2 2008-09-17 01:17:05 binet Exp $ +#ifndef SGTOOLS_UNORDERED_MAP_H +#define SGTOOLS_UNORDERED_MAP_H 1 + +#ifndef CXXUTILS_UNORDERED_MAP_H + #include "CxxUtils/unordered_map.h" +#endif + +#endif /* !SGTOOLS_UNORDERED_MAP_H */ diff --git a/EDM/athena/Control/SGTools/cmt/requirements b/EDM/athena/Control/SGTools/cmt/requirements new file mode 100644 index 00000000..44a90364 --- /dev/null +++ b/EDM/athena/Control/SGTools/cmt/requirements @@ -0,0 +1,46 @@ +package SGTools +author Paolo Calafiura <Paolo.Calafiura@cern.ch> +author Srini Rajagopalan <srinir@bnl.gov> + +use AtlasPolicy AtlasPolicy-* + +use CxxUtils CxxUtils-* Control +use AthenaKernel AthenaKernel-* Control + +#need IAddressProvider.h, IResetable.h + +use AtlasBoost AtlasBoost-* External +use GaudiInterface GaudiInterface-* External + +library SGTools *.cxx +apply_pattern installed_library + +private +# Get the boost threads dso linked. +macro_append Boost_linkopts $(Boost_linkopts_thread) +macro_append SGTools_shlibflags $(Boost_linkopts) + +use SGAudCore SGAudCore-* Control/SGMon +use TestTools TestTools-* AtlasTest +use AtlasReflex AtlasReflex-* External -no_auto_imports + +apply_pattern lcgdict dict=SGTools selectionfile=selection.xml headerfiles="-s=${SGTools_root}/SGTools SGToolsDict.h" + +apply_pattern UnitTest_run unit_test=CLIDRegistry +apply_pattern UnitTest_run unit_test=VersionedKey +apply_pattern UnitTest_run unit_test=DataBucket \ + extrapatterns="^HistogramPersis.* INFO" +apply_pattern UnitTest_run unit_test=BaseInfo +apply_pattern UnitTest_run unit_test=safe_clid +apply_pattern UnitTest_run unit_test=crc64 +apply_pattern UnitTest_run unit_test=exceptions +apply_pattern UnitTest_run unit_test=StringPool +apply_pattern UnitTest_run unit_test=ClassName +apply_pattern UnitTest_run unit_test=DataProxy +apply_pattern UnitTest_run unit_test=DataStore +apply_pattern UnitTest_run unit_test=TransientAddress +apply_pattern UnitTest_run unit_test=CurrentEventStore +apply_pattern UnitTest_run unit_test=SGFolderItem + +macro_append DOXYGEN_INPUT " ../doc" +end_private diff --git a/EDM/athena/Control/SGTools/doc/MainPage.h b/EDM/athena/Control/SGTools/doc/MainPage.h new file mode 100644 index 00000000..6e9bb51c --- /dev/null +++ b/EDM/athena/Control/SGTools/doc/MainPage.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + +@mainpage + +This package contains implementation classes for StoreGate. + +@section uses Packages used + +@htmlinclude used_packages.html + +@section requirements requirements + +@include requirements + +@section refs More Documentation + +More information is available from the Athena wiki +<https://twiki.cern.ch/twiki/bin/view/Atlas/StoreGate> + +The code can be browsed using LXR +(http://alxr.usatlas.bnl.gov/lxr/source/atlas/Control/SGTools/) + + +@author Paolo Calafiura <Paolo.Calafiura@cern.ch> +*/ diff --git a/EDM/athena/Control/SGTools/ispellwords b/EDM/athena/Control/SGTools/ispellwords new file mode 100644 index 00000000..bba2d8d2 --- /dev/null +++ b/EDM/athena/Control/SGTools/ispellwords @@ -0,0 +1,620 @@ +personal_ws-1.1 en 342 +updateItemList +decls +addSymLink +clid +resetOnly +requestRelease +DataBucketCast +EventHeader +cmt +SGAudCore +theApp +CLIDSvc +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +SGToolsDict +StoreGateSvc +SGTools +bool +bla +Bleah +blu +Vukotic +ProxyMap +proxymap +toObjectType +dbbObject +pSGAudSvc +LXR +StreamBuffer +asStorable +Leggett +CxxUtils +crc +NoBase +builtins +cxx +utils +addAlias +rawVersionKey +FCA +Calafiura +DataObjects +symlinks +symLinks +symlinked +symLinked +castTo +cassert +typeinfoName +speeded +IOA +addInit +addint +CLASSVERSION +malloc +DataList +initGaudi +endcode +AtlasBoost +hpp +StorableConversions +SGIFolder +SGFolder +pDObj +MyDataObj +getMessageSvc +printf +gcc +getAddress +IProxyDictWithPool +pRange +Quarrie +DataModel +symlink +DataHandles +ctor +gaudi +cout +gdo +typedef'd +pObj +MyKey +BaseInfoBase +substr +mem +ajsdla +StorageType +TransientAddress +NN +Nuno +accessData +msg +ns +pok +TestTools +poly +unsetInput +regbase +retrieveAllVersions +pre +StatusCode +dbb +modifs +DataHeaderElement +SG +sg +circ +DF +timespec +setAlias +DHE +rhs +ClassID +classID +wrt +ItemList +CLIDs +CLID's +clids +refcount +refCount +Xed +xd +AbstractDataObj +dp +dep +createObj +InputDataHeader +dtor +TrEMBL +Gemmeren +AbstractType +BaseInfoBaseImpl +setDefaults +lkjasd +lkajsd +VK +vkey +wiki +AthenaKernel +persistency +AddressProvider +typeinfo +paks +mutex +StringPool +CLIDComps +MacOSX +outputLevel +typeName +copyVK +pMap +pmap +IStringPool +VersionedKey +CallBackID +behaviour +metafunction +pointee +setClid +converterTo +IConversionSvc +stdout +stringToKey +DataBucket +DataSvc +param +stateFlag +const +vtable +IOVSvc +hashtable +AtlasReflex +svcLocator +SGVersionedKey +templated +isInput +dobjs +fromStorable +DBDataModel +ptr +DataObj +SFINAE +dobj +DataBucketTraitFwd +genreflex +DataBucketBase +StlVectorClids +registerKey +MessageSvc +relPool +ClassName +Binet +binet +castObject +BuiltinsClids +sgkey +ProxyProvider +InterfaceID +INITIALCRC +SLC +GaudiKernel +DEFS +scott +CLASSDEF +DataHeader +cptr +getPrimaryClassID +clearStore +everything's +snyder +ssnyder +decl +doxygen +SGComps +aspdk +CLIDREG +castfnTo +outObject +dquarrie +DataStore +FIXME +forceRemove +dict +src +tinfo +DLT +demangled +refcounting +valgrind +Stl +DEFAULTKEY +refcounts +str +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +clearAddress +DATAVECTOR +DataVector +StatusCodeSvc +SWISSPROT +CLIDRegistry +namespace +aliasKey +typeid +Schaffer +schaffer +inlined +chkconfig +DataBucketTrait +tryELRemap +tdef +Storable +storable +Rajagopalan +impl +castfn +CreateSvc +IPageAccessControlSvc +toType +INLINE +func +SGAudSvc +IOpaqueAddress +objName +ISGAudSvc +EventSelectorAthenaPool +html +baseinfo +BaseInfo +IProxyRegistry +icc +arg +eg +i'll +ULL +noAudSvc +pObject +API +FdB +IID +atoi +irt +ElementLink +resetFlag +MAXCLID +pgref +vkeys +addEntry +BaseInfoImpl +readback +keyToString +MINCLID +strlen +eval +indep +converterToHelper +StoreGate +struct +iostream +ints +versionKey +StoreMap +pMember +BaseType +IRegisterTransient +Versioned +mixup +ClassIDSvc +IMessageSvcHolder +SAFECLID +ECMA +SGFolderItem +retrieveHighestVersion +Ilija +args +IRegistry +initlist +removeProxy +enum +GaudiDataObj +uint +init +DataProxy +inObject +consultProvider +isDataObject +libSGTools +IProxyDict +ptrhash +htmlinclude +setProperty +IDC +DataObject +mainpage +calaf +CGL +asd +StorableConversion +pRegister +STLMAPCLIDS +StlMapClids +addr +laskjkd +t2pmap +T2pMap +typedef +instantiation +doesn +v1r19 +v19 +v16 +crc64addint +gcc4 +lookup +casted +SLC4 +typedefs +t2pRegister +t2p +ispellwords +addToStore +IResetable +runtime +RegisterAddBaseInit +keyless +Kittelmann +reinit +setTransientAddress +errNo +errno +checkreq +d3pds +defaultkey +isConst +bools +DataHandleBase +DataHandle +resized +ulonglong +ulong +ushort +uint8 +vec +savannah +cacheable +updateAddress +isValid +storeID +gcc43 +coverity +SGImplSvc +Paolo +wscript +Sebastien +sz +dst +MyType +MyCopyConversion +Base3 +Base2 +Base1 +instantiations +B3 +B2 +B1 +BASES3 +BASES2 +BASES1 +isn +Destructor +CopyConversionBase +cnv +initializations +initializer +recurse +AddBaseInfo +ourself +ARG2 +ARG1 +DEF2 +accessors +0x +decrement +fwk +itr1 +ok +T2PMap +EL +02u +ost +aren +CRC64 +unordered +unspecialized +HistogramPersis +DynamicType +dataPointer +typeless +itrEnd +itr +GaudiObject +resettable +nmatch +crc64 +0xd800000000000000ULL +POLY64REV +0x0000000000000000ULL +08X +test1 +test2 +fooB +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +C874767DA8254746 +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +2DF1AA17420FCA3F +NoAuxStore +AuxStore +CLASSAUXSTORE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +dicts +AthContainers +AthContainersInterfaces +leggett +charles +setSGKey +setID +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +pTAd +addRef +key2 +key3 +key4 +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +setStore +clID +tAddr +ims +gLog +MsgStream +endmsg +endreq +queryInterface +pTransient +proxy1 +proxy2 +proxy3 +exact1 +keyToString1 +keyToString2 +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +ExcBadDataProxyCast +keyMap +storeMap +tid +dummied +shouldn +ExcProxyCollision +dp1 +dp2 +dp1a +dp1b +dpx +dp3 +typeCount +tRange +proxyList +dp4 +dp1x +pac +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +abc +LCGCMT +Seusterk +Rolf +Buttinger +clidEntry +newEntries +Niels +ILockable +setConst +Nowak +Marcin +typeInfo +typeId +hashmap +finalReset +abi +ActiveStoreSvc +AthLinks +CurrentEventStore +gcc5 +setStorePtr +TestStore +RegisterBaseInit +curStore +unboundHandle +boundHandle +isValidAddress +CLIDdefault +recordObject +DataObjectSharedPtr +updatedObject +snprintf +sprintf +cppcheck +'s + + + + + + +ElementLinks +destructor +outKey +SGTest +canonicalize +nullptr +VarHandleBase +resetBoundHandles +ir +unbindHandle +autoincrement +COMPILEFAIL +Baz +test3 +pConverter +addConverter +removeConverter +outputFile +connectOutput1 +openMode +connectOutput2 +commitOutput +objType +repSvcType +pService +setDataProvider +dataProvider +setConversionSvc +conversionSvc +setAddressCreator +addressCreator +pAddress +refpObject +fillObjRefs +updateObj +updateObjRefs +fillRepRefs +updateRep +updateRepRefs +refpAddress +createRep +svcType +setRegistry +ipar +test4 +ley +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +dump2 +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE diff --git a/EDM/athena/Control/SGTools/share/BaseInfo_test.ref b/EDM/athena/Control/SGTools/share/BaseInfo_test.ref new file mode 100644 index 00000000..bae42c55 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/BaseInfo_test.ref @@ -0,0 +1,2 @@ +test1 +test2 diff --git a/EDM/athena/Control/SGTools/share/CLIDRegistry_test.ref b/EDM/athena/Control/SGTools/share/CLIDRegistry_test.ref new file mode 100644 index 00000000..b5d0b6a4 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/CLIDRegistry_test.ref @@ -0,0 +1,2 @@ +*** CLIDRegistry_test starts *** +*** CLIDRegistry_test OK *** diff --git a/EDM/athena/Control/SGTools/share/ClassName_test.ref b/EDM/athena/Control/SGTools/share/ClassName_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/SGTools/share/CurrentEventStore_test.ref b/EDM/athena/Control/SGTools/share/CurrentEventStore_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/SGTools/share/CurrentEventStore_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/SGTools/share/DataBucket_test.ref b/EDM/athena/Control/SGTools/share/DataBucket_test.ref new file mode 100644 index 00000000..1c572a18 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/DataBucket_test.ref @@ -0,0 +1,48 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Thu Apr 17 17:22:20 2014 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +int has_classID 244260744 version 1 and does not inherit from DataObject +const int* has_classID 244260744 +vector<int> has_classID 22592129 +GaudiDataObj has_classID 8010 and does inherit from DataObject +MyDataObj has_classID 8000 and does not inherit from DataObject +AbstractDataObj has_classID 8011 +AbstractType has_classID 8004 +Now we expect to see an error message: +----Error Message Starts--->> +SG::fromStorable WARNING can't convert stored DataObject 0x1c33120 to type (WrongType) + Unless you are following a symlink, it probably means you have a duplicate CLID = 8000 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +SG::fromStorable WARNING can't convert stored DataObject 0x1c33120 to type (WrongType) + Unless you are following a symlink, it probably means you have a duplicate CLID = 8000 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +SG::fromStorable WARNING null input pointer +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +SG::fromStorable WARNING can't convert stored DataObject 0x1c33120 to type (WrongType) + Unless you are following a symlink, it probably means you have a duplicate CLID = 8010 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +SG::fromStorable WARNING can't convert stored DataObject 0x1e61c00 to type (WrongType) + Unless you are following a symlink, it probably means you have a duplicate CLID = 8010 +<<---Error Message Ends------- +test2 +SG::fromStorable WARNING can't convert stored DataObject 0x1c33120 to type (X3) + Unless you are following a symlink, it probably means you have a duplicate CLID = 8011 +test3 +lock +*** DataBucket_test OK *** diff --git a/EDM/athena/Control/SGTools/share/DataProxy_test.ref b/EDM/athena/Control/SGTools/share/DataProxy_test.ref new file mode 100644 index 00000000..ce520890 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/DataProxy_test.ref @@ -0,0 +1,6 @@ +test1 +test2 +lock +lock +test3 +test4 diff --git a/EDM/athena/Control/SGTools/share/DataStore_test.ref b/EDM/athena/Control/SGTools/share/DataStore_test.ref new file mode 100644 index 00000000..6c942137 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/DataStore_test.ref @@ -0,0 +1,15 @@ +test_ctor +test_addToStore +test_addAlias +test_addSymLink +test_proxy_exact +test_proxy +test_typeCount +test_tRange +test_pRange +test_proxyList +test_keys +test_removeProxy +test_clearStore +test_t2p +test_dummy diff --git a/EDM/athena/Control/SGTools/share/SGFolderItem_test.ref b/EDM/athena/Control/SGTools/share/SGFolderItem_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/Control/SGTools/share/SGFolderItem_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/Control/SGTools/share/StringPool_test.ref b/EDM/athena/Control/SGTools/share/StringPool_test.ref new file mode 100644 index 00000000..8c273c7b --- /dev/null +++ b/EDM/athena/Control/SGTools/share/StringPool_test.ref @@ -0,0 +1,15 @@ +test1 +000000003FFFFFFF +000000000FD9252C MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +000000000EE07ECA MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE +000000000AC0B3E3 ajsdla lkjasd lkjasd +000000003979421C paks aspdk pok asd +000000001B269909 asd laskjkd lkajsd +pool dump + ac0b3e3 3 ajsdla lkjasd lkjasd + ee07eca 2 MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE + fd9252c 1 MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE + 1b269909 5 asd laskjkd lkajsd + 3979421c 4 paks aspdk pok asd + 3fffffff 0 +pool dump2 diff --git a/EDM/athena/Control/SGTools/share/TransientAddress_test.ref b/EDM/athena/Control/SGTools/share/TransientAddress_test.ref new file mode 100644 index 00000000..204dae56 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/TransientAddress_test.ref @@ -0,0 +1,7 @@ +test1 +addRef 1 1 +addRef 2 1 +release 1 0 +release 2 0 +addRef 2 1 +release 2 0 diff --git a/EDM/athena/Control/SGTools/share/VersionedKey_test.ref b/EDM/athena/Control/SGTools/share/VersionedKey_test.ref new file mode 100644 index 00000000..dcbda6f6 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/VersionedKey_test.ref @@ -0,0 +1,3 @@ +Versioned Key 1=;01;bla +Versioned Key 2=;99;Bleah +Versioned Key 3=;00;default diff --git a/EDM/athena/Control/SGTools/share/crc64_test.ref b/EDM/athena/Control/SGTools/share/crc64_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/SGTools/share/exceptions_test.ref b/EDM/athena/Control/SGTools/share/exceptions_test.ref new file mode 100644 index 00000000..d3ec4082 --- /dev/null +++ b/EDM/athena/Control/SGTools/share/exceptions_test.ref @@ -0,0 +1,3 @@ +test1 +Bad cast of DataProxy with CLID 123 to type int +ExcProxyCollision: proxy collision for clid/key 123 / abc (primary 456 / def). diff --git a/EDM/athena/Control/SGTools/share/safe_clid_test.ref b/EDM/athena/Control/SGTools/share/safe_clid_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/SGTools/src/BaseInfo.cxx b/EDM/athena/Control/SGTools/src/BaseInfo.cxx new file mode 100644 index 00000000..2ff9abf9 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/BaseInfo.cxx @@ -0,0 +1,702 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.cxx,v 1.9 2008-11-25 21:45:04 ssnyder Exp $ +/** + * @file SGTools/BaseInfo.cxx + * @author scott snyder + * @date Nov 2005 + * @brief Provide an interface for finding inheritance information + * at run time. + * Out-of-line implementation. + */ + +#include "SGTools/BaseInfo.h" +#include "SGTools/CLIDRegistry.h" +#include "GaudiKernel/System.h" +//#include "boost/thread/mutex.hpp" +#include <map> +#include <unordered_map> +#include "string.h" + + +namespace SG { + + +struct BaseInfoBaseImpl { + /// Structure to hold information about one base. + struct info { + /// Constructor. @a converter* and @a is_virtual are as for @a add_info. + info (BaseInfoBase::castfn_t* converter = 0, + BaseInfoBase::castfn_t* converterTo = 0, + bool is_virtual = false); + + /// Converter function. Takes a @a T* and converts to a pointer + /// to this base. + BaseInfoBase::castfn_t* m_converter; + + /// Converter function. Takes a pointer to this base and converts + /// to @a T*. + /// to this base. + BaseInfoBase::castfn_t* m_converterTo; + + /// True if the derivation from this base to @a T is via + /// virtual derivation. + bool m_is_virtual; + }; + + + /// CLID of this class. + CLID m_clid; + + /// Set to true when first created. + /// Reset after we scan for init functions. + bool m_needs_init; + + /// @c std::type_info of this class. + const std::type_info* m_typeinfo; + + + /// Hold base information indexed by @a type_info. + typedef std::pair<const std::type_info*, info> ti_map_pair_type; + typedef std::vector<ti_map_pair_type> ti_map_type; + ti_map_type m_timap; + + + /// Hold copy conversion information indexed by @ type_info. + typedef std::pair<const std::type_info*, const CopyConversionBase*> + ti_copyconversion_pair_type; + typedef std::vector<ti_copyconversion_pair_type> ti_copyconversion_type; + ti_copyconversion_type m_ti_copyconversion_map; + + + /// Map of all @c type_info pointers to @c BaseInfoBase instances. + typedef std::unordered_map<const std::type_info*, BaseInfoBase*> bi_by_ti_map_type; + static bi_by_ti_map_type* s_bi_by_ti; + + + /// Used to canonicalize @c type_info instances. + typedef std::unordered_map<std::string, const std::type_info*> ti_by_name_map_type; + static ti_by_name_map_type* s_ti_by_name; + + + /// Holds @c BaseInfo classes awaiting initialization. + /// This is used to defer initialization until everything's loaded. + typedef std::unordered_multimap<const std::type_info*, + BaseInfoBase::init_func_t*> init_list_t; + static init_list_t* s_init_list; + + + // To make sure that the maps get deleted at program termination. + struct Deleter { + ~Deleter(); + }; + static Deleter s_deleter; + + /// For thread-safety. + //static boost::mutex s_mutex; + + + /** + * @brief Find a base by @c type_info. + * @param tinfo The @c type_info to find. + * + * Returns the @c info pointer for the base corresponding + * to @c info, or nullptr if there is no match. + */ + const info* findInfo (const std::type_info& tinfo) const + { + // We don't expect there to be many entries, so just use a linear search. + for (const auto& i : m_timap) { + if (i.first == &tinfo) + return &i.second; + } + + // Sometimes type_info's are not actually unique, depending on how libraries + // get loaded. Try again, comparing names. + for (const auto& i : m_timap) { + if (strcmp (i.first->name(), tinfo.name()) == 0) + return &i.second; + } + return nullptr; + } +}; + + + +/** + * @brief Return the CLID for this class. + */ +CLID BaseInfoBase::clid() const +{ + return m_impl->m_clid; +} + + +/** + * @brief Return the @c std::type_info for this class. + */ +const std::type_info& BaseInfoBase::typeinfo() const +{ + return *m_impl->m_typeinfo; +} + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +void* BaseInfoBase::cast (void* p, CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->cast (p, *ti); + return 0; +} + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +void* BaseInfoBase::cast (void* p, const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converter (p); + return nullptr; +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +void* BaseInfoBase::castTo (void* p, CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->castTo (p, *ti); + return 0; +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +void* BaseInfoBase::castTo (void* p, const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converterTo (p); + return nullptr; +} + + +/** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +BaseInfoBase::castfn_t* BaseInfoBase::castfn (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->castfn (*ti); + return 0; +} + + +/** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +BaseInfoBase::castfn_t* +BaseInfoBase::castfn (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converter; + return nullptr; +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +BaseInfoBase::castfn_t* BaseInfoBase::castfnTo (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->castfnTo (*ti); + return 0; +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +BaseInfoBase::castfn_t* +BaseInfoBase::castfnTo (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converterTo; + return nullptr; +} + + +/** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ +std::vector<CLID> BaseInfoBase::get_bases() const +{ + const BaseInfoBaseImpl::ti_map_type& map = m_impl->m_timap; + std::vector<CLID> v; + v.reserve (map.size()); + for (const auto& p : map) { + CLID clid = CLIDRegistry::typeinfoToCLID (*p.first); + if (clid != CLID_NULL) + v.push_back (clid); + } + return v; +} + + +/** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ +std::vector<const std::type_info*> BaseInfoBase::get_ti_bases() const +{ + const BaseInfoBaseImpl::ti_map_type& map = m_impl->m_timap; + std::vector<const std::type_info*> v; + v.reserve (map.size()); + for (const auto& i : map) + v.push_back (i.first); + return v; +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ +bool BaseInfoBase::is_base (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->is_base (*ti); + return 0; +} + + +/** + * @brief Return true if @a tinfo is the @a type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ +bool BaseInfoBase::is_base (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + return i != 0; +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ +bool BaseInfoBase::is_virtual (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->is_virtual (*ti); + return false; +} + + +/** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ +bool BaseInfoBase::is_virtual (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_is_virtual; + return false; +} + + +/** + * @brief Search for a copy conversion to @c tinfo. + * @param tinfo The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ +const CopyConversionBase* +BaseInfoBase::copy_conversion (const std::type_info& tinfo) const +{ + for (const auto& p : m_impl->m_ti_copyconversion_map) { + if (p.first == &tinfo) + return p.second; + } + return 0; +} + + +/** + * @brief Search for a copy conversion to @c clid. + * @param clid The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ +const CopyConversionBase* +BaseInfoBase::copy_conversion (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->copy_conversion (*ti); + return 0; +} + + +/** + * @brief Add a new copy conversion. + * @param tinfo The @c std::type_info of the target class. + * @param cnv A @c CopyConversionBase instance describing the conversion. + * + * The @c BaseInfoBase takes ownership of the @c cnv object. + */ +void +BaseInfoBase::add_copy_conversion (const std::type_info& tinfo, + const CopyConversionBase* cnv) +{ + m_impl->m_ti_copyconversion_map.emplace_back (&tinfo, cnv); +} + + +/** + * @brief Return known copy conversions. + * + * Returns the CLIDs of all target classes that have been registered + * with this one for copy conversion. + */ +std::vector<CLID> +BaseInfoBase::get_copy_conversions() const +{ + std::vector<CLID> out; + out.reserve (m_impl->m_ti_copyconversion_map.size()); + for (const auto& i : m_impl->m_ti_copyconversion_map) { + CLID clid = CLIDRegistry::typeinfoToCLID (*i.first); + if (clid != CLID_NULL) + out.push_back (clid); + } + return out; +} + + +/** + * @brief Add information about one base class. + * @param tinfo The @a std::type_info of the base. + * @param converter Converter function. This should be able to + * convert a @a T* to a pointer to this base. + * @param converterTo Converter function. This should be able to + * convert a pointer to this base to a @a T*. + * @param is_virtual True if the derivation from this base to @a T + * is via virtual derivation. + */ +void BaseInfoBase::add_info (const std::type_info& tinfo, + castfn_t* converter, + castfn_t* converterTo, + bool is_virtual) +{ + { + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (!i) { + m_impl->m_timap.emplace_back (&tinfo, + BaseInfoBaseImpl::info (converter, converterTo, is_virtual)); + } + } + + auto i = BaseInfoBaseImpl::s_bi_by_ti->find (&tinfo); + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) { + BaseInfoBaseImpl& impl = *i->second->m_impl; + if (impl.m_clid == CLID_NULL) + impl.m_clid = CLIDRegistry::typeinfoToCLID (tinfo); + } +} + + +/** + * @brief Convenience constructor. + * @param converter Converter function. This should be able to + * convert a @a T* to a pointer to this base. + * @param converterTo Converter function. This should be able to + * convert a pointer to this base to a @a T*. + * @param is_virtual True if the derivation from this base to @a T + * is via virtual derivation. + * + * The defaults are there just so this class can be used with STL + * containers that require a default ctor. + */ +BaseInfoBaseImpl::info::info (BaseInfoBase::castfn_t* converter /*= 0*/, + BaseInfoBase::castfn_t* converterTo /*= 0*/, + bool is_virtual /*= false*/) + : m_converter (converter), + m_converterTo (converterTo), + m_is_virtual (is_virtual) +{ +} + + +/** + * @brief Constructor. + * @param tinfo The @c std::type_info for this class. + */ +BaseInfoBase::BaseInfoBase (const std::type_info& tinfo) + : m_impl (new BaseInfoBaseImpl) +{ + m_impl->m_clid = CLIDRegistry::typeinfoToCLID (tinfo); + m_impl->m_typeinfo = &tinfo; + m_impl->m_needs_init = true; + + //boost::mutex::scoped_lock lock (BaseInfoBaseImpl::s_mutex); + if (!BaseInfoBaseImpl::s_bi_by_ti) + BaseInfoBaseImpl::s_bi_by_ti = new BaseInfoBaseImpl::bi_by_ti_map_type; + if (!BaseInfoBaseImpl::s_ti_by_name) + BaseInfoBaseImpl::s_ti_by_name = new BaseInfoBaseImpl::ti_by_name_map_type; + + // Register this instance in the static maps. + (*BaseInfoBaseImpl::s_bi_by_ti)[&tinfo] = this; + (*BaseInfoBaseImpl::s_ti_by_name)[tinfo.name()] = &tinfo; +} + + +/** + * @brief Destructor. + */ +BaseInfoBase::~BaseInfoBase() +{ + for (BaseInfoBaseImpl::ti_copyconversion_type::iterator it = + m_impl->m_ti_copyconversion_map.begin(); + it != m_impl->m_ti_copyconversion_map.end(); + ++it) + { + delete it->second; + } + delete m_impl; +} + + +/** + * @brief Find the @c BaseInfoBase instance for @c clid. + * @param clid The class ID of the class for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ +const BaseInfoBase* BaseInfoBase::find (CLID clid) +{ + //boost::mutex::scoped_lock lock (BaseInfoBaseImpl::s_mutex); + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return BaseInfoBase::find (*ti); + return 0; +} + + +/** + * @brief Helper for @c find. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ +const BaseInfoBase* BaseInfoBase::find1 (const std::type_info& tinfo) +{ + //boost::mutex::scoped_lock lock (BaseInfoBaseImpl::s_mutex); + if (!BaseInfoBaseImpl::s_bi_by_ti) return 0; + BaseInfoBaseImpl::bi_by_ti_map_type::iterator i = + BaseInfoBaseImpl::s_bi_by_ti->find (&tinfo); + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) { + if (!i->second->m_impl->m_needs_init) + return i->second; + i->second->m_impl->m_needs_init = false; + } + + // Try the initlist. + if (BaseInfoBaseImpl::s_init_list) { + while (true) { + BaseInfoBaseImpl::init_list_t::iterator it = + BaseInfoBaseImpl::s_init_list->find (&tinfo); + if (it == BaseInfoBaseImpl::s_init_list->end()) break; + BaseInfoBase::init_func_t* init = it->second; + BaseInfoBaseImpl::s_init_list->erase (it); + init(); + i = BaseInfoBaseImpl::s_bi_by_ti->find (&tinfo); + } + } + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) + return i->second; + + return 0; +} + + +/** + * @brief Find the @c BaseInfoBase instance for @c tinfo. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ +const BaseInfoBase* BaseInfoBase::find (const std::type_info& tinfo) +{ + const BaseInfoBase* bib = find1 (tinfo); + + // If we didn't find it, try looking up by name. + // This to deal with the issue of sometimes getting duplicate + // @c std::type_info instances. + if (!bib && BaseInfoBaseImpl::s_ti_by_name) { + BaseInfoBaseImpl::ti_by_name_map_type::iterator i = + BaseInfoBaseImpl::s_ti_by_name->find (tinfo.name()); + if (i != BaseInfoBaseImpl::s_ti_by_name->end() && i->second != &tinfo) + bib = find1 (*i->second); + } + + if (bib) { + BaseInfoBaseImpl& impl = *bib->m_impl; + if (impl.m_clid == CLID_NULL) + impl.m_clid = CLIDRegistry::typeinfoToCLID (*impl.m_typeinfo); + } + + return bib; +} + + +/** + * @brief Register an initialization function. + * @param tinfo The @c std::type_info for the class being registered. + * @param init_func Function to initialize @c BaseInfo for the class. + */ +void BaseInfoBase::addInit (const std::type_info* tinfo, + init_func_t* init_func) +{ + //boost::mutex::scoped_lock lock (BaseInfoBaseImpl::s_mutex); + if (!BaseInfoBaseImpl::s_init_list) + BaseInfoBaseImpl::s_init_list = + new BaseInfoBaseImpl::init_list_t; + BaseInfoBaseImpl::s_init_list->insert (std::make_pair (tinfo, init_func)); + + if (BaseInfoBaseImpl::s_bi_by_ti) { + auto i = BaseInfoBaseImpl::s_bi_by_ti->find (tinfo); + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) { + BaseInfoBaseImpl& impl = *i->second->m_impl; + impl.m_needs_init = true; + if (impl.m_clid == CLID_NULL) + impl.m_clid = CLIDRegistry::typeinfoToCLID (*tinfo); + } + } +} + + +/** + * @brief Run initializations for this class, if needed. + */ +void BaseInfoBase::maybeInit() +{ + if (m_impl->m_needs_init) + find (*m_impl->m_typeinfo); +} + + + +/// Declare the static members of @c BaseInfoBaseImpl. +BaseInfoBaseImpl::bi_by_ti_map_type* BaseInfoBaseImpl::s_bi_by_ti = 0; +BaseInfoBaseImpl::ti_by_name_map_type* BaseInfoBaseImpl::s_ti_by_name = 0; +BaseInfoBaseImpl::init_list_t* BaseInfoBaseImpl::s_init_list = 0; +//boost::mutex BaseInfoBaseImpl::s_mutex; + +// To get them deleted. +BaseInfoBaseImpl::Deleter BaseInfoBaseImpl::s_deleter; +BaseInfoBaseImpl::Deleter::~Deleter() +{ + delete s_bi_by_ti; + delete s_ti_by_name; + delete s_init_list; +} + + +// Helper for dumping within the debugger. +void dumpBaseInfo() +{ + std::cout << "map:\n"; + if (BaseInfoBaseImpl::s_bi_by_ti) { + std::vector<const std::type_info*> vv; + for (const auto& x : *BaseInfoBaseImpl::s_bi_by_ti) + vv.push_back (x.first); + std::sort (vv.begin(), vv.end()); + for (const std::type_info* ti : vv) + { + const BaseInfoBase* bib = (*BaseInfoBaseImpl::s_bi_by_ti)[ti]; + std::cout << ti << " " << bib->clid() << " [" << System::typeinfoName (*ti) + << "]\n"; + } + } + + std::cout << "\ninitlist:\n"; + if (BaseInfoBaseImpl::s_init_list) { + for (const auto& x : *BaseInfoBaseImpl::s_init_list) + std::cout << x.first << " " << x.second << " [" + << System::typeinfoName (*x.first) << "]\n"; + } +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/src/CLIDRegistry.cxx b/EDM/athena/Control/SGTools/src/CLIDRegistry.cxx new file mode 100644 index 00000000..89076f1b --- /dev/null +++ b/EDM/athena/Control/SGTools/src/CLIDRegistry.cxx @@ -0,0 +1,145 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SGTools/CLIDRegistry.h" +#include "CxxUtils/make_unique.h" +#include <unordered_map> +#include <memory> +/* #include <algorithm> */ +using namespace std; + +const unsigned long CLIDRegistry::MINCLID = CLIDdetail::MINCLID; +const unsigned long CLIDRegistry::MAXCLID = CLIDdetail::MAXCLID; + +namespace { +unsigned int alreadyDone (0); +} + + +// bool +// CLIDRegistry::addEntry(unsigned long id, const string& typeName) { +// assert( MINCLID <= id && id <= MAXCLID ); +// registry().push_back(pair<unsigned long, string>(id,typeName)); +// return true; +// } + + +CLIDRegistry::const_iterator CLIDRegistry::begin() { +#ifdef CLIDREG_DEBUG + cerr << "CLIDRegistry::begin: returns " + << &*(registry().begin()) << " for registry " <<®istry() + <<endl; +#endif + return registry().begin(); +} + + +CLIDRegistry::const_iterator CLIDRegistry::end() { +#ifdef CLIDREG_DEBUG + cerr << "CLIDRegistry::end: returns " + << &*(registry().end()) << " for registry " <<®istry() + <<endl; +#endif + return registry().end(); + //return unique(registry().begin(), registry().end()); //FIXME O(N)! +} + +bool +CLIDRegistry::hasNewEntries() { + return (alreadyDone < CLIDRegistry::registry().size()); +} + +std::pair<CLIDRegistry::const_iterator, CLIDRegistry::const_iterator> +CLIDRegistry::newEntries() { + std::pair<CLIDRegistry::const_iterator, CLIDRegistry::const_iterator> ret = + std::make_pair(CLIDRegistry::begin()+alreadyDone, + CLIDRegistry::end()); + alreadyDone = CLIDRegistry::registry().size(); + return ret; +} + + +CLIDRegistry::CLIDRegistryImpl& CLIDRegistry::registry() { + static CLIDRegistryImpl reg; + return reg; +} + + +namespace { +typedef std::unordered_map<unsigned long, const std::type_info*> clid_ti_map_t; +std::unique_ptr<clid_ti_map_t> clid_ti_map; + +typedef std::unordered_map<const std::type_info*, unsigned long> ti_clid_map_t; +std::unique_ptr<ti_clid_map_t> ti_clid_map; +} + + +/** + * @brief Add a new CLID <> type_info mapping. + * @param clid The CLID of the class. + * @param ti The @c type_info of the class. + */ +void CLIDRegistry::addCLIDMapping (unsigned long clid, const std::type_info& ti) +{ + if (!clid_ti_map) + clid_ti_map = CxxUtils::make_unique<clid_ti_map_t>(); + if (!ti_clid_map) + ti_clid_map = CxxUtils::make_unique<ti_clid_map_t>(); + + (*clid_ti_map)[clid] = &ti; + (*ti_clid_map)[&ti] = clid; +} + + +/** + * @brief Return the @c type_info corresponding to a CLID. + * @param clid The CLID to find. + * + * Returns the corresponding @c type_info or nullptr. + */ +const std::type_info* CLIDRegistry::CLIDToTypeinfo (unsigned long clid) +{ + if (clid_ti_map) { + auto i = clid_ti_map->find (clid); + if (i != clid_ti_map->end()) + return i->second; + } + return nullptr; +} + + +/** + * @brief Return the CLID corresponding to a @c type_info. + * @param ti The @c type_info to find. + * + * Returns the corresponding @c CLID or CLID_NULL. + */ +unsigned long CLIDRegistry::typeinfoToCLID (const std::type_info& ti) +{ + if (ti_clid_map) { + auto i = ti_clid_map->find (&ti); + if (i != ti_clid_map->end()) + return i->second; + } + return 0; +} + + +/// Out-of-line part of addEntry(). +bool CLIDRegistry::addEntry (unsigned long clid, + const std::type_info& ti, + const char* typeName, + const Athena::PackageInfo& pkgInfo, + const std::string& typeInfoName) +{ + registry().push_back(tuple_t(clid, std::string(typeName), pkgInfo, typeInfoName)); +#ifdef CLIDREG_DEBUG + std::cerr << "CLIDRegistry::addEntry: for CLID/type " + << clid << '/' << typeName << " to registry " <<®istry() + <<std::endl; +#endif + addCLIDMapping (clid, ti); + return true; +} + diff --git a/EDM/athena/Control/SGTools/src/CurrentEventStore.cxx b/EDM/athena/Control/SGTools/src/CurrentEventStore.cxx new file mode 100644 index 00000000..95d37be5 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/CurrentEventStore.cxx @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/src/CurrentEventStore.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2015 + * @brief Hold a pointer to the current event store. + */ + + +#include "SGTools/CurrentEventStore.h" + + +namespace SG { + + +IProxyDict* CurrentEventStore::m_curStore = nullptr; + + +/** + * @brief Set the current store. + * Returns the previous store. + */ +IProxyDict* CurrentEventStore::setStore (IProxyDict* store) +{ + IProxyDict* oldstore = m_curStore; + m_curStore = store; + return oldstore; +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/src/DataHandleBase.cxx b/EDM/athena/Control/SGTools/src/DataHandleBase.cxx new file mode 100644 index 00000000..74d886e7 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/DataHandleBase.cxx @@ -0,0 +1,249 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// DataHandleBase.cxx +// Implementation file for class DataHandleBase +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +// SGTools includes +#include "SGTools/DataHandleBase.h" + +// STL includes + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// + +/// Default constructor: +DataHandleBase::DataHandleBase() : + IResetable(), + m_itr(), + m_itrEnd(), + m_proxy(0), + //m_ptr(0), + m_useItr(false) +{} + +/// Copy constructor: +DataHandleBase::DataHandleBase( const DataHandleBase& rhs ) : + IResetable(), + m_itr(rhs.m_itr), + m_itrEnd(rhs.m_itrEnd), + m_proxy(rhs.m_proxy), + //m_ptr(rhs.m_ptr), + m_useItr(rhs.m_useItr) +{ + if (m_proxy) { + m_proxy->addRef(); + } +} + + +/// Assignment operator: +DataHandleBase& +DataHandleBase::operator=( const DataHandleBase& rhs ) +{ + if (this != &rhs) { + if (m_proxy) { + m_proxy->release(); + } + + m_itr = rhs.m_itr; + m_itrEnd = rhs.m_itrEnd; + m_useItr = rhs.m_useItr; + m_proxy = rhs.m_proxy; + //m_ptr = rhs.m_ptr; + if (m_proxy) { + m_proxy->addRef(); + } + } + + return *this; +} + +/// Constructor with parameters: +DataHandleBase::DataHandleBase(SG::DataProxy* proxy) : + IResetable(), + m_itr(), + m_itrEnd(), + m_proxy(proxy), + //m_ptr(0), + m_useItr(false) +{ + if (m_proxy) { + m_proxy->addRef(); + } +} + +DataHandleBase::DataHandleBase(const SG::ConstProxyIterator& itr, + const SG::ConstProxyIterator& itrEnd) : + IResetable(), + m_itr(itr), + m_itrEnd(itrEnd), + m_proxy(0), + //m_ptr(0), + m_useItr(true) +{ + if (m_itr != m_itrEnd) { + m_proxy = m_itr->second; + } + + if (m_proxy) { + m_proxy->addRef(); + } +} + + +/// Destructor: +DataHandleBase::~DataHandleBase() +{ + if (m_proxy != 0) { + m_proxy->unbindHandle(this); + m_proxy->release(); + } +} + +// Destructor +/////////////// + +/////////////////////////////////////////////////////////////////// +// Const methods: +/////////////////////////////////////////////////////////////////// + +StatusCode +DataHandleBase::setState(SG::ConstProxyIterator &itr, + const SG::ConstProxyIterator &itrEnd) const +{ + if (m_proxy) m_proxy->release(); + + m_itr = itr; + m_itrEnd = itrEnd; + m_useItr = true; + + // ouch! FIXME ? + // we could have a void* m_ptr data member and have a + // typeless_dataPointer method using the typeless machinery of + // DataProxy+DataBucketBase... + const_cast<DataHandleBase*>(this)->reset (false); + + // scan from itr to itrEnd and set m_itr to the first valid iterator: + + for (; itr != itrEnd; itr++) { + if (itr->second->isValid()) { + m_itr = itr; + m_proxy = m_itr->second; + if (m_proxy) m_proxy->addRef(); + return StatusCode::SUCCESS; + } + } + + m_itr = itrEnd; + m_proxy = 0; + + return StatusCode::FAILURE; +} + +StatusCode +DataHandleBase::setState(SG::DataProxy* proxy) const +{ + if (0 == proxy || !proxy->isValid()) { + return StatusCode::FAILURE; + } + + if (m_proxy != proxy) { + if (m_proxy) m_proxy->release(); + m_proxy = proxy; + m_proxy->addRef(); + } + + m_useItr = false; + const_cast<DataHandleBase*>(this)->reset (false); + + return StatusCode::SUCCESS; +} + +StatusCode +DataHandleBase::setState(IProxyDict* store, const ID_type& key) const +{ + if (0 == store) { + return StatusCode::FAILURE; + } + CLID cid = this->clid(); + SG::DataProxy* proxy = store->proxy(cid, key); + return this->setState(proxy); +} + +const std::string& +DataHandleBase::key() const +{ + if (m_itr == m_itrEnd) { + return m_proxy->name(); + } else { + return m_itr->first; + } +} + +bool +DataHandleBase::isConst() const +{ + return 0 != m_proxy + ? m_proxy->isConst() + : false; +} + + +// A weaker test that +// *does not* retrieve the GaudiObject to check validity if not already done +bool +DataHandleBase::isInitialized() const +{ + return (0 != m_proxy); +} + +/////////////////////////////////////////////////////////////////// +// Non-const methods: +/////////////////////////////////////////////////////////////////// + +StatusCode +DataHandleBase::setState(SG::DataProxy* proxy) +{ + if (0 == proxy || !proxy->isValid() || proxy->isConst()) { + return StatusCode::FAILURE; + } + + if (m_proxy != proxy) { + if (m_proxy) m_proxy->release(); + m_proxy = proxy; + m_proxy->addRef(); + } + + m_useItr = false; + this->reset (false); + return StatusCode::SUCCESS; +} + +StatusCode +DataHandleBase::setState(IProxyDict* store, const ID_type& key) +{ + if (0 == store) { + return StatusCode::FAILURE; + } + CLID cid = this->clid(); + SG::DataProxy* proxy = store->proxy(cid, key); + return this->setState(proxy); +} + +/////////////////////////////////////////////////////////////////// +// Protected methods: +/////////////////////////////////////////////////////////////////// + + diff --git a/EDM/athena/Control/SGTools/src/DataProxy.cxx b/EDM/athena/Control/SGTools/src/DataProxy.cxx new file mode 100644 index 00000000..c02db351 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/DataProxy.cxx @@ -0,0 +1,416 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <algorithm> + +#include <cassert> +#include <stdexcept> + +#include "AthenaKernel/IResetable.h" +#include "AthenaKernel/getMessageSvc.h" + +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IConversionSvc.h" +#include "GaudiKernel/GenericAddress.h" +#include "GaudiKernel/MsgStream.h" + +#include "SGTools/TransientAddress.h" +#include "SGTools/T2pMap.h" +#include "SGTools/DataBucketBase.h" +#include "SGTools/CurrentEventStore.h" +#include "AthenaKernel/IProxyDict.h" + +#include "SGTools/DataProxy.h" +using SG::DataProxy; +using SG::TransientAddress; +using std::find; + + +namespace { + ///sets pMember to pgref (resetting it if pgref is 0). Handles Gaudi refcount + template <class GAUDIREF> + void setGaudiRef(GAUDIREF* pgref, GAUDIREF*& pMember) { + if (0 != pgref) pgref->addRef(); + if (0 != pMember) pMember->release(); + pMember = pgref; + } + + ///resets pMember. Handles Gaudi refcount + template <class GAUDIREF> + void resetGaudiRef(GAUDIREF*& pMember) { setGaudiRef((GAUDIREF*)0, pMember); } + +} //end of unnamed namespace + +// Default Constructor +DataProxy::DataProxy(): + m_tAddress(new TransientAddress()), + m_refCount(0), + m_dObject(0), + m_dataLoader(0), + m_const(false), + m_origConst(false), + m_storageType(0), + m_resetFlag(true), + m_t2p(0), + m_errno(ALLOK), + m_store(0) +{ +} + +// DataProxy constructor with Transient Address +// (typically called from Proxy Provider) +DataProxy::DataProxy(TransientAddress* tAddr, + IConversionSvc* svc, + bool constFlag, bool resetOnly): + m_tAddress(tAddr), + m_refCount(0), + m_dObject(0), + m_dataLoader(svc), + m_const(constFlag), + m_origConst(constFlag), + m_storageType(0), + m_resetFlag(resetOnly), + m_t2p(0), + m_errno(ALLOK), + m_store(0) +{ + //assert( tAddr->clID() != 0 ); + if (svc) svc->addRef(); +} + +// with Data Object: +// (typically called from a StoreGate record +DataProxy::DataProxy(DataObject* dObject, + TransientAddress* tAddr, + bool constFlag, bool resetOnly): + m_tAddress(tAddr), + m_refCount(0), + m_dObject(0), + m_dataLoader(0), + m_const(constFlag), + m_origConst(constFlag), + m_storageType(0), + m_resetFlag(resetOnly), + m_t2p(0), + m_errno(ALLOK), + m_store(0) +{ + setObject(dObject); +} + +// Destructor +DataProxy::~DataProxy() +{ + finalReset(); + delete m_tAddress; +} + +void DataProxy::setT2p(T2pMap* t2p) +{ + m_t2p = t2p; +} + + +/** + * @brief Mark this object as const. (Lock the object.) + * + * If the object held that derives from @c ILockable, then we also + * call @c lock on the object. + */ +void DataProxy::setConst() +{ + m_const = true; + lock(); +} + +bool DataProxy::bindHandle(IResetable* ir) { + assert(ir); + if (ir->isSet()) { + return false; + } else { + m_handles.push_back(ir); + if (m_store) + m_store->boundHandle(ir); + return true; + } +} + + + +void DataProxy::reset (bool hard /*= false*/) +{ + + if (! m_handles.empty()) { resetBoundHandles (hard); } + + resetGaudiRef(m_dObject); + m_tAddress->reset(); + m_const = m_origConst; + +} + +void DataProxy::finalReset() +{ + m_const=false; //hack to force the resetting of proxy ptr in VarHandleBase + + for (auto ih: m_handles) { + if (0 != ih) ih->finalReset(); + } + + resetGaudiRef(m_dObject); + resetGaudiRef(m_dataLoader); +} + +/// don't need no comment +void DataProxy::resetBoundHandles (bool hard) { + auto i = m_handles.begin(); + auto iEnd = m_handles.end(); + while (i != iEnd) { + // std::cout << "resetBoundHandles loop " << *i << std::endl; + if (0 == *i) { + i = m_handles.erase(i); //NULL IResetable* means handle was unbound + } else { + (*(i++))->reset(hard); + } + } +} + +void DataProxy::unbindHandle(IResetable *ir) { + assert(ir); + // std::cout << "unbindHandle " << ir << std::endl; + auto ifr = find(m_handles.begin(), m_handles.end(), ir ); + //reset the entry for ir instead of deleting it, so this can be called + //within a m_handles loop + if (ifr != m_handles.end()) { + *ifr=0; + if (m_store) + m_store->unboundHandle(ir); + } +} + +/// return refCount +unsigned long DataProxy::refCount() const +{ + return m_refCount; +} + +/// Add reference to object +unsigned long DataProxy::addRef() +{ + return ++m_refCount; +} + +/// release reference to object +unsigned long DataProxy::release() +{ + unsigned long count(--m_refCount); + if ( 0 == count ) delete this; + return count; +} + + +///request to release the instance (may just reset it) +bool DataProxy::requestRelease(bool force, bool hard) { + + //this needs to happen no matter what + if (! m_handles.empty()) { resetBoundHandles(hard); } + + bool canRelease = !isResetOnly() || force; +#ifndef NDEBUG + MsgStream gLog(m_ims, "DataProxy"); + if (gLog.level() <= MSG::VERBOSE) { + gLog << MSG::VERBOSE << "requestRelease(): " + << (canRelease ? " release " : " reset") + <<" object " + << name() << " CLID " << clID() << " address " << MSG::hex + << object() << MSG::dec << endmsg; + } +#endif + if (canRelease) release(); + else reset(hard); + return canRelease; +} + +/// set a DataObject address +void DataProxy::setObject(DataObject* dObject) +{ + setGaudiRef(dObject, m_dObject); + if (0 != m_dObject) { + m_dObject->setRegistry(this); + if (m_const) lock(); + } +} + + +// set IOpaqueAddress +void DataProxy::setAddress(IOpaqueAddress* address) +{ + m_tAddress->setAddress(address); +} +////////////////////////////////////////////////////////////// + + +/** + * @brief Read in a new copy of the object referenced by this proxy. + * @param errNo If non-null, set to the resulting error code. + * + * If this proxy has an associated loader and address, then load + * a new copy of the object and return it. Any existing copy + * held by the proxy is unaffected. + * + * This will fail if the proxy does not refer to an object read from an + * input file. + */ +std::unique_ptr<DataObject> DataProxy::readData (ErrNo* errNo) const +{ + if (errNo) *errNo = ALLOK; + + if (0 == m_dataLoader) { + //MsgStream gLog(m_ims, "DataProxy"); + //gLog << MSG::WARNING + // << "accessData: IConversionSvc ptr not set" <<endmsg; + if (errNo) *errNo=NOCNVSVC; + return nullptr; + } + if (!isValidAddress()) { + //MsgStream gLog(m_ims, "DataProxy"); + //gLog << MSG::WARNING + // << "accessData: IOA pointer not set" <<endmsg; + if (errNo) *errNo=NOIOA; + return nullptr; + } + + SG::CurrentEventStore::Push push (m_store); + + DataObject* obj = nullptr; + StatusCode sc = m_dataLoader->createObj(m_tAddress->address(), obj); + if (sc.isSuccess()) + return std::unique_ptr<DataObject>(obj); + if (errNo) *errNo = CNVFAILED; + return nullptr; +} + + +/// Access DataObject on-demand using conversion service +DataObject* DataProxy::accessData() +{ + if (0 != m_dObject) return m_dObject; // cached object + + if (isValidAddress()) { + // An address provider called by isValidAddress may have set the object + // pointer directly, rather than filling in the address. So check + // the cached object pointer again. + if (0 != m_dObject) return m_dObject; // cached object + } + + std::unique_ptr<DataObject> obju = readData (&m_errno); + if (!obju) { + if (m_errno == NOIOA) { + MsgStream gLog(m_ims, "DataProxy"); + gLog << MSG::WARNING + << "accessData: IOA pointer not set" <<endmsg; + } + else if (m_errno == CNVFAILED) { + MsgStream gLog(m_ims, "DataProxy"); + gLog << MSG::WARNING + << "accessData: conversion failed for data object " + <<m_tAddress->clID() << '/' << m_tAddress->name() << '\n' + <<" Returning NULL DataObject pointer " << endmsg; + } + setObject(0); + return 0; + } + + DataObject* obj = obju.release(); + setObject(obj); + DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(obj); + if (bucket) { + void* payload = bucket->object(); + m_t2p->t2pRegister(payload, this); + m_errno=ALLOK; + + // Register bases as well. + const SG::BaseInfoBase* bi = SG::BaseInfoBase::find (m_tAddress->clID()); + if (bi) { + std::vector<CLID> base_clids = bi->get_bases(); + for (unsigned i=0; i < base_clids.size(); ++i) { + void* bobj = SG::DataProxy_cast (this, base_clids[i]); + if (bobj && bobj != payload) + m_t2p->t2pRegister (bobj, this); + } + } + } + else { + MsgStream gLog(m_ims, "DataProxy"); + gLog << MSG::ERROR + << "accessData: ERROR registering object in t2p map" + <<m_tAddress->clID() << '/' << m_tAddress->name() << '\n' + <<" Returning NULL DataObject pointer " << endmsg; + obj=0; + setObject(0); + m_errno=T2PREGFAILED; + } + + return obj; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +bool DataProxy::isValidAddress() const +{ + return (0 != m_tAddress && m_tAddress->isValid()); +} + +bool DataProxy::isValidObject() const +{ + // FIXME: should we try to chase? + return (0!= m_dObject); +} + +bool DataProxy::isValid() const +{ + return (isValidObject() || isValidAddress()); +} + + +/** + * @brief Try to get the pointer back from a @a DataProxy, + * converted to be of type @a clid. + * @param proxy The @a DataProxy. + * @param clid The ID of the class to which to convert. + * + * Only works if the held object is a @a DataBucket. + * Returns 0 on failure, + */ +void* SG::DataProxy_cast (SG::DataProxy* proxy, CLID clid) +{ + if (0 == proxy || !proxy->isValid()) + return 0; + DataObject* pObject = proxy->accessData(); + if (0 == pObject) + return 0; + return SG::Storable_cast (pObject, clid, proxy, proxy->isConst()); +} + + +/** + * @brief Register a transient object in a t2p map. + * @param trans The object to register. + */ +void DataProxy::registerTransient (void* p) +{ + if (m_t2p) + m_t2p->t2pRegister (p, this); +} + + +/** + * @brief Lock the data object we're holding, if any. + */ +void DataProxy::lock() +{ + DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(m_dObject); + if (bucket) + bucket->lock(); +} + diff --git a/EDM/athena/Control/SGTools/src/DataStore.cxx b/EDM/athena/Control/SGTools/src/DataStore.cxx new file mode 100644 index 00000000..bdd7a3bd --- /dev/null +++ b/EDM/athena/Control/SGTools/src/DataStore.cxx @@ -0,0 +1,490 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SGTools/DataStore.h" +#include "SGTools/DataProxy.h" +#include "SGTools/exceptions.h" +#include "AthenaKernel/IStringPool.h" +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/ISvcLocator.h" +#include "SGAudCore/ISGAudSvc.h" + +using namespace std; +using SG::DataStore; +using SG::DataProxy; +using SG::ProxyMap; +using SG::ProxyIterator; +using SG::ConstProxyIterator; + + +/** + * @brief Constructor. + * @param pool The string pool associated with this store. + */ +DataStore::DataStore (IProxyDict& pool) + : m_pool (pool), + m_storeMap(), m_storeID(StoreID::UNKNOWN), m_t2p(), + m_pSGAudSvc(0), m_noAudSvc(0), m_pSvcLoc(0) +{ + setSvcLoc().ignore(); +} + +//Destructor +DataStore::~DataStore() +{ + clearStore(false, true, nullptr); +} + +StatusCode DataStore::setSvcLoc(){ + StatusCode sc(StatusCode::FAILURE); + m_pSvcLoc = Gaudi::svcLocator( ); + if (!m_pSvcLoc) std::cout<<"DataStore::setSvcLoc: WARNING svcLocator not found! "<<std::endl; + return sc; +} + +void DataStore::setSGAudSvc() const { //m_noAudSvc and m_pSGAudSvc are mutable + if (0 == m_pSGAudSvc) { + //try once to get the service + const bool DONOTCREATE(false); + if (!m_noAudSvc) { + m_noAudSvc = m_pSvcLoc->service("SGAudSvc", m_pSGAudSvc, + DONOTCREATE).isFailure(); + } + } + return; +} + + +////////////////////////////////////////////////////////////// +void DataStore::clearStore(bool force, bool hard, MsgStream* pmlog) +{ + + for (StoreMap::value_type& m : m_storeMap) + { + + ProxyMap& pmap = m.second; + + ProxyIterator iter = pmap.begin(); + ProxyIterator end = pmap.end(); + + while (iter != end) { + + if (pmlog) { + *pmlog << MSG::VERBOSE + << "DataStore::clearStore() " + << (force ? "forcing" : "requesting") + << " release of DataProxy @" << iter->second + << ", recorded with key=" << iter->second->name() + << ", CLID=" << iter->second->clID() + << ", containing data object @" << iter->second->object(); + pmlog->flush(); //make sure this is printed now + } + if (iter->second->requestRelease(force, hard)) { //request proxy deletion + //proxy was released, remove map entry + sgkey_t sgkey = m_pool.stringToKey (iter->first, m.first); + m_keyMap.erase (sgkey); + + pmap.erase(iter++); //increment the pre-erase iterator (Effective STL Item 9) + } else { + //proxy was reset, keep map entry + ++iter; + } + if(pmlog) *pmlog << MSG::VERBOSE << " ... -> DONE" << endmsg; + } + } + + // clear T2PMap + m_t2p.clear(); +} + +///////////////////////////////////////////////////////////// +// access all the keys associated with an object: +// +void DataStore::keys(const CLID& id, std::vector<std::string>& vkeys, + bool includeAlias, bool onlyValid) +{ + vector<string> tkeys; + ProxyMap& pmap = m_storeMap[id]; + ConstProxyIterator p_iter = pmap.begin(); + for (; p_iter != pmap.end(); p_iter++) { + bool includeProxy(true); + if (onlyValid) includeProxy=p_iter->second->isValid(); + if (includeAlias) { + if (includeProxy) tkeys.push_back(p_iter->first); + } + else { + if (p_iter->first == p_iter->second->name() && includeProxy) + tkeys.push_back(p_iter->first); + } + } + vkeys.swap(tkeys); + return; +} + +////////////////////////////////////////////////////////////// +//---------------------------------------------------------------// +// record the proxy in StoreGate +StatusCode +DataStore::addToStore(const CLID& id, DataProxy* dp) +{ + StatusCode sc(StatusCode::FAILURE); + if (0 != dp) { + TransientAddress* tad = dp->transientAddress(); + + if (id == 0 && tad->clID() == 0 && tad->sgkey() != 0) { + // Handle a dummied proxy. + m_keyMap[tad->sgkey()] = dp; + } + else { + ProxyMap& pmap = m_storeMap[id]; + + // Set the primary key. + sgkey_t primary_sgkey = m_pool.stringToKey (tad->name(), tad->clID()); + tad->setSGKey (primary_sgkey); + + pmap.insert(ProxyMap::value_type(dp->name(), dp)); + + sgkey_t sgkey = primary_sgkey; + if (id != tad->clID()) + sgkey = m_pool.stringToKey (tad->name(), id); + m_keyMap[sgkey] = dp; + } + + // Note : No checking if proxy already exists in store because it + // is already checked in StoreGateSvc. + // if (pmap.find(dp->name()) == pmap.end()) { + dp->addRef(); // The store now owns this + dp->setT2p(&m_t2p); + dp->setStore(&m_pool); + + sc = StatusCode::SUCCESS; + // } else { + // std::cout << "!!!!!!!!!!!! Dupe found in store " << this << "CLID/KEY" << id << "/" << dp->name() << std::endl; + // } + } + return sc; + +} + +////////////////////////////////////////////////////////////////// +//---------------------------------------------------------------// +// if Proxy is a resettable proxy only then reset it, otherwise +// delete it and remove from proxy map. +StatusCode +DataStore::removeProxy(DataProxy* proxy, bool forceRemove, bool hard) +{ + StatusCode sc(StatusCode::FAILURE); + if (0 == proxy) return sc; + + if (!forceRemove && proxy->isResetOnly()) { + proxy->reset (hard); + sc = StatusCode::SUCCESS; + } else { + + SG::DataProxy::CLIDCont_t clids = proxy->transientID(); + std::string name = proxy->name(); + sgkey_t primary_sgkey = proxy->transientAddress()->sgkey(); + + StoreIterator storeIter = m_storeMap.find(proxy->clID()); + if (storeIter != m_storeMap.end()) { + CLID clid = proxy->clID(); + // first remove the alias key: + ProxyMap& pmap = m_storeMap[clid]; + SG::DataProxy::AliasCont_t alias_set = proxy->alias(); + for (SG::DataProxy::AliasCont_t::const_iterator i = alias_set.begin(); + i != alias_set.end(); ++i) + { + m_keyMap.erase (m_pool.stringToKey (*i, clid)); + if (1 == pmap.erase(*i)) proxy->release(); + } + + // then remove the primary key + m_keyMap.erase (primary_sgkey); + if (1 == storeIter->second.erase(name)) { + proxy->release(); + sc = StatusCode::SUCCESS; + } + + // Remove all symlinks too. + for (SG::DataProxy::CLIDCont_t::const_iterator i = clids.begin(); + i != clids.end(); ++i) + { + storeIter = m_storeMap.find(*i); + if (storeIter != m_storeMap.end()) { + m_keyMap.erase (m_pool.stringToKey (name, *i)); + if (1 == storeIter->second.erase(name)) + proxy->release(); + } + } //symlinks loop + } //proxy there + } //reset only + return sc; +} + +////////////////////////////////////////////////////////////// +//---------------------------------------------------------------// +// record the symlink in StoreGate +StatusCode +DataStore::addSymLink(const CLID& linkid, DataProxy* dp) +{ + // Make sure the symlink doesn't already exist. + DataProxy* exist = proxy_exact (linkid, dp->name()); + if (exist == dp) { + // Entry already exists pointing at the desired proxy. + return StatusCode::SUCCESS; + } + else if (exist != 0) { + // Entry already exists pointing at another proxy. + // Don't change the existing entry. + return StatusCode::FAILURE; + } + + dp->transientAddress()->setTransientID(linkid); + return addToStore(linkid, dp); +} +//---------------------------------------------------------------// +// record the alias in StoreGate +StatusCode +DataStore::addAlias(const std::string& aliasKey, DataProxy* dp) +{ + // locate proxy map and add alias to proxymap + ProxyMap& pmap = m_storeMap[dp->clID()]; + + // check if another proxy for the same type caries the same alias. + // if yes, then remove that alias from that proxy and establish the + // alias in the new proxy. + // pmap.insert will overwrite, associate alias with new proxy. + ConstProxyIterator p_iter = pmap.find(aliasKey); + if (p_iter != pmap.end() && dp->clID() == p_iter->second->clID()) { + if (dp->name() == p_iter->second->name()) return StatusCode::SUCCESS; + p_iter->second->transientAddress()->removeAlias(aliasKey); + p_iter->second->release(); + } + // set alias in proxy + dp->transientAddress()->setAlias(aliasKey); + dp->addRef(); + pmap[aliasKey] = dp; + m_keyMap[m_pool.stringToKey (aliasKey, dp->clID())] = dp; + // pmap.insert(ProxyMap::value_type(aliasKey, dp)); + // use [] as it overwrites, .insert ignores second entry + + return StatusCode::SUCCESS; +} +//---------------------------------------------------------------// +// Count instances of TYPE in store +int DataStore::typeCount(const CLID& id) const +{ + ConstStoreIterator storeIter = m_storeMap.find(id); + if (storeIter == m_storeMap.end()) return 0; + return (storeIter->second).size(); +} + +//---------------------------------------------------------------// +// Return proxy for a given Transient Address +DataProxy* DataStore::proxy(const TransientAddress* tAddr) const +{ + return proxy(tAddr->clID(), tAddr->name()); +} + +// Return proxy for a given Transient ID (TYPE and KEY) +DataProxy* DataStore::proxy(const CLID& id, const std::string& key) const +{ + + // The logic here: if a key is specified, we locate it. + // If we don't find it and the default key (DEFAULTKEY) is specified, + // then we return any existing proxy for this type as long as there + // is exactly one, not counting aliases. More than one would be ambiguous + + ConstStoreIterator siter = m_storeMap.find(id); + DataProxy *p(0); + if (siter != m_storeMap.end()) + { + const ProxyMap& pmap = siter->second; + ConstProxyIterator p_iter = pmap.find(key); + if (p_iter != pmap.end()) { + p=p_iter->second; + + } else if (key == SG::DEFAULTKEY && !pmap.empty()) { + // we did not find the object using key. + // Now check for default object. + // Simple case first --- single object. + if (pmap.size() == 1) { + p = pmap.begin()->second; + } else { + // Otherwise, match only the exact type requested. + ConstProxyIterator p_match = pmap.end(); + size_t nmatch = 0; + for (p_iter = pmap.begin(); p_iter != pmap.end(); ++p_iter) { + if (p_iter->second->transientAddress()->clID() == id) { + ++nmatch; + if (p_match == pmap.end()) p_match = p_iter; + } + } + + // We must have matched only one object, not counting its aliases. + // Notice: we test that there are less than two matches: symlinked objects + // may carry aliases from the concrete class. In that case nmatch + // may be equal to or even smaller than the number of aliases + if (nmatch > 0 && + (int(nmatch - p_match->second->alias().size()) < 2)) + { + p = pmap.begin()->second; + } + } + } + else { + p = const_cast<DataStore*>(this)->findDummy (id, key); + } + } + else { + p = const_cast<DataStore*>(this)->findDummy (id, key); + } + + if (p && doAudit()) + m_pSGAudSvc->SGAudit(p->transientAddress()->name(), id, 0, m_storeID); + + return p; +} + + +/** + * @brief Look for (and convert) a matching dummy proxy. + * @param id The CLID for which to search. + * @param key The key for which to search. + * + * In some cases, we may enter into the store a `dummy' proxy, + * which is identified only by the hashed CLID/key pair. + * (This can happen when we have a link to an object that's not + * listed in the DataHeader; in this case, we know the only hashed key + * and not the CLID or key.) + * + * This function is called after we fail to find a proxy by CLID/key. + * It additionally checks to see if there exists a dummy proxy with + * a hash matching this CLID/key. If so, the CLID/key are filled + * in in the proxy, and the proxy is entered in m_storeMap. + * + * Returns either the matching proxy or 0. + */ +DataProxy* DataStore::findDummy (CLID id, const std::string& key) +{ + sgkey_t sgkey = m_pool.stringToKey (key, id); + DataProxy* p = proxy_exact (sgkey); + if (p) { + p->transientAddress()->setID (id, key); + ProxyMap& pmap = m_storeMap[id]; + if (!pmap.insert(ProxyMap::value_type(key, p)).second) { + // This shouldn't happen. + DataProxy* p2 = pmap[key]; + throw SG::ExcProxyCollision (id, key, p2->clID(), p2->name()); + } + } + return p; +} + + +/// get proxy with given key. Returns 0 to flag failure +/// the key must match exactly (no wild carding for the default key) +DataProxy* DataStore::proxy_exact(sgkey_t sgkey) const +{ + if (doAudit()) { + CLID clid; + const std::string* strkey = m_pool.keyToString (sgkey, clid); + if (strkey) + m_pSGAudSvc->SGAudit(*strkey, clid, 0, m_storeID); + } + KeyMap_t::const_iterator i = m_keyMap.find (sgkey); + if (i != m_keyMap.end()) + return i->second; + return 0; +} + + +/// get proxy with given key. Returns 0 to flag failure +/// the key must match exactly (no wild carding for the default key) +DataProxy* DataStore::proxy_exact(const CLID& id, + const std::string& key) const +{ + return proxy_exact (m_pool.stringToKey (key, id)); +} + + +//---------------------------------------------------------------// +// Return an iterator over proxies for a given CLID: +StatusCode DataStore::pRange(const CLID& id, ConstProxyIterator& pf, + ConstProxyIterator& pe) const +{ + static const ProxyMap emptyMap; + StatusCode sc(StatusCode::FAILURE); + + ConstStoreIterator storeIter = m_storeMap.find(id); + if (storeIter != m_storeMap.end()) + { + const ProxyMap& pmap = storeIter->second; + pf = pmap.begin(); + pe = pmap.end(); + if (pmap.size() > 0) sc = StatusCode::SUCCESS; + } else { + //keep valgrind happy + pf = emptyMap.end(); + pe = emptyMap.end(); + } + return sc; +} +//---------------------------------------------------------------// +// Return an iterator over the Store Map +StatusCode DataStore::tRange(ConstStoreIterator& tf, + ConstStoreIterator& te) const +{ + tf = m_storeMap.begin(); + te = m_storeMap.end(); + return StatusCode::SUCCESS; +} +//---------------------------------------------------------------// +// Build a list of proxies that are in the Store: +StatusCode DataStore::proxyList(std::list<DataProxy*>& plist) const +{ + ConstProxyIterator pf, pe; + ConstStoreIterator sf, se; + (tRange(sf, se)).ignore(); + for (; sf!=se; sf++) + { + (pRange(sf->first, pf, pe)).ignore(); + for (; pf!=pe; pf++) { + // FIXME : Check validity of proxy. + plist.push_back(pf->second); + } + } + return StatusCode::SUCCESS; +} +//---------------------------------------------------------------// +// locate Persistent Representation of a Transient Object +// +DataProxy* DataStore::locatePersistent(const void* const pTransient) const +{ + return m_t2p.locatePersistent(pTransient); +} + +////////////////////////////////////////////////////////////////// +StatusCode +DataStore::t2pRegister(const void* const pTrans, DataProxy* const pPers) +{ + std::string name=pPers->name(); + int i=name.find("/", 0); + name=name.erase(0,i+1); + + if (doAudit()) m_pSGAudSvc->SGAudit(name, pPers->clID(), 1, m_storeID); + + return (m_t2p.t2pRegister(pTrans, pPers)) ? + StatusCode::SUCCESS : + StatusCode::FAILURE; +} + + + + + + + diff --git a/EDM/athena/Control/SGTools/src/SGFolderItem.cxx b/EDM/athena/Control/SGTools/src/SGFolderItem.cxx new file mode 100644 index 00000000..ef7d496b --- /dev/null +++ b/EDM/athena/Control/SGTools/src/SGFolderItem.cxx @@ -0,0 +1,12 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SGTools/SGFolderItem.h" + +bool +SG::FolderItem::isFolder() const { + return false; + //FIXME return (m_id == ClassID_traits<Folder>::ID()); +} + diff --git a/EDM/athena/Control/SGTools/src/SGToolsClids.cxx b/EDM/athena/Control/SGTools/src/SGToolsClids.cxx new file mode 100644 index 00000000..0b2040e8 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/SGToolsClids.cxx @@ -0,0 +1,9 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// anchor for the clids defined by this package + +#include "SGTools/BuiltinsClids.h" +#include "SGTools/StlMapClids.h" +#include "SGTools/StlVectorClids.h" diff --git a/EDM/athena/Control/SGTools/src/SGVersionedKey.cxx b/EDM/athena/Control/SGTools/src/SGVersionedKey.cxx new file mode 100644 index 00000000..dd16d319 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/SGVersionedKey.cxx @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <stdexcept> +#include <cassert> +#include "SGTools/SGVersionedKey.h" +using namespace SG; +using namespace std; + +VersionedKey::~VersionedKey() {} + +bool +VersionedKey::isVersionedKey(const char * vkey) { + return (vkey[0]==separator() && vkey[3]==separator()); +} + +bool +VersionedKey::isVersionedKey(const std::string& vkey) { + return isVersionedKey(vkey.c_str()); +} + +bool +VersionedKey::isAuto(const std::string& vkey) { + return (vkey.substr(0,4) == VersionedKey::autoVS()); +} + +VersionedKey::VersionedKey(const char* key, unsigned char version) { + encode(std::string(key), version); +} +VersionedKey::VersionedKey(const std::string& key, unsigned char version) { + encode(key, version); +} +VersionedKey::VersionedKey(const std::string& versionedKey) { + copyVK(versionedKey); +} +VersionedKey::VersionedKey(const char* versionedKey) { + copyVK(std::string(versionedKey)); +} +VersionedKey::VersionedKey(const VersionedKey& versionedKey) : + m_versionKey(versionedKey.m_versionKey) {} + +void VersionedKey::decode(std::string& outKey, unsigned char& version) const { + outKey = this->key(); + version = (unsigned char)atoi(m_versionKey.substr(1,2).c_str()); + assert(version <= 99); +} + +void VersionedKey::encode(const std::string& inKey, unsigned char version) { + assert(version <= 99); + char vers[5]; + snprintf(vers, 5, versionFormatString(), version); + m_versionKey = vers + inKey; +} + +void VersionedKey::copyVK(const std::string& inKey) { + if (isVersionedKey(inKey)) { + m_versionKey = inKey; + } else { + encode(inKey, 0); //FIXME should autoincrement + } +} +unsigned char VersionedKey::version() const { + return (unsigned char) std::stoul(m_versionKey.substr(1,2), nullptr, 0); +} +/// @returns base key +const std::string& VersionedKey::key() const { + if (m_baseKey.empty()) { + m_baseKey = m_versionKey.substr(4); + } + return m_baseKey; +} + +bool +VersionedKey::sameKey(const VersionedKey& vkey) const { + return (this->key() == vkey.key()); +} + +bool +VersionedKey::sameKey(const std::string& baseKey) const { + return (this->key() == baseKey); +} + +bool +VersionedKey::sameKey(const char* baseKey) const { + return (this->key() == std::string(baseKey)); +} + +/// sort according to highest key version +bool operator < (const SG::VersionedKey& lhs, const SG::VersionedKey& rhs) { + std::string lhskey; + unsigned char lhsVersion(0); + lhs.decode(lhskey, lhsVersion); + unsigned char rhsVersion(0); + std::string rhskey; + rhs.decode(rhskey, rhsVersion); + int keyCompare(strcmp(lhskey.c_str(), rhskey.c_str())); + return ( ( keyCompare < 0) || + ( (keyCompare == 0) && (lhsVersion < rhsVersion) ) ) ; + +} diff --git a/EDM/athena/Control/SGTools/src/StorableConversions.cxx b/EDM/athena/Control/SGTools/src/StorableConversions.cxx new file mode 100644 index 00000000..9f43eea2 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/StorableConversions.cxx @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file StorableConversions.cxx + * @brief convert to and from a SG storable + * $Id: StorableConversions.cxx,v 1.2 2008-04-08 16:05:32 ssnyder Exp $ + * @author ATLAS Collaboration + **/ + +#include "SGTools/StorableConversions.h" + + +namespace SG { + + +/** + * @brief Try to get the pointer back from a @a DataObject, + * converted to be of type @a clid. + * @param pDObj The @a DataObject. + * @param clid The ID of the class to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + * + * Only works if the @a DataObject is a @a DataBucket. + * Returns 0 on failure, + */ +void* fromStorable(DataObject* pDObj, CLID clid, + IRegisterTransient*irt/*= 0*/, + bool isConst /*= true*/) +{ + // Try to use BaseInfo information to convert pointers. + DataBucketBase* b = dynamic_cast<DataBucketBase*>(pDObj); + if (b) + return b->cast (clid, irt, isConst); + return 0; +} + + +/** + * @brief Try to get the pointer back from a @a DataObject, + * converted to be of type @a clid. + * @param pDObj The @a DataObject. + * @param clid The ID of the class to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + * + * Only works if the @a DataObject is a @a DataBucket. + * Returns 0 on failure, + */ +void* Storable_cast(DataObject* pDObj, CLID clid, + IRegisterTransient* irt /*= 0*/, + bool isConst /*= true*/) +{ + return fromStorable (pDObj, clid, irt, isConst); +} + + +/** + * @brief Try to get the pointer back from a @a DataObject, + * converted to be of type @a clid. + * @param pDObj The @a DataObject. + * @param clid The ID of the class to which to convert. + * @param irt To be called if we make a new instance. + * @param isConst True if the object being converted is regarded as const. + * + * Only works if the @a DataObject is a @a DataBucket. + * Returns 0 on failure, + */ +const void* Storable_cast(const DataObject* pDObj, CLID clid, + IRegisterTransient* irt /*= 0*/, + bool isConst /*= true*/) +{ + return fromStorable (const_cast<DataObject*> (pDObj), clid, irt, isConst); +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/src/StringPool.cxx b/EDM/athena/Control/SGTools/src/StringPool.cxx new file mode 100644 index 00000000..08920791 --- /dev/null +++ b/EDM/athena/Control/SGTools/src/StringPool.cxx @@ -0,0 +1,321 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StringPool.cxx,v 1.3 2007-12-10 22:20:03 ssnyder Exp $ +/** + * @file SGTools/StringPool.cxx + * @author scott snyder + * @date Mar 2007 + * @brief Maintain a mapping of strings to 64-bit ints. + */ + + +#include "SGTools/StringPool.h" +#include "SGTools/crc64.h" +#include "CxxUtils/make_unique.h" +#include <map> +#include <unordered_map> +#include <vector> +#include <algorithm> +#include <cstdlib> +#include <iostream> +#include <iomanip> + + +namespace SG { + + +//*************************************************************************** +// Implementation class. +// + + +class StringPoolImpl +{ +public: + /// Remember an additional mapping from key to string. + bool registerKey (StringPool::sgkey_t key, + const std::string& str, + StringPool::sgaux_t aux); + + /// Find the string corresponding to a given key. + const std::string* keyToString (StringPool::sgkey_t key, + StringPool::sgaux_t& aux) const; + + /// Number of registered mappings. + size_t size() const; + + /// Clear data. + void clear(); + + /// Debugging dump. Write to stdout. + void dump() const; + + +private: + // Hash function for the key. + // Just cast the low bits to a size_t. + struct keyhash + { + std::size_t operator() (StringPool::sgkey_t key) const + { return static_cast<std::size_t> (key); } + }; + + // The key hash table. + typedef std::pair<StringPool::sgaux_t, std::string> pair_t; + typedef std::unordered_map<StringPool::sgkey_t, pair_t, keyhash> keymap_t; + keymap_t m_keymap; +}; + + +/** + * @brief Remember an additional mapping from key to string. + * @param key The key to enter. + * @param str The string to enter. + * @param aux Auxiliary data to include along with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + */ +bool StringPoolImpl::registerKey (StringPool::sgkey_t key, + const std::string& str, + StringPool::sgaux_t aux) +{ + StringPoolImpl::keymap_t::iterator i = m_keymap.find (key); + if (i == m_keymap.end()) { + pair_t& p = m_keymap[key]; + p.first = aux; + p.second = str; + } + else if (i->second.first != aux || i->second.second != str) + return false; + return true; +} + + +/** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @param aux[out] Auxiliary data associated with the key. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* +StringPoolImpl::keyToString (StringPool::sgkey_t key, + StringPool::sgaux_t& aux) const +{ + StringPoolImpl::keymap_t::const_iterator i = m_keymap.find (key); + if (i != m_keymap.end()) { + aux = i->second.first; + return &i->second.second; + } + return 0; +} + + +/** + * @brief Number of registered mappings. + */ +size_t StringPoolImpl::size() const +{ + return m_keymap.size(); +} + + +/** + * @brief Clear data. + */ +void StringPoolImpl::clear() +{ + m_keymap.clear(); +} + + +/** + * @brief Debugging dump. Write to cout. + */ +void StringPoolImpl::dump() const +{ + std::vector<StringPool::sgkey_t> keys; + keys.reserve (m_keymap.size()); + for (const keymap_t::value_type& p : m_keymap) + keys.push_back (p.first); + std::sort (keys.begin(), keys.end()); + for (StringPool::sgkey_t k : keys) { + keymap_t::const_iterator it = m_keymap.find (k); + std::cout << std::hex << std::setw(18) << k << " " + << std::dec << std::setw(9) << it->second.first << " " + << it->second.second << "\n"; + } +} + + +//*************************************************************************** +// StringPool class. +// + +/** + * @brief Constructor. + */ +StringPool::StringPool() + : m_impl (CxxUtils::make_unique<StringPoolImpl>()) +{ +} + + +/** + * @brief Copy constructor. + * @brief other Object from which to copy. + */ +StringPool::StringPool (const StringPool& other) + : m_impl (CxxUtils::make_unique<StringPoolImpl> (*other.m_impl)) +{ +} + + +/** + * @brief Move constructor. + * @brief other Object from which to move. + */ +StringPool::StringPool (StringPool&& other) + : m_impl (std::move (other.m_impl)) +{ + other.m_impl = CxxUtils::make_unique<StringPoolImpl>(); +} + + +/** + * @brief Assignment operator. + * @brief other Object from which to copy. + */ +StringPool& StringPool::operator= (const StringPool& other) +{ + if (this != &other) { + *m_impl = *other.m_impl; + } + return *this; +} + + +/** + * @brief Move operator. + * @brief other Object from which to move. + */ +StringPool& StringPool::operator= (StringPool&& other) +{ + if (this != &other) { + StringPoolImpl& other_impl = *other.m_impl; + *m_impl = std::move (other_impl); + } + return *this; +} + + +/** + * @brief Destructor. + */ +StringPool::~StringPool() +{ + clear(); +} + + +/** + * @brief Find the key for a string. + * @param str The string to look up. + * @param aux Auxiliary data to include along with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ +StringPool::sgkey_t StringPool::stringToKey (const std::string& str, + sgaux_t aux /*= 0*/) +{ + uint64_t crc = crc64 (str); + if (aux) crc = crc64addint (crc, aux); + sgkey_t key = (crc & sgkey_t_max); + if (!m_impl->registerKey (key, str, aux)) + std::abort(); + return key; +} + + +/** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* StringPool::keyToString (sgkey_t key) const +{ + sgaux_t aux; + return m_impl->keyToString (key, aux); +} + + +/** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @param aux[out] Auxiliary data associated with the key. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* StringPool::keyToString (sgkey_t key, + sgaux_t& aux) const +{ + return m_impl->keyToString (key, aux); +} + + +/** + * @brief Remember an additional mapping from key to string. + * @param key The key to enter. + * @param str The string to enter. + * @param aux Auxiliary data to include along with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + */ +bool StringPool::registerKey (sgkey_t key, + const std::string& str, + sgaux_t aux /*= 0*/) +{ + // Make sure the primary mapping is registered first. + stringToKey (str, aux); + return m_impl->registerKey (key, str, aux); +} + + +/** + * @brief Number of registered mappings. + */ +size_t StringPool::size() const +{ + return m_impl->size(); +} + + +/** + * @brief Debugging dump. Write to cout. + */ +void StringPool::dump () const +{ + m_impl->dump(); +} + + +/** + * @brief Empty the pool. + */ +void StringPool::clear() +{ + m_impl->clear(); +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/src/T2pMap.cxx b/EDM/athena/Control/SGTools/src/T2pMap.cxx new file mode 100644 index 00000000..03a7c3ea --- /dev/null +++ b/EDM/athena/Control/SGTools/src/T2pMap.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SGTools/T2pMap.h" +using namespace SG; +std::vector<DataProxy*> T2pMap::pacReport() const { + std::vector<DataProxy*> notAccessed; + if (m_pac) { + t2p::const_iterator i(m_t2p.begin()), e(m_t2p.end()); + while (i != e) { + if (!m_pac->accessed(i->first)) notAccessed.push_back(i->second); + ++i; + } + } + return notAccessed; +} diff --git a/EDM/athena/Control/SGTools/src/TestStore.cxx b/EDM/athena/Control/SGTools/src/TestStore.cxx new file mode 100644 index 00000000..e3e7a05e --- /dev/null +++ b/EDM/athena/Control/SGTools/src/TestStore.cxx @@ -0,0 +1,215 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/src.TestStore.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2015 + * @brief Dummy event store, for regression tests. + */ + + +#include "SGTools/TestStore.h" +#include <iostream> + + +namespace SGTest { + + +TestStore store; + + +unsigned long TestStore::addRef() +{ + std::cout << "addRef\n"; std::abort(); +} + + +unsigned long TestStore::release() +{ + std::cout << "release\n"; std::abort(); +} + + +StatusCode TestStore::queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) +{ + std::cout << "queryInterface\n"; std::abort(); +} + + +std::vector<const SG::DataProxy*> TestStore::proxies() const +{ + std::cout << "proxies\n"; std::abort(); +} + + +const std::string* TestStore::keyToString (sgkey_t key) const +{ + return m_stringPool.keyToString (key); +} + + +void TestStore::registerKey (sgkey_t /*key*/, + const std::string& /*str*/, + CLID /*clid*/) +{ + std::cout << "registerKey\n"; std::abort(); +} + + +SG::DataProxy* TestStore::recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) +{ + const void* raw_ptr = obj.get(); + CLID clid = obj->clID(); + SG::DataProxy* proxy = this->proxy (clid, key); + if (proxy) { + if (returnExisting) + return proxy; + else + return nullptr; + } + proxy = record1 (raw_ptr, obj.get(), clid, key); + if (!allowMods) + proxy->setConst(); + return proxy; +} + + +StatusCode TestStore::updatedObject (CLID /*id*/, + const std::string& key) +{ + m_updated.push_back (key); + if (m_failUpdatedObject) + return StatusCode::FAILURE; + return StatusCode::SUCCESS; +} + + +const std::string& TestStore::name() const +{ + static const std::string nm = "TestStore"; + return nm; +} + + +SG::DataProxy* TestStore::proxy(const void* const pTransient) const +{ + tmap_t::const_iterator i = m_tmap.find (pTransient); + if (i != m_tmap.end()) + return i->second; + return 0; +} + + +SG::DataProxy* TestStore::proxy(const CLID& id, const std::string& key) const +{ + sgkey_t sgkey = const_cast<TestStore*>(this)->stringToKey (key, id); + kmap_t::const_iterator i = m_kmap.find (sgkey); + if (i != m_kmap.end()) + return i->second; + m_missedProxies.emplace_back (id, key); + return 0; +} + + +SG::DataProxy* TestStore::proxy_exact (SG::sgkey_t sgkey) const +{ + kmap_t::const_iterator i = m_kmap.find (sgkey); + if (i != m_kmap.end()) + return i->second; + return 0; +} + + +sgkey_t TestStore::stringToKey (const std::string& str, CLID clid) +{ + return m_stringPool.stringToKey (str, clid); +} + + +const std::string* TestStore::keyToString (sgkey_t key, CLID& clid) const +{ + return m_stringPool.keyToString (key, clid); +} + + +bool TestStore::tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out) +{ + remap_t::iterator i = m_remap.find (TestStoreRemap (sgkey_in, index_in)); + if (i == m_remap.end()) return false; + sgkey_out = i->second.key; + index_out = i->second.index; + return true; +} + + +StatusCode TestStore::addToStore (CLID /*id*/, SG::DataProxy* proxy) +{ + proxy->setStore (this); + m_kmap[proxy->transientAddress()->sgkey()] = proxy; + proxy->addRef(); + return StatusCode::SUCCESS; +} + + +void TestStore::boundHandle (IResetable* handle) +{ + m_boundHandles.push_back (handle); +} + + +void TestStore::unboundHandle (IResetable* handle) +{ + std::vector<IResetable*>::iterator it = + std::find (m_boundHandles.begin(), m_boundHandles.end(), handle); + if (it != m_boundHandles.end()) + m_boundHandles.erase (it); +} + + +SG::DataProxy* TestStore::record1 (const void* p, DataObject* obj, + CLID clid, const std::string& key) +{ + sgkey_t sgkey = stringToKey (key, clid); + if (m_kmap.find (sgkey) != m_kmap.end()) { + SG::DataProxy* dp = m_kmap[sgkey]; + dp->setObject (obj); + if (dp->transientAddress()->clID() == CLID_NULL) + dp->transientAddress()->setID (clid, key); + m_tmap[p] = dp; + return dp; + } + + SG::TransientAddress* tAddr = new SG::TransientAddress(clid, key); + SG::DataProxy* dp = new SG::DataProxy(obj, tAddr); + dp->setStore (this); + m_tmap[p] = dp; + + m_kmap[sgkey] = dp; + dp->addRef(); + tAddr->setSGKey (sgkey); + return dp; +} + + +void TestStore::remap (sgkey_t sgkey_in, sgkey_t sgkey_out, + size_t index_in, size_t index_out) +{ + m_remap[TestStoreRemap(sgkey_in, index_in)] = + TestStoreRemap(sgkey_out, index_out); +} + + +void initTestStore() +{ + SG::CurrentEventStore::setStore (&store); +} + + +} // namespace SGTest diff --git a/EDM/athena/Control/SGTools/src/TransientAddress.cxx b/EDM/athena/Control/SGTools/src/TransientAddress.cxx new file mode 100644 index 00000000..5ad9091c --- /dev/null +++ b/EDM/athena/Control/SGTools/src/TransientAddress.cxx @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SGTools/TransientAddress.h" +#include "AthenaKernel/IAddressProvider.h" +#include "GaudiKernel/IOpaqueAddress.h" + +#include <assert.h> + +using SG::TransientAddress; + +// Default Constructor: +TransientAddress::TransientAddress() + : m_clid(0), m_name(""), m_address(0), m_clearAddress(true), + m_consultProvider(false), m_pAddressProvider(0), m_storeID(StoreID::UNKNOWN), + m_sgkey(0) +{ } + +// Constructor with CLID and string key: +// (typically used through a StoreGate::record() +TransientAddress::TransientAddress(const CLID& id, const std::string& key) + : m_clid(id), m_name(key), m_address(0), m_clearAddress(true), + m_consultProvider(false), m_pAddressProvider(0), m_storeID(StoreID::UNKNOWN), + m_sgkey(0) +{ + if (id != CLID_NULL) + m_transientID.insert(id); +} + +// Constructor with CLID, string key and IOpaqueAddress: +// (typically used by a ProxyProvider) +TransientAddress::TransientAddress(const CLID& id, const std::string& key, + IOpaqueAddress* addr, + bool clearAddress) + : m_clid(id), m_name(key), m_address(0), m_clearAddress(clearAddress), + m_consultProvider(true), m_pAddressProvider(0), m_storeID(StoreID::UNKNOWN), + m_sgkey(0) +{ + if (id != CLID_NULL) + m_transientID.insert(id); + setAddress(addr); +} + +// Destructor +TransientAddress::~TransientAddress() +{ + setAddress(0); +} + + +/** + * @brief Set the CLID / key. + * @param id The new CLID. + * @param key The new StoreGate key. + * + * This will only succeed if the clid/key are currently clear. + */ +void TransientAddress::setID (CLID id, const std::string& key) +{ + assert (m_clid == CLID_NULL && m_name.empty() && m_transientID.empty() && + m_transientAlias.empty()); + m_clid = id; + m_name = key; + if (id != CLID_NULL) + m_transientID.insert(id); +} + +/// set IOpaqueAddress +void TransientAddress::setAddress(IOpaqueAddress* pAddress) +{ + if (0 != pAddress) pAddress->addRef(); + if (0 != m_address) m_address->release(); + m_address = pAddress; +} + +bool TransientAddress::isValid() +{ + if (0 != address()) return true; + + // FIXME CGL +// if (!m_consultProvider) { +// if ( m_clid != 0 && m_name != "" ) { return true; } +// } + if (m_consultProvider && 0 != provider()) { + if ((provider()->updateAddress(storeID(), this)).isSuccess()) + return true; + } + return false; +} + + + + + diff --git a/EDM/athena/Control/SGTools/src/crc64.cxx b/EDM/athena/Control/SGTools/src/crc64.cxx new file mode 100644 index 00000000..6081bbec --- /dev/null +++ b/EDM/athena/Control/SGTools/src/crc64.cxx @@ -0,0 +1,126 @@ +// $Id: crc64.cxx,v 1.2 2007-03-08 02:02:06 ssnyder Exp $ +/** + * @file SGTools/crc64.cxx + * @author scott snyder, originally from David T. Jones + * @date Mar 2007 + * @brief A CRC-64 implementation. + */ +/* + * Original comments: + * Improved calculation of CRC-64 values for protein sequences + * By David T. Jones (dtj@cs.ucl.ac.uk) - September 28th 2002 + * + * Modified from code at URL: + * ftp://ftp.ebi.ac.uk/pub/software/swissprot/Swissknife/old/SPcrc.tar.gz + * + * Changed to C++ and moved into a namespace. + */ + + +#include "SGTools/crc64.h" +#include <cstdio> +using namespace std; + + +// I don't have a citation for the source of this polynomial. +// Maybe should replace it with the ECMA DLT poly? +#define POLY64REV 0x95AC9329AC4BC9B5ULL +#define INITIALCRC 0xFFFFFFFFFFFFFFFFULL + +// Original SWISSPROT/TrEMBL poly. Shown to be weak. +//#define POLY64REV 0xd800000000000000ULL +//#define INITIALCRC 0x0000000000000000ULL + + +namespace { + +bool crc_init = false; +uint64_t CRCTable[256]; + +// Initialize the CRC table. +void init_table() +{ + crc_init = true; + for (int i = 0; i < 256; i++) + { + uint64_t part = i; + for (int j = 0; j < 8; j++) + { + if (part & 1) + part = (part >> 1) ^ POLY64REV; + else + part >>= 1; + } + CRCTable[i] = part; + } +} + +} // anonymous namespace + + +namespace SG { + + +/** + * @brief Find the CRC-64 of a string. + * @param str The string to hash. + */ +uint64_t crc64 (const std::string& str) +{ + if (!crc_init) + init_table(); + + uint64_t crc = INITIALCRC; + const char* seq = str.data(); + const char* end = seq + str.size(); + while (seq < end) + crc = CRCTable[(crc ^ *seq++) & 0xff] ^ (crc >> 8); + return crc; +} + + +/** + * @brief Extend a previously-calculated CRC to include an int. + * @param crc The previously-calculated CRC. + * @param x The integer to add. + * @return The new CRC. + */ +uint64_t crc64addint (uint64_t crc, unsigned int x) +{ + if (!crc_init) + init_table(); + + while (x > 0) { + crc = CRCTable[(crc ^ x) & 0xff] ^ (crc >> 8); + x >>= 8; + } + return crc; +} + + +/** + * @brief Format a CRC-64 as a string. + * @param crc The CRC to format. + */ +std::string crc64format (uint64_t crc) +{ + char buf[64]; + sprintf (buf, "%08X%08X", + (unsigned)((crc>>32)&0xffffffff), (unsigned)(crc&0xffffffff)); + return buf; +} + + +/** + * @brief Return a CRC-64 digest of a string. + * @param str The string to hash. + * @return The CRC-64 digest of the string. + * This is the hash code, expressed as hex as a string. + */ +std::string crc64digest (const std::string& str) +{ + return crc64format (crc64 (str)); +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/src/exceptions.cxx b/EDM/athena/Control/SGTools/src/exceptions.cxx new file mode 100644 index 00000000..dad034bd --- /dev/null +++ b/EDM/athena/Control/SGTools/src/exceptions.cxx @@ -0,0 +1,100 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/src/exceptions.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Exceptions that can be thrown by SGTools. + */ + + +#include "SGTools/exceptions.h" +#include "GaudiKernel/System.h" +#include <sstream> +#include <string> + + +namespace SG { + + +/// Helper: Format exception string. +std::string excBadDataProxyCast_format (CLID id, const std::type_info& tid) +{ + std::ostringstream os; + os << "Bad cast of DataProxy with CLID " << id + << " to type " << System::typeinfoName (tid); + return os.str(); +} + + +/** + * @brief Constructor. + * @param id CLID of the DataProxy. + * @param tid Type to which we're trying to convert the object. + */ +ExcBadDataProxyCast::ExcBadDataProxyCast (CLID id, const std::type_info& tid) + : m_what (excBadDataProxyCast_format (id, tid)) +{ +} + + +/** + * @brief Return the message for this exception. + */ +const char* ExcBadDataProxyCast::what() const throw() +{ + return m_what.c_str(); +} + + +/** + * @brief Throw an ExcBadDataProxyCast exception. + * @param id CLID of the DataProxy. + * @param tid Type to which we're trying to convert the object. + */ +void throwExcBadDataProxyCast (CLID id, const std::type_info& tid) +{ + throw ExcBadDataProxyCast (id, tid); +} + + +//************************************************************************* + + +/// Helper: Format exception string. +std::string excProxyCollision_format (CLID id, + const std::string& key, + CLID primary_id, + const std::string& primary_key) +{ + std::ostringstream os; + os << "ExcProxyCollision: proxy collision for clid/key " + << id << " / " << key + << " (primary " << primary_id << " / " << primary_key << ")."; + return os.str(); +} + + +/** + * @brief Constructor. + * @param id CLID we're trying to set on the dummy proxy. + * @param key Key we're trying to set on the dummy proxy. + * @param primary_id CLID of the existing proxy. + * @param primary_key Key of the existing proxy. + */ +ExcProxyCollision::ExcProxyCollision (CLID id, + const std::string& key, + CLID primary_id, + const std::string& primary_key) + : std::runtime_error (excProxyCollision_format (id, + key, + primary_id, + primary_key)) +{ +} + + +} // namespace SG diff --git a/EDM/athena/Control/SGTools/test/BaseInfo_test.cxx b/EDM/athena/Control/SGTools/test/BaseInfo_test.cxx new file mode 100644 index 00000000..f799afc8 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/BaseInfo_test.cxx @@ -0,0 +1,354 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/BaseInfo_test.cxx + * @author scott snyder + * @date A while ago. + * @brief Regression test for BaseInfo. + */ + + +#undef NDEBUG + +#include "SGTools/BaseInfo.h" +#include "SGTools/CLASS_DEF.h" +#include "boost/assign/list_of.hpp" +#include <iostream> +#include <algorithm> +#include <cassert> + +using std::cout; +using boost::assign::list_of; + +struct AA +{ + AA (int the_x=0): x(the_x) {} + ~AA() { } + int x; +}; +struct BB : public AA +{ + BB (int the_x=0) : AA(the_x) {} +}; +struct CC : public BB +{ + CC (int the_x=0) : BB(the_x) {} +}; + +SG_BASE(BB, AA); +SG_BASE(CC, BB); + +CLASS_DEF (AA, 1111, 2) +CLASS_DEF (BB, 1112, 2) +CLASS_DEF (CC, 1113, 2) + +struct M +{ + M (int the_x=0) : x(the_x) {} + virtual ~M() { } + int x; +}; +struct N : virtual public M +{ + N (int the_x=0) : M(the_x) {} +}; +struct O : virtual public M +{ + O (int the_x=0) : M(the_x) {} +}; +struct P : virtual public N, virtual public O +{ + P (int the_x=0) : M(the_x) {} +}; + +CLASS_DEF (M, 1114, 2) +CLASS_DEF (N, 1115, 2) +CLASS_DEF (O, 1116, 2) +CLASS_DEF (P, 1117, 2) + +SG_BASE (N, SG_VIRTUAL (M)); +SG_BASE (O, SG_VIRTUAL (M)); +SG_BASES2 (P, SG_VIRTUAL (N), SG_VIRTUAL (O)); + +struct X1 {}; +struct X2 : public X1 {}; +SG_BASE (X2, X1); + +struct Q : virtual public M +{ + Q (int the_x=0) : M(the_x) {} +}; +struct R : virtual public N, virtual public O, virtual public Q +{ + R (int the_x=0) : M(the_x) {} +}; + +CLASS_DEF (Q, 1118, 2) +CLASS_DEF (R, 1119, 2) + +SG_BASE (Q, SG_VIRTUAL (M)); +SG_BASES3 (R, SG_VIRTUAL (N), + SG_VIRTUAL (O), + SG_VIRTUAL (Q)); + + +struct I1 : public AA {}; +struct I2 : public AA {}; +SG_BASE (I1, AA); +SG_BASE (I2, AA); +CLASS_DEF (I2, 1120, 2) + +struct J : public AA, virtual public X1, public M {}; +SG_BASE(J, AA); +SG_ADD_BASE(J, SG_VIRTUAL(X1)); +SG_ADD_BASE(J, M); + +struct K : public AA {}; +SG_ADD_BASE(K, AA); + + +int test1() +{ + std::cout << "test1\n"; + + typedef SG::BaseInfo<CC> CC_C; + typedef SG::BaseInfo<R> R_C; + + std::vector<CLID> clids; + clids = CC_C::get_bases(); + std::vector<CLID> exp1 = list_of + (ClassID_traits<CC>::ID()) + (ClassID_traits<BB>::ID()) + (ClassID_traits<AA>::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp1.begin(), exp1.end()); + assert (clids == exp1); + + std::vector<const std::type_info*> tinfos; + tinfos = CC_C::get_ti_bases(); + std::vector<const std::type_info*> exp1ti = list_of + (&typeid(CC)) + (&typeid(BB)) + (&typeid(AA)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp1ti.begin(), exp1ti.end()); + assert (tinfos == exp1ti); + + clids = R_C::get_bases(); + std::vector<CLID> exp2 = list_of + (ClassID_traits<M>::ID()) + (ClassID_traits<N>::ID()) + (ClassID_traits<O>::ID()) + (ClassID_traits<Q>::ID()) + (ClassID_traits<R>::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp2.begin(), exp2.end()); + assert (clids == exp2); + + tinfos = R_C::get_ti_bases(); + std::vector<const std::type_info*> exp2ti = list_of + (&typeid(M)) + (&typeid(N)) + (&typeid(O)) + (&typeid(Q)) + (&typeid(R)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp2ti.begin(), exp2ti.end()); + assert (tinfos == exp2ti); + + SG::BaseInfoBase::castfn_t* castfn; + + M* m0 = new M; + R* r1 = new R; + M* m1 = r1; + assert ((long)m1 != (long)r1); + M* m2 = (M*)R_C::cast (r1, ClassID_traits<M>::ID()); + assert ((long)m1 == (long)m2); + m2 = (M*)R_C::cast (r1, typeid (M)); + assert ((long)m1 == (long)m2); + R* r2 = (R*)R_C::castTo (m1, ClassID_traits<M>::ID()); + assert ((long)r1 == (long)r2); + r2 = (R*)R_C::castTo (m1, typeid (M)); + assert ((long)r1 == (long)r2); + r2 = (R*)R_C::castTo (m0, typeid (M)); + assert (r2 == 0); + + castfn = R_C::castfn (ClassID_traits<M>::ID()); + assert ((long)m1 == (long)castfn(r1)); + castfn = R_C::castfn (typeid (M)); + assert ((long)m1 == (long)castfn(r1)); + castfn = R_C::castfnTo (ClassID_traits<M>::ID()); + assert ((long)r1 == (long)castfn(m1)); + castfn = R_C::castfnTo (typeid (M)); + assert ((long)r1 == (long)castfn(m1)); + assert (0 == (long)castfn(m0)); + + assert (R_C::cast (r1, ClassID_traits<AA>::ID()) == 0); + assert (R_C::cast (r1, typeid (AA)) == 0); + assert (R_C::castTo (r1, ClassID_traits<AA>::ID()) == 0); + assert (R_C::castTo (r1, typeid (AA)) == 0); + assert (R_C::castfn (ClassID_traits<AA>::ID()) == 0); + assert (R_C::castfn (typeid (AA)) == 0); + assert (R_C::castfnTo (ClassID_traits<AA>::ID()) == 0); + assert (R_C::castfnTo (typeid (AA)) == 0); + + assert (R_C::is_base (ClassID_traits<M>::ID())); + assert (R_C::is_base (typeid (M))); + + assert (!R_C::is_base (ClassID_traits<AA>::ID())); + assert (!R_C::is_base (typeid (AA))); + + assert (CC_C::is_base (ClassID_traits<AA>::ID())); + assert (CC_C::is_base (typeid (AA))); + + assert (R_C::is_virtual (ClassID_traits<M>::ID())); + assert (R_C::is_virtual (typeid (M))); + + assert (!CC_C::is_virtual (ClassID_traits<AA>::ID())); + assert (!CC_C::is_virtual (typeid (AA))); + + typedef SG::BaseInfo<X2> X_C; + assert (X_C::is_base (typeid (X1))); + X2* x2 = new X2; + X1* x1 = (X1*)X_C::cast (x2, typeid (X1)); + assert (x1 == x2); + X2* x2a = (X2*)X_C::castTo (x1, typeid (X1)); + assert (x2a == 0); // castTo doesn't work now for non-polymorphic classes. + + clids = SG::BaseInfoBase::find (ClassID_traits<CC>::ID())->get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp1); + tinfos = SG::BaseInfoBase::find (ClassID_traits<CC>::ID())->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp1ti); + + clids = CC_C::baseinfo().get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp1); + tinfos = CC_C::baseinfo().get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp1ti); + + clids = SG::BaseInfoBase::find (typeid (CC))->get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp1); + tinfos = SG::BaseInfoBase::find (typeid (CC))->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp1ti); + + assert (SG::BaseInfoBase::find (typeid(CC))->clid() == + ClassID_traits<CC>::ID()); + assert (SG::BaseInfoBase::find (typeid(CC))->typeinfo() == typeid(CC)); + + assert (SG::BaseInfoBase::find (99999) == 0); + assert (SG::BaseInfoBase::find (typeid(int)) == 0); + + assert (typeid(SG::BaseType<SG::Bases<BB>::Base1>::type) == typeid(AA)); + assert (typeid(SG::BaseType<SG::Bases<BB>::Base1>::is_virtual) == + typeid(std::false_type)); + + assert (typeid(SG::BaseType<SG::Bases<N>::Base1>::type) == typeid(M)); + assert (typeid(SG::BaseType<SG::Bases<N>::Base1>::is_virtual) == + typeid(std::true_type)); + + std::vector<CLID> exp3 = list_of + (ClassID_traits<AA>::ID()); + clids = SG::BaseInfoBase::find (typeid (I1))->get_bases(); + assert (clids == exp3); + + std::vector<const std::type_info*> exp3ti = list_of + (&typeid (AA)) + (&typeid (I1)); + std::sort (exp3ti.begin(), exp3ti.end()); + tinfos = SG::BaseInfoBase::find (typeid (I1))->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp3ti); + + std::vector<CLID> exp4 = list_of + (ClassID_traits<AA>::ID()) + (ClassID_traits<I2>::ID()); + clids = SG::BaseInfoBase::find (ClassID_traits<I2>::ID())->get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp4); + + std::vector<const std::type_info*> exp4ti = list_of + (&typeid (AA)) + (&typeid (I2)); + std::sort (exp4ti.begin(), exp4ti.end()); + tinfos = SG::BaseInfoBase::find (typeid (I2))->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp4ti); + + const SG::BaseInfoBase* jbib = SG::BaseInfoBase::find (typeid (J)); + tinfos = jbib->get_ti_bases(); + std::vector<const std::type_info*> exp5ti = list_of + (&typeid (AA)) + (&typeid (X1)) + (&typeid (M)) + (&typeid (J)); + std::sort (exp5ti.begin(), exp5ti.end()); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp5ti); + assert (!jbib->is_virtual (typeid (AA))); + assert ( jbib->is_virtual (typeid (X1))); + assert (!jbib->is_virtual (typeid (M))); + + const SG::BaseInfoBase* kbib = SG::BaseInfoBase::find (typeid (K)); + tinfos = kbib->get_ti_bases(); + std::vector<const std::type_info*> exp6ti = list_of + (&typeid (AA)) + (&typeid (K)); + std::sort (exp6ti.begin(), exp6ti.end()); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp6ti); + + return 0; +} + + +class KCopyConversion + : public SG::CopyConversion<K, M> +{ +public: + void convert (const K& src, M& dst) const + { dst.x = src.x; } +}; + +SG_ADD_COPY_CONVERSION(K, KCopyConversion); + + +// Test copying conversions. +void test2() +{ + std::cout << "test2\n"; + const SG::BaseInfoBase& bib = SG::BaseInfo<K>::baseinfo(); + std::vector<CLID> clids = bib.get_copy_conversions(); + std::vector<CLID> exp1 = list_of + (ClassID_traits<M>::ID()); + assert (clids == exp1); + + const SG::CopyConversionBase* b = bib.copy_conversion (clids[0]); + assert (b == bib.copy_conversion (typeid (M))); + assert (0 == bib.copy_conversion (typeid (X1))); + assert (0 == bib.copy_conversion (typeid (Q))); + assert (0 == bib.copy_conversion (ClassID_traits<Q>::ID())); + + K k; + k.x = 10; + M m; + m.x = 0; + b->convertUntyped (&k, &m); + assert (m.x == 10); +} + + +int main() +{ + test1(); + test2(); + return 0; +} + diff --git a/EDM/athena/Control/SGTools/test/CLIDRegistry_test.cxx b/EDM/athena/Control/SGTools/test/CLIDRegistry_test.cxx new file mode 100644 index 00000000..e0bb249a --- /dev/null +++ b/EDM/athena/Control/SGTools/test/CLIDRegistry_test.cxx @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file CLIDRegistry_test.cxx + * @brief unit test for CLIDRegistry + * + * $Id: CLIDRegistry_test.cxx,v 1.2 2009-01-19 17:02:55 binet Exp $ + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + */ + +/* #define COMPILEFAIL 1 */ + +#undef NDEBUG + +#include "SGTools/CLIDRegistry.h" + +#include <algorithm> +#include <cassert> +#include <iostream> +#include <typeinfo> + +#include <boost/tuple/tuple.hpp> +using boost::get; +#include "AthenaKernel/tools/AthenaPackageInfo.h" + +class Foo {}; +class Bar {}; +class Baz {}; + +int main () { + std::cerr << "*** CLIDRegistry_test starts ***" <<std::endl; + //reset newEntries before we start counting + std::pair<CLIDRegistry::const_iterator, CLIDRegistry::const_iterator> er = + CLIDRegistry::newEntries(); + Athena::PackageInfo info(PACKAGE_VERSION); +#ifdef COMPILEFAIL + CLIDRegistry::addEntry<12>(typeid(Foo), "Foo", info, "Foo"); + //no upper limit CLIDRegistry::addEntry<1245736740>("Foo", info); +#endif + CLIDRegistry::addEntry<1234>(typeid(Foo), "Foo", info, "Foo"); + CLIDRegistry::addEntry<4321>(typeid(Bar), "Bar", info, "Bar"); + assert(CLIDRegistry::hasNewEntries()); + er = CLIDRegistry::newEntries(); + assert( distance(er.first, er.second) == 2 ); + assert( get<0>(*(CLIDRegistry::end()-2)) == 1234 ); + assert( get<1>(*(CLIDRegistry::end()-2)) == "Foo" ); + assert( get<2>(*(CLIDRegistry::end()-2)).name() == "SGTools" ); + + assert (CLIDRegistry::CLIDToTypeinfo (4321) == &typeid(Bar)); + assert (CLIDRegistry::CLIDToTypeinfo (43213) == 0); + assert (CLIDRegistry::typeinfoToCLID (typeid(Bar)) == 4321); + assert (CLIDRegistry::typeinfoToCLID (typeid(Baz)) == 0); + + CLIDRegistry::addEntry<43213>(typeid(Baz), "Baz", info, "Baz"); + assert (CLIDRegistry::CLIDToTypeinfo (43213) == &typeid(Baz)); + assert (CLIDRegistry::typeinfoToCLID (typeid(Baz)) == 43213); + + er = CLIDRegistry::newEntries(); + assert( distance(er.first, er.second) == 1 ); + assert( !CLIDRegistry::hasNewEntries()); + std::cerr << "*** CLIDRegistry_test OK ***" <<std::endl; + + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/ClassName_test.cxx b/EDM/athena/Control/SGTools/test/ClassName_test.cxx new file mode 100644 index 00000000..efd1eebc --- /dev/null +++ b/EDM/athena/Control/SGTools/test/ClassName_test.cxx @@ -0,0 +1,25 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cassert> +#include "SGTools/ClassName.h" + +class A {}; +class B {}; +template <class T> class C {}; + +template <> +class ClassName<B> +{ +public: + static std::string name() { return "fooB"; } +}; + +int main() +{ + assert (ClassName<A>::name() == "A"); + assert (ClassName<C<C<A> > >::name() == "C<C<A> >"); + assert (ClassName<B>::name() == "fooB"); + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/CurrentEventStore_test.cxx b/EDM/athena/Control/SGTools/test/CurrentEventStore_test.cxx new file mode 100644 index 00000000..d2adcf75 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/CurrentEventStore_test.cxx @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/test/CurrentEventStore_test.cxx + * @author scott snyder + * @date Apr, 2015 + * @brief Hold a pointer to the current event store. + */ + +#undef NDEBUG + + +#include "SGTools/CurrentEventStore.h" +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + + + IProxyDict* s1 = reinterpret_cast<IProxyDict*>(0x1000); + + assert (SG::CurrentEventStore::store() == 0); + assert (SG::CurrentEventStore::setStore(s1) == 0); + assert (SG::CurrentEventStore::store() == s1); + + { + IProxyDict* s2 = reinterpret_cast<IProxyDict*>(0x2000); + SG::CurrentEventStore::Push p (s2); + assert (SG::CurrentEventStore::store() == s2); + } + assert (SG::CurrentEventStore::store() == s1); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/DataBucket_test.cxx b/EDM/athena/Control/SGTools/test/DataBucket_test.cxx new file mode 100644 index 00000000..f944041b --- /dev/null +++ b/EDM/athena/Control/SGTools/test/DataBucket_test.cxx @@ -0,0 +1,433 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG + +#include "SGTools/BuiltinsClids.h" +#include "SGTools/StlVectorClids.h" +#include "SGTools/StlMapClids.h" +#include "SGTools/DataBucket.h" +#include "SGTools/StorableConversions.h" +#include "AthenaKernel/ILockable.h" +#include <iostream> +#include <cassert> + +/*FIXME can get it from TestTools circ package dep */ +#define SGASSERTERROR( FALSEEXPR ) \ + std::cerr << "Now we expect to see an error message:" << std::endl \ + << "----Error Message Starts--->>" << std::endl; \ + assert(!FALSEEXPR); \ + std::cerr<< "<<---Error Message Ends-------" << std::endl + + +#include "GaudiKernel/DataObject.h" + + +//using namespace std; +//using namespace SG; + + +class GaudiDataObj : public DataObject { + +public: + static int count; + + GaudiDataObj(): DataObject(), m_val(0) { ++count; }; + GaudiDataObj(int i): DataObject(), m_val(i) { ++count; }; + virtual ~GaudiDataObj(){ --count; }; + + static const CLID& classID() { + static const CLID ID = 8010; + return ID; } + virtual const CLID& clID() const { return classID(); } + + void val(int i) { m_val = i; } + int val() const { return m_val; } + +private: + int m_val; +}; +int GaudiDataObj::count = 0; + +class WrongType {}; + +class AbstractType { +public: + virtual ~AbstractType() {} + virtual void abstractMethod()=0; +}; + +class AbstractDataObj : public DataObject { +public: + static const CLID& classID() { + static const CLID ID = 8011; + return ID; } + virtual const CLID& clID() const { return classID(); } + virtual void abstractMethod()=0; +}; + +class MyDataObj { + +public: + static int count; + + MyDataObj(): m_val(0) { ++count; }; + MyDataObj(int i): m_val(i) { ++count; } + ~MyDataObj(){ --count; } + + void val(int i) { m_val = i; } + int val() const { return m_val; } + +private: + int m_val; +}; +int MyDataObj::count = 0; + +#include "SGTools/CLASS_DEF.h" +CLASS_DEF(MyDataObj, 8000, 3) + +#include <cassert> +#include <vector> +#include <map> + +#include "TestTools/initGaudi.h" + +//CLASSID_DEF(int, 34) +//CLASSVERSION_DEF(int, 5) +// CLASS_DEF(int, 8105, 1) +// CLASS_DEF(std::vector<int>, 8002, 1) +// CLASS_DEF2(std::map<int, float>, 8003, 1) +CLASS_DEF(AbstractType, 8004, 1) +CLASS_DEF(WrongType, 8005, 1) + +struct X1 +{ + ~X1() {} + int a; +}; + +struct X2 + : public virtual X1 +{ + int b; +}; + +CLASS_DEF(X1, 8011, 1) +CLASS_DEF(X2, 8012, 1) +SG_BASE(X2, X1); + +CLASS_DEF( const int* , 206871866 , 1 ) + +class X3 +{ +public: + int a; +}; +CLASS_DEF(X3, 8013, 1) + + +class XCopyConversion + : public SG::CopyConversion<X1, X3> +{ +public: + void convert (const X1& src, X3& dst) const + { dst.a = src.a; } +}; + +SG_ADD_COPY_CONVERSION(X1, XCopyConversion); + +class X4 +{ +public: + int a; +}; +CLASS_DEF(X4, 8014, 1) + + +class X5 +{ +public: + X5 (int the_a) : a(the_a){} + ~X5() { log.push_back (a); } + int a; + static std::vector<int> log; +}; +std::vector<int> X5::log; +CLASS_DEF(X5, 8015, 1) + + +class XLock : public ILockable +{ +public: + XLock() : m_locked (false) {} + void lock() { m_locked = true; std::cout << "lock\n"; } + bool m_locked; +}; +CLASS_DEF(XLock, 8114, 1) + + + +class TestRegisterTransient + : public SG::IRegisterTransient +{ +public: + virtual void registerTransient (void* trans) { m_xtrans.push_back (trans); } + + std::vector<void*> m_xtrans; +}; + + + +// Test copying conversion. +void test2() +{ + std::cout << "test2\n"; + TestRegisterTransient trt; + + X1* x1 = new X1; + x1->a = 10; + DataObject* xbucket = SG::asStorable(x1); + + const X3* x3 = SG::Storable_cast<X3>(xbucket, false, &trt); + assert ((char*)x3 != (char*)x1); + assert (x3->a == 10); + + assert (trt.m_xtrans.size() == 1); + assert (trt.m_xtrans[0] == x3); + + const X4* x4 = SG::Storable_cast<X4>(xbucket, true, &trt); + assert (x4 == 0); + + assert (SG::Storable_cast<X3>(xbucket, false, &trt, false) == 0); + + SG::DataBucket<X1>* xb = dynamic_cast<SG::DataBucket<X1>*> (xbucket); + assert (xb->cast (ClassID_traits<X3>::ID(), &trt) == x3); + assert (xb->cast (typeid(X3), &trt) == x3); + + assert (xb->cast (ClassID_traits<X4>::ID(), &trt) == 0); + assert (xb->cast (typeid(X4), &trt) == 0); + + assert (xb->cast (ClassID_traits<X3>::ID(), &trt, false) == 0); + assert (xb->cast (typeid(X3), &trt, false) == 0); +} + + +// Test lock() +void test3() +{ + using namespace SG; + std::cout << "test3\n"; + + X1* x1 = new X1; + XLock* xlock = new XLock; + + DataObject* b1 = asStorable (x1); + DataObject* b2 = asStorable (xlock); + + DataBucketBase* bb1 = dynamic_cast<DataBucketBase*> (b1); + DataBucketBase* bb2 = dynamic_cast<DataBucketBase*> (b2); + + bb1->lock(); + assert (!xlock->m_locked); + bb2->lock(); + assert (xlock->m_locked); +} + + +int main () { + using namespace std; + using namespace SG; + ISvcLocator* pDum; + Athena_test::initGaudi(pDum); //need the MessageSvc + assert( pDum ); + SG::DataBucket<int> intBucket(0); + SG::DataBucket<const int*> pintBucket(0); + SG::DataBucket<vector<int> > vintBucket(0); + std::cerr << "int has_classID " << intBucket.clID() << " version " + << ClassID_traits<int>::s_version << " and " + << (ClassID_traits<int>::s_isDataObject ? "does" : "does not") + << " inherit from DataObject" <<std::endl; + std::cerr << "const int* has_classID " << pintBucket.clID() <<std::endl; + assert(intBucket.clID() == pintBucket.clID()); + assert(intBucket.tinfo() == typeid(int)); + + std::cerr << "vector<int> has_classID " << vintBucket.clID() <<std::endl; + SG::DataBucket<GaudiDataObj> gdobjBucket(0); + std::cerr << "GaudiDataObj has_classID " << gdobjBucket.clID() << " and " + << (ClassID_traits<GaudiDataObj>::s_isDataObject ? "does" : "does not") + << " inherit from DataObject" <<std::endl; + assert(gdobjBucket.clID() == GaudiDataObj::classID()); + assert(ClassID_traits<GaudiDataObj>::s_isDataObject); + + SG::DataBucket<MyDataObj> dobjBucket(0); + std::cerr << "MyDataObj has_classID " << dobjBucket.clID() << " and " + << (ClassID_traits<MyDataObj>::s_isDataObject ? "does" : "does not") + << " inherit from DataObject" <<std::endl; + assert(dobjBucket.clID() == ClassID_traits<MyDataObj>::ID()); + assert(!ClassID_traits<MyDataObj>::s_isDataObject); + + SG::DataBucket<AbstractDataObj> absdobjBucket(0); + std::cerr << "AbstractDataObj has_classID " << absdobjBucket.clID() <<std::endl; + assert(absdobjBucket.clID() == AbstractDataObj::classID()); + assert(ClassID_traits<AbstractDataObj>::s_isDataObject); + + SG::DataBucket<AbstractType> absBucket(0); + std::cerr << "AbstractType has_classID " << absBucket.clID() <<std::endl; + assert(absBucket.clID() == ClassID_traits<AbstractType>::ID()); + assert(!ClassID_traits<AbstractType>::s_isDataObject); + + assert("int" == ClassID_traits<int>::typeName()); + assert("GaudiDataObj" == ClassID_traits<GaudiDataObj>::typeName()); + if("std::map<int,float>" != + ClassID_traits<map<int, float> >::typeName()) { + std::cerr << "error checking type name for map<int,float>: ClassID has it as " << ClassID_traits<map<int, float> >::typeName() <<std::endl; + assert(0); + } + + MyDataObj* pMDO = new MyDataObj(1); + MyDataObj* pRes(0); + + DataObject* pBucket(asStorable(pMDO)); + assert(fromStorable(pBucket, pRes)); + //FIXME asStorable above creates a DataBucket which is not deleted by anybody + WrongType* pWrong(0); + SGASSERTERROR(fromStorable(pBucket, pWrong)); + assert(pMDO == pRes); + assert(pRes->val()==1); + + pRes = 0; + // static const bool QUIET(true); + static const bool VERBOSE(false); + assert(0 != (pRes = SG::Storable_cast<MyDataObj>(pBucket, VERBOSE))); + + std::cerr << "Now we expect to see an error message:" << std::endl + << "----Error Message Starts--->>" << std::endl; + pWrong = SG::Storable_cast<WrongType>(pBucket, VERBOSE); + assert(0 == pWrong); + std::cerr<< "<<---Error Message Ends-------" << std::endl; + std::cerr << "Now we expect to see an error message:" << std::endl + << "----Error Message Starts--->>" << std::endl; + pWrong = SG::Storable_cast<WrongType>((DataObject*)0); + assert(0 == pWrong); + std::cerr<< "<<---Error Message Ends-------" << std::endl; + delete pBucket; + + GaudiDataObj* pGDO = new GaudiDataObj(2); + GaudiDataObj* pGRes(0); + DataObject* DBGDO(asStorable(pGDO)); + assert(fromStorable(DBGDO, pGRes)); + SGASSERTERROR(fromStorable(DBGDO, pWrong)); + assert(pGDO == pGRes); + assert(pGRes->val()==2); + + DataObject* pDO(0); + assert (0 != (pDO = asStorable(new GaudiDataObj(3)))); + pGRes = 0; + assert(0 != (pGRes = SG::Storable_cast<GaudiDataObj>(pDO, VERBOSE))); + + const DataObject& rDO(*pDO); + const GaudiDataObj& rGRes(SG::Storable_cast<GaudiDataObj>(rDO, VERBOSE)); + + try { + std::cerr << "Now we expect to see an error message:" << std::endl + << "----Error Message Starts--->>" << std::endl; + const WrongType& rWr = SG::Storable_cast<WrongType>(rGRes, VERBOSE); + pWrong=const_cast<WrongType*>(&rWr); //remove warning + } catch (bad_Storable_cast ) { + std::cerr << "<<---Error Message Ends-------" << std::endl; + } + + const DataObject* cpDO(pDO); + const GaudiDataObj* cpGRes(SG::Storable_cast<GaudiDataObj>(cpDO, VERBOSE)); + assert( 0 != cpGRes ); + delete pDO; + delete DBGDO; + + //---------------------------------------------------------- + X2* x2 = new X2; + X1* x1 = x2; + assert ((long)x1 != (long)x2); + DataObject* xbucket = asStorable(x2); + X1* x1b = 0; + assert (fromStorable (xbucket, x1b)); + assert (x1 == x1b); + delete xbucket; + //---------------------------------------------------------- + // Test refcounting. + int c1 = GaudiDataObj::count; + int c2 = MyDataObj::count; + GaudiDataObj* gdo = new GaudiDataObj; + assert(1 == gdo->addRef()); + DataBucketBase* b1 = dynamic_cast<DataBucketBase*>(asStorable(gdo)); + assert(1 == b1->addRef()); + assert(1 == b1->refCount()); + assert(2 == gdo->refCount()); //notice how DB and DO have indep refcounts + assert(1 == gdo->release()); + assert(1 == gdo->refCount()); + assert(1 == b1->refCount()); + assert(0 == b1->release()); + assert (c1 == GaudiDataObj::count); + //another combination + gdo = new GaudiDataObj; + assert(1 == gdo->addRef()); + DataObject* b2(asStorable(gdo)); + assert(3 == gdo->addRef()); + delete b2; //this must not delete gdo, only decrease its refcount + assert(2 == gdo->refCount()); + assert (c1 + 1 == GaudiDataObj::count); + //this is simpler: no DataObj in play + b2 = asStorable(new MyDataObj); + delete b2; + assert (c2 == MyDataObj::count); + //cleanup + delete gdo; + //---------------------------------------------------------- + + { + std::unique_ptr<X5> p (new X5(10)); + DataBucketBase* b3 = new SG::DataBucket<X5> (std::move(p)); + assert (p.get() == 0); + assert (X5::log.empty()); + delete b3; + assert (X5::log == std::vector<int> {10}); + X5::log.clear(); + } + + { + std::unique_ptr<X5> p (new X5(11)); + DataObject* b4 = asStorable (std::move(p)); + assert (p.get() == 0); + assert (X5::log.empty()); + delete b4; + assert (X5::log == std::vector<int> {11}); + } + + { + SG::DataObjectSharedPtr<GaudiDataObj> ptr (new GaudiDataObj); + assert (ptr->refCount() == 1); + DataBucketBase* b5 = new SG::DataBucket<GaudiDataObj> (ptr); + assert (ptr->refCount() == 2); + assert (b5->object() == ptr.get()); + delete b5; + assert (ptr->refCount() == 1); + } + + { + SG::DataObjectSharedPtr<GaudiDataObj> ptr (new GaudiDataObj); + assert (ptr->refCount() == 1); + DataObject* b6 = asStorable (ptr); + assert (ptr->refCount() == 2); + delete b6; + assert (ptr->refCount() == 1); + } + + test2(); + test3(); + + std::cerr << "*** DataBucket_test OK ***" <<std::endl; + return 0; + +} + + diff --git a/EDM/athena/Control/SGTools/test/DataProxy_test.cxx b/EDM/athena/Control/SGTools/test/DataProxy_test.cxx new file mode 100644 index 00000000..fec43279 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/DataProxy_test.cxx @@ -0,0 +1,275 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file DataProxy_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Regression tests for DataProxy. + */ + +#undef NDEBUG +#include "SGTools/DataProxy.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/TestStore.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/T2pMap.h" +#include "SGTools/CLASS_DEF.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/ILockable.h" +#include "AthenaKernel/IResetable.h" +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/IConversionSvc.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include <iostream> +#include <cstdlib> +#include <cassert> + + +struct X1 +{ + ~X1() {} +}; +CLASS_DEF(X1, 8011, 1) + +class XLock : public ILockable +{ +public: + XLock() : m_locked (false) {} + void lock() { m_locked = true; std::cout << "lock\n"; } + bool m_locked; +}; +CLASS_DEF(XLock, 8114, 1) + +class TestConversionSvc + : public IConversionSvc +{ +public: + virtual StatusCode addConverter(IConverter* /*pConverter*/) + { std::cout << "addConverter\n"; std::abort(); } + virtual StatusCode addConverter(const CLID& /*clid*/) + { std::cout << "addConverter clid\n"; std::abort(); } + virtual StatusCode removeConverter(const CLID& /*clid*/) + { std::cout << "removeConverter\n"; std::abort(); } + virtual IConverter* converter(const CLID& /*clid*/) + { std::cout << "converter\n"; std::abort(); } + virtual StatusCode connectOutput(const std::string& /*outputFile*/) + { std::cout << "connectOutput1\n"; std::abort(); } + virtual StatusCode connectOutput(const std::string& /*outputFile*/, + const std::string& /*openMode*/) + { std::cout << "connectOutput2\n"; std::abort(); } + virtual StatusCode commitOutput(const std::string& /*outputFile*/, + bool /*do_commit*/) + { std::cout << "commitOutput\n"; std::abort(); } + + virtual StatusCode initialize() + { std::cout << "initialize\n"; std::abort(); } + virtual StatusCode finalize() + { std::cout << "finalize\n"; std::abort(); } + virtual const CLID& objType() const + { std::cout << "objType\n"; std::abort(); } + virtual long repSvcType() const + { std::cout << "repSvcType\n"; std::abort(); } + virtual StatusCode setDataProvider(IDataProviderSvc* /*pService*/) + { std::cout << "setDataProvider\n"; std::abort(); } + virtual SmartIF<IDataProviderSvc>& dataProvider() const + { std::cout << "dataProvider\n"; std::abort(); } + virtual StatusCode setConversionSvc(IConversionSvc* /*pService*/) + { std::cout << "setConversionSvc\n"; std::abort(); } + virtual SmartIF<IConversionSvc>& conversionSvc() const + { std::cout << "conversionSvc\n"; std::abort(); } + virtual StatusCode setAddressCreator(IAddressCreator* /*creator*/) + { std::cout << "setAddressCreator\n"; std::abort(); } + virtual SmartIF<IAddressCreator>& addressCreator() const + { std::cout << "addressCreator\n"; std::abort(); } + virtual StatusCode createObj(IOpaqueAddress* /*pAddress*/, DataObject*& /*refpObject*/) + { std::cout << "createObj\n"; std::abort(); } + virtual StatusCode fillObjRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/) + { std::cout << "fillObjRefs\n"; std::abort(); } + virtual StatusCode updateObj(IOpaqueAddress* /*pAddress*/, DataObject* /*refpObject*/) + { std::cout << "updateObj\n"; std::abort(); } + virtual StatusCode updateObjRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/) + { std::cout << "updateObjRefs\n"; std::abort(); } + virtual StatusCode fillRepRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/) + { std::cout << "fillRepRefs\n"; std::abort(); } + virtual StatusCode updateRep(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/) + { std::cout << "updateRep\n"; std::abort(); } + virtual StatusCode updateRepRefs(IOpaqueAddress* /*pAddress*/, DataObject* /*pObject*/) + { std::cout << "updateRepRefs\n"; std::abort(); } + + virtual unsigned long addRef() { return 1; } + virtual unsigned long release() { return 1; } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) + { std::cout << "queryInterface\n"; std::abort(); } + + virtual StatusCode createRep(DataObject* /*pObject*/, IOpaqueAddress*& /*refpAddress*/) + { std::cout << "createRep\n"; std::abort(); } +}; + + +class TestOpaqueAddress + : public IOpaqueAddress +{ +public: + virtual unsigned long addRef () { return 1; } + virtual unsigned long release () { return 1; } + virtual const CLID& clID () const + { std::cout << "clID\n"; std::abort(); } + virtual long svcType () const + { std::cout << "svcType\n"; std::abort(); } + virtual IRegistry* registry () const + { std::cout << "registry\n"; std::abort(); } + virtual void setRegistry(IRegistry* /*r*/) + { std::cout << "setRegistry\n"; std::abort(); } + virtual const std::string* par () const + { std::cout << "par\n"; std::abort(); } + virtual const unsigned long* ipar () const + { std::cout << "ipar\n"; std::abort(); } +}; + + +class TestResetable : public IResetable +{ +public: + using IResetable::reset; + TestResetable() : set_flag(false) {} + virtual void reset (bool hard) override { resets.push_back((int)hard); } + virtual void finalReset() override { resets.push_back(2); } + virtual bool isSet() const override { return set_flag; } + virtual const std::string& key() const override { return key_string; } + + std::vector<int> resets; + bool set_flag; + std::string key_string; +}; + + +void test1() +{ + std::cout << "test1\n"; + SGTest::TestStore store; + + SG::DataProxy dp; + assert (dp.store() == 0); + dp.setStore (&store); + assert (dp.store() == &store); +} + + +// Test setConst() +void test2() +{ + std::cout << "test2\n"; + + X1* x1 = new X1; + DataObject* b1 = SG::asStorable (x1); + SG::DataProxy dp1; + dp1.setObject (b1); + assert (!dp1.isConst()); + dp1.setConst(); + assert (dp1.isConst()); + + XLock* xlock = new XLock; + DataObject* b2 = SG::asStorable (xlock); + SG::DataProxy dp2; + dp2.setObject (b2); + assert (!dp2.isConst()); + assert (!xlock->m_locked); + dp2.setConst(); + assert (dp2.isConst()); + assert (xlock->m_locked); + + XLock* xlock_a = new XLock; + DataObject* b2a = SG::asStorable (xlock_a); + assert (!xlock_a->m_locked); + dp2.setObject (b2a); + assert (xlock_a->m_locked); + assert (dp2.isConst()); +} + + +class Test3Loader + : public TestConversionSvc +{ +public: + Test3Loader(); + + virtual StatusCode createObj(IOpaqueAddress* /*pAddress*/, DataObject*& refpObject) + { + m_store = SG::CurrentEventStore::store(); + refpObject = m_bucket; + return StatusCode::SUCCESS; + } + + IProxyDict* m_store; + SG::DataBucket<X1>* m_bucket; +}; + + +Test3Loader::Test3Loader() + : m_store(nullptr), + m_bucket (new SG::DataBucket<X1>(CxxUtils::make_unique<X1>())) +{ +} + + +// Test current event store setting in accessData. +void test3() +{ + std::cout << "test3\n"; + + SGTest::TestStore store1; + SGTest::TestStore store2; + Test3Loader loader; + TestOpaqueAddress address; + auto tad = CxxUtils::make_unique<SG::TransientAddress>(); + tad->setAddress (&address); + SG::DataProxy dp1 (tad.release(), &loader); + dp1.setStore (&store1); + SG::T2pMap t2pmap; + dp1.setT2p (&t2pmap); + SG::CurrentEventStore::setStore (&store2); + assert (SG::CurrentEventStore::store() == &store2); + assert (dp1.accessData() == loader.m_bucket); + assert (SG::CurrentEventStore::store() == &store2); + assert (loader.m_store == &store1); +} + + +// Test bind/reset. +void test4() +{ + std::cout << "test4\n"; + + SGTest::TestStore store; + SG::DataProxy dp; + TestResetable r; + dp.setStore (&store); + assert (dp.bindHandle (&r)); + assert (store.m_boundHandles == std::vector<IResetable*> {&r} ); + dp.reset (false); + dp.reset (true); + dp.finalReset(); + assert (r.resets == (std::vector<int> {0,1,2}) ); + r.resets.clear(); + dp.unbindHandle(&r); + assert (store.m_boundHandles.empty()); + assert (r.resets.empty()); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + + // FIXME: INCOMPLETE! + + return 0; +} + + diff --git a/EDM/athena/Control/SGTools/test/DataStore_test.cxx b/EDM/athena/Control/SGTools/test/DataStore_test.cxx new file mode 100644 index 00000000..28fb7d72 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/DataStore_test.cxx @@ -0,0 +1,537 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file DataStore_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Regression tests for DataStore. + */ + +#undef NDEBUG +#include "SGTools/DataStore.h" +#include "SGTools/StringPool.h" +#include "SGTools/DataProxy.h" +#include "SGTools/TestStore.h" +#include "SGTools/TransientAddress.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/getMessageSvc.h" +#include "AthenaKernel/IAddressProvider.h" +#include <iostream> +#include <cstdlib> +#include <cassert> + + +class TestProvider + : public IAddressProvider +{ +public: + virtual StatusCode updateAddress(StoreID::type /*storeID*/, + SG::TransientAddress* /*pTAd*/) + { return StatusCode::SUCCESS; } +}; + + +SG::DataProxy* make_proxy (CLID clid, const std::string& name) +{ + SG::TransientAddress* tad = new SG::TransientAddress (clid, name); + return new SG::DataProxy (tad, (IConversionSvc*)0); +} + + +void test_ctor() +{ + std::cout << "test_ctor\n"; + SGTest::TestStore pool; + SG::DataStore store (pool); + assert (store.storeID() == StoreID::UNKNOWN); + store.setStoreID (StoreID::SPARE_STORE); + assert (store.storeID() == StoreID::SPARE_STORE); +} + + +void test_addToStore() +{ + std::cout << "test_addToStore\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + SG::StringPool::sgkey_t sgkey = pool.stringToKey ("dp1", 123); + + assert (store.addToStore (123, 0).isFailure()); + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (dp1->refCount() == 0); + assert (store.addToStore (123, dp1).isSuccess()); + assert (dp1->store() == &pool); + assert (dp1->refCount() == 1); + assert (dp1->transientAddress()->sgkey() == sgkey); + assert (store.proxy_exact (sgkey) == dp1); + assert (store.proxy (123, "dp1") == dp1); + + int trans1; + dp1->registerTransient (&trans1); + assert (store.locatePersistent (&trans1) == dp1); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (124, dp2).isSuccess()); + SG::StringPool::sgkey_t sgkey2a = pool.stringToKey ("dp2", 123); + SG::StringPool::sgkey_t sgkey2b = pool.stringToKey ("dp2", 124); + assert (store.proxy_exact (sgkey2b) == dp2); + assert (store.proxy_exact (sgkey2a) == 0); + assert (dp2->transientAddress()->sgkey() == sgkey2a); +} + + +void test_addAlias() +{ + std::cout << "test_addAlias\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + + assert (store.addAlias ("dp1a", dp1).isSuccess()); + assert (store.addAlias ("dp1b", dp1).isSuccess()); + assert (dp1->refCount() == 3); + + assert (store.proxy (123, "dp1a") == dp1); + assert (store.proxy_exact (pool.stringToKey ("dp1a", 123)) == dp1); + + assert (dp1->transientAddress()->alias().count ("dp1a") == 1); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + assert (store.addAlias ("dpx", dp2).isSuccess()); + assert (dp2->refCount() == 2); + assert (dp2->transientAddress()->alias().count ("dpx") == 1); + + assert (store.addAlias ("dpx", dp1).isSuccess()); + assert (dp1->refCount() == 4); + assert (dp2->refCount() == 1); + assert (dp2->transientAddress()->alias().count ("dpx") == 0); + assert (dp1->transientAddress()->alias().count ("dpx") == 1); + assert (store.addAlias ("dpx", dp1).isSuccess()); + assert (dp1->refCount() == 4); + assert (dp2->refCount() == 1); +} + + +void test_addSymLink() +{ + std::cout << "test_addSymLink\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + + assert (store.proxy_exact (123, "dp1") == dp1); + assert (store.proxy_exact (124, "dp1") == dp1); + assert (dp1->transientAddress()->transientID(123)); + assert (dp1->transientAddress()->transientID(124)); + + assert (store.addSymLink (124, dp1).isSuccess()); + assert (store.proxy_exact (124, "dp1") == dp1); + + SG::DataProxy* dp2 = make_proxy (125, "dp1"); + assert (store.addToStore (125, dp2).isSuccess()); + assert (store.addSymLink (125, dp1).isFailure()); + assert (!dp1->transientAddress()->transientID(125)); +} + + +void test_proxy_exact() +{ + std::cout << "test_proxy_exact\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + + assert (store.proxy_exact (123, "dp1") == dp1); + assert (store.proxy_exact (124, "dp1") == 0); + assert (store.proxy_exact (123, "dp2") == 0); + SG::StringPool::sgkey_t sgkey = pool.stringToKey ("dp1", 123); + assert (store.proxy_exact (sgkey) == dp1); + assert (store.proxy_exact (sgkey+1) == 0); +} + + +void test_proxy() +{ + std::cout << "test_proxy\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + + assert (store.proxy (123, "dp1") == dp1); + assert (store.proxy (123, "") == dp1); + + assert (store.proxy (new SG::TransientAddress (123, "dp1")) == dp1); + + assert (store.addAlias ("dp1a", dp1).isSuccess()); + assert (store.addAlias ("dp1b", dp1).isSuccess()); + assert (store.proxy (123, "") == dp1); + + SG::DataProxy* dp2 = make_proxy (124, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + assert (store.proxy (123, "") == dp1); + + SG::DataProxy* dp3 = make_proxy (123, "dp3"); + assert (store.addToStore (123, dp3).isSuccess()); + assert (store.proxy (123, "") == 0); + assert (store.proxy (123, "dp3") == dp3); +} + + +void test_typeCount() +{ + std::cout << "test_typeCount\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + + assert (store.typeCount (123) == 2); + assert (store.typeCount (124) == 1); + assert (store.typeCount (125) == 0); +} + + +void test_tRange() +{ + std::cout << "test_tRange\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + + SG::DataStore::ConstStoreIterator tbeg; + SG::DataStore::ConstStoreIterator tend; + assert (store.tRange (tbeg, tend).isSuccess()); + + assert (tbeg->first == 123); + assert (tbeg->second.size() == 2); + ++tbeg; + assert (tbeg->first == 124); + assert (tbeg->second.size() == 1); + ++tbeg; + assert (tbeg == tend); +} + + +void test_pRange() +{ + std::cout << "test_pRange\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + + SG::ConstProxyIterator pbeg; + SG::ConstProxyIterator pend; + + assert (store.pRange (123, pbeg, pend).isSuccess()); + assert (pbeg->first == "dp1"); + assert (pbeg->second == dp1); + ++pbeg; + assert (pbeg->first == "dp2"); + assert (pbeg->second == dp2); + ++pbeg; + assert (pbeg == pend); + + assert (store.pRange (124, pbeg, pend).isSuccess()); + assert (pbeg->first == "dp1"); + assert (pbeg->second == dp1); + ++pbeg; + assert (pbeg == pend); + + assert (store.pRange (125, pbeg, pend).isFailure()); + assert (pbeg == pend); +} + + +void test_proxyList() +{ + std::cout << "test_proxyList\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + + std::list<SG::DataProxy*> pl; + assert (store.proxyList (pl).isSuccess()); + assert (pl.size() == 3); + + std::vector<SG::DataProxy*> pv (pl.begin(), pl.end()); + assert (pv[0] == dp1); + assert (pv[1] == dp2); + assert (pv[2] == dp1); +} + + +void test_keys() +{ + std::cout << "test_keys\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + + std::vector<std::string> v; + store.keys (123, v, true, false); + assert (v.size() == 2); + assert (v[0] == "dp1"); + assert (v[1] == "dp2"); + + store.keys (124, v, true, false); + assert (v.size() == 1); + assert (v[0] == "dp1"); + + assert (store.addAlias ("dp1a", dp1).isSuccess()); + store.keys (123, v, false, false); + assert (v.size() == 2); + assert (v[0] == "dp1"); + assert (v[1] == "dp2"); + + store.keys (123, v, true, false); + assert (v.size() == 3); + assert (v[0] == "dp1"); + assert (v[1] == "dp1a"); + assert (v[2] == "dp2"); + + SG::DataProxy* dp3 = make_proxy (125, "dp3"); + SG::DataProxy* dp4 = make_proxy (125, "dp4"); + assert (store.addToStore (125, dp3).isSuccess()); + assert (store.addToStore (125, dp4).isSuccess()); + TestProvider prov; + dp4->transientAddress()->setProvider (&prov, StoreID::SPARE_STORE); + + store.keys (125, v, true, false); + assert (v.size() == 2); + assert (v[0] == "dp3"); + assert (v[1] == "dp4"); + + store.keys (125, v, true, true); + assert (v.size() == 1); + assert (v[0] == "dp4"); +} + + +void test_removeProxy() +{ + std::cout << "test_removeProxy\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + assert (store.removeProxy (0, false, false).isFailure()); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + dp1->addRef(); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + assert (store.addAlias ("dp1x", dp1).isSuccess()); + + assert (store.proxy_exact (pool.stringToKey ("dp1", 123)) == dp1); + assert (store.proxy_exact (pool.stringToKey ("dp1", 124)) == dp1); + assert (store.proxy_exact (pool.stringToKey ("dp1x", 123)) == dp1); + assert (store.proxy (123, "dp1") == dp1); + assert (store.proxy (124, "dp1") == dp1); + assert (store.proxy (123, "dp1x") == dp1); + + assert (dp1->refCount() == 4); + + dp1->resetOnly (true); + assert (store.removeProxy (dp1, false, false).isSuccess()); + assert (dp1->refCount() == 4); + + dp1->resetOnly (false); + assert (store.removeProxy (dp1, false, false).isSuccess()); + assert (dp1->refCount() == 1); + assert (store.proxy_exact (pool.stringToKey ("dp1", 123)) == 0); + assert (store.proxy_exact (pool.stringToKey ("dp1", 124)) == 0); + assert (store.proxy_exact (pool.stringToKey ("dp1x", 123)) == 0); + assert (store.proxy (123, "dp1") == 0); + assert (store.proxy (124, "dp1") == 0); + assert (store.proxy (123, "dp1x") == 0); + +} + + +void test_clearStore() +{ + std::cout << "test_clearStore\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + DataObject* o1 = new DataObject; + dp1->setObject (o1); + dp1->addRef(); + assert (store.addToStore (123, dp1).isSuccess()); + assert (store.addSymLink (124, dp1).isSuccess()); + dp1->resetOnly (false); + + SG::DataProxy* dp2 = make_proxy (123, "dp2"); + assert (store.addToStore (123, dp2).isSuccess()); + DataObject* o2 = new DataObject; + dp2->setObject (o2); + dp2->addRef(); + + assert (dp1->refCount() == 3); + assert (dp2->refCount() == 2); + + int trans1; + dp1->registerTransient (&trans1); + assert (store.locatePersistent (&trans1) == dp1); + int trans2; + dp2->registerTransient (&trans2); + assert (store.locatePersistent (&trans2) == dp2); + + store.clearStore (false, false, nullptr); + + assert (store.locatePersistent (&trans1) == 0); + assert (store.locatePersistent (&trans2) == 0); + + assert (dp1->refCount() == 1); + assert (dp1->object() == o1); + assert (store.proxy (123, "dp1") == 0); + assert (store.proxy (124, "dp1") == 0); + assert (store.proxy_exact (pool.stringToKey ("dp1", 123)) == 0); + assert (store.proxy_exact (pool.stringToKey ("dp1", 124)) == 0); + + assert (dp2->refCount() == 2); + assert (dp2->object() == 0); + assert (store.proxy (123, "dp2") == dp2); + assert (store.proxy_exact (pool.stringToKey ("dp2", 123)) == dp2); + + store.clearStore (true, false, nullptr); + assert (dp2->refCount() == 1); + assert (store.proxy (123, "dp2") == 0); + assert (store.proxy_exact (pool.stringToKey ("dp2", 123)) == 0); +} + + +void test_t2p() +{ + std::cout << "test_t2p\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::DataProxy* dp1 = make_proxy (123, "dp1"); + assert (store.addToStore (123, dp1).isSuccess()); + + int trans1; + assert (store.locatePersistent (&trans1) == 0); + assert (store.t2pRegister (&trans1, dp1).isSuccess()); + assert (store.locatePersistent (&trans1) == dp1); + assert (store.locatePersistent (&trans1) == dp1); + assert (store.t2pRegister (&trans1, dp1).isFailure()); + store.t2pRemove (&trans1); + assert (store.locatePersistent (&trans1) == 0); +} + + +void test_dummy() +{ + std::cout << "test_dummy\n"; + + SGTest::TestStore pool; + SG::DataStore store (pool); + + SG::StringPool::sgkey_t sgkey = pool.stringToKey ("dp1", 456); + + SG::DataProxy* dp1 = make_proxy (0, ""); + dp1->transientAddress()->setSGKey (sgkey); + assert (store.addToStore (0, dp1).isSuccess()); + assert (dp1->refCount() == 1); + assert (store.proxy_exact (sgkey) == dp1); + + assert (store.proxy (456, "dp1") == dp1); + assert (dp1->clID() == 456); + assert (dp1->name() == "dp1"); + assert (dp1->refCount() == 1); + + SG::StringPool::sgkey_t sgkey2 = pool.stringToKey ("dp2", 456); + SG::DataProxy* dp2 = make_proxy (0, ""); + dp2->transientAddress()->setSGKey (sgkey2); + assert (store.addToStore (0, dp2).isSuccess()); + assert (dp2->refCount() == 1); + assert (store.proxy_exact (sgkey2) == dp2); + + assert (store.proxy (456, "dp2") == dp2); + assert (dp2->clID() == 456); + assert (dp2->name() == "dp2"); + assert (dp2->refCount() == 1); +} + + +int main() +{ + Athena::getMessageSvcQuiet = true; + test_ctor(); + test_addToStore(); + test_addAlias(); + test_addSymLink(); + test_proxy_exact(); + test_proxy(); + test_typeCount(); + test_tRange(); + test_pRange(); + test_proxyList(); + test_keys(); + test_removeProxy(); + test_clearStore(); + test_t2p(); + // pac routines not tested. + test_dummy(); + return 0; +} + + +// handle retrieval of dummied dp +// insert dummied dp diff --git a/EDM/athena/Control/SGTools/test/SGFolderItem_test.cxx b/EDM/athena/Control/SGTools/test/SGFolderItem_test.cxx new file mode 100644 index 00000000..8a98e03b --- /dev/null +++ b/EDM/athena/Control/SGTools/test/SGFolderItem_test.cxx @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/test/SGFolderItem_test.cxx + * @author scott snyder + * @date May, 2016 + * @brief Unit test for SGFolderItem. + */ + +#undef NDEBUG + + +#include "SGTools/SGFolderItem.h" +#include <iostream> +#include <cassert> + + +void test1() +{ + std::cout << "test1\n"; + + SG::FolderItem i1 (123, "key"); + assert (i1.id() == 123); + assert (i1.key() == "key"); + assert (i1.exact() == false); + assert (i1.isFolder() == false); + + SG::FolderItem i2 (456, "ley", true); + assert (i2.id() == 456); + assert (i2.key() == "ley"); + assert (i2.exact() == true); + assert (i2.isFolder() == false); + + SG::FolderItem i3 (123, "ley"); + + assert (!(i1 < i1)); + assert (i1 < i2); + assert (i1 < i3); + + assert (!(i2 < i1)); + assert (!(i2 < i2)); + assert (!(i2 < i3)); + + assert (!(i3 < i1)); + assert ( (i3 < i2)); + assert (!(i3 < i3)); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/SGTools.xml b/EDM/athena/Control/SGTools/test/SGTools.xml new file mode 100644 index 00000000..cf2d08d1 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/SGTools.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="SGToolsTest" type="makecheck" suite="Examples"> + <package>Control/SGTools</package> + <timelimit>10</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/SGTools/test/StringPool_test.cxx b/EDM/athena/Control/SGTools/test/StringPool_test.cxx new file mode 100644 index 00000000..66c35dd9 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/StringPool_test.cxx @@ -0,0 +1,150 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StringPool_test.cxx,v 1.2 2007-12-10 22:20:04 ssnyder Exp $ +/** + * @file SGTools/StringPool_test.cxx + * @author scott snyder + * @date Mar 2007 + * @brief Regression test for StringPool. + */ + + +#undef NDEBUG + +#include "SGTools/StringPool.h" +#include "SGTools/crc64.h" +#include <vector> +#include <string> +#include <cstdlib> +#include <cassert> +#include <iostream> + + +const char* teststrings[] = { + "", + "MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE", + "MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE", + "ajsdla lkjasd lkjasd ", + "paks aspdk pok asd", + "asd laskjkd lkajsd", +}; + + +std::string randstring() +{ + char buf[256]; + int len = std::rand() % 256; + for (int i = 0; i < len; i++) + buf[i] = (char)(std::rand() % 256); + return std::string (buf, len); +} + + +void checkPool (const SG::StringPool& sp, + const std::vector<SG::StringPool::sgkey_t>& keys, + const std::vector<SG::StringPool::sgaux_t>& aux, + const std::vector<std::string>& strings, + bool test2) + +{ + for (size_t i = 0; i < keys.size(); i++) { + SG::StringPool::sgaux_t auxout = 0; + assert (*sp.keyToString (keys[i]) == strings[i]); + assert (*sp.keyToString (keys[i], auxout) == strings[i]); + assert (auxout == aux[i]); + auxout = 0; + if (test2) { + assert (*sp.keyToString (keys[i]+1, auxout) == strings[i]); + assert (auxout == aux[i]); + } + else + assert (!sp.keyToString (keys[i]+1)); + } +} + + +void test1() +{ + std::cout << "test1\n"; + + SG::StringPool sp; + std::vector<std::string> strings; + std::vector<SG::StringPool::sgkey_t> keys; + std::vector<SG::StringPool::sgaux_t> aux; + size_t ntest = sizeof (teststrings) / sizeof (teststrings[0]); + for (size_t i = 0; i < ntest; i++) { + SG::StringPool::sgkey_t key = sp.stringToKey (teststrings[i], i); + assert (key <= SG::StringPool::sgkey_t_max); + strings.push_back (teststrings[i]); + keys.push_back (key); + aux.push_back (i); + std::cout << SG::crc64format (key) << " " << teststrings[i] << "\n"; + } + size_t nstore = ntest; + assert (sp.size() == nstore); + + std::cout << "pool dump\n"; + sp.dump(); + + for (int i=0; i < 1000; i++) { + SG::StringPool::sgaux_t auxkey = std::rand(); + std::string str = randstring(); + SG::StringPool::sgkey_t key = sp.stringToKey (str, auxkey); + assert (key <= SG::StringPool::sgkey_t_max); + strings.push_back (str); + keys.push_back (key); + aux.push_back (auxkey); + } + + nstore += 1000; + assert (sp.size() == nstore); + checkPool (sp, keys, aux, strings, false); + + for (size_t i = 0; i < keys.size(); i++) { + assert (sp.registerKey (keys[i]+1, strings[i], aux[i])); + } + + nstore *= 2; + assert (sp.size() == nstore); + checkPool (sp, keys, aux, strings, true); + + assert (sp.registerKey (keys[10], strings[10], aux[10])); + assert (!sp.registerKey (keys[10], strings[11], aux[10])); + assert (!sp.registerKey (keys[10], strings[10], aux[11])); + nstore += 2; + + SG::StringPool sp2 = sp; + + sp.clear(); + assert (sp.size() == 0); + std::cout << "pool dump2\n"; + sp.dump(); + + assert (sp2.size() == nstore); + checkPool (sp2, keys, aux, strings, true); + + SG::StringPool sp3 (std::move (sp2)); + assert (sp2.size() == 0); + assert (sp3.size() == nstore); + checkPool (sp3, keys, aux, strings, true); + + sp2 = sp3; + assert (sp2.size() == nstore); + assert (sp3.size() == nstore); + checkPool (sp2, keys, aux, strings, true); + checkPool (sp3, keys, aux, strings, true); + + sp = std::move (sp3); + assert (sp.size() == nstore); + assert (sp3.size() == 0); + checkPool (sp, keys, aux, strings, true); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/TransientAddress_test.cxx b/EDM/athena/Control/SGTools/test/TransientAddress_test.cxx new file mode 100644 index 00000000..3a58bbb6 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/TransientAddress_test.cxx @@ -0,0 +1,181 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file TransientAddress_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2013 + * @brief Regression tests for TransientAddress. + */ + +#undef NDEBUG +#include "SGTools/TransientAddress.h" +#include "AthenaKernel/IAddressProvider.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include <iostream> +#include <cstdlib> +#include <cassert> + + +class TestAddress + : public IOpaqueAddress +{ +public: + TestAddress (int x) : m_x (x), m_ref(0) {} + /// Add reference to object + virtual unsigned long addRef (); + /// release reference to object + virtual unsigned long release (); + /// Retrieve class information from link + virtual const CLID& clID () const { std::abort(); } + /// Retrieve service type + virtual long svcType () const { std::abort(); } + /// Update branch name + virtual IRegistry* registry () const { std::abort(); } + /// Update directory pointer + virtual void setRegistry(IRegistry* /*r*/) { std::abort(); } + /// Retrieve String parameters + virtual const std::string* par () const { std::abort(); } + /// Access to generic link parameters + virtual const unsigned long* ipar () const { std::abort(); } + + int m_x; + int m_ref; +}; + + +class TestProvider + : public IAddressProvider +{ +public: + virtual StatusCode updateAddress(StoreID::type /*storeID*/, + SG::TransientAddress* /*pTAd*/) + { return StatusCode::SUCCESS; } +}; + + +unsigned long TestAddress::addRef() +{ + ++m_ref; + std::cout << "addRef " << m_x << " " << m_ref << "\n"; + return m_ref; +} + + +unsigned long TestAddress::release() +{ + --m_ref; + std::cout << "release " << m_x << " " << m_ref << "\n"; + return m_ref; +} + + +void test1() +{ + std::cout << "test1\n"; + + SG::TransientAddress tad1; + assert (tad1.clID() == CLID_NULL); + assert (tad1.name() == ""); + assert (tad1.transientID().size() == 0); + assert (tad1.alias().size() == 0); + assert (!tad1.isValid()); + assert (tad1.provider() == 0); + assert (tad1.storeID() == StoreID::UNKNOWN); + assert (tad1.address() == 0); + assert (tad1.sgkey() == 0); + tad1.setID (123, "key"); + assert (tad1.name() == "key"); + assert (tad1.clID() == 123); + assert (tad1.transientID().size() == 1); + assert (tad1.alias().size() == 0); + + SG::TransientAddress tad2 (123, "key"); + assert (tad2.name() == "key"); + assert (tad2.clID() == 123); + assert (tad2.transientID().size() == 1); + assert (tad2.alias().size() == 0); + assert (!tad2.isValid()); + assert (tad2.provider() == 0); + assert (tad2.storeID() == StoreID::UNKNOWN); + assert (tad2.address() == 0); + assert (tad2.sgkey() == 0); + + tad2.setSGKey (876); + assert (tad2.sgkey() == 876); + + assert (tad2.transientID (123)); + assert (!tad2.transientID (124)); + tad2.setTransientID (124); + assert (tad2.transientID (124)); + assert (tad2.transientID().size() == 2); + + tad2.setAlias ("key2"); + assert (tad2.alias().size() == 1); + std::set<std::string> a; + a.insert ("key3"); + a.insert ("key4"); + tad2.setAlias (a); + assert (tad2.alias().size() == 2); + assert (tad2.alias().count ("key2") == 0); + assert (tad2.alias().count ("key3") == 1); + tad2.removeAlias ("key3"); + assert (tad2.alias().size() == 1); + assert (tad2.alias().count ("key3") == 0); + + TestAddress ad1(1); + SG::TransientAddress tad3 (123, "key", &ad1); + assert (tad3.name() == "key"); + assert (tad3.clID() == 123); + assert (tad3.isValid()); + assert (tad3.provider() == 0); + assert (tad3.storeID() == StoreID::UNKNOWN); + assert (tad3.address() == &ad1); + + TestAddress ad2(2); + tad3.setAddress (&ad2); + assert (tad3.isValid()); + assert (tad3.address() == &ad2); + tad3.reset(); + assert (!tad3.isValid()); + assert (tad3.address() == 0); + + tad3.setAddress (&ad2); + tad3.clearAddress (false); + tad3.reset(); + assert (tad3.isValid()); + assert (tad3.address() == &ad2); + tad3.clearAddress (true); + tad3.reset(); + assert (!tad3.isValid()); + assert (tad3.address() == 0); + + TestProvider tp; + tad3.setProvider (&tp, StoreID::SPARE_STORE); + assert (tad3.provider() == &tp); + assert (tad3.storeID() == StoreID::SPARE_STORE); + assert (tad3.isValid()); + tad3.consultProvider (false); + assert (!tad3.isValid()); + tad3.consultProvider (true); + assert (tad3.isValid()); + + SG::TransientAddress tad4(0, ""); + assert (tad4.clID() == CLID_NULL); + assert (tad4.name() == ""); + assert (tad4.transientID().size() == 0); + tad4.setID (123, "key"); + assert (tad4.name() == "key"); + assert (tad4.clID() == 123); + assert (tad4.transientID().size() == 1); + assert (tad4.alias().size() == 0); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/VersionedKey_test.cxx b/EDM/athena/Control/SGTools/test/VersionedKey_test.cxx new file mode 100644 index 00000000..b2f70726 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/VersionedKey_test.cxx @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG + +#include "SGTools/SGVersionedKey.h" +#include <cstring> +#include <iostream> +#include <stdexcept> +#include <string> +#include <cassert> +using namespace std; +using namespace SG; + +#define SGASSERTERROR( FALSEEXPR ) \ + std::cerr << "Now we expect to see an error message:" << std::endl \ + << "----Error Message Starts--->>" << std::endl; \ + assert(!FALSEEXPR); \ + std::cerr<< "<<---Error Message Ends-------" << std::endl + +int main() { + VersionedKey vk1("bla", 1); + std::string key("Bleah"); + unsigned int version(99); + VersionedKey vk2(key, version); + VersionedKey vk3(";00;default"); + VersionedKey vk4("default"); + + cout << "Versioned Key 1=" << vk1 << endl; + std::string k1; + unsigned char v1(0); + vk1.decode(k1,v1); + assert("bla" == k1); + assert(1 == v1); + cout << "Versioned Key 2=" << vk2 << endl; + vk2.decode(k1,v1); + assert("Bleah"== k1); + assert(99 == v1); + assert(99 == vk2.version()); + cout << "Versioned Key 3=" << vk3 << endl; + vk3.decode(k1,v1); + assert("default" == k1); + assert(0 == v1); + vk4.decode(k1,v1); + assert(0 == v1); + + assert("bla" == vk1.key()); + assert("Bleah" == vk2.key()); + assert("default" == vk3.key()); + + + //compare vkeys + VersionedKey ck1("bla", 1); + VersionedKey ck2("bla", 2); + VersionedKey ck3("blu", 0); + VersionedKey ck4("blu", 0); + assert(ck1 < ck2); + assert(!(ck2 < ck1)); + assert(ck1 < ck3); + assert(!(ck3 < ck1)); + assert(ck2 < ck3); + assert(!(ck3 < ck1)); + assert(!(ck3 < ck4)); + assert(!(ck4 < ck3)); + + assert(!ck1.sameKey(ck4)); + assert(ck3.sameKey(ck4)); + assert(ck3.sameKey("blu")); + std::string bluString("blu"); + assert(ck3.sameKey(bluString)); + + return 0; +} + + + diff --git a/EDM/athena/Control/SGTools/test/crc64_test.cxx b/EDM/athena/Control/SGTools/test/crc64_test.cxx new file mode 100644 index 00000000..b97ad615 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/crc64_test.cxx @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: crc64_test.cxx,v 1.2 2007-03-08 02:02:06 ssnyder Exp $ +/** + * @file SGTools/crc64_test.cxx + * @author scott snyder, originally from David T. Jones + * @date Mar 2007 + * @brief Regression tests for CRC-64 calculation. + */ + +#undef NDEBUG + +#include "SGTools/crc64.h" +#include <iostream> +#include <cassert> + + +void testextend (const std::string& str, unsigned int x) +{ + uint64_t crc1 = SG::crc64 (str); + crc1 = SG::crc64addint (crc1, x); + + std::string str2 = str; + while (x > 0) { + str2.push_back ((char)(x&0xff)); + x >>= 8; + } + assert (crc1 == SG::crc64 (str2)); +} + + +int main() +{ + const char* testin1 = "MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGTVIRGATTSYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE"; + const char* testout1 = "C874767DA8254746"; + const char* testin2 = "MNIIQGNLVGTGLKIGIVVGRFNDFITSKLLSGAEDALLRHGVDTNDIDVAWVPGAFEIPFAAKKMAETKKYDAIITLGDVIRGATTHYDYVCNEAAKGIAQAANTTGVPVIFGIVTTENIEQAIERAGTKAGNKGVDCAVSAIEMANLNRSFE"; /* Differs from 1st seq in two places */ + const char* testout2 = "2DF1AA17420FCA3F"; + + assert (SG::crc64digest (testin1) == std::string (testout1)); + assert (SG::crc64digest (testin2) == std::string (testout2)); + + testextend (testin1, 54356); + testextend (testin2, 9812674); + return 0; +} + diff --git a/EDM/athena/Control/SGTools/test/exceptions_test.cxx b/EDM/athena/Control/SGTools/test/exceptions_test.cxx new file mode 100644 index 00000000..aacbba6b --- /dev/null +++ b/EDM/athena/Control/SGTools/test/exceptions_test.cxx @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file SGTools/test/exceptions_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2014 + * @brief Regression tests for exceptions. + */ + +#undef NDEBUG +#include "SGTools/exceptions.h" +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + + std::cout << SG::ExcBadDataProxyCast (123, typeid(int)).what() << "\n"; + + std::cout << SG::ExcProxyCollision (123, "abc", 456, "def").what() << "\n"; +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Control/SGTools/test/safe_clid_test.cxx b/EDM/athena/Control/SGTools/test/safe_clid_test.cxx new file mode 100644 index 00000000..c5a042c6 --- /dev/null +++ b/EDM/athena/Control/SGTools/test/safe_clid_test.cxx @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG + +#include "SGTools/safe_clid.h" +#include "SGTools/CLASS_DEF.h" +#include "GaudiKernel/DataObject.h" +#include <cassert> + +#include <iostream> + +struct A {}; +struct B {}; +CLASS_DEF (B, 98765, 0) +struct C + : public DataObject +{ + static CLID& classID() { static CLID clid = 44444; return clid; } +}; + +int main() +{ + assert (SG::safe_clid<int> () == 0); + assert (SG::safe_clid<A> () == 0); + assert (SG::safe_clid<B> () == 98765); + assert (SG::safe_clid<C> () == 44444); + return 0; +} + diff --git a/EDM/athena/Control/StoreGate/AUTHORS b/EDM/athena/Control/StoreGate/AUTHORS new file mode 100644 index 00000000..a64e5ad2 --- /dev/null +++ b/EDM/athena/Control/StoreGate/AUTHORS @@ -0,0 +1,3 @@ +Paolo Calafiura <Paolo.Calafiura@cern.ch> +Hong Ma <hma@bnl.gov> +Srini Rajagopalan <srinir@bnl.gov> diff --git a/EDM/athena/Control/StoreGate/CMakeLists.txt b/EDM/athena/Control/StoreGate/CMakeLists.txt new file mode 100644 index 00000000..1851dfb9 --- /dev/null +++ b/EDM/athena/Control/StoreGate/CMakeLists.txt @@ -0,0 +1,139 @@ +# $Id: CMakeLists.txt 743842 2016-04-29 08:16:42Z ssnyder $ +################################################################################ +# Package: StoreGate +################################################################################ + +# Declare the package name: +atlas_subdir( StoreGate ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/AthAllocators + Control/AthContainersInterfaces + Control/AthenaKernel + Control/SGTools + GaudiKernel + PRIVATE + AtlasTest/TestTools + Control/CxxUtils ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) +find_package( TBB ) + +# Component(s) in the package: +atlas_add_library( StoreGateLib src/*.cxx + PUBLIC_HEADERS StoreGate + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${TBB_LIBRARIES} AthAllocators AthenaKernel + SGTools GaudiKernel + PRIVATE_LINK_LIBRARIES CxxUtils TestTools ) + +atlas_add_component( StoreGate src/components/*.cxx + LINK_LIBRARIES GaudiKernel StoreGateLib ) + +# Test library used by the package's unit tests: +atlas_add_library( SGtests test/SGtests.cxx + NO_PUBLIC_HEADERS + LINK_LIBRARIES StoreGateLib TestTools ) + +# Declare the package's tests: +atlas_add_test( ActiveStore_test + SOURCES test/ActiveStore_test.cxx + LINK_LIBRARIES SGtests + EXTRA_PATTERNS "JobOptionsSvc +INFO" + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +if( ATHENAHIVE ) + set( _hivePatterns "JobOptionsSvc +INFO|StoreGateSvc.*DEBUG|HiveMgrSvc +DEBUG" ) +else() + set( _hivePatterns ".*" ) +endif() +atlas_add_test( SGHive_test + SOURCES test/SGHive_test.cxx + LINK_LIBRARIES SGtests + EXTRA_PATTERNS "${_hivePatterns}" + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( DataHandle_test + SOURCES test/DataHandle_test.cxx + LINK_LIBRARIES SGtests + EXTRA_PATTERNS "ClassIDSvc Initialized successfully|^HistogramPersis.* INFO" ) + +atlas_add_test( SGIterator_test + SOURCES test/SGIterator_test.cxx + LINK_LIBRARIES SGtests + EXTRA_PATTERNS "^HistogramPersis.* INFO" ) + +atlas_add_test( KeyConcept_test + SOURCES test/KeyConcept_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( StoreClearedIncident_test + SOURCES test/StoreClearedIncident_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( SegMemSvc_test + SOURCES test/SegMemSvc_test.cxx + LINK_LIBRARIES SGtests + EXTRA_PATTERNS "^HistogramPersis.* INFO" ) + +atlas_add_test( exceptions_test + SOURCES test/exceptions_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( VarHandleKey_test + SOURCES test/VarHandleKey_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( VarHandleKeyProperty_test + SOURCES test/VarHandleKeyProperty_test.cxx + LINK_LIBRARIES SGtests + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( VarHandleProperty_test + SOURCES test/VarHandleProperty_test.cxx + LINK_LIBRARIES SGtests + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( ReadHandleKey_test + SOURCES test/ReadHandleKey_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( UpdateHandleKey_test + SOURCES test/UpdateHandleKey_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( VarHandleBase_test + SOURCES test/VarHandleBase_test.cxx + LINK_LIBRARIES SGtests + EXTRA_PATTERNS "could not get proxy for|try using a ReadHandle" + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( VarHandles_test + SOURCES test/VarHandles_test.cxx + LINK_LIBRARIES SGtests ) + +atlas_add_test( WriteHandle_test + SOURCES test/WriteHandle_test.cxx + LINK_LIBRARIES SGtests + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( ReadHandle_test + SOURCES test/ReadHandle_test.cxx + LINK_LIBRARIES SGtests + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +atlas_add_test( UpdateHandle_test + SOURCES test/UpdateHandle_test.cxx + LINK_LIBRARIES SGtests + ENVIRONMENT "JOBOPTSEARCHPATH=${CMAKE_CURRENT_SOURCE_DIR}/share" ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/StoreGate_jobOptions.txt + share/StoreGate_jobOptions.py + share/SGHive_test.txt + share/ActiveStore_test.txt ) + diff --git a/EDM/athena/Control/StoreGate/StoreGate/ActiveStoreSvc.h b/EDM/athena/Control/StoreGate/StoreGate/ActiveStoreSvc.h new file mode 100644 index 00000000..86a57dd1 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ActiveStoreSvc.h @@ -0,0 +1,176 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_ACTIVESTORESVC_H +#define STOREGATE_ACTIVESTORESVC_H + +#include "GaudiKernel/Service.h" +#include "GaudiKernel/StatusCode.h" + +#include "AthenaKernel/IProxyDict.h" + +class StoreGateSvc; +class ISvcLocator; + +template <class TYPE> class SvcFactory; + +/** @class ActiveStoreSvc + * @brief A service that caches a pointer to the currently active store. + * It also implements the IProxyDict store interface + * + * In most jobs the active store is simply the default event store + * (named "StoreGateSvc"). When doing pile-up (and perhaps later on in + * multi-threaded jobs, the active store changes during the event loop + * execution. It is important, for example, that converters always refer + * to the active store rather than to the default one. + * @author ATLAS Collaboration + * $Id: ActiveStoreSvc.h,v 1.10 2009-04-18 02:56:20 calaf Exp $ + **/ + +class ActiveStoreSvc : public IProxyDict, + public Service +{ +public: + friend class SvcFactory<ActiveStoreSvc>; + + ///returns pointer to the active store as StoreGateSvc + inline StoreGateSvc* activeStore() const { + return p_activeStore; + } + + ///dereference operator to access the active store + inline StoreGateSvc* operator->() const { + return activeStore(); + } + + /// TEMPORARY: avoid warings + using IProxyDict::proxy; + + ///set the active store pointer: used by the event loop mgrs + void setStore(StoreGateSvc* s); + + /// get proxy for a given data object address in memory + virtual SG::DataProxy* proxy(const void* const pTransient) const override; + + /// get proxy with given id and key. Returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key) const override; + + /// Get proxy given a hashed key+clid. + /// Find an exact match; no handling of aliases, etc. + /// Returns 0 to flag failure. + virtual SG::DataProxy* proxy_exact (SG::sgkey_t sgkey) const override; + + /// return the list of all current proxies in store + virtual std::vector<const SG::DataProxy*> proxies() const override; + //@} + + /// Raw addition of a proxy to the store. + StatusCode addToStore (CLID id, SG::DataProxy* proxy) override; + + /** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ + virtual + SG::DataProxy* recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) override; + + + /** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ + virtual StatusCode updatedObject (CLID id, const std::string& key) override; + + + /** + * @brief Find the key for a string/CLID pair. + * @param str The string to look up. + * @param clid The CLID associated with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ + virtual + sgkey_t stringToKey (const std::string& str, CLID clid) override; + + /** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key) const override; + + /** + * @brief Find the string and CLID corresponding to a given key. + * @param key The key to look up. + * @param clid[out] The found CLID. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key, + CLID& clid) const override; + + /** + * @brief Remember an additional mapping from key to string/CLID. + * @param key The key to enter. + * @param str The string to enter. + * @param clid The CLID associated with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + * Logs an error if @c key already corresponds to a different string. + */ + virtual + void registerKey (sgkey_t key, + const std::string& str, + CLID clid) override; + + + //@{ @name Gaudi Service boilerplate + virtual StatusCode initialize() override; + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ) override; + //@} + + /// not really kosher: should be in IActiveStoreSvc + static const InterfaceID& interfaceID(); + +private: + StoreGateSvc* p_activeStore; + std::string m_storeName; //< property: storegate instance name + +protected: + + /// Standard Service Constructor. sets active store to default event store + ActiveStoreSvc(const std::string& name, ISvcLocator* svc); + + virtual ~ActiveStoreSvc() override; + +}; +#endif // STOREGATE_ACTIVESTORESVC_H + + + diff --git a/EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.h new file mode 100644 index 00000000..40915798 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_CONDHANDLEKEY_H +#define STOREGATE_CONDHANDLEKEY_H 1 + +#include "AthenaKernel/CondCont.h" +#include "StoreGate/VarHandleKey.h" +#include "StoreGate/StoreGateSvc.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/MsgStream.h" + +namespace SG { + + template <class T> + class CondHandleKey : public VarHandleKey { + + public: + CondHandleKey( const std::string& key, + const std::string& dbKey, + Gaudi::DataHandle::Mode a ); + +// CondHandleKey& operator= (const std::string& sgkey); + + StatusCode initialize(); + + const std::string& dbKey() const { return m_dbKey; } + void setDbKey(const std::string& dbKey) { m_dbKey = dbKey; } + + protected: + bool isInit() const { return m_isInit; } + + CondCont<T>* getCC() const { return m_cc; } + + StoreGateSvc* getCS() const; + + private: + + ServiceHandle<StoreGateSvc> m_cs; + CondCont<T>* m_cc{0}; + + std::string m_dbKey{""}; + + bool m_isInit {false}; + + }; + + +} + +#include "StoreGate/CondHandleKey.icc" + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.icc b/EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.icc new file mode 100644 index 00000000..6666dc83 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/CondHandleKey.icc @@ -0,0 +1,86 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +namespace SG { + + template <class T> + CondHandleKey<T>::CondHandleKey(const std::string& key, + const std::string& dbKey, + Gaudi::DataHandle::Mode mode ) : + VarHandleKey(ClassID_traits<T>::ID(), key, mode, + "StoreGateSvc/ConditionStore"), + m_cs("StoreGateSvc/ConditionStore","CondHandleKey"), + m_dbKey(dbKey) + {} + + //--------------------------------------------------------------------------- + + template <class T> + StatusCode + CondHandleKey<T>::initialize() { + if (m_isInit) return StatusCode::SUCCESS; + + + if (VarHandleKey::initialize() != StatusCode::SUCCESS) { + return StatusCode::FAILURE; + } + + if (!m_cs.isValid()) { + MsgStream msg(Athena::getMessageSvc(), "CondHandleKey"); + msg << MSG::ERROR + << "CondHandleKey::initialize() :Unable to locate ConditionStore " + << m_cs.name() + << endmsg; + return StatusCode::FAILURE; + } + + + if (m_cs->contains< CondCont<T> > (Gaudi::DataHandle::objKey())) { + if (m_cs->retrieve(m_cc, Gaudi::DataHandle::objKey()).isFailure()) { + MsgStream msg(Athena::getMessageSvc(), "CondHandleKey"); + msg << MSG::ERROR + << "CondHandleKey::init(): unable to retrieve CondCont of " + << Gaudi::DataHandle::fullKey() << " from ConditionStore" + << endmsg; + return StatusCode::FAILURE; + } + } else { + m_cc = new CondCont<T>(Gaudi::DataHandle::fullKey()); + if (m_cs->record(m_cc, Gaudi::DataHandle::objKey()).isFailure()) { + MsgStream msg(Athena::getMessageSvc(), "CondHandleKey"); + msg << MSG::ERROR + << "CondHandleKey::init(): unable to record empty CondCont of " + << Gaudi::DataHandle::fullKey() << " in ConditionStore" << endmsg; + delete m_cc; + m_cc = 0; + return StatusCode::FAILURE; + } + } + + + m_isInit = true; + + return StatusCode::SUCCESS; + + } + + //--------------------------------------------------------------------------- + + template <class T> + StoreGateSvc* + CondHandleKey<T>::getCS() const { + if (!m_cs.isValid()) { + MsgStream msg(Athena::getMessageSvc(), "CondHandleKey"); + msg << MSG::ERROR + << "CondHandleKey::getCS() : Unable to locate ConditionStore" + << endmsg; + return 0; + } + + return m_cs.get(); + } + + +} diff --git a/EDM/athena/Control/StoreGate/StoreGate/DataHandle.h b/EDM/athena/Control/StoreGate/StoreGate/DataHandle.h new file mode 100644 index 00000000..98c6765c --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/DataHandle.h @@ -0,0 +1,191 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file DataHandle.h + * defines an "iterator" over instances of a given type in StoreGateSvc + */ +#ifndef STOREGATE_DATAHANDLE_H +#define STOREGATE_DATAHANDLE_H + +#include "SGTools/DataBucket.h" +#include "SGTools/ProxyMap.h" +#include "AthenaKernel/IResetable.h" +#include "AthenaKernel/IProxyDict.h" +#include "SGTools/DataProxy.h" +#include "SGTools/DataHandleBase.h" +#include <iterator> + +template <typename DATA> +class DataHandle; + +template <class DATA> +bool operator== (const DataHandle<DATA>& h1, + const DataHandle<DATA>& h2); + +template <class DATA> +bool operator!= (const DataHandle<DATA>& h1, + const DataHandle<DATA>& h2); + +/** @class DataHandle + * @brief an iterator over instances of a given type in StoreGateSvc. It d-casts + * and caches locally the pointed-at object, to speed-up subsequent accesses. + * It can be reset by the store for asynchronous updates (IOVSvc) + * + * Holds a reference count on the proxy to which it's currently pointing. + * Note: one may think that we should hold reference counts for the + * entire range which the DataHandle references (if it is a range). + * The problem with this is that the range may change underneath us. + * For example, if someone does a SG record, then a new element may appear + * within the range. So we only hold the refcount for the object + * to which we're currently pointing. + * + * @param DATA the data object type + * @author ATLAS Collaboration + * $Id: DataHandle.h,v 1.40 2008-09-26 23:37:52 calaf Exp $ + **/ +template <typename DATA> +class DataHandle : + public DataHandleBase, + public std::iterator<std::forward_iterator_tag, DATA> +{ +public: + typedef std::iterator<std::forward_iterator_tag, DATA> base_t; + + //FIXME this should come from iterator inher! + typedef typename base_t::iterator_category iterator_category; + typedef typename base_t::value_type value_type; + typedef typename base_t::difference_type difference_type; + typedef typename base_t::pointer pointer_type; + typedef const DATA* const_pointer_type; + typedef typename base_t::reference reference_type; + typedef const DATA& const_reference_type; + + typedef DataHandleBase::ID_type ID_type; + + /// \name structors and assignment + //@{ + DataHandle(); + DataHandle(const DataHandle& h); + DataHandle& operator= (const DataHandle& h); + DataHandle& operator= (const DATA& d) + { + typename DataHandle<DATA>::pointer_type ptr = this->ptr(); + if (ptr) { + *ptr = d; + } else { + std::cerr << "invalid proxy\n"; + } + return *this; + } + + virtual ~DataHandle(); ///< unbind from the proxy before we go + //@} + + /// \name validity checks + //@{ + bool isValid() const; ///<RETRIEVES the DO to check it is valid and unlocked + bool isValid(); ///<RETRIEVES the DO to check it is valid + + // FIXME op! is to keep backward compatibility with Gaudi + // FIXME similar to checking the SmartDataPtr + // FIXME dangerous stuff: remove! + ///DEPRECATED for statements like: if (!DataHandle<XXX>) {...} + bool operator !() const { return !isValid(); } + + //FIXME VERY dangerous stuff: remove! + ///DEPRECATED for statements like: if (DataHandle<XXX>) {...} + operator int() const { return isValid(); } + //@} + + /// \name iterator interface + //@{ + const DataHandle& operator++ () const; ///<prefix + DataHandle operator++ (int) const; ///<postfix + + const_pointer_type operator->() const { return cptr(); } + pointer_type operator->() { return ptr(); } + + const_reference_type operator*() const { return *cptr(); } + reference_type operator*() { return *ptr(); } + //@} + + /// \name access to the underlying ptr + //@{ + operator pointer_type() { return ptr(); } ///< often ambiguos + operator const_pointer_type() const { return cptr(); } ///< often ambiguos + + const_pointer_type cptr() const; ///< safer explicit ptr accessor + pointer_type ptr(); ///< safer explicit ptr accessor + + // Should be like this. + //virtual void reset (bool /*hard*/) override { m_ptr = 0; } ///< reset pointer + // Temp workaround for TrigDecisionTool back-compat. + virtual void reset (bool /*hard*/) override { m_ptr = 0; reset(); } + virtual void reset () override { m_ptr = 0; } + //@} + + /// \name other constructors and methods for SG internal use + //@{ + DataHandle(SG::DataProxy* proxy); ///< + DataHandle(const SG::ConstProxyIterator& itr1, + const SG::ConstProxyIterator& itr2); + + //@} + + /// the CLID of the object we are bound to + virtual CLID clid() const override { return ClassID_traits<DATA>::ID(); } + + friend + bool operator==<>(const DataHandle<DATA>& h1, + const DataHandle<DATA>& h2); + friend + bool operator!=<>(const DataHandle<DATA>& h1, + const DataHandle<DATA>& h2); +private: + + mutable pointer_type m_ptr; + pointer_type dataPointer() const; + + +}; + +/// \name Comparison ops (compare proxies) +//@{ +template <class DATA> +bool operator==(const DataHandle<DATA>& h1, + const DataHandle<DATA>& h2) +{ + return (h1.m_proxy == h2.m_proxy); +} +template <class DATA> +bool operator!=(const DataHandle<DATA>& h1, + const DataHandle<DATA>& h2) +{ + return (h1.m_proxy != h2.m_proxy); +} +//@} + +#ifndef STOREGATE_DATAHANDLE_ICC +#include "StoreGate/DataHandle.icc" +#endif + +/* FIXME LEGACY - No dependency on ActiveStoreSvc here, but a number of Muon AtlasEvent packages are + getting the include through this one!!!! */ + +#include "StoreGate/ActiveStoreSvc.h" + +#endif // STOREGATE_DATAHANDLE_H + + + + + + + + + + + diff --git a/EDM/athena/Control/StoreGate/StoreGate/DataHandle.icc b/EDM/athena/Control/StoreGate/StoreGate/DataHandle.icc new file mode 100644 index 00000000..e389d853 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/DataHandle.icc @@ -0,0 +1,194 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_DATAHANDLE_ICC +#define STOREGATE_DATAHANDLE_ICC + +#include "SGTools/DataBucketBase.h" + +/////////////////////////////////////////////////////////////////////////////// +// CONSTRUCTORS +/////////////////////////////////////////////////////////////////////////////// + +template <class DATA> +DataHandle<DATA>::DataHandle() : + DataHandleBase(), + m_ptr(0) +{ } + +//.................................................................... + +template <class DATA> +DataHandle<DATA>::DataHandle(const DataHandle& h): + DataHandleBase(h), + m_ptr(h.m_ptr) +{} + +//.................................................................... + +template <class DATA> +DataHandle<DATA>& +DataHandle<DATA>::DataHandle::operator= (const DataHandle& h) +{ + if (this != &h) { + this->DataHandleBase::operator=(h); + m_ptr = h.m_ptr; + } + return *this; +} + +//.................................................................... + +template <class DATA> +DataHandle<DATA>::DataHandle(SG::DataProxy* proxy) : + DataHandleBase(proxy), + m_ptr(0) +{} + +//.................................................................... + +template <class DATA> +DataHandle<DATA>::DataHandle(const SG::ConstProxyIterator &itr, + const SG::ConstProxyIterator &itrEnd) : + DataHandleBase(itr, itrEnd), + m_ptr(0) +{} + + +// DESTRUCTOR + +template <class DATA> +DataHandle<DATA>::~DataHandle() +{ +} + + +/////////////////////////////////////////////////////////////////////////////// +// ITERATION OPERATORS: +/////////////////////////////////////////////////////////////////////////////// + +template <class DATA> +const DataHandle<DATA>& +DataHandle<DATA>::operator++() const //prefix +{ + if (m_proxy) m_proxy->release(); + m_proxy = 0; + m_ptr = 0; // reset pointer to perform retrieveObject + + // set the iterator to the next valid proxy (or end) + if (m_useItr && m_itr != m_itrEnd) + { + while (m_itr != m_itrEnd) { + ++m_itr; + if (m_itr != m_itrEnd && m_itr->second->isValid() ) + { + m_proxy = (*m_itr).second; + break; + } + } + } + + if (m_proxy) m_proxy->addRef(); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// +template <class DATA> +DataHandle<DATA> +DataHandle<DATA>::operator++ (int) const //postfix +{ + DataHandle<DATA> ret(*this); + if (m_proxy) m_proxy->release(); + m_proxy = 0; + m_ptr = 0; // reset pointer to perform retrieveObject + + // set the iterator to the next valid proxy (or end) + if (m_useItr && m_itr != m_itrEnd) + { + while (m_itr != m_itrEnd) { + ++m_itr; + if (m_itr != m_itrEnd && m_itr->second->isValid() ) + { + m_proxy = m_itr->second; + break; + } + } + } + + if (m_proxy) m_proxy->addRef(); + return ret; +} + + +/////////////////////////////////////////////////////////////////////////////// +// ACCESSOR METHODS: +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// + +template <class DATA> +typename DataHandle<DATA>::const_pointer_type +DataHandle<DATA>::cptr() const +{ + return dataPointer(); +} + +/////////////////////////////////////////////////////////////////////////////// + +template <class DATA> +typename DataHandle<DATA>::pointer_type +DataHandle<DATA>::ptr() +{ + typename DataHandle<DATA>::pointer p = dataPointer(); + return 0 != p && !isConst() ? p : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +// The const version checks if the pointer is a valid pointer. +// Retrieves the GaudiObject to check validity if not already done + +template <class DATA> +bool +DataHandle<DATA>::isValid() const +{ + // dataPointer() prints a warning if the proxy is null, + // so also test isInitialized(). + return (isInitialized() && 0 != dataPointer()); +} + +////////////////////////////////////////////////////////////////////////////// + +// The non-const version checks if the pointer is a valid pointer and +// if the DataObject is not const. +// Retrieves the GaudiObject to check validity if not already done + +template <class DATA> +bool +DataHandle<DATA>::isValid() +{ + // ptr() prints a warning if the proxy is null, so also test isInitialized(). + return (isInitialized() && 0 != ptr()); +} + +////////////////////////////////////////////////////////////////////////////// +template <class DATA> +typename DataHandle<DATA>::pointer_type +DataHandle<DATA>::dataPointer() const { + if (0 == m_ptr) { + m_ptr = SG::DataProxy_cast<DATA>(m_proxy); + } + return m_ptr; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + +#endif // STOREGATE_DATAHANDLE_ICC diff --git a/EDM/athena/Control/StoreGate/StoreGate/RVar.h b/EDM/athena/Control/StoreGate/StoreGate/RVar.h new file mode 100644 index 00000000..efc5451b --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/RVar.h @@ -0,0 +1,11 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_SG_RVAR_H +#define STOREGATE_SG_RVAR_H 1 + +#warning "RVar is obsolete, please use ReadHandle" + +#include "StoreGate/ReadHandle.h" +#endif //> !STOREGATE_SG_RVAR_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/RWVar.h b/EDM/athena/Control/StoreGate/StoreGate/RWVar.h new file mode 100644 index 00000000..a1def313 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/RWVar.h @@ -0,0 +1,11 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_SG_RWVAR_H +#define STOREGATE_SG_RWVAR_H 1 + +#warning "RWVar is obsolete, please use UpdateHandle" + +#include "StoreGate/UpdateHandle.h" +#endif //> !STOREGATE_SG_RWVAR_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadCondHandle.h b/EDM/athena/Control/StoreGate/StoreGate/ReadCondHandle.h new file mode 100644 index 00000000..551ffefa --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadCondHandle.h @@ -0,0 +1,227 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_READCONDHANDLE_H +#define STOREGATE_READCONDHANDLE_H 1 + +#include "AthenaKernel/getMessageSvc.h" +#include "AthenaKernel/CondCont.h" +#include "AthenaKernel/IOVEntryT.h" + +#include "StoreGate/VarHandleBase.h" +#include "StoreGate/ReadCondHandleKey.h" + +#include "GaudiKernel/DataHandle.h" +#include "GaudiKernel/DataObjID.h" +#include "GaudiKernel/EventIDBase.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/ThreadLocalContext.h" + +#include <string> +#include <stdexcept> + + +namespace SG { + + template <typename T> + class ReadCondHandle : public SG::VarHandleBase { + + public: + typedef T* pointer_type; // FIXME: better handling of + typedef const T* const_pointer_type; // qualified T type ? + typedef T& reference_type; + typedef const T& const_reference_type; + + public: + ReadCondHandle(const SG::ReadCondHandleKey<T>& key); + ReadCondHandle(const SG::ReadCondHandleKey<T>& key, + const EventContext& ctx); + + virtual ~ReadCondHandle() override {}; + + const_pointer_type retrieve(); + const_pointer_type retrieve( const EventIDBase& t); + + const_pointer_type operator->() { return retrieve(); } + const_pointer_type operator*() { return retrieve(); } + + + virtual bool isValid() override; + bool isValid(const EventIDBase& t) const ; + + bool range(EventIDRange& r); + bool range(const EventIDBase& t, EventIDRange& r) const; + + private: + + bool init(); + + const EventIDBase& m_eid; + CondCont<T>* m_cc {nullptr}; + const IOVEntryT<T> * m_ent {nullptr}; + + const SG::ReadCondHandleKey<T>& m_hkey; + + }; + + + //--------------------------------------------------------------------------- + + template <typename T> + ReadCondHandle<T>::ReadCondHandle(const SG::ReadCondHandleKey<T>& key): + ReadCondHandle(key, Gaudi::Hive::currentContext()) + { + } + + //--------------------------------------------------------------------------- + + template <typename T> + ReadCondHandle<T>::ReadCondHandle(const SG::ReadCondHandleKey<T>& key, + const EventContext& ctx): + SG::VarHandleBase( key, ctx ), + m_eid( ctx.eventID() ), + m_cc( key.getCC() ), + m_hkey(key) + { + if (! m_hkey.isInit()) { + MsgStream msg(Athena::getMessageSvc(), "WriteCondHandle"); + msg << MSG::ERROR + << "ReadCondHandleKey " << key.objKey() << " was not initialized" + << endmsg; + throw std::runtime_error("ReadCondHandle: ReadCondHandleKey was not initialized"); + } + + if (m_cc == 0) { + MsgStream msg(Athena::getMessageSvc(), "ReadCondHandle"); + msg << MSG::ERROR + << "ReadCondHandle : ptr to CondCont<T> is zero" + << endmsg; + throw std::runtime_error("ReadCondHandle: ptr to CondCont<T> is zero"); + } + + } + + //--------------------------------------------------------------------------- + + template <typename T> + bool + ReadCondHandle<T>::init() { + + if (m_ent != 0) return true; + + if ( ! m_cc->findEntry(m_eid, m_ent) ) { + std::ostringstream ost; + m_cc->list(ost); + MsgStream msg(Athena::getMessageSvc(), "ReadCondHandle"); + msg << MSG::ERROR + << "ReadCondHandle: could not find current EventTime " + << m_eid << " for key " << objKey() << "\n" + << ost.str() + << endmsg; + m_ent = nullptr; + return false; + } + + return true; + } + + //--------------------------------------------------------------------------- + + template <typename T> + const T* + ReadCondHandle<T>::retrieve() { + + if (m_ent == 0) { + if (!init()) { + // std::ostringstream ost; + // m_cc->list(ost); + // MsgStream msg(Athena::getMessageSvc(), "ReadCondHandle"); + // msg << MSG::ERROR + // << "ReadCondHandle::retrieve() could not find EventTime " + // << m_eid << " for key " << objKey() << "\n" + // << ost.str() + // << endmsg; + return nullptr; + } + } + + const_pointer_type cobj = + const_cast<const_pointer_type>( m_ent->objPtr() ); + return cobj; + } + + //--------------------------------------------------------------------------- + + template <typename T> + const T* + ReadCondHandle<T>::retrieve(const EventIDBase& eid) { + if (eid == m_eid) { + return retrieve(); + } + + pointer_type obj(0); + if (! (m_cc->find(eid, obj) ) ) { + std::ostringstream ost; + m_cc->list(ost); + MsgStream msg(Athena::getMessageSvc(), "ReadCondHandle"); + msg << MSG::ERROR + << "ReadCondHandle::retrieve() could not find EventTime " + << eid << " for key " << objKey() << "\n" + << ost.str() + << endmsg; + return nullptr; + } + + const_pointer_type cobj = const_cast<const_pointer_type>( obj ); + + return cobj; + } + + //--------------------------------------------------------------------------- + + template <typename T> + bool + ReadCondHandle<T>::isValid() { + + return init(); + } + + //--------------------------------------------------------------------------- + + template <typename T> + bool + ReadCondHandle<T>::isValid(const EventIDBase& t) const { + + return (m_cc->valid(t)); + } + + //--------------------------------------------------------------------------- + + template <typename T> + bool + ReadCondHandle<T>::range(EventIDRange& r) { + + if (m_ent == 0) { + if (!init()) { + return false; + } + } + + r = m_ent->range(); + return true; + } + + //--------------------------------------------------------------------------- + + template <typename T> + bool + ReadCondHandle<T>::range(const EventIDBase& eid, EventIDRange& r) const { + + return ( m_cc->range(eid, r) ); + } + +} + +#endif + diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadCondHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/ReadCondHandleKey.h new file mode 100644 index 00000000..f0a74595 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadCondHandleKey.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_READCONDHANDLEKEY_H +#define STOREGATE_READCONDHANDLEKEY_H + +#include "StoreGate/CondHandleKey.h" +#include <string> + + +namespace SG { + + template <class T> + class ReadCondHandle; + + template <class T> + class ReadCondHandleKey + : public CondHandleKey<T> + { + public: + + friend class ReadCondHandle<T>; + + ReadCondHandleKey (const std::string& key, const std::string& dbKey="") : + CondHandleKey<T>(key, dbKey, Gaudi::DataHandle::Reader) + {} + +}; + + +} // namespace SG + +#endif // not STOREGATE_READCONDHANDLEKEY_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadHandle.h b/EDM/athena/Control/StoreGate/StoreGate/ReadHandle.h new file mode 100644 index 00000000..37b6bc09 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadHandle.h @@ -0,0 +1,243 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ReadHandle.h 726621 2016-02-27 20:03:45Z ssnyder $ +/** + * @file StoreGate/ReadHandle.h + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Handle class for reading from StoreGate. + */ + +#ifndef STOREGATE_SG_READHANDLE_H +#define STOREGATE_SG_READHANDLE_H 1 + + +#include "StoreGate/VarHandleBase.h" +#include "StoreGate/ReadHandleKey.h" +#include "SGTools/ClassID_traits.h" +#include "GaudiKernel/EventContext.h" +#include <string> + + + +namespace SG { + + +/** + * @class SG::ReadHandle<T> + * @brief a smart pointer to an object of a given type in an @c IProxyDict (such + * as StoreGateSvc). It d-casts and caches locally the pointed-at object, to + * speed-up subsequent accesses. + * It can be reset by the store for asynchronous updates (IOVSvc) + * + * @c SG::ReadHandle<T> can access const and non-const proxies in StoreGate but + * cannot modify them (ie: it is actually a const T*). + * A valid proxy must already exist in StoreGate. + * + * Usage example: + * @code + * class MyAlg : public AthAlgorithm + * { + * SG::ReadHandle<int> m_int; + * }; + * + * MyAlg::MyAlg(...) : ..., m_int("MyIntSgKey") { + * declareProperty("IntHandle", + * m_int = SG::ReadHandle<int>("MyIntSgKey"), + * "a handle to an int in StoreGate"); + * } + * + * StatusCode MyAlg::execute() + * { + * ATH_MSG_INFO("int value @[" << m_int.name() << "]=" + * << *m_int); + * return StatusCode::SUCCESS; + * } + * @endcode + * + * For more information have a look under the package + * Control/AthenaExamples/AthExHelloWorld + * + */ +template <class T> +class ReadHandle + : public SG::VarHandleBase +{ +public: + typedef T* pointer_type; // FIXME: better handling of + typedef const T* const_pointer_type; // qualified T type ? + typedef T& reference_type; + typedef const T& const_reference_type; + + + //************************************************************************ + // Constructors, etc. + // + + + /** + * @brief Default constructor. + * + * The handle will not be usable until a non-blank key is assigned. + */ + ReadHandle(); + + + /** + * @brief Constructor with full arguments. + * @param sgkey StoreGate key of the referenced object. + * @param storename Name of the referenced event store. + */ + explicit ReadHandle(const std::string& sgkey, + const std::string& storename = "StoreGateSvc"); + + + /** + * @brief Constructor from a ReadHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ + explicit ReadHandle (const ReadHandleKey<T>& key); + + + /** + * @brief Constructor from a ReadHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ + explicit ReadHandle (const ReadHandleKey<T>& key, const EventContext& ctx); + + + /** + * @brief Copy constructor. + */ + ReadHandle( const ReadHandle& rhs ); + + + /** + * @brief Move constructor. + */ + ReadHandle( ReadHandle&& rhs ); + + + /** + * @brief Assignment operator. + */ + ReadHandle& operator=( const ReadHandle& rhs ); + + + /** + * @brief Move operator. + */ + ReadHandle& operator=( ReadHandle&& rhs ); + + + //************************************************************************ + // Dereference. + // + + + /** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + */ + const_pointer_type operator->(); + + + /** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + */ + const_reference_type operator*(); + + + /** + * @brief Dereference the pointer. + * Returns nullptr on failure. + */ + const_pointer_type cptr(); + + + /** + * @brief Dereference the pointer. + * Returns nullptr on failure. + */ + const_pointer_type ptr(); + + + /** + * @brief Return the cached pointer directly; no lookup. + */ + const_pointer_type cachedPtr() const; + + + /** + * @brief Can the handle be successfully dereferenced? + */ + virtual bool isValid() override final; + + +private: + /** + * @brief Helper: dereference the pointer. + * Throws ExcNullReadHandle on failure. + */ + const_pointer_type checkedCPtr(); +}; + + +/** + * @brief Return a @c ReadHandle referencing @c key. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +ReadHandle<T> makeHandle (const ReadHandleKey<T>& key); + + +/** + * @brief Return a @c ReadHandle referencing @c key for an explicit context. + * @param key The key object holding the clid/key/store. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +ReadHandle<T> makeHandle (const ReadHandleKey<T>& key, + const EventContext& ctx); + + +} /* namespace SG */ + + + +#include "StoreGate/ReadHandle.icc" + + +#ifndef NO_LEGACY_HANDLES +namespace SG { + template <class T> + using RVar = ReadHandle<T>; +} +#endif + + +#endif //> !STOREGATE_SG_READHANDLE_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadHandle.icc b/EDM/athena/Control/StoreGate/StoreGate/ReadHandle.icc new file mode 100644 index 00000000..78611f48 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadHandle.icc @@ -0,0 +1,268 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ReadHandle.icc 726621 2016-02-27 20:03:45Z ssnyder $ +/** + * @file StoreGate/ReadHandle.icc + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Handle class for reading from StoreGate. + */ + +#ifndef STOREGATE_SG_READHANDLE_ICC +#define STOREGATE_SG_READHANDLE_ICC 1 + + +#include "StoreGate/exceptions.h" +#include "SGTools/ClassID_traits.h" +#include <stdexcept> + + +namespace SG { + + +//************************************************************************ +// Constructors, etc. +// + + +/** + * @brief Default constructor. + * + * The handle will not be usable until a non-blank key is assigned. + */ +template <class T> +inline +ReadHandle<T>::ReadHandle() + : VarHandleBase(ClassID_traits<T>::ID(), Gaudi::DataHandle::Reader) +{ +} + + +/** + * @brief Constructor with full arguments. + * @param sgkey StoreGate key of the referenced object. + * @param storename Name of the referenced event store. + */ +template <class T> +inline +ReadHandle<T>::ReadHandle(const std::string& sgkey, + const std::string& storename /*= "StoreGateSvc"*/) + : VarHandleBase( ClassID_traits<T>::ID(), + sgkey, Gaudi::DataHandle::Reader, storename ) +{ +} + + +/** + * @brief Constructor from a ReadHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +inline +ReadHandle<T>::ReadHandle (const ReadHandleKey<T>& key) + : VarHandleBase (key) +{ +} + + +/** + * @brief Constructor from a ReadHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +inline +ReadHandle<T>::ReadHandle (const ReadHandleKey<T>& key, + const EventContext& ctx) + : VarHandleBase (key, ctx) +{ +} + + +/** + * @brief Copy constructor. + */ +template <class T> +inline +ReadHandle<T>::ReadHandle(const ReadHandle& h) + : VarHandleBase(h) +{ +} + + +/** + * @brief Move constructor. + */ +template <class T> +inline +ReadHandle<T>::ReadHandle(ReadHandle&& h) + : VarHandleBase(std::move(h)) +{ +} + + +/** + * @brief Assignment operator. + */ +template <class T> +ReadHandle<T>& +ReadHandle<T>::ReadHandle::operator= (const ReadHandle& h) +{ + if (this != &h) + this->VarHandleBase::operator=(h); + return *this; +} + +/** + * @brief Move operator. + */ +template <class T> +inline +ReadHandle<T>& +ReadHandle<T>::ReadHandle::operator= (ReadHandle&& h) +{ + if (this != &h) + this->VarHandleBase::operator=(std::move(h)); + return *this; +} + + +/** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + */ +template <class T> +inline +typename ReadHandle<T>::const_pointer_type +ReadHandle<T>::operator->() +{ + return checkedCPtr(); +} + + +/** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + */ +template <class T> +inline +typename ReadHandle<T>::const_reference_type +ReadHandle<T>::operator*() +{ + return *checkedCPtr(); +} + + +/** + * @brief Dereference the pointer. + * Returns nullptr on failure. + */ +template <class T> +inline +typename ReadHandle<T>::const_pointer_type +ReadHandle<T>::cptr() +{ + return reinterpret_cast<const_pointer_type>(this->typeless_cptr()); +} + + +/** + * @brief Dereference the pointer. + * Returns nullptr on failure. + */ +template <class T> +inline +typename ReadHandle<T>::const_pointer_type +ReadHandle<T>::ptr() +{ + return cptr(); +} + + +/** + * @brief Return the cached pointer directly; no lookup. + */ +template <class T> +inline +typename ReadHandle<T>::const_pointer_type +ReadHandle<T>::cachedPtr() const +{ + return reinterpret_cast<const_pointer_type>(this->m_ptr); +} + + +/** + * @brief Can the handle be successfully dereferenced? + */ +template <class T> +inline +bool ReadHandle<T>::isValid() +{ + return 0 != this->typeless_cptr(true); +} + + +/** + * @brief Helper: dereference the pointer. + * Throws ExcNullReadHandle on failure. + */ +template <class T> +inline +typename ReadHandle<T>::const_pointer_type +ReadHandle<T>::checkedCPtr() +{ + const_pointer_type p = this->cptr(); + if (!p) + throwExcNullReadHandle (clid(), key(), store()); + return p; +} + + +/** + * @brief Return a @c ReadHandle referencing @c key. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +ReadHandle<T> makeHandle (const ReadHandleKey<T>& key) +{ + return ReadHandle<T> (key); +} + + +/** + * @brief Return a @c ReadHandle referencing @c key for an explicit context. + * @param key The key object holding the clid/key/store. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +ReadHandle<T> makeHandle (const ReadHandleKey<T>& key, + const EventContext& ctx) +{ + return ReadHandle<T> (key, ctx); +} + + +} /* namespace SG */ + + +#endif //> !STOREGATE_SG_READHANDLE_ICC diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.h new file mode 100644 index 00000000..cc8c2c90 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.h @@ -0,0 +1,73 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/ReadHandleKey.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Property holding a SG store/key/clid from which a ReadHandle is made. + */ + + +#ifndef STOREGATE_READHANDLEKEY_H +#define STOREGATE_READHANDLEKEY_H + + +#include "StoreGate/VarHandleKey.h" +#include "SGTools/CLASS_DEF.h" + + +namespace SG { + + +/** + * @brief Property holding a SG store/key/clid from which a ReadHandle is made. + * + * This class holds the key part of a ReadHandle. For a reentrant algorithm, + * you would use this as the algorithm property and construct the actual + * ReadHandle on the stack from this key object (and optionally the event + * context). + * + * See VarHandleKey for more details. + */ +template <class T> +class ReadHandleKey + : public VarHandleKey +{ +public: + /** + * @brief Constructor. + * @param key The StoreGate key for the object. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. + */ + ReadHandleKey (const std::string& key = "", + const std::string& storeName = "StoreGateSvc"); + + + /** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. + */ + ReadHandleKey& operator= (const std::string& sgkey); +}; + + +} // namespace SG + + +#include "StoreGate/ReadHandleKey.icc" + + +#endif // not STOREGATE_READHANDLEKEY_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.icc b/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.icc new file mode 100644 index 00000000..fa98b4f6 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKey.icc @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/ReadHandleKey.icc + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Property holding a SG store/key/clid from which a ReadHandle is made. + */ + + +namespace SG { + + +/** + * @brief Constructor. + * @param key The StoreGate key for the object. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. + */ +template <class T> +ReadHandleKey<T>::ReadHandleKey (const std::string& key /*= ""*/, + const std::string& storeName /*= "StoreGateSvc"*/) + : VarHandleKey (ClassID_traits<T>::ID(), key, + Gaudi::DataHandle::Reader, + storeName) +{ +} + + +/** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. + */ +template <class T> +ReadHandleKey<T>& ReadHandleKey<T>::operator= (const std::string& sgkey) +{ + VarHandleKey::operator= (sgkey); + return *this; +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKeyArray.h b/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKeyArray.h new file mode 100644 index 00000000..d9464c50 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/ReadHandleKeyArray.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_READHANDLEKEYARRAY_H +#define STOREGATE_READHANDLEKEYARRAY_H 1 + +#include "StoreGate/VarHandleKeyArray.h" + +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/ReadHandle.h" + +#include <vector> +#include <string> + +namespace SG { + + /** + * @class SG::ReadHandleKeyArray<T> + * @brief class to hold an array of ReadHandleKeys + * + * since it inherits from std::vector, all vector operations are + * permitted. + * + * initialization can be done in three ways. + * 1: with an std::vector<ReadHandleKey> as a parameter + * SG::ReadHandleKeyArray<foo> m_foo ( std::vector<ReadHandleKey> ); + * 2: with an initializer list of ReadHandleKeys + * SG::ReadHandleKeyArray<foo> m_foo { ReadHandleKey<foo> k1, ReadHandleKey<foo> k2 }; + * 3: with an initializer list of std::strings, that will be used to + * internally create ReadHandleKeys with those initializers + * SG::ReadHandleKeyArray<foo> m_foo { "key1", "key2", "key3" }; + */ + + template <class T> + class ReadHandleKeyArray : public VarHandleKeyArrayCommon< ReadHandleKey<T> > { + public: + /** + * @brief default Constructor from a ReadHandleKeyArray + */ + ReadHandleKeyArray(){}; + + /** + * @brief Constructor from a ReadHandleKeyArray that takes a vector + * of ReaDHandleKeys + * @param v vector of ReadHandleKey + */ + ReadHandleKeyArray( const std::vector<ReadHandleKey<T>>& v ): + VarHandleKeyArrayCommon<ReadHandleKey<T>> ( v ) {}; + + /** + * @brief Constructor from a ReadHandleKeyArray that takes an + * initializer list of ReadHandleKeys + * @param l initializer list of ReadHandleKey + */ + ReadHandleKeyArray( std::initializer_list<ReadHandleKey<T>> l ): + VarHandleKeyArrayCommon<ReadHandleKey<T>> {l} {}; + + /** + * @brief Constructor from a ReadHandleKeyArray that takes an + * initializer list of std::strings. + * @param l initializer list of std::strings used to create the + * ReadHandleKeys + */ + ReadHandleKeyArray( std::initializer_list<std::string> l ): + VarHandleKeyArrayCommon<ReadHandleKey<T>> {l} {}; + + /** + * @brief return the type (Read/Write/Update) of handle + */ + Gaudi::DataHandle::Mode mode() const { return Gaudi::DataHandle::Reader; } + + /** + * @brief create a vector of ReadHandles from the ReadHandleKeys + * in the array + */ + std::vector< ReadHandle<T> > makeHandles() const { + std::vector< ReadHandle<T> > hndl; + typename std::vector<ReadHandleKey<T>>::const_iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + hndl.push_back ( ReadHandle<T>( *itr) ); + } + return ( std::move( hndl ) ); + } + + }; + + +} // namespace SG + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/SGHiveEventSlot.h b/EDM/athena/Control/StoreGate/StoreGate/SGHiveEventSlot.h new file mode 100644 index 00000000..267ad41b --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SGHiveEventSlot.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_SGHIVEEVENTSLOT +#define STOREGATE_SGHIVEEVENTSLOT 1 +/** @class HiveEventSlot + * @brief A structure created by HiveMgrSvc and used by SGHiveStoreSvc + * to forward the StoreGateSvc method to a thread-specific SGImplSvc + * + * $Id: SGHiveEventSlot.h 637398 2014-12-23 20:45:22Z calaf $ + **/ +#include "tbb/recursive_mutex.h" + +class SGImplSvc; + +namespace SG { + struct HiveEventSlot { + typedef tbb::recursive_mutex mutex_t; + friend class TestSGHiveMgrSvc; + HiveEventSlot(SGImplSvc* pSG=0, int evt=-1) : + pEvtStore(pSG), eventNumber(evt) {} + HiveEventSlot(const HiveEventSlot& parent) : + pEvtStore(parent.pEvtStore), eventNumber(parent.eventNumber) {} + SGImplSvc* pEvtStore; + int eventNumber; + mutex_t storeMutex; + }; +} +#endif // STOREGATE_SGHIVEEVENTSLOT + + + + + diff --git a/EDM/athena/Control/StoreGate/StoreGate/SGIterator.h b/EDM/athena/Control/StoreGate/StoreGate/SGIterator.h new file mode 100644 index 00000000..c6ed8e60 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SGIterator.h @@ -0,0 +1,129 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file SG_iterator.h + * defines a standard conforming forward iterator based on DataHandle + */ +#ifndef STOREGATE_SG_ITERATOR_H +#define STOREGATE_SG_ITERATOR_H 1 + +#include "StoreGate/DataHandle.h" +#include <boost/iterator/iterator_facade.hpp> + +namespace SG { + +namespace detail { +/** @class DHIteratorBase + * Implementation class, not to be used directly + */ + template <class DATA> + class DHIteratorBase { + protected: + /// @name boost iterator implementation + //@{ + DHIteratorBase() : m_dh() {} + explicit DHIteratorBase(const DataHandle<DATA>& dh) : m_dh(dh) {} + + friend class boost::iterator_core_access; + void increment() { ++m_dh; } + //@} + + bool eql(const DHIteratorBase<DATA>& rhs) const { + return m_dh == rhs.m_dh; + } + DATA& deref() const { return *m_dh; } + const DATA& const_deref() const + { + const DataHandle<DATA>& dh = m_dh; + return *dh; + } + + public: + /// @name SG-specific accessors + //@{ + /// Get the key string with which the current object was stored. + const std::string& key() const + { return m_dh.key(); } + /// RETRIEVES the data object to check it is valid and unlocked + bool isValid() const + { + const DataHandle<DATA>& dh = m_dh; + return dh.isValid(); + } + /// RETRIEVES the data object to check it is valid + //bool isValid() + //{ return m_dh.isValid(); } + /// weaker test but it does not touch the disk! + bool isInitialized() const + { return m_dh.isInitialized(); } + //@} + private: + mutable DataHandle<DATA> m_dh; + }; + +} //end ns detail + +/** @class ConstIterator + * a const_iterator facade to DataHandle. Behaves like a forward iterator + */ + template <class DATA> + class ConstIterator : + public detail::DHIteratorBase<DATA>, + public boost::iterator_facade< + ConstIterator<DATA>, + const DATA, + boost::forward_traversal_tag > + { + public: + ConstIterator() : detail::DHIteratorBase<DATA>() {} + explicit ConstIterator(const DataHandle<DATA>& dh) : + detail::DHIteratorBase<DATA>(dh) {} + private: + /// @name boost iterator implementation + //@{ + friend class boost::iterator_core_access; + //INHERITED void increment(); + bool equal(const ConstIterator<DATA>& rhs) const { + return detail::DHIteratorBase<DATA>::eql(rhs); + } + const DATA& dereference() const { + return detail::DHIteratorBase<DATA>::const_deref(); + } + //@} + }; + + + /** @class Iterator + * an iterator facade to DataHandle. Behaves like a forward iterator + */ + template <class DATA> + class Iterator : + public detail::DHIteratorBase<DATA>, + public boost::iterator_facade< + Iterator<DATA>, + DATA, + boost::forward_traversal_tag > + { + public: + Iterator() : detail::DHIteratorBase<DATA>() {} + explicit Iterator(const DataHandle<DATA>& dh) : + detail::DHIteratorBase<DATA>(dh) {} + private: + /// @name boost iterator implementation + //@{ + friend class boost::iterator_core_access; + //INHERITED void increment(); + bool equal(const Iterator<DATA>& rhs) const { + return detail::DHIteratorBase<DATA>::eql(rhs); + } + DATA& dereference() const { + return detail::DHIteratorBase<DATA>::deref(); + } + //@} + }; +} //ns SG +#endif + diff --git a/EDM/athena/Control/StoreGate/StoreGate/SGObjectWithVersion.h b/EDM/athena/Control/StoreGate/StoreGate/SGObjectWithVersion.h new file mode 100644 index 00000000..2cad148a --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SGObjectWithVersion.h @@ -0,0 +1,46 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// @file SGObjectWithVersion.h +/// @brief associate a data object with its VersionedKey +#ifndef STOREGATE_SGOBJECTWITHVERSION_H +#define STOREGATE_SGOBJECTWITHVERSION_H 1 + +#include "SGTools/SGVersionedKey.h" +#include "StoreGate/DataHandle.h" +namespace SG { + /// @class ObjectWithVersion + /// @brief associate a data object with its VersionedKey + /// The object is held by a DataHandle to delay its retrieval + /// in case the user is interested only in the versionedKey + template <typename T> + class ObjectWithVersion { + public: + ObjectWithVersion(): versionedKey(), dataObject() {} + ObjectWithVersion(const ObjectWithVersion& rhs): + versionedKey(rhs.versionedKey), dataObject(rhs.dataObject) {} + ObjectWithVersion(const VersionedKey& vk, const DataHandle<T>& dh): + versionedKey(vk), dataObject(dh) {} + ObjectWithVersion& operator= (const ObjectWithVersion& rhs) + { + if (this != &rhs) { + versionedKey = rhs.versionedKey; + dataObject = rhs.dataObject; + } + return *this; + } + SG::VersionedKey versionedKey; + DataHandle<T> dataObject; + }; +} +/// sort according to highest key version +template <typename T> +bool operator < (const SG::ObjectWithVersion<T>& lhs, + const SG::ObjectWithVersion<T>& rhs) { + return (lhs.versionedKey < rhs.versionedKey); +} + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/SGWPtr.h b/EDM/athena/Control/StoreGate/StoreGate/SGWPtr.h new file mode 100644 index 00000000..4842a273 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SGWPtr.h @@ -0,0 +1,20 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file SGWPtr.h + * return type of StoreGateSvc::create. + * Currently a plain pointer, may become a handle informing the scheduler + * when we are done "writing" + */ +#ifndef STOREGATE_SGWPTR_H +#define STOREGATE_SGWPTR_H +#include <boost/config.hpp> +namespace SG { +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + template<class T> using WPtr = T*; +#endif +} +#endif // STOREGATE_SGWPTR_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/SGtests.h b/EDM/athena/Control/StoreGate/StoreGate/SGtests.h new file mode 100644 index 00000000..d2098117 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SGtests.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_SGTESTS_H +# define STOREGATE_SGTESTS_H 1 +/** + @brief "library" of SG test functions. + Useful to exercise StoreGateSvc templates compilation + + @author ATLAS Collaboration + $Id: SGtests.h,v 1.7 2008-07-10 00:33:50 calaf Exp $ + ***************************************************************************/ +class StoreGateSvc; + +namespace Athena_test +{ + void testCreate(StoreGateSvc& rSG); + + void testRecord(StoreGateSvc& rSG); + + void testSymLink(StoreGateSvc& rSG); + + void test_symlink2(StoreGateSvc& rSG); + + void test_symlink3(StoreGateSvc& rSG); + + void testContains(StoreGateSvc& rSG); + + void testFolders(StoreGateSvc& rSG); + + void testRetrieve(StoreGateSvc& rSG); + + void testTryRetrieve(StoreGateSvc& rSG); + + void testReadPrivateCopy(StoreGateSvc& rSG); + + void testRetrievePrivateCopy(StoreGateSvc& rSG); + + void testRemove(StoreGateSvc& rSG); + + void testBind(StoreGateSvc& rSG); + + void testClear(StoreGateSvc& rSG); + + void testTransientSwap(StoreGateSvc& rSG); + + void testVersionedKey(StoreGateSvc& rSG); + + void testKeys(StoreGateSvc& rSG); + + void testRetrieveAux(StoreGateSvc& rSG); + + void testBoundReset(StoreGateSvc& rSG); + + void testRecordObject(StoreGateSvc& rSG); + + void testWriteAux(StoreGateSvc& rSG); + +} //end namespace +#endif // TEST_SGTESTS_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.h b/EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.h new file mode 100644 index 00000000..3ef9c827 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.h @@ -0,0 +1,115 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CONTROL_STOREGATE_SEGMEMSVC_H +#define CONTROL_STOREGATE_SEGMEMSVC_H 1 + +#include "GaudiKernel/Service.h" +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthAllocators/Arena.h" + +#include <string> + +// Forward declarations +template <class TYPE> class SvcFactory; + +/** @class SegMemSvc + * @brief Service to access an arena caching allocator + * + * @param No user settable jobOptions + * + * @author Charles Leggett + * $Id: $ + **/ + +class SegMemSvc: public Service, + public IIncidentListener { + +public: + + + enum LIFETIME { + EVENT = 0, + JOB = 1, + INCIDENT = 2 + }; + + //////////////////////////////////////////////////////////////////////// + /// \name Internals: Gaudi boilerplate + //@{ + + virtual StatusCode initialize(); + virtual StatusCode reinitialize(); + virtual StatusCode finalize(); + + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + static const InterfaceID& interfaceID() { + static const InterfaceID IID("SegMemSvc", 1, 0); + return IID; + } + + virtual void handle(const Incident&); + + //@} + + + //////////////////////////////////////////////////////////////////////// + /// \name Client Interface: allocate and free memory + //@{ + + + /// @brief Get pointer to an area in the arena, used for new with placement + /// @param LIFETIME object lifetime in the arena: EVENT, JOB or INCIDENT + /// @return T* to be used with new with placement + template <typename T> + T* allocate(SegMemSvc::LIFETIME, bool cache=true); + + /// free memory managed by arena + template <typename T> + bool del(T*); + + //@} + + +protected: + + SegMemSvc( const std::string& name, ISvcLocator* svc ); + + // Destructor. + virtual ~SegMemSvc(); + + +private: + friend class SvcFactory<SegMemSvc>; + + ServiceHandle<IIncidentSvc> p_incSvc; + + mutable MsgStream m_log; + + /// helper to for printout + inline std::string cvt(SegMemSvc::LIFETIME life) { + switch (life) { + case SegMemSvc::EVENT : return "EVENT"; + case SegMemSvc::JOB : return "JOB"; + case SegMemSvc::INCIDENT: return "INCIDENT"; + } + return "UNKNOWN"; + } + + /// three arenas for different lifetimes + SG::ArenaHeader m_ahead_job, m_ahead_evt, m_ahead_inc; + SG::Arena m_arena_job, m_arena_evt, m_arena_inc; + + +}; + + +#include "StoreGate/SegMemSvc.icc" + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.icc b/EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.icc new file mode 100644 index 00000000..ce3e6cca --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/SegMemSvc.icc @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthAllocators/ArenaCachingHandle.h" +#include "AthAllocators/ArenaHandle.h" +#include "AthAllocators/ArenaPoolAllocator.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +T* +SegMemSvc::allocate(SegMemSvc::LIFETIME life, bool cache) { + + T* ptr = 0; + + if (cache) { + typedef SG::ArenaCachingHandle<T, SG::ArenaPoolAllocator> Handle_t; + if (life == SegMemSvc::EVENT) { + ptr = (T*)Handle_t(&m_ahead_evt).allocate(); + } else if (life == SegMemSvc::JOB) { + ptr = (T*)Handle_t(&m_ahead_job).allocate(); + } else if (life == SegMemSvc::INCIDENT) { + ptr = (T*)Handle_t(&m_ahead_inc).allocate(); + } + } else { + typedef SG::ArenaHandle<T, SG::ArenaPoolAllocator> Handle_t; + if (life == SegMemSvc::EVENT) { + ptr = (T*)Handle_t(&m_ahead_evt).allocate(); + } else if (life == SegMemSvc::JOB) { + ptr = (T*)Handle_t(&m_ahead_job).allocate(); + } else if (life == SegMemSvc::INCIDENT) { + ptr = (T*)Handle_t(&m_ahead_inc).allocate(); + } + } + + if (m_log.level() <= MSG::DEBUG) { + m_log << MSG::DEBUG << "allocating object size " << sizeof(T) + << " with lifetime/cache " << cvt(life) << "/" << cache << " at " + << ptr << endmsg; + } + + + return ptr; + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T> +bool +SegMemSvc::del(T* ptr) { + + if (m_log.level() <= MSG::DEBUG) { + m_log << MSG::DEBUG << "deleting object at " << ptr << endmsg; + } + + + return true; + +} diff --git a/EDM/athena/Control/StoreGate/StoreGate/StoreClearedIncident.h b/EDM/athena/Control/StoreGate/StoreGate/StoreClearedIncident.h new file mode 100644 index 00000000..d3e1d67c --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/StoreClearedIncident.h @@ -0,0 +1,52 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StoreClearedIncident.h,v 1.2 2008-09-10 04:07:14 ssnyder Exp $ + +/** + * @file StoreGate/StoreClearedIncident.h + * @author scott snyder + * @date Sep 2008 + * @brief Incident sent after a store is cleared. + */ + + +#ifndef STOREGATE_STORECLEAREDINCIDENT_H +#define STOREGATE_STORECLEAREDINCIDENT_H + + +#include "GaudiKernel/Incident.h" +class StoreGateSvc; + + +/** + * @brief Incident sent after a store is cleared. + */ +class StoreClearedIncident + : public Incident +{ +public: + /** + * @brief Constructor. + * @param sg The store that was cleared. + * @param source the name of the service/algorithm firing + * @param type e.g. "StoreCleared" + */ + StoreClearedIncident (StoreGateSvc* sg, + const std::string& source, + const std::string& type = "StoreCleared"); + + /// Return the store that was cleared. + StoreGateSvc* store() const; + + +private: + /// The store that was cleared. + StoreGateSvc* m_sg; +}; + + +#endif // not STOREGATE_STORECLEAREDINCIDENT_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/StoreGate.h b/EDM/athena/Control/StoreGate/StoreGate/StoreGate.h new file mode 100644 index 00000000..52e83e85 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/StoreGate.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_STOREGATE_H +#define STOREGATE_STOREGATE_H + +/** @class StoreGate + * @brief a multipleton that provides access to StoreGateSvc instances + * @author ATLAS Collaboration + * $Id: StoreGate.h,v 1.10 2003-04-16 01:58:11 calaf Exp $ + **/ + +#include "StoreGate/StoreGateSvc.h" +#include <string> + +class NullType; +class ActiveStoreSvc; + +class StoreGate { +public: + /// returns active store ptr (see ActiveStoreSvc). Can be slow: use sparingly + static StoreGateSvc* pointer(); + /// returns active store ref (see ActiveStoreSvc). Can be slow: use sparingly + static StoreGateSvc& instance(); + /// returns ptr to ActiveStoreSvc. Cache it and use it to access active store + /// multiple times + static ActiveStoreSvc* activeStoreSvc(); + /** multipleton: get a store by name + * @param sgID name of the StoreGateSvc ptr to be returned */ + static StoreGateSvc* pointer(std::string sgID); + /** multipleton: get a store by name + * @param sgID name of the StoreGateSvc ptr to be returned + * @throws std::runtime_error if not found*/ + static StoreGateSvc& instance(std::string sgID); + + friend class NullType; //remove compiler warning + +protected: + ~StoreGate(); //FIXME avoid compiler warning for private +private: + //standard singleton stuff + StoreGate(); + StoreGate(StoreGate&); + StoreGate& operator=(const StoreGate&); +}; +#endif // STOREGATE_STOREGATE_H + + + + + diff --git a/EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.h b/EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.h new file mode 100644 index 00000000..46d90c6f --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.h @@ -0,0 +1,1087 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_STOREGATESVC_H +#define STOREGATE_STOREGATESVC_H + +//FIXME the CLASS_DEF header is not needed here but was added to work around +//bad include statements in client code: when using CLASS_DEF put the +//include below in your header file! +#include "SGTools/CLASS_DEF.h" + +#ifndef ATHENAHIVE +#define SGImplSvc StoreGateSvc +#include "StoreGate/tools/SGImplSvc.h" +#else +//HIVE wrapper implementation +//base classes +#include "GaudiKernel/Service.h" +#include "AthenaKernel/IProxyDict.h" + +#include "AthenaKernel/IHiveStore.h" +#include "AthenaKernel/IHiveStoreMgr.h" +#include "StoreGate/tools/SGImplSvc.h" +#include "StoreGate/SGHiveEventSlot.h" + +#include <GaudiKernel/ClassID.h> // for CLID +#include <GaudiKernel/IInterface.h> // for InterfaceID +#include <GaudiKernel/IMessageSvc.h> // for Level +#include "GaudiKernel/Property.h" /*StringArrayProperty*/ +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/StatusCode.h" + +#include <cstddef> // for size_t +#include <list> +#include <memory> /* auto_ptr */ +#include <mutex> +#include <string> +#include <sys/types.h> // for off_t +#include <vector> + +#include "AthenaKernel/StoreID.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IOVSvcDefs.h" +#include "AthenaKernel/DefaultKey.h" +#include "AthAllocators/Arena.h" + +#include <SGTools/StringPool.h> +#include "SGTools/ProxyMap.h" /* for SG::ConstProxyIterator */ + +// includes used in StoreGateSvc.icc +#include "AthenaKernel/IResetable.h" +#include "AthenaKernel/IClassIDSvc.h" +#include "AthenaKernel/IIOVSvc.h" +#include "StoreGate/SGHiveEventSlot.h" +#include "StoreGate/SGIterator.h" +#include "StoreGate/DataHandle.h" +#include "StoreGate/SGWPtr.h" +#include "SGTools/DataStore.h" +#include "StoreGate/SGObjectWithVersion.h" + +#include "GaudiKernel/ServiceHandle.h" + +//forward declarations +namespace SG { + class DataProxy; + class TransientAddress; + struct RemapImpl; + class TestHiveStoreSvc; + class HiveMgrSvc; +} + +class DataObject; +class IConversionSvc; +class IIncidentSvc; +class IProxyProviderSvc; +class IHistorySvc; + +// python forward +struct _object; typedef _object PyObject; +class StoreGateSvc; +namespace AthenaInternal { + PyObject* recordObjectToStore(StoreGateSvc*,PyObject*,PyObject*,bool,bool,bool); + void py_sg_clearProxyPayload(StoreGateSvc* self, SG::DataProxy*); +} +namespace SG { + class NoAuxStore; +} + +//friends... +class AthenaOutputStream; +class IOVDbSvc; +class IOVSvc; +class IOVSvcTool; +class PileUpMergeSvc; +class EventDumperSvc; +class MemoryMonitorSvc; +class SGDeleteAlg; +class ThinningSvc; +class ActiveStoreSvc; +class CondSvc; +namespace SG { + class VarHandleBase; +} +namespace PerfMon { class StorePayloadMon; } + +/** @class StoreGateSvc + * @brief The Athena Transient Store API. + * + * @param "Dump" property (default false): set to call dump() at EndEvent + * @param "FolderNameList" property (default ""): data folders to be created + * in this store + * Caches a pointer to the currently hive store. + * In most jobs the hive store is simply the default event store + * (named "StoreGateSvc"). When doing pile-up (and perhaps later on in + * multi-threaded jobs, the hive store changes during the event loop + * execution. It is important, for example, that converters always refer + * to the hive store rather than to the default one. + * + * @author ATLAS Collaboration + * $Id: SGStoreGateSvc.h 549999 2013-06-06 00:26:39Z calaf $ + **/ +class StoreGateSvc : + public Service, + public IProxyDict, + public IHiveStore, + public IHiveStoreMgr +{ + +public: +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + ///////////////////////////////////////////////////////////////////////// + /// \name Basic Client Interface: data object creation + //@{ + + /** Create an object with one of its constructors and record it with a key. + * @param key a string (or an object convertible to a string) + * identifying the object within the event + * @param constructorArgs a variable list of args passed to the constructor + * @returns a "pointer" to the created object (set to 0 if creation failed) + * Example: + * struct Foo { + * int m_i; + * int i() const { return m_i; } + * Foo(int i) : m_i(i) {} + * }; + * CLASS_DEF(Foo, 123456, 1); + * .... + * auto pFoo = pSG.create<Foo>("aFoo", 23); + * assert(pFoo->i()==23); + * assert(pSG.transientContains<Foo>("aFoo")); + */ + + template <typename T, typename TKEY, typename... ARGS> + SG::WPtr<T> create(const TKEY& key, ARGS... constructorArgs); + //@} +#endif /* needs C++11 variadic templates to call arbitrary constructors */ +#endif /* needs "templated typedef" to define SG::WPtr (for now) */ + + ///////////////////////////////////////////////////////////////////////// + /// \name Basic Client Interface: data object registration + //@{ + + /// Record an object with a key. + template <typename T, typename TKEY> + StatusCode record(T* p2BRegistered, const TKEY& key); + + /// Record a const object with a key + template <typename T, typename TKEY> + StatusCode record(const T* p2BRegistered, const TKEY& key); + + /// Record an object with a key, take ownership of the auto_pointed obj + template <typename T, typename TKEY> + StatusCode record(std::auto_ptr<T> p2BRegistered, const TKEY& key); + + /// Record an object with a key, allow possibility of specifying + /// const-access. + template <typename T, typename TKEY> + StatusCode record(T* p2BRegistered, const TKEY& key, + bool allowMods, bool resetOnly=true, bool noHist=false); + +#if __cplusplus > 201100 + /// Record an object with a key, take ownership of the unique_ptr obj + template <typename T, typename TKEY> + StatusCode record(std::unique_ptr<T> pUnique, const TKEY& key); + + /// Record a const object with a key + template <typename T, typename TKEY> + StatusCode record(std::unique_ptr<const T> pUnique, const TKEY& key); + + /// Record an object with a key, allow possibility of specifying + /// const-access. + template <typename T, typename TKEY> + StatusCode record(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool resetOnly=true, bool noHist=false); +#endif + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name Basic Client Interface: data object access + //@{ + + /// Retrieve the default object into a const T* + template <typename T> + StatusCode retrieve(const T*& ptr); + + /// Retrieve the default object into a T* + template <typename T> + StatusCode retrieve(T*& ptr); + + /// Variant of the above which does't return a status code. + /// Just returns null if the object isn't found. + template <typename T> + T* retrieve (); + + /// Variant of the above which does't print a warning message. + /// Just returns null if the object isn't found. Compare to contains + template <typename T> + T* tryRetrieve (); + template <typename T> + const T* tryConstRetrieve(); + + /// Retrieve an object with "key", into a const T* + template <typename T, typename TKEY> + StatusCode retrieve(const T*& ptr, const TKEY& key); + + /// Retrieve an object with "key", into a T* + template <typename T, typename TKEY> + StatusCode retrieve(T*& ptr, const TKEY& key); + + /// Variant of the above which does't return a status code. + /// Just returns null if the object isn't found. + template <typename T, class TKEY> + T* retrieve (const TKEY& key); + + /// Variant of the above which does't print a warning message. + /// Just returns null if the object isn't found. Compare to contains + template <typename T, class TKEY> + T* tryRetrieve (const TKEY& key); + template <typename T, class TKEY> + const T* tryConstRetrieve(const TKEY& key); + + /** + * @brief try to associate a data object to its auxiliary store + * if ignoreMissing=false @returns false if the aux store is not found. + * @param key The key to use for the lookup. + **/ + template <class DOBJ> + bool associateAux (DataHandle<DOBJ>&, bool ignoreMissing=true); + template <class DOBJ> + bool associateAux (const DataHandle<DOBJ>&, bool ignoreMissing=true); + + /// retrieve a data object deriving from DataVectorAuxBase, + /// associate the data object to its matching IAuxStore. + /// The matching is done by name, with the IAuxStore assumed to have key + /// key + "Aux" + /// returns null if the object or its IAuxStore isn't found. + template <typename T, class TKEY> + T* retrieveAux (const TKEY& key); + template <typename T, class TKEY> + const T* constRetrieveAux (const TKEY& key); + + + + + + /// Retrieve all objects of type T: returns an SG::ConstIterator range + template <typename T> + StatusCode retrieve(SG::ConstIterator<T>& begin, + SG::ConstIterator<T>& end); + + /** Look up a keyed object in TDS (compare also tryRetrieve) + * returns false if object not available in TDS or persistent stores + * Usage: if (!p_store->contains<Foo>("fooKey")) { ... } */ + /// + template <typename T, typename TKEY> + bool contains(const TKEY& key) const; + + /** A "once-per-job" retrieve that binds a data object to a DataHandle, + * typically a data member of an Algorithm/AlgTool. + * At the end of every event, or more in general + * when the data object is not valid anymore, the DataHandle is reset, + * so that the next time the handle is accessed it will point to the + * current version of that data object. + * For example if MyAlg.h has a data member + * DataHandle<Foo> m_myFoo; + * after bind is called once per job, usually in MyAlg::initialize: + * sc = p_store->bind(m_myFoo, "MyFoo"); + * m_myFoo will provide to access the current MyFoo e.g. in MyAlg::execute(): + * m_myFoo->useMe(); + */ + template <typename T, typename TKEY> + StatusCode bind(const DataHandle<T>& handle, const TKEY& key); + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name Advanced Client Interface: data object registration + //@{ + + /// Record an object with a key, overwriting any existing object with same key + template <typename T, typename TKEY> + StatusCode overwrite(T* p2BRegistered, const TKEY& key); + + /// Record an object with a key, overwriting any existing object with same key + template <typename T, typename TKEY> + StatusCode overwrite(T* p2BRegistered, const TKEY& key, + bool allowMods, bool noHist=false); + + /// Record an object with a key, overwriting any existing object with same key, take ownership of the auto_pointed obj + template <typename T, typename TKEY> + StatusCode overwrite(std::auto_ptr<T> p2BRegistered, const TKEY& key); + +#if __cplusplus > 201100 + /// Record an object with a key, overwriting any existing object with same key + template <typename T, typename TKEY> + StatusCode overwrite(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool noHist=false); + + /// Record an object with a key, overwriting any existing object with same key, take ownership of the unique_ptr obj + template <typename T, typename TKEY> + StatusCode overwrite(std::unique_ptr<T> pUnique, const TKEY& key); +#endif + + /// Create a proxy object using an IOpaqueAddress and a transient key + StatusCode recordAddress(const std::string& skey, + IOpaqueAddress* pAddress, bool clearAddressFlag=true); + /// Create a proxy object using an IOpaqueAddress + StatusCode recordAddress(IOpaqueAddress* pAddress, bool clearAddressFlag=true); + + /// make a soft link to the object T* already registered (non-const) + template <typename T, typename TLINK> + StatusCode symLink (const T* p2BRegistered, TLINK* p2BLinked ); + + /// make a soft link to the object T* already registered (const link) + template <typename T, typename TLINK> + StatusCode symLink (const T* p2BRegistered, const TLINK* p2BLinked ); + + /// make a soft link to the object pointed by id/key + template <typename TKEY> + StatusCode symLink (const CLID& id, const TKEY& key, const CLID& linkid); + + /// make an alias to a DataObject (provide data type and old key) + template <typename T, typename TKEY, typename AKEY> + StatusCode setAlias(const T* p2BAliased, const TKEY& key, const AKEY& aliasKey); + + /// make an alias to a DataObject (provide only valid pointer) + template <typename T, typename AKEY> + StatusCode setAlias(const T* p2BAliased, const AKEY& aliasKey); + + /// prevent downstream clients from modyfing the pointed-at dobj + StatusCode setConst(const void* pointer); + + /// Remove pObject, will remove its proxy if not reset only. + template <typename T> + StatusCode remove(const T* pObject); + + /// Remove pObject and its proxy no matter what. + template <typename T> + StatusCode removeDataAndProxy(const T* pObject); + + /// @brief swap the content of 2 keys + /// payload A indexed by keyA will now be accessed via keyB and vice versa + /// Note that the swap is invalidated at event boundaries and/or when + /// somebody clear the store. + /// @return false if swap failed + bool transientSwap( const CLID& id, + const std::string& keyA, const std::string& keyB ); + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name Advanced Client Interface: data object access + //@{ + + /// Retrieve version with highest cycle number for a given T,KEY combination + /// If there is only one available version of this data object + /// the returned ObjectWithVersion<T>.versionedKey is set to requestedKey + /// NOTICE that this method is significantly slower than + /// retrieve(const T*, const TKEY&) + /// which returns the last recorded version rather than the one with the + /// highest cycle number. + /// @returns StatusCode::FAILURE if no dataObject found + template <typename T, class TKEY> + StatusCode retrieveHighestVersion(SG::ObjectWithVersion<T>& dobjWithVersion, + const TKEY& requestedKey); + + /// Retrieve all versions of a given T,KEY combination + /// sets allVersions, a ref to a vector of ObjectWithVersion<T> + /// If there is only one available version of this dataObject + /// allVersions[0].versionedKey is set to requestedKey. + /// @returns StatusCode::FAILURE if no dataObject found + //FIXME using a vector exposes ObjectWithVersion definition and hence + //FIXME VersionedKey.h. Should try an iface like + //FIXME retrieveAllVersions(const TKEY& requestedKey, + //FIXME ObjectWithVersion<T>& begin, + //FIXME ObjectWithVersion<T>& end) + template <typename T, class TKEY> + StatusCode + retrieveAllVersions(std::list< SG::ObjectWithVersion<T> >& allVersions, + const TKEY& requestedKey); + + + + /// EXPERTS ONLY: reads from disk your very own private copy of a StoreGate + /// object of type T and given key, if available and locked. + /// readPrivateCopy does not look up the object in SG transient memory + /// so it will fail to return a newly recorded object. + /// You are responsible for managing the returned object and for keeping it + /// in sync with the "main" copy in transient memory, if any. + /// DEPRECATED: Prefer readUniquePrivateCopy. + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::auto_ptr<T> readPrivateCopy (const std::string& key); + + /// EXPERTS ONLY: reads from disk your very own private copy of a StoreGate + /// object of type T and given key, if available and locked. + /// readPrivateCopy does not look up the object in SG transient memory + /// so it will fail to return a newly recorded object. + /// You are responsible for managing the returned object and for keeping it + /// in sync with the "main" copy in transient memory, if any. + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::unique_ptr<T> readUniquePrivateCopy (const std::string& key); + + /// readPrivateCopy implementation (possibly useful from python hence public) + DataObject* + typeless_readPrivateCopy(const CLID& clid, const std::string& key); + + + /// EXPERTS ONLY: like readPrivateCopy this method returns your own private + /// copy of a data object of type T and given key, if available and locked. + /// The difference is that it will return you also an object in SG transient + /// memory. Since we are taking ownership of it, the object in SG + /// will be released after retrievePrivateCopy returns, making + /// all cached references to the object potentially invalid and + /// obviously preventing it from being written out. + /// Sequencing becomes critical. Caveat emptor! + /// + /// DEPRECATED: Prefer retrieveUniquePrivateCopy. + /// + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::auto_ptr<T> retrievePrivateCopy (const std::string& key); + + /// EXPERTS ONLY: like readPrivateCopy this method returns your own private + /// copy of a data object of type T and given key, if available and locked. + /// The difference is that it will return you also an object in SG transient + /// memory. Since we are taking ownership of it, the object in SG + /// will be released after retrievePrivateCopy returns, making + /// all cached references to the object potentially invalid and + /// obviously preventing it from being written out. + /// Sequencing becomes critical. Caveat emptor! + /// + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::unique_ptr<T> retrieveUniquePrivateCopy (const std::string& key); + + /// Retrieve the main @c CLID of the object recorded in @c StoreGate + /// with the given "key" + /// WARNING: slow! + template<typename TKEY> + CLID clid( const TKEY& key ) const; + + /// Retrieve all the @c CLID s (including symlinks) of the object recorded in @c StoreGate + /// with the given "key" + /// WARNING: slow! + template<typename TKEY> + std::vector<CLID> clids( const TKEY& key ) const; + + /** Return the number of instances of an object of type T + * int i = p_store->typeCount<T>(); + * Note that this will return the number of proxies in transient memory + * only, will not check with proxy providers. */ + template <typename T> + int typeCount() const; + + /** Return the number of instances of type T (input CLID) */ + int typeCount(const CLID& id) const; + + /** Look up a keyed object in TDS by CLID. + * returns false if object not available in TDS or persistent stores + * Usage: if (!p_store->contains(FooID, "fooKey")) { ... } */ + template <typename TKEY> + bool contains(const CLID& id, const TKEY& key) const; + + + /** Look up a transient data object in TDS only (no Proxy lookup) + * returns false if object not available in TDS + * Usage: if (!p_store->contains<Foo>("fooKey")) { ... } */ + /// + template <typename T, typename TKEY> + bool transientContains(const TKEY& key) const; + + /** Look up a transient data object in TDS only by CLID. + * returns false if object not available in TDS */ + template <typename TKEY> + bool transientContains(const CLID& id, const TKEY& key) const; + + /** dump objects in store. request forwarded to DataStore + * this is triggered at EndEvent setting the Dump property to true */ + std::string dump() const; + + /// set store ID. request forwarded to DataStore: + void setStoreID(StoreID::type id); + /// get store ID. request forwarded to DataStore: + StoreID::type storeID() const; + + + /** provide list of all storegate keys associated with an object. + * usage: p_store->keys<T>(vkeys, optional flags); + * @param vkeys will be filled with the (possibly empty) list of keys + * @param includeAlias (default false) add alias keys as well + * @param onlyValid (default true) add only keys of valid dobjs + */ + template <typename T> + void + keys(std::vector<std::string>& vkeys, + bool includeAlias = false, bool onlyValid = true); + + /** provide list of all storegate keys associated with an object. + * usage: p_store->keys(CLID, vkeys, optionalFlags); + * @param id CLID for which we are requesting list of keys + * @param vkeys will be filled with the (possibly empty) list of keys + * @param includeAlias (default false) add alias keys as well + * @param onlyValid (default true) add only keys of valid dobjs + */ + void + keys(const CLID& id, std::vector<std::string>& vkeys, + bool includeAlias = false, bool onlyValid = true); + + //@} + + + /// implements IHiveStore interface + // FIXME pointer to unsafe impl exposed + virtual ::IProxyDict* hiveProxyDict() override final { + return StoreGateSvc::currentStore(); + } + + + /////////////////////////////////////////////////////////////////////// + /// \name IHiveStoreMgr implementation + //@{ + /// clear DataStore contents: called by the event loop mgrs + /// @param forceRemove: if true remove proxies ignoring their resetOnly flag + virtual StatusCode clearStore(bool forceRemove=false) override final; + + /** Get data objects registred in store since last getNewDataObjects call (or since init for 1st call) + * + * @param products [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode getNewDataObjects(DataObjIDColl& products) override final; + + /** Check if something has been added to the store since last getNewDataObjects call + * + * @param products [IN] Slot number (event slot) * + * @return Boolean indicating the presence of new products + */ + virtual bool newDataObjectsPresent() override final; + + /** make newly recorded DataObjects know to the WhiteBoard, by copying + * from thread local storage to m_newDataObjects + */ + virtual void commitNewDataObjects() override final; + //@} + + ///a new transient object has been recorded + void addedNewTransObject(CLID clid, const std::string& key); + + void addedNewPersObject(CLID clid, SG::DataProxy* dp); + + ///set the hive event slot pointer: used by the event loop mgrs + static void setSlot(SG::HiveEventSlot* pSlot); + + + ///set pointer to default event store: used by ActiveStoreSvc + void setDefaultStore(SGImplSvc* pStore); + + + ///////////////////////////////////////////////////////////////////////// + /// \name IOVSvc interface + //@{ + + template <typename H, typename TKEY> + StatusCode regHandle( const DataHandle<H>& handle, const TKEY& key ); + + /// non-const method - will return an error + template <typename H, typename TKEY> + StatusCode regHandle( DataHandle<H>& handle, const TKEY& key); + + /// register a callback function, with handle + key + template <typename T, typename H, typename TKEY> + StatusCode regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, const DataHandle<H>& handle, + const TKEY& key, bool trigger=false); + + /// register a callback function, with handle + key. Non const. Error + template <typename T, typename H, typename TKEY> + StatusCode regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, DataHandle<H>& handle, + const TKEY& key, bool trigger=false); + + /// register a callback function(2) with an already registered function(1) + template <typename T1, typename T2> + StatusCode regFcn(StatusCode (T1::*fcn1)(IOVSVC_CALLBACK_ARGS), + const T1* obj1, + StatusCode (T2::*fcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, bool trigger=false); + + /// register a callback function(2) with an already registered AlgTool + template <typename T2> + StatusCode regFcn(const std::string& toolName, + StatusCode (T2::*fcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, bool trigger=false); + + //@} + ///////////////////////////////////////////////////////////////////////// + + /// get proxy for a given data object address in memory + virtual SG::DataProxy* proxy(const void* const pTransient) const override final; + + /// get default proxy with given id. Returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id) const final; + + /// get proxy with given id and key. Returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key) const override final; + /// get proxy with given id and key. Returns 0 to flag failure + /// (overload to prevent a char* to be interpreted as a bool.) + SG::DataProxy* proxy(const CLID& id, const char* key) const; + + /// Raw addition of a proxy to the store. + virtual StatusCode addToStore (CLID id, SG::DataProxy* proxy) override final; + + /** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ + virtual + SG::DataProxy* recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) override final; + + + /** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ + virtual + StatusCode updatedObject (CLID id, const std::string& key) override final; + + + /// Get proxy given a hashed key+clid. + /// Find an exact match; no handling of aliases, etc. + /// Returns 0 to flag failure. + virtual SG::DataProxy* proxy_exact (SG::sgkey_t sgkey) const override final; + + + //@} + + /// \name more proxy dictionary functionality + //@{ + /// get default proxy with given id, optionally checking validity. + /// @returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, bool checkValid) const final; + /// get proxy with given id and key, optionally checking validity. + /// @returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key, bool checkValid) const final; + /// get proxy with given id and key, optionally checking validity. + /// @returns 0 to flag failure + /// (overload to prevent a char* to be interpreted as a bool.) + virtual SG::DataProxy* proxy(const CLID& id, const char* key, bool checkValid) const final + { return this->proxy(id, std::string(key), checkValid); } + + /// return the list of all current proxies in store + virtual std::vector<const SG::DataProxy*> proxies() const override final; + + /// get proxy with given id and key. Does not query ProxyProviderSvc. + /// @returns 0 to flag failure + SG::DataProxy* transientProxy(const CLID& id, const std::string& key) const; + + /// find proxy and access its data. Returns 0 to flag failure + DataObject* accessData(const CLID& id) const; + /// find proxy and access its data. Returns 0 to flag failure + DataObject* accessData(const CLID& id, const std::string& key) const; + + /// associate ProxyProviderSvc to this store + void setProxyProviderSvc(IProxyProviderSvc* pPPSvc); + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name String <-> int key conversions. + //@{ + + typedef IStringPool::sgkey_t sgkey_t; + + /** + * @brief Find the key for a string/CLID pair. + * @param str The string to look up. + * @param clid The CLID associated with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ + virtual + sgkey_t stringToKey (const std::string& str, CLID clid) override final; + + /** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key) const override final; + + /** + * @brief Find the string and CLID corresponding to a given key. + * @param key The key to look up. + * @param clid[out] The found CLID. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key, CLID& clid) const override final; + + /** + * @brief Remember an additional mapping from key to string/CLID. + * @param key The key to enter. + * @param str The string to enter. + * @param clid The CLID associated with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + * Logs an error if @c key already corresponds to a different string. + */ + virtual + void registerKey (sgkey_t key, + const std::string& str, + CLID clidid) override final; + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name ElementLink remapping + //@{ + + + /** + * @brief Declare a remapping. + * @brief clid Class ID of the container being remapped. + * @brief source Key of the container being remapped. + * @brief target Key of the container being remapped to. + * @brief index_offset Amount by which the index should be adjusted + * between the two containers. + * + * This can be used to change the container to which @c ElementLink's + * (and @c DataLink's) point on output. + * + * For example, suppose you have two containers of type T, A and B. + * There possibly are @c ElementLink's pointing at elements contained + * in them. You want to change to a single container C, containing + * the contents of A and B concatenated. To get @c ElementLink's + * updated on output, you can do: + * + *@code + * m_sg->remap (ClassID_traits<T>::ID(), "A", "C", 0); + * m_sg->remap (ClassID_traits<T>::ID(), "B", "C", a.size());; + @endcode + */ + template <class TKEY> + void remap (CLID clid, + const TKEY& source, + const TKEY& target, + off_t index_offset); + + + /** + * @brief Declare a remapping. + * @brief source Key hash of the container being remapped. + * @brief target Key hash of the container being remapped to. + * @brief index_offset Amount by which the index should be adjusted + * between the two containers. + */ + void remap_impl (sgkey_t source, + sgkey_t target, + off_t index_offset); + + + /** + * @brief Test to see if the target of an ElementLink has moved. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + */ + virtual bool tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out) override final; + + //@} + + ////////////////////////////////////////////////////////////////// + /// \name Gaudi Standard Service structors + //@{ + StoreGateSvc(const std::string& name, ISvcLocator* svc); + virtual ~StoreGateSvc() override; + //@} + + /////////////////////////////////////////////////////////////////////// + /// \name Gaudi IService implementation + //@{ + virtual StatusCode initialize() override; + virtual StatusCode stop() override; + virtual StatusCode finalize() override; + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ) override; + //@} + /// Should rather be in IStoreGateSvc.h if we had one + static const InterfaceID& interfaceID(); + + + ////////////////////////////////////////////////////////////////// + /// \name Gaudi IIncidentListener implementation + //@{ + /// load proxies at begin event + StatusCode loadEventProxies(); + //@} + +private: + + SGImplSvc* m_defaultStore; + std::string m_defaultStoreName; ///< property + ServiceHandle<IProxyProviderSvc> m_pPPSHandle; ///< property + ServiceHandle<IIncidentSvc> m_incSvc; ///< property + mutable std::recursive_mutex m_recMutex; ///< to lock det store accesses + + friend class SG::TestHiveStoreSvc; + static SG::HiveEventSlot* currentSlot(); + + friend class SG::HiveMgrSvc; + ///returns pointer to the current SGImplSvc + SGImplSvc* currentStore() const; + ///is the current store an event store being managed by an IHiveWhiteboard? + bool isHiveStore() const; + + + ///access proxyRange() + friend class AthenaOutputStream; + ///return a range to all proxies of a given CLID + StatusCode proxyRange(const CLID& id, + SG::ConstProxyIterator& beg, + SG::ConstProxyIterator& end) const; + + ///access releaseObject + friend class TileInfoLoader; + /// release object held by proxy, if any. Gives up ownership + /// (somebody else must take charge) + void releaseObject(const CLID& id, const std::string& key); + + + ///access clearProxyPayload + friend class IOVDbSvc; + friend class IOVSvcTool; + friend class SGDeleteAlg; + friend + void + AthenaInternal::py_sg_clearProxyPayload(StoreGateSvc*, SG::DataProxy*); + friend class PerfMon::StorePayloadMon; + + /// use to reset a proxy (clearing the data object it contains) + /// Unlike DataProxy::reset this method correctly updates SGSvc internals + void clearProxyPayload(SG::DataProxy*); + + ///access store() + friend class CondSvc; + friend class IOVSvc; // FIXME + friend class PileUpMergeSvc; // FIXME needs to call tRange + friend class EventDumperSvc; + friend class MemoryMonitorSvc; + friend void testHLTAutoKeyReset(StoreGateSvc&, IProxyProviderSvc&); + ///access typeless_record + friend class ThinningSvc; + friend class SG::VarHandleBase; + friend + PyObject* + AthenaInternal::recordObjectToStore(StoreGateSvc*,PyObject*,PyObject*,bool,bool,bool); + /// type-less recording of an object with a key, allow possibility of + /// specifying const-access and history record + StatusCode typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly=true, + bool noHist=false ); + /// same as typeless_record, allows to ovewrite an object in memory or on disk + StatusCode typeless_overwrite( const CLID& id, + DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, + bool noHist=false, + const std::type_info* tinfo=0); + + //FIXME need to add wrapper like this class, to make relevant DataStore methods thread-safe + ///thread UNSAFE access to underlying DataStore. Use at your own risk + const SG::DataStore* store() const { return currentStore()->store(); } + SG::DataStore* store() { return currentStore()->store(); } ///< DEPRECATED + bool isSymLinked(const CLID& linkID, SG::DataProxy* dp); + + StatusCode addSymLink(const CLID& linkid, SG::DataProxy* dp); + + StatusCode addAlias(const std::string& aliasKey, SG::DataProxy* dp); + + /// creates a key internally if none specified by client + std::string createKey(const CLID& dataID); + + /// try to locate a proxy or create it if needed + SG::DataProxy* setupProxy(const CLID& dataID, + const std::string& gK, + DataObject* pDObj, + bool allowMods, + bool resetOnly); + + ///put a bad (unrecordable) dobj away + void recycle(DataObject* pBadDObj); + ///throw away bad objects + void emptyTrash(); + + ///name says it all + bool bindHandleToProxy(const CLID& id, const std::string& key, + IResetable* ir, SG::DataProxy*& dp); + + /// remove proxy from store, unless it is reset only. + /// provide pTrans!=0 (must match proxy...) to save time + /// @param forceRemove remove the proxy no matter what + /// DO NOT USE THIS FUNCTION! + /// IT IS UNSAFE AND IS LIKELY TO BE REMOVED! + StatusCode removeProxy(SG::DataProxy* proxy, const void* pTrans, + bool forceRemove=false); + ///forwarded to DataStore + StatusCode t2pRegister(const void* const pTrans, SG::DataProxy* const pPers); + ///forwarded to DataStore + void t2pRemove(const void* const pTrans); + + /// callback for output level property + void msg_update_handler(Property& outputLevel); + + template <class DOBJ, class AUXSTORE> + bool associateAux_impl(DataHandle<DOBJ>& handle, const AUXSTORE*); + template <class DOBJ, class AUXSTORE> + bool associateAux_impl(const DataHandle<DOBJ>& handle, const AUXSTORE*); + template <class DOBJ> + bool associateAux_impl(DataHandle<DOBJ>& , const SG::NoAuxStore*) { return true; } + template <class DOBJ> + bool associateAux_impl(const DataHandle<DOBJ>&, const SG::NoAuxStore*) { return true; } + + /// Add automatically-made symlinks for DP. + void addAutoSymLinks (const std::string& key, CLID clid, SG::DataProxy* dp, + const std::type_info* tinfo, + bool warn_nobib = true); + + friend class ActiveStoreSvc; + /// The current store is becoming the active store. Switch the + /// allocation arena, if needed. + /// Only intended to be called by ActiveStoreSvc. + void makeCurrent(); + + bool m_DumpStore; ///< property Dump: triggers dump() at EndEvent + bool m_ActivateHistory; ///< property: activate the history service + + ///get the IOVSvc "just in time" (breaks recursion at initialize) + IIOVSvc* getIIOVSvc(); + IIOVSvc* m_pIOVSvc; + +public: + /////////////////////////////////////////////////////////////////////// + /// \name Obsolete and Deprecated methods + //@{ + /// DEPRECATED: Retrieve the default object into a const DataHandle + template <typename T> + StatusCode __attribute__((deprecated)) retrieve(const DataHandle<T>& handle); + + /// DEPRECATED: Retrieve the default object into a DataHandle + template <typename T> + StatusCode __attribute__((deprecated)) retrieve(DataHandle<T>& handle); + + /// DEPRECATED: Retrieve an object with "key", into a const DataHandle + template <typename T, typename TKEY> + StatusCode __attribute__((deprecated)) retrieve(const DataHandle<T>& handle, const TKEY& key); + /// DEPRECATED: Retrieve an object with "key", into a DataHandle + template <typename T, typename TKEY> + StatusCode __attribute__((deprecated)) retrieve(DataHandle<T>& handle, const TKEY& key); + + /// DEPRECATED Retrieve all objects of type T: use iterators version instead + template <typename T> + StatusCode __attribute__((deprecated)) retrieve(const DataHandle<T>& begin, + const DataHandle<T>& end); + /// DEPRECATED, use version taking ref to vector + template <typename T> + std::vector<std::string> //FIXME inefficient. Should take ref to vector + __attribute__((deprecated)) keys(bool allKeys = false); + + /// DEPRECATED, use version taking ref to vector + std::vector<std::string> //FIXME inefficient. Should take ref to vector + __attribute__((deprecated)) keys(const CLID& id, bool allKeys = false); + + /// DEPRECATED: use recordAddress instead + StatusCode __attribute__((deprecated)) createProxy(IOpaqueAddress* pAddress, bool clearAddressFlag=true) { + return recordAddress(pAddress, clearAddressFlag); + } + + /// DEPRECATED put a dobj pointer in a bucket as appropriate + /// see tools/StorableConversion.h for replacement + template <typename T> + static + DataObject* __attribute__((deprecated)) asStorable(T* pDObj); + + /// DEPRECATED gets a dobj pointer from a bucket as appropriate + /// see tools/StorableConversion.h for replacement + template <typename T> + static + bool __attribute__((deprecated)) fromStorable(DataObject* pObject, T*& pData); + + //@} + + +private: + StoreGateSvc (const StoreGateSvc&); + StoreGateSvc& operator= (const StoreGateSvc&); +}; + + +/// Here's one that's easy to call from the debugger. +void SG_dump (StoreGateSvc* sg); + + +#include "StoreGate/StoreGateSvc.icc" + + +//- PyGate: StoreGate access from python ------------------------------------- +template< class T > +struct PyGate { + // default object retrieval + static const T* retrieve( StoreGateSvc* psg ) { + const T* obj = 0; + if ( StatusCode::SUCCESS == psg->retrieve( obj ) ) + return obj; + return 0; + } + + // object retrieval with string key + static const T* retrieve( StoreGateSvc* psg, const std::string& key ) { + const T* obj = 0; + if ( StatusCode::SUCCESS == psg->retrieve( obj, key ) ) + return obj; + return 0; + } +}; + +#endif //ATHENAHIVE +#endif // STOREGATE_STOREGATESVC_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.icc b/EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.icc new file mode 100644 index 00000000..e0d38a5f --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/StoreGateSvc.icc @@ -0,0 +1,619 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file SGHiveStore.icc + * forwarded implementation of StoreGateSvc methods + */ + +#ifndef STOREGATE_STOREGATESVC_ICC +#define STOREGATE_STOREGATESVC_ICC +#include <vector> + +/// macro to help writing the function calls. +/// first looks if there is a hive slot defined, otherwise forwards to the "serial" implementation +#define _SGXCALL(FUN,ARGS,ONERR) \ + if (isHiveStore()) { \ + SG::HiveEventSlot* pSlot(StoreGateSvc::currentSlot()); \ + SG::HiveEventSlot::mutex_t::scoped_lock lock; lock.acquire(pSlot->storeMutex); \ + return (0 != pSlot->pEvtStore) ? \ + pSlot->pEvtStore->FUN ARGS : ONERR; \ + } else { \ + std::lock_guard<std::recursive_mutex> lock (m_recMutex); \ + return m_defaultStore->FUN ARGS; } + +/// macro to help writing the function calls +#define _SGVOIDCALL(FUN,ARGS) \ + if (isHiveStore()) { \ + SG::HiveEventSlot* pSlot(StoreGateSvc::currentSlot()); \ + SG::HiveEventSlot::mutex_t::scoped_lock lock; lock.acquire(pSlot->storeMutex); \ + if (0 != pSlot->pEvtStore) pSlot->pEvtStore->FUN ARGS; \ + } else { \ + std::lock_guard<std::recursive_mutex> lock (m_recMutex); \ + m_defaultStore->FUN ARGS; } + +inline +SG::DataProxy* +StoreGateSvc::proxy(const CLID& id, const char* key) const { + _SGXCALL( proxy, (id, key), 0 ); +} + +inline +SG::DataProxy* +StoreGateSvc::proxy_exact (SG::sgkey_t sgkey) const { + _SGXCALL( proxy_exact, (sgkey), 0 ); +} + +template <typename H, typename TKEY> +StatusCode +StoreGateSvc::regHandle( const DataHandle<H>& handle, const TKEY& key ) { + _SGXCALL( regHandle, (handle, key), StatusCode::FAILURE ); +} + +/// non-const method - will return an error +template <typename H, typename TKEY> +StatusCode +StoreGateSvc::regHandle( DataHandle<H>& handle, const TKEY& key) { + _SGXCALL( regHandle, (handle, key), StatusCode::FAILURE ); +} + +/// register a callback function, with handle + key +template <typename T, typename H, typename TKEY> +StatusCode +StoreGateSvc::regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, const DataHandle<H>& handle, + const TKEY& key, bool trigger) { + _SGXCALL( regFcn, (updFcn, obj, handle, key, trigger), StatusCode::FAILURE ); +} + +/// register a callback function, with handle + key. Non const. Error +template <typename T, typename H, typename TKEY> +StatusCode +StoreGateSvc::regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, DataHandle<H>& handle, + const TKEY& key, bool trigger) { + _SGXCALL( regFcn, (updFcn, obj, handle, key, trigger), StatusCode::FAILURE ); +} + + +/// register a callback function(2) with an already registered function(1) +template <typename T1, typename T2> +StatusCode +StoreGateSvc::regFcn(StatusCode (T1::*fcn1)(IOVSVC_CALLBACK_ARGS), + const T1* obj1, + StatusCode (T2::*fcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, bool trigger) { + _SGXCALL( regFcn, (fcn1, obj1, fcn2, obj2, trigger), StatusCode::FAILURE ); +} + + +/// register a callback function(2) with an already registered AlgTool +template <typename T2> +StatusCode +StoreGateSvc::regFcn(const std::string& toolName, + StatusCode (T2::*fcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, bool trigger) { + _SGXCALL( regFcn, (toolName, fcn2, obj2, trigger), StatusCode::FAILURE ); +} + +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES +/////////////////////////////////////////////////////////////////// +// create an object and record it with key +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY, typename... ARGS> +SG::WPtr<T> +StoreGateSvc::create(const TKEY& key, ARGS... constructorArgs) { + T* pT = new T(constructorArgs...); + if(!(this->record(pT, key).isSuccess())) { + msg() << MSG::ERROR << "create: problem recording created object @" + << pT << " using key " << key << endmsg; + pT=0; //record will take care of deleting pT even if it fails + } + return pT; +} +#endif +#endif +/////////////////////////////////////////////////////////////////// +// record an object with key +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(std::auto_ptr<T> pAuto, const TKEY& key) +{ + const bool ALLOWMODS(true); + _SGXCALL(record, (pAuto.release(), key, ALLOWMODS), StatusCode::FAILURE); //SG takes ownership +} + +template <typename T, typename TKEY> +StatusCode +StoreGateSvc::overwrite(std::auto_ptr<T> p2BRegistered, const TKEY& key) +{ + _SGXCALL(overwrite, (p2BRegistered, key), StatusCode::FAILURE); +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(T* pObject, const TKEY& key) +{ + const bool ALLOWMODS(true); + _SGXCALL(record, (pObject, key, ALLOWMODS), StatusCode::FAILURE); +} +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(const T* pObject, const TKEY& key) +{ + const bool NOMODS(false); + _SGXCALL(record, (const_cast<T*>(pObject), key, NOMODS), StatusCode::FAILURE); +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(T* pObject, const TKEY& key, + bool allowMods, bool resetOnly, bool noHist) +{ + _SGXCALL(record, (pObject, key, allowMods, resetOnly, noHist ), StatusCode::FAILURE); +} +////////////////////////////////////////////////////////////////// +// Retrieve the default object (with no key) as a const pointer +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode StoreGateSvc::retrieve(const T*& ptr) +{ + _SGXCALL(retrieve, (ptr), StatusCode::FAILURE); +} + +////////////////////////////////////////////////////////////////// +// Retrieve the default object (with no key) as a pointer (non-const) +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode StoreGateSvc::retrieve(T*& ptr) +{ + _SGXCALL(retrieve, (ptr), StatusCode::FAILURE); +} + +////////////////////////////////////////////////////////////////// +// Retrieve the keyed object as a const pointer +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode StoreGateSvc::retrieve(const T*& ptr, const TKEY& key) +{ + _SGXCALL(retrieve, (ptr, key), StatusCode::FAILURE); +} + +////////////////////////////////////////////////////////////////// +// Retrieve the keyed object as a non-const pointer +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode StoreGateSvc::retrieve(T*& ptr, const TKEY& key) +{ + _SGXCALL(retrieve, (ptr, key), StatusCode::FAILURE); +} + +/// Retrieve all objects of type T: returns an SG::ConstIterator range +template <typename T> +StatusCode +StoreGateSvc::retrieve(SG::ConstIterator<T>& begin, + SG::ConstIterator<T>& end) { + _SGXCALL(retrieve, (begin, end), StatusCode::FAILURE); +} + + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. + **/ + +template <typename T> +T* StoreGateSvc::retrieve () +{ + _SGXCALL(retrieve<T>, (), 0); +} + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. + * @param key The key to use for the lookup. + **/ +template <typename T, class TKEY> +T* StoreGateSvc::retrieve (const TKEY& key) +{ + _SGXCALL(retrieve<T>, (key), 0); +} + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. + **/ +template <typename T> +T* StoreGateSvc::tryRetrieve () +{ + _SGXCALL(tryRetrieve<T>, (), 0); +} + +template <typename T> +const T* StoreGateSvc::tryConstRetrieve() +{ + _SGXCALL(tryConstRetrieve<T>, (), 0); +} + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. Don't print any WARNINGs + * @param key The key to use for the lookup. + **/ +template <typename T, class TKEY> +T* StoreGateSvc::tryRetrieve (const TKEY& key) +{ + _SGXCALL(tryRetrieve<T>, (key), 0); +} + +template <typename T, class TKEY> +const T* StoreGateSvc::tryConstRetrieve (const TKEY& key) +{ + _SGXCALL(tryConstRetrieve<T>, (key), 0); +} + +/** + * @brief Retrieve an object of type @c T from storegate and associate it + * to its auxiliary store + * Return 0 the object or the aux store is not found. + * @param key The key to use for the lookup. + **/ +template <typename T, class TKEY> +T* StoreGateSvc::retrieveAux (const TKEY& key) +{ + _SGXCALL(retrieveAux<T>, (key), 0); +} + +template <typename T, class TKEY> +const T* StoreGateSvc::constRetrieveAux (const TKEY& key) +{ + _SGXCALL(constRetrieveAux<T>, (key), 0); +} + +template <typename T> +int StoreGateSvc::typeCount() const +{ + return typeCount(ClassID_traits<T>::ID()); +} + + +template <typename T, typename TKEY> +bool +StoreGateSvc::contains(const TKEY& key) const +{ + return this->contains(ClassID_traits<T>::ID(), key); +} + +template <typename TKEY> +bool +StoreGateSvc::contains(const CLID& clid, const TKEY& key) const +{ + _SGXCALL( contains, (clid,key), false ); +} + +template <typename T, typename TKEY> +bool +StoreGateSvc::transientContains(const TKEY& key) const +{ + return transientContains(ClassID_traits<T>::ID(), key); +} + + + +template <typename TKEY> +bool +StoreGateSvc::transientContains(const CLID& id, const TKEY& key) const +{ + _SGXCALL(transientContains, (id, key), false); +} + +//-------------------------end of contains methods-------------------- +template <typename T> +void +StoreGateSvc::keys(std::vector<std::string>& vkeys, + bool includeAlias, bool onlyValid) { + return this->keys(ClassID_traits<T>::ID(), vkeys, includeAlias, onlyValid); +} + + +template <typename T, typename TKEY> +StatusCode +StoreGateSvc::bind(const DataHandle<T>& handle, const TKEY& key) { + _SGXCALL(bind, (handle, key), StatusCode::FAILURE); +} + +#if __cplusplus > 201100 +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(std::unique_ptr<T> pUnique, const TKEY& key) +{ + _SGXCALL(record, (std::move(pUnique), key), StatusCode::FAILURE); +} +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(std::unique_ptr<const T> pUnique, + const TKEY& key) +{ + _SGXCALL(record, (std::move(pUnique), key), StatusCode::FAILURE); +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode StoreGateSvc::record(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool resetOnly, bool noHist) +{ + _SGXCALL(record, (std::move(pUnique), key, allowMods, resetOnly, noHist), StatusCode::FAILURE); +} +#endif + +template <typename T, typename TKEY> +StatusCode StoreGateSvc::overwrite(T* p2BRegistered, const TKEY& key) +{ + const bool ALLOWMODS(true); + return overwrite(p2BRegistered, key, ALLOWMODS); //SG takes ownership +} + +template <typename T, typename TKEY> +StatusCode +StoreGateSvc::overwrite(T* pObject, const TKEY& key, + bool allowMods, bool noHist) +{ + _SGXCALL(overwrite, (pObject, key, allowMods, noHist), StatusCode::FAILURE); +} + +#if __cplusplus > 201100 +template <typename T, typename TKEY> +StatusCode StoreGateSvc::overwrite(std::unique_ptr<T> pUnique, const TKEY& key) +{ + _SGXCALL(overwrite, (std::move(pUnique), key), StatusCode::FAILURE); +} + +template <typename T, typename TKEY> +StatusCode StoreGateSvc::overwrite(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool noHist) +{ + _SGXCALL(overwrite, (std::move(pUnique), key, allowMods, noHist), StatusCode::FAILURE); +} +#endif + +template <typename T, typename AKEY> +StatusCode StoreGateSvc::setAlias(const T* pObject, const AKEY& aKey) +{ + _SGXCALL(setAlias, (pObject, aKey), StatusCode::FAILURE); +} +//------------------------------------------------------------------- +template <typename T, typename TKEY, typename AKEY> +StatusCode +StoreGateSvc::setAlias(const T* dummy, + const TKEY& key, const AKEY& aKey) +{ + _SGXCALL(setAlias, (dummy, key, aKey), StatusCode::FAILURE); +} + +////////////////////////////////////////////////////////////////// +// Make a soft link to the object with key: return non_const link +////////////////////////////////////////////////////////////////// +template <typename T, typename TLINK> +StatusCode +StoreGateSvc::symLink(const T* pObject, TLINK* dummy) +{ + _SGXCALL(symLink, (pObject, dummy), StatusCode::FAILURE); +} + +////////////////////////////////////////////////////////////////// +// Make a soft link to the object with key: set const link +////////////////////////////////////////////////////////////////// +template <typename T, typename TLINK> +StatusCode +StoreGateSvc::symLink(const T* pObject, const TLINK* dummy) +{ + _SGXCALL(symLink, (pObject, dummy), StatusCode::FAILURE); +} + +template <typename TKEY> +StatusCode +StoreGateSvc::symLink(const CLID& id, const TKEY& key, const CLID& linkid) +{ + _SGXCALL(symLink, (id, key, linkid), StatusCode::FAILURE); +} + + +/// Remove pObject, will remove its proxy if not reset only. +template <typename T> +StatusCode +StoreGateSvc::remove(const T* pObject) { + _SGXCALL(remove, (pObject), StatusCode::FAILURE); +} + +/// Remove pObject and its proxy no matter what. +template <typename T> +StatusCode +StoreGateSvc::removeDataAndProxy(const T* pObject) { + _SGXCALL(removeDataAndProxy, (pObject), StatusCode::FAILURE); +} + +template <typename T, class TKEY> +StatusCode +StoreGateSvc::retrieveHighestVersion(SG::ObjectWithVersion<T>& dobjWithVersion, + const TKEY& requestedKey) { + _SGXCALL(retrieveHighestVersion, (dobjWithVersion, requestedKey), StatusCode::FAILURE); +} + +template <typename T, class TKEY> +StatusCode +StoreGateSvc::retrieveAllVersions(std::list< SG::ObjectWithVersion<T> >& allVersions, + const TKEY& requestedKey) { + _SGXCALL(retrieveAllVersions, (allVersions, requestedKey), StatusCode::FAILURE); +} + + +template <typename T> +std::auto_ptr<T> +StoreGateSvc::readPrivateCopy (const std::string& key) { + std::auto_ptr<T> nullT; + _SGXCALL(readPrivateCopy<T>, (key), nullT); +} + + +template <typename T> +std::auto_ptr<T> +StoreGateSvc::retrievePrivateCopy (const std::string& key) { + std::auto_ptr<T> nullT; + _SGXCALL(retrievePrivateCopy<T>, (key), nullT); +} + +template <typename T> +std::unique_ptr<T> +StoreGateSvc::readUniquePrivateCopy (const std::string& key) { + if (isHiveStore()) { + SG::HiveEventSlot* pSlot(StoreGateSvc::currentSlot()); + SG::HiveEventSlot::mutex_t::scoped_lock lock; lock.acquire(pSlot->storeMutex); + return (0 != pSlot->pEvtStore) ? + pSlot->pEvtStore->readUniquePrivateCopy<T>(key) : + std::unique_ptr<T>{}; + } else { + std::lock_guard<std::recursive_mutex> lock (m_recMutex); + return m_defaultStore->readUniquePrivateCopy<T>(key); + } +} + + +template <typename T> +std::unique_ptr<T> +StoreGateSvc::retrieveUniquePrivateCopy (const std::string& key) { + if (isHiveStore()) { + SG::HiveEventSlot* pSlot(StoreGateSvc::currentSlot()); + SG::HiveEventSlot::mutex_t::scoped_lock lock; lock.acquire(pSlot->storeMutex); + return (0 != pSlot->pEvtStore) ? + pSlot->pEvtStore->retrieveUniquePrivateCopy<T>(key) : + std::unique_ptr<T>{}; + } else { + std::lock_guard<std::recursive_mutex> lock (m_recMutex); + return m_defaultStore->retrieveUniquePrivateCopy<T>(key); + } +} + +////////////////////////////////////////////////////////////////// +// Retrieve the @c CLID of a given "key" +// WARNING: slow! +////////////////////////////////////////////////////////////////// +template<typename TKEY> +CLID +StoreGateSvc::clid( const TKEY& key ) const +{ + _SGXCALL(clid, (key), CLID_NULL); +} + +////////////////////////////////////////////////////////////////// +// Retrieve the @c CLID s of a given "key" +// WARNING: slow! +////////////////////////////////////////////////////////////////// +template<typename TKEY> +std::vector<CLID> +StoreGateSvc::clids( const TKEY& key ) const +{ + std::vector<CLID> nullV; + _SGXCALL(clids, (key), nullV); +} + +/////////////////////////////////////////////////////////////////////////// + +inline +void +StoreGateSvc::setProxyProviderSvc(IProxyProviderSvc* pPPSvc) { + _SGVOIDCALL(setProxyProviderSvc, (pPPSvc)); +} + + +/** + * @brief associate a data object to its auxiliary store + * Return false if the aux store is not found. + * @param key The key to use for the lookup. + **/ +template <class DOBJ> +bool StoreGateSvc::associateAux (DataHandle<DOBJ>& handle, bool ignoreMissing) +{ + _SGXCALL(associateAux, (handle, ignoreMissing), false); +} + +template <class DOBJ> +bool StoreGateSvc::associateAux (const DataHandle<DOBJ>& handle, bool ignoreMissing) +{ + _SGXCALL(associateAux, (handle, ignoreMissing), false); +} + +template <class TKEY> +void +StoreGateSvc::remap (CLID clid, + const TKEY& source, + const TKEY& target, + off_t index_offset) { + _SGVOIDCALL(remap, (clid, source, target, index_offset)); +} + + +/// DEPRECATED: Retrieve the default object into a const DataHandle +template <typename T> +StatusCode +StoreGateSvc::retrieve(const DataHandle<T>& handle) { + _SGXCALL(retrieve, (handle), StatusCode::FAILURE); +} + +/// DEPRECATED: Retrieve the default object into a DataHandle +template <typename T> +StatusCode +StoreGateSvc::retrieve(DataHandle<T>& handle) { + _SGXCALL(retrieve, (handle), StatusCode::FAILURE); +} + +/// DEPRECATED: Retrieve an object with "key", into a const DataHandle +template <typename T, typename TKEY> +StatusCode +StoreGateSvc::retrieve(const DataHandle<T>& handle, const TKEY& key) { + _SGXCALL(retrieve, (handle, key), StatusCode::FAILURE); +} + +/// DEPRECATED: Retrieve an object with "key", into a DataHandle +template <typename T, typename TKEY> +StatusCode +StoreGateSvc::retrieve(DataHandle<T>& handle, const TKEY& key) { + _SGXCALL(retrieve, (handle, key), StatusCode::FAILURE); +} + +/// DEPRECATED Retrieve all objects of type T: use iterators version instead +template <typename T> +StatusCode +StoreGateSvc::retrieve(const DataHandle<T>& begin, + const DataHandle<T>& end) { + _SGXCALL(retrieve, (begin, end), StatusCode::FAILURE); +} + +/// DEPRECATED put a dobj pointer in a bucket as appropriate +/// see tools/StorableConversion.h for replacement +template <typename T> +DataObject* +StoreGateSvc::asStorable(T* pDObj) { + return SG::asStorable(pDObj); +} +/// DEPRECATED gets a dobj pointer from a bucket as appropriate +/// see tools/StorableConversion.h for replacement +template <typename T> +bool +StoreGateSvc::fromStorable(DataObject* pObject, T*& pData) { + return SG::fromStorable(pObject, pData); +} + + +/// DEPRECATED, use version taking ref to vector +template <typename T> +std::vector<std::string> //FIXME inefficient. Should take ref to vector +StoreGateSvc::keys(bool allKeys) { + std::vector<std::string> nullV; + _SGXCALL( keys<T>, (allKeys), nullV ); +} + + +#endif //STOREGATE_STOREGATESVC_ICC diff --git a/EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.h b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.h new file mode 100644 index 00000000..8b9b25b7 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.h @@ -0,0 +1,267 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: UpdateHandle.h 733875 2016-04-04 23:33:03Z leggett $ +/** + * @file StoreGate/UpdateHandle.h + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Handle class for modifying an existing object in StoreGate. + */ + +#ifndef STOREGATE_SG_UPDATEHANDLE_H +#define STOREGATE_SG_UPDATEHANDLE_H 1 + + +#include "StoreGate/VarHandleBase.h" +#include "StoreGate/UpdateHandleKey.h" +#include "StoreGate/StoreGateSvc.h" /* needed by clients */ +#include "GaudiKernel/EventContext.h" +#include <string> + + + +namespace SG { + + + /** + * @class SG::UpdateHandle<T> + * @brief a smart pointer to an object of a given type in an @c IProxyDict (such + * as StoreGateSvc). It d-casts and caches locally the pointed-at object, to + * speed-up subsequent accesses. + * It can be reset by the store for asynchronous updates (IOVSvc) + * + * @c SG::UpdateHandle<T> can only access non-const proxies in StoreGate. + * A valid proxy must already exist in StoreGate. + * + * Usage example: + * @code + * class MyAlg : public AthAlgorithm + * { + * SG::UpdateHandle<int> m_int; + * }; + * + * MyAlg::MyAlg(...) : ..., m_int("MyIntSgKey") { + * declareProperty("IntHandle", + * m_int = SG::UpdateHandle<int>("MyIntSgKey"), + * "a handle to an int in StoreGate"); + * } + * + * StatusCode MyAlg::execute() + * { + * ATH_MSG_INFO("int value @[" << m_int.name() << "]=" + * << *m_int); + * *m_int = 10; + * ATH_MSG_INFO("int value @[" << m_int.name() << "]=" + * << *m_int); + * return StatusCode::SUCCESS; + * } + * @endcode + * + * For more information have a look under the package + * Control/AthenaExamples/AthExHelloWorld + * + */ + template <class T> + class UpdateHandle + : public SG::VarHandleBase + { + public: + typedef T* pointer_type; // FIXME: better handling of + typedef const T* const_pointer_type; // qualified T type ? + typedef T& reference_type; + typedef const T& const_reference_type; + + + //************************************************************************ + // Constructors, etc. + // + + + /** + * @brief Default constructor. + * + * The handle will not be usable until a non-blank key is assigned. + */ + UpdateHandle(); + + + /** + * @brief Constructor with full arguments. + * @param sgkey StoreGate key of the referenced object. + * @param storename Name of the referenced event store. + */ + UpdateHandle(const std::string& sgkey, + const std::string& storename = "StoreGateSvc"); + + + /** + * @brief Constructor from an UpdateHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ + explicit UpdateHandle (const UpdateHandleKey<T>& key); + + + /** + * @brief Constructor from an UpdateHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ + explicit UpdateHandle (const UpdateHandleKey<T>& key,const EventContext& ctx); + + + /** + * @brief Copy constructor. + */ + UpdateHandle( const UpdateHandle& rhs ); + + + /** + * @brief Move constructor. + */ + UpdateHandle( UpdateHandle&& rhs ); + + + /** + * @brief Assignment operator. + */ + UpdateHandle& operator=( const UpdateHandle& rhs ); + + + /** + * @brief Move operator. + */ + UpdateHandle& operator=( UpdateHandle&& rhs ); + + + //************************************************************************ + // Dereference. + // + + + /** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + * + * This will inform Hive that the object has been modified. + */ + pointer_type operator->(); + + + /** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + * + * This will inform Hive that the object has been modified. + */ + reference_type operator*(); + + + /** + * @brief Derefence the pointer. + * Returns nullptr on failure. + * + * This will _not_ inform Hive that the object has been modified. + */ + const_pointer_type cptr(); + + + /** + * @brief Derefence the pointer. + * Returns nullptr on failure. + * + * This will inform Hive that the object has been modified. + */ + pointer_type ptr(); + + + /** + * @brief Return the cached pointer directly; no lookup. + */ + pointer_type cachedPtr() const; + + + /** + * @brief Can the handle be successfully dereferenced? + */ + virtual bool isValid() override final; + + + // FIXME: Remove this once IResetable is cleaned up. + using IResetable::reset; + + + /** + * @brief Reset this handle. + * @param hard If true, anything depending on the event store is cleared. + * + * Clear the updated flag, then call reset() from the base class. + */ + virtual void reset (bool hard) override; + + + private: + /** + * @brief Helper: dereference the pointer. + * Throws ExcNullUpdateHandle on failure. + */ + pointer_type checkedPtr(); + + /// Flag to prevent multiple calls to IProxyDict::udpatedObject. + bool m_updated; + }; + + + /** + * @brief Return an @c UpdateHandle referencing @c key. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ + template <class T> + UpdateHandle<T> makeHandle (const UpdateHandleKey<T>& key); + + + /** + * @brief Return an @c UpdateHandle referencing @c key for an explicit context. + * @param key The key object holding the clid/key/store. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ + template <class T> + UpdateHandle<T> makeHandle (const UpdateHandleKey<T>& key, + const EventContext& ctx); + + +} /* namespace SG */ + + +#include "StoreGate/UpdateHandle.icc" + + +#ifndef NO_LEGACY_HANDLES +namespace SG { + template <class T> + using RWVar = UpdateHandle<T>; +} +#endif + +#endif //> !STOREGATE_SG_UPDATEHANDLE_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.icc b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.icc new file mode 100644 index 00000000..b1f62407 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandle.icc @@ -0,0 +1,306 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: UpdateHandle.icc 726621 2016-02-27 20:03:45Z ssnyder $ +/** + * @file StoreGate/UpdateHandle.icc + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Handle class for modifying an existing object in StoreGate. + */ + +#ifndef STOREGATE_SG_UPDATEHANDLE_ICC +#define STOREGATE_SG_UPDATEHANDLE_ICC 1 + + +#include "StoreGate/exceptions.h" +#include "SGTools/ClassID_traits.h" +#include <stdexcept> + + +namespace SG { + + +/** + * @brief Default constructor. + * + * The handle will not be usable until a non-blank key is assigned. + */ +template <class T> +inline +UpdateHandle<T>::UpdateHandle() + : VarHandleBase(ClassID_traits<T>::ID(), Gaudi::DataHandle::Updater), + m_updated(false) +{ +} + + +/** + * @brief Constructor with full arguments. + * @param sgkey StoreGate key of the referenced object. + * @param storename Name of the referenced event store. + */ +template <class T> +inline +UpdateHandle<T>::UpdateHandle(const std::string& sgkey, + const std::string& storename /*= "StoreGateSvc"*/) + : VarHandleBase( ClassID_traits<T>::ID(), + sgkey, Gaudi::DataHandle::Updater, storename ), + m_updated(false) +{ +} + + +/** + * @brief Constructor from an UpdateHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +inline +UpdateHandle<T>::UpdateHandle (const UpdateHandleKey<T>& key) + : VarHandleBase (key), + m_updated(false) +{ +} + + +/** + * @brief Constructor from an UpdateHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +UpdateHandle<T>::UpdateHandle (const UpdateHandleKey<T>& key, + const EventContext& ctx) + : VarHandleBase (key, ctx), + m_updated(false) +{ +} + + +/** + * @brief Copy constructor. + */ +template <class T> +inline +UpdateHandle<T>::UpdateHandle(const UpdateHandle& h) + : VarHandleBase(h), + m_updated(h.m_updated) +{ +} + +/** + * @brief Move constructor. + */ +template <class T> +inline +UpdateHandle<T>::UpdateHandle(UpdateHandle&& h) + : VarHandleBase(std::move(h)), + m_updated(h.m_updated) +{ +} + + +/** + * @brief Assignment operator. + */ +template <class T> +inline +UpdateHandle<T>& +UpdateHandle<T>::UpdateHandle::operator= (const UpdateHandle& h) +{ + if (this != &h) { + this->VarHandleBase::operator=(h); + this->m_updated = h.m_updated; + } + return *this; +} + + +/** + * @brief Move operator. + */ +template <class T> +inline +UpdateHandle<T>& +UpdateHandle<T>::UpdateHandle::operator= (UpdateHandle&& h) +{ + if (this != &h) { + this->VarHandleBase::operator=(std::move(h)); + this->m_updated = h.m_updated; + } + return *this; +} + + +//************************************************************************ +// Dereference. +// + + +/** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + * + * This will inform Hive that the object has been modified. + */ +template <class T> +inline +typename UpdateHandle<T>::pointer_type +UpdateHandle<T>::operator->() +{ + return checkedPtr(); +} + + +/** + * @brief Derefence the pointer. + * Throws ExcNullReadHandle on failure. + * + * This will inform Hive that the object has been modified. + */ +template <class T> +inline +typename UpdateHandle<T>::reference_type UpdateHandle<T>::operator*() +{ + return *checkedPtr(); +} + + +/** + * @brief Derefence the pointer. + * Returns nullptr on failure. + * + * This will _not_ inform Hive that the object has been modified. + */ +template <class T> +inline +typename UpdateHandle<T>::const_pointer_type UpdateHandle<T>::cptr() +{ + return reinterpret_cast<const_pointer_type>(this->typeless_cptr()); +} + + +/** + * @brief Derefence the pointer. + * Returns nullptr on failure. + * + * This will inform Hive that the object has been modified. + */ +template <class T> +typename UpdateHandle<T>::pointer_type +UpdateHandle<T>::ptr() +{ + pointer_type ptr = reinterpret_cast<pointer_type>(this->typeless_ptr()); + if (ptr && !m_updated && m_store) { + if (m_store->updatedObject (this->clid(), this->name()).isFailure()) + SG::throwExcUpdatedObjectFailure (clid(), name(), store()); + m_updated = true; + } + return ptr; +} + + +/** + * @brief Return the cached pointer directly; no lookup. + */ +template <class T> +inline +typename UpdateHandle<T>::pointer_type +UpdateHandle<T>::cachedPtr() const +{ + return reinterpret_cast<pointer_type>(this->m_ptr); +} + + +/** + * @brief Can the handle be successfully dereferenced? + */ +template <class T> +inline +bool UpdateHandle<T>::isValid() +{ + const bool QUIET=true; + if (0 != this->typeless_dataPointer(QUIET)) + return !isConst(); + return false; +} + + +/** + * @brief Reset this handle. + * @param hard If true, anything depending on the event store is cleared. + * + * Clear the updated flag, then call reset() from the base class. + */ +template <class T> +void UpdateHandle<T>::reset (bool hard) +{ + m_updated = false; + VarHandleBase::reset (hard); +} + + +/** + * @brief Helper: dereference the pointer. + * Throws ExcNullUpdateHandle on failure. + */ +template <class T> +inline +typename UpdateHandle<T>::pointer_type +UpdateHandle<T>::checkedPtr() +{ + pointer_type p = this->ptr(); + if (!p) + throwExcNullUpdateHandle (clid(), key(), store()); + return p; +} + + +/** + * @brief Return an @c UpdateHandle referencing @c key. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +UpdateHandle<T> makeHandle (const UpdateHandleKey<T>& key) +{ + return UpdateHandle<T> (key); +} + + +/** + * @brief Return an @c UpdateHandle referencing @c key for an explicit context. + * @param key The key object holding the clid/key/store. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +UpdateHandle<T> makeHandle (const UpdateHandleKey<T>& key, + const EventContext& ctx) +{ + return UpdateHandle<T> (key, ctx); +} + + +} /* namespace SG */ + + +#endif //> !STOREGATE_SG_UPDATEHANDLE_ICC diff --git a/EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.h new file mode 100644 index 00000000..a89c1d18 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.h @@ -0,0 +1,73 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/UpdateHandleKey.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Property holding a SG store/key/clid from which an UpdateHandle is made. + */ + + +#ifndef STOREGATE_UPDATEHANDLEKEY_H +#define STOREGATE_UPDATEHANDLEKEY_H + + +#include "StoreGate/VarHandleKey.h" +#include "SGTools/CLASS_DEF.h" + + +namespace SG { + + +/** + * @brief Property holding a SG store/key/clid from which an UpdateHandle is made. + * + * This class holds the key part of an UpdateHandle. For a reentrant algorithm, + * you would use this as the algorithm property and construct the actual + * ReadHandle on the stack from this key object (and optionally the event + * context). + * + * See VarHandleKey for more details. + */ +template <class T> +class UpdateHandleKey + : public VarHandleKey +{ +public: + /** + * @brief Constructor. + * @param key The StoreGate key for the object. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. + */ + UpdateHandleKey (const std::string& key = "", + const std::string& storeName = "StoreGateSvc"); + + + /** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. + */ + UpdateHandleKey& operator= (const std::string& sgkey); +}; + + +} // namespace SG + + +#include "StoreGate/UpdateHandleKey.icc" + + +#endif // not STOREGATE_UPDATEHANDLEKEY_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.icc b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.icc new file mode 100644 index 00000000..cd6838f1 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/UpdateHandleKey.icc @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/UpdateHandleKey.icc + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Property holding a SG store/key/clid from which an UpdateHandle is made. + */ + + +namespace SG { + + +/** + * @brief Constructor. + * @param key The StoreGate key for the object. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. + */ +template <class T> +UpdateHandleKey<T>::UpdateHandleKey (const std::string& key /*= ""*/, + const std::string& storeName /*= "StoreGateSvc"*/) + : VarHandleKey (ClassID_traits<T>::ID(), key, + Gaudi::DataHandle::Updater, + storeName) +{ +} + + +/** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. + */ +template <class T> +UpdateHandleKey<T>& UpdateHandleKey<T>::operator= (const std::string& sgkey) +{ + VarHandleKey::operator= (sgkey); + return *this; +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.h b/EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.h new file mode 100644 index 00000000..560ecb30 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.h @@ -0,0 +1,449 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: VarHandleBase.h 757253 2016-06-23 13:01:18Z ssnyder $ +/** + * @file StoreGate/VarHandleBase.h + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Base class for VarHandle classes. + */ + +#ifndef STOREGATE_SG_VARHANDLEBASE_H +#define STOREGATE_SG_VARHANDLEBASE_H 1 + +// STL includes +#include <string> + +#include "StoreGate/VarHandleKey.h" + +// fwk includes +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IResetable.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/EventContext.h" + +// SGTools includes +#include "SGTools/DataProxy.h" +#include "SGTools/ProxyMap.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/BuiltinsClids.h" +#include "SGTools/StlVectorClids.h" +#include "SGTools/StlMapClids.h" + +namespace Athena_test { + void varHandleTest(void); + void resetableTest(void); + void refCountTest(void); +} +namespace SG { +#ifdef NDEBUG + const bool defaultQuiet = true; +#else + const bool defaultQuiet = false; +#endif + + + /** + * @class SG::VarHandleBase + * @brief Base class for VarHandle types. + * + * This is the base class for smart pointer types used to access objects + * in an @c IProxyDict (such as a StoreGateSvc). The handle types + * @c ReadHandle, @c WriteHandle, and @c UpdateHandle derive from this; + * see those classes for usage information. + * + * This class derives from @c VarHandleKey, which holds the CLID of the class + * we're referencing (which gets passed to the constructor of this class + * from the templated derived classes), the StoreGate key of the object + * we're referencing, and a handle to the event store. In this class, we + * keep a pointer to the actual event store being used + * (may be thread-dependent), a pointer to the @c DataProxy for the + * referenced object, and a cached pointer to the object itself. + * + * A handle object may be used as a algorithm/tool property directly. + * Because the handle caches state, however, this means that the component + * using it cannot be reentrant. In such a case, the handle will be reset + * when the current algorithm completes. + * + * The preferred way of using handles is to use a HandleKey object + * (one of ReadHandleKey<T>, WriteHandleKey<T>, UpdateHandleKey<T>) + * as the property, and to create a handle instance on the stack from + * the key object (and the event context, if available). + */ + class VarHandleBase : public VarHandleKey, public IResetable + { + // For testing. + friend void Athena_test::varHandleTest(void); + friend void Athena_test::resetableTest(void); + friend void Athena_test::refCountTest(void); + friend std::ostream& operator<<( std::ostream&, const VarHandleBase&); + + public: + /** + * @brief Constructor with default key. + * @param clid CLID of the referenced class. + * @param mode Mode of this handle (read/write/update). + */ + explicit VarHandleBase(CLID clid, Gaudi::DataHandle::Mode mode); + + + /** + * @brief Constructor with full arguments. + * @param clid CLID of the referenced class. + * @param sgkey StoreGate key of the referenced object. + * @param mode Mode of this handle (read/write/update). + * @param storename Name of the referenced event store. + */ + explicit VarHandleBase(CLID clid, + const std::string& sgkey, + Gaudi::DataHandle::Mode mode, + const std::string& storename = "StoreGateSvc"); + + + /** + * @brief Constructor from a VarHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ + explicit VarHandleBase (const VarHandleKey& key); + + + /** + * @brief Constructor from a VarHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The current event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ + explicit VarHandleBase (const VarHandleKey& key, const EventContext& ctx); + + + /** + * @brief Copy constructor. + */ + VarHandleBase( const VarHandleBase& rhs ); + + + /** + * @brief Move constructor. + */ + VarHandleBase( VarHandleBase&& rhs ); + + + /** + * @brief Assignment operator. + */ + VarHandleBase& operator=( const VarHandleBase& rhs ); + + + /** + * @brief Move operator. + */ + VarHandleBase& operator=( VarHandleBase&& rhs ); + + + /** + * @brief Destructor. + */ + virtual ~VarHandleBase() override; + + + //************************************************************************* + // Accessors + // + // Inherited from VarHandleKey: + // CLID clid() const; + // ServiceHandle<IProxyDict> storeHandle() const; + + + /** + * @brief Return the StoreGate ID for the referenced object. + * + * This is defined in @c VarHandleKey. We need to redefine it here because + * it's also in @c IResetable. (Otherwise there would be an ambiguity.) + */ + virtual const std::string& key() const override final; + + + /** + * @brief Return the StoreGate ID for the referenced object. + * + * A synonym for key(). + */ + const std::string& name() const ; + + + /** + * @brief Return the name of the store holding the object we are proxying. + */ + std::string store() const; + + + //************************************************************************* + // Validity checking. + // + + + /** + * @brief Can the handle be successfully dereferenced? + * + * Non-const method; the handle may cache information as a result of this. + */ + virtual bool isValid() = 0; + + + /** + * @brief Is the referenced object present in SG? + * + * Const method; the handle does not change as a result of this. + */ + bool isPresent() const; + + + /** + * @brief Has a proxy been retrieved from SG? + * + * (Weaker test than @c isValid, but does not touch the disk.) + */ + bool isInitialized() const; + + + /** + * @brief Has a proxy been retrieved from SG? + * + * Same as @c isInitialized; this is an interface required by @c IResetable. + */ + virtual bool isSet() const override final; + + + /** + * @brief True if this handle has a proxy, and the proxy is const. + * + * Refers to the state of the proxy, not of the handle. + */ + bool isConst() const; + + + /** + * @brief Retrieve and cache all information managed by a handle. + * + * This will retrieve and cache the associated @c DataProxy. + * + * Note for the case of a WriteHandle that has not yet been written to, + * the proxy may not exist. We return Success in that case; however, + * @c isInitialized will still return false. + */ + StatusCode initialize(); + + + /** + * @brief Retrieve and cache all information managed by a handle. + * + * Synonym for initialize(). + */ + StatusCode setState(); + + + //************************************************************************* + // State setting. + // + + + /** + * @brief Explicitly set the event store. + * @param store The new event store. + * + * This implicitly does a reset(). + */ + StatusCode setProxyDict (IProxyDict* store); + + + // FIXME: Remove this once IResetable is cleaned up. + using IResetable::reset; + + + /** + * @brief Reset this handle. + * @param hard If true, anything depending on the event store is cleared. + * + * If the handle stays associated with a given event store, then hard=false. + * In that case, we clear the cached pointer; the proxy is also dropped + * if it is reset only. If hard=true, then we always drop the proxy and + * in addition clear the cached pointer to the event store. + */ + virtual void reset (bool hard) override; + + + /** + * @brief Reset this handle at the end of processing. + * @brief hard If true, anything depending on the event store is cleared. + * + * Same as reset(true); + */ + virtual void finalReset() override final; + + + /** + * @brief Set the 'const' bit for the bound proxy in the store. + */ + StatusCode setConst(); + + protected: + //************************************************************************* + // Protected methods. + // + + + /** + * @brief Set the state of the handle to a given proxy. + * @param proxy The proxy to set. + * + * The proxy must be valid; otherwise FAILURE will be returned. + */ + StatusCode setState(SG::DataProxy* proxy); + + + /** + * @brief Set the state of a handle from a store and a key name. + * @param store The event store to access. + * @param name The StoreGate key to search for. + * + * Fails if no such object is recorded. + */ + StatusCode setState(IProxyDict* store, const std::string& name); + + + /** + * @brief Helper to record an object in the event store. + * @param The wrapped data object (DataBucket) to record. + * @param dataPtr Pointer to the transient object itself. + * @param allowMods If false, record the object as const. + * @param returnExisting Allow an existing object. + * + * If there is already an existing object with our key, then return + * failure, unless @c returnExisting is true, in which case + * return success. In either case, @c dobj is destroyed. + */ + StatusCode record_impl (std::unique_ptr<DataObject> dobj, + void* dataPtr, + bool allowMods, + bool returnExisting); + + + /** + * @brief Retrieve an object from StoreGate. + * @param quiet If true, suppress failure messages. + */ + void* typeless_dataPointer_impl(bool quiet); + + + /** + * @brief Retrieve an object from StoreGate. + * @param quiet If true, suppress failure messages. + * + * Inline method: first check cached pointer, then call the _impl method. + */ + void* typeless_dataPointer(bool quiet=defaultQuiet); + + + /** + * @brief Retrieve an object from StoreGate as a const pointer. + * + * Same as typeless_dataPointer with the return value converted to const. + */ + const void* typeless_cptr(); + const void* typeless_cptr(bool quiet); + + + /** + * @brief Retrieve an object from StoreGate as non-const pointer. + * + * Calls typeless_dataPointer, then raises an exception if the + * proxy is marked as const. + */ + void* typeless_ptr(bool quiet=defaultQuiet); + + + protected: + //************************************************************************* + // Protected data. + // + + /// The object to which we are bound. + void* m_ptr; + + /// Proxy holding the object to which we are bound. + SG::DataProxy* m_proxy; + + /// Pointer to the store that owns the object. + IProxyDict* m_store; + + + private: + /** + * @brief Initialize the store pointer from the store handle. + * Also checks that the key is valid. + */ + StatusCode storeFromHandle(); + + + /** + * @brief Clear the m_proxy field and release the old proxy. + */ + void resetProxy(); + + + /** + * @brief Set a new proxy. Release any old one first. + * @param proxy The new proxy. + */ + void setProxy (SG::DataProxy* proxy); + }; + + + //************************************************************************* + // Free functions. + // + + + /** + * @brief Output stream. + * @param out Stream to which to write. + * @parma o Object to write. + */ + std::ostream& operator<<( std::ostream& out, const VarHandleBase& o ); + + + /** + * @brief Equality comparison. + */ + bool operator==(const VarHandleBase& l, const VarHandleBase& r); + + + /** + * @brief Inequality comparison. + */ + bool operator!=(const VarHandleBase& l, const VarHandleBase& r); + + +} /* namespace SG */ + +// For the ConditionHandles +#include "SGTools/CLASS_DEF.h" +#include "AthenaKernel/CondCont.h" +CLASS_DEF( CondContBase , 34480459 , 1 ) + +#include "StoreGate/VarHandleBase.icc" + + +#endif //> !STOREGATE_SG_VARHANDLEBASE_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.icc b/EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.icc new file mode 100644 index 00000000..62ba2873 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleBase.icc @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/VarHandleBase.icc + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Property holding a SG store/key/clid from which a WriteHandle is made. + */ + + +namespace SG { + + +/** + * @brief Retrieve an object from StoreGate. + * @param quiet If true, suppress failure messages. + * + * Inline method: first check cached pointer, then call the _impl method. + */ +inline +void* VarHandleBase::typeless_dataPointer(bool quiet/*=defaultQuiet*/) +{ + if (m_ptr) { return m_ptr; } + return typeless_dataPointer_impl(quiet); +} + + +/** + * @brief Retrieve an object from StoreGate as a const pointer. + * + * Same as typeless_dataPointer with the return value converted to const. + */ +inline +const void* VarHandleBase::typeless_cptr() +{ + return typeless_dataPointer(); +} +inline +const void* VarHandleBase::typeless_cptr(bool quiet) +{ + return typeless_dataPointer (quiet); +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKey.h new file mode 100644 index 00000000..9b084d72 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKey.h @@ -0,0 +1,166 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/VarHandleKey.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief A property holding a SG store/key/clid from which a VarHandle is made. + */ + + +#ifndef STOREGATE_VARHANDLEKEY_H +#define STOREGATE_VARHANDLEKEY_H + + +#include "AthenaKernel/IProxyDict.h" +#include "GaudiKernel/DataHandle.h" +#include "GaudiKernel/ServiceHandle.h" + + +namespace SG { + + +/** + * @brief A property holding a SG store/key/clid from which a VarHandle is made. + * + * This class holds the key part of a VarHandle. This consists of a handle + * to the referenced store, the CLID, and the StoreGate key. The VarHandle + * classes derived from this. However, the VarHandle classes cache information + * about the referenced object, so they can't be used as members of a + * reentrant algorithm. Instead, we define separate key classes deriving + * from this that can be used as properties of algorithms or tools. + * A VarHandle can then be constructed from the key object and (optionally) + * an event context object. + * + * The classes @c WriteHandleKey, @c ReadHandleKey, and @c UpdateHandleKey + * derive from this. + * + * The actual StoreGate key is stored in the base @c DataHandle object. + * A reference to the store is saved in this class. + * + * The string for the key property can optionally be prefixed with the store + * name, separated by a slash: "MyStore/Obj". (However, if the key name + * starts with a slash, it is interpreted as a hierarchical key name, + * not an empty store name.) + */ +class VarHandleKey + : public Gaudi::DataHandle +{ +public: + /** + * @brief Constructor. + * @param clid The class ID for the referenced object. + * @param sgkey The StoreGate key for the object. + * @param a Mode: read/write/update. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. However, if the key name + * starts with a slash, it is interpreted as a hierarchical key name, + * not an empty store name. + * + * A SG::ExcBadHandleKey exception will the thrown if the key string + * format is bad. + */ + VarHandleKey (CLID clid, + const std::string& sgkey, + Gaudi::DataHandle::Mode a, + const std::string& storeName = "StoreGateSvc"); + + + /** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. A key name that starts with a slash + * is interpreted as a hierarchical key name, not an empty store name. + * + * A SG::ExcBadHandleKey exception will the thrown if the key string + * format is bad. + */ + VarHandleKey& operator= (const std::string& sgkey); + + + /** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store is not changed. A key name that starts with a slash + * is interpreted as a hierarchical key name, not an empty store name. + * + * Returns failure the key string format is bad. + */ + StatusCode assign (const std::string& sgkey); + + + /** + * @brief If this object is used as a property, then this should be called + * during the initialize phase. It will fail if the requested StoreGate + * service cannot be found or if the key is blank. + */ + StatusCode initialize(); + + + /** + * @brief Return the class ID for the referenced object. + */ + CLID clid() const; + + + /** + * @brief Return the StoreGate ID for the referenced object. + */ + const std::string& key() const; + + + /** + * @brief Return handle to the referenced store. + */ + ServiceHandle<IProxyDict> storeHandle() const; + + +private: + /// Don't allow calling these. + virtual void setKey(const DataObjID& key) override final; + virtual void updateKey(const std::string& key) override final; + + + /** + * @brief Handle assignment/construction from a string key. + * @param sgkey The StoreGate key for the referenced object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store named by @c storeName is used. A key name that starts + * with a slash is interpreted as a hierarchical key name, + * not an empty store name. + */ + StatusCode parseKey (const std::string& sgkey, const std::string& storeName); + + + /** + * @brief Update the name of the store to which we're referring. + * @param name The new store name. + */ + void updateHandle (const std::string& name); + + + /// Handle to the referenced store. + ServiceHandle<IProxyDict> m_storeHandle; +}; + + +} // namespace SG + + +#endif // not STOREGATE_VARHANDLEKEY_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.h b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.h new file mode 100644 index 00000000..3616da01 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.h @@ -0,0 +1,116 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_VARHANDLEKEYARRAY_H +#define STOREGATE_VARHANDLEKEYARRAY_H 1 + +/** + * @file StoreGate/VarHandleKeyArray.h + * @author C. Leggett + * @date Updated: Jun 17, 2016 + * @brief Base class for VarHandleKeyArray for reading from StoreGate. + */ + +#include "GaudiKernel/DataHandle.h" +#include "StoreGate/VarHandleKey.h" + +#include <vector> +#include <string> + +namespace SG { + + /** + * @class SG::VarHandleKeyArray<T> + * @brief untemplated base class for VarHandleKeyArrays + */ + class VarHandleKeyArray { + public: + VarHandleKeyArray(){}; + virtual ~VarHandleKeyArray(){}; + virtual StatusCode assign(const std::vector<std::string>& vs)=0; + virtual std::string toString() const = 0; + virtual Gaudi::DataHandle::Mode mode() const = 0; + + virtual std::vector<SG::VarHandleKey*> keys() const = 0; + + }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +// mixin class for common functionality +// + + /** + * @class SG::VarHandleKeyArrayCommon<T> + * @brief mixin base class for VarHandleKeyArrays, inheriting from + * std::vector as well as VarHandleKeyArray to provide vector-like + * access + * + */ + + template <class Base> + class VarHandleKeyArrayCommon : public VarHandleKeyArray, + public std::vector<Base> { + public: + /** + * @brief default base Constructor of mixin + * + */ + VarHandleKeyArrayCommon() : std::vector<Base>() {}; + + /** + * @brief base Constructor from a VarHandleKeyArray that takes a vector + * @param v vector of Read/Write/UpdateHandleKey + */ + VarHandleKeyArrayCommon( const std::vector<Base>& v ): + std::vector<Base>(v) {}; + + /** + * @brief base Constructor from a VarHandleKeyArray that takes an + * initializer list of VarHandleKeys + * @param l initializer list of Read/Write/UpdateHandleKey + */ + VarHandleKeyArrayCommon( std::initializer_list<Base> l ): + std::vector<Base>{l} {}; + + /** + * @brief base Constructor from a VarHandleKeyArray that takes an + * initializer list of std::strings. + * @param l initializer list of std::strings used to create the + * VarHandleKeys + */ + VarHandleKeyArrayCommon( std::initializer_list<std::string> l ) { + for (auto &e : l) { + this->push_back( Base{e} ); + } + } + + /** + * @brief forward the initialization to the member VarHandleKeys + */ + StatusCode initialize(); + + /** + * @brief Set the contents of the VarHandleKeyArray from a + * vector of std::strings + * @param vs vector of initializer strings + */ + StatusCode assign(const std::vector<std::string>& vs); + + /** + * @brief string representation of the VarHandleKeyArray + */ + std::string toString() const; + + /** + * @brief create array of all base VarHandleKeys in the Array + */ + std::vector<SG::VarHandleKey*> keys() const; + + }; + +} // namespace SG + +#include "StoreGate/VarHandleKeyArray.icc" + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.icc b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.icc new file mode 100644 index 00000000..9dd049ce --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArray.icc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +namespace SG { + // + // Forward the initialization to the member VarHandleKeys + // + template <class Base> + inline + StatusCode VarHandleKeyArrayCommon<Base>::initialize() { + StatusCode sc(StatusCode::SUCCESS); + typename std::vector<Base>::iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + if (! itr->initialize() ) { + sc = StatusCode::FAILURE; + } + } + return sc; + } + + // + // Set the VarHandleKey from a string + // + template <class Base> + inline + StatusCode VarHandleKeyArrayCommon<Base>::assign(const std::vector<std::string>& vs) { + StatusCode sc(StatusCode::SUCCESS); + this->clear(); + for (auto & s : vs) { + Base b; + if (!b.assign(s)) { + sc = StatusCode::FAILURE; + } else { + // Skip blank keys + if (b.key() != "") { + this->push_back(b); + } + } + } + return sc; + } + + // + // string representation of VarHandleKeyArray + // + template <class Base> + inline + std::string VarHandleKeyArrayCommon<Base>::toString() const { + std::ostringstream ost; + typename std::vector<Base>::const_iterator itr; + itr = this->begin(); + size_t sz = this->size(); + for ( size_t i=0; i < sz; ++i, ++itr) { + ost << "'" << itr->storeHandle().name() << "/" + << itr->objKey() << "'"; + if (i != sz-1) { + ost << ","; + } + } + return ost.str(); + } + + // + // create array of all base VarHandleKeys in the Array + // + template <class Base> + inline + std::vector<SG::VarHandleKey*> VarHandleKeyArrayCommon<Base>::keys() const { + std::vector<SG::VarHandleKey*> keys; + typename std::vector<Base>::const_iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + SG::VarHandleKey* vk = + const_cast<SG::VarHandleKey*>( (const SG::VarHandleKey*) &(*itr) ); + keys.push_back( vk ); + } + return keys; + } + +} diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h new file mode 100644 index 00000000..eaa86d68 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyArrayProperty.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_VARHANDLEKEYARRAYPROPERTY +#define STOREGATE_VARHANDLEKEYARRAYPROPERTY 1 + +/** + * @file StoreGate/VarHandleKeyArrayProperty.h + * @author C. Leggett + * @date Updated: Jun 17, 2016 + * @brief class to handle Properties for VarHandleKeyArray + */ + +#include "StoreGate/VarHandleKeyArray.h" +#include "StoreGate/ReadHandleKeyArray.h" +#include "StoreGate/WriteHandleKeyArray.h" +#include "GaudiKernel/Property.h" +#include <iostream> + +namespace Gaudi { + namespace Parsers { + GAUDI_API + StatusCode parse(SG::VarHandleKeyArray& v, const std::string& s); + } + + namespace Utils { + GAUDI_API + std::ostream& toStream(const SG::VarHandleKeyArray& v, std::ostream& o); + } +} + +namespace SG { + + class GAUDI_API VarHandleKeyArrayProperty + : public ::Property + { + public: + + VarHandleKeyArrayProperty( const std::string& name, + SG::VarHandleKeyArray& ref ); + + VarHandleKeyArrayProperty& operator=( const SG::VarHandleKeyArray& value ); + + virtual VarHandleKeyArrayProperty* clone() const override; + + virtual bool load( Property& destination ) const override; + + virtual bool assign( const Property& source ) override; + + virtual std::string toString() const override; + + virtual void toStream(std::ostream& out) const override; + + virtual StatusCode fromString(const std::string& s) override; + + const SG::VarHandleKeyArray& value() const; + + bool setValue( const SG::VarHandleKeyArray& value ); + + + private: + /** Pointer to the real property. Reference would be better, + * but Reflex does not support references yet + */ + SG::VarHandleKeyArray* m_pValue; + }; + + +} // namespace SG + +template<> +class SimplePropertyRef< SG::VarHandleKeyArray > : + public SG::VarHandleKeyArrayProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::VarHandleKeyArray& value) : + SG::VarHandleKeyArrayProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::ReadHandleKeyArray<T> > : + public SG::VarHandleKeyArrayProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::ReadHandleKeyArray<T>& value) : + SG::VarHandleKeyArrayProperty(name, value) {} +}; + +template<typename T> +class SimplePropertyRef< SG::WriteHandleKeyArray<T> > : + public SG::VarHandleKeyArrayProperty +{ +public: + SimplePropertyRef( const std::string& name, + SG::WriteHandleKeyArray<T>& value ) : + SG::VarHandleKeyArrayProperty(name, value) {} +}; + + + + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyProperty.h b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyProperty.h new file mode 100644 index 00000000..29acbe84 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleKeyProperty.h @@ -0,0 +1,239 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/VarHandleKeyProperty.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Handle Gaudi property setting for VarHandleKey. + * + * Gaudi property handling can be extended for a new type T by specializing + * SimplePropertyRef<T> to be something that derives from Property. + * This class will then handle conversions of T to and from strings. + */ + + +#ifndef STOREGATE_VARHANDLEKEYPROPERTY_H +#define STOREGATE_VARHANDLEKEYPROPERTY_H + + +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/ReadCondHandleKey.h" +#include "StoreGate/WriteHandleKey.h" +#include "StoreGate/WriteCondHandleKey.h" +#include "StoreGate/UpdateHandleKey.h" +#include "GaudiKernel/Property.h" +#include <iostream> + +namespace Gaudi { +namespace Parsers { + + +/** + * @brief Gaudi function used to initialize a property from a string. + * @param v The object to initialize. + * @param s The string from which to initialize. + * + * Used during Gaudi property handling to set object @c v from the string @c s. + * Note that @c s is a representation of the property setting; thus, in the + * case of setting a property from a string, @c s will contain quote marks. + */ +GAUDI_API +StatusCode parse(SG::VarHandleKey& v, const std::string& s); + +} //> ns Parsers + +namespace Utils { + + +/** + * @brief Gaudi function used to convert a property to a string. + * @param v The object to convert. + * @param o Stream to which to do the conversion. + * + * Used during Gaudi property handling to get a string representation of @c v. + * Note that if the representation is a string, it should be surrounded + * by quote marks. + */ +GAUDI_API +std::ostream& toStream(const SG::VarHandleKey& v, std::ostream& o); + +} //> ns Utils +} //> ns Gaudi + + +namespace SG { + + +/** + * @brief VarHandleKeyProperty is the class which wraps a @c SG::VarHandleKey. + * + * The Property object refers to an instance of @c SG::VarHandleKey + * (the value object) and provides generic methods for manipulating it. + */ +class GAUDI_API VarHandleKeyProperty + : public ::Property +{ +public: + + /** + * @brief Constructor with parameters. + * @param name Name of the property. + * @param ref Object which this property is setting (the value object). + */ + VarHandleKeyProperty( const std::string& name, SG::VarHandleKey& ref ); + + + /** + * @brief Assignment operator. + * @param value Value from which to assign. + * + * Copy the value object which we control from another value object. + */ + VarHandleKeyProperty& operator=( const SG::VarHandleKey& value ); + + + /** + * @brief Return a new copy of this Property object. + * + * The new object will be associated with the _same_ value object + * as the original. + */ + virtual VarHandleKeyProperty* clone() const override; + + + /** + * @brief Set the value of another Property. + * @param destination The Property whose value is changed. + * + * The value object of this Property is copied to that of @c destination + * by converting to a string and back again. Returns true on success, + * false on failure. + */ + virtual bool load( Property& destination ) const override; + + + /** + * @brief Set the value of this Property from another. + * @param destination The Property from which the value should be copied. + * + * The value object of this @c source is copied to that of this Property + * by converting to a string and back again. Returns true on success, + * false on failure. + */ + virtual bool assign( const Property& source ) override; + + + /** + * @brief Return a string representation of the value object. + */ + virtual std::string toString() const override; + + + /** + * @brief Write a string representation of the value object to a stream. + * @param out Stream to which to write. + */ + virtual void toStream(std::ostream& out) const override; + + + /** + * @brief Set this value object from a string. + * @param s String from which to initialize the value. + * + * Returns failure if the conversion does not succeed. + */ + virtual StatusCode fromString(const std::string& s) override; + + + /** + * @brief Return the value object for this Property. + */ + const SG::VarHandleKey& value() const; + + + /** + * @brief Set the value object for this Property. + * @param value Value from which to copy. + * + * Return true on success; false if the update handler failed. + */ + bool setValue( const SG::VarHandleKey& value ); + + +private: + /** Pointer to the real property. Reference would be better, + * but Reflex does not support references yet + */ + SG::VarHandleKey* m_pValue; +}; + + +} // namespace SG + + +// ** Specializations of SimplePropertyRef for the HandleKey classes. + +template<> +class SimplePropertyRef< SG::VarHandleKey > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::VarHandleKey& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::ReadHandleKey<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::ReadHandleKey<T>& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + +template<typename T> +class SimplePropertyRef< SG::ReadCondHandleKey<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::ReadCondHandleKey<T>& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::UpdateHandleKey<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef( const std::string& name, SG::UpdateHandleKey<T>& value ) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::WriteHandleKey<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef( const std::string& name, SG::WriteHandleKey<T>& value ) : + SG::VarHandleKeyProperty(name, value) {} +}; + +template<typename T> +class SimplePropertyRef< SG::WriteCondHandleKey<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef( const std::string& name, SG::WriteCondHandleKey<T>& value ) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +#endif // not STOREGATE_VARHANDLEKEYPROPERTY_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/VarHandleProperty.h b/EDM/athena/Control/StoreGate/StoreGate/VarHandleProperty.h new file mode 100644 index 00000000..ff7155d2 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/VarHandleProperty.h @@ -0,0 +1,84 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// VarHandleProperty.h +// Header file for class VarHandleProperty +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef STOREGATE_VARHANDLEPROPERTY_H +#define STOREGATE_VARHANDLEPROPERTY_H 1 + +#include "StoreGate/VarHandleKeyProperty.h" +#include "StoreGate/ReadHandle.h" +#include "StoreGate/WriteHandle.h" +#include "StoreGate/UpdateHandle.h" + +#include "StoreGate/ReadCondHandle.h" +#include "StoreGate/WriteCondHandle.h" + + +// ** Specializations of SimplePropertyRef for the VarHandle classes. + +template<> +class SimplePropertyRef< SG::VarHandleBase > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::VarHandleBase& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::ReadHandle<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::ReadHandle<T>& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::UpdateHandle<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef( const std::string& name, SG::UpdateHandle<T>& value ) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +template<typename T> +class SimplePropertyRef< SG::WriteHandle<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef( const std::string& name, SG::WriteHandle<T>& value ) : + SG::VarHandleKeyProperty(name, value) {} +}; + +template<typename T> +class SimplePropertyRef< SG::ReadCondHandle<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::ReadCondHandle<T>& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + +template<typename T> +class SimplePropertyRef< SG::WriteCondHandle<T> > : + public SG::VarHandleKeyProperty +{ +public: + SimplePropertyRef(const std::string& name, SG::WriteCondHandle<T>& value) : + SG::VarHandleKeyProperty(name, value) {} +}; + + +#endif /* !STOREGATE_VARHANDLEPROPERTY_H */ + diff --git a/EDM/athena/Control/StoreGate/StoreGate/WVar.h b/EDM/athena/Control/StoreGate/StoreGate/WVar.h new file mode 100644 index 00000000..a66c3b75 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WVar.h @@ -0,0 +1,11 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_SG_WVAR_H +#define STOREGATE_SG_WVAR_H 1 + +#warning "WVar is obsolete, please use WriteHandle" + +#include "StoreGate/WriteHandle.h" +#endif //> !STOREGATE_SG_WVAR_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteCondHandle.h b/EDM/athena/Control/StoreGate/StoreGate/WriteCondHandle.h new file mode 100644 index 00000000..742d1c96 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteCondHandle.h @@ -0,0 +1,151 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_WRITECONDHANDLE_H +#define STOREGATE_WRITECONDHANDLE_H 1 + +#include "AthenaKernel/CondCont.h" +#include "AthenaKernel/getMessageSvc.h" + +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/VarHandleBase.h" +#include "StoreGate/WriteCondHandleKey.h" + +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/DataHandle.h" +#include "GaudiKernel/DataObjID.h" +#include "GaudiKernel/EventIDBase.h" + +#include <string> +#include <stdexcept> + +namespace SG { + + template <typename T> + class WriteCondHandle : public SG::VarHandleBase { + + public: + typedef T* pointer_type; // FIXME: better handling of + typedef const T* const_pointer_type; // qualified T type ? + typedef T& reference_type; + typedef const T& const_reference_type; + + public: + WriteCondHandle(const WriteCondHandleKey<T>& key); + WriteCondHandle(const WriteCondHandleKey<T>& key, const EventContext& ctx); + + virtual ~WriteCondHandle() override {}; + + virtual bool isValid() override; + bool isValid(const EventIDBase& t) const; + + StatusCode record(const EventIDRange& range, T* t); + void updateStore(); + + const std::string& dbKey() const { return m_hkey.dbKey(); } + + private: + + const EventIDBase& m_eid; + CondCont<T>* m_cc {nullptr}; + StoreGateSvc* m_cs {nullptr}; + + const SG::WriteCondHandleKey<T>& m_hkey; + + }; + + + //--------------------------------------------------------------------------- + + template <typename T> + WriteCondHandle<T>::WriteCondHandle( const SG::WriteCondHandleKey<T>& key ) : + WriteCondHandle( key, Gaudi::Hive::currentContext() ) {} + + //--------------------------------------------------------------------------- + + template <typename T> + WriteCondHandle<T>::WriteCondHandle( const SG::WriteCondHandleKey<T>& key, + const EventContext& ctx) : + SG::VarHandleBase( key, ctx ), + m_eid(ctx.eventID()), + m_cc( key.getCC() ), + m_cs( key.getCS() ), + m_hkey(key) + { + if (m_cc == 0) { + MsgStream msg(Athena::getMessageSvc(), "WriteCondHandle"); + msg << MSG::ERROR + << "WriteCondHandle : ptr to CondCont<T> is zero" + << endmsg; + } + + if (! m_hkey.isInit()) { + MsgStream msg(Athena::getMessageSvc(), "WriteCondHandle"); + msg << MSG::ERROR + << "WriteCondHandleKey " << key.objKey() << " was not initialized" + << endmsg; + throw std::runtime_error("WriteCondHandle: WriteCondHandleKey was not initialized"); + + } + + } + + + //--------------------------------------------------------------------------- + + template <typename T> + StatusCode + WriteCondHandle<T>::record(const EventIDRange& r, T* t) { + + if (!m_cc->insert(r, t)) { + MsgStream msg(Athena::getMessageSvc(), "WriteCondHandle"); + msg << MSG::ERROR + << "WriteCondHandle::record() : unable to insert obj in CondCont<T>" + << endmsg; + return StatusCode::FAILURE; + } + + + MsgStream msg(Athena::getMessageSvc(), "WriteCondHandle"); + msg << MSG::DEBUG + << "WriteCondHandle::record() : obj at: " << t << " range: " << r + << endmsg; + + updateStore(); + + return StatusCode::SUCCESS; + } + + //--------------------------------------------------------------------------- + + template <typename T> + void + WriteCondHandle<T>::updateStore() { + m_cs->addedNewTransObject( fullKey().clid(), fullKey().key() ); + } + + + //--------------------------------------------------------------------------- + + template <typename T> + bool + WriteCondHandle<T>::isValid(const EventIDBase& t) const { + + return (m_cc->valid(t)); + } + + + //--------------------------------------------------------------------------- + + template <typename T> + bool + WriteCondHandle<T>::isValid() { + + return (m_cc->valid(m_eid)); + } + +} + +#endif + diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteCondHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/WriteCondHandleKey.h new file mode 100644 index 00000000..05ef4865 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteCondHandleKey.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_WRITECONDHANDLEKEY_H +#define STOREGATE_WRITECONDHANDLEKEY_H + + +#include "StoreGate/CondHandleKey.h" + + +namespace SG { + + template <class T> + class WriteCondHandle; + + template <class T> + class WriteCondHandleKey + : public CondHandleKey<T> + { + + friend class WriteCondHandle<T>; + + public: + WriteCondHandleKey(const std::string& key, const std::string& dbKey) : + CondHandleKey<T>(key, dbKey, Gaudi::DataHandle::Writer) + {} + + }; + +} // namespace SG + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteHandle.h b/EDM/athena/Control/StoreGate/StoreGate/WriteHandle.h new file mode 100644 index 00000000..84d99dcf --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteHandle.h @@ -0,0 +1,383 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: WriteHandle.h 756419 2016-06-21 02:02:43Z ssnyder $ +/** + * @file StoreGate/WriteHandle.h + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Handle class for recording to StoreGate. + */ + +#ifndef STOREGATE_SG_WRITEHANDLE_H +#define STOREGATE_SG_WRITEHANDLE_H 1 + + +#include "StoreGate/VarHandleBase.h" +#include "StoreGate/WriteHandleKey.h" +#include "StoreGate/StoreGateSvc.h" /* needed by clients */ +#include "GaudiKernel/EventContext.h" +#include <string> +#include <memory> /*unique_ptr*/ + + +namespace SG { + + +/** + * @class SG::WriteHandle<T> + * @brief A smart pointer to an object of a given type in an @c IProxyDict (such + * as StoreGateSvc). It d-casts and caches locally the pointed-at object, to + * speed-up subsequent accesses. + * It can be reset by the store for asynchronous updates (IOVSvc). + * + * @c SG::WriteHandle<T> can only create new objects in StoreGate; no proxy + * should already exist. This handle will only return the pointer that + * has been recorded. + * + * Usage example: + * @code + * class MyAlg : public AthAlgorithm + * { + * SG::WriteHandle<int> m_int; + * }; + * + * MyAlg::MyAlg(...) : ..., m_int("MyIntSgKey") { + * declareProperty("IntHandle", + * m_int = SG::WriteHandle<int>("MyIntSgKey"), + * "a handle to an int in StoreGate"); + * } + * + * StatusCode MyAlg::execute() + * { + * ATH_CHECK( m_int.record (CxxUtils::make_unique<int>(42)) ); + * ATH_MSG_INFO("int value @[" << m_int.name() << "]=" + * << *m_int); + * *m_int += 10; + * ATH_MSG_INFO("int value @[" << m_int.name() << "]=" + * << *m_int); + * return StatusCode::SUCCESS; + * } + * @endcode + * + * For more information have a look under the package + * Control/AthenaExamples/AthExHelloWorld + * + */ +template <class T> +class WriteHandle + : public SG::VarHandleBase +{ +public: + typedef T* pointer_type; // FIXME: better handling of + typedef const T* const_pointer_type; // qualified T type ? + typedef T& reference_type; + typedef const T& const_reference_type; + + + //************************************************************************ + // Constructors, etc. + // + + + /** + * @brief Default constructor. + * + * The handle will not be usable until a non-blank key is assigned. + */ + WriteHandle(); + + + /** + * @brief Constructor with full arguments. + * @param sgkey StoreGate key of the referenced object. + * @param storename Name of the referenced event store. + */ + explicit WriteHandle(const std::string& sgkey, + const std::string& storename = "StoreGateSvc"); + + + /** + * @brief Constructor from a WriteHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ + explicit WriteHandle (const WriteHandleKey<T>& key); + + + /** + * @brief Constructor from a WriteHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ + explicit WriteHandle (const WriteHandleKey<T>& key, const EventContext& ctx); + + + /** + * @brief Copy constructor. + */ + WriteHandle( const WriteHandle& rhs ); + + + /** + * @brief Move constructor. + */ + WriteHandle( WriteHandle&& rhs ); + + + /** + * @brief Assignment operator. + */ + WriteHandle& operator=( const WriteHandle& rhs ); + + + /** + * @brief Move operator. + */ + WriteHandle& operator=( WriteHandle&& rhs ); + + + /** + * @brief Destructor. + * + * Lock an aux object if m_lockAuxPending is set. + */ + ~WriteHandle(); + + + //************************************************************************ + // Deference. These all return only the cached pointer. + // + + + /** + * @brief Derefence the pointer. + * Returns the cached pointer. Throws ExcNullWriteHandle if null. + */ + pointer_type operator->() const; + + + /** + * @brief Derefence the pointer. + * Returns the cached pointer. Throws ExcNullWriteHandle if null. + */ + reference_type operator*() const; + + + /** + * @brief Dereference the pointer. + * Returns the cached pointer. + */ + const_pointer_type cptr() const; + + + /** + * @brief Dereference the pointer. + * Returns the cached pointer. + */ + pointer_type ptr() const; + + + /** + * @brief Return the cached pointer directly; no lookup. + */ + pointer_type cachedPtr() const; + + + /** + * @brief Can the handle be successfully dereferenced? + */ + virtual bool isValid() override final; + + + //************************************************************************ + // Record. + // + + + /** + * @brief Record a const object to the store. + * @param data The object to record. + */ + StatusCode record (std::unique_ptr<T> data); + + + /** + * @brief Record a non-const object to the store. + * @param data The object to record. + */ + StatusCode recordNonConst (std::unique_ptr<T> data); + + + /** + * @brief Record a const object and its auxiliary store to the store. + * @param data The object to record. + * @param auxstore Auxiliary store object. + */ + template <class AUXSTORE> + StatusCode record (std::unique_ptr<T> data, + std::unique_ptr<AUXSTORE> store); + + + /** + * @brief Record a non-const object and its auxiliary store to the store. + * @param data The object to record. + * @param auxstore Auxiliary store object. + */ + template <class AUXSTORE> + StatusCode recordNonConst (std::unique_ptr<T> data, + std::unique_ptr<AUXSTORE> store); + + + /** + * @brief Record a const shared DataObject to the store. + * @param data The object to record. + * + * The event store takes shared ownership of the object. + */ + StatusCode record (SG::DataObjectSharedPtr<T> data); + + + /** + * @brief Record a non-const shared DataObject to the store. + * @param data The object to record. + * + * The event store takes shared ownership of the object. + */ + StatusCode recordNonConst (SG::DataObjectSharedPtr<T> data); + + + // Commit this out for now since it looks like we don't actually need it. +#if 0 + /** + * @brief Record a new non-const object, or retrieve an old one. + * @param data The object to record. + * @param isConst If true, record the objects as const. + * + * If no object for this handle's key exists already in StoreGate, + * then record @c data. + * Otherwise, if one exists and is non-const, then initialize + * the handle to refer to that object (and destroy @c data). + * Otherwise return an error. + * + * No const version of this method, since it then doesn't make sense + * to do that in multiple threads. + */ + StatusCode recordOrRetrieve (std::unique_ptr<T> data); +#endif + + + /** + * @brief Alternate notation for record. Records a non-const object. + * @param data Object to record. + * + * Throws an execption on failure. + */ + WriteHandle& operator=( std::unique_ptr<T> data ); + + + +private: + /** + * @brief Return the cached pointer directly. + * + * If it is null, throw ExcNullWriteHandle. + */ + pointer_type checkedCachedPtr() const; + + + /** + * @brief Helper for record. + * @param data The object to record. + * @param isConst If true, record the object as const. + * @param returnExisting Allow an existing object. + */ + template <class U> + StatusCode doRecord (U data, + bool isConst, + bool returnExisting); + + + /** + * @brief Record an object and its auxiliary store to the store. + * @param data The object to record. + * @param auxstore Auxiliary store object. + * @param isConst If true, record the objects as const. + */ + template <class AUXSTORE> + StatusCode + record (std::unique_ptr<T> data, + std::unique_ptr<AUXSTORE> auxstore, + bool isConst); + + +private: + /// If non-null, then we need to lock the associated aux store object + /// when we're deleted. + /// + /// This is set when we record an object along with the associated aux const + /// with the const flag set (the default). Recall that for a const record, + /// we want to support the semantics that you can get a non-const pointer + /// back from the handle as long as it exists, to finish initialization + /// of the object. For an aux store, though, just getting back a non-const + /// pointer is not sufficient, since the store will have been locked + /// at the time of the record, preventing changes to the store. + /// + /// So if we're meant to record a const aux store object, we don't actually + /// set it const on the record, but instead set this and do the + /// setConst in the destructor. + SG::DataProxy* m_lockAuxPending = nullptr; +}; + + +/** + * @brief Return a @c WriteHandle referencing @c key. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +WriteHandle<T> makeHandle (const WriteHandleKey<T>& key); + + +/** + * @brief Return a @c WriteHandle referencing @c key for an explicit context. + * @param key The key object holding the clid/key/store. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +WriteHandle<T> makeHandle (const WriteHandleKey<T>& key, + const EventContext& ctx); + + +} /* namespace SG */ + + +#include "StoreGate/WriteHandle.icc" + + +#ifndef NO_LEGACY_HANDLES +namespace SG { + template <class T> + using WVar = WriteHandle<T>; +} +#endif +#endif //> !STOREGATE_SG_WRITEHANDLE_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteHandle.icc b/EDM/athena/Control/StoreGate/StoreGate/WriteHandle.icc new file mode 100644 index 00000000..4b5e3f01 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteHandle.icc @@ -0,0 +1,531 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: WriteHandle.icc 756419 2016-06-21 02:02:43Z ssnyder $ +/** + * @file StoreGate/WriteHandle.icc + * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov> + * @date Updated: Feb, 2016 + * @brief Handle class for recording to StoreGate. + */ + +#ifndef STOREGATE_SG_WRITEHANDLE_ICC +#define STOREGATE_SG_WRITEHANDLE_ICC 1 + + +#include "StoreGate/exceptions.h" +#include "SGTools/ClassID_traits.h" +#include "AthenaKernel/errorcheck.h" +#include <stdexcept> + + +namespace SG { + + +/** + * @brief Helper to temporarily clear aux store association. + * + * This is used in the object+store version of record, in order to prevent + * the store from being locked prematurely. + */ +template <class T> +class SaveStore +{ +public: + SaveStore (T& o) + : m_store (o.getStore()), + m_o (o) + { + if (m_store) + o.setStore (static_cast<SG::IAuxStore*>(nullptr)); + } + + ~SaveStore() + { + if (m_store) + m_o.setStore (m_store); + } + +private: + IAuxStore* m_store; + T& m_o; +}; + + +//************************************************************************ +// Constructors, etc. +// + + +/** + * @brief Default constructor. + * + * The handle will not be usable until a non-blank key is assigned. + */ +template <class T> +inline +WriteHandle<T>::WriteHandle() + : VarHandleBase(ClassID_traits<T>::ID(), Gaudi::DataHandle::Writer) +{ +} + + +/** + * @brief Constructor with full arguments. + * @param sgkey StoreGate key of the referenced object. + * @param storename Name of the referenced event store. + */ +template <class T> +inline +WriteHandle<T>::WriteHandle (const std::string& sgkey, + const std::string& storename /* ="StoreGateSvc"*/) + : VarHandleBase (ClassID_traits<T>::ID(), sgkey, + Gaudi::DataHandle::Writer, storename) +{ +} + + +/** + * @brief Constructor from a WriteHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +inline +WriteHandle<T>::WriteHandle (const WriteHandleKey<T>& key) + : VarHandleBase (key) +{ +} + + +/** + * @brief Constructor from a WriteHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +inline +WriteHandle<T>::WriteHandle (const WriteHandleKey<T>& key, + const EventContext& ctx) + : VarHandleBase (key, ctx) +{ +} + + +/** + * @brief Copy constructor. + */ +template <class T> +inline +WriteHandle<T>::WriteHandle(const WriteHandle& h) + : VarHandleBase(h) +{ +} + + +/** + * @brief Move constructor. + */ +template <class T> +WriteHandle<T>::WriteHandle(WriteHandle&& h) + : VarHandleBase(std::move(h)) +{ +} + + +/** + * @brief Assignment operator. + */ +template <class T> +inline +WriteHandle<T>& +WriteHandle<T>::operator= (const WriteHandle& h) +{ + if (this != &h) + this->VarHandleBase::operator=(h); + return *this; +} + + +/** + * @brief Move operator. + */ +template <class T> +inline +WriteHandle<T>& +WriteHandle<T>::operator= (WriteHandle&& h) +{ + if (this != &h) + this->VarHandleBase::operator=(std::move(h)); + return *this; +} + + +/** + * @brief Destructor. + * + * Lock an aux object if m_lockAuxPending is true. + */ +template <class T> +WriteHandle<T>::~WriteHandle() +{ + if (m_lockAuxPending) { + m_lockAuxPending->setConst(); + } +} + + +//************************************************************************ +// Deference. These all return only the cached pointer. +// + + +/** + * @brief Derefence the pointer. + * Returns the cached pointer. Throws ExcNullWriteHandle if null. + */ +template <class T> +inline +typename WriteHandle<T>::pointer_type +WriteHandle<T>::operator->() const +{ + return WriteHandle<T>::checkedCachedPtr(); +} + + +/** + * @brief Derefence the pointer. + * Returns the cached pointer. Throws ExcNullWriteHandle if null. + */ +template <class T> +inline +typename WriteHandle<T>::reference_type +WriteHandle<T>::operator*() const +{ + return *WriteHandle<T>::checkedCachedPtr(); +} + + +/** + * @brief Dereference the pointer. + * Returns the cached pointer. + */ +template <class T> +inline +typename WriteHandle<T>::const_pointer_type +WriteHandle<T>::cptr() const +{ + return cachedPtr(); +} + + +/** + * @brief Dereference the pointer. + * Returns the cached pointer. + */ +template <class T> +inline +typename WriteHandle<T>::pointer_type +WriteHandle<T>::ptr() const +{ + return cachedPtr(); +} + + +/** + * @brief Return the cached pointer directly; no lookup. + */ +template <class T> +inline +typename WriteHandle<T>::pointer_type +WriteHandle<T>::cachedPtr() const +{ + return reinterpret_cast<pointer_type>(this->m_ptr); +} + + +/** + * @brief Can the handle be successfully dereferenced? + */ +template <class T> +inline +bool WriteHandle<T>::isValid() +{ + return this->m_ptr != nullptr; +} + + +//************************************************************************ +// Record. + + +/** + * @brief Record a const object to the store. + * @param data The object to record. + */ +template <class T> +inline +StatusCode +WriteHandle<T>::WriteHandle::record (std::unique_ptr<T> data) +{ + return this->doRecord (std::move(data), true, false); +} + + +/** + * @brief Record a non-const object to the store. + * @param data The object to record. + * @param isConst If true, record the object as const. + */ +template <class T> +inline +StatusCode +WriteHandle<T>::WriteHandle::recordNonConst (std::unique_ptr<T> data) +{ + return this->doRecord (std::move(data), false, false); +} + + +/** + * @brief Record a const object and its auxiliary store to the store. + * @param data The object to record. + * @param auxstore Auxiliary store object. + */ +template <class T> +template <class AUXSTORE> +inline +StatusCode +WriteHandle<T>::WriteHandle::record (std::unique_ptr<T> data, + std::unique_ptr<AUXSTORE> auxstore) +{ + return record (std::move(data), std::move(auxstore), true); +} + + +/** + * @brief Record a non-const object and its auxiliary store to the store. + * @param data The object to record. + * @param auxstore Auxiliary store object. + */ +template <class T> +template <class AUXSTORE> +inline +StatusCode +WriteHandle<T>::WriteHandle::recordNonConst (std::unique_ptr<T> data, + std::unique_ptr<AUXSTORE> auxstore) +{ + return record (std::move(data), std::move(auxstore), false); +} + + +/** + * @brief Record a const shared DataObject to the store. + * @param data The object to record. + * + * The event store takes shared ownership of the object. + */ +template <class T> +inline +StatusCode +WriteHandle<T>::record (SG::DataObjectSharedPtr<T> data) +{ + return this->doRecord (std::move(data), true, false); +} + + +/** + * @brief Record a non-const shared DataObject to the store. + * @param data The object to record. + * + * The event store takes shared ownership of the object. + */ +template <class T> +inline +StatusCode +WriteHandle<T>::recordNonConst (SG::DataObjectSharedPtr<T> data) +{ + return this->doRecord (std::move(data), false, false); +} + + +#if 0 +/** + * @brief Record a new non-const object, or retrieve an old one. + * @param data The object to record. + * @param isConst If true, record the objects as const. + * + * If no object for this handle's key exists already in StoreGate, + * then record @c data. + * Otherwise, if one exists and is non-const, then initialize + * the handle to refer to that object (and destroy @c data). + * Otherwise return an error. + * + * No const version of this method, since it then doesn't make sense + * to do that in multiple threads. + */ +template <class T> +inline +StatusCode +WriteHandle<T>::recordOrRetrieve (std::unique_ptr<T> data) +{ + return this->doRecord (std::move(data), false, true); +} +#endif + + +/** + * @brief Alternate notation for record. Records a non-const object. + * @param data Object to record. + * + * Throws an execption on failure. + */ +template <class T> +WriteHandle<T>& +WriteHandle<T>::operator= (std::unique_ptr<T> data) +{ + if (recordNonConst (std::move(data)).isFailure()) { + throw std::runtime_error ("WriteHandle<T>::operator=(unique_ptr) Record failed."); + } + return *this; +} + + +/** + * @brief Return the cached pointer directly. + * + * If it is null, throw ExcNullWriteHandle. + */ +template <class T> +typename WriteHandle<T>::pointer_type +WriteHandle<T>::checkedCachedPtr() const +{ + if (!m_ptr) + throwExcNullWriteHandle (clid(), key(), store()); + return cachedPtr(); +} + + +/** + * @brief Helper for record. + * @param data The object to record. + * @param isConst If true, record the object as const. + * @param returnExisting Allow an existing object. + */ +template <class T> +template <class U> +StatusCode WriteHandle<T>::doRecord (U data, + bool isConst, + bool returnExisting) +{ + typedef typename U::element_type elt_t; + + // make sure the BaseInfo(Base) structure is initialized + SG::BaseInfo<elt_t>::baseinfo(); + + // If s_isConst is set for this type, then we want to automatically + // make it const when recorded. + bool allowMods = !isConst; + if (ClassID_traits<elt_t>::s_isConst) + allowMods = false; + + void* dataPtr(data.get()); + std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data))); + return this->record_impl (std::move(dobj), dataPtr, allowMods, returnExisting); +} + + +/** + * @brief Record an object and its auxiliary store to the store. + * @param data The object to record. + * @param auxstore Auxiliary store object. + * @param isConst If true, record the objects as const. + */ +template <class T> +template <class AUXSTORE> +StatusCode +WriteHandle<T>::record (std::unique_ptr<T> data, + std::unique_ptr<AUXSTORE> auxstore, + bool isConst) +{ + T& dref = *data; + + if (isConst) { + // Temporarily clear the store association, in order to prevent + // the aux store from being locked at this point. + SaveStore<T> ss (*data); + CHECK (this->record(std::move(data))); + } + else + CHECK (this->recordNonConst(std::move(data))); + + // Store and proxy must be valid if we get to this point. + + SG::DataObjectSharedPtr<DataObject> dobj + (SG::asStorable (std::move (auxstore))); + SG::DataProxy* proxy = m_store->recordObject (std::move(dobj), + this->name() + "Aux.", + true, + false); + if (!proxy) { + REPORT_ERROR (StatusCode::FAILURE) + << "recordObject of aux store failed"; + + // If we've failed here, then the aux store object has been deleted, + // but not the primary object. Null out the store pointer to prevent + // having a dangling pointer to a deleted object. + dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr)); + return StatusCode::FAILURE; + } + + if (m_proxy->isConst()) + m_lockAuxPending = proxy; + return StatusCode::SUCCESS; +} + + +/** + * @brief Return a @c WriteHandle referencing @c key. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ +template <class T> +WriteHandle<T> makeHandle (const WriteHandleKey<T>& key) +{ + return WriteHandle<T> (key); +} + + +/** + * @brief Return a @c WriteHandle referencing @c key for an explicit context. + * @param key The key object holding the clid/key/store. + * @param ctx The event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ +template <class T> +WriteHandle<T> makeHandle (const WriteHandleKey<T>& key, + const EventContext& ctx) +{ + return WriteHandle<T> (key, ctx); +} + + +} /* namespace SG */ + + +#endif //> !STOREGATE_SG_WRITEHANDLE_ICC diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.h b/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.h new file mode 100644 index 00000000..951bb8c4 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.h @@ -0,0 +1,73 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/WriteHandleKey.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Property holding a SG store/key/clid from which a WriteHandle is made. + */ + + +#ifndef STOREGATE_WRITEHANDLEKEY_H +#define STOREGATE_WRITEHANDLEKEY_H + + +#include "StoreGate/VarHandleKey.h" +#include "SGTools/CLASS_DEF.h" + + +namespace SG { + + +/** + * @brief Property holding a SG store/key/clid from which a WriteHandle is made. + * + * This class holds the key part of a WriteHandle. For a reentrant algorithm, + * you would use this as the algorithm property and construct the actual + * ReadHandle on the stack from this key object (and optionally the event + * context). + * + * See VarHandleKey for more details. + */ +template <class T> +class WriteHandleKey + : public VarHandleKey +{ +public: + /** + * @brief Constructor. + * @param key The StoreGate key for the object. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. + */ + WriteHandleKey (const std::string& key = "", + const std::string& storeName = "StoreGateSvc"); + + + /** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. + */ + WriteHandleKey& operator= (const std::string& sgkey); +}; + + +} // namespace SG + + +#include "StoreGate/WriteHandleKey.icc" + + +#endif // not STOREGATE_WRITEHANDLEKEY_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.icc b/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.icc new file mode 100644 index 00000000..2341acee --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKey.icc @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/WriteHandleKey.icc + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Property holding a SG store/key/clid from which a WriteHandle is made. + */ + + +namespace SG { + + +/** + * @brief Constructor. + * @param key The StoreGate key for the object. + * @param storeName Name to use for the store, if it's not encoded in sgkey. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. + */ +template <class T> +WriteHandleKey<T>::WriteHandleKey (const std::string& key /*= ""*/, + const std::string& storeName /*= "StoreGateSvc"*/) + : VarHandleKey (ClassID_traits<T>::ID(), key, + Gaudi::DataHandle::Writer, + storeName) +{ +} + + +/** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store is not changed. + */ +template <class T> +WriteHandleKey<T>& WriteHandleKey<T>::operator= (const std::string& sgkey) +{ + VarHandleKey::operator= (sgkey); + return *this; +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKeyArray.h b/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKeyArray.h new file mode 100644 index 00000000..8c051ff8 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/WriteHandleKeyArray.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_WRITEHANDLEKEYARRAY_H +#define STOREGATE_WRITEHANDLEKEYARRAY_H 1 + +#include "StoreGate/VarHandleKeyArray.h" + +#include "StoreGate/WriteHandleKey.h" +#include "StoreGate/WriteHandle.h" + +#include <vector> +#include <string> + +namespace SG { + + /** + * @class SG::WriteHandleKeyArray<T> + * @brief class to hold an array of WriteHandleKeys + * + * since it inherits from std::vector, all vector operations are + * permitted. + * + * initialization can be done in three ways. + * 1: with an std::vector<WriteHandleKey> as a parameter + * SG::WriteHandleKeyArray<foo> m_foo ( std::vector<WriteHandleKey> ); + * 2: with an initializer list of WriteHandleKeys + * SG::WriteHandleKeyArray<foo> m_foo { WriteHandleKey<foo> k1, WriteHandleKey<foo> k2 }; + * 3: with an initializer list of std::strings, that will be used to + * internally create WriteHandleKeys with those initializers + * SG::WriteHandleKeyArray<foo> m_foo { "key1", "key2", "key3" }; + */ + + template <class T> + class WriteHandleKeyArray : public VarHandleKeyArrayCommon< WriteHandleKey<T> > { + public: + /** + * @brief default Constructor from a WriteHandleKeyArray + */ + WriteHandleKeyArray(){}; + + /** + * @brief Constructor from a WriteHandleKeyArray that takes a vector + * of ReaDHandleKeys + * @param v vector of WriteHandleKey + */ + WriteHandleKeyArray( const std::vector<WriteHandleKey<T>>& v ) : + VarHandleKeyArrayCommon<WriteHandleKey<T>> ( v ) {}; + + /** + * @brief Constructor from a WriteHandleKeyArray that takes an + * initializer list of WriteHandleKeys + * @param l initializer list of WriteHandleKey + */ + WriteHandleKeyArray( std::initializer_list<WriteHandleKey<T>> l ): + VarHandleKeyArrayCommon<WriteHandleKey<T>> {l} {}; + + /** + * @brief Constructor from a WriteHandleKeyArray that takes an + * initializer list of std::strings. + * @param l initializer list of std::strings used to create the + * WriteHandleKeys + */ + WriteHandleKeyArray( std::initializer_list<std::string> l ): + VarHandleKeyArrayCommon<WriteHandleKey<T>> {l} {}; + + /** + * @brief return the type (Read/Write/Update) of handle + */ + Gaudi::DataHandle::Mode mode() const { return Gaudi::DataHandle::Writer; } + + /** + * @brief create a vector of WriteHandles from the WriteHandleKeys + * in the array + */ + std::vector< WriteHandle<T> > makeHandles() const { + std::vector< WriteHandle<T> > hndl; + typename std::vector<WriteHandleKey<T>>::const_iterator itr; + for (itr = this->begin(); itr != this->end(); ++itr) { + hndl.push_back ( WriteHandle<T>( *itr) ); + } + return ( std::move( hndl ) ); + } + + }; + + +} // namespace SG + +#endif diff --git a/EDM/athena/Control/StoreGate/StoreGate/constraints/KeyConcept.h b/EDM/athena/Control/StoreGate/StoreGate/constraints/KeyConcept.h new file mode 100644 index 00000000..f9113cb3 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/constraints/KeyConcept.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CONSTRAINTS_KEYCONCEPT_H +#define CONSTRAINTS_KEYCONCEPT_H +#ifndef _CPP_STRING + #include <string> +#endif +#include <boost/version.hpp> +#ifndef BOOST_CONCEPT_CHECKS_HPP + #include <boost/concept_check.hpp> +#endif + +//CONCEPT +template <class T, class ID=std::string > +struct KeyConcept { + void constraints() { + // check that key can be converted to an identifier + //needed? boost::function_requires< boost::ConvertibleConcept<ID, T> >(); + boost::function_requires< boost::ConvertibleConcept<T, ID> >(); + //should also have boost::function_requires< boost::LessThanComparableConcept<T> >(); + } + T a; +}; + +template<std::size_t N> +struct KeyConcept<char[N], std::string> { + void constraints() { } //no check for char arrays +}; + +template<> +struct KeyConcept<char*, std::string> { + void constraints() { } //no check for char arrays +}; + +template<> +struct KeyConcept<char, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<short, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<int, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<long, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<long long, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<unsigned char, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<unsigned short, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<unsigned int, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<unsigned long, std::string> { + void constraints() { } //no check for char arrays +}; +template<> +struct KeyConcept<unsigned long long, std::string> { + void constraints() { } //no check for char arrays +}; + + +//HELPER FUNCTION AND CLASS TO EXPRESS THE CHECK IN A COMPACT FASHION +template <class T> +inline int classIsKey() { +#ifndef SKIP_GCC_INTERNAL_ERROR_980519 + //triggers an internal error in 2.91 + boost::function_requires< KeyConcept<T> > (); +#endif + return 0; +} + +template <class T> +struct KeyClass { + KeyClass() {} + ~KeyClass() {} +#ifndef CODEWIZARD +# if BOOST_VERSION < 103700 + BOOST_CLASS_REQUIRES(T, KeyConcept); +# else + BOOST_CONCEPT_ASSERT((KeyConcept<T>)); +# endif +#endif +}; + +#endif + + + + + + + diff --git a/EDM/athena/Control/StoreGate/StoreGate/exceptions.h b/EDM/athena/Control/StoreGate/StoreGate/exceptions.h new file mode 100644 index 00000000..8fdfee83 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/exceptions.h @@ -0,0 +1,269 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/exceptions.h + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Exceptions that can be thrown from StoreGate. + */ + + +#ifndef STOREGATE_EXCEPTIONS_H +#define STOREGATE_EXCEPTIONS_H + + +#include "GaudiKernel/ClassID.h" +#include <stdexcept> +#include <typeinfo> +#include <string> + + +namespace SG { + + +/** + * @brief Exception --- Attempt to dereference a Read/Write/UpdateHandle with a null key. + * + * An explicit key must always be given when using Read/Write/UpdateHandle. + */ +class ExcNullHandleKey + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + */ + ExcNullHandleKey(); +}; + + +/** + * @brief Throw a SG::ExcNullHandleKey exception. + */ +[[noreturn]] +void throwExcNullHandleKey(); + + +/** + * @brief Exception --- Bad key format for VarHandleKey. + * + * The key for a VarHandle must be of the form KEY or STORE/KEY; + * no more than one slash may be present in the key string. + */ +class ExcBadHandleKey + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param key The supplied key string. + */ + ExcBadHandleKey (const std::string& key); +}; + + +/** + * @brief Exception --- Forbidden method called. + */ +class ExcForbiddenMethod + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param name Name of the called method. + */ + ExcForbiddenMethod (const std::string& name); +}; + + +/** + * @brief Exception --- Error initializing VarHandle from VarHandleKey. + */ +class ExcHandleInitError + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcHandleInitError (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Exception --- Tried to create a handle from an uninitialized key. + */ +class ExcUninitKey + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcUninitKey (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Exception --- Tried to retrieve non-const pointer to const object. + */ +class ExcConstObject + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcConstObject (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Exception --- Attempt to dereference write handle before record. + */ +class ExcNullWriteHandle + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcNullWriteHandle (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Throw a SG::ExcNullWriteHandle exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +[[noreturn]] +void throwExcNullWriteHandle (CLID clid, + const std::string& sgkey, + const std::string& storename); + + +/** + * @brief Exception --- Deference of read handle failed. + */ +class ExcNullReadHandle + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcNullReadHandle (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Throw a SG::ExcNullReadHandle exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +[[noreturn]] +void throwExcNullReadHandle (CLID clid, + const std::string& sgkey, + const std::string& storename); + + +/** + * @brief Exception --- Deference of update handle failed. + */ +class ExcNullUpdateHandle + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcNullUpdateHandle (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Throw a SG::ExcNullUpdateHandle exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +[[noreturn]] +void throwExcNullUpdateHandle (CLID clid, + const std::string& sgkey, + const std::string& storename); + + +/** + * @brief Exception --- updatedObject failed. + */ +class ExcUpdatedObjectFailure + : public std::runtime_error +{ +public: + /** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ + ExcUpdatedObjectFailure (CLID clid, + const std::string& sgkey, + const std::string& storename); +}; + + +/** + * @brief Throw a SG::ExcUpdatedObjectFailure exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +[[noreturn]] +void throwExcUpdatedObjectFailure (CLID clid, + const std::string& sgkey, + const std::string& storename); + + +} // namespace SG + + +#endif // not STOREGATE_EXCEPTIONS_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/setupStoreGate.h b/EDM/athena/Control/StoreGate/StoreGate/setupStoreGate.h new file mode 100644 index 00000000..dc6a3b39 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/setupStoreGate.h @@ -0,0 +1,39 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/setupStoreGate.h + * @author scott snyder <snyder@bnl.gov>, after S. Binet's code from TestPolicy. + * @date Aug, 2014 + * @brief Helper for setting up StoreGate for regression tests. + */ + + +#ifndef STOREGATESVC_SETUPSTOREGATE_H +#define STOREGATESVC_SETUPSTOREGATE_H + + +#include <string> + + +namespace Athena_test { + + +/** + * @brief Helper for setting up StoreGate for regression tests. + * @param progname Program name (argv[0]). + * @param options_file Name of the JO text file to read. + * If defaulted, one will be generated. + */ +bool setupStoreGate (std::string progname, + std::string options_file = ""); + + +} // namespace Athena_test + + +#endif // not STOREGATESVC_SETUPSTOREGATE_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.h b/EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.h new file mode 100644 index 00000000..bb75e2cd --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.h @@ -0,0 +1,1215 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_SGIMPLSVC_H +#define STOREGATE_SGIMPLSVC_H + +//FIXME the CLASS_DEF header is not needed here but was added to work around +//bad include statements in client code: when using CLASS_DEF put the +//include below in your header file! +#include "SGTools/CLASS_DEF.h" + +//base classes +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/Service.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaKernel/IProxyDict.h" + +#include <GaudiKernel/ClassID.h> // for CLID +#include <GaudiKernel/IInterface.h> // for InterfaceID +#include <GaudiKernel/IMessageSvc.h> // for Level +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Property.h" /*StringArrayProperty*/ +#include "GaudiKernel/StatusCode.h" + +#include "GaudiKernel/DataObjID.h" + +#include <cstddef> // for size_t +#include <list> +#include <memory> /* auto_ptr */ +#include <string> +#include <sys/types.h> // for off_t +#include <vector> +#include <thread> + +#ifndef __CLING__ +#include <tbb/spin_rw_mutex.h> +#endif + +#include "AthenaKernel/StoreID.h" +#include "AthenaKernel/IProxyDict.h" +#include "AthenaKernel/IProxyProviderSvc.h" +#include "AthenaKernel/IHiveStoreMgr.h" +#include "AthenaKernel/IOVSvcDefs.h" +#include "AthenaKernel/DefaultKey.h" + +#include <SGTools/StringPool.h> +#include "SGTools/ProxyMap.h" /* for SG::ConstProxyIterator */ + + +// includes used in SGImplSvc.icc +#include "AthenaKernel/IResetable.h" +#include "AthenaKernel/IClassIDSvc.h" +#include "AthenaKernel/IIOVSvc.h" +#include "StoreGate/SGIterator.h" +#include "StoreGate/DataHandle.h" +#include "StoreGate/SGWPtr.h" +#include "SGTools/DataStore.h" +#include "SGTools/SGVersionedKey.h" +#include "StoreGate/SGObjectWithVersion.h" +#include "AthAllocators/Arena.h" +#include "SGTools/IProxyDictWithPool.h" // TEMPORARY + +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/ServiceHandle.h" +//forward declarations +namespace SG { + class DataProxy; + class TransientAddress; + struct RemapImpl; +} + +class DataObject; +class IConversionSvc; +//FIXME class IIncidentSvc; +class Incident; +class IHistorySvc; + +// python forward +struct _object; typedef _object PyObject; +class StoreGateSvc; +namespace AthenaInternal { + PyObject* recordObjectToStore(StoreGateSvc*,PyObject*,PyObject*,bool,bool,bool); + void py_sg_clearProxyPayload(StoreGateSvc* self, SG::DataProxy*); +} + +namespace SG { + class NoAuxStore; +} + +//friends... +class AthenaOutputStream; +class IOVDbSvc; +class IOVSvc; +class IOVSvcTool; +class PileUpMergeSvc; +class EventDumperSvc; +class MemoryMonitorSvc; +class SGDeleteAlg; +class ThinningSvc; +class ActiveStoreSvc; +namespace SG { + class VarHandleBase; +} +namespace PerfMon { class StorePayloadMon; } + +/** @class SGImplSvc + * @brief The Athena Transient Store API. + * + * @param "Dump" property (default false): set to call dump() at EndEvent + * @param "FolderNameList" property (default ""): data folders to be created + * in this store + * @author ATLAS Collaboration + * $Id: SGImplSvc.h 766223 2016-08-03 12:32:24Z will $ + **/ +class SGImplSvc : + public Service, + public IProxyDict, + public IHiveStoreMgr, + public IIncidentListener +{ + +public: +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + ///////////////////////////////////////////////////////////////////////// + /// \name Basic Client Interface: data object creation + //@{ + + /** Create an object with one of its constructors and record it with a key. + * @param key a string (or an object convertible to a string) + * identifying the object within the event + * @param constructorArgs a variable list of args passed to the constructor + * @returns a "pointer" to the created object (set to 0 if creation failed) + * Example: + * struct Foo { + * int m_i; + * int i() const { return m_i; } + * Foo(int i) : m_i(i) {} + * }; + * CLASS_DEF(Foo, 123456, 1); + * .... + * auto pFoo = pSG.create<Foo>("aFoo", 23); + * assert(pFoo->i()==23); + * assert(pSG.transientContains<Foo>("aFoo")); + */ + + template <typename T, typename TKEY, typename... ARGS> + SG::WPtr<T> create(const TKEY& key, ARGS... constructorArgs); + //@} +#endif /* needs C++11 variadic templates to call arbitrary constructors */ +#endif /* needs "templated typedef" to define SG::WPtr (for now) */ + + ///////////////////////////////////////////////////////////////////////// + /// \name Basic Client Interface: data object registration + //@{ + + /// Record an object with a key. + template <typename T, typename TKEY> + StatusCode record(T* p2BRegistered, const TKEY& key); + + /// Record a const object with a key + template <typename T, typename TKEY> + StatusCode record(const T* p2BRegistered, const TKEY& key); + + /// Record an object with a key, take ownership of the auto_pointed obj + template <typename T, typename TKEY> + StatusCode record(std::auto_ptr<T> p2BRegistered, const TKEY& key); + + /// Record an object with a key, allow possibility of specifying + /// const-access. + template <typename T, typename TKEY> + StatusCode record(T* p2BRegistered, const TKEY& key, + bool allowMods, bool resetOnly=true, bool noHist=false); + +#if __cplusplus > 201100 + /// Record an object with a key, take ownership of the unique_ptr obj + template <typename T, typename TKEY> + StatusCode record(std::unique_ptr<T> pUnique, const TKEY& key); + + /// Record a const object with a key + template <typename T, typename TKEY> + StatusCode record(std::unique_ptr<const T> pUnique, const TKEY& key); + + /// Record an object with a key, allow possibility of specifying + /// const-access. + template <typename T, typename TKEY> + StatusCode record(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool resetOnly=true, bool noHist=false); +#endif + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name Basic Client Interface: data object access + //@{ + + /// Retrieve the default object into a const T* + template <typename T> + StatusCode retrieve(const T*& ptr); + + /// Retrieve the default object into a T* + template <typename T> + StatusCode retrieve(T*& ptr); + + /// Variant of the above which does't return a status code. + /// Just returns null if the object isn't found. + template <typename T> + T* retrieve (); + + /// Variant of the above which does't print a warning message. + /// Just returns null if the object isn't found. Compare to contains + template <typename T> + T* tryRetrieve (); + template <typename T> + const T* tryConstRetrieve(); + + /// Retrieve an object with "key", into a const T* + template <typename T, typename TKEY> + StatusCode retrieve(const T*& ptr, const TKEY& key); + + /// Retrieve an object with "key", into a T* + template <typename T, typename TKEY> + StatusCode retrieve(T*& ptr, const TKEY& key); + + /// Variant of the above which does't return a status code. + /// Just returns null if the object isn't found. + template <typename T, class TKEY> + T* retrieve (const TKEY& key); + + /// Variant of the above which does't print a warning message. + /// Just returns null if the object isn't found. Compare to contains + template <typename T, class TKEY> + T* tryRetrieve (const TKEY& key); + template <typename T, class TKEY> + const T* tryConstRetrieve(const TKEY& key); + + /** + * @brief try to associate a data object to its auxiliary store + * if ignoreMissing=false @returns false if the aux store is not found. + * @param key The key to use for the lookup. + **/ + template <class DOBJ> + bool associateAux (DataHandle<DOBJ>&, bool ignoreMissing=true); + template <class DOBJ> + bool associateAux (const DataHandle<DOBJ>&, bool ignoreMissing=true); + + /// retrieve a data object deriving from DataVectorAuxBase, + /// associate the data object to its matching IAuxStore. + /// The matching is done by name, with the IAuxStore assumed to have key + /// key + "Aux" + /// returns null if the object or its IAuxStore isn't found. + template <typename T, class TKEY> + T* retrieveAux (const TKEY& key); + template <typename T, class TKEY> + const T* constRetrieveAux (const TKEY& key); + + + + + + /// Retrieve all objects of type T: returns an SG::ConstIterator range + template <typename T> + StatusCode retrieve(SG::ConstIterator<T>& begin, + SG::ConstIterator<T>& end); + + /** Look up a keyed object in TDS (compare also tryRetrieve) + * returns false if object not available in TDS or persistent stores + * Usage: if (!p_store->contains<Foo>("fooKey")) { ... } */ + /// + template <typename T, typename TKEY> + bool contains(const TKEY& key) const; + + /** A "once-per-job" retrieve that binds a data object to a DataHandle, + * typically a data member of an Algorithm/AlgTool. + * At the end of every event, or more in general + * when the data object is not valid anymore, the DataHandle is reset, + * so that the next time the handle is accessed it will point to the + * current version of that data object. + * For example if MyAlg.h has a data member + * DataHandle<Foo> m_myFoo; + * after bind is called once per job, usually in MyAlg::initialize: + * sc = p_store->bind(m_myFoo, "MyFoo"); + * m_myFoo will provide to access the current MyFoo e.g. in MyAlg::execute(): + * m_myFoo->useMe(); + */ + template <typename T, typename TKEY> + StatusCode bind(const DataHandle<T>& handle, const TKEY& key); + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name Advanced Client Interface: data object registration + //@{ + + /// Record an object with a key, overwriting any existing object with same key + template <typename T, typename TKEY> + StatusCode overwrite(T* p2BRegistered, const TKEY& key); + + /// Record an object with a key, overwriting any existing object with same key + template <typename T, typename TKEY> + StatusCode overwrite(T* p2BRegistered, const TKEY& key, + bool allowMods, bool noHist=false); + + /// Record an object with a key, overwriting any existing object with same key, take ownership of the auto_pointed obj + template <typename T, typename TKEY> + StatusCode overwrite(std::auto_ptr<T> p2BRegistered, const TKEY& key); + +#if __cplusplus > 201100 + /// Record an object with a key, overwriting any existing object with same key + template <typename T, typename TKEY> + StatusCode overwrite(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool noHist=false); + + /// Record an object with a key, overwriting any existing object with same key, take ownership of the unique_ptr obj + template <typename T, typename TKEY> + StatusCode overwrite(std::unique_ptr<T> pUnique, const TKEY& key); +#endif + + /// Create a proxy object using an IOpaqueAddress and a transient key + StatusCode recordAddress(const std::string& skey, + IOpaqueAddress* pAddress, bool clearAddressFlag=true); + /// Create a proxy object using an IOpaqueAddress + StatusCode recordAddress(IOpaqueAddress* pAddress, bool clearAddressFlag=true); + + /// make a soft link to the object T* already registered (non-const) + template <typename T, typename TLINK> + StatusCode symLink (const T* p2BRegistered, TLINK* p2BLinked ); + + /// make a soft link to the object T* already registered (const link) + template <typename T, typename TLINK> + StatusCode symLink (const T* p2BRegistered, const TLINK* p2BLinked ); + + /// make a soft link to the object pointed by id/key + template <typename TKEY> + StatusCode symLink (const CLID& id, const TKEY& key, const CLID& linkid); + + /// make an alias to a DataObject (provide data type and old key) + template <typename T, typename TKEY, typename AKEY> + StatusCode setAlias(const T* p2BAliased, const TKEY& key, const AKEY& aliasKey); + + /// make an alias to a DataObject (provide only valid pointer) + template <typename T, typename AKEY> + StatusCode setAlias(const T* p2BAliased, const AKEY& aliasKey); + + /// prevent downstream clients from modyfing the pointed-at dobj + StatusCode setConst(const void* pointer); + + /// Remove pObject, will remove its proxy if not reset only. + template <typename T> + StatusCode remove(const T* pObject); + + /// Remove pObject and its proxy no matter what. + template <typename T> + StatusCode removeDataAndProxy(const T* pObject); + + /// @brief swap the content of 2 keys + /// payload A indexed by keyA will now be accessed via keyB and vice versa + /// Note that the swap is invalidated at event boundaries and/or when + /// somebody clear the store. + /// @return false if swap failed + bool transientSwap( const CLID& id, + const std::string& keyA, const std::string& keyB ); + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name Advanced Client Interface: data object access + //@{ + + /// Retrieve version with highest cycle number for a given T,KEY combination + /// If there is only one available version of this data object + /// the returned ObjectWithVersion<T>.versionedKey is set to requestedKey + /// NOTICE that this method is significantly slower than + /// retrieve(const T*, const TKEY&) + /// which returns the last recorded version rather than the one with the + /// highest cycle number. + /// @returns StatusCode::FAILURE if no dataObject found + template <typename T, class TKEY> + StatusCode retrieveHighestVersion(SG::ObjectWithVersion<T>& dobjWithVersion, + const TKEY& requestedKey); + + /// Retrieve all versions of a given T,KEY combination + /// sets allVersions, a ref to a vector of ObjectWithVersion<T> + /// If there is only one available version of this dataObject + /// allVersions[0].versionedKey is set to requestedKey. + /// @returns StatusCode::FAILURE if no dataObject found + //FIXME using a vector exposes ObjectWithVersion definition and hence + //FIXME VersionedKey.h. Should try an iface like + //FIXME retrieveAllVersions(const TKEY& requestedKey, + //FIXME ObjectWithVersion<T>& begin, + //FIXME ObjectWithVersion<T>& end) + template <typename T, class TKEY> + StatusCode + retrieveAllVersions(std::list< SG::ObjectWithVersion<T> >& allVersions, + const TKEY& requestedKey); + + + + /// EXPERTS ONLY: reads from disk your very own private copy of a StoreGate + /// object of type T and given key, if available and locked. + /// readPrivateCopy does not look up the object in SG transient memory + /// so it will fail to return a newly recorded object. + /// You are responsible for managing the returned object and for keeping it + /// in sync with the "main" copy in transient memory, if any. + /// DEPRECATED Use readUniquePrivateCopy + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::auto_ptr<T> readPrivateCopy (const std::string& key); + + /// EXPERTS ONLY: reads from disk your very own private copy of a StoreGate + /// object of type T and given key, if available and locked. + /// readPrivateCopy does not look up the object in SG transient memory + /// so it will fail to return a newly recorded object. + /// You are responsible for managing the returned object and for keeping it + /// in sync with the "main" copy in transient memory, if any. + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::unique_ptr<T> readUniquePrivateCopy (const std::string& key); + + /// readPrivateCopy implementation (possibly useful from python hence public) + DataObject* + typeless_readPrivateCopy(const CLID& clid, const std::string& key); + + + /// EXPERTS ONLY: like readPrivateCopy this method returns your own private + /// copy of a data object of type T and given key, if available and locked. + /// The difference is that it will return you also an object in SG transient + /// memory. Since we are taking ownership of it, the object in SG + /// will be released after retrievePrivateCopy returns, making + /// all cached references to the object potentially invalid and + /// obviously preventing it from being written out. + /// Sequencing becomes critical. Caveat emptor! + /// DEPRECATED Use retrieveUniquePrivateCopy + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::auto_ptr<T> retrievePrivateCopy (const std::string& key); + + /// EXPERTS ONLY: like readPrivateCopy this method returns your own private + /// copy of a data object of type T and given key, if available and locked. + /// The difference is that it will return you also an object in SG transient + /// memory. Since we are taking ownership of it, the object in SG + /// will be released after retrievePrivateCopy returns, making + /// all cached references to the object potentially invalid and + /// obviously preventing it from being written out. + /// Sequencing becomes critical. Caveat emptor! + /// @param key The key to use for the lookup. + /// @return null auto_ptr if the object isn't found or if it is unlocked. + template <typename T> + std::unique_ptr<T> retrieveUniquePrivateCopy (const std::string& key); + + /// Retrieve the main @c CLID of the object recorded in @c StoreGate + /// with the given "key" + /// WARNING: slow! + template<typename TKEY> + CLID clid( const TKEY& key ) const; + + /// Retrieve all the @c CLID s (including symlinks) of the object recorded in @c StoreGate + /// with the given "key" + /// WARNING: slow! + template<typename TKEY> + std::vector<CLID> clids( const TKEY& key ) const; + + /** Return the number of instances of an object of type T + * int i = p_store->typeCount<T>(); + * Note that this will return the number of proxies in transient memory + * only, will not check with proxy providers. */ + template <typename T> + int typeCount() const; + + /** Return the number of instances of type T (input CLID) */ + int typeCount(const CLID& id) const; + + /** Look up a keyed object in TDS by CLID. + * returns false if object not available in TDS or persistent stores + * Usage: if (!p_store->contains(FooID, "fooKey")) { ... } */ + template <typename TKEY> + bool contains(const CLID& id, const TKEY& key) const; + + + /** Look up a transient data object in TDS only (no Proxy lookup) + * returns false if object not available in TDS + * Usage: if (!p_store->contains<Foo>("fooKey")) { ... } */ + /// + template <typename T, typename TKEY> + bool transientContains(const TKEY& key) const; + + /** Look up a transient data object in TDS only by CLID. + * returns false if object not available in TDS */ + template <typename TKEY> + bool transientContains(const CLID& id, const TKEY& key) const; + + /** dump objects in store. request forwarded to DataStore + * this is triggered at EndEvent setting the Dump property to true */ + std::string dump() const; + + /// set store ID. request forwarded to DataStore: + void setStoreID(StoreID::type id); + /// get store ID. request forwarded to DataStore: + StoreID::type storeID() const; + + + /** provide list of all storegate keys associated with an object. + * usage: p_store->keys<T>(vkeys, optional flags); + * @param vkeys will be filled with the (possibly empty) list of keys + * @param includeAlias (default false) add alias keys as well + * @param onlyValid (default true) add only keys of valid dobjs + */ + template <typename T> + void + keys(std::vector<std::string>& vkeys, + bool includeAlias = false, bool onlyValid = true); + + /** provide list of all storegate keys associated with an object. + * usage: p_store->keys(CLID, vkeys, optionalFlags); + * @param id CLID for which we are requesting list of keys + * @param vkeys will be filled with the (possibly empty) list of keys + * @param includeAlias (default false) add alias keys as well + * @param onlyValid (default true) add only keys of valid dobjs + */ + void + keys(const CLID& id, std::vector<std::string>& vkeys, + bool includeAlias = false, bool onlyValid = true); + + /// implements IHiveStore interface for compat with Hive + virtual ::IProxyDict* hiveProxyDict() { + return this; + } + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name IOVSvc interface + //@{ + + template <typename H, typename TKEY> + StatusCode regHandle( const DataHandle<H>& handle, const TKEY& key ); + + /// non-const method - will return an error + template <typename H, typename TKEY> + StatusCode regHandle( DataHandle<H>& handle, const TKEY& key); + + /// register a callback function, with handle + key + template <typename T, typename H, typename TKEY> + StatusCode regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, const DataHandle<H>& handle, + const TKEY& key, bool trigger=false); + + /// register a callback function, with handle + key. Non const. Error + template <typename T, typename H, typename TKEY> + StatusCode regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, DataHandle<H>& handle, + const TKEY& key, bool trigger=false); + + /// register a callback function(2) with an already registered function(1) + template <typename T1, typename T2> + StatusCode regFcn(StatusCode (T1::*fcn1)(IOVSVC_CALLBACK_ARGS), + const T1* obj1, + StatusCode (T2::*fcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, bool trigger=false); + + /// register a callback function(2) with an already registered AlgTool + template <typename T2> + StatusCode regFcn(const std::string& toolName, + StatusCode (T2::*fcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, bool trigger=false); + + //@} + ///////////////////////////////////////////////////////////////////////// + + /// get proxy for a given data object address in memory + virtual SG::DataProxy* proxy(const void* const pTransient) const override final; + + /// get default proxy with given id. Returns 0 to flag failure + /// Deprecated for the event store. + virtual SG::DataProxy* proxy(const CLID& id) const final; + + /// get proxy with given id and key. Returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key) const override final; + /// get proxy with given id and key. Returns 0 to flag failure + /// (overload to prevent a char* to be interpreted as a bool.) + virtual SG::DataProxy* proxy(const CLID& id, const char* key) const final + { return this->proxy(id, std::string(key)); } + + /// Raw addition of a proxy to the store. + virtual StatusCode addToStore (CLID id, SG::DataProxy* proxy) override final; + + /** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ + virtual + SG::DataProxy* recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) override final; + + + /** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ + virtual + StatusCode updatedObject (CLID id, const std::string& key) override final; + + + /// Get proxy given a hashed key+clid. + /// Find an exact match; no handling of aliases, etc. + /// Returns 0 to flag failure. + virtual SG::DataProxy* proxy_exact (SG::sgkey_t sgkey) const override final + { return m_pStore->proxy_exact (sgkey); } + + + //@} + + /// \name more proxy dictionary functionality + //@{ + /// get default proxy with given id, optionally checking validity. + /// @returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, bool checkValid) const; + /// get proxy with given id and key, optionally checking validity. + /// @returns 0 to flag failure + virtual SG::DataProxy* proxy(const CLID& id, const std::string& key, bool checkValid) const; + /// get proxy with given id and key, optionally checking validity. + /// @returns 0 to flag failure + /// (overload to prevent a char* to be interpreted as a bool.) + virtual SG::DataProxy* proxy(const CLID& id, const char* key, bool checkValid) const + { return this->proxy(id, std::string(key), checkValid); } + + /// return the list of all current proxies in store + virtual std::vector<const SG::DataProxy*> proxies() const override final; + + /// get proxy with given id and key. Does not query ProxyProviderSvc. + /// @returns 0 to flag failure + SG::DataProxy* transientProxy(const CLID& id, const std::string& key) const; + + /// find proxy and access its data. Returns 0 to flag failure + DataObject* accessData(const CLID& id) const; + /// find proxy and access its data. Returns 0 to flag failure + DataObject* accessData(const CLID& id, const std::string& key) const; + + /// associate ProxyProviderSvc to this store + void setProxyProviderSvc(IProxyProviderSvc* pPPSvc); + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name String <-> int key conversions. IStringPool implementation + //@{ + + typedef IStringPool::sgkey_t sgkey_t; + + /** + * @brief Find the key for a string/CLID pair. + * @param str The string to look up. + * @param clid The CLID associated with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ + virtual + sgkey_t stringToKey (const std::string& str, CLID clid) override final; + + /** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key) const override final; + + /** + * @brief Find the string and CLID corresponding to a given key. + * @param key The key to look up. + * @param clid[out] The found CLID. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ + virtual + const std::string* keyToString (sgkey_t key, CLID& clid) const override final; + + /** + * @brief Remember an additional mapping from key to string/CLID. + * @param key The key to enter. + * @param str The string to enter. + * @param clid The CLID associated with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + * Logs an error if @c key already corresponds to a different string. + */ + virtual + void registerKey (sgkey_t key, + const std::string& str, + CLID clidid) override final; + + //@} + + ///////////////////////////////////////////////////////////////////////// + /// \name ElementLink remapping + //@{ + + + /** + * @brief Declare a remapping. + * @brief clid Class ID of the container being remapped. + * @brief source Key of the container being remapped. + * @brief target Key of the container being remapped to. + * @brief index_offset Amount by which the index should be adjusted + * between the two containers. + * + * This can be used to change the container to which @c ElementLink's + * (and @c DataLink's) point on output. + * + * For example, suppose you have two containers of type T, A and B. + * There possibly are @c ElementLink's pointing at elements contained + * in them. You want to change to a single container C, containing + * the contents of A and B concatenated. To get @c ElementLink's + * updated on output, you can do: + * + *@code + * m_sg->remap (ClassID_traits<T>::ID(), "A", "C", 0); + * m_sg->remap (ClassID_traits<T>::ID(), "B", "C", a.size());; + @endcode + */ + template <class TKEY> + void remap (CLID clid, + const TKEY& source, + const TKEY& target, + off_t index_offset); + + + /** + * @brief Declare a remapping. + * @brief source Key hash of the container being remapped. + * @brief target Key hash of the container being remapped to. + * @brief index_offset Amount by which the index should be adjusted + * between the two containers. + */ + void remap_impl (sgkey_t source, + sgkey_t target, + off_t index_offset); + + + /** + * @brief Test to see if the target of an ElementLink has moved. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + */ + virtual bool tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out) override final; + + //@} + + ////////////////////////////////////////////////////////////////// + /// \name Gaudi Standard Service structors + //@{ + SGImplSvc(const std::string& name, ISvcLocator* svc); + virtual ~SGImplSvc() override final; + //@} + + /////////////////////////////////////////////////////////////////////// + /// \name Gaudi IService implementation + //@{ + virtual StatusCode initialize() override final; + virtual StatusCode reinitialize() override final; + virtual StatusCode start() override final; + virtual StatusCode stop() override final; + virtual StatusCode finalize() override final; + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ) override final; + //@} + /// Should rather be in ISGImplSvc.h if we had one + static const InterfaceID& interfaceID(); + + + ////////////////////////////////////////////////////////////////// + /// \name Gaudi IIncidentListener implementation + //@{ + /// triggered by Incident service + virtual void handle(const Incident&) override final; + /// load proxies at begin event + StatusCode loadEventProxies(); + //@} + + + /////////////////////////////////////////////////////////////////////// + /// \name IHiveStoreMgr implementation + //@{ + /// clear DataStore contents: called by the event loop mgrs + /// @param forceRemove: if true remove proxies ignoring their resetOnly flag + virtual StatusCode clearStore(bool forceRemove=false) override final; + + /** Get data objects registred in store since last getNewDataObjects call (or since init for 1st call) + * + * @param products [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode getNewDataObjects(DataObjIDColl& products) override final; + + /** Check if something has been added to the store since last getNewDataObjects call + * + * @param products [IN] Slot number (event slot) * + * @return Boolean indicating the presence of new products + */ + virtual bool newDataObjectsPresent() override final; + + /** make newly recorded DataObjects know to the WhiteBoard, by copying + * from thread local storage to m_newDataObjects + */ + virtual void commitNewDataObjects() override final; + //@} + /// a new data object has been retrieved from persistency + void addedNewPersObject(CLID clid, SG::DataProxy* dp); + ///a new object transient object has been recorded + void addedNewTransObject(CLID clid, const std::string& key); + + + /** + * @brief Set the Hive slot number for this store. + * @param slot The slot number. -1 means that this isn't a Hive store. + * @param numSlots The total number of slots. Should be 1 for the + * non-Hive case. + */ + void setSlotNumber (int slot, int numSlots); + + + /** + * @brief Tell the store that a proxy has been bound to a handle. + * @param proxy The proxy that was bound. + * The default implemenatation does nothing. + */ + virtual void boundHandle (IResetable* handle) override final; + + + /** + * @brief Tell the store that a handle has been unbound from a proxy. + * @param handle The handle that was unbound. + * The default implementation does nothing. + */ + virtual void unboundHandle (IResetable* handle) override final; + + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /** @brief Test the output level + * @param lvl The message level to test against + * @return boolean Indicting if messages at given level will be printed + * @retval true Messages at level "lvl" will be printed + */ + bool + msgLvl (const MSG::Level lvl) const; + + /** The standard message stream. + * Returns a reference to the default message stream + * May not be invoked before sysInitialize() has been invoked. + */ + MsgStream& msg() const; + + /** The standard message stream. + * Returns a reference to the default message stream + * May not be invoked before sysInitialize() has been invoked. + */ + MsgStream& + msg (const MSG::Level lvl) const; + + /////////////////////////////////////////////////////////////////////// +private: + + // Helper for record. + template <typename T, typename TKEY> + StatusCode record1(DataObject* obj, T* pObject, const TKEY& key, + bool allowMods, bool resetOnly=true, bool noHist=false); + + // Helper for overwrite. + template <typename T, typename TKEY> + StatusCode overwrite1(DataObject* obj, T* pObject, const TKEY& key, + bool allowMods, bool noHist=false); + + StatusCode record_HistObj(const CLID& id, const std::string& key, + const std::string& store, bool allowMods, + bool resetOnly=true); + + + friend + PyObject* + AthenaInternal::recordObjectToStore(StoreGateSvc*,PyObject*,PyObject*,bool,bool,bool); + /// type-less recording of an object with a key, allow possibility of + /// specifying const-access and history record + StatusCode typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly=true, + bool noHist=false ); + /// same as typeless_record, allows to ovewrite an object in memory or on disk + StatusCode typeless_overwrite( const CLID& id, + DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, + bool noHist=false, + const std::type_info* tinfo=0); + + StatusCode typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, + bool noHist, + const std::type_info* tinfo); + StatusCode typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, + bool noHist, + const std::type_info* tinfo, + SG::DataProxy** proxy_ret); + + /// real recording of an object with a key, allow possibility of + /// specifying const-access + SG::DataProxy* record_impl( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, bool allowOverwrite, + const std::type_info* tinfo); + + + /// release object held by proxy, if any. Gives up ownership + /// (somebody else must take charge) + void releaseObject(const CLID& id, const std::string& key); + + ///access clearProxyPayload + friend class IOVDbSvc; + friend class IOVSvcTool; + friend class SGDeleteAlg; + friend class PerfMon::StorePayloadMon; + friend + void + AthenaInternal::py_sg_clearProxyPayload(StoreGateSvc*, SG::DataProxy*); + /// use to reset a proxy (clearing the data object it contains) + /// Unlike DataProxy::reset this method correctly updates SGSvc internals + void clearProxyPayload(SG::DataProxy*); + + /////////////////////////////////////////////////////////////////////// + SG::DataProxy* locatePersistent(const SG::TransientAddress* tAddr, + bool checkValid = false) const; + + ///access proxyRange() + friend class AthenaOutputStream; + ///return a range to all proxies of a given CLID + StatusCode proxyRange(const CLID& id, + SG::ConstProxyIterator& beg, + SG::ConstProxyIterator& end) const; + + ///access store() + friend class IOVSvc; // FIXME + friend class PileUpMergeSvc; // FIXME needs to call tRange + friend class EventDumperSvc; + friend class MemoryMonitorSvc; + friend void testHLTAutoKeyReset(SGImplSvc&, IProxyProviderSvc&); +#ifdef ATHENAHIVE + friend class StoreGateSvc; +#endif + ///access typeless_record + friend class ThinningSvc; + friend class SG::VarHandleBase; + + ///DEPRECATED: Return a _pointer_ to the DataStore + SG::DataStore* store(); + const SG::DataStore* store() const; + + bool isSymLinked(const CLID& linkID, SG::DataProxy* dp); + + StatusCode addSymLink(const CLID& linkid, SG::DataProxy* dp); + + StatusCode addAlias(const std::string& aliasKey, SG::DataProxy* dp); + + /// creates a key internally if none specified by client + std::string createKey(const CLID& dataID); + + /// try to locate a proxy or create it if needed + SG::DataProxy* setupProxy(const CLID& dataID, + const std::string& gK, + DataObject* pDObj, + bool allowMods, + bool resetOnly); + + ///put a bad (unrecordable) dobj away + void recycle(DataObject* pBadDObj); + ///throw away bad objects + void emptyTrash(); + + ///name says it all + bool bindHandleToProxy(const CLID& id, const std::string& key, + IResetable* ir, SG::DataProxy*& dp); + + /// remove proxy from store, unless it is reset only. + /// provide pTrans!=0 (must match proxy...) to save time + /// @param forceRemove remove the proxy no matter what + StatusCode removeProxy(SG::DataProxy* proxy, const void* pTrans, + bool forceRemove=false); + ///forwarded to DataStore + StatusCode t2pRegister(const void* const pTrans, SG::DataProxy* const pPers); + ///forwarded to DataStore + void t2pRemove(const void* const pTrans); + + /// callback for output level property + void msg_update_handler(Property& outputLevel); + + template <class DOBJ, class AUXSTORE> + bool associateAux_impl(DataHandle<DOBJ>& handle, const AUXSTORE*); + template <class DOBJ, class AUXSTORE> + bool associateAux_impl(const DataHandle<DOBJ>& handle, const AUXSTORE*); + template <class DOBJ> + bool associateAux_impl(DataHandle<DOBJ>& , const SG::NoAuxStore*) { return true; } + template <class DOBJ> + bool associateAux_impl(const DataHandle<DOBJ>&, const SG::NoAuxStore*) { return true; } + + /// Add automatically-made symlinks for DP. + void addAutoSymLinks (const std::string& key, CLID clid, SG::DataProxy* dp, + const std::type_info* tinfo, + bool warn_nobib = true); + + friend class ActiveStoreSvc; + /// The current store is becoming the active store. Switch the + /// allocation arena, if needed. + /// Only intended to be called by ActiveStoreSvc. + void makeCurrent(); + + IClassIDSvc* m_pCLIDSvc; + IConversionSvc* m_pDataLoader; + + ServiceHandle<IProxyProviderSvc> m_pPPSHandle; + // Has to be separate from handle due to setProxyProviderSvc() interface. + // Can we get rid of that? + IProxyProviderSvc* m_pPPS; + + IHistorySvc* m_pHistorySvc; + + SG::DataStore* m_pStore; + std::list<DataObject*> m_trash; ///< The Recycle Bin + + std::string m_defaultStoreName; ///< property + ServiceHandle<IIncidentSvc> m_pIncSvc; ///< property + bool m_DumpStore; ///< Dump Property flag: triggers dump() at EndEvent + bool m_ActivateHistory; ///< Activate the history service + + // typedef std::list<std::string> StrList; + StringArrayProperty m_folderNameList; ///< FolderNameList Property + + ///get the IOVSvc "just in time" (breaks recursion at initialize) + IIOVSvc* getIIOVSvc(); + IIOVSvc* m_pIOVSvc; + + bool m_storeLoaded; ///< FIXME hack needed by loadEventProxies + + SG::StringPool m_stringpool; + + SG::RemapImpl* m_remap_impl; + + /// Allocation arena to associate with this store. + SG::Arena m_arena; + + /// a std::cout like stream with levels to log messages + mutable MsgStream m_msg; + + ///list of recently added data objects, needed to implement getNewDataObjects + DataObjIDColl m_newDataObjects; +#ifndef __CLING__ + tbb::spin_rw_mutex m_newDataLock; +#endif + + /// The Hive slot number for this store, or -1 if this isn't a Hive store. + int m_slotNumber; + + /// The total number of slots. 1 if this isn't a Hive store. + int m_numSlots; + + /// Keep track of proxies bound since the last call to commitNewDataObjects + /// or clearStore. Has to be done per-thread. We can't use + /// thread_specific_ptr because we want to be able to clear the vectors + /// for all threads in clearStore(). + std::map<std::thread::id, std::vector<IResetable*> > m_newBoundHandles; + +public: + /////////////////////////////////////////////////////////////////////// + /// \name Obsolete and Deprecated methods + //@{ + /// DEPRECATED: Retrieve the default object into a const DataHandle + template <typename T> + StatusCode retrieve(const DataHandle<T>& handle); + + /// DEPRECATED: Retrieve the default object into a DataHandle + template <typename T> + StatusCode retrieve(DataHandle<T>& handle); + + /// DEPRECATED: Retrieve an object with "key", into a const DataHandle + template <typename T, typename TKEY> + StatusCode retrieve(const DataHandle<T>& handle, const TKEY& key); + /// DEPRECATED: Retrieve an object with "key", into a DataHandle + template <typename T, typename TKEY> + StatusCode retrieve(DataHandle<T>& handle, const TKEY& key); + + /// DEPRECATED Retrieve all objects of type T: use iterators version instead + template <typename T> + StatusCode retrieve(const DataHandle<T>& begin, + const DataHandle<T>& end); + /// DEPRECATED, use version taking ref to vector + template <typename T> + std::vector<std::string> //FIXME inefficient. Should take ref to vector + keys(bool allKeys = false); + + /// DEPRECATED, use version taking ref to vector + std::vector<std::string> //FIXME inefficient. Should take ref to vector + keys(const CLID& id, bool allKeys = false); + + /// DEPRECATED: use recordAddress instead + inline + StatusCode createProxy(IOpaqueAddress* pAddress, bool clearAddressFlag=true); + + /// OBSOLETE try to locate a proxy or create it if needed + /// use new signature with two bool flags + SG::DataProxy* setupProxy(const CLID& dataID, + const std::string& gK, + DataObject* pDObj); + //@} + + /// \name Obsolete and Deprecated methods + //@{ + /// DEPRECATED put a dobj pointer in a bucket as appropriate + /// see tools/StorableConversion.h for replacement + template <typename T> + static + DataObject* asStorable(T* pDObj); + /// DEPRECATED gets a dobj pointer from a bucket as appropriate + /// see tools/StorableConversion.h for replacement + template <typename T> + static + bool fromStorable(DataObject* pObject, T*& pData); + //@} + + +private: + SGImplSvc (const SGImplSvc&); + SGImplSvc& operator= (const SGImplSvc&); +}; + + +/// Here's one that's easy to call from the debugger. +void SG_dump (SGImplSvc* sg); + + +#include "StoreGate/tools/SGImplSvc.icc" + +#ifndef ATHENAHIVE +//- PyGate: StoreGate access from python ------------------------------------- +template< class T > +struct PyGate { + // default object retrieval + static const T* retrieve( SGImplSvc* psg ) { + const T* obj = 0; + if ( StatusCode::SUCCESS == psg->retrieve( obj ) ) + return obj; + return 0; + } + + // object retrieval with string key + static const T* retrieve( SGImplSvc* psg, const std::string& key ) { + const T* obj = 0; + if ( StatusCode::SUCCESS == psg->retrieve( obj, key ) ) + return obj; + return 0; + } +}; +#endif + +// inline methods +inline +bool +SGImplSvc::msgLvl (const MSG::Level lvl) const +{ return m_msg.level() <= lvl; } + +inline +MsgStream& +SGImplSvc::msg() const +{ return m_msg; } + +inline +MsgStream& +SGImplSvc::msg (const MSG::Level lvl) const +{ return m_msg << lvl; } + +#endif // STOREGATE_SGIMPLSVC_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.icc b/EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.icc new file mode 100644 index 00000000..6ca36a5d --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/tools/SGImplSvc.icc @@ -0,0 +1,1276 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** @file SGImplSvc.icc + * inlined implementation of SGImplSvc templated methods + */ + +#ifndef STOREGATE_SGIMPLSVC_ICC +#define STOREGATE_SGIMPLSVC_ICC + +#include "StoreGate/constraints/KeyConcept.h" +#include "StoreGate/DataHandle.h" +#include "AthContainersInterfaces/AuxStore_traits.h" +#include "SGTools/DataBucket.h" +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/CallBackID.h" +#include "SGTools/BaseInfo.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ClassID.h" +#include "boost/type_traits/remove_const.hpp" +#include "boost/concept/assert.hpp" +#include "boost/bind.hpp" +#include <iostream> + + + +// HACK LIFTED FROM AthenaBaseComps/AthMsgStreamMacros.h to remove dep loop +#define SG_MSG_LVL(lvl, x) \ + do { \ + if (msg().level() <= lvl) { \ + msg() << lvl << x << endmsg; \ + } \ + } while (0) + +#define SG_MSG_VERBOSE(x) SG_MSG_LVL(MSG::VERBOSE, x) +#define SG_MSG_DEBUG(x) SG_MSG_LVL(MSG::DEBUG, x) +#define SG_MSG_INFO(x) SG_MSG_LVL(MSG::INFO, x) +#define SG_MSG_WARNING(x) SG_MSG_LVL(MSG::WARNING, x) + + +////////////////////////////////////////////////////////////////// +// record an object without key +////////////////////////////////////////////////////////////////// +/************OBSOLETE METHODS*********************** +template <typename T> +StatusCode SGImplSvc::record(T* pObject) +{ + return record(pObject, true); +} + +template <typename T> +StatusCode SGImplSvc::record(const T* pObject) +{ + return record(const_cast<T*>(pObject), false); +} +////////////////////////////////////////////////////////////////// +// Record an Object in the Transient Data Store without key +// Can specify its const-ness in store +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::record(T* pObject, const bool& allowMods) +{ + //always delete the proxy of a keyless object + static const bool RESETONLY(false); + // generate a default unique key + return record(pObject, createKey(ClassID_traits<T>::ID()), allowMods, RESETONLY); + +} +***********OBSOLETE METHODS********************/ + +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES +/////////////////////////////////////////////////////////////////// +// create an object and record it with key +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY, typename... ARGS> +SG::WPtr<T> +SGImplSvc::create(const TKEY& key, ARGS... constructorArgs) { + T* pT = new T(constructorArgs...); + if(!(this->record(pT, key).isSuccess())) { + msg() << MSG::ERROR << "create: problem recording created object @" + << pT << " using key " << key << endmsg; + pT=0; //record will take care of deleting pT even if it fails + } + return pT; +} +#endif +#endif +/////////////////////////////////////////////////////////////////// +// record an object with key +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(std::auto_ptr<T> pAuto, const TKEY& key) +{ + const bool ALLOWMODS(true); + return record(pAuto.release(), key, ALLOWMODS); //SG takes ownership +} + +template <typename T, typename TKEY> +StatusCode SGImplSvc::overwrite(std::auto_ptr<T> pAuto, const TKEY& key) +{ + const bool ALLOWMODS(true); + return overwrite(pAuto.release(), key, ALLOWMODS); //SG takes ownership +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(T* pObject, const TKEY& key) +{ + const bool ALLOWMODS(true); + return record(pObject, key, ALLOWMODS); //allow mods by default +} +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(const T* pObject, const TKEY& key) +{ + const bool NOMODS(false); + return record(const_cast<T*>(pObject), key, NOMODS); // do not allow mods +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(T* pObject, const TKEY& key, + bool allowMods, bool resetOnly, bool noHist) +{ + return record1 (SG::asStorable<T>(pObject), pObject, key, + allowMods, resetOnly, noHist); +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record1(DataObject* obj, + T* pObject, const TKEY& key, + bool allowMods, bool resetOnly, bool noHist) +{ +#ifndef __clang__ + BOOST_CONCEPT_ASSERT( (KeyConcept<TKEY>) ); +#endif + // make sure the BaseInfo(Base) structure is initialized + SG::BaseInfo<T>::baseinfo(); + + // If s_isConst is set for this type, then we want to automatically + // make it const when recorded. + if (ClassID_traits<T>::s_isConst) + allowMods = false; + + StatusCode sc = typeless_record( obj, key, pObject, allowMods, resetOnly, noHist, + &typeid(T)); +#ifndef NDEBUG + if (sc.isSuccess()) { + SG_MSG_DEBUG( + "Recorded object @" << pObject + << " with key " << (std::string)key + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() + << ")\n in DataObject @" << obj + << "\n object " << (allowMods ? "" : "not ") + << "modifiable when retrieved"); + } +#endif + + return sc; +} + +#if __cplusplus > 201100 +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(std::unique_ptr<T> pUnique, const TKEY& key) +{ + const bool ALLOWMODS(true); + return record(std::move(pUnique), key, ALLOWMODS); //allow mods by default +} +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(std::unique_ptr<const T> pUnique, + const TKEY& key) +{ + const bool NOMODS(false); + T* ptr = const_cast<T*> (pUnique.release()); + return record1(SG::asStorable (ptr), ptr, + key, NOMODS); // do not allow mods +} + +//------------------------------------------------------------------- +template <typename T, typename TKEY> +StatusCode SGImplSvc::record(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool resetOnly, bool noHist) +{ + T* ptr = pUnique.get(); + return record1 (SG::asStorable<T>(std::move(pUnique)), ptr, key, + allowMods, resetOnly, noHist); +} +#endif + +template <typename T, typename TKEY> +StatusCode SGImplSvc::overwrite1(DataObject* obj, T* pObject, + const TKEY& key, + bool allowMods, bool noHist) +{ +#ifndef __clang__ + BOOST_CONCEPT_ASSERT( (KeyConcept<TKEY>) ); +#endif + // make sure the BaseInfo(Base) structure is initialized + SG::BaseInfo<T>::baseinfo(); + + // If s_isConst is set for this type, then we want to automatically + // make it const when recorded. + if (ClassID_traits<T>::s_isConst) allowMods = false; + + StatusCode sc = typeless_overwrite(ClassID_traits<T>::ID(), obj, key, + pObject, allowMods, noHist, + &typeid(T)); +#ifndef NDEBUG + if (sc.isSuccess()) { + SG_MSG_DEBUG( + "overwrite: Recorded object @" << pObject + << " with key " << (std::string)key + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() + << ")\n in DataObject @" << obj + << "\n object " << (allowMods ? "" : "not ") + << "modifiable when retrieved"); + } +#endif + return sc; +} + +template <typename T, typename TKEY> +StatusCode SGImplSvc::overwrite(T* p2BRegistered, const TKEY& key) +{ + const bool ALLOWMODS(true); + return overwrite(p2BRegistered, key, ALLOWMODS); //SG takes ownership +} + + +template <typename T, typename TKEY> +StatusCode SGImplSvc::overwrite(T* pObject, const TKEY& key, + bool allowMods, bool noHist) +{ + return overwrite1 (SG::asStorable<T>(pObject), pObject, key, + allowMods, noHist); +} + +#if __cplusplus > 201100 +template <typename T, typename TKEY> +StatusCode SGImplSvc::overwrite(std::unique_ptr<T> pUnique, const TKEY& key) +{ + const bool ALLOWMODS(true); + return overwrite(std::move(pUnique), key, ALLOWMODS); //allow mods by default +} + +template <typename T, typename TKEY> +StatusCode SGImplSvc::overwrite(std::unique_ptr<T> pUnique, const TKEY& key, + bool allowMods, bool noHist) +{ + T* ptr = pUnique.get(); + return overwrite1 (SG::asStorable<T>(std::move(pUnique)), ptr, key, + allowMods, noHist); +} +#endif + +//------------------------------------------------------------------- +template <typename T, typename AKEY> +StatusCode SGImplSvc::setAlias(const T* pObject, const AKEY& aKey) +{ + boost::function_requires< KeyConcept<AKEY> > (); + std::string aliasKey(aKey); + + SG::DataProxy* dp(0); + dp = proxy(pObject); + if (0 == dp) { + msg() << MSG::ERROR << "setAlias: problem setting alias " + << aliasKey << '\n' + << "DataObject does not exist, record before setting alias." + << endmsg; + return StatusCode::FAILURE; + } + + StatusCode sc = addAlias(aliasKey, dp); + if (sc.isFailure()) { + msg() << MSG::ERROR << "setAlias: problem setting alias " + << aliasKey << '\n' + << "DataObject does not exist, record before setting alias." + << endmsg; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} +//------------------------------------------------------------------- +template <typename T, typename TKEY, typename AKEY> +StatusCode SGImplSvc::setAlias(const T* /*pObject*/, + const TKEY& key, const AKEY& aKey) +{ +#ifndef __clang__ + BOOST_CONCEPT_ASSERT( (KeyConcept<TKEY>) ); + BOOST_CONCEPT_ASSERT( (KeyConcept<AKEY>) ); +#endif + + SG::DataProxy* dp(0); + dp = proxy(ClassID_traits<T>::ID(), key); + if (0 == dp) { + msg() << MSG::ERROR << "setAlias: problem setting alias " + << std::string(aKey) << '\n' + << "DataObject does not exist, record before setting alias." + << endmsg; + return StatusCode::FAILURE; + } + + StatusCode sc = addAlias(aKey, dp); + if (sc.isFailure()) { + msg() << MSG::ERROR << "setAlias: problem setting alias " + << (std::string)aKey << '\n' + << "DataObject does not exist, record before setting alias." + << endmsg; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; + +} +//------------------------------------------------------------------- + + +////////////////////////////////////////////////////////////////// +// Make a soft link to the object with key: return non_const link +////////////////////////////////////////////////////////////////// +template <typename T, typename TLINK> +StatusCode SGImplSvc::symLink(const T* pObject, TLINK*) +{ + SG::DataProxy* dp(proxy(pObject)); + CLID linkID = ClassID_traits<TLINK>::ID(); + + // if symLink already exists, just return success + return isSymLinked(linkID,dp) ? + StatusCode::SUCCESS : + addSymLink(linkID,dp); +} + +////////////////////////////////////////////////////////////////// +// Make a soft link to the object with key: set const link +////////////////////////////////////////////////////////////////// +template <typename T, typename TLINK> +StatusCode SGImplSvc::symLink(const T* pObject, const TLINK*) +{ + SG::DataProxy* dp(proxy(pObject)); + CLID linkID = ClassID_traits<TLINK>::ID(); + // if symLink already exists, just return success + return isSymLinked(linkID,dp) ? + StatusCode::SUCCESS : + addSymLink(linkID,dp); +} + +template <typename TKEY> +StatusCode SGImplSvc::symLink(const CLID& id, const TKEY& key, const CLID& linkID) +{ +#ifndef __clang__ + //FIXME we have no way to check that the type represented by ID (the primary) + //FIXME is convertible into the linkid type. VERY BAD. Need introspection??? + BOOST_CONCEPT_ASSERT( (KeyConcept<TKEY>) ); +#endif + SG::DataProxy* dp(proxy(id, key, false)); + // if symLink already exists, just return success + return isSymLinked(linkID,dp) ? + StatusCode::SUCCESS : + addSymLink(linkID,dp); +} + + +////////////////////////////////////////////////////////////////// +// Retrieve the default object (with no key) as a const pointer +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::retrieve(const T*& ptr) +{ + const DataHandle<T> handle; + StatusCode sc = retrieve(handle); + try { + ptr = sc.isSuccess() ? handle.cptr() : 0; + } catch (...) { + ptr = 0; + } + if (0 == ptr) sc = StatusCode::FAILURE; + return sc; +} + +////////////////////////////////////////////////////////////////// +// Retrieve the default object (with no key) as a pointer (non-const) +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::retrieve(T*& ptr) +{ + DataHandle<T> handle; + StatusCode sc = retrieve(handle); + try { + ptr = sc.isSuccess() ? handle.ptr() : 0; + } catch (...) { + ptr = 0; + } + if (0 == ptr) sc = StatusCode::FAILURE; + return sc; +} + +////////////////////////////////////////////////////////////////// +// Retrieve the keyed object as a const pointer +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode SGImplSvc::retrieve(const T*& ptr, const TKEY& key) +{ + + const DataHandle<T> handle; + StatusCode sc = retrieve(handle, key); + try { + ptr = sc.isSuccess() ? handle.cptr() : 0; + } catch (...) { + ptr = 0; + } + if (0 == ptr) sc = StatusCode::FAILURE; + return sc; +} + +////////////////////////////////////////////////////////////////// +// Retrieve the keyed object as a non-const pointer +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode SGImplSvc::retrieve(T*& ptr, const TKEY& key) +{ + + DataHandle<T> handle; + StatusCode sc = retrieve(handle, key); + try { + ptr = sc.isSuccess() ? handle.ptr() : 0; + } catch (...) { + ptr = 0; + } + if (0 == ptr) sc = StatusCode::FAILURE; + + return sc; +} + + +////////////////////////////////////////////////////////////////// +// Retrieve the default object (with no key) as a const DataHandle +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::retrieve(const DataHandle<T>& handle) +{ + SG::DataProxy* dp(proxy(ClassID_traits<T>::ID())); + StatusCode sc = handle.setState(dp); + + if (sc.isFailure()) { + msg() << MSG::WARNING + << "retrieve(default): No valid proxy for default object \n" + << " of type " << ClassID_traits<T>::typeName() << "(CLID " + << ClassID_traits<T>::ID() << ')' << endmsg; + } else { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); +#ifndef NDEBUG + SG_MSG_DEBUG("retrieve(default): Retrieved const handle to default object \n" + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() << ')'); +#endif + addedNewPersObject(ClassID_traits<T>::ID(), dp); + } + return sc; +} + +////////////////////////////////////////////////////////////////// +// Retrieve the default object (with no key) as a non-const DataHandle +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::retrieve(DataHandle<T>& handle) +{ + + SG::DataProxy* dp(proxy(ClassID_traits<T>::ID())); + StatusCode sc = handle.setState(dp); + + if (sc.isFailure()) { + msg() << MSG::WARNING + << "retrieve(default): No valid proxy for default object " + << " of type " << ClassID_traits<T>::typeName() << "(CLID " + << ClassID_traits<T>::ID() << ")\n Try to use a const DataHandle " + << endmsg; + } else { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); +#ifndef NDEBUG + SG_MSG_DEBUG("Retrieved non-const handle to default object " + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() << ')'); +#endif + addedNewPersObject(ClassID_traits<T>::ID(), dp); + } + + return sc; +} + +////////////////////////////////////////////////////////////////// +// Retrieve the keyed object as a const DataHandle +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode SGImplSvc::retrieve(const DataHandle<T>& handle, + const TKEY& key) +{ +#ifndef __clang__ + BOOST_CONCEPT_ASSERT( (KeyConcept<TKEY>) ); +#endif + + SG::DataProxy* dp(proxy(ClassID_traits<T>::ID(), (std::string)key, false)); + StatusCode sc = handle.setState(dp); + + if (sc.isFailure()) { + msg() << MSG::WARNING + << "retrieve(const): No valid proxy for object " << key << ' ' + << " of type " << ClassID_traits<T>::typeName() << "(CLID " + << ClassID_traits<T>::ID() << ')' << endmsg; + } else { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); +#ifndef NDEBUG + SG_MSG_DEBUG( "Retrieved const handle to object " << key << ' ' + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() << ')'); +#endif + addedNewPersObject(ClassID_traits<T>::ID(), dp); + } + return sc; + +} +////////////////////////////////////////////////////////////////// +// Retrieve the keyed object as a non-const DataHandle +////////////////////////////////////////////////////////////////// +template <typename T, typename TKEY> +StatusCode SGImplSvc::retrieve(DataHandle<T>& handle, + const TKEY& key) +{ +#ifndef __clang__ + BOOST_CONCEPT_ASSERT( (KeyConcept<TKEY>) ); +#endif + + SG::DataProxy* dp(proxy(ClassID_traits<T>::ID(), (std::string)key, false)); + StatusCode sc = handle.setState(dp); + + if (sc.isFailure()) { + SG_MSG_WARNING("retrieve(non-const): No valid proxy for object " + << (std::string)key << ' ' + << " of type " << ClassID_traits<T>::typeName() << "(CLID " + << ClassID_traits<T>::ID() + << ") \n Try to use a const DataHandle" ); + } else { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); +#ifndef NDEBUG + SG_MSG_DEBUG("Retrieved non-const handle to object " << (std::string)key + << ' ' << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() << ')'); +#endif + addedNewPersObject(ClassID_traits<T>::ID(), dp); + } + return sc; + +} + +////////////////////////////////////////////////////////////////// +// Retrieve a list of collections from Transient Store with no Key. +// const version +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::retrieve(SG::ConstIterator<T>& cibegin, + SG::ConstIterator<T>& ciend ) +{ + const DataHandle<T> chbegin, chend; + StatusCode sc = this->retrieve(chbegin, chend); + if (sc.isSuccess()) { + cibegin=SG::ConstIterator<T>(chbegin); + ciend=SG::ConstIterator<T>(chend); + } + //FIXME no associateAux + return sc; +} + +////////////////////////////////////////////////////////////////// +// Retrieve a list of collections from Transient Store with no Key. +// const version +////////////////////////////////////////////////////////////////// +template <typename T> +StatusCode SGImplSvc::retrieve(const DataHandle<T>& chbegin, + const DataHandle<T>& chend ) +{ + SG::ConstProxyIterator first; + SG::ConstProxyIterator end = first; + + if (!(proxyRange(ClassID_traits<T>::ID(),first,end)).isSuccess()) { +#ifndef NDEBUG + SG_MSG_DEBUG("retrieve(range): no object found " + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() << ')'); +#endif + } + + (chend.setState(end, end)).ignore(); + + if (!(chbegin.setState(first, end)).isSuccess()) { +#ifndef NDEBUG + SG_MSG_DEBUG("retrieve(range): Can't set DataHandle for object range " + << " of type " << ClassID_traits<T>::typeName() + << "(CLID " << ClassID_traits<T>::ID() << ')'); +#endif + return StatusCode::FAILURE; + } + + //FIXME no associateAux + SG::ConstProxyIterator idp(first); + while (idp != end) addedNewPersObject(ClassID_traits<T>::ID(), idp++->second); + + return StatusCode::SUCCESS; +} + + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. + * @param key The key to use for the lookup. + **/ +template <typename T> +T* SGImplSvc::retrieve () +{ + T* p = 0; + retrieve (p).ignore(); + return p; +} + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. + * @param key The key to use for the lookup. + **/ +template <typename T, class TKEY> +T* SGImplSvc::retrieve (const TKEY& key) +{ + T* p = 0; + retrieve (p, key).ignore(); + return p; +} + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. + * @param key The key to use for the lookup. + **/ +template <typename T> +T* SGImplSvc::tryRetrieve () +{ + //FIXME should call addNewPersObject + DataHandle<T> handle; + if (handle.setState(proxy(ClassID_traits<T>::ID())).isSuccess()) { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); + return handle.ptr(); + } else return 0; +} + +template <typename T> +const T* SGImplSvc::tryConstRetrieve() +{ + //FIXME should call addNewPersObject + const DataHandle<T> handle; + if (handle.setState(proxy(ClassID_traits<T>::ID())).isSuccess()) { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); + return handle.cptr(); + } else return 0; +} + +/** + * @brief Retrieve an object of type @c T from storegate. + * Return 0 if not found. Don't print any WARNINGs + * @param key The key to use for the lookup. + **/ +template <typename T, class TKEY> +T* SGImplSvc::tryRetrieve (const TKEY& key) +{ + DataHandle<T> handle; + if ( handle.setState(proxy(ClassID_traits<T>::ID(), key, false)).isSuccess() ) { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); + return handle.ptr(); + } else return 0; +} + +template <typename T, class TKEY> +const T* SGImplSvc::tryConstRetrieve (const TKEY& key) +{ + const DataHandle<T> handle; + if ( handle.setState(proxy(ClassID_traits<T>::ID(), key, false)).isSuccess() ) { + //for types with an associated store, try to retrieve it and associate it + this->associateAux(handle); + return handle.cptr(); + } else return 0; +} + +/** + * @brief Retrieve an object of type @c T from storegate and associate it + * to its auxiliary store + * Return 0 the object or the aux store is not found. + * @param key The key to use for the lookup. + **/ +template <typename T, class TKEY> +T* SGImplSvc::retrieveAux (const TKEY& key) +{ + //FIXME should call addNewPersObject + DataHandle<T> handle; + StatusCode sc = retrieve(handle, key); + const bool REQUIREAUX(false); + return (sc.isSuccess() && associateAux(handle, REQUIREAUX)) ? + handle.ptr() : + 0; +} + +template <typename T, class TKEY> +const T* SGImplSvc::constRetrieveAux (const TKEY& key) +{ + //FIXME should call addNewPersObject + const DataHandle<T> handle; + StatusCode sc = retrieve(handle, key); + const bool REQUIREAUX(false); + return (sc.isSuccess() && associateAux(handle, REQUIREAUX)) ? + handle.cptr() : + 0; +} + +template <typename T> +std::auto_ptr<T> +SGImplSvc::readPrivateCopy (const std::string& key) +{ + return std::auto_ptr<T>(SG::Storable_cast<T>( + this->typeless_readPrivateCopy(ClassID_traits<T>::ID(), key))); +} + + +template <typename T> +std::unique_ptr<T> +SGImplSvc::readUniquePrivateCopy (const std::string& key) +{ + return std::unique_ptr<T>(SG::Storable_cast<T>( + this->typeless_readPrivateCopy(ClassID_traits<T>::ID(), key))); +} + + +template <typename T> +std::auto_ptr<T> +SGImplSvc::retrievePrivateCopy (const std::string& key) +{ + const T* p = 0; + //we do not want anyone to mess up with our copy hence we release it + //immediately + if(this->retrieve (p, key).isSuccess()) { + this->releaseObject(ClassID_traits<T>::ID(), key); + } + return std::auto_ptr<T>(const_cast<T*>(p)); +} + + +template <typename T> +std::unique_ptr<T> +SGImplSvc::retrieveUniquePrivateCopy (const std::string& key) +{ + const T* p = 0; + //we do not want anyone to mess up with our copy hence we release it + //immediately + if(this->retrieve (p, key).isSuccess()) { + this->releaseObject(ClassID_traits<T>::ID(), key); + } + return std::unique_ptr<T>(const_cast<T*>(p)); +} + + +////////////////////////////////////////////////////////////////// +// Retrieve the @c CLID of a given "key" +// WARNING: slow! +////////////////////////////////////////////////////////////////// +template<typename TKEY> +CLID SGImplSvc::clid( const TKEY& key ) const +{ + SG::DataStore::ConstStoreIterator s_iter, s_end; + store()->tRange(s_iter, s_end).ignore(); + + for ( ; s_iter != s_end; ++s_iter ) { + if ( s_iter->second.find( key ) != s_iter->second.end() ) { + return s_iter->first; + } + } + + return CLID_NULL; +} +////////////////////////////////////////////////////////////////// +// Retrieve the @c CLID s of a given "key" +// WARNING: slow! +////////////////////////////////////////////////////////////////// +template<typename TKEY> +std::vector<CLID> SGImplSvc::clids( const TKEY& key ) const +{ + std::list<CLID> clids; + SG::DataStore::ConstStoreIterator s_iter, s_end; + store()->tRange(s_iter, s_end).ignore(); + + for ( ; s_iter != s_end; ++s_iter ) { + if ( s_iter->second.find( key ) != s_iter->second.end() ) { + clids.push_back(s_iter->first); + } + } + + return std::vector<CLID>(clids.begin(), clids.end()); +} + +//-------------------------end of retrieve methods-------------------- +template <typename T> +int SGImplSvc::typeCount() const +{ + return typeCount(ClassID_traits<T>::ID()); +} + +template <typename T, typename TKEY> +bool +SGImplSvc::contains(const TKEY& key) const +{ + return contains(ClassID_traits<T>::ID(), key); +} + + +template <typename TKEY> +bool +SGImplSvc::contains(const CLID& id, const TKEY& key) const +{ + try { + return (0 != proxy(id, key, true)); + } catch(...) { return false; } +} + + +template <typename T, typename TKEY> +bool +SGImplSvc::transientContains(const TKEY& key) const +{ + return transientContains(ClassID_traits<T>::ID(), key); +} + + +template <typename TKEY> +bool +SGImplSvc::transientContains(const CLID& id, const TKEY& key) const +{ + try { + return (0 != transientProxy(id, key)); + } catch(...) { return false; } +} + +//-------------------------end of contains methods-------------------- +template <typename T> +void +SGImplSvc::keys(std::vector<std::string>& vkeys, + bool includeAlias, bool onlyValid) { + return this->keys(ClassID_traits<T>::ID(), vkeys, includeAlias, onlyValid); +} + +// DEPRECATED +template <typename T> +std::vector<std::string> SGImplSvc::keys(bool allKeys) +{ + return this->keys(ClassID_traits<T>::ID(), allKeys); +} +// DEPRECATED +inline +std::vector<std::string> +SGImplSvc::keys(const CLID& id, bool allKeys) { + std::vector<std::string> vkeys; + this->keys(id, vkeys, allKeys); + return vkeys; +} + +// remove an object from Store, will remove its proxy if not reset only +template <typename T> +StatusCode +SGImplSvc::remove(const T* pObject) +{ + return removeProxy(proxy(pObject), pObject); +} + +// remove an object and its proxy from Store +template <typename T> +StatusCode +SGImplSvc::removeDataAndProxy(const T* pObject) +{ + const bool FORCEREMOVE(true); + return removeProxy(proxy(pObject), pObject, FORCEREMOVE); +} + +// utility method put a dobj pointer in a bucket as appropriate +template <typename T> +DataObject* +SGImplSvc::asStorable(T* pDObj) { + return SG::asStorable(pDObj); +} + +// utility method gets a dobj pointer from a bucket as appropriate +template <typename T> +bool +SGImplSvc::fromStorable(DataObject* pObject, T*& pData) { + return SG::fromStorable(pObject, pData); +} + +// deprecated method temporary forwarding to the new one +inline +StatusCode +SGImplSvc::createProxy(IOpaqueAddress* pAddress, bool clearAddressFlag) +{ + return recordAddress(pAddress, clearAddressFlag); +} + +//obsolete temporary forwarding to new one +inline +SG::DataProxy* +SGImplSvc::setupProxy(const CLID& dataID, + const std::string& gK, + DataObject* pDObj) { + return setupProxy(dataID, gK, pDObj, true, true); +} + +/////////////////////////////////////////////////////////////////////////// + +template <typename T, typename TKEY> +StatusCode +SGImplSvc::bind(const DataHandle<T>& handle, const TKEY& key) { + const IResetable *ir = &handle; + SG::DataProxy *dp = 0; + if (!(bindHandleToProxy(ClassID_traits<T>::ID(), key, + const_cast<IResetable*>(ir),dp) )) + { + return StatusCode::FAILURE; + } else + { + return (handle.setState(dp)); // FIXME - should be retrieve? + } +} + + +/////////////////////////////////////////////////////////////////////////// + +inline +void +SGImplSvc::setProxyProviderSvc(IProxyProviderSvc* pPPSvc) { + m_pPPS = pPPSvc; +} + +////////////////////////////////////////////////////////////////// + +template <typename H, typename TKEY> +StatusCode +SGImplSvc::regHandle(const DataHandle<H>& handle, const TKEY& key) { + + CLID id = ClassID_traits<H>::ID(); + std::string tname; + (m_pCLIDSvc->getTypeNameOfID(id, tname)).ignore(); + + std::string fullname = tname + "[" + key + "]"; + +#ifndef NDEBUG + SG_MSG_VERBOSE("regHandle: " << fullname); +#endif + // bind the handle to the key, creates an invalid DataProxy + if (bind(handle,key).isFailure()) { + msg() << MSG::ERROR << "regHandle: could not bind handle to " << tname + << " to key: " << key << endmsg; + return StatusCode::FAILURE; + } + + // register the proxy + SG::DataProxy* dp = proxy(id,key,false); //specify "false" to disambiguate on MAC + + if ( dp == 0 ) { + msg() << MSG::ERROR << "could not get proxy for handle " << fullname + << endmsg; + return StatusCode::FAILURE; + } + + std::string skey = key; + + StatusCode sc = getIIOVSvc()->regProxy(dp,skey); + + return sc; + +} + +////////////////////////////////////////////////////////////////// + +template <typename H, typename TKEY> +StatusCode +SGImplSvc::regHandle( DataHandle<H>& /*handle*/, + const TKEY& key) { + + CLID id = ClassID_traits<H>::ID(); + std::string tname; + (m_pCLIDSvc->getTypeNameOfID(id, tname)).ignore(); + + std::string fullname = tname + "[" + key + "]"; + msg() << MSG::ERROR << "regHandle(): DataHandle must be const: " << fullname + << endmsg; + + return StatusCode::FAILURE; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T, typename H, typename TKEY> +StatusCode +SGImplSvc::regFcn(StatusCode (T::*/*updFcn*/)(IOVSVC_CALLBACK_ARGS), + const T* /*obj*/, DataHandle<H>& /*handle*/, + const TKEY& key, bool /*trigger*/) { + + CLID id = ClassID_traits<H>::ID(); + std::string tname; + m_pCLIDSvc->getTypeNameOfID(id, tname).ignore(); + + std::string fullname = tname + "[" + key + "]"; + + msg() << MSG::ERROR << "regFcn(): DataHandle must be const: " << fullname + << endmsg; + + return StatusCode::FAILURE; + +} +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T, typename H, typename TKEY> +StatusCode +SGImplSvc::regFcn(StatusCode (T::*updFcn)(IOVSVC_CALLBACK_ARGS), + const T* obj, const DataHandle<H>& handle, + const TKEY& key, bool trigger) { + + CLID id = ClassID_traits<H>::ID(); + std::string tname; + m_pCLIDSvc->getTypeNameOfID(id, tname).ignore(); + + std::string fullname = tname + "[" + key + "]"; + + // bind the handle to the key, creates an invalid DataProxy + if (bind(handle,key).isFailure()) { + msg() << MSG::ERROR << "regFcn: could not bind handle to " << tname + << " to key: " << key << endmsg; + return StatusCode::FAILURE; + } + + // register the proxy + SG::DataProxy* dp = proxy(id, std::string(key)); + + if ( dp == 0 ) { + msg() << MSG::ERROR << "could not get proxy for handle " << fullname + << endmsg; + return StatusCode::FAILURE; + } + + if (getIIOVSvc()->regProxy(dp,key).isFailure()) { + return StatusCode::FAILURE; + } + + const CallBackID c(updFcn,obj); + + IOVSvcCallBackFcn fcn(boost::bind(updFcn,const_cast<T*>(obj),_1,_2)); + + return ( getIIOVSvc()->regFcn(dp,c,fcn,trigger) ); + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T1, typename T2> +StatusCode +SGImplSvc::regFcn( StatusCode (T1::*updFcn1)(IOVSVC_CALLBACK_ARGS), + const T1* obj1, + StatusCode (T2::*updFcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, + bool trigger) { + + + const CallBackID c1(updFcn1, obj1); + const CallBackID c2(updFcn2, obj2); + + IOVSvcCallBackFcn fcn2( boost::bind(updFcn2,const_cast<T2*>(obj2),_1,_2)); + + return ( getIIOVSvc()->regFcn(c1,c2,fcn2,trigger) ); + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +template <typename T2> +StatusCode +SGImplSvc::regFcn( const std::string& toolName, + StatusCode (T2::*updFcn2)(IOVSVC_CALLBACK_ARGS), + const T2* obj2, + bool trigger) { + + + const CallBackID c2(updFcn2, obj2); + + IOVSvcCallBackFcn fcn2( boost::bind(updFcn2,const_cast<T2*>(obj2),_1,_2)); + + return ( getIIOVSvc()->regFcn(toolName,c2,fcn2,trigger) ); + +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/// Retrieve version with highest cycle number for a given T,KEY combination +/// If there is only one available version of this data object +/// the returned ObjectWithVersion<T>.versionedKey is set to requestedKey +/// NOTICE that this method is significantly slower than +/// retrieve(const T*, const TKEY&) +/// which returns the last recorded version rather than the one with the +/// highest cycle number. +/// @returns StatusCode::FAILURE if no dataObject found +template <typename T, class TKEY> +StatusCode +SGImplSvc::retrieveHighestVersion(SG::ObjectWithVersion<T>& dobjWithVersion, + const TKEY& requestedKey) { + std::list< SG::ObjectWithVersion<T> > allVersions; + StatusCode sc(this->retrieveAllVersions(allVersions,requestedKey)); + if (sc.isSuccess()) { + allVersions.sort(); // on highest version number + dobjWithVersion.versionedKey.copyVK(allVersions.back().versionedKey.rawVersionKey()); + } + return sc; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/// Retrieve all versions of a given T,KEY combination +/// sets allVersions, a ref to a vector of ObjectWithVersion<T> +/// If there is only one available version of this dataObject +/// allVersions[0].versionedKey is set to requestedKey. +/// @returns StatusCode::FAILURE if no dataObject found +template <typename T, class TKEY> +StatusCode +SGImplSvc::retrieveAllVersions(std::list< SG::ObjectWithVersion<T> >& allVersions, + const TKEY& requestedKey) { + StatusCode sc(StatusCode::FAILURE); + const DataHandle<T> i,e; + if ((this->retrieve<T>(i,e)).isSuccess()){ + SG::VersionedKey reqVK(requestedKey); + while (i != e) { + SG::VersionedKey vk(i.key()); + if (reqVK.sameKey(vk)) { + sc = StatusCode::SUCCESS; + SG::ObjectWithVersion<T> okOWV(vk, i); + allVersions.push_back(okOWV); + } + ++i; + } + } + return sc; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/** + * @brief Declare a remapping. + * @brief clid Class ID of the container being remapped. + * @brief source Key of the container being remapped. + * @brief target Key of the container being remapped to. + * @brief index_offset Amount by which the index should be adjusted + * between the two containers. + * + * This can be used to change the container to which @c ElementLink's + * (and @c DataLink's) point on output. + * + * For example, suppose you have two containers of type T, A and B. + * There possibly are @c ElementLink's pointing at elements contained + * in them. You want to change to a single container C, containing + * the contents of A and B concatenated. To get @c ElementLink's + * updated on output, you can do: + * + *@code + * m_sg->remap (ClassID_traits<T>::ID(), "A", "C", 0); + * m_sg->remap (ClassID_traits<T>::ID(), "B", "C", a.size());; + @endcode +*/ +template <class TKEY> +void SGImplSvc::remap (CLID clid, + const TKEY& source, + const TKEY& target, + off_t index_offset) +{ + this->remap_impl (this->stringToKey (source, clid), + this->stringToKey (target, clid), + index_offset); +} + + + +/** + * @brief associate a data object to its auxiliary store + * Return false if the aux store is not found. + * @param key The key to use for the lookup. + **/ +template <class DOBJ, class AUXSTORE> +bool SGImplSvc::associateAux_impl(DataHandle<DOBJ>& handle, const AUXSTORE*) +{ + const std::string& key(handle.key()); + SG_MSG_VERBOSE("called associateAux_impl non const for key " + key); + DOBJ* pDObj(handle.ptr()); + bool hasAux(0 != pDObj->hasStore()); + // no Aux store set yet + if (!hasAux) { + AUXSTORE* pAux = tryRetrieve<AUXSTORE>(key + "Aux." ); + hasAux = (0 != pAux); + if (hasAux) pDObj->setStore( pAux ); + } + return hasAux; +} + +/** + * @brief associate a data object to its auxiliary store + * Return false if the aux store is not found. + * @param key The key to use for the lookup. + **/ +template <class DOBJ, class AUXSTORE> +bool SGImplSvc::associateAux_impl(const DataHandle<DOBJ>& handle, const AUXSTORE*) +{ + const std::string& key(handle.key()); + SG_MSG_VERBOSE("called associateAux_impl const for key " + key); + const DOBJ* pDObj(handle.cptr()); + bool hasAux(0 != pDObj->hasStore()); + // no Aux store set yet + if (!hasAux) { + const AUXSTORE* pAux = tryConstRetrieve<AUXSTORE>(key + "Aux." ); + hasAux = (0 != pAux); + if (hasAux) const_cast< DOBJ* >(pDObj)->setStore( const_cast< AUXSTORE* >(pAux) ); + } + return hasAux; +} + +/** + * @brief associate a data object to its auxiliary store + * Return false if the aux store is not found. + * @param key The key to use for the lookup. + **/ +template <class DOBJ> +bool SGImplSvc::associateAux (DataHandle<DOBJ>& handle, bool ignoreMissing) +{ + typename SG::AuxStore_traits<DOBJ>::type* pDummy(0); //used to pass down auxstore type + bool hasAux=associateAux_impl(handle, pDummy) || ignoreMissing; + if (!hasAux) SG_MSG_WARNING("associateAux const: Could not associate AuxStore of type " + << SG::AuxStore_traits<DOBJ>::const_typeName() + << "\n to object of type " << ClassID_traits<DOBJ>::typeName() << "(CLID " + << ClassID_traits<DOBJ>::ID() << ") with key " << handle.key() << endmsg); + return hasAux; +} + +template <class DOBJ> +bool SGImplSvc::associateAux (const DataHandle<DOBJ>& handle, bool ignoreMissing) +{ + typename SG::AuxStore_traits<DOBJ>::const_type* pDummy(0); //used to pass down auxstore type + bool hasAux=associateAux_impl(handle, pDummy) || ignoreMissing; + if (!hasAux) SG_MSG_WARNING("associateAux const: Could not associate AuxStore of type " + << SG::AuxStore_traits<DOBJ>::const_typeName() + << "\n to object of type " << ClassID_traits<DOBJ>::typeName() << "(CLID " + << ClassID_traits<DOBJ>::ID() << ") with key " << handle.key() << endmsg); + return hasAux; +} +#endif // STOREGATE_SGIMPLSVC_ICC diff --git a/EDM/athena/Control/StoreGate/StoreGate/tools/StorableConversions.h b/EDM/athena/Control/StoreGate/StoreGate/tools/StorableConversions.h new file mode 100644 index 00000000..a3c491a8 --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/tools/StorableConversions.h @@ -0,0 +1,20 @@ +/* -*- C++ -*- */ + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef STOREGATE_TOOLS_STORABLECONVERSIONS_H +# define STOREGATE_TOOLS_STORABLECONVERSIONS_H + +/** @file StorableConversions.h + * @brief TEMPORARY forwarding to SGTools + * @author Paolo Calafiura <pcalafiura@lbl.gov> - ATLAS Collaboration + *$Id: StorableConversions.h,v 1.7 2003-04-02 23:12:21 calaf Exp $ + */ +# warning deprecated include file: forwarding to SGTools/StorableConversions.h +#ifndef SGTOOLS_STORABLECONVERSIONS_H +# include "SGTools/StorableConversions.h" +#endif + +#endif // TOOLS_STORABLECONVERSIONS_H diff --git a/EDM/athena/Control/StoreGate/StoreGate/tools/hash_functions.h b/EDM/athena/Control/StoreGate/StoreGate/tools/hash_functions.h new file mode 100644 index 00000000..bd12092d --- /dev/null +++ b/EDM/athena/Control/StoreGate/StoreGate/tools/hash_functions.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef HASH_FUNCTIONS_H +#define HASH_FUNCTIONS_H + +#include <functional> +#include <string> + +namespace SG { + ///simple hash function derived from Sedgewick Algorithms in C++ 3rd ed + ///@param str the string to be hashed + ///@param maxInt the maximum value the function returns. + /// Hash collision probability is 1/min(maxInt, 2**127) + inline int simpleStringHash(std::string str, int maxInt=0xFFFF) { + int h(0), a(127); + for (std::string::size_type iC=0; iC<str.size(); iC++) + h = (a*h + str[iC]) % maxInt; + return h; + } + +} + +#endif + + + diff --git a/EDM/athena/Control/StoreGate/cmt/requirements b/EDM/athena/Control/StoreGate/cmt/requirements new file mode 100644 index 00000000..a3cd2525 --- /dev/null +++ b/EDM/athena/Control/StoreGate/cmt/requirements @@ -0,0 +1,72 @@ +package StoreGate + +author Paolo Calafiura <Paolo.Calafiura@cern.ch> +author Hong Ma <hma@bnl.gov> +author Srini Rajagopalan <srinir@bnl.gov> +author Wim Lavrijsen <WLavrijsen@lbl.gov> + +use AtlasPolicy AtlasPolicy-* + +use AthenaKernel AthenaKernel-* Control +#need ClassID_traits.h, CLASS_DEF.h +use SGTools SGTools-* Control + +use AtlasBoost AtlasBoost-* External +use AtlasTBB AtlasTBB-* External +use GaudiInterface GaudiInterface-* External + +use AthAllocators AthAllocators-* Control +use AthContainersInterfaces AthContainersInterfaces-* Control + +# Inform cmake that this package has private header files (transparent to CMT) +apply_pattern cmake_add_command command="include_directories(src)" + +private +use CxxUtils CxxUtils-* Control +end_private + +apply_pattern dual_use_library files=*.cxx + +macro_append cppflags "" \ + gcc-3 " -DHAVE_ITERATOR -DHAVE_NEW_IOSTREAMS " + +private + +apply_pattern install_runtime +apply_pattern declare_joboptions files="StoreGate_jobOptions.txt StoreGate_jobOptions.py SGHive_test.txt ActiveStore_test.txt" +apply_pattern declare_python_modules files="*.py" + +macro_append SGtests_dependencies "StoreGateLib" + +use TestTools TestTools-* AtlasTest +library SGtests ../test/SGtests.cxx +macro SGtests_shlibflags " $(componentshr_linkopts) $(use_linkopts) " +apply_pattern optdebug_library name=SGtests + +apply_pattern UnitTest_run unit_test=ActiveStore extrapatterns="JobOptionsSvc +INFO" +macro HIVEPATTERNS ".*" \ + ATHENAHIVE "JobOptionsSvc +INFO|StoreGateSvc.*DEBUG|HiveMgrSvc +DEBUG" +apply_pattern UnitTest_run unit_test=SGHive extrapatterns="$(HIVEPATTERNS)" +apply_pattern UnitTest_run unit_test=DataHandle extrapatterns="ClassIDSvc Initialized successfully|^HistogramPersis.* INFO" +apply_pattern UnitTest_run unit_test=SGIterator extrapatterns="^HistogramPersis.* INFO" + +apply_pattern UnitTest_run unit_test=KeyConcept +apply_pattern UnitTest_run unit_test=StoreClearedIncident +apply_pattern UnitTest_run unit_test=SegMemSvc extrapatterns="^HistogramPersis.* INFO" +apply_pattern UnitTest_run unit_test=exceptions +apply_pattern UnitTest_run unit_test=VarHandleKey +apply_pattern UnitTest_run unit_test=VarHandleKeyProperty +apply_pattern UnitTest_run unit_test=VarHandleProperty +apply_pattern UnitTest_run unit_test=ReadHandleKey +apply_pattern UnitTest_run unit_test=UpdateHandleKey +apply_pattern UnitTest_run unit_test=VarHandleBase extrapatterns="could not get proxy for|try using a ReadHandle" +apply_pattern UnitTest_run unit_test=VarHandles +apply_pattern UnitTest_run unit_test=WriteHandle +apply_pattern UnitTest_run unit_test=ReadHandle +apply_pattern UnitTest_run unit_test=UpdateHandle + +macro_append DOXYGEN_INPUT " ../test" +macro_append DOXYGEN_FILE_PATTERNS " *.icc" + +macro_append StoreGate_pp_cppflags " -Wno-deprecated " +end_private diff --git a/EDM/athena/Control/StoreGate/doc/MainPage.h b/EDM/athena/Control/StoreGate/doc/MainPage.h new file mode 100644 index 00000000..807298d5 --- /dev/null +++ b/EDM/athena/Control/StoreGate/doc/MainPage.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + + \mainpage + +%StoreGate is a toolkit to implement the Atlas Data Model. +It consists of four packages %StoreGate(this one), DataModel, SGComps, and SGTools. + +This package contains the client API to the Transient Data +Store. The core data access API is provided by +StoreGateSvc. StoreGateSvc manages the Data Objects in transient form +in collaboration with DataStore (SGTools pkg). The +transient/persistent conversion of each data object type is managed by +a DataProxy (again in SGTools). The DataProxy instances for object on disk +are added by a list of IAddressProvider services managed by the +ProxyProviderSvc (in SGComps). + +ActiveStoreSvc is not for general use: it allows to +access the instance of StoreGateSvc which is currently active (this is +used by classes dealing with multiple event stores, e.g. for pile-up studies). + +\section Examples Examples + +The package Control/AthenaExamples/AthExStoreGateExamples contains +running examples of algorithms accessing Data Objects using StoreGateSvc. +This examples are (very close to) the ones described in the tutorial above + +\section tests Unit Tests + +The directory test contains several test programs that can be run issuing +a "gmake check". + StoreGateSvcClient_test.cxx should cover most of the high-level client API. + +@section requirements file + +@include requirements + +@section Documentation + +The user guide is part of the Data Model User Guide which is +mantained in CVS +(http://atlas-sw.cern.ch/cgi-bin/viewcvs-atlas.cgi/offline/AtlasDoc/doc/DataModel/DataModel.pdf?rev=1.3). + +More information is available from the Athena wiki +(https://twiki.cern.ch/twiki/bin/view/Atlas/AthenaFramework#StoreGate_The_Data_Model_Archite) + +The code can be browsed using LXR +(http://alxr.usatlas.bnl.gov/lxr/source/atlas/Control/StoreGate/) + + +\author Paolo Calafiura <Paolo.Calafiura@cern.ch> +\author Hong Ma <hma@bnl.gov> +\author Srini Rajagopalan <srinir@bnl.gov> +*/ diff --git a/EDM/athena/Control/StoreGate/python/Bindings.py b/EDM/athena/Control/StoreGate/python/Bindings.py new file mode 100644 index 00000000..eba621e6 --- /dev/null +++ b/EDM/athena/Control/StoreGate/python/Bindings.py @@ -0,0 +1,23 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# File: StoreGate/python/Bindings.py +# Author: Wim Lavrijsen <WLavrijsen@lbl.gov> + +import PyCintex + +### data +__version__ = '2.0.0' +__author__ = 'Wim Lavrijsen (WLavrijsen@lbl.gov)' + +import warnings,os +msg = "'StoreGate.Bindings' module has been retired ! " + \ + "Please use StoreGateBindings.Bindings instead:" + \ + " 'import StoreGateBindings.Bindings'" +warnings.warn(msg, DeprecationWarning, stacklevel=2) + +### pythonization for StoreGateSvc +import StoreGateBindings.Bindings + +### enable proper redirection... +import sys +sys.modules['StoreGate.Bindings'] = sys.modules['StoreGateBindings.Bindings'] diff --git a/EDM/athena/Control/StoreGate/python/RedirectProxyProviderSvc.py b/EDM/athena/Control/StoreGate/python/RedirectProxyProviderSvc.py new file mode 100644 index 00000000..1d6b5d5c --- /dev/null +++ b/EDM/athena/Control/StoreGate/python/RedirectProxyProviderSvc.py @@ -0,0 +1,13 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +## @file RedirectProxyProviderSvc.py +# @brief temporary backward compatibility hack +# @details This hack allows to keep backward compatibility for statements like +# @code +# from StoreGate.StoreGateConf import ProxyProviderSvc +# @endcode + +from StoreGate.StoreGateConf import * +import SGComps.SGCompsConf +ProxyProviderSvc = SGComps.SGCompsConf.ProxyProviderSvc +#FIXME print a warning when ProxyProviderSvc is used diff --git a/EDM/athena/Control/StoreGate/python/__init__.py b/EDM/athena/Control/StoreGate/python/__init__.py new file mode 100644 index 00000000..385cb3d8 --- /dev/null +++ b/EDM/athena/Control/StoreGate/python/__init__.py @@ -0,0 +1,17 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +## @file: StoreGate/python/__init__.py +# @author: Wim Lavrijsen (WLavrijsen@lbl.gov) + +__version__ = '1.0.0' +__author__ = 'Wim Lavrijsen (WLavrijsen@lbl.gov)' + +__all__ = [ 'Bindings' ] + +# FIXME replace the autogenerated configurable repository with a hand-hacked one. +# FIXME This allows to keep backward compatibility for statements like +# from StoreGate.StoreGateConf import ProxyProviderSvc + +import sys +import StoreGate.RedirectProxyProviderSvc +sys.modules[ "StoreGate.StoreGateConf" ] = sys.modules[ "StoreGate.RedirectProxyProviderSvc" ] diff --git a/EDM/athena/Control/StoreGate/share/ActiveStoreHive_test.ref b/EDM/athena/Control/StoreGate/share/ActiveStoreHive_test.ref new file mode 100644 index 00000000..1e6e4c34 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/ActiveStoreHive_test.ref @@ -0,0 +1,40 @@ +*** ActiveStoreHiveTest BEGINS *** + + +Initializing Gaudi ApplicationMgr using job opts ../share/ActiveStore_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/work/c/calaf/public/testHive/Control/StoreGate/run/../share/ActiveStore_test.txt) +JobOptionsSvc INFO # (1,1): ApplicationMgr.ExtSvc = ["StoreGateSvc/E1", "StoreGateSvc/E2"] +JobOptionsSvc INFO # (2,1): StoreGateSvc.OutputLevel = 1 +JobOptionsSvc INFO # (3,1): ActiveStoreSvc.StoreName = "E1" +JobOptionsSvc INFO # (4,1): HiveMgrSvc.OutputLevel = 1 +JobOptionsSvc INFO # (5,1): HiveMgrSvc.NSlots = 4 +JobOptionsSvc INFO Job options successfully read in from ../share/ActiveStore_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v1r3) + running on lxplus0006 on Wed May 8 02:24:12 2013 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +E1 INFO Initializing E1 - package version StoreGate-02-39-07-branch +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-06-07 +ClassIDSvc INFO getRegistryEntries: read 137 CLIDRegistry entries for module ALL +ClassIDSvc INFO getRegistryEntries: read 137 CLIDRegistry entries for module ALL +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-01-06 +E2 INFO Initializing E2 - package version StoreGate-02-39-07-branch +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +SG::HiveStoreSvc INFO Initializing SG::HiveStoreSvc - package version StoreGate-02-39-07-branch +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-02-39-07-branch +StoreGateSvc DEBUG Service base class initialized successfully +StoreGateSvc VERBOSE ServiceLocatorHelper::service: found service IncidentSvc +StoreGateSvc VERBOSE ServiceLocatorHelper::service: found service EventPersistencySvc +StoreGateSvc VERBOSE ServiceLocatorHelper::service: found service ClassIDSvc +StoreGateSvc VERBOSE ServiceLocatorHelper::service: found service ProxyProviderSvc +ActiveStoreSvc INFO Initializing ActiveStoreSvc - package version StoreGate-02-39-07-branch +ActiveStoreSvc INFO ActiveStoreSvc will use SG::HiveStoreSvc +*** ActiveStoreHiveTest OK *** + + diff --git a/EDM/athena/Control/StoreGate/share/ActiveStore_test.ref b/EDM/athena/Control/StoreGate/share/ActiveStore_test.ref new file mode 100644 index 00000000..75910c85 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/ActiveStore_test.ref @@ -0,0 +1,32 @@ +*** ActiveStoreTest BEGINS *** + + +Initializing Gaudi ApplicationMgr using job opts ../share/ActiveStore_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/work/c/calaf/public/testHive/Control/StoreGate/run/../share/ActiveStore_test.txt) +JobOptionsSvc INFO # (1,1): ApplicationMgr.ExtSvc = ["StoreGateSvc/E1", "StoreGateSvc/E2"] +JobOptionsSvc INFO # (2,1): StoreGateSvc.OutputLevel = 1 +JobOptionsSvc INFO # (3,1): ActiveStoreSvc.StoreName = "E1" +JobOptionsSvc INFO # (4,1): HiveMgrSvc.OutputLevel = 1 +JobOptionsSvc INFO # (5,1): HiveMgrSvc.NSlots = 4 +JobOptionsSvc INFO Job options successfully read in from ../share/ActiveStore_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v1r3) + running on lxplus0006 on Wed May 8 02:24:05 2013 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +E1 INFO Initializing E1 - package version StoreGate-02-39-07-branch +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-06-07 +ClassIDSvc INFO getRegistryEntries: read 137 CLIDRegistry entries for module ALL +ClassIDSvc INFO getRegistryEntries: read 137 CLIDRegistry entries for module ALL +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-01-06 +E2 INFO Initializing E2 - package version StoreGate-02-39-07-branch +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +ActiveStoreSvc INFO Initializing ActiveStoreSvc - package version StoreGate-02-39-07-branch +*** ActiveStoreTest OK *** + + diff --git a/EDM/athena/Control/StoreGate/share/ActiveStore_test.txt b/EDM/athena/Control/StoreGate/share/ActiveStore_test.txt new file mode 100644 index 00000000..b82b19be --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/ActiveStore_test.txt @@ -0,0 +1,7 @@ +ApplicationMgr.ExtSvc={"StoreGateSvc/E1", "StoreGateSvc/E2"}; +StoreGateSvc.OutputLevel=1; +E1.ProxyProviderSvc=""; +E2.ProxyProviderSvc=""; +ActiveStoreSvc.StoreName="E1"; +HiveMgrSvc.OutputLevel=1; +HiveMgrSvc.NSlots=4; diff --git a/EDM/athena/Control/StoreGate/share/DataHandle_test.ref b/EDM/athena/Control/StoreGate/share/DataHandle_test.ref new file mode 100644 index 00000000..48d4fb20 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/DataHandle_test.ref @@ -0,0 +1,18 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr $Revision: 1.11 $ + running on lxplus230.cern.ch on Tue Apr 8 03:43:08 2008 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis... INFO 'CnvServices':[ 'HbookHistSvc' , 'RootHistSvc' ] +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +Now we expect to see an error message: +----Error Message Starts--->> +SG::DataProxy_castWARNING this proxy 0x82a9028 is in an invalid state +<<---Error Message Ends------- +*** DataHandle_test static handle test OK *** +*** DataHandle_test OK *** diff --git a/EDM/athena/Control/StoreGate/share/KeyConcept_test.ref b/EDM/athena/Control/StoreGate/share/KeyConcept_test.ref new file mode 100644 index 00000000..f529c543 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/KeyConcept_test.ref @@ -0,0 +1,2 @@ +*** KeyConcept_test BEGIN *** +*** KeyConcept_test OK *** diff --git a/EDM/athena/Control/StoreGate/share/ReadHandleKey_test.ref b/EDM/athena/Control/StoreGate/share/ReadHandleKey_test.ref new file mode 100644 index 00000000..774d7013 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/ReadHandleKey_test.ref @@ -0,0 +1,16 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Tue Feb 16 19:11:36 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 103 CLIDRegistry entries for module ALL +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 diff --git a/EDM/athena/Control/StoreGate/share/ReadHandle_test.ref b/EDM/athena/Control/StoreGate/share/ReadHandle_test.ref new file mode 100644 index 00000000..2aff596a --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/ReadHandle_test.ref @@ -0,0 +1,42 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/VarHandleBase_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/user/s/ssnyder/atlas-work15/Control/StoreGate/share/../share/VarHandleBase_test.txt +JobOptionsSvc INFO # (1,1): ApplicationMgr.ExtSvc = ["StoreGateSvc/OtherStore"] +JobOptionsSvc INFO # (2,1): OtherStore.ProxyProviderSvc = "" +JobOptionsSvc INFO Job options successfully read in from ../share/VarHandleBase_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v4r1) + running on lxplus081.cern.ch on Thu May 10 19:46:08 2018 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +ClassIDSvc INFO getRegistryEntries: read 212 CLIDRegistry entries for module ALL +ClassIDSvc ERROR uncheckedSetTypePackageForID: PyAnalysisExamples-00-00-00 can not set CLID <86839352> for type name MyObj: Known CLID for this name <293847295> It was set by StoreGate-00-00-00 +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 867 CLIDRegistry entries for module ALL +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +test2 +test3 +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): could not get proxy for key foox +test4 +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() diff --git a/EDM/athena/Control/StoreGate/share/SGHive_test.ref b/EDM/athena/Control/StoreGate/share/SGHive_test.ref new file mode 100644 index 00000000..a2068b86 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/SGHive_test.ref @@ -0,0 +1,127 @@ +*** SGHiveTest BEGINS *** + + +Initializing Gaudi ApplicationMgr using job opts ../share/SGHive_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/user/s/ssnyder/atlas-work7/Control/StoreGate/run/../share/SGHive_test.txt +JobOptionsSvc INFO # (1,1): StoreGateSvc.OutputLevel = 1 +JobOptionsSvc INFO # (2,1): HiveMgrSvc.OutputLevel = 1 +JobOptionsSvc INFO # (3,1): HiveMgrSvc.NSlots = 4 +JobOptionsSvc INFO Job options successfully read in from ../share/SGHive_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v3r6) + running on lxplus066.cern.ch on Fri Feb 19 01:46:58 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +HiveMgrSvc INFO Initializing HiveMgrSvc - package version StoreGate-03-06-17 +HiveMgrSvc DEBUG Service base class initialized successfully +StoreGateSvc DEBUG Service base class initialized successfully +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-03-06-17 +StoreGateSvc_Impl INFO Initializing StoreGateSvc_Impl - package version StoreGate-03-06-17 +StoreGateSvc_Impl DEBUG Service base class initialized successfully +StoreGateSvc_Impl VERBOSE ServiceLocatorHelper::service: found service EventPersistencySvc +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-06-18-02 +ClassIDSvc INFO getRegistryEntries: read 159 CLIDRegistry entries for module ALL +StoreGateSvc_Impl VERBOSE ServiceLocatorHelper::service: found service ClassIDSvc +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-02-04 +0_StoreGateSvc_... INFO Initializing 0_StoreGateSvc_Impl - package version StoreGate-03-06-17 +0_StoreGateSvc_... DEBUG Service base class initialized successfully +0_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service EventPersistencySvc +0_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service ClassIDSvc +1_StoreGateSvc_... INFO Initializing 1_StoreGateSvc_Impl - package version StoreGate-03-06-17 +1_StoreGateSvc_... DEBUG Service base class initialized successfully +1_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service EventPersistencySvc +1_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service ClassIDSvc +2_StoreGateSvc_... INFO Initializing 2_StoreGateSvc_Impl - package version StoreGate-03-06-17 +2_StoreGateSvc_... DEBUG Service base class initialized successfully +2_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service EventPersistencySvc +2_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service ClassIDSvc +3_StoreGateSvc_... INFO Initializing 3_StoreGateSvc_Impl - package version StoreGate-03-06-17 +3_StoreGateSvc_... DEBUG Service base class initialized successfully +3_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service EventPersistencySvc +3_StoreGateSvc_...VERBOSE ServiceLocatorHelper::service: found service ClassIDSvc +Now we expect to see an error message: +----Error Message Starts--->> +HiveMgrSvc FATAL Too late to change the number of slots! +<<---Error Message Ends------- +HiveMgrSvc DEBUG Slot 0 allocated to event number 0 +HiveMgrSvc DEBUG Slot 1 allocated to event number 1 +HiveMgrSvc DEBUG Slot 2 allocated to event number 2 +HiveMgrSvc DEBUG Slot 3 allocated to event number 3 +Now we expect to see an error message: +----Error Message Starts--->> +HiveMgrSvc ERROR No slots available for event number 123465 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +HiveMgrSvc ERROR Attempt to allocate an event slot for an event that is still active: event number 0 +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +HiveMgrSvc ERROR could not clear store 222222 +<<---Error Message Ends------- +1_StoreGateSvc_... DEBUG Clearing store with forceRemove=0 +HiveMgrSvc DEBUG cleared store 1 +HiveMgrSvc DEBUG Freed slot 1 +HiveMgrSvc DEBUG Slot 1 allocated to event number 333333 + +*** SGHive_test noSlot BEGINS *** +ClassIDSvc INFO getRegistryEntries: read 784 CLIDRegistry entries for module ALL +StoreGateSvc_Impl VERBOSE committing dataObj "('SG::Foo','blassed')" +StoreGateSvc_Impl DEBUG Recorded object @0xd49da0 with key pFoo1 of type SG::Foo(CLID 81010) + in DataObject @0xcaa2b0 + object modifiable when retrieved +StoreGateSvc_Impl DEBUG Recorded object @0xd4b880 with key pFoo2 of type SG::Foo(CLID 81010) + in DataObject @0xd29b40 + object modifiable when retrieved +StoreGateSvc_Impl VERBOSE committing dataObj "('SG::Foo','pFoo2')" +StoreGateSvc_Impl VERBOSE committing dataObj "('SG::Foo','pFoo1')" +StoreGateSvc_Impl DEBUG Recorded object @0xd4c3c0 with key pFoo3 of type SG::Foo(CLID 81010) + in DataObject @0xd1f750 + object modifiable when retrieved +StoreGateSvc_Impl VERBOSE committing dataObj "('SG::Foo','pFoo3')" + +*** SGHive_test noSlot ENDS *** + +*** SGHive_test withSlot BEGINS *** +0_StoreGateSvc_...VERBOSE committing dataObj "('SG::Foo','blassed')" +0_StoreGateSvc_... DEBUG Recorded object @0xd4c900 with key pFoo1 of type SG::Foo(CLID 81010) + in DataObject @0xc88e70 + object modifiable when retrieved +0_StoreGateSvc_... DEBUG Recorded object @0xd4ea50 with key pFoo2 of type SG::Foo(CLID 81010) + in DataObject @0xc88ec0 + object modifiable when retrieved +0_StoreGateSvc_...VERBOSE committing dataObj "('SG::Foo','pFoo2')" +0_StoreGateSvc_...VERBOSE committing dataObj "('SG::Foo','pFoo1')" +0_StoreGateSvc_... DEBUG Recorded object @0xd4ee70 with key pFoo3 of type SG::Foo(CLID 81010) + in DataObject @0xc88c50 + object modifiable when retrieved +0_StoreGateSvc_...VERBOSE committing dataObj "('SG::Foo','pFoo3')" + +*** SGHive_test withSlot ENDS *** +StoreGateSvc INFO Finalizing StoreGateSvc - package version StoreGate-03-06-17 +StoreGateSvc_Impl INFO Finalizing StoreGateSvc_Impl - package version StoreGate-03-06-17 +StoreGateSvc_Impl DEBUG Clearing store with forceRemove=1 +StoreGateSvc_Impl VERBOSE DataStore::clearStore() forcing release of DataProxy @0xd231c0, recorded with key=pFoo1, CLID=81010, containing data object @0xcaa2b0 ... -> DONE +StoreGateSvc_Impl VERBOSE DataStore::clearStore() forcing release of DataProxy @0xd2e1e0, recorded with key=pFoo2, CLID=81010, containing data object @0xd29b40 ... -> DONE +StoreGateSvc_Impl VERBOSE DataStore::clearStore() forcing release of DataProxy @0xd71f50, recorded with key=pFoo3, CLID=81010, containing data object @0xd1f750 ... -> DONE +HiveMgrSvc INFO Finalizing HiveMgrSvc - package version StoreGate-03-06-17 +0_StoreGateSvc_... INFO Finalizing 0_StoreGateSvc_Impl - package version StoreGate-03-06-17 +0_StoreGateSvc_... DEBUG Clearing store with forceRemove=1 +0_StoreGateSvc_...VERBOSE DataStore::clearStore() forcing release of DataProxy @0xd75650, recorded with key=pFoo1, CLID=81010, containing data object @0xc88e70 ... -> DONE +0_StoreGateSvc_...VERBOSE DataStore::clearStore() forcing release of DataProxy @0xd2ed90, recorded with key=pFoo2, CLID=81010, containing data object @0xc88ec0 ... -> DONE +0_StoreGateSvc_...VERBOSE DataStore::clearStore() forcing release of DataProxy @0xd27240, recorded with key=pFoo3, CLID=81010, containing data object @0xc88c50 ... -> DONE +1_StoreGateSvc_... INFO Finalizing 1_StoreGateSvc_Impl - package version StoreGate-03-06-17 +1_StoreGateSvc_... DEBUG Clearing store with forceRemove=1 +2_StoreGateSvc_... INFO Finalizing 2_StoreGateSvc_Impl - package version StoreGate-03-06-17 +2_StoreGateSvc_... DEBUG Clearing store with forceRemove=1 +3_StoreGateSvc_... INFO Finalizing 3_StoreGateSvc_Impl - package version StoreGate-03-06-17 +3_StoreGateSvc_... DEBUG Clearing store with forceRemove=1 +*** SGHiveTest OK *** + + diff --git a/EDM/athena/Control/StoreGate/share/SGHive_test.txt b/EDM/athena/Control/StoreGate/share/SGHive_test.txt new file mode 100644 index 00000000..ef3d8339 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/SGHive_test.txt @@ -0,0 +1,3 @@ +StoreGateSvc.OutputLevel=1; +HiveMgrSvc.OutputLevel=1; +HiveMgrSvc.NSlots=4; diff --git a/EDM/athena/Control/StoreGate/share/SGIterator_test.ref b/EDM/athena/Control/StoreGate/share/SGIterator_test.ref new file mode 100644 index 00000000..66ade89b --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/SGIterator_test.ref @@ -0,0 +1,24 @@ +*** SGIterator_test starts *** +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr $Revision: 1.1 $ + running on lxplus212.cern.ch on Mon Sep 29 04:55:27 2008 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis... INFO 'CnvServices':[ 'HbookHistSvc' , 'RootHistSvc' ] +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +Now we expect to see an error message: +----Error Message Starts--->> +SG::DataProxy_castWARNING this proxy 0x82e0bd8 is in an invalid state +<<---Error Message Ends------- +*** SGIterator test OK *** +Now we expect to see an error message: +----Error Message Starts--->> +SG::DataProxy_castWARNING this proxy 0x82e0bd8 is in an invalid state +<<---Error Message Ends------- +*** SGConstIterator test OK *** +*** SGIterator_test OK *** diff --git a/EDM/athena/Control/StoreGate/share/SegMemSvc_test.ref b/EDM/athena/Control/StoreGate/share/SegMemSvc_test.ref new file mode 100644 index 00000000..7a9e211d --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/SegMemSvc_test.ref @@ -0,0 +1,13 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr $Revision: 1.1 $ + running on lxplus232.cern.ch on Thu Oct 2 00:19:52 2008 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis... INFO 'CnvServices':[ 'HbookHistSvc' , 'RootHistSvc' ] +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +*** SegMemSvc_test OK *** diff --git a/EDM/athena/Control/StoreGate/share/StoreClearedIncident_test.ref b/EDM/athena/Control/StoreGate/share/StoreClearedIncident_test.ref new file mode 100644 index 00000000..e69de29b diff --git a/EDM/athena/Control/StoreGate/share/StoreGateSvcClient_test.txt b/EDM/athena/Control/StoreGate/share/StoreGateSvcClient_test.txt new file mode 100644 index 00000000..f89aae62 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/StoreGateSvcClient_test.txt @@ -0,0 +1 @@ +#include "StoreGate/StoreGateTestCommon.txt" diff --git a/EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.py b/EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.py new file mode 100644 index 00000000..446be677 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.py @@ -0,0 +1,11 @@ +from AthenaCommon.AppMgr import theApp, ServiceMgr, theAuditorSvc +theApp.CreateSvc += [ "StoreGateSvc/DetectorStore", "StoreGateSvc" ] +theApp.ExtSvc += [ "StoreGateSvc/HistoryStore" ] + +from AthenaCommon.ConfigurableDb import getConfigurable +ServiceMgr += getConfigurable("ClassIDSvc")() +ServiceMgr.ClassIDSvc.CLIDDBFiles += [ "Gaudi_clid.db" ] + +from AthenaCommon.AppMgr import theAuditorSvc +from GaudiAud.GaudiAudConf import AlgContextAuditor +theAuditorSvc += AlgContextAuditor() diff --git a/EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.txt b/EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.txt new file mode 100644 index 00000000..ac93faed --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/StoreGate_jobOptions.txt @@ -0,0 +1,4 @@ +ApplicationMgr.ExtSvc += { "StoreGateSvc/DetectorStore", "StoreGateSvc/HistoryStore" }; +//FIXME uncomment to verify that your CLIDs are good! +//ClassIDSvc.CLIDDBFiles += { "clid.db" }; +AuditorSvc.Auditors += { "AlgContextAuditor"}; diff --git a/EDM/athena/Control/StoreGate/share/UpdateHandleKey_test.ref b/EDM/athena/Control/StoreGate/share/UpdateHandleKey_test.ref new file mode 100644 index 00000000..45810fcd --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/UpdateHandleKey_test.ref @@ -0,0 +1,17 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Tue Feb 16 19:37:29 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 103 CLIDRegistry entries for module ALL +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 818 CLIDRegistry entries for module ALL diff --git a/EDM/athena/Control/StoreGate/share/UpdateHandle_test.ref b/EDM/athena/Control/StoreGate/share/UpdateHandle_test.ref new file mode 100644 index 00000000..34412160 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/UpdateHandle_test.ref @@ -0,0 +1,49 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/VarHandleBase_test.txt +JobOptionsSvc INFO # =======> /home/sss/nobackup/atlas/build/../tests/../share/VarHandleBase_test.txt +JobOptionsSvc INFO # (1,1): ApplicationMgr.ExtSvc = ["StoreGateSvc/OtherStore"] +JobOptionsSvc INFO # (2,1): OtherStore.ProxyProviderSvc = "" +JobOptionsSvc INFO Job options successfully read in from ../share/VarHandleBase_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Sun Apr 24 21:57:27 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +OtherStore INFO Initializing OtherStore - package version StoreGate-00-00-00 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 157 CLIDRegistry entries for module ALL +ClassIDSvc ERROR uncheckedSetTypePackageForID: PyAnalysisExamples-00-00-00 can not set CLID <86839352> for type name MyObj: Known CLID for this name <293847295> It was set by StoreGate-00-00-00 +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 833 CLIDRegistry entries for module ALL +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() +test2 +test3 +VarHandle(FooSv...WARNING FILE:LINE (FUNC): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (FUNC): try using a ReadHandle +VarHandle(FooSv...WARNING FILE:LINE (FUNC): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (FUNC): try using a ReadHandle +VarHandle(FooSv...WARNING FILE:LINE (FUNC): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (FUNC): try using a ReadHandle +VarHandle(FooSv...WARNING FILE:LINE (FUNC): could not get proxy for key foox +VarHandle(FooSv...WARNING FILE:LINE (FUNC): try using a ReadHandle +test4 +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() diff --git a/EDM/athena/Control/StoreGate/share/VarHandleBase_test.ref b/EDM/athena/Control/StoreGate/share/VarHandleBase_test.ref new file mode 100644 index 00000000..52a5f364 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleBase_test.ref @@ -0,0 +1,61 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/VarHandleBase_test.txt +JobOptionsSvc INFO # =======> /home/sss/nobackup/atlas/build/../tests/../share/VarHandleBase_test.txt +JobOptionsSvc INFO # (1,1): ApplicationMgr.ExtSvc = ["StoreGateSvc/OtherStore"] +JobOptionsSvc INFO # (2,1): OtherStore.ProxyProviderSvc = "" +JobOptionsSvc INFO Job options successfully read in from ../share/VarHandleBase_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Sun Apr 24 21:36:13 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +OtherStore INFO Initializing OtherStore - package version StoreGate-00-00-00 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 156 CLIDRegistry entries for module ALL +ClassIDSvc ERROR uncheckedSetTypePackageForID: PyAnalysisExamples-00-00-00 can not set CLID <86839352> for type name MyObj: Known CLID for this name <293847295> It was set by StoreGate-00-00-00 +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 833 CLIDRegistry entries for module ALL +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +test2 +test3 +test4 +ServiceManager FATAL No Service factory for FooSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service FooSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +VarHandle(FooSv... FATAL FILE:LINE (StatusCode SG::VarHandleBase::initialize()): code 0: VarHandleKey::initialize() +test5 +ServiceManager FATAL No Service factory for FooSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service FooSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +VarHandle(FooSv... FATAL FILE:LINE (StatusCode SG::VarHandleBase::initialize()): code 0: VarHandleKey::initialize() +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): could not get proxy for key foo +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): try using a ReadHandle +test6 +test7 +ServiceManager FATAL No Service factory for FooSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service FooSvc + FATAL FILE:LINE (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() +VarHandle(FooSv... FATAL FILE:LINE (StatusCode SG::VarHandleBase::record_impl(std::unique_ptr<DataObject>, void*, bool, bool)): code 0: VarHandleKey::initialize() +VarHandle(FooSv... ERROR FILE:LINE (StatusCode SG::VarHandleBase::record_impl(std::unique_ptr<DataObject>, void*, bool, bool)): code 0: recordObject failed +VarHandle(FooSv... ERROR FILE:LINE (StatusCode SG::VarHandleBase::record_impl(std::unique_ptr<DataObject>, void*, bool, bool)): code 0: Attempt to record an object with a null key +test8 +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): could not get proxy for key foo +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): try using a ReadHandle +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): Proxy [293847295/foo] is in an invalid state +VarHandle(FooSv...WARNING FILE:LINE (void*SG::VarHandleBase::typeless_dataPointer_impl(bool)): Request for an invalid object; requested CLID = 293847295, proxy primary ID is 293847296 +test9 +VarHandleBase @0x7ffcec9b1760 store=FooSvc, clid=293847295, key=foo----------- ptr@0, proxy@0 diff --git a/EDM/athena/Control/StoreGate/share/VarHandleBase_test.txt b/EDM/athena/Control/StoreGate/share/VarHandleBase_test.txt new file mode 100644 index 00000000..ec103ddc --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleBase_test.txt @@ -0,0 +1,2 @@ +ApplicationMgr.ExtSvc={"StoreGateSvc/OtherStore"}; +OtherStore.ProxyProviderSvc=""; diff --git a/EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.ref b/EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.ref new file mode 100644 index 00000000..232badeb --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.ref @@ -0,0 +1,29 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/VarHandleKeyProperty_test.txt +JobOptionsSvc INFO # =======> /home/sss/atlas/dvtest/build/../tests/../share/VarHandleKeyProperty_test.txt +JobOptionsSvc INFO # (1,1): test4.k1 = "FooSvc/aaa" +JobOptionsSvc INFO # (2,1): test4.k2 = "bbb" +JobOptionsSvc INFO # (3,1): test4.k3 = "BarSvc/ccc" +JobOptionsSvc INFO # (4,1): test4.k4 = "BazSvc/ddd" +JobOptionsSvc INFO # (5,1): test5.k1 = "FooSvc/xxx/aaa" +JobOptionsSvc INFO Job options successfully read in from ../share/VarHandleKeyProperty_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Wed Feb 17 13:55:21 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 103 CLIDRegistry entries for module ALL +test2 +test3 +test4 +test5 +JobOptionsSvc ERROR Unable to set the property 'k1' of 'test5'. Check option and algorithm names, type and bounds. diff --git a/EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.txt b/EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.txt new file mode 100644 index 00000000..b4d6dfdd --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleKeyProperty_test.txt @@ -0,0 +1,5 @@ +test4.k1 = "FooSvc/aaa"; +test4.k2 = "bbb"; +test4.k3 = "BarSvc/ccc"; +test4.k4 = "BazSvc/ddd"; +test5.k1 = "FooSvc/xxx/aaa"; diff --git a/EDM/athena/Control/StoreGate/share/VarHandleKey_test.ref b/EDM/athena/Control/StoreGate/share/VarHandleKey_test.ref new file mode 100644 index 00000000..03384e3c --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleKey_test.ref @@ -0,0 +1,21 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Wed Mar 16 23:38:52 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 105 CLIDRegistry entries for module ALL +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 835 CLIDRegistry entries for module ALL +ServiceManager FATAL No Service factory for FooSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service FooSvc + FATAL ../src/VarHandleKey.cxx:96 (StatusCode SG::VarHandleKey::initialize()): code 0: m_storeHandle.retrieve() + ERROR ../src/VarHandleKey.cxx:92 (StatusCode SG::VarHandleKey::initialize()): code 0: Cannot initialize a Read/Write/Update handle with a null key. diff --git a/EDM/athena/Control/StoreGate/share/VarHandleProperty_test.ref b/EDM/athena/Control/StoreGate/share/VarHandleProperty_test.ref new file mode 100644 index 00000000..f3aa134f --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleProperty_test.ref @@ -0,0 +1,22 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/VarHandleProperty_test.txt +JobOptionsSvc INFO # =======> /home/sss/atlas/dvtest/build/../tests/../share/VarHandleProperty_test.txt +JobOptionsSvc INFO # (1,1): test1.k1 = "FooSvc/aaa" +JobOptionsSvc INFO # (2,1): test1.k2 = "bbb" +JobOptionsSvc INFO # (3,1): test1.k3 = "BarSvc/ccc" +JobOptionsSvc INFO Job options successfully read in from ../share/VarHandleProperty_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Tue Feb 23 00:35:33 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 151 CLIDRegistry entries for module ALL diff --git a/EDM/athena/Control/StoreGate/share/VarHandleProperty_test.txt b/EDM/athena/Control/StoreGate/share/VarHandleProperty_test.txt new file mode 100644 index 00000000..776f5b40 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandleProperty_test.txt @@ -0,0 +1,3 @@ +test1.k1 = "FooSvc/aaa"; +test1.k2 = "bbb"; +test1.k3 = "BarSvc/ccc"; diff --git a/EDM/athena/Control/StoreGate/share/VarHandles_test.ref b/EDM/athena/Control/StoreGate/share/VarHandles_test.ref new file mode 100644 index 00000000..b59740f8 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/VarHandles_test.ref @@ -0,0 +1,28 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v4r1) + running on lxplus081.cern.ch on Thu May 10 19:46:06 2018 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +*** VarHandles_test starts *** +ClassIDSvc INFO getRegistryEntries: read 213 CLIDRegistry entries for module ALL +Now we expect to see an error message: +----Error Message Starts--->> +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +<<---Error Message Ends------- +ClassIDSvc INFO getRegistryEntries: read 869 CLIDRegistry entries for module ALL +*** VarHandles_test static handle test OK *** +Now we expect to see an error message: +----Error Message Starts--->> +<<---Error Message Ends------- +Now we expect to see an error message: +----Error Message Starts--->> +<<---Error Message Ends------- +*** VarHandles_test resetable test OK *** +*** VarHandles_test ref count test OK *** +*** VarHandles_test OK *** diff --git a/EDM/athena/Control/StoreGate/share/WriteHandleKey_test.ref b/EDM/athena/Control/StoreGate/share/WriteHandleKey_test.ref new file mode 100644 index 00000000..9f2afa9d --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/WriteHandleKey_test.ref @@ -0,0 +1,17 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Tue Feb 16 19:30:54 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 103 CLIDRegistry entries for module ALL +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 818 CLIDRegistry entries for module ALL diff --git a/EDM/athena/Control/StoreGate/share/WriteHandle_test.ref b/EDM/athena/Control/StoreGate/share/WriteHandle_test.ref new file mode 100644 index 00000000..e6238ae9 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/WriteHandle_test.ref @@ -0,0 +1,49 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/VarHandleBase_test.txt +JobOptionsSvc INFO # =======> /home/sss/nobackup/atlas/build/../tests/../share/VarHandleBase_test.txt +JobOptionsSvc INFO # (1,1): ApplicationMgr.ExtSvc = ["StoreGateSvc/OtherStore"] +JobOptionsSvc INFO # (2,1): OtherStore.ProxyProviderSvc = "" +JobOptionsSvc INFO Job options successfully read in from ../share/VarHandleBase_test.txt +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v999r999) + running on karma on Sun Apr 24 21:56:59 2016 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +OtherStore INFO Initializing OtherStore - package version StoreGate-00-00-00 +ClassIDSvc INFO Initializing ClassIDSvc - package version CLIDComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 159 CLIDRegistry entries for module ALL +ClassIDSvc ERROR uncheckedSetTypePackageForID: PyAnalysisExamples-00-00-00 can not set CLID <86839352> for type name MyObj: Known CLID for this name <293847295> It was set by StoreGate-00-00-00 +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready +test1 +StoreGateSvc INFO Initializing StoreGateSvc - package version StoreGate-00-00-00 +ProxyProviderSvc INFO Initializing ProxyProviderSvc - package version SGComps-00-00-00 +ClassIDSvc INFO getRegistryEntries: read 833 CLIDRegistry entries for module ALL +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() +test2 +test3 +test4 +VarHandle(FooSv... ERROR FILE:LINE (FUNC): code 0: recordObject failed +test5 +VarHandle(FooSv... ERROR FILE:LINE (FUNC): code 0: recordObject failed + FATAL FILE:LINE (FUNC): code 0: this->record(std::move(data)) + ERROR FILE:LINE (FUNC): code 0: recordObject of aux store failed +test6 +VarHandle(FooSv... ERROR FILE:LINE (FUNC): code 0: recordObject failed +test8 +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() +ServiceManager FATAL No Service factory for BazSvc available. +VarHandleKey.Se... ERROR ServiceLocatorHelper::service: can not locate service BazSvc + FATAL FILE:LINE (FUNC): code 0: m_storeHandle.retrieve() diff --git a/EDM/athena/Control/StoreGate/share/exceptions_test.ref b/EDM/athena/Control/StoreGate/share/exceptions_test.ref new file mode 100644 index 00000000..ea07cb84 --- /dev/null +++ b/EDM/athena/Control/StoreGate/share/exceptions_test.ref @@ -0,0 +1,11 @@ +test1 +SG::ExcNullHandleKey: Attempt to dereference a Read/Write/UpdateHandle with a null key. +SG::ExcBadHandleKey: Bad key format for VarHandleKey: `xkey' +SG::ExcForbiddenMethod: Forbidden method called: `meth' +SG::ExcHandleInitError: Error initializing VarHandle from VarHandleKey: FooSvc/foo[123] +SG::ExcUninitKey: Error initializing VarHandle from uninitialized VarHandleKey: FooSvc/foo[123]; keys should be initialized in your initialize(). +SG::ExcConstObject: Tried to retrieve non-const pointer to const object via VarHandleKey: FooSvc/foo[123] +SG::ExcNullWriteHandle: Attempt to dereference write handle before record: FooSvc/foo[123] +SG::ExcNullReadHandle: Dereference of read handle failed: FooSvc/foo[123] +SG::ExcNullUpdateHandle: Dereference of update handle failed: FooSvc/foo[123] +SG::ExcUpdatedObjectFailure: updatedObject failed: FooSvc/foo[123] diff --git a/EDM/athena/Control/StoreGate/src/ActiveStoreSvc.cxx b/EDM/athena/Control/StoreGate/src/ActiveStoreSvc.cxx new file mode 100644 index 00000000..2d854a7e --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/ActiveStoreSvc.cxx @@ -0,0 +1,208 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "StoreGate/ActiveStoreSvc.h" +#include "StoreGate/StoreGateSvc.h" + +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" + +using namespace SG; +using namespace std; + +/// Standard Constructor +ActiveStoreSvc::ActiveStoreSvc(const std::string& name,ISvcLocator* svc) : + Service(name,svc), + p_activeStore(0), + m_storeName() +{ + declareProperty("StoreName", m_storeName="StoreGateSvc"); +} + + +/// Standard Destructor +ActiveStoreSvc::~ActiveStoreSvc() +{} + +////////////////////////////////////////////////////////////// +/// Service initialisation +StatusCode ActiveStoreSvc::initialize() { + + // Initialize service: + if(!(Service::initialize()).isSuccess()) return StatusCode::FAILURE; + + MsgStream log( msgSvc(), name() ); + log << MSG::INFO << "Initializing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + + const bool CREATEIF(true); + StatusCode sc = service(m_storeName, p_activeStore, CREATEIF); + if ( !sc.isSuccess() ) { + log << MSG::ERROR << "Could not locate default store" << endmsg; + return sc; + } + + return StatusCode::SUCCESS; + +} + +///set the active store pointer: used by the event loop mgrs +void ActiveStoreSvc::setStore(StoreGateSvc* s) +{ + p_activeStore = s; + s->makeCurrent(); +} + + +/// get proxy for a given data object address in memory +DataProxy* +ActiveStoreSvc::proxy(const void* const pTransient) const { + return activeStore()->proxy(pTransient); +} + +/// get proxy with given id and key. Returns 0 to flag failure +DataProxy* +ActiveStoreSvc::proxy(const CLID& id, const std::string& key) const { + return activeStore()->proxy(id,key); +} + +SG::DataProxy* ActiveStoreSvc::proxy_exact (SG::sgkey_t sgkey) const +{ + return p_activeStore->proxy_exact (sgkey); +} + +/// return the list of all current proxies in store +vector<const SG::DataProxy*> +ActiveStoreSvc::proxies() const { + return activeStore()->proxies(); +} + + +/// Raw addition of a proxy to the store. +StatusCode ActiveStoreSvc::addToStore (CLID id, SG::DataProxy* proxy) +{ + return p_activeStore->addToStore (id, proxy); +} + + +/** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ +SG::DataProxy* +ActiveStoreSvc::recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) +{ + return p_activeStore->recordObject (obj, key, allowMods, returnExisting); +} + + +/** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ +StatusCode ActiveStoreSvc::updatedObject (CLID id, const std::string& key) +{ + return p_activeStore->updatedObject (id, key); +} + + +/** + * @brief Find the key for a string/CLID pair. + * @param str The string to look up. + * @param clid The CLID associated with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ +sgkey_t ActiveStoreSvc::stringToKey (const std::string& str, CLID clid) +{ + return p_activeStore->stringToKey (str, clid); +} + + +/** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* ActiveStoreSvc::keyToString (sgkey_t key) const +{ + return p_activeStore->keyToString (key); +} + + +/** + * @brief Find the string and CLID corresponding to a given key. + * @param key The key to look up. + * @param clid[out] The found CLID. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* ActiveStoreSvc::keyToString (sgkey_t key, + CLID& clid) const +{ + return p_activeStore->keyToString (key, clid); +} + + +/** + * @brief Remember an additional mapping from key to string/CLID. + * @param key The key to enter. + * @param str The string to enter. + * @param clid The CLID associated with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + * Logs an error if @c key already corresponds to a different string. + */ +void ActiveStoreSvc::registerKey (sgkey_t key, + const std::string& str, + CLID clid) +{ + return p_activeStore->registerKey (key, str, clid); +} + + +const InterfaceID& ActiveStoreSvc::interfaceID() { + static const InterfaceID IDActiveStoreSvc("ActiveStoreSvc", 1, 0); + return IDActiveStoreSvc; +} +StatusCode ActiveStoreSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( interfaceID().versionMatch(riid) ) { + *ppvInterface = (ActiveStoreSvc*)this; + } + else if ( IProxyDict::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IProxyDict*)this; + } + else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + + diff --git a/EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.cxx b/EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.cxx new file mode 100644 index 00000000..94b731f7 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.cxx @@ -0,0 +1,197 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef ATHENAHIVE +#include "AthenaKernel/CloneService.h" +#include "AthenaKernel/errorcheck.h" +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/tools/SGImplSvc.h" +#include "SGHiveMgrSvc.h" +using namespace SG; + +__thread HiveEventSlot* s_current(0); + +HiveMgrSvc::HiveMgrSvc(const std::string& name, + ISvcLocator* svc) : Service(name, svc), + m_hiveStore("StoreGateSvc", name), + m_nSlots(1) +{ + declareProperty("HiveStoreSvc", m_hiveStore); + declareProperty("NSlots", m_nSlots, "number of event slots"); +} + + + +/** Activate an given 'slot' for all subsequent calls within the + * same thread id. + * + * @param slot [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ +StatusCode HiveMgrSvc::selectStore(size_t slotIndex) { + s_current = &m_slots[slotIndex]; + StoreGateSvc::setSlot(s_current); + return StatusCode::SUCCESS; +} + +/** Clear a given 'slot'. + * + * @param slot [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ +StatusCode HiveMgrSvc::clearStore(size_t slotIndex) { + StatusCode rc(StatusCode::FAILURE); + if (slotIndex < m_nSlots) { + rc=m_slots[slotIndex].pEvtStore->clearStore(); + if (rc.isSuccess()) debug() << "cleared store " << slotIndex << endmsg; + } + if (!rc.isSuccess()) error() << "could not clear store " << slotIndex << endmsg; + return rc; +} + +/** Set the number of 'slots'. + * + * @param slot [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ +StatusCode HiveMgrSvc::setNumberOfStores(size_t slots) { + //FIXME what if running? + if(FSMState() == Gaudi::StateMachine::INITIALIZED) { + fatal() << "Too late to change the number of slots!" << endmsg; + return StatusCode::FAILURE; + } else { + m_slots.resize(slots); + m_nSlots = slots; + return StatusCode::SUCCESS; + } +} + +size_t HiveMgrSvc::getNumberOfStores() { + return m_nSlots; +} + + + +/** Allocate a store slot for new event + * + * @param evtnumber [IN] Event number + * @param slot [OUT] Returned slot or slot number + * @return Slot number (npos to indicate an error). + */ +size_t HiveMgrSvc::allocateStore( int evtNumber ) { + for (size_t index=0; index<m_nSlots; ++index) { + if( m_slots[index].eventNumber == evtNumber) { + error() << "Attempt to allocate an event slot for an event that is still active: event number " << evtNumber << endmsg; + return std::string::npos; + } else if (m_slots[index].eventNumber == -1) { + m_slots[index].eventNumber = evtNumber; + debug() << "Slot " << index + << " allocated to event number "<< evtNumber << endmsg; + return index; + } + } + error() << "No slots available for event number " << evtNumber << endmsg; + return std::string::npos; +} + +/** Free a store slot + * + * @param slot [IN] Slot number + * @return Status code indicating failure or success. + */ +StatusCode HiveMgrSvc::freeStore( size_t slotIndex ) { + if (slotIndex < m_nSlots) { + m_slots[slotIndex].eventNumber = -1; + debug() << "Freed slot " << slotIndex << endmsg; + return StatusCode::SUCCESS; + } else { + error() << "no slot at " << slotIndex << endmsg; + return StatusCode::FAILURE; + } +} + + +/** Get the slot number corresponding to a given event + * + * @param evtNumber [IN] Event number + * @return slot number (npos to indicate an error). + */ +size_t HiveMgrSvc::getPartitionNumber(int evtNumber) const { + for (size_t index=0; index<m_nSlots; ++index) { + if( m_slots[index].eventNumber == evtNumber) return index; + } + return std::string::npos; +} + + +StatusCode HiveMgrSvc::getNewDataObjects(DataObjIDColl& products) { + return m_hiveStore->getNewDataObjects(products); +} + +bool HiveMgrSvc::newDataObjectsPresent() { + return m_hiveStore->newDataObjectsPresent(); +} + +StatusCode HiveMgrSvc::initialize() { + info() << "Initializing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + + if ( !(Service::initialize().isSuccess()) ) { + fatal() << "Unable to initialize base class" << endmsg; + return StatusCode::FAILURE; + } + //this sets the hiveStore pointer to StoreGateSvc.defaultStore + if (!(m_hiveStore.retrieve()).isSuccess()) { + fatal() << "Unable to get hive event store" << endmsg; + return StatusCode::FAILURE; + } + + //use hiveStore default impl store as prototype + Service* child(0); + SGImplSvc* pSG(0); + + for( size_t i = 0; i< m_nSlots; ++i) { + std::ostringstream oss; + oss << i << '_' << m_hiveStore->currentStore()->name(); + if (CloneService::clone(m_hiveStore->currentStore(), oss.str(), child).isSuccess() && + child->initialize().isSuccess() && + 0 != (pSG = dynamic_cast<SGImplSvc*>(child)) ) + { + pSG->setSlotNumber (i, m_nSlots); + m_slots.push_back(SG::HiveEventSlot(pSG)); + } else { + fatal() << "Unable to clone event store " << oss.str() << endmsg; + return StatusCode::FAILURE; + } + } + return selectStore(0); +} +StatusCode HiveMgrSvc::finalize() { + info() << "Finalizing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + + for (SG::HiveEventSlot& s : m_slots) { + // The impl services are not set to active, so ServiceMananger + // won't finalize them. + CHECK( s.pEvtStore->finalize() ); + s.pEvtStore->release(); + } + + return StatusCode::SUCCESS; +} + +StatusCode HiveMgrSvc::queryInterface( const InterfaceID& riid, void** ppvInterface ) { + if ( IHiveWhiteBoard::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IHiveWhiteBoard*)this; + } + else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} +#endif /*ATHENAHIVE*/ + + diff --git a/EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.h b/EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.h new file mode 100644 index 00000000..ae4c5797 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/SGHiveMgrSvc.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef ATHENAHIVE +#ifndef STOREGATE_HIVEMGRSVC_H +#define STOREGATE_HIVEMGRSVC_H + +#include <vector> +#include <string> + +/* maybe #include "tbb/mutex.h" */ + +#include "GaudiKernel/Service.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/IHiveWhiteBoard.h" +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/SGHiveEventSlot.h" + +class StoreGateSvc; +class ISvcLocator; + +template <class TYPE> class SvcFactory; + +/** @class HiveMgrSvc + * @brief A service that manages a multi-event collection of StoreGateSvc + * It implements the IHiveWhiteBoard interface + * + * $Id: SGHiveMgrSvc.h 694789 2015-09-14 19:36:04Z leggett $ + **/ +namespace SG { +class HiveMgrSvc : virtual public IHiveWhiteBoard, public Service { + friend class SvcFactory<HiveMgrSvc>; + friend class TestSGHiveMgrSvc; +public: + //@{ @name IHiveWhiteBoard implementation + /** Activate an given 'slot' for all subsequent calls within the + * same thread id. + * + * @param slot [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode selectStore(size_t slotIndex); + + /** Clear a given 'slot'. + * + * @param slot [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode clearStore(size_t slotIndex); + + /** Set the number of 'slots'. + * + * @param slot [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode setNumberOfStores(size_t slots); + + /** Get the number of 'slots'. + * + * @return Number of event stores allocated in the whiteboard + */ + virtual size_t getNumberOfStores(); + + /** Get the latest new data objects registred in store. + * + * @param products [IN] Slot number (event slot) * + * @return Status code indicating failure or success. + */ + virtual StatusCode getNewDataObjects(DataObjIDColl& products); + + /** Check if something is new in the whiteboard without getting the products. + * + * @param products [IN] Slot number (event slot) * + * @return Boolean indicating the presence of new products + */ + virtual bool newDataObjectsPresent(); + + /** Allocate a store slot for new event + * + * @param evtnumber [IN] Event number + * @param slot [OUT] Returned slot or slot number + * @return Slot number (npos to indicate an error). + */ + virtual size_t allocateStore( int evtnumber ); + + /** Free a store slot + * + * @param slot [IN] Slot number + * @return Status code indicating failure or success. + */ + virtual StatusCode freeStore( size_t slotIndex ); + + + /** Get the slot number corresponding to a given event + * + * @param evtnumber [IN] Event number + * @return slot number (npos to indicate an error). + */ + virtual size_t getPartitionNumber(int eventnumber) const; + //@{ @name Gaudi Service boilerplate + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + //@} + + +private: + ServiceHandle<StoreGateSvc> m_hiveStore; + size_t m_nSlots; //property settable also by setNumberOfStores + std::vector<SG::HiveEventSlot> m_slots; + //maybe ServiceHandle<ActiveStoreSvc> m_active; + +protected: + /// Standard Service Constructor. sets active store to default event store + HiveMgrSvc(const std::string& name, ISvcLocator* svc); + + virtual ~HiveMgrSvc() {} + +}; +} //namespace SG +#endif // STOREGATE_HIVEMGRSVC_H +#endif // ATHENAHIVE + + + diff --git a/EDM/athena/Control/StoreGate/src/SGImplSvc.cxx b/EDM/athena/Control/StoreGate/src/SGImplSvc.cxx new file mode 100644 index 00000000..64711843 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/SGImplSvc.cxx @@ -0,0 +1,1623 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef ATHENAHIVE +#define SLOW_NEWDATAOBJECTS 1 +#endif +#include <algorithm> +#include <cassert> +#include <iostream> +#include <functional> +#include <string> + +#include <sstream> +#include <iomanip> + +#include "AthenaKernel/IClassIDSvc.h" +#include "AthenaKernel/IProxyProviderSvc.h" +#include "AthenaKernel/IIOVSvc.h" +#include "AthenaKernel/errorcheck.h" +//#include "CxxUtils/PageAccessControl.h" +#include "GaudiKernel/IHistorySvc.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/IConversionSvc.h" +#include "GaudiKernel/Incident.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/DataHistory.h" +#include "SGTools/CurrentEventStore.h" +#include "SGTools/DataBucketBase.h" +#include "SGTools/DataProxy.h" +#include "SGTools/DataStore.h" +#include "SGTools/StringPool.h" +#include "SGTools/TransientAddress.h" +#include "SGTools/SGVersionedKey.h" +#include "CxxUtils/unordered_map.h" +#include "StoreGate/ActiveStoreSvc.h" +#include "StoreGate/StoreClearedIncident.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthenaKernel/errorcheck.h" + +// StoreGateSvc. must come before SGImplSvc.h +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/tools/SGImplSvc.h" +#include "boost/foreach.hpp" + +using std::ostringstream; +using std::setw; +using std::bind1st; +using std::find_if; +using std::mem_fun; +using std::not1; +using std::hex; +using std::dec; +using std::endl; +using std::ends; +using std::pair; +using std::setw; +using std::string; +using std::vector; + +using SG::DataProxy; +using SG::DataStore; +using SG::TransientAddress; + +/////////////////////////////////////////////////////////////////////////// +// Find the store id + +// return StoreID corresponding to storeNamePrefix. +StoreID::type findStoreID(const string& storeNamePrefix) { + //vector must be lexically sorted + static const vector<pair<string, StoreID::type> > NAMETOID { + { "ConditionsStore", StoreID::CONDITION_STORE }, + { "DetectorStore", StoreID::DETECTOR_STORE }, + { "EventStore", StoreID::EVENT_STORE }, + { "InputMetaDataStore", StoreID::METADATA_STORE }, + { "MetaDataStore", StoreID::SIMPLE_STORE }, + { "SpareStore", StoreID::SPARE_STORE }, + { "StoreGateSvc", StoreID::EVENT_STORE }, + { "TagMetaDataStore", StoreID::METADATA_STORE } + }; + const auto BEG(NAMETOID.begin()); + const auto END(NAMETOID.end()); + + // Account for AthenaMT stores that start with {digits}_ + size_t ist (0); + if (::isdigit(storeNamePrefix.at(0))) { + ist = storeNamePrefix.find("_",0) +1; + } + + auto i(BEG); + while (i != END) { + int comp = storeNamePrefix.compare(ist, (i->first).size(), (i->first)); + // std::cout << storeNamePrefix <<' '<< storeNamePrefix.size() <<' '<< i->first <<' '<< (i->first).size() <<' '<< comp << std::endl; + //NAMETOID is sorted so if we go past storeNamePrefix we are done + if (comp < 0) break; + else if (comp == 0) return i->second; + ++i; + } + return StoreID::UNKNOWN; +} + +/////////////////////////////////////////////////////////////////////////// +// Remapping implementation. + +thread_local DataObjIDColl s_newObjs; + +namespace SG { + + + struct RemapImpl + { + typedef IStringPool::sgkey_t sgkey_t; + + // Hash function for the key. + // Just cast the low bits to a size_t. + struct keyhash + { + std::size_t operator() (sgkey_t key) const + { return static_cast<std::size_t> (key); } + }; + + struct remap_t { + sgkey_t target; + off_t index_offset; + }; + typedef SG::unordered_map<sgkey_t, remap_t, keyhash> remap_map_t; + remap_map_t m_remaps; + }; + + +} // namespace SG + + +/////////////////////////////////////////////////////////////////////////// +/// Standard Constructor +SGImplSvc::SGImplSvc(const string& name,ISvcLocator* svc) + : Service(name, svc), m_pCLIDSvc(0), m_pDataLoader(0), + m_pPPSHandle("ProxyProviderSvc", name), + m_pPPS(nullptr), + m_pHistorySvc(0), m_pStore(new DataStore(*this)), + m_defaultStoreName(""), + m_pIncSvc("IncidentSvc", name), + m_DumpStore(false), + m_ActivateHistory(false), + m_pIOVSvc(0), + m_storeLoaded(false), + m_remap_impl (new SG::RemapImpl), + m_arena (name), + m_msg(msgSvc(), name), + m_slotNumber(-1), + m_numSlots(1) +{ + //our properties + declareProperty("ProxyProviderSvc", m_pPPSHandle); + declareProperty("Dump", m_DumpStore); + declareProperty("ActivateHistory", m_ActivateHistory); + //StoreGateSvc properties + declareProperty("defaultStoreName", m_defaultStoreName, "NOT USED"); + declareProperty("IncidentSvc", m_pIncSvc); + //add handler for Service base class property + m_outputLevel.declareUpdateHandler(&SGImplSvc::msg_update_handler, this); + + SG::ArenaHeader* header = SG::ArenaHeader::defaultHeader(); + header->addArena (&m_arena); +} + + +/// Standard Destructor +SGImplSvc::~SGImplSvc() { + SG::ArenaHeader* header = SG::ArenaHeader::defaultHeader(); + header->delArena (&m_arena); + + delete m_pStore; + delete m_remap_impl; +} + +////////////////////////////////////////////////////////////// +/// Service initialisation +StatusCode SGImplSvc::initialize() { + + msg() << MSG::VERBOSE << "Initializing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + + if(!(Service::initialize()).isSuccess()) { + msg() << MSG::ERROR << "Could not initialize base Service !!" << endmsg; + return StatusCode::FAILURE; + } + + if (!m_pStore) + m_pStore = new DataStore (*this); + if (!m_remap_impl) + m_remap_impl = new SG::RemapImpl; + + //properties accessible from now on + + store()->setStoreID(findStoreID(name())); + // If this is the default event store (StoreGateSvc), then declare + // our arena as the default for memory allocations. + if (this->storeID() == StoreID::EVENT_STORE) { + m_arena.makeCurrent(); + SG::CurrentEventStore::setStore (this); + } + // set up the incident service: + if (!(m_pIncSvc.retrieve()).isSuccess()) { + msg() << MSG::ERROR + << "Could not locate IncidentSvc " + << endmsg; + return StatusCode::FAILURE; + } + + //start listening to "EndEvent" + const int PRIORITY = 100; + m_pIncSvc->addListener(this, "EndEvent", PRIORITY); + m_pIncSvc->addListener(this, "BeginEvent", PRIORITY); + + const bool CREATEIF(true); + // cache pointer to Persistency Service + if (!(service("EventPersistencySvc", m_pDataLoader, CREATEIF)).isSuccess()) { + m_pDataLoader = 0; + msg() << MSG::ERROR + << "Could not get pointer to Persistency Service" + << endmsg; + return StatusCode::FAILURE;; + } + + if (!(service("ClassIDSvc", m_pCLIDSvc, CREATEIF)).isSuccess()) { + msg() << MSG::ERROR + << "Could not get pointer to ClassID Service" + << endmsg; + return StatusCode::FAILURE;; + } + + if (!m_pPPSHandle.empty()) { + CHECK( m_pPPSHandle.retrieve() ); + m_pPPS = &*m_pPPSHandle; + } + + if ( m_pPPS && (m_pPPS->preLoadProxies(*m_pStore)).isFailure() ) + { + SG_MSG_DEBUG(" Failed to preLoad proxies"); + return StatusCode::FAILURE; + } + + // Get hold of History Service + if (m_ActivateHistory && + !(service("HistorySvc", m_pHistorySvc, CREATEIF)).isSuccess()) { + msg() << MSG::ERROR + << "Could not locate History Service" + << endmsg; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} +/// Service start +StatusCode SGImplSvc::start() { + + msg() << MSG::VERBOSE << "Start " << name() << endmsg; + /* + // This will need regFcn clients to be updated first. + if ( 0 == m_pPPS || (m_pPPS->preLoadProxies(*m_pStore)).isFailure() ) + { + msg() << MSG::DEBUG + << " Failed to preLoad proxies" + << endmsg; + return StatusCode::FAILURE; + } + */ + + return StatusCode::SUCCESS; +} +/// Service stop +StatusCode SGImplSvc::stop() { + + msg() << MSG::VERBOSE << "Stop " << name() << endmsg; + //HACK ALERT: ID event store objects refer to det store objects + //by setting an ad-hoc priority for event store(s) we make sure they are finalized and hence cleared first + // see e.g. https://savannah.cern.ch/bugs/index.php?99993 + if (store()->storeID() == StoreID::EVENT_STORE) { + ISvcManager* pISM(dynamic_cast<ISvcManager*>(serviceLocator().get())); + if (!pISM) + return StatusCode::FAILURE; + pISM->setPriority(name(), pISM->getPriority(name())+1).ignore(); + msg() << MSG::VERBOSE << "stop: setting service priority to " << pISM->getPriority(name()) + << " so that event stores get finalized and cleared before other stores" <<endmsg; + } + return StatusCode::SUCCESS; +} + +////////////////////////////////////////////////////////////// +IIOVSvc* SGImplSvc::getIIOVSvc() { + // Get hold of the IOVSvc + if (0 == m_pIOVSvc && !(service("IOVSvc", m_pIOVSvc)).isSuccess()) { + msg() << MSG::WARNING + << "Could not locate IOVSvc " + << endmsg; + } + return m_pIOVSvc; +} + +////////////////////////////////////////////////////////////// +void SGImplSvc::handle(const Incident &inc) { + + if (inc.type() == "EndEvent") { + if (m_DumpStore) { + SG_MSG_DEBUG("Dumping StoreGate Contents"); + msg() << MSG::INFO + << '\n' << dump() << endl + << endmsg; + } + } +} + +StatusCode SGImplSvc::loadEventProxies() { + StatusCode sc(StatusCode::SUCCESS); + //FIXME this should probably be dealt with by the providers + if (0 != m_pPPS && !m_storeLoaded) { + m_storeLoaded = true; +#ifndef ATHENAHIVE + //this (probably) can't be done in initialize (circular init!) + ActiveStoreSvc* pActive(0); + const bool CREATEIF(true); + if (!(serviceLocator()->service("ActiveStoreSvc", pActive, CREATEIF)).isSuccess()) return StatusCode::FAILURE; + pActive->setStore(this); +#endif + sc=m_pPPS->loadProxies(*m_pStore); + } + return sc; +} + +/////////////////////////////////////////////////////////////////// +// Create a key for a type (used if the client has not specified a key) +string SGImplSvc::createKey(const CLID& id) +{ + ostringstream o; + o << m_pStore->typeCount(id)+1 << std::ends; + string ret(o.str()); + return ret; +} +////////////////////////////////////////////////////////////// +// clear store +StatusCode SGImplSvc::clearStore(bool forceRemove) +{ + emptyTrash(); + for (auto& p : m_newBoundHandles) + p.second.clear(); + assert(m_pStore); + MsgStream* pmlog( msgLvl(MSG::VERBOSE) ? &msg() : 0); + msg() << MSG::DEBUG << "Clearing store with forceRemove=" + << forceRemove << endmsg; + bool hard_reset = (m_numSlots > 1); + m_pStore->clearStore(forceRemove, hard_reset, pmlog); + m_storeLoaded=false; //FIXME hack needed by loadEventProxies + m_remap_impl->m_remaps.clear(); + m_arena.reset(); + +#ifndef ATHENAHIVE + // Send a notification that the store was cleared. + // FIXME test forceRemove to avoid calling during finalize. A better solution would be to test m_pIncSvc.m_pObject + if (!forceRemove && m_pIncSvc) + m_pIncSvc->fireIncident (StoreClearedIncident (this, name())); +#endif + + return StatusCode::SUCCESS; +} +////////////////////////////////////////////////////////////// +/// Service finalisation +StatusCode SGImplSvc::finalize() { + msg() << MSG::VERBOSE << "Finalizing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + + // Incident service may not work in finalizea. + // Clear this, so that we won't try to send an incident from clearStore. + (m_pIncSvc.release()).ignore(); + + const bool FORCEREMOVE(true); + clearStore(FORCEREMOVE).ignore(); + + //protect against double release + if (m_pHistorySvc) { + m_pHistorySvc->release(); + m_pHistorySvc = 0; + } + + m_stringpool.clear(); + delete m_pStore; + m_pStore = nullptr; + delete m_remap_impl; + m_remap_impl = 0; + m_arena.erase(); + + return Service::finalize(); +} +////////////////////////////////////////////////////////////// +/// Service reinitialization +StatusCode SGImplSvc::reinitialize() { + msg() << MSG::VERBOSE << "Reinitializing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + const bool FORCEREMOVE(true); + clearStore(FORCEREMOVE).ignore(); + //not in v20r2p2! return Service::reinitialize(); + return StatusCode::SUCCESS; +} + +const InterfaceID& +SGImplSvc::interfaceID() { + static const InterfaceID IID("SGImplSvc", 1, 0); + return IID; +} + +// Query the interfaces. +// Input: riid, Requested interface ID +// ppvInterface, Pointer to requested interface +// Return: StatusCode indicating SUCCESS or FAILURE. +// N.B. Don't forget to release the interface after use!!! +StatusCode SGImplSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( IProxyDict::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IProxyDict*)this; + } + else if ( IProxyDict::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IProxyDict*)this; + } + else if ( IHiveStoreMgr::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IHiveStoreMgr*)this; + } + else if ( interfaceID().versionMatch(riid) ) { + // In principle this should be cast to ISGImplSvc*. However, there + // is an anomaly in that existing clients are using the concrete StoreGate + // interface instread of an abstract ISGImplSvc interface. + *ppvInterface = (SGImplSvc*)this; + } else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + +////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// add proxy (with IOpaqueAddress that will later be retrieved from P) +////////////////////////////////////////////////////////////////////// +StatusCode SGImplSvc::recordAddress(const std::string& skey, + IOpaqueAddress* pAddress, + bool clearAddressFlag) +{ + assert(0 != pAddress); + CLID dataID = pAddress->clID(); + + if (dataID == 0) + { + msg() << MSG::WARNING + << "recordAddress: Invalid Class ID found in IOpaqueAddress @" + << pAddress << ". IOA will not be recorded" + << endmsg; + return StatusCode::FAILURE; + } + + //do not ovewrite a persistent object + if (m_pPPS) { + DataProxy *dp(m_pPPS->retrieveProxy(dataID, skey, *m_pStore)); + if (dp && dp->transientAddress() && dp->transientAddress()->provider()) { + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(dataID, clidTypeName).ignore(); + msg() << MSG::WARNING + << "recordAddress: failed for key="<< skey << ", type " << clidTypeName + << " (CLID " << dataID << ')' + << "\n there is already a persistent version of this object. Will not record a duplicate! " + << endmsg; + return StatusCode::FAILURE; + } + } + + // Check if a key already exists + DataProxy* dp = m_pStore->proxy_exact(dataID, skey); + if (0 == dp && 0 != m_pPPS) { + dp = m_pPPS->retrieveProxy(dataID, skey, *m_pStore); + } + + // Now treat the various cases: + if (0 == dp) + { + // create the proxy object and register it + TransientAddress* tAddr = new TransientAddress(dataID, skey, + pAddress, clearAddressFlag); + dp = new DataProxy(tAddr, m_pDataLoader, true, true); + m_pStore->addToStore(dataID, dp).ignore(); + + addAutoSymLinks (skey, dataID, dp, 0, false); + } + else if ((0 != dp) && (0 == dp->address())) + // Note: intentionally not checking dp->isValidAddress() + { + // Update proxy with IOpaqueAddress + dp->setAddress(pAddress); + } + else + { + string errType; + m_pCLIDSvc->getTypeNameOfID(dataID, errType).ignore(); + msg() << MSG::WARNING + << "recordAddress: preexisting proxy @" << dp + << " with non-NULL IOA found for key " + << skey << " type " << errType << " (" << dataID << "). \n" + << "Cannot record IOpaqueAddress @" << pAddress + << endmsg; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; + +} + +////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// add proxy (with IOpaqueAddress that will later be retrieved from P) +////////////////////////////////////////////////////////////////////// +StatusCode SGImplSvc::recordAddress(IOpaqueAddress* pAddress, bool clearAddressFlag) +{ + assert(0 != pAddress); + + CLID dataID = pAddress->clID(); + + string gK = (pAddress->par())[1]; // transient name by convention + if (gK.empty()) gK = (pAddress->par())[0]; // FIXME backward compatibility + if (gK.empty()) gK = createKey(dataID); + + return this->recordAddress(gK, pAddress, clearAddressFlag); +} + +DataProxy* SGImplSvc::setupProxy(const CLID& dataID, + const string& gK, + DataObject* pDObj, + bool allowMods, + bool resetOnly) { + // locate the proxy + DataProxy* dp = m_pStore->proxy_exact(dataID, gK); + + if (0 != dp) { //proxy found + if (0 != dp->object()) + { + // Case 0: duplicated proxy + msg() << MSG::WARNING << " setupProxy:: error setting up proxy for key " + << gK << " and clid " << dataID + << "\n Pre-existing valid DataProxy @"<< dp + << " found in Store for key " << dp->object()->name() + << " with clid " << dp->object()->clID() + << endmsg; + recycle(pDObj); // commit this object to trash + dp = 0; + } else { + // Case 1: Proxy found... if not valid, update it: + dp->setObject(pDObj); + if (!allowMods) dp->setConst(); + } + } else { + // Case 2: No Proxy found: + TransientAddress* tAddr = new TransientAddress(dataID, gK); + dp = new DataProxy(pDObj, tAddr, !allowMods, resetOnly); + if (!(m_pStore->addToStore(dataID, dp).isSuccess())) { + msg() << MSG::WARNING + << " setupProxy:: could not addToStore proxy @" << dp + << endmsg; + recycle(pDObj); // commit this object to trash + delete dp; + dp = 0; + } + } + return dp; +} + +/// set store id in DataStore: +void SGImplSvc::setStoreID(StoreID::type id) +{ + store()->setStoreID(id); +} +/// get store id from DataStore: +StoreID::type SGImplSvc::storeID() const +{ + return store()->storeID(); +} + +void +SGImplSvc::keys(const CLID& id, std::vector<std::string>& vkeys, + bool includeAlias, bool onlyValid) + +{ + return store()->keys(id, vkeys, includeAlias, onlyValid); +} + +bool SGImplSvc::isSymLinked(const CLID& linkID, DataProxy* dp) +{ + return (0 != dp) ? dp->transientAddress()->transientID(linkID) : false; +} + +////////////////////////////////////////////////////////////////// +// Dump Contents in store: +string SGImplSvc::dump() const +{ + ostringstream ost; + ost << "<<<<<<<<<<<<<<<<< Data Store Dump >>>>>>>>>>>>>>> \n"; + ost << "SGImplSvc(" + name() + ")::dump():\n"; + + DataStore::ConstStoreIterator s_iter, s_end; + store()->tRange(s_iter, s_end).ignore(); + + for (; s_iter != s_end; ++s_iter) + { + + CLID id = s_iter->first; + int nProxy = store()->typeCount(id); + string tname; + m_pCLIDSvc->getTypeNameOfID(id, tname).ignore(); + ost << "Found " << nProxy << ((nProxy == 1) ? " proxy" : " proxies") + << " for ClassID " << id <<" ("<< tname << "): \n"; + + // loop over each type: + SG::ConstProxyIterator p_iter = (s_iter->second).begin(); + SG::ConstProxyIterator p_end = (s_iter->second).end(); + + while (p_iter != p_end) { + const DataProxy& dp(*p_iter->second); + // ost << " proxy@" << &dp; + ost << " flags: (" + << setw(7) << (dp.isValid() ? "valid" : "INVALID") << ", " + << setw(8) << (dp.isConst() ? "locked" : "UNLOCKED") << ", " + << setw(6) << (dp.isResetOnly() ? "reset" : "DELETE") + << ") --- data: " << hex << setw(10) << dp.object() << dec + << " --- key: " << p_iter->first << '\n'; + ++p_iter; + } + } + ost << "<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>> \n"; + string ret(ost.str()); + return ret; + +} + +DataStore* +SGImplSvc::store() +{ + return m_pStore; +} + +const DataStore* +SGImplSvc::store() const +{ + return m_pStore; +} + + +StatusCode +SGImplSvc::addSymLink(const CLID& linkid, DataProxy* dp) +{ + if (0 == dp) { + msg() << MSG::WARNING + << "addSymLink: no target DataProxy found. Sorry, can't link to a non-existing data object" + << endmsg; + return StatusCode::FAILURE; + } + StatusCode sc = m_pStore->addSymLink(linkid, dp); + + // If the symlink is a derived->base conversion, then we may have + // a different transient pointer for the symlink. + if (sc.isSuccess() && dp->object()) { + void* baseptr = SG::DataProxy_cast (dp, linkid); + if (baseptr) + this->t2pRegister (baseptr, dp).ignore(); + } + return sc; +} + + +StatusCode +SGImplSvc::addAlias(const std::string& aliasKey, DataProxy* proxy) +{ + if (0 == proxy) { + msg() << MSG::WARNING + << "addAlias: no target DataProxy given, Cannot alias to a non-existing object" + << endmsg; + return StatusCode::FAILURE; + } + + // add key to proxy and to ProxyStore + return m_pStore->addAlias(aliasKey, proxy); +} + +int SGImplSvc::typeCount(const CLID& id) const +{ + return m_pStore->typeCount(id); +} + +DataProxy* +SGImplSvc::proxy(const void* const pTransient) const +{ + return m_pStore->locatePersistent(pTransient); +} + +DataProxy* +SGImplSvc::proxy(const CLID& id) const +{ + return proxy(id, false); +} + +DataProxy* +SGImplSvc::proxy(const CLID& id, bool checkValid) const +{ + DataProxy* dp = m_pStore->proxy(id); + if (0 == dp && 0 != m_pPPS) { + dp = m_pPPS->retrieveProxy(id, string("DEFAULT"), *m_pStore); + } + /// Check if it is valid + if (checkValid && 0 != dp) { + // FIXME: For keyless retrieve, this checks only the first instance + // of the CLID in store. If that happens to be invalid, but the second + // is valid - this does not work (when checkValid is requested). + return dp->isValid() ? dp : 0; + } + return dp; +} + +DataProxy* +SGImplSvc::proxy(const CLID& id, const string& key) const +{ + return proxy(id, key, false); +} + +DataProxy* +SGImplSvc::proxy(const CLID& id, const string& key, bool checkValid) const +{ + DataProxy* dp = m_pStore->proxy(id, key); + if (0 == dp && 0 != m_pPPS) { + dp = m_pPPS->retrieveProxy(id, key, *m_pStore); + } + if (checkValid && 0 != dp && !(dp->isValid())) dp = 0; + return dp; +} + + +/** + * @brief Raw addition of a proxy to the store. + * @param id CLID of object being added. + * @param proxy proxy to add. + */ +StatusCode SGImplSvc::addToStore (CLID id, SG::DataProxy* proxy) +{ + return m_pStore->addToStore (id, proxy); +} + + +/** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ +SG::DataProxy* SGImplSvc::recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) +{ + const void* raw_ptr = obj.get(); + const std::type_info* tinfo = nullptr; + + if (DataBucketBase* bucket = dynamic_cast<DataBucketBase*> (obj.get())) { + raw_ptr = bucket->object(); + tinfo = &bucket->tinfo(); + } + + if (returnExisting) { + SG::DataProxy* proxy = this->proxy (obj->clID(), key); + if (proxy) return proxy; + + // Look for the same object recorded under a different key. + proxy = this->proxy (raw_ptr); + if (proxy) { + // Make an alias. + if (addAlias (key, proxy).isFailure()) { + CLID clid = proxy->clID(); + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore(); + msg() << MSG::WARNING + << "SGImplSvc::recordObject: addAlias fails for object " + << clid << "[" << clidTypeName << "] " << proxy->name() + << " and new key " << key + << endmsg; + + proxy = nullptr; + } + return proxy; + } + } + + const bool resetOnly = true; + const bool noHist = false; + SG::DataProxy* proxy = nullptr; + if (this->typeless_record (obj.get(), key, raw_ptr, + allowMods, resetOnly, noHist, tinfo, + &proxy).isFailure()) + { + return nullptr; + } + return proxy; +} + + +/** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ +StatusCode SGImplSvc::updatedObject (CLID id, const std::string& key) +{ + addedNewTransObject (id, key); + return StatusCode::SUCCESS; +} + + +/** + * @brief Set the Hive slot number for this store. + * @param slot The slot number. -1 means that this isn't a Hive store. + * @param numSlots The total number of slots. Should be 1 for the + * non-Hive case. + */ +void SGImplSvc::setSlotNumber (int slot, int numSlots) +{ + m_slotNumber = slot; + m_numSlots = numSlots; +} + + +std::vector<const SG::DataProxy*> +SGImplSvc::proxies() const +{ + using std::distance; + DataStore::ConstStoreIterator s_iter, s_end; + store()->tRange(s_iter, s_end).ignore(); + + std::vector<const SG::DataProxy*> proxies; + proxies.reserve( distance( s_iter, s_end ) ); + + for (; s_iter != s_end; ++s_iter ) { + + const CLID id = s_iter->first; + proxies.reserve( proxies.size() + store()->typeCount(id) ); + + // loop over each type: + SG::ConstProxyIterator p_iter = (s_iter->second).begin(); + SG::ConstProxyIterator p_end = (s_iter->second).end(); + + for ( ; p_iter != p_end; ++p_iter ) { + proxies.push_back( p_iter->second ); + } + } + + return proxies; +} + +DataProxy* +SGImplSvc::transientProxy(const CLID& id, const string& key) const +{ + DataProxy* dp(m_pStore->proxy(id, key)); + return ( (0 != dp && dp->isValidObject()) ? dp : 0 ); +} + +DataObject* +SGImplSvc::accessData(const CLID& id) const +{ + DataProxy* theProxy(proxy(id, true)); + return (0 == theProxy) ? 0 : theProxy->accessData(); +} + +DataObject* +SGImplSvc::accessData(const CLID& id, const string& key) const +{ + DataProxy* theProxy(proxy(id, key, true)); + return (0 == theProxy) ? 0 : theProxy->accessData(); +} + +bool +SGImplSvc::transientSwap( const CLID& id, + const std::string& keyA, const std::string& keyB ) +{ + const bool checkValid = true; + DataProxy* a = proxy( id, keyA, checkValid ); + DataProxy* b = proxy( id, keyB, checkValid ); + if ( 0 == a || 0 == b ) { return false; } + DataObject* objA = a->accessData(); + DataObject* objB = b->accessData(); + + if ( 0 == objA || 0 == objB ) { return false; } + // prevent 'accidental' release of DataObjects... + const unsigned int refCntA = objA->addRef(); + const unsigned int refCntB = objB->addRef(); + // in case swap is being specialized for DataObjects + using std::swap; + swap( objA, objB ); + a->setObject( objA ); + b->setObject( objB ); + // and then restore old ref-count; + return ( (refCntA-1) == objA->release() && + (refCntB-1) == objB->release() ); +} + +StatusCode +SGImplSvc::typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, bool noHist) +{ + return typeless_record (obj, key, raw_ptr, allowMods, resetOnly, noHist, 0, + nullptr); +} + + +StatusCode +SGImplSvc::typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, bool noHist, + const std::type_info* tinfo) +{ + return typeless_record (obj, key, raw_ptr, allowMods, resetOnly, noHist,tinfo, + nullptr); +} + + +StatusCode +SGImplSvc::typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, bool noHist, + const std::type_info* tinfo, + SG::DataProxy** proxy_ret) +{ + const bool NOOVERWRITE(false); + SG::DataProxy* proxy = + record_impl( obj, key, raw_ptr, allowMods, resetOnly, NOOVERWRITE, tinfo); + if ( proxy == nullptr ) + return StatusCode::FAILURE; + if (proxy_ret) + *proxy_ret = proxy; + + if ( !m_ActivateHistory || noHist ) { + return StatusCode::SUCCESS; + } + + if ( store()->storeID() != StoreID::EVENT_STORE ) { + return StatusCode::SUCCESS; + } else { + return record_HistObj( obj->clID(), key, name(), allowMods, resetOnly ); + } +} + +StatusCode +SGImplSvc::typeless_overwrite( const CLID& clid, + DataObject* obj, + const std::string& key, + const void* const raw_ptr, + bool allowMods, + bool noHist, + const std::type_info* tinfo) +{ + StatusCode sc(StatusCode::SUCCESS); + SG::DataProxy* toRemove(proxy(clid, key, false)); + if (0 != toRemove) { + toRemove->addRef(); + const bool FORCEREMOVE(true); + sc =removeProxy(toRemove, (void*)0, FORCEREMOVE); + } + if (sc.isSuccess()) { + const bool ALLOWOVERWRITE(true); + const bool NORESET(false); + if (record_impl( obj, key, raw_ptr, allowMods, NORESET, ALLOWOVERWRITE, tinfo) == nullptr) + sc = StatusCode::FAILURE; + else if ( m_ActivateHistory && noHist && store()->storeID() == StoreID::EVENT_STORE ) { + sc = record_HistObj( obj->clID(), key, name(), allowMods, NORESET ); + } + } + //for detector store objects managed by IIOVSvc, replace the old proxy with the new one (#104311) + if (toRemove && sc.isSuccess() && store()->storeID() == StoreID::DETECTOR_STORE) { + sc = getIIOVSvc()->replaceProxy(toRemove, proxy(clid, key)); + } + if (toRemove) + toRemove->release(); + return sc; +} + +SG::DataProxy* +SGImplSvc::record_impl( DataObject* pDObj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, bool allowOverwrite, + const std::type_info* tinfo) +{ + CLID clid = pDObj->clID(); + std::string rawKey(key); + bool isVKey(SG::VersionedKey::isVersionedKey(key)); + if (isVKey) { + //FIXME VersionedKeys will need to be handled more efficiently + SG::VersionedKey vk(rawKey); + DataProxy *dp(proxy(clid, vk.key())); + if (dp) { + //proxies primary key + TransientAddress *pTA(dp->transientAddress()); + assert(pTA); + const std::string& pTAName(pTA->name()); + //original key as versioned + SG::VersionedKey primaryVK(pTAName); + + //if the existing matching object has no version + //create a versioned alias for the original unversioned key + //so it will remain accessible + if (!SG::VersionedKey::isVersionedKey(pTAName)) { + if (!(this->addAlias(primaryVK.rawVersionKey(), dp)).isSuccess()) { + msg() << MSG::WARNING + << "record_impl: Could not setup alias key " + << primaryVK.rawVersionKey() + << " for unversioned object " << pTAName + << endmsg; + return nullptr; + } + } + if (vk.isAuto()) { + //make a new versioned key incrementing the existing version + SG::VersionedKey newVK(primaryVK.key(), primaryVK.version()+1); + //FIXME this will fail in a confusing way if version+1 is in use + //FIXME need a better error message below, probably looking at all + //FIXME aliases + rawKey = newVK.rawVersionKey(); + } + } + } + if (!allowOverwrite && m_pPPS) { + //do not overwrite a persistent object + DataProxy *dp(m_pPPS->retrieveProxy(clid, rawKey, *m_pStore)); + if (dp && dp->transientAddress() && dp->transientAddress()->provider()) { + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore(); + msg() << MSG::WARNING + << "record_impl: you are recording an object with key " + << rawKey << ", type " << clidTypeName + << " (CLID " << clid << ')' + << "\n There is already a persistent version of this object. Recording a duplicate may lead to unreproducible results and it is deprecated. Use SGImplSvc::overwrite method instead" + << endmsg; + } + } + //now check whether raw_ptr has already been recorded + //We need to do this before we create the bucket, the proxy etc + SG::DataProxy* dp(proxy(raw_ptr)); + if (0 != dp) { + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore(); + msg() << MSG::WARNING + << "record_impl: failed for key="<< rawKey << ", type " << clidTypeName + << " (CLID " << clid << ')' + << "\n object @" << raw_ptr + << " already in store with key="<< dp->name() + << ". Will not record a duplicate! " + << endmsg; + if (pDObj != dp->object()) { + DataBucketBase* pDBB(dynamic_cast<DataBucketBase*>(pDObj)); + pDBB->relinquish(); //don't own the data obj already recorded! + } + this->recycle(pDObj); + return nullptr; + } + + + // setup the proxy + dp = setupProxy( clid, rawKey, pDObj, allowMods, resetOnly ); + if ( 0 == dp ) { + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore(); + msg() << MSG::WARNING + << "record_impl: Problem setting up the proxy for object @" <<raw_ptr + << "\n recorded with key " << rawKey + << " of type " << clidTypeName + << " (CLID " << clid << ") in DataObject @" << pDObj + << endmsg; + + return nullptr; + } + + // record in t2p: + if ( !(this->t2pRegister( raw_ptr, dp )).isSuccess() ) { + std::string clidTypeName; + m_pCLIDSvc->getTypeNameOfID(clid, clidTypeName).ignore(); + msg() << MSG::WARNING + << "record_impl: can not add to t2p map object @" <<raw_ptr + << "\n with key " << rawKey + << " of type " << clidTypeName + << " (CLID " << clid << ')' + << endmsg; + return nullptr; + } + + addAutoSymLinks (rawKey, clid, dp, tinfo); + + //handle versionedKeys: we register an alias with the "true" key + //unless an object as already been recorded with that key. + //Notice that addAlias overwrites any existing alias, so a generic + //retrieve will always return the last version added + //FIXME not the one with the highest version + if (isVKey) { + SG::VersionedKey vk(rawKey); + if (!(this->addAlias(vk.key(), dp)).isSuccess()) { + msg() << MSG::WARNING + << "record_impl: Could not setup alias key " << vk.key() + << " for VersionedKey " << rawKey + << ". Generic access to this object with clid" << clid + << " will not work" + << endmsg; + } + } + + addedNewTransObject(clid, rawKey); + + return dp; + +} + +DataProxy* +SGImplSvc::locatePersistent(const TransientAddress* tAddr, + bool checkValid) const +{ + DataProxy* dp = m_pStore->proxy(tAddr); + + if (checkValid && 0 != dp) { + return dp->isValid() ? dp : 0; + } else { + return dp; + } +} + +StatusCode +SGImplSvc::removeProxy(DataProxy* proxy, const void* pTrans, + bool forceRemove) +{ + // check if valid proxy + if (0 == proxy) return StatusCode::FAILURE; + + if (0 == pTrans) { + DataBucketBase* bucket = dynamic_cast<DataBucketBase*>(proxy->object()); + if (bucket) pTrans = bucket->object(); + } + + // remove all entries from t2p map + this->t2pRemove(pTrans); + SG::DataProxy::CLIDCont_t clids = proxy->transientID(); + for (SG::DataProxy::CLIDCont_t::const_iterator i = clids.begin(); + i != clids.end(); + ++i) + { + void* ptr = SG::DataProxy_cast (proxy, *i); + this->t2pRemove(ptr); + } + + // remove from store + return m_pStore->removeProxy(proxy, forceRemove, true); +} + +StatusCode +SGImplSvc::t2pRegister(const void* const pTrans, DataProxy* const pPers) +{ + return m_pStore->t2pRegister(pTrans, pPers); +} + + +void +SGImplSvc::t2pRemove(const void* const pTrans) +{ + m_pStore->t2pRemove(pTrans); +} + +void +SGImplSvc::msg_update_handler(Property& /*outputLevel*/) +{ + msg().setLevel (outputLevel()); + msgSvc()->setOutputLevel(name(), outputLevel()); +} + +StatusCode +SGImplSvc::proxyRange(const CLID& id, + SG::ConstProxyIterator& begin, + SG::ConstProxyIterator& end) const { + return m_pStore->pRange(id,begin,end); +} + +StatusCode SGImplSvc::setConst(const void* pObject) +{ + // Check if dataproxy does not exist + DataProxy * dp = proxy(pObject); + + if (0 == dp) + { + msg() << MSG::WARNING + << "setConst: NO Proxy for the dobj you want to set const" + << endmsg; + return StatusCode::FAILURE; + } + + dp->setConst(); + return StatusCode::SUCCESS; +} + +//put a bad (unrecordable) dobj away +void SGImplSvc::recycle(DataObject* pBadDObj) { + assert(pBadDObj); + pBadDObj->addRef(); + m_trash.push_back(pBadDObj); +} + +//throw away bad objects +void SGImplSvc::emptyTrash() { + while (!m_trash.empty()) { + m_trash.front()->release(); //delete the bad data object + m_trash.pop_front(); //remove pointer from list + } +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +bool SGImplSvc::bindHandleToProxy(const CLID& id, const string& key, + IResetable* ir, DataProxy *&dp) +{ + + dp = (0 == m_pPPS) ? 0 : m_pPPS->retrieveProxy(id, key, *m_pStore); + + if (0 == dp) return false; + + if (! dp->bindHandle(ir) ) { + msg() << MSG::FATAL << "DataHandle at " << hex << ir << dec + << " already bound to DataProxy with key " << ir->key() + << ". Cannot bind to proxy " << dp->name() << " as well\n" + << " You have probably registered multiple callbacks via regFcn with the same DataHandle using different keys (DataProxies)\n" + << endmsg; + return false; + } + + //already done in DataHandleBase::setState dp->addRef(); + +#ifndef NDEBUG + SG_MSG_DEBUG(" Bound handle " << MSG::hex << ir << " to proxy " + << dp << MSG::dec); +#endif + return true; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +StatusCode +SGImplSvc::record_HistObj(const CLID& id, const std::string& key, + const std::string& store, + bool allowMods, bool resetOnly) { + + assert(m_pHistorySvc); + + DataHistory *dho; + dho = m_pHistorySvc->createDataHistoryObj( id, key, store ); + + std::string idname; + StatusCode sc = m_pCLIDSvc->getTypeNameOfID(id, idname); + if (sc.isFailure() || idname == "" ) { + std::ostringstream ost; + ost << id; + idname = ost.str(); + } + idname = idname + "/" + key; + + DataObject* obj = asStorable<DataHistory>(dho); + + const bool ALLOWOVERWRITE(false); + if (record_impl(obj, idname, dho, allowMods, resetOnly, ALLOWOVERWRITE, + &typeid(DataHistory)) == nullptr) + return StatusCode::FAILURE; + return StatusCode::SUCCESS; +} + + +/** + * @brief Find the key for a string/CLID pair. + * @param str The string to look up. + * @param clid The CLID associated with the string. + * @return A key identifying the string. + * A given string will always return the same key. + * Will abort in case of a hash collision! + */ +SGImplSvc::sgkey_t +SGImplSvc::stringToKey (const std::string& str, CLID clid) +{ + return m_stringpool.stringToKey (str, clid); +} + + +/** + * @brief Find the string corresponding to a given key. + * @param key The key to look up. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* SGImplSvc::keyToString (sgkey_t key) const +{ + return m_stringpool.keyToString (key); +} + + +/** + * @brief Find the string and CLID corresponding to a given key. + * @param key The key to look up. + * @param clid[out] The found CLID. + * @return Pointer to the string found, or null. + * We can find keys as long as the corresponding string + * was given to either @c stringToKey() or @c registerKey(). + */ +const std::string* +SGImplSvc::keyToString (sgkey_t key, CLID& clid) const +{ + return m_stringpool.keyToString (key, clid); +} + + +/** + * @brief Remember an additional mapping from key to string/CLID. + * @param key The key to enter. + * @param str The string to enter. + * @param clid The CLID associated with the string. + * @return True if successful; false if the @c key already + * corresponds to a different string. + * + * This registers an additional mapping from a key to a string; + * it can be found later through @c lookup() on the string. + * Logs an error if @c key already corresponds to a different string. + */ +void SGImplSvc::registerKey (sgkey_t key, + const std::string& str, + CLID clid) +{ + if (!m_stringpool.registerKey (key, str, clid)) { + CLID clid2; + const std::string* str2 = m_stringpool.keyToString (key, clid2); + REPORT_MESSAGE (MSG::WARNING) << "The numeric key " << key + << " maps to multiple string key/CLID pairs: " + << *str2 << "/" << clid2 << " and " + << str << "/" << clid; + } +} + +void +SGImplSvc::releaseObject(const CLID& id, const std::string& key) { + DataProxy *pP(0); + if (0 != (pP = proxy(id, key))) { + // remove all entries from t2p map + SG::DataProxy::CLIDCont_t clids = pP->transientID(); + SG::DataProxy::CLIDCont_t::const_iterator i(clids.begin()), e(clids.end()); + while (i != e) t2pRemove(SG::DataProxy_cast (pP, *i++)); + DataBucketBase *pDBB(dynamic_cast<DataBucketBase*>(pP->object())); + //tell the bucket to let go of the data object + if (0 != pDBB) pDBB->relinquish(); //somebody else better took ownership + bool hard_reset = (m_numSlots > 1); + pP->reset (hard_reset); + } +} + +void +SGImplSvc::clearProxyPayload(SG::DataProxy* dp) { + SG::DataProxy::CLIDCont_t clids = dp->transientID(); + SG::DataProxy::CLIDCont_t::const_iterator i(clids.begin()), e(clids.end()); + while (i != e) { + t2pRemove(SG::DataProxy_cast (dp, *i++)); + } + bool hard_reset = (m_numSlots > 1); + dp->reset (hard_reset); +} + + +/** + * @brief Declare a remapping. + * @brief source Key hash of the container being remapped. + * @brief target Key hash of the container being remapped to. + * @brief index_offset Amount by which the index should be adjusted + * between the two containers. + */ +void SGImplSvc::remap_impl (sgkey_t source, + sgkey_t target, + off_t index_offset) +{ + SG::RemapImpl::remap_t payload; + payload.target = target; + payload.index_offset = index_offset; + m_remap_impl->m_remaps[source] = payload; +} + + +/** + * @brief Test to see if the target of an ElementLink has moved. + * @param sgkey_in Original hashed key of the EL. + * @param index_in Original index of the EL. + * @param sgkey_out[out] New hashed key for the EL. + * @param index_out[out] New index for the EL. + * @return True if there is a remapping; false otherwise. + */ +bool SGImplSvc::tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out) +{ + SG::RemapImpl::remap_map_t::iterator i = + m_remap_impl->m_remaps.find (sgkey_in); + if (i == m_remap_impl->m_remaps.end()) + return false; + const SG::RemapImpl::remap_t& payload = i->second; + sgkey_out = payload.target; + index_out = index_in + payload.index_offset; + return true; +} + +DataObject* SGImplSvc::typeless_readPrivateCopy(const CLID& clid, + const std::string& key) { + DataObject *pObj(0); + DataProxy *p(this->proxy(clid, key)); + if (p) { + if (p->object()) { //this looks in transient mem only + //if there is a dobj in transient memory we take ownership with addRef + p->addRef(); + //and make the store forget about the proxy for a moment + const bool FORCEREMOVE(true); + bool hard_reset = (m_numSlots > 1); + store()->removeProxy(p, FORCEREMOVE, hard_reset).ignore(); + //now we try to read the object from disk. Relies on PPS to reload proxy + DataProxy *pDisk(this->proxy(clid, key)); + if (pDisk) { + //We are managing the pObj so we addRef it + if ( (pObj = pDisk->accessData()) ) pObj->addRef(); + //don't need this guy anymore, notice we use the SGImplSvc version + //to remove the t2p entry as well + removeProxy(pDisk, SG::DataProxy_cast(pDisk,clid), FORCEREMOVE).ignore(); + } + //replace the "transient" proxy where it was + if (store()->addToStore(clid, p).isFailure()) { + msg() << MSG::ERROR << "SGImplSvc::typeless_readPrivateCopy: " + << "could not re-record proxy in store: " + << clid << "/" << key << endmsg; + } + } else if ( (pObj = p->accessData()) ) { //try reading from disk + //We are managing the pObj so we addRef it + pObj->addRef(); + //and make the proxy forget about it + bool hard_reset = (m_numSlots > 1); + p->reset (hard_reset); + } + } + if (0 == pObj) { + string errType; + m_pCLIDSvc->getTypeNameOfID(clid, errType).ignore(); + msg() << MSG::WARNING << "SGImplSvc::typeless_readPrivateCopy: " + << "did not find object of type " + << errType << " with key " << key << endmsg; + } + return pObj; +} + +/// Add automatically-made symlinks for DP. +void SGImplSvc::addAutoSymLinks (const std::string& key, + CLID clid, + DataProxy* dp, + const std::type_info* tinfo, + bool warn_nobib /*= true*/) +{ + // Automatically make all legal base class symlinks + const SG::BaseInfoBase* bib = SG::BaseInfoBase::find( clid ); + if (!bib && tinfo) + bib = SG::BaseInfoBase::find (*tinfo); + if ( bib ) { + std::vector<CLID> bases = bib->get_bases(); + for ( std::size_t i = 0, iMax = bases.size(); i < iMax; ++i ) { + if ( bases[i] != clid ) { + if ( addSymLink( bases[i], dp ).isSuccess() ) { + // register with t2p + if (dp->object()) + this->t2pRegister( SG::DataProxy_cast( dp, bases[i] ), dp ).ignore(); + } + else { + msg() << MSG::WARNING + << "record_impl: Doing auto-symlinks for object with CLID " << clid + << " and SG key " << key + << ": Proxy already set for base CLID " << bases[i] + << "; not making auto-symlink." << endmsg; + } + } + } + + // Handle copy conversions. + { + BOOST_FOREACH(CLID copy_clid, bib->get_copy_conversions()) { + if (m_pStore->addSymLink (copy_clid, dp).isFailure()) { + msg() << MSG::WARNING + << "record_impl: Doing auto-symlinks for object with CLID " << clid + << " and SG key " << key + << ": Proxy already set for copy-conversion CLID " << copy_clid + << "; not making auto-symlink." << endmsg; + } + } + } + } + else { + if (warn_nobib) { + msg() << MSG::WARNING + << "record_impl: Could not find suitable SG::BaseInfoBase for CLID [" + << clid << "] (" << key << ") !\t" + << "No auto-symlink established !" + << endmsg; + } + } +} + +StatusCode SGImplSvc::getNewDataObjects(DataObjIDColl& products) { + tbb::spin_rw_mutex::scoped_lock lock(m_newDataLock,true); + products.swap(m_newDataObjects); + m_newDataObjects.clear(); + return StatusCode::SUCCESS; +} + +bool SGImplSvc::newDataObjectsPresent() /*const*/ { + tbb::spin_rw_mutex::scoped_lock lock(m_newDataLock,false); + return !m_newDataObjects.empty(); +} + +void +SGImplSvc::commitNewDataObjects() { + tbb::spin_rw_mutex::scoped_lock lock(m_newDataLock,true); + for (auto obj : s_newObjs) { + if (msg().level() <= MSG::VERBOSE) { + msg() << MSG::VERBOSE + << "committing dataObj \"" << obj << "\"" + << endmsg; + } + m_newDataObjects.insert( obj ); + } + s_newObjs.clear(); + + // Reset handles added since the last call to commit. + bool hard_reset = (m_numSlots > 1); + std::vector<IResetable*> handles; + m_newBoundHandles[std::this_thread::get_id()].swap (handles); + for (IResetable* h : handles) + h->reset (hard_reset); +} + +#ifndef SLOW_NEWDATAOBJECTS +void SGImplSvc::addedNewPersObject(CLID, DataProxy*) {} +void SGImplSvc::addedNewTransObject(CLID, const std::string&) {} +#else +void SGImplSvc::addedNewPersObject(CLID clid, DataProxy* dp) { + //if proxy is loading from persistency + //add key of object to list of "newly recorded" objects + if (0 != dp->transientAddress()->provider()) { + s_newObjs.insert(DataObjID(clid,dp->name())); + } +} +void SGImplSvc::addedNewTransObject(CLID clid, const std::string& key) { + s_newObjs.insert(DataObjID(clid,key)); +} +#endif + + +/** + * @brief Tell the store that a proxy has been bound to a handle. + * @param proxy The proxy that was bound. + * The default implemenatation does nothing. + */ +void +SGImplSvc::boundHandle (IResetable* handle) +{ + m_newBoundHandles[std::this_thread::get_id()].push_back (handle); +} + + +/** + * @brief Tell the store that a handle has been unbound from a proxy. + * @param handle The handle that was unbound. + * The default implementation does nothing. + */ +void +SGImplSvc::unboundHandle (IResetable* handle) +{ + std::vector<IResetable*>& v = m_newBoundHandles[std::this_thread::get_id()]; + std::vector<IResetable*>::iterator it = + std::find (v.begin(), v.end(), handle); + if (it != v.end()) + v.erase (it); +} + + +/// The current store is becoming the active store. Switch the +/// allocation arena, if needed. +// Only intended to be called by ActiveStoreSvc. +void SGImplSvc::makeCurrent() +{ + m_arena.makeCurrent(); + SG::CurrentEventStore::setStore (this); +} + + +// This is intended to be called from the debugger. +void SG_dump (SGImplSvc* sg) +{ + std::cout << sg->dump() << "\n"; +} + + diff --git a/EDM/athena/Control/StoreGate/src/SegMemSvc.cxx b/EDM/athena/Control/StoreGate/src/SegMemSvc.cxx new file mode 100644 index 00000000..ad4c99b5 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/SegMemSvc.cxx @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "StoreGate/SegMemSvc.h" + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/Incident.h" +#include "GaudiKernel/IIncidentListener.h" + +using namespace std; + + +// +/////////////////////////////////////////////////////////////////////////// +// + +SegMemSvc::SegMemSvc( const std::string& name, ISvcLocator* svc ) + : Service( name, svc ), p_incSvc("IncidentSvc",name), + m_log(msgSvc(), name), + m_arena_job("sms_job",&m_ahead_job), + m_arena_evt("sms_evt",&m_ahead_evt), + m_arena_inc("sms_inc",&m_ahead_inc) +{ + +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +SegMemSvc::~SegMemSvc() { + +} + + +StatusCode SegMemSvc::queryInterface( const InterfaceID& riid, + void** ppvInterface ) { + StatusCode sc = StatusCode::FAILURE; + if ( ppvInterface ) { + *ppvInterface = 0; + + if ( SegMemSvc::interfaceID().versionMatch(riid) ) { + *ppvInterface = static_cast<SegMemSvc*>(this); + sc = StatusCode::SUCCESS; + addRef(); + } + else + sc = Service::queryInterface( riid, ppvInterface ); + } + return sc; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +StatusCode +SegMemSvc::initialize() { + + SG::Arena::Push push(m_arena_job); + SG::Arena::Push push2(m_arena_evt); + SG::Arena::Push push3(m_arena_inc); + + // m_ahead.addArena(&m_arena); + + + p_incSvc->addListener( this, "EndEvent" ); + p_incSvc->addListener( this, "DefragMemory" ); + + return StatusCode::SUCCESS; + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +StatusCode +SegMemSvc::reinitialize() { + + return StatusCode::SUCCESS; + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +StatusCode +SegMemSvc::finalize() { + + return StatusCode::SUCCESS; + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void +SegMemSvc::handle(const Incident& inc) { + + if (inc.type() == "EndEvent") { + if (m_log.level() <= MSG::DEBUG) { + m_log << MSG::DEBUG << "Running report for " << m_arena_evt.name() + << std::endl; + std::ostringstream ost; + m_ahead_evt.report(ost); + m_log << MSG::DEBUG << ost.str() << endmsg; + // m_log << MSG::DEBUG << "header: " << m_ahead.reportStr() << endmsg; + + } + + m_log << MSG::DEBUG << "freeing all memory allocated for Event" + << endmsg; + m_arena_evt.reset(); + m_ahead_evt.reset(); + + } else if ( inc.type() == "DefragMemory") { + + if (m_log.level() <= MSG::DEBUG) { + m_log << MSG::DEBUG << "defragmenting memory" + << endmsg; + } + m_log << MSG::DEBUG << "freeing all memory allocated associated with " + << "DefragMemory incident" + << endmsg; + m_arena_inc.reset(); + m_ahead_inc.reset(); + } + +} + diff --git a/EDM/athena/Control/StoreGate/src/StoreClearedIncident.cxx b/EDM/athena/Control/StoreGate/src/StoreClearedIncident.cxx new file mode 100644 index 00000000..0e1acca2 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/StoreClearedIncident.cxx @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StoreClearedIncident.cxx,v 1.2 2008-09-10 04:07:14 ssnyder Exp $ +/** + * @file StoreGate/src/StoreClearedIncident.cxx + * @author scott snyder + * @date Sep 2008 + * @brief Incident sent after a store is cleared. + */ + + +#include "StoreGate/StoreClearedIncident.h" + + +/** + * @brief Constructor. + * @param sg The store that was cleared. + * @param source the name of the service/algorithm firing + * @param type e.g. "StoreCleared" + */ +StoreClearedIncident::StoreClearedIncident (StoreGateSvc* sg, + const std::string& source, + const std::string& type /*= "StoreCleared"*/) + : Incident (source, type), + m_sg (sg) +{ +} + + +/// Return the store that was cleared. +StoreGateSvc* StoreClearedIncident::store() const +{ + return m_sg; +} + diff --git a/EDM/athena/Control/StoreGate/src/StoreGate.cxx b/EDM/athena/Control/StoreGate/src/StoreGate.cxx new file mode 100644 index 00000000..875e1ecf --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/StoreGate.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "StoreGate/StoreGate.h" +#include "StoreGate/ActiveStoreSvc.h" +#include "StoreGate/tools/hash_functions.h" + +#include <exception> +#include <iostream> + +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/Kernel.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IService.h" + +using namespace std; + +ActiveStoreSvc* +getActiveStoreSvc() { + ActiveStoreSvc* pASG(0); + static const bool CREATEIF(true); + if ((Gaudi::svcLocator()->service("ActiveStoreSvc", pASG, CREATEIF)).isSuccess()) { + pASG->addRef(); //FIXME WHO RELEASES? + return pASG; + } else { +#ifndef NDEBUG + cerr << __FILE__ << ':' << __LINE__ << ": " + << "ERROR Could not locate ActiveStoreSvc " <<endl; +#endif + return 0; + } +} + +StoreGateSvc* +getStore() { + ActiveStoreSvc* pASG(0); + StoreGateSvc* pSG(0); + static const bool CREATEIF(true); + if ((Gaudi::svcLocator()->service("ActiveStoreSvc", pASG, CREATEIF)).isSuccess() && + 0 != (pSG = pASG->operator->())) { + pSG->addRef(); //FIXME WHO RELEASES? + return pSG; + } else { +#ifndef NDEBUG + cerr << __FILE__ << ':' << __LINE__ << ": " + << "ERROR Could not locate active StoreGate " <<endl; +#endif + return 0; + } +} + +StoreGateSvc* +getStore(std::string name) throw (std::runtime_error) { + StoreGateSvc* pSGService(0); + static const bool CREATEIF(true); + if ((Gaudi::svcLocator()->service(name, pSGService, CREATEIF)).isSuccess()) { + pSGService->addRef(); + return pSGService; + } else { +#ifndef NDEBUG + cerr << __FILE__ << ':' << __LINE__ << ": " + << "ERROR Could not locate StoreGate " + << "instance named " << name << endl; +#endif + return 0; + } +} + +StoreGateSvc* +StoreGate::pointer() { + return getStore(); +} + + +StoreGateSvc& +StoreGate::instance() { + StoreGateSvc* ptr(pointer()); + if (0 == ptr) { + throw std::runtime_error("Could not locate active StoreGate "); + } + return *ptr; +} + +ActiveStoreSvc* +StoreGate::activeStoreSvc() { + return getActiveStoreSvc(); +} + +StoreGateSvc* +StoreGate::pointer(std::string sgID) { + return getStore(sgID); +} + + +StoreGateSvc& +StoreGate::instance(std::string sgID) { + StoreGateSvc* ptr(pointer(sgID)); + if (0 == ptr) { + throw std::runtime_error("Could not locate required StoreGate instance"); + } + return *ptr; +} + + + + + + + + + + + + diff --git a/EDM/athena/Control/StoreGate/src/StoreGateSvc.cxx b/EDM/athena/Control/StoreGate/src/StoreGateSvc.cxx new file mode 100644 index 00000000..a4129e76 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/StoreGateSvc.cxx @@ -0,0 +1,552 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef ATHENAHIVE +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/IAppMgrUI.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "AthenaKernel/errorcheck.h" +#include "StoreGate/StoreClearedIncident.h" +#include "AthAllocators/ArenaHeader.h" + +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/ActiveStoreSvc.h" +#include "StoreGate/tools/SGImplSvc.h" + +using namespace SG; +using namespace std; + +__thread HiveEventSlot* s_pSlot(0); + + +/// Standard Constructor +StoreGateSvc::StoreGateSvc(const std::string& name,ISvcLocator* svc) : + Service(name,svc), + m_defaultStore(0), m_defaultStoreName(name+"_Impl"), + m_pPPSHandle("ProxyProviderSvc", name), + m_incSvc("IncidentSvc", name) +{ + //our properties + declareProperty("defaultStoreName", m_defaultStoreName, "the implementation for the default event store"); + + //properties of SGImplSvc + declareProperty("Dump", m_DumpStore=false, "Dump contents at EndEvent"); + declareProperty("ActivateHistory", m_ActivateHistory=false, "record DataObjects history"); + declareProperty("ProxyProviderSvc", m_pPPSHandle); + declareProperty("IncidentSvc", m_incSvc); + + //add handler for Service base class property + //FIXME m_outputLevel.declareUpdateHandler(&SGImplSvc::msg_update_handler, this); +} + +/// Standard Destructor +StoreGateSvc::~StoreGateSvc() +{} + +void +StoreGateSvc::setDefaultStore(SGImplSvc* pStore) { + if (m_defaultStore) m_defaultStore->release(); + m_defaultStore = pStore; + if (m_defaultStore) m_defaultStore->addRef(); +} + +bool +StoreGateSvc::isHiveStore() const { + return ((m_defaultStore->store()->storeID() == StoreID::EVENT_STORE) && (0 != s_pSlot)); +} + +SGImplSvc* +StoreGateSvc::currentStore() const { + return isHiveStore() ? s_pSlot->pEvtStore : m_defaultStore; +} + + +void +StoreGateSvc::setSlot(SG::HiveEventSlot* pSlot) { + s_pSlot=pSlot; + if ( 0 != s_pSlot) { + //probably overkill since Hive should not call setSlot concurrently + SG::HiveEventSlot::mutex_t::scoped_lock lock; + lock.acquire(s_pSlot->storeMutex); + s_pSlot->pEvtStore->makeCurrent(); + } +} + +SG::HiveEventSlot* +StoreGateSvc::currentSlot() { + return s_pSlot; +} + +///////////////////////////////////////////////////////////////// + + +bool +StoreGateSvc::newDataObjectsPresent() { + _SGXCALL(newDataObjectsPresent, (), false); +} + +StatusCode +StoreGateSvc::getNewDataObjects(DataObjIDColl& products) { + _SGXCALL(getNewDataObjects, (products), StatusCode::FAILURE); +} + +void +StoreGateSvc::commitNewDataObjects() { + _SGVOIDCALL(commitNewDataObjects, ()); +} + +///a new object transient object has been recorded +void +StoreGateSvc::addedNewTransObject(CLID clid, const std::string& key) { + _SGVOIDCALL(addedNewTransObject, (clid, key)); +} + +///a new object persistent object has been recorded +void +StoreGateSvc::addedNewPersObject(CLID clid, SG::DataProxy* dp) { + _SGVOIDCALL(addedNewPersObject, (clid, dp)); +} + +/// Create a proxy object using an IOpaqueAddress and a transient key +StatusCode +StoreGateSvc::recordAddress(const std::string& skey, + IOpaqueAddress* pAddress, bool clearAddressFlag) { + _SGXCALL(recordAddress, (skey, pAddress, clearAddressFlag), StatusCode::FAILURE); +} +/// Create a proxy object using an IOpaqueAddress +StatusCode +StoreGateSvc::recordAddress(IOpaqueAddress* pAddress, bool clearAddressFlag) { + _SGXCALL(recordAddress, (pAddress, clearAddressFlag), StatusCode::FAILURE); +} + + +StatusCode +StoreGateSvc::setConst(const void* pObject) { + _SGXCALL(setConst, (pObject), StatusCode::FAILURE); +} + +/// DEPRECATED, use version taking ref to vector +std::vector<std::string> //FIXME inefficient. Should take ref to vector +StoreGateSvc::keys(const CLID& id, bool allKeys){ + std::vector<std::string> nullV; + _SGXCALL( keys, (id, allKeys), nullV ); +} + + + + +///////////////////////////////////////////////////////////// +/// Service initialisation +StatusCode StoreGateSvc::initialize() { + + // Initialize service: + if(!(Service::initialize()).isSuccess()) return StatusCode::FAILURE; + + MsgStream log( messageService(), name() ); + log << MSG::VERBOSE << "Initializing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + + // lifted from AlwaysPrivateToolSvc (see Wim comment about lack of global jo svc accessor + // retrieve the job options svc (TODO: the code below relies heavily on + // internals; figure out if there's no global getJobOptionsSvc() ... ) + IAppMgrUI* appmgr = Gaudi::createApplicationMgr(); + IProperty* appmgrprop = 0; + appmgr->queryInterface( IProperty::interfaceID(), (void**)&appmgrprop ).ignore(); + //all of the above to get the jo svc type + const Property& prop = appmgrprop->getProperty( "JobOptionsSvcType" ); + IJobOptionsSvc* pJOSvc(0); + if ( serviceLocator()->service( prop.toString(), "JobOptionsSvc", pJOSvc ).isFailure() ) { + error() << "Failed to retrieve JobOptionsSvc" << endmsg; + } + //copy our properties to the prototype (default) SGImplSvc + const std::vector<const Property*>* props = pJOSvc->getProperties( name() ); + if ( props ) { + std::vector<const Property*>::const_iterator prop(props->begin()); + std::vector<const Property*>::const_iterator pEnd(props->end()); + while (prop != pEnd) { + pJOSvc->addPropertyToCatalogue( m_defaultStoreName, **prop ).ignore(); + ++prop; + } + } + pJOSvc->release(); + pJOSvc=0; + + //HACK ALERT: using createService rather then the customary service(...,CREATEIF=true) we set our pointer + // to SGImplSvc early (even before it is initialized). This should help take care of some initialize loops + // for example when we try to record an address from one of the address providers initialize methods + ISvcManager* pSM(dynamic_cast<ISvcManager*>(&*serviceLocator())); + m_defaultStore = dynamic_cast<SGImplSvc*>( (pSM->createService("SGImplSvc/"+m_defaultStoreName)).get() ); + if ( m_defaultStore && m_defaultStore->initialize().isSuccess() ) { + // createService returns to us a reference to the service; we shouldn't + // increment it again. + //m_defaultStore->addRef(); + + // If this is the default event store (StoreGateSvc), then declare + // our arena as the default for memory allocations. + if (name() == "StoreGateSvc") { + m_defaultStore->makeCurrent(); + } + } else { + error() << "Could not locate default store " << m_defaultStoreName << endmsg; + return StatusCode::FAILURE; + } + if ( !m_incSvc.retrieve().isSuccess() ) { + error() << "Could not locate IncidentSvc" << endmsg; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +/// Service start +StatusCode StoreGateSvc::stop() { + msg() << MSG::VERBOSE << "Stop " << name() << endmsg; + //HACK ALERT: ID event store objects refer to det store objects + //by setting an ad-hoc priority for event store(s) we make sure they are finalized and hence cleared first + // see e.g. https://savannah.cern.ch/bugs/index.php?99993 + if (store()->storeID() == StoreID::EVENT_STORE) { + ISvcManager* pISM(dynamic_cast<ISvcManager*>(serviceLocator().get())); + if (!pISM) + return StatusCode::FAILURE; + pISM->setPriority(name(), pISM->getPriority(name())+1).ignore(); + msg() << MSG::VERBOSE << "stop: setting service priority to " << pISM->getPriority(name()) + << " so that event stores get finalized and cleared before other stores" <<endmsg; + } + return StatusCode::SUCCESS; +} + +////////////////////////////////////////////////////////////// +IIOVSvc* StoreGateSvc::getIIOVSvc() { + // Get hold of the IOVSvc + if (0 == m_pIOVSvc && !(service("IOVSvc", m_pIOVSvc)).isSuccess()) { + msg() << MSG::WARNING + << "Could not locate IOVSvc " + << endmsg; + } + return m_pIOVSvc; +} + +StatusCode +StoreGateSvc::finalize() { + if(!(Service::finalize()).isSuccess()) return StatusCode::FAILURE; + MsgStream log( messageService(), name() ); + log << MSG::VERBOSE << "Finalizing " << name() + << " - package version " << PACKAGE_VERSION << endmsg ; + if (m_defaultStore) { + // m_defaultStore is not active, so ServiceManager won't finalize it! + CHECK( m_defaultStore->finalize()); + m_defaultStore->release(); + } + return StatusCode::SUCCESS; +} + + +/// get proxy for a given data object address in memory +DataProxy* +StoreGateSvc::proxy(const void* const pTransient) const { + _SGXCALL(proxy, (pTransient), 0); +} + +/// get default proxy with given id. Returns 0 to flag failure +DataProxy* +StoreGateSvc::proxy(const CLID& id) const { + _SGXCALL(proxy, (id), 0); +} + +/// get proxy with given id and key. Returns 0 to flag failure +DataProxy* +StoreGateSvc::proxy(const CLID& id, const std::string& key) const { + _SGXCALL(proxy, (id, key), 0); +} + + +/// get default proxy with given id, optionally checking validity. +/// @returns 0 to flag failure +SG::DataProxy* +StoreGateSvc::proxy(const CLID& id, bool checkValid) const { + _SGXCALL(proxy, (id, checkValid), 0); +} + +/// get proxy with given id and key, optionally checking validity. +/// @returns 0 to flag failure +SG::DataProxy* +StoreGateSvc::proxy(const CLID& id, const std::string& key, bool checkValid) const { + _SGXCALL(proxy, (id, key, checkValid), 0); +} + + +/** + * @brief Raw addition of a proxy to the store. + * @param id CLID of object being added. + * @param proxy proxy to add. + */ +StatusCode StoreGateSvc::addToStore (CLID id, SG::DataProxy* proxy) +{ + _SGXCALL(addToStore, (id, proxy), StatusCode::FAILURE); +} + + +/** + * @brief Record an object in the store. + * @param obj The data object to store. + * @param key The key as which it should be stored. + * @param allowMods If false, the object will be recorded as const. + * @param returnExisting If true, return proxy if this key already exists. + * If the object has been recorded under a different + * key, then make an alias. + * + * Full-blown record. @c obj should usually be something + * deriving from @c SG::DataBucket. + * + * Returns the proxy for the recorded object; nullptr on failure. + * If the requested CLID/key combination already exists in the store, + * the behavior is controlled by @c returnExisting. If true, then + * the existing proxy is returned; otherwise, nullptr is returned. + * In either case, @c obj is destroyed. + */ +SG::DataProxy* +StoreGateSvc::recordObject (SG::DataObjectSharedPtr<DataObject> obj, + const std::string& key, + bool allowMods, + bool returnExisting) +{ + _SGXCALL(recordObject, (std::move(obj), key, allowMods, returnExisting), nullptr); +} + + +/** + * @brief Inform HIVE that an object has been updated. + * @param id The CLID of the object. + * @param key The key of the object. + */ +StatusCode StoreGateSvc::updatedObject (CLID id, const std::string& key) +{ + _SGXCALL(updatedObject, (id, key), StatusCode::FAILURE); +} + + +/// return the list of all current proxies in store +vector<const SG::DataProxy*> +StoreGateSvc::proxies() const { + vector<const SG::DataProxy*> nullV; + _SGXCALL(proxies, (), nullV); +} + +/// get proxy with given id and key. Does not query ProxyProviderSvc. +/// @returns 0 to flag failure +SG::DataProxy* +StoreGateSvc::transientProxy(const CLID& id, const std::string& key) const { + _SGXCALL(transientProxy, (id, key), 0); +} + + +/// find proxy and access its data. Returns 0 to flag failure +DataObject* +StoreGateSvc::accessData(const CLID& id) const { + _SGXCALL(accessData, (id), 0); +} + +/// find proxy and access its data. Returns 0 to flag failure +DataObject* +StoreGateSvc::accessData(const CLID& id, const std::string& key) const { + _SGXCALL(accessData, (id, key), 0); +} + +bool +StoreGateSvc::transientSwap( const CLID& id, + const std::string& keyA, const std::string& keyB ) { + _SGXCALL(transientSwap, (id, keyA, keyB), false); +} + +DataObject* +StoreGateSvc::typeless_readPrivateCopy(const CLID& clid, const std::string& key) { + _SGXCALL(typeless_readPrivateCopy, (clid, key), 0); +} +/// type-less recording of an object with a key, allow possibility of +/// specifying const-access and history record +StatusCode +StoreGateSvc::typeless_record( DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, bool resetOnly, + bool noHist ) { + _SGXCALL(typeless_record, (obj, key, raw_ptr, allowMods, resetOnly, noHist), StatusCode::FAILURE); +} +/// same as typeless_record, allows to ovewrite an object in memory or on disk +StatusCode +StoreGateSvc::typeless_overwrite( const CLID& id, + DataObject* obj, const std::string& key, + const void* const raw_ptr, + bool allowMods, + bool noHist, + const std::type_info* tinfo) { + _SGXCALL(typeless_overwrite, (id, obj, key, raw_ptr, allowMods, noHist, tinfo), StatusCode::FAILURE); +} + +/// set store id in DataStore: +void +StoreGateSvc::setStoreID(StoreID::type id) +{ + _SGVOIDCALL(setStoreID,(id)); +} +StoreID::type +StoreGateSvc::storeID() const +{ + _SGXCALL(storeID,(),StoreID::UNKNOWN); +} + +void +StoreGateSvc::keys(const CLID& id, std::vector<std::string>& vkeys, + bool includeAlias, bool onlyValid) +{ + _SGVOIDCALL(keys,(id, vkeys, includeAlias, onlyValid)); +} + + + +std::string +StoreGateSvc::dump() const { + std::string nullS; + _SGXCALL(dump, (), nullS); +} + +int +StoreGateSvc::typeCount(const CLID& clid) const{ + _SGXCALL(typeCount, (clid), -1); +} + + + +typename StoreGateSvc::sgkey_t +StoreGateSvc::stringToKey (const std::string& str, CLID clid) { + _SGXCALL( stringToKey, (str, clid), 0 ); +} + +const std::string* +StoreGateSvc::keyToString (sgkey_t key) const { + _SGXCALL( keyToString, (key), 0 ); +} + +const std::string* +StoreGateSvc::keyToString (sgkey_t key, CLID& clid) const { + _SGXCALL( keyToString, (key, clid), 0 ); +} + +void +StoreGateSvc::registerKey (sgkey_t key, + const std::string& str, + CLID clidid) { + _SGVOIDCALL( registerKey, (key, str, clidid) ); +} +void +StoreGateSvc::remap_impl (sgkey_t source, + sgkey_t target, + off_t index_offset) { + _SGVOIDCALL( remap_impl, (source, target, index_offset) ); +} + +bool +StoreGateSvc::tryELRemap (sgkey_t sgkey_in, size_t index_in, + sgkey_t& sgkey_out, size_t& index_out) { + _SGXCALL( tryELRemap, (sgkey_in, index_in, sgkey_out, index_out), false ); +} + +StatusCode +StoreGateSvc::proxyRange(const CLID& id, + SG::ConstProxyIterator& beg, + SG::ConstProxyIterator& end) const { + _SGXCALL( proxyRange, (id, beg, end), StatusCode::FAILURE ); +} + + +void +StoreGateSvc::releaseObject(const CLID& id, const std::string& key) { + _SGVOIDCALL( releaseObject, (id, key) ); +} + +void +StoreGateSvc::clearProxyPayload(SG::DataProxy* proxy) { + _SGVOIDCALL( clearProxyPayload, (proxy) ); +} + + +StatusCode +StoreGateSvc::loadEventProxies() { + ActiveStoreSvc* pActive(0); + const bool CREATEIF(true); + if (!(serviceLocator()->service("ActiveStoreSvc", pActive, CREATEIF)).isSuccess()) return StatusCode::FAILURE; + pActive->setStore(this); + _SGXCALL(loadEventProxies, (), StatusCode::FAILURE); +} + +////////////////////////////////////////////////////////////// +// clear store +StatusCode +StoreGateSvc::clearStore(bool forceRemove) +{ + StatusCode sc; + if (isHiveStore()) { + SG::HiveEventSlot::mutex_t::scoped_lock lock; lock.acquire(s_pSlot->storeMutex); + if (0 != s_pSlot->pEvtStore) { + sc = s_pSlot->pEvtStore->clearStore(forceRemove); + } + } else sc = m_defaultStore->clearStore(forceRemove); + + // Send a notification that the store was cleared. + if (sc.isSuccess()) { + m_incSvc->fireIncident(StoreClearedIncident (this, name())); + } + return sc; +} + +void +StoreGateSvc::emptyTrash() { + _SGVOIDCALL( emptyTrash, () ); +} + +const InterfaceID& +StoreGateSvc::interfaceID() { + static const InterfaceID _IDStoreGateSvc("StoreGateSvc", 1, 0); + return _IDStoreGateSvc; +} +StatusCode StoreGateSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( interfaceID().versionMatch(riid) ) { + *ppvInterface = (StoreGateSvc*)this; + } + else if ( IProxyDict::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IProxyDict*)this; + } + else if ( IHiveStore::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IHiveStore*)this; + } + else if ( IHiveStoreMgr::interfaceID().versionMatch(riid) ) { + *ppvInterface = (IHiveStoreMgr*)this; + } + else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + + +/// The current store is becoming the active store. Switch the +/// allocation arena, if needed. +// Only intended to be called by ActiveStoreSvc. +void StoreGateSvc::makeCurrent() +{ + _SGVOIDCALL (makeCurrent, ()); +} + +StatusCode StoreGateSvc::removeProxy(SG::DataProxy* proxy, const void* pTrans, + bool forceRemove) { + _SGXCALL(removeProxy, (proxy, pTrans, forceRemove), StatusCode::FAILURE); +} + + +#endif //ATLASHIVE diff --git a/EDM/athena/Control/StoreGate/src/VarHandleBase.cxx b/EDM/athena/Control/StoreGate/src/VarHandleBase.cxx new file mode 100644 index 00000000..0e981f3a --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/VarHandleBase.cxx @@ -0,0 +1,831 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// VarHandleBase.cxx +// Implementation file for class VarHandleBase +// Author: Paolo Calafiura +// Author: S.Binet<binet@cern.ch> +/////////////////////////////////////////////////////////////////// + +#undef DEBUG_VHB /* define to get verbose debug printouts */ + +#include "StoreGate/VarHandleBase.h" + +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/exceptions.h" + +#include "SGTools/DataBucketBase.h" +#include "SGTools/StorableConversions.h" + +// fwk includes +#include "GaudiKernel/MsgStream.h" +#include "AthenaKernel/IHiveStore.h" +#include "AthenaKernel/getMessageSvc.h" +#include "AthenaKernel/errorcheck.h" +#include "GaudiKernel/ThreadLocalContext.h" + +#include <algorithm> +#include <sstream> + + +namespace errorcheck { + + + /** + * @brief Return a context name for a VarHandle. + * @param context The VarHandle. + * + * For use with the CHECK and REPORT_MESSAGE macros. + */ + std::string context_name (const SG::VarHandleBase* context) + { + std::ostringstream ss; + ss << "VarHandle(" + << context->storeHandle().name() << "/" << context->key() + << "[" << context->clid() << "]" + << ")"; + return ss.str(); + } + + +} // namespace errorcheck + + +namespace SG { + + + /** + * @brief Constructor with default key. + * @param clid CLID of the referenced class. + * @param mode Mode of this handle (read/write/update). + */ + VarHandleBase::VarHandleBase(CLID clid, Gaudi::DataHandle::Mode mode) : + VarHandleKey (clid, "", mode), + IResetable(), + m_ptr(0), + m_proxy(0), + m_store(nullptr) + { +#ifdef DEBUG_VHB + std::cerr << "VarHandleBase() " << this << std::endl; +#endif + } + + + /** + * @brief Constructor with full arguments. + * @param clid CLID of the referenced class. + * @param sgkey StoreGate key of the referenced object. + * @param mode Mode of this handle (read/write/update). + * @param storename Name of the referenced event store. + */ + VarHandleBase::VarHandleBase(CLID clid, + const std::string& sgkey, + Gaudi::DataHandle::Mode mode, + const std::string& storename) : + VarHandleKey(clid, sgkey, mode, storename), + IResetable(), + m_ptr(NULL), + m_proxy(NULL), + m_store(nullptr) + { + } + + + /** + * @brief Constructor from a VarHandleKey. + * @param key The key object holding the clid/key/store. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + */ + VarHandleBase::VarHandleBase(const VarHandleKey& key) : + VarHandleKey(key), + IResetable(), + m_ptr(nullptr), + m_proxy(nullptr), + m_store(nullptr) + { + if (key.storeHandle().get() == nullptr) + throw SG::ExcUninitKey (key.clid(), key.key(), + key.storeHandle().name()); + + if (storeFromHandle().isFailure()) + throw SG::ExcHandleInitError (key.clid(), key.key(), + key.storeHandle().name()); + } + + + /** + * @brief Constructor from a VarHandleKey and an explicit event context. + * @param key The key object holding the clid/key. + * @param ctx The current event context. + * + * This will raise an exception if the StoreGate key is blank, + * or if the event store cannot be found. + * + * If the default event store has been requested, then the thread-specific + * store from the event context will be used. + */ + VarHandleBase::VarHandleBase(const VarHandleKey& key, const EventContext& ctx) : + VarHandleBase (key) + { + if (storeHandle().name() == "StoreGateSvc") + m_store = ctx.proxy(); + } + + + /** + * @brief Copy constructor. + */ + VarHandleBase::VarHandleBase( const VarHandleBase& rhs ) : + VarHandleKey(rhs), + IResetable(), + m_ptr(rhs.m_ptr), + m_proxy(nullptr), + m_store(rhs.m_store) + { +#ifdef DEBUG_VHB + std::cerr << "::VHB::copy constr from " << &rhs + << " to " << this << ", " + << "proxy=" << this->m_proxy << ", " + << "key=" <<this->key() + << std::endl; +#endif + + setProxy (rhs.m_proxy); + } + + + /** + * @brief Move constructor. + */ + VarHandleBase::VarHandleBase( VarHandleBase&& rhs ) : + VarHandleKey (std::move (rhs)), + IResetable(), + m_ptr(rhs.m_ptr), + m_proxy(nullptr), + m_store(rhs.m_store) + { + rhs.m_ptr=0; + + if (rhs.m_proxy) { + rhs.m_proxy->unbindHandle (&rhs); + rhs.m_proxy->bindHandle(this); + m_proxy = rhs.m_proxy; + rhs.m_proxy=0; //no release: this has the ref now + } +#ifdef DEBUG_VHB + std::cerr << "::VHB:: move constr from " << &rhs + << "to " << this << ", " + << "proxy=" << this->m_proxy << ", " + << "key=" <<this->key() + << std::endl; +#endif + } + + + /** + * @brief Assignment operator. + */ + VarHandleBase& + VarHandleBase::operator=( const VarHandleBase& rhs ) + { + if (this != &rhs) { + VarHandleKey::operator= (rhs); + m_ptr = rhs.m_ptr; + m_store = rhs.m_store; + setProxy (rhs.m_proxy); + } +#ifdef DEBUG_VHB + std::cerr << "::VHB::assignment from " << &rhs + << " to " << this << ", " + << "proxy=" << this->m_proxy << ", " + << "key=" <<this->key() + << std::endl; +#endif + return *this; + } + + + /** + * @brief Move operator. + */ + VarHandleBase& + VarHandleBase::operator=( VarHandleBase&& rhs ) + { + if (this != &rhs) { + VarHandleKey::operator= (std::move (rhs)); + + m_ptr = rhs.m_ptr; + m_store = rhs.m_store; + + rhs.m_ptr=0; + + resetProxy(); + if (rhs.m_proxy) { + rhs.m_proxy->unbindHandle (&rhs); + rhs.m_proxy->bindHandle (this); + m_proxy = rhs.m_proxy; + rhs.m_proxy=0; //no release: this has the ref now + } + } +#ifdef DEBUG_VHB + std::cerr << "::VHB:: move assign from " << &rhs + << " to " << this << ", " + << "proxy=" << this->m_proxy << ", " + << "key=" <<this->m_sgkey + << std::endl; +#endif + return *this; + } + + + /** + * @brief Destructor. + */ + VarHandleBase::~VarHandleBase() + { +#ifdef DEBUG_VHB + std::cerr << "~VarHandleBase(" << this + << ",ptr=" << this->m_ptr + << ",proxy=" << this->m_proxy << ", "; + if (m_proxy) { + std::cerr << " -- isValid: " << m_proxy->isValid() + << " -- isConst: " << m_proxy->isConst(); + } + std::cerr << ", key=" <<this->m_sgkey << ")...\n"; +#endif + + resetProxy(); + m_ptr = 0; + } + + + + //************************************************************************* + // Accessors + // + + + /** + * @brief Return the StoreGate ID for the referenced object. + * + * This is defined in @c VarHandleKey. We need to redefine it here because + * it's also in @c IResetable. (Otherwise there would be an ambiguity.) + */ + const std::string& VarHandleBase::key() const + { + return VarHandleKey::key(); + } + + + /** + * @brief Return the StoreGate ID for the referenced object. + * + * A synonym for key(). + */ + const std::string& VarHandleBase::name() const + { + return this->key(); + } + + + /** + * @brief Return the name of the store holding the object we are proxying. + */ + std::string VarHandleBase::store() const + { + if (m_store) + return m_store->name(); + return this->storeHandle().name(); + } + + + //************************************************************************* + // Validity checking. + // + + + /** + * @brief Is the referenced object present in SG? + * + * Const method; the handle does not change as a result of this. + */ + bool VarHandleBase::isPresent() const + { + const DataProxy* proxy = m_proxy; + if (!proxy) { + IProxyDict* store = m_store; + if (!store) + store = this->storeHandle().get(); + if (store) + proxy = m_store->proxy(this->clid(), this->key()); + } + if (proxy) { + return proxy->isValid(); + } + return false; + } + + + /** + * @brief Has a proxy been retrieved from SG? + * + * (Weaker test than @c isValid, but does not touch the disk.) + */ + bool + VarHandleBase::isInitialized() const + { +#ifdef DEBUG_VHB + std::cerr << "::VHB::isInitialized(" + << this + << ", proxy" << m_proxy << ") const\n"; +#endif + return (0 != m_proxy); + } + + + /** + * @brief Has a proxy been retrieved from SG? + * + * Same as @c isInitialized; this is an interface required by @c IResetable. + */ + bool VarHandleBase::isSet() const + { + return isInitialized(); + } + + + /** + * @brief True if this handle has a proxy, and the proxy is const. + * + * Refers to the state of the proxy, not of the handle. + */ + bool + VarHandleBase::isConst() const + { +#ifdef DEBUG_VHB + std::cerr << "::VHB::isConst(" + << this + << ", proxy" << m_proxy; + if (m_proxy) { + std::cerr + << " -- isValid: " << m_proxy->isValid() + << " -- isConst: " << m_proxy->isConst(); + } + std::cerr << ") const\n"; +#endif + return 0 != m_proxy + ? m_proxy->isConst() + : false; + } + + + /** + * @brief Retrieve and cache all information managed by a handle. + * + * This will retrieve and cache the associated @c DataProxy. + * + * Note for the case of a WriteHandle that has not yet been written to, + * the proxy may not exist. We return Success in that case; however, + * @c isInitialized will still return false. + */ + StatusCode + VarHandleBase::initialize() + { + if (!m_store) { + CHECK( VarHandleKey::initialize() ); + m_store = this->storeHandle().get(); + } + + if (!m_store) + return StatusCode::FAILURE; + + StatusCode sc = this->setState(m_store->proxy(this->clid(), this->key())); + + // Failure to find the proxy is ok in the case of a @c WriteHandle + // that has not yet been written to. + if (sc.isFailure() && mode() == Gaudi::DataHandle::Writer && m_ptr == nullptr) + return StatusCode::SUCCESS; + + return sc; + } + + + /** + * @brief Retrieve and cache all information managed by a handle. + * + * Synonym for initialize(). + */ + StatusCode + VarHandleBase::setState() + { + return initialize(); + } + + + //************************************************************************* + // State setting. + // + + + /** + * @brief Explicitly set the event store. + * @param store The new event store. + * + * This implicitly does a reset(). + */ + StatusCode VarHandleBase::setProxyDict (IProxyDict* store) + { + reset(true); + m_store = store; + return StatusCode::SUCCESS; + } + + + /** + * @brief Reset this handle. + * @param hard If true, anything depending on the event store is cleared. + * + * If the handle stays associated with a given event store, then hard=false. + * In that case, we clear the cached pointer; the proxy is also dropped + * if it is reset only. If hard=true, then we always drop the proxy and + * in addition clear the cached pointer to the event store. + */ + void + VarHandleBase::reset (bool hard) { +#ifdef DEBUG_VHB + std::cerr << "::VHB::reset(" + << "ptr=" << this->m_ptr << ", " + << "proxy=" << this->m_proxy << ", " + << "key=" <<this->key() + << ")..." + << std::endl; +#endif + m_ptr = 0; + + if (hard) + m_store = 0; + + //if the proxy is not resetOnly then release it as it will become invalid + // Also release on a hard reset. + if (0 != m_proxy && (!m_proxy->isResetOnly() || hard)) { + resetProxy(); + } + } + + + /** + * @brief Reset this handle at the end of processing. + * @brief hard If true, anything depending on the event store is cleared. + * + * Same as reset(true); + */ + void VarHandleBase::finalReset() { +#ifdef DEBUG_VHB + std::cerr << "::VHB::finalReset(" + << "ptr=" << this->m_ptr << ", " + << "proxy=" << this->m_proxy << ", " + << "key=" <<this->key() + << ")..." + << std::endl; +#endif + reset (true); + } + + + /** + * @brief Set the 'const' bit for the bound proxy in the store. + */ + StatusCode VarHandleBase::setConst() + { + if (typeless_dataPointer()) { + m_proxy->setConst(); + return StatusCode::SUCCESS; + } + return StatusCode::FAILURE; + } + + + //************************************************************************* + // Protected methods. + // + + + /** + * @brief Set the state of the handle to a given proxy. + * @param proxy The proxy to set. + * + * The proxy must be valid; otherwise FAILURE will be returned. + */ + StatusCode + VarHandleBase::setState(SG::DataProxy* proxy) + { +#ifdef DEBUG_VHB + std::cerr << "::VHB::setState(" + << proxy; + if (0 != proxy) { + std::cerr << " -- isValid: " << proxy->isValid() + << " -- isConst: " << proxy->isConst(); + } + std::cerr << ") const\n"; +#endif + if (0 == proxy || !proxy->isValid()) { + return StatusCode::FAILURE; + } + + if (m_proxy != proxy) { + // We're changing proxies. Release the old and bind to the new. + setProxy (proxy); + // Clear cached pointer. + m_ptr=0; + } + + return StatusCode::SUCCESS; + } + + + /** + * @brief Set the state of a handle from a store and a key name. + * @param store The event store to access. + * @param name The StoreGate key to search for. + */ + StatusCode + VarHandleBase::setState(IProxyDict* store, const std::string& key) + { + if (0 == store) { + return StatusCode::FAILURE; + } +#ifdef DEBUG_VHB + std::cerr << "::VHB::setState(" + << store->name() << ", " + << key + << ") const\n"; +#endif + CLID cid = this->clid(); + SG::DataProxy* proxy = store->proxy(cid, key); + // std::cerr << "::VHB:: -- clid=[" << cid << "] proxy=[" << proxy << "]\n"; + return this->setState(proxy); + } + + + /** + * @brief Helper to record an object in the event store. + * @param The wrapped data object (DataBucket) to record. + * @param dataPtr Pointer to the transient object itself. + * @param allowMods If false, record the object as const. + * @param returnExisting Allow an existing object. + * + * If there is already an existing object with our key, then return + * failure, unless @c returnExisting is true, in which case + * return success. In either case, @c dobj is destroyed. + */ + StatusCode + VarHandleBase::record_impl (std::unique_ptr<DataObject> dobj, + void* dataPtr, + bool allowMods, + bool returnExisting) + { + if (!m_store) { + CHECK (VarHandleKey::initialize()); + m_store = this->storeHandle().get(); + } + + if (this->name() == "") { + REPORT_ERROR (StatusCode::FAILURE) << "Attempt to record an object with a null key"; + return StatusCode::FAILURE; + } + + SG::DataObjectSharedPtr<DataObject> sptr (dobj.release()); + unsigned int initRefCount = sptr->refCount(); + SG::DataProxy* new_proxy = + m_store->recordObject (sptr, this->name(), allowMods, returnExisting); + if (!new_proxy) { + REPORT_ERROR (StatusCode::FAILURE) << "recordObject failed"; + resetProxy(); + return StatusCode::FAILURE; + } + if (m_proxy != new_proxy) { + CHECK (this->setState (new_proxy)); + } + + if (new_proxy && initRefCount == sptr->refCount() && new_proxy->isValid()) { + // If the reference count hasn't changed, then we've returned an existing + // object rather than recording a new one. Retrieve the pointer, making + // sure that it isn't const. + if (m_proxy->isConst()) { + REPORT_ERROR (StatusCode::FAILURE) + << "Found an existing const object from recordOrRetrieve."; + return StatusCode::FAILURE; + } + m_ptr = typeless_dataPointer_impl(true); + if (!allowMods) + CHECK( setConst() ); + } + else + m_ptr=(void*)dataPtr; + + return StatusCode::SUCCESS; + } + + + /** + * @brief Retrieve an object from StoreGate. + * @param quiet If true, suppress failure messages. + */ + void* + VarHandleBase::typeless_dataPointer_impl (bool quiet) + { +#ifdef DEBUG_VHB + std::cerr << "::VHB::typeless_dataPointer_impl(" + << this + << ",ptr=" << this->m_ptr + << ",proxy=" << this->m_proxy << ", "; + if (m_proxy) { + std::cerr << " -- isValid: " << m_proxy->isValid() + << " -- isConst: " << m_proxy->isConst(); + } + std::cerr << ", key=" <<this->key() << ")...\n"; +#endif + + // First check for cached pointer. + if (0 != m_ptr) + return m_ptr; + + if (0 == m_proxy) { + // No proxy, need to look it up. + if (this->setState().isFailure() || !m_proxy) { + if (!quiet) { + REPORT_MESSAGE(MSG::WARNING) + << "could not get proxy for key " << key(); + if (this->mode() != Gaudi::DataHandle::Reader) { + REPORT_MESSAGE(MSG::WARNING)<< " try using a ReadHandle"; + } + } //quiet + return 0; + } //setstate + } //m_proxy + + if (!m_proxy || !m_proxy->isValid()) { + // invalid proxy + if (!quiet) { + REPORT_MESSAGE(MSG::WARNING) + << "Proxy " + << " [" << (m_proxy != 0 ? m_proxy->clID() : 0) + << "/" << (m_proxy != 0 + ? m_proxy->name() + : std::string("<N/A>")) + << "] is in an invalid state"; + } //quiet + return m_ptr; + } + + DataObject* dobj = m_proxy->accessData(); + if (!dobj) { + // invalid dobj + if (!quiet) { + REPORT_MESSAGE(MSG::WARNING) + << "this proxy " << MSG::hex << m_proxy + << MSG::dec << " has a NULL data object ptr"; + } + return m_ptr; + } + + const CLID clid = this->clid(); + m_ptr = SG::Storable_cast(dobj, clid, m_proxy); + if (m_ptr) { + return m_ptr; + } + + // if m_ptr is null, probably the clid we gave wasn't the clid + // the object was stored with, nor it inherits from it. + // before giving up, let's check its transient CLIDs + DataBucketBase *dbb = 0; + if (m_proxy->transientAddress()->transientID(clid) && + 0 != (dbb = dynamic_cast<DataBucketBase*>(dobj))) { + // it is a symlink after all. + // Let's hard cast (and keep our fingers Xed) + m_ptr = static_cast<void*>(dbb->object()); + } else { + if (!quiet) { + REPORT_MESSAGE(MSG::WARNING) + << "Request for an invalid object; requested CLID = " + << clid + << ", proxy primary ID is " << m_proxy->clID(); + } + } // try symlink -- endif + return m_ptr; + } + + + /** + * @brief Retrieve an object from StoreGate as non-const pointer. + * + * Calls typeless_dataPointer, then raises an exception if the + * proxy is marked as const. + */ + void* VarHandleBase::typeless_ptr(bool quiet/*=defaultQuiet*/) + { + void* p = typeless_dataPointer(quiet); + if (p != nullptr && isConst()) + throw SG::ExcConstObject (clid(), key(), store()); + return p; + } + + + /** + * @brief Initialize the store pointer from the store handle. + * Also checks that the key is valid. + */ + StatusCode VarHandleBase::storeFromHandle() + { + CHECK( VarHandleKey::initialize() ); + if (this->storeHandle()->name() == "StoreGateSvc") + m_store = Gaudi::Hive::currentContext().proxy(); + else { + m_store = &*this->storeHandle(); + if (IHiveStore* hs = dynamic_cast<IHiveStore*> (m_store)) + m_store = hs->hiveProxyDict(); + } + return StatusCode::SUCCESS; + } + + + /** + * @brief Clear the m_proxy field and release the old proxy. + */ + void VarHandleBase::resetProxy() + { + if (m_proxy) { + m_proxy->unbindHandle(this); + m_proxy->release(); + m_proxy = nullptr; + } + } + + + /** + * @brief Set a new proxy. Release any old one first. + * @param proxy The new proxy. + */ + void VarHandleBase::setProxy (SG::DataProxy* proxy) + { + resetProxy(); + if (proxy) { + proxy->addRef(); + proxy->bindHandle (this); + m_proxy = proxy; + } + } + + + //************************************************************************* + // Free functions. + // + + + /** + * @brief Output stream. + * @param out Stream to which to write. + * @parma o Object to write. + */ + std::ostream& operator<<( std::ostream& out, const VarHandleBase& o ) + { + out << "VarHandleBase @" << &o + << " store=" <<o.store() + << ", clid=" <<o.clid() + << ", key=" <<o.key() + << "----------- ptr@" << o.m_ptr + << ", proxy@" << o.m_proxy ; + if (o.m_proxy) + out << ", DataObject@" << o.m_proxy->object(); + return out; + } + + + /** + * @brief Equality comparison. + */ + bool operator==(const VarHandleBase& l, const VarHandleBase& r) + { + return (l.clid() == r.clid() && + l.mode() == r.mode() && + l.name() == r.name() && + l.store() == r.store()); + } + + + /** + * @brief Inequality comparison. + */ + bool operator!=(const VarHandleBase& l, const VarHandleBase& r) + { + return !(l==r); + } + + +} /* namespace SG */ diff --git a/EDM/athena/Control/StoreGate/src/VarHandleKey.cxx b/EDM/athena/Control/StoreGate/src/VarHandleKey.cxx new file mode 100644 index 00000000..f9627bb3 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/VarHandleKey.cxx @@ -0,0 +1,204 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/src/VarHandleKey.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief + */ + + +#include "StoreGate/VarHandleKey.h" +#include "StoreGate/exceptions.h" +#include "AthenaKernel/getMessageSvc.h" +#include "AthenaKernel/errorcheck.h" +#include <boost/tokenizer.hpp> + + +namespace SG { + + +/** + * @brief Constructor. + * @param clid The class ID for the referenced object. + * @param sgkey The StoreGate key for the object. + * @param a Mode: read/write/update. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present, + * the store named by @c storeName is used. However, if the key name + * starts with a slash, it is interpreted as a hierarchical key name, + * not an empty store name. + * + * A SG::ExcBadHandleKey exception will the thrown if the key string + * format is bad. + */ +VarHandleKey::VarHandleKey (CLID clid, + const std::string& sgkey, + Gaudi::DataHandle::Mode a, + const std::string& storeName /*= "StoreGateSvc"*/) + : Gaudi::DataHandle (DataObjID (clid, sgkey), a), + m_storeHandle (storeName, "VarHandleKey") +{ + if (parseKey (sgkey, storeName).isFailure()) + throw SG::ExcBadHandleKey (sgkey); +} + + +/** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store is not changed. A key name that starts with a slash + * is interpreted as a hierarchical key name, not an empty store name. + * + * A SG::ExcBadHandleKey exception will the thrown if the key string + * format is bad. + */ +VarHandleKey& VarHandleKey::operator= (const std::string& sgkey) +{ + if (parseKey (sgkey, m_storeHandle.name()).isFailure()) + throw SG::ExcBadHandleKey (sgkey); + return *this; +} + + +/** + * @brief Change the key of the object to which we're referring. + * @param sgkey The StoreGate key for the object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store is not changed. A key name that starts with a slash + * is interpreted as a hierarchical key name, not an empty store name. + * + * Returns failure the key string format is bad. + */ +StatusCode VarHandleKey::assign (const std::string& sgkey) +{ + return parseKey (sgkey, m_storeHandle.name()); +} + + +/** + * @brief If this object is used as a property, then this should be called + * during the initialize phase. It will fail if the requested StoreGate + * service cannot be found or if the key is blank. + */ +StatusCode VarHandleKey::initialize() +{ + if (Gaudi::DataHandle::objKey() == "") { + REPORT_ERROR (StatusCode::FAILURE) + << "Cannot initialize a Read/Write/Update handle with a null key."; + return StatusCode::FAILURE; + } + CHECK( m_storeHandle.retrieve() ); + return StatusCode::SUCCESS; +} + + +/** + * @brief Return the class ID for the referenced object. + */ +CLID VarHandleKey::clid() const +{ + return Gaudi::DataHandle::fullKey().clid(); +} + + +/** + * @brief Return the StoreGate ID for the referenced object. + */ +const std::string& VarHandleKey::key() const +{ + return Gaudi::DataHandle::objKey(); +} + + +/** + * @brief Return handle to the referenced store. + */ +ServiceHandle<IProxyDict> VarHandleKey::storeHandle() const +{ + return m_storeHandle; +} + + +/** + * @brief Prevent this method from being called. + */ +void VarHandleKey::setKey(const DataObjID& /*key*/) +{ + throw SG::ExcForbiddenMethod ("VarHandleKey::setKey"); +} + + +/** + * @brief Prevent this method from being called. + */ +void VarHandleKey::updateKey(const std::string& /*key*/) +{ + throw SG::ExcForbiddenMethod ("VarHandleKey::updateKey"); +} + + +/** + * @brief Handle assignment/construction from a string key. + * @param sgkey The StoreGate key for the referenced object. + * + * The provided key may actually start with the name of the store, + * separated by a slash: "MyStore/Obj". If no slash is present + * the store named by @c storeName is used. A key name that starts + * with a slash is interpreted as a hierarchical key name, + * not an empty store name. + */ +StatusCode VarHandleKey::parseKey (const std::string& sgkey, + const std::string& storeName) +{ + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("/"); + tokenizer tokens(sgkey, sep); + int nToks = distance(tokens.begin(), tokens.end()); + if (nToks == 0) { + this->updateHandle (storeName); + Gaudi::DataHandle::updateKey (""); + } else { + if (sgkey.find("/") == 0) { + this->updateHandle( storeName ); + Gaudi::DataHandle::updateKey( sgkey ); + } else { + if (nToks == 1) { + this->updateHandle (storeName); + Gaudi::DataHandle::updateKey (*(tokens.begin())); + } else if (nToks == 2) { + auto tok = tokens.begin(); + this->updateHandle (*tok); + Gaudi::DataHandle::updateKey (*(++tok)); + } else { + return StatusCode::FAILURE; + } + } + } + return StatusCode::SUCCESS; +} + + +/** + * @brief Update the name of the store to which we're referring. + * @param name The new store name. + */ +void VarHandleKey::updateHandle (const std::string& name) +{ + // Don't invalidate a stored pointer if the handle is already pointing + // at the desired service. + if (m_storeHandle.name() != name) + m_storeHandle = ServiceHandle<IProxyDict>(name, "VarHandleKey"); +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx b/EDM/athena/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx new file mode 100644 index 00000000..c1996368 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/VarHandleKeyArrayProperty.cxx @@ -0,0 +1,206 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// stl includes +#include <sstream> +#include <map> +#include <boost/tokenizer.hpp> + +// StoreGate includes +#include "StoreGate/VarHandleKeyArrayProperty.h" + +namespace Gaudi { + namespace Parsers { + + +/** + * @brief Gaudi function used to initialize a property from a string. + * @param v The object to initialize. + * @param s The string from which to initialize. + * + * Used during Gaudi property handling to set object @c v from the string @c s. + * Note that @c s is a representation of the property setting; thus, in the + * case of setting a property from a string, @c s will contain quote marks. + */ + StatusCode + GAUDI_API + parse(SG::VarHandleKeyArray& v, const std::string& s) + { + std::vector<std::string> vp; + StatusCode sc = Gaudi::Parsers::parse(vp, s); + + if (sc.isSuccess()) + sc = v.assign( vp ); + + return sc; + } + + } //> ns Parsers + + namespace Utils { + + +/** + * @brief Gaudi function used to convert a property to a string. + * @param v The object to convert. + * @param o Stream to which to do the conversion. + * + * Used during Gaudi property handling to get a string representation of @c v. + * Note that if the representation is a string, it should be surrounded + * by quote marks. + */ + std::ostream& + GAUDI_API + toStream(const SG::VarHandleKeyArray& v, std::ostream& o) + { + o << "[" << v.toString() << "]"; + return o; + } + + } //> ns Utils +} //> ns Gaudi + + +namespace SG { + + +/** + * @brief Constructor with parameters. + * @param name Name of the property. + * @param ref Object which this property is setting. + */ + VarHandleKeyArrayProperty::VarHandleKeyArrayProperty( const std::string& name, + SG::VarHandleKeyArray& ref ) + : Property( name, typeid( SG::VarHandleKeyArray ) ), + m_pValue( &ref ) + { +} + + +/** + * @brief Assignment operator. + * @param value Value from which to assign. + * + * Copy the value object which we control from another value object. + */ +VarHandleKeyArrayProperty& +VarHandleKeyArrayProperty::operator=( const SG::VarHandleKeyArray& value ) +{ + setValue( value ); + return *this; +} + + +/** + * @brief Return a new copy of this Property object. + * + * The new object will be associated with the _same_ value object + * as the original. + */ +VarHandleKeyArrayProperty* +VarHandleKeyArrayProperty::clone() const +{ + return new VarHandleKeyArrayProperty( *this ); +} + + +/** + * @brief Set the value of another Property. + * @param destination The Property whose value is changed. + * + * The value object of this Property is copied to that of @c destination + * by converting to a string and back again. Returns true on success, + * false on failure. + */ +bool +VarHandleKeyArrayProperty::load( Property& destination ) const +{ + return destination.assign( *this ); +} + + +/** + * @brief Set the value of this Property from another. + * @param destination The Property from which the value should be copied. + * + * The value object of this @c source is copied to that of this Property + * by converting to a string and back again. Returns true on success, + * false on failure. + */ +bool +VarHandleKeyArrayProperty::assign( const Property& source ) +{ + return fromString( source.toString() ).isSuccess(); +} + + +/** + * @brief Return a string representation of the value object. + */ +std::string +VarHandleKeyArrayProperty::toString( ) const +{ + useReadHandler(); + std::ostringstream o; + Gaudi::Utils::toStream(*m_pValue, o); + return o.str(); +} + + +/** + * @brief Write a string representation of the value object to a stream. + * @param out Stream to which to write. + */ +void +VarHandleKeyArrayProperty::toStream(std::ostream& out) const +{ + useReadHandler(); + out << this->toString(); +} + + +/** + * @brief Set this value object from a string. + * @param s String from which to initialize the value. + * + * Returns failure if the conversion does not succeed. + */ +StatusCode +VarHandleKeyArrayProperty::fromString(const std::string& s) +{ + if (!Gaudi::Parsers::parse(*m_pValue, s).isSuccess()) { + return StatusCode::FAILURE; + } + return useUpdateHandler() + ? StatusCode::SUCCESS + : StatusCode::FAILURE; +} + + +/** + * @brief Return the value object for this Property. + */ +const SG::VarHandleKeyArray& +VarHandleKeyArrayProperty::value() const +{ + useReadHandler(); + return *m_pValue; +} + + +/** + * @brief Set the value object for this Property. + * @param value Value from which to copy. + * + * Return true on success; false if the update handler failed. + */ +bool +VarHandleKeyArrayProperty::setValue( const SG::VarHandleKeyArray& value ) +{ + m_pValue->operator=(value); + return useUpdateHandler(); +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/src/VarHandleKeyProperty.cxx b/EDM/athena/Control/StoreGate/src/VarHandleKeyProperty.cxx new file mode 100644 index 00000000..2b99b88a --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/VarHandleKeyProperty.cxx @@ -0,0 +1,211 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file VarHandleKeyProperty.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief + */ + +// stl includes +#include <sstream> +#include <map> +#include <boost/tokenizer.hpp> + +// StoreGate includes +#include "StoreGate/VarHandleKeyProperty.h" + +namespace Gaudi { +namespace Parsers { + + +/** + * @brief Gaudi function used to initialize a property from a string. + * @param v The object to initialize. + * @param s The string from which to initialize. + * + * Used during Gaudi property handling to set object @c v from the string @c s. + * Note that @c s is a representation of the property setting; thus, in the + * case of setting a property from a string, @c s will contain quote marks. + */ +StatusCode +parse(SG::VarHandleKey& v, const std::string& s) +{ + std::string prop; + StatusCode sc = Gaudi::Parsers::parse(prop, s); + if (sc.isSuccess()) + sc = v.assign (prop); + return sc; +} + +} //> ns Parsers + +namespace Utils { + + +/** + * @brief Gaudi function used to convert a property to a string. + * @param v The object to convert. + * @param o Stream to which to do the conversion. + * + * Used during Gaudi property handling to get a string representation of @c v. + * Note that if the representation is a string, it should be surrounded + * by quote marks. + */ +std::ostream& +toStream(const SG::VarHandleKey& v, std::ostream& o) +{ + o << "'" << v.storeHandle().name() << "/" << v.objKey() << "'"; + return o; +} + +} //> ns Utils + +} //> ns Gaudi + + +namespace SG { + + +/** + * @brief Constructor with parameters. + * @param name Name of the property. + * @param ref Object which this property is setting. + */ +VarHandleKeyProperty::VarHandleKeyProperty( const std::string& name, + SG::VarHandleKey& ref ) + : Property( name, typeid( SG::VarHandleKey ) ), + m_pValue( &ref ) +{ +} + + +/** + * @brief Assignment operator. + * @param value Value from which to assign. + * + * Copy the value object which we control from another value object. + */ +VarHandleKeyProperty& +VarHandleKeyProperty::operator=( const SG::VarHandleKey& value ) +{ + setValue( value ); + return *this; +} + + +/** + * @brief Return a new copy of this Property object. + * + * The new object will be associated with the _same_ value object + * as the original. + */ +VarHandleKeyProperty* +VarHandleKeyProperty::clone() const +{ + return new VarHandleKeyProperty( *this ); +} + + +/** + * @brief Set the value of another Property. + * @param destination The Property whose value is changed. + * + * The value object of this Property is copied to that of @c destination + * by converting to a string and back again. Returns true on success, + * false on failure. + */ +bool +VarHandleKeyProperty::load( Property& destination ) const +{ + return destination.assign( *this ); +} + + +/** + * @brief Set the value of this Property from another. + * @param destination The Property from which the value should be copied. + * + * The value object of this @c source is copied to that of this Property + * by converting to a string and back again. Returns true on success, + * false on failure. + */ +bool +VarHandleKeyProperty::assign( const Property& source ) +{ + return fromString( source.toString() ).isSuccess(); +} + + +/** + * @brief Return a string representation of the value object. + */ +std::string +VarHandleKeyProperty::toString( ) const +{ + useReadHandler(); + std::ostringstream o; + Gaudi::Utils::toStream(*m_pValue, o); + return o.str(); +} + + +/** + * @brief Write a string representation of the value object to a stream. + * @param out Stream to which to write. + */ +void +VarHandleKeyProperty::toStream(std::ostream& out) const +{ + useReadHandler(); + out << this->toString(); +} + + +/** + * @brief Set this value object from a string. + * @param s String from which to initialize the value. + * + * Returns failure if the conversion does not succeed. + */ +StatusCode +VarHandleKeyProperty::fromString(const std::string& s) +{ + if (!Gaudi::Parsers::parse(*m_pValue, s).isSuccess()) { + return StatusCode::FAILURE; + } + return useUpdateHandler() + ? StatusCode::SUCCESS + : StatusCode::FAILURE; +} + + +/** + * @brief Return the value object for this Property. + */ +const SG::VarHandleKey& +VarHandleKeyProperty::value() const +{ + useReadHandler(); + return *m_pValue; +} + + +/** + * @brief Set the value object for this Property. + * @param value Value from which to copy. + * + * Return true on success; false if the update handler failed. + */ +bool +VarHandleKeyProperty::setValue( const SG::VarHandleKey& value ) +{ + m_pValue->operator=(value); + return useUpdateHandler(); +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/src/components/StoreGateSvc_entries.cxx b/EDM/athena/Control/StoreGate/src/components/StoreGateSvc_entries.cxx new file mode 100644 index 00000000..3c6d7b9a --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/components/StoreGateSvc_entries.cxx @@ -0,0 +1,16 @@ +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/ActiveStoreSvc.h" +#include "StoreGate/tools/SGImplSvc.h" +#include "StoreGate/SegMemSvc.h" +#include "../SGHiveMgrSvc.h" +#include "GaudiKernel/DeclareFactoryEntries.h" + +DECLARE_SERVICE_FACTORY( ActiveStoreSvc ) +DECLARE_SERVICE_FACTORY( StoreGateSvc ) +DECLARE_SERVICE_FACTORY( SGImplSvc ) +DECLARE_SERVICE_FACTORY( SegMemSvc ) + +#ifdef ATHENAHIVE +DECLARE_NAMESPACE_SERVICE_FACTORY( SG, HiveMgrSvc ) +#endif + diff --git a/EDM/athena/Control/StoreGate/src/components/StoreGateSvc_load.cxx b/EDM/athena/Control/StoreGate/src/components/StoreGateSvc_load.cxx new file mode 100644 index 00000000..4af836cc --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/components/StoreGateSvc_load.cxx @@ -0,0 +1,4 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(StoreGate) + diff --git a/EDM/athena/Control/StoreGate/src/exceptions.cxx b/EDM/athena/Control/StoreGate/src/exceptions.cxx new file mode 100644 index 00000000..f3a47099 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/exceptions.cxx @@ -0,0 +1,340 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/src/exceptions.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Exceptions that can be thrown from StoreGate. + */ + + +#include "StoreGate/exceptions.h" +#include <sstream> + + +namespace SG { + + +/** + * @brief Constructor. + */ +ExcNullHandleKey::ExcNullHandleKey() + : std::runtime_error ("SG::ExcNullHandleKey: Attempt to dereference a Read/Write/UpdateHandle with a null key.") +{ +} + + +/** + * @brief Throw a SG::ExcNullHandleKey exception. + */ +[[noreturn]] +void throwExcNullHandleKey() +{ + throw ExcNullHandleKey(); +} + + +//**************************************************************************** + + +/** + * @brief Constructor. + * @param key The supplied key string. + */ +ExcBadHandleKey::ExcBadHandleKey (const std::string& key) + : std::runtime_error ("SG::ExcBadHandleKey: Bad key format for VarHandleKey: `" + key + "'") +{ +} + + +//**************************************************************************** + + +/** + * @brief Constructor. + * @param name Name of the called method. + */ +ExcForbiddenMethod::ExcForbiddenMethod (const std::string& name) + : std::runtime_error ("SG::ExcForbiddenMethod: Forbidden method called: `" + name + "'") +{ +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excHandleInitError_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcHandleInitError: " + << "Error initializing VarHandle from VarHandleKey: " + << storename << "/" << sgkey << "[" << clid << "]"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcHandleInitError::ExcHandleInitError (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excHandleInitError_format (clid, sgkey, storename)) +{ +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excUninitKey_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcUninitKey: " + << "Error initializing VarHandle from uninitialized VarHandleKey: " + << storename << "/" << sgkey << "[" << clid << "]; " + << "keys should be initialized in your initialize()."; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcUninitKey::ExcUninitKey (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excUninitKey_format (clid, sgkey, storename)) +{ +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excConstObject_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcConstObject: " + << "Tried to retrieve non-const pointer to const object via VarHandleKey: " + << storename << "/" << sgkey << "[" << clid << "]"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcConstObject::ExcConstObject (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excConstObject_format (clid, sgkey, storename)) +{ +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excNullWriteHandle_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcNullWriteHandle: " + << "Attempt to dereference write handle before record: " + << storename << "/" << sgkey << "[" << clid << "]"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcNullWriteHandle::ExcNullWriteHandle (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excNullWriteHandle_format (clid, sgkey, storename)) +{ +} + + +/** + * @brief Throw a SG::ExcNullWriteHandle exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +void throwExcNullWriteHandle (CLID clid, + const std::string& sgkey, + const std::string& storename) +{ + throw ExcNullWriteHandle (clid, sgkey, storename); +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excNullReadHandle_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcNullReadHandle: " + << "Dereference of read handle failed: " + << storename << "/" << sgkey << "[" << clid << "]"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcNullReadHandle::ExcNullReadHandle (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excNullReadHandle_format (clid, sgkey, storename)) +{ +} + + +/** + * @brief Throw a SG::ExcNullReadHandle exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +void throwExcNullReadHandle (CLID clid, + const std::string& sgkey, + const std::string& storename) +{ + throw ExcNullReadHandle (clid, sgkey, storename); +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excNullUpdateHandle_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcNullUpdateHandle: " + << "Dereference of update handle failed: " + << storename << "/" << sgkey << "[" << clid << "]"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcNullUpdateHandle::ExcNullUpdateHandle (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excNullUpdateHandle_format (clid, sgkey, storename)) +{ +} + + +/** + * @brief Throw a SG::ExcNullUpdateHandle exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +void throwExcNullUpdateHandle (CLID clid, + const std::string& sgkey, + const std::string& storename) +{ + throw ExcNullUpdateHandle (clid, sgkey, storename); +} + + +//**************************************************************************** + + +/// Helper: format exception error string. +std::string excUpdatedObjectFailure_format (CLID clid, + const std::string& sgkey, + const std::string& storename) + +{ + std::ostringstream os; + os << "SG::ExcUpdatedObjectFailure: " + << "updatedObject failed: " + << storename << "/" << sgkey << "[" << clid << "]"; + return os.str(); +} + + +/** + * @brief Constructor. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +ExcUpdatedObjectFailure::ExcUpdatedObjectFailure (CLID clid, + const std::string& sgkey, + const std::string& storename) + : std::runtime_error (excUpdatedObjectFailure_format (clid, sgkey, storename)) +{ +} + + +/** + * @brief Throw a SG::ExcUpdatedObjectFailure exception. + * @param clid CLID from the key. + * @param sgkey StoreGate key from the key. + * @param storename Store name from the key. + */ +void throwExcUpdatedObjectFailure (CLID clid, + const std::string& sgkey, + const std::string& storename) +{ + throw ExcUpdatedObjectFailure (clid, sgkey, storename); +} + + +} // namespace SG diff --git a/EDM/athena/Control/StoreGate/src/setupStoreGate.cxx b/EDM/athena/Control/StoreGate/src/setupStoreGate.cxx new file mode 100644 index 00000000..1fb6fbd3 --- /dev/null +++ b/EDM/athena/Control/StoreGate/src/setupStoreGate.cxx @@ -0,0 +1,99 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/src/setupStoreGate.cxx + * @author scott snyder <snyder@bnl.gov>, after S. Binet's code from TestPolicy. + * @date Aug, 2014 + * @brief Helper for setting up StoreGate for regression tests. + */ + + +#include "StoreGate/setupStoreGate.h" +#include "StoreGate/StoreGateSvc.h" +#include "TestTools/initGaudi.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/Bootstrap.h" +#include <fstream> +#include <iostream> +#include <list> +#include <cassert> + + +namespace Athena_test { + + +bool setupStoreGate (std::string progname, + std::string options_file /*= ""*/) +{ + // Build job options file if CppUnit_jobOptions.txt is unavailable + if (options_file.empty()) { + std::string::size_type pos = progname.rfind ("/"); + if (pos != std::string::npos) + progname.erase (0, pos+1); + pos = progname.rfind ("."); + if (pos != std::string::npos) + progname.erase (pos, std::string::npos); + options_file = "./" + progname + "_generated.txt"; + (void)remove (options_file.c_str()); + std::ofstream jobopt(options_file.c_str()); + + // Build a default list of options. + { + std::list<std::string> opts; + opts.push_back("#pragma print off"); + opts.push_back("ApplicationMgr.DLLs += { \"StoreGate\" };"); + //opts.push_back("ApplicationMgr.DLLs += { \"CLIDSvc\" };"); + opts.push_back("ApplicationMgr.ExtSvc += { \"ClassIDSvc\" };"); + opts.push_back("ApplicationMgr.ExtSvc += { \"StoreGateSvc\", \"StoreGateSvc/DetectorStore\", \"StoreGateSvc/HistoryStore\" };"); + opts.push_back("ApplicationMgr.ExtSvc += { \"ActiveStoreSvc\" };"); + opts.push_back("AuditorSvc.Auditors += { \"AlgContextAuditor\"};"); + opts.push_back("StoreGateSvc.OutputLevel = 2;"); + opts.push_back("StoreGateSvc.ActivateHistory = false;"); + //opts.push_back("CLIDSvc.OutputLevel = 2;"); + opts.push_back("MessageSvc.useColors = false;"); + opts.push_back("MessageSvc.OutputLevel = 3;"); + opts.push_back("#include \"IOVSvc/IOVSvc.txt\""); + // Build job options file from list. + for ( std::list<std::string>::const_iterator iopt=opts.begin(); + iopt!=opts.end(); ++iopt ) + { + jobopt << *iopt << std::endl; + } + } + jobopt.close(); + } + + try { + /// Get StoreGateSvc + ISvcLocator* svcLoc = 0; + if (!Athena_test::initGaudi(options_file, svcLoc)) { + std::cerr << "This test can not be run" << std::endl; + return false; + } + assert( 0 != svcLoc); + + StoreGateSvc* storeGate = 0; + static const bool CREATE(true); + bool sc = ( svcLoc->service( "StoreGateSvc", + storeGate, CREATE) ).isSuccess(); + assert( sc ); + assert( 0 != storeGate ); + + if ( false == sc || 0 == storeGate ) { + std::string error = "No valid pointer to StoreGateSvc !!"; + std::cerr << error << std::endl; + return false; + } else { + return true; + } + } catch ( std::exception& e ) { + std::cerr << "Caught : " << e.what() << std::endl; + return false; + } +} + + +} // namespace Athena_test diff --git a/EDM/athena/Control/StoreGate/test/ActiveStore_test.cxx b/EDM/athena/Control/StoreGate/test/ActiveStore_test.cxx new file mode 100644 index 00000000..d3c6a473 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/ActiveStore_test.cxx @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + test ActiveStoreSvc functionality + ------------------------------ + ATLAS Collaboration + ***************************************************************************/ + +// $Id: ActiveStore_test.cxx 698338 2015-10-03 18:39:22Z ssnyder $ + +//<<<<<< INCLUDES >>>>>> +#include <string> +#include "TestTools/initGaudi.h" +#include "TestTools/SGassert.h" +#include "StoreGate/ActiveStoreSvc.h" +#include "StoreGate/StoreGateSvc.h" + + +using namespace std; +using namespace Athena_test; + +class Foo { +public: + Foo() : m_i(0), m_d(0.0) {} + Foo(int i) : m_i(i), m_d(0.0) {} + int i() const { return m_i; } + ~Foo() { + } + + // Members public to avoid clang warning about unused private members. + int m_i; + double m_d; +}; + + +#include "SGTools/CLASS_DEF.h" +CLASS_DEF(Foo, 8101, 1) + +int main() { + cout << "*** ActiveStoreTest BEGINS ***" << endl; + ISvcLocator* pSvcLoc; + initGaudi("ActiveStore_test.txt", pSvcLoc); + ActiveStoreSvc* pASS(0); + assert( pSvcLoc->service("ActiveStoreSvc", pASS, true).isSuccess() ); + assert( pASS->activeStore() == pASS->operator->() ); + //as set in ActiveStore_test.txt + assert( pASS->activeStore()->name() == "E1" ); + StoreGateSvc* pE2(0); + assert( pSvcLoc->service("E2", pE2).isSuccess() ); + pASS->setStore(pE2); + assert( pASS->activeStore()->name() == "E2" ); + assert( pASS->finalize().isSuccess() ); + cout << "*** ActiveStoreTest OK ***\n\n" <<endl; + + return 0; +} + diff --git a/EDM/athena/Control/StoreGate/test/DataHandle_test.cxx b/EDM/athena/Control/StoreGate/test/DataHandle_test.cxx new file mode 100644 index 00000000..c5678b80 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/DataHandle_test.cxx @@ -0,0 +1,228 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TestTools/initGaudi.h" +#include "TestTools/SGassert.h" +#include "StoreGate/DataHandle.h" +#include "StoreGate/StoreGateSvc.h" +#include "SGTools/TransientAddress.h" +#include "SGTools/DataProxy.h" + +#include <cassert> +#include <iostream> +#include <list> + +using SG::DataProxy; +using SG::TransientAddress; +using std::list; +using std::cerr; +using std::cout; +using std::endl; + + +struct MyDataObj { + MyDataObj() : m_i(3), m_f(3.14) {} + int m_i; + double m_f; + double f() { return m_f; } +}; +bool operator==(const MyDataObj& lhs, const MyDataObj& rhs) { + return ((lhs.m_i==rhs.m_i) && (lhs.m_f==rhs.m_f)); +} + +typedef std::list<int> IntList; +/** @file DataHandle_test.cxx unit test for DataHandle + * @author ATLAS Collaboration + * $Id: DataHandle_test.cxx,v 1.15 2008-05-22 22:52:12 calaf Exp $ + ***************************************************************************/ + +#include "SGTools/CLASS_DEF.h" +#include "SGTools/StorableConversions.h" +CLASS_DEF(IntList, 8001, 3) +CLASS_DEF(MyDataObj, 8000, 1) + +namespace Athena_test { + void handleTest() { + //empty handles + const DataHandle<MyDataObj> empty; + DataHandle<MyDataObj> copy(empty); //FIXME this should not compile + assert(copy==empty); + + //init with an empty proxy + DataProxy* emProxy(new DataProxy()); + const DataHandle<IntList> emptyProxy(emProxy); + SGASSERTERROR(emptyProxy.isValid()); + //delete emProxy; + //init with a valid proxy + DataProxy* pMyProxy(new DataProxy(SG::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo"))); + DataHandle<MyDataObj> hMy(pMyProxy); + assert(hMy.isValid()); + assert(hMy->m_i==3); + assert(hMy!=empty); + + //copy it and test + DataHandle<MyDataObj> hMyCopy(hMy); + assert(hMyCopy.isValid()); + assert(hMyCopy->m_i==3); + assert(hMy==hMyCopy); + + //assign it and test + DataHandle<MyDataObj> hMyCopy2; + hMyCopy2 = hMyCopy; + assert(hMyCopy2.isValid()); + assert(hMyCopy2->m_i==3); + assert(hMy==hMyCopy2); + + //init with another copy of the same object and compare + DataProxy* pMyProxy2(new DataProxy(SG::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo2"))); + DataHandle<MyDataObj> hMy2(pMyProxy2); + assert(hMy2.isValid()); + assert(hMy2->m_i==3); + assert(hMy!=hMy2); + assert(*hMy==*hMy2); + + const DataHandle<MyDataObj> hMy3(pMyProxy2); + assert(hMy3.isValid()); + assert(hMy3->m_i==3); +#ifdef CHECKCOMPILER + assert(hMy3->f()==3.14); +#endif + assert(hMy!=hMy3); + assert(*hMy==*hMy3); + + + //init with another proxy referring to the same object and compare + DataHandle<MyDataObj> hMySameProxy(pMyProxy); + assert(hMySameProxy.isValid()); + assert(hMySameProxy->m_i==3); + assert(hMy==hMySameProxy); + assert(*hMy==*hMySameProxy); + cout << "*** DataHandle_test static handle test OK ***" <<endl; + } + + + void refcount_test (ISvcLocator* /*svcloc*/) +{ + std::vector<DataProxy*> vp; + SG::ProxyMap mp; + for (int i=0; i < 4; i++) { + DataProxy* dp = new DataProxy(SG::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo")); + vp.push_back (dp); + mp[std::string (1, 'A' + i)] = dp; + } + + { + DataHandle<MyDataObj> dh (vp[0]); + assert (vp[0]->refCount() == 1); + dh.setState (vp[0]); + assert (vp[0]->refCount() == 1); + DataHandle<MyDataObj> dh2 (dh); + assert (vp[0]->refCount() == 2); + DataHandle<MyDataObj> dh3 (mp.begin(), mp.end()); + assert (vp[0]->refCount() == 3); + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 0); + + dh2 = dh3; + assert (vp[0]->refCount() == 3); + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 0); + + dh2 = dh; + assert (vp[0]->refCount() == 3); + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 0); + + ++dh; + assert (vp[0]->refCount() == 2); + dh2++; + assert (vp[0]->refCount() == 1); + + dh.setState (vp[0]); + assert (vp[0]->refCount() == 2); + SG::ConstProxyIterator it = mp.begin(); + dh3.setState (it, mp.end()); + assert (vp[0]->refCount() == 2); + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 0); + dh3++; + assert (vp[0]->refCount() == 1); + assert (vp[1]->refCount() == 1); + dh2.setState (vp[1]); + ++dh3; + for (int i=0; i < 3; i++) + assert (vp[i]->refCount() == 1); + + for (int i=0; i < 4; i++) + vp[i]->addRef(); + + dh.setState (vp[1]); + assert (vp[0]->refCount() == 1); + assert (vp[1]->refCount() == 3); + assert (vp[2]->refCount() == 2); + assert (vp[3]->refCount() == 1); + dh.setState (vp[0]); + assert (vp[3]->refCount() == 1); + for (int i=0; i < 3; i++) + assert (vp[i]->refCount() == 2); + it++; it++; + dh.setState (it, mp.end()); + assert (vp[0]->refCount() == 1); + assert (vp[1]->refCount() == 2); + assert (vp[2]->refCount() == 3); + assert (vp[3]->refCount() == 1); + --it; + dh.setState (it, mp.end()); + assert (vp[0]->refCount() == 1); + assert (vp[1]->refCount() == 3); + assert (vp[2]->refCount() == 2); + assert (vp[3]->refCount() == 1); + dh.setState (vp[0]); + assert (vp[3]->refCount() == 1); + for (int i=0; i < 3; i++) + assert (vp[i]->refCount() == 2); + + const DataHandle<MyDataObj> dh4; + dh4.setState (vp[0]); + assert (vp[0]->refCount() == 3); + assert (vp[1]->refCount() == 2); + assert (vp[2]->refCount() == 2); + assert (vp[3]->refCount() == 1); + dh4.setState (it, mp.end()); + assert (vp[0]->refCount() == 2); + assert (vp[1]->refCount() == 3); + assert (vp[2]->refCount() == 2); + assert (vp[3]->refCount() == 1); + dh4.setState (vp[0]); + assert (vp[0]->refCount() == 3); + assert (vp[1]->refCount() == 2); + assert (vp[2]->refCount() == 2); + assert (vp[3]->refCount() == 1); + } + + for (unsigned int i=0; i < vp.size(); ++i) { + assert (vp[i]->refCount() == 1); + delete vp[i]; + } + +} + +} + +using namespace Athena_test; + +//#include "Reflex/PluginService.h" + +int main() { + // ROOT::Reflex::PluginService::SetDebug(8); + ISvcLocator* pDum; + initGaudi(pDum); //need MessageSvc + handleTest(); + refcount_test(pDum); + cout << "*** DataHandle_test OK ***" <<endl; + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/KeyConcept_test.cxx b/EDM/athena/Control/StoreGate/test/KeyConcept_test.cxx new file mode 100644 index 00000000..592f4758 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/KeyConcept_test.cxx @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "StoreGate/constraints/KeyConcept.h" + +#include <cassert> +#include <iostream> +#include <string> + +using namespace std; + + +int main () { + + cerr << "*** KeyConcept_test BEGIN ***" << endl; + + KeyClass<string> tryThis; + classIsKey<string>(); + + KeyClass<int> tryThat; + classIsKey<int>(); + + cerr << "*** KeyConcept_test OK ***" <<endl; + return 0; + +} + + + + + diff --git a/EDM/athena/Control/StoreGate/test/ReadHandleKey_test.cxx b/EDM/athena/Control/StoreGate/test/ReadHandleKey_test.cxx new file mode 100644 index 00000000..fceaef8b --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/ReadHandleKey_test.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/ReadHandleKey_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for ReadHandleKey. + */ + + +#undef NDEBUG +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/exceptions.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include <cassert> +#include <iostream> + + +class MyObj {}; +CLASS_DEF (MyObj, 293847295, 1) + + +void test1() +{ + std::cout << "test1\n"; + + SG::ReadHandleKey<MyObj> k1 ("aaa"); + assert (k1.clid() == 293847295); + assert (k1.key() == "aaa"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (!k1.storeHandle().isSet()); + assert (k1.initialize().isSuccess()); + assert (k1.storeHandle().isSet()); + + k1 = "aab"; + assert (k1.clid() == 293847295); + assert (k1.key() == "aab"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (k1.storeHandle().isSet()); + + k1 = "FeeSvc/aac"; + assert (k1.clid() == 293847295); + assert (k1.key() == "aac"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "FeeSvc"); + assert (!k1.storeHandle().isSet()); + + SG::ReadHandleKey<MyObj> k2 ("bbb", "FooSvc"); + assert (k2.clid() == 293847295); + assert (k2.key() == "bbb"); + assert (k2.mode() == Gaudi::DataHandle::Reader); + assert (k2.storeHandle().name() == "FooSvc"); + assert (!k2.storeHandle().isSet()); +} + + +int main() +{ + ISvcLocator* pDum; + Athena_test::initGaudi(pDum); //need MessageSvc + + test1(); +} diff --git a/EDM/athena/Control/StoreGate/test/ReadHandle_test.cxx b/EDM/athena/Control/StoreGate/test/ReadHandle_test.cxx new file mode 100644 index 00000000..dbd9ef5d --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/ReadHandle_test.cxx @@ -0,0 +1,264 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/ReadHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for ReadHandle. + */ + + +#undef NDEBUG +#include "StoreGate/ReadHandle.h" +#include "StoreGate/exceptions.h" +#include "SGTools/TestStore.h" +#include "SGTools/CLASS_DEF.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include "AthenaKernel/errorcheck.h" +#include "CxxUtils/unused.h" +#include <cassert> +#include <iostream> + + +class MyObj +{ +public: + MyObj(int x=0) : x(x) {} + int x; +}; +CLASS_DEF (MyObj, 293847295, 1) +static const CLID MyCLID = 293847295; + + +// Ctors. +void test1() +{ + std::cout << "test1\n"; + + SG::ReadHandle<MyObj> h1; + assert (h1.clid() == MyCLID); + assert (h1.key() == ""); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Reader); + + SG::ReadHandle<MyObj> h2 ("foo", "FooSvc"); + assert (h2.clid() == MyCLID); + assert (h2.key() == "foo"); + assert (h2.name() == "foo"); + assert (h2.storeHandle().name() == "FooSvc"); + assert (h2.mode() == Gaudi::DataHandle::Reader); + + SG::ReadHandleKey<MyObj> k3 ("asd"); + assert (k3.initialize().isSuccess()); + SG::ReadHandle<MyObj> h3 (k3); + assert (h3.clid() == MyCLID); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "StoreGateSvc"); + assert (h3.mode() == Gaudi::DataHandle::Reader); + + { + SG::ReadHandleKey<MyObj> k4 ("asd", "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::ReadHandle<MyObj> h4 (k4)); + } + + SGTest::TestStore dumstore; + EventContext ctx5; + ctx5.setProxy (&dumstore); + SG::ReadHandle<MyObj> h5 (k3, ctx5); + assert (h5.clid() == MyCLID); + assert (h5.key() == "asd"); + assert (h5.storeHandle().name() == "StoreGateSvc"); + assert (h5.mode() == Gaudi::DataHandle::Reader); + assert (h5.store() == "TestStore"); + + SG::ReadHandleKey<MyObj> k6 ("asd", "OtherStore"); + assert (k6.initialize().isSuccess()); + SG::ReadHandle<MyObj> h6 (k6, ctx5); + assert (h6.clid() == MyCLID); + assert (h6.key() == "asd"); + assert (h6.storeHandle().name() == "OtherStore"); + assert (h6.mode() == Gaudi::DataHandle::Reader); + assert (h6.store() == "OtherStore" || h6.store() == "OtherStore_Impl"); + + { + SG::ReadHandleKey<MyObj> k7 ("asd", "BazSvc"); + k7.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::ReadHandle<MyObj> h7 (k7, ctx5)); + } +} + + +// Copy. +void test2() +{ + std::cout << "test2\n"; + SGTest::TestStore testStore; + + MyObj* fooptr = new MyObj(13); + testStore.record (fooptr, "foo"); + SG::DataProxy* foo_proxy = testStore.proxy (MyCLID, "foo"); + assert (foo_proxy->refCount() == 1); + + MyObj* barptr = new MyObj(14); + testStore.record (barptr, "bar"); + SG::DataProxy* bar_proxy = testStore.proxy (MyCLID, "bar"); + assert (bar_proxy->refCount() == 1); + + SG::ReadHandle<MyObj> h1 ("foo", "FooSvc"); + assert (h1.store() == "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (h1.store() == "TestStore"); + assert (h1.cptr() == fooptr); + assert (foo_proxy->refCount() == 2); + + SG::ReadHandle<MyObj> h2 (h1); + assert (h2.key() == "foo"); + assert (h2.store() == "TestStore"); + assert (h2.isInitialized()); + assert (h2.cptr() == fooptr); + assert (foo_proxy->refCount() == 3); + + SG::ReadHandle<MyObj> h3 (std::move(h2)); + assert (h3.key() == "foo"); + assert (h3.store() == "TestStore"); + assert (h3.isInitialized()); + assert (h3.cptr() == fooptr); + assert (foo_proxy->refCount() == 3); + assert (h2.key() == "foo"); + assert (h2.store() == "TestStore"); + assert (!h2.isInitialized()); + assert (h2.cachedPtr() == nullptr); + + SG::ReadHandle<MyObj> h4 ("bar", "FooSvc"); + assert (h4.setProxyDict (&testStore).isSuccess()); + assert (h4.cptr() == barptr); + assert (bar_proxy->refCount() == 2); + + h3 = h4; + assert (h3.key() == "bar"); + assert (h3.store() == "TestStore"); + assert (h3.isInitialized()); + assert (h3.cptr() == barptr); + assert (h4.key() == "bar"); + assert (h4.store() == "TestStore"); + assert (h4.isInitialized()); + assert (h4.cptr() == barptr); + + assert (foo_proxy->refCount() == 2); + assert (bar_proxy->refCount() == 3); + + // h1: foo, h2: unint, h3: bar, h4: bar + + h2 = std::move(h3); + assert (h2.key() == "bar"); + assert (h2.store() == "TestStore"); + assert (h2.isInitialized()); + assert (h2.cptr() == barptr); + assert (h3.key() == "bar"); + assert (h3.store() == "TestStore"); + assert (!h3.isInitialized()); + assert (h3.cachedPtr() == nullptr); + + assert (foo_proxy->refCount() == 2); + assert (bar_proxy->refCount() == 3); +} + + +// Retrieve +void test3() +{ + std::cout << "test3\n"; + SGTest::TestStore testStore; + + MyObj* fooptr = new MyObj(23); + testStore.record (fooptr, "foo"); + SG::DataProxy* foo_proxy = testStore.proxy (MyCLID, "foo"); + assert (foo_proxy->refCount() == 1); + + SG::ReadHandle<MyObj> h1 ("foo", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (!h1.isInitialized()); + assert (h1.cachedPtr() == nullptr); + assert (h1.cptr() == fooptr); + assert (h1.isInitialized()); + assert (h1.isValid()); + assert (h1.cachedPtr() == fooptr); + assert (h1.ptr() == fooptr); + assert (h1->x == 23); + assert ((*h1).x == 23); + assert (foo_proxy->refCount() == 2); + + SG::ReadHandle<MyObj> h2 ("foox", "FooSvc"); + assert (h2.setProxyDict (&testStore).isSuccess()); + assert (h2.cachedPtr() == nullptr); + assert (!h2.isInitialized()); + assert (!h2.isValid()); + assert (h2.cachedPtr() == nullptr); + assert (h2.ptr() == nullptr); + assert (h2.cptr() == nullptr); + int UNUSED(xx) = 0; + EXPECT_EXCEPTION (SG::ExcNullReadHandle, xx = (*h2).x); + EXPECT_EXCEPTION (SG::ExcNullReadHandle, xx = h2->x ); +} + + +// makeHandle +void test4() +{ + std::cout << "test4\n"; + SGTest::TestStore testStore; + + SG::ReadHandleKey<MyObj> k1 ("asd"); + assert (k1.initialize().isSuccess()); + auto h1 = SG::makeHandle (k1); + assert (h1.clid() == MyCLID); + assert (h1.key() == "asd"); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Reader); + + SG::ReadHandleKey<MyObj> k2 ("asd", "BazSvc"); + k2.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::makeHandle (k2)); + + SGTest::TestStore dumstore; + EventContext ctx; + ctx.setProxy (&dumstore); + auto h2 = SG::makeHandle (k1, ctx); + assert (h2.clid() == MyCLID); + assert (h2.key() == "asd"); + assert (h2.storeHandle().name() == "StoreGateSvc"); + assert (h2.mode() == Gaudi::DataHandle::Reader); + assert (h2.store() == "TestStore"); + + SG::ReadHandleKey<MyObj> k3 ("asd", "OtherStore"); + assert (k3.initialize().isSuccess()); + auto h3 = SG::makeHandle (k3, ctx); + assert (h3.clid() == MyCLID); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "OtherStore"); + assert (h3.mode() == Gaudi::DataHandle::Reader); + assert (h3.store() == "OtherStore" || h3.store() == "OtherStore_Impl"); + + SG::ReadHandleKey<MyObj> k4 ("asd", "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::makeHandle (k4, ctx)); +} + + +int main() +{ + errorcheck::ReportMessage::hideErrorLocus(); + ISvcLocator* svcloc; + Athena_test::initGaudi("VarHandleBase_test.txt", svcloc); //need MessageSvc + + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/SGHive_test.cxx b/EDM/athena/Control/StoreGate/test/SGHive_test.cxx new file mode 100644 index 00000000..066903f6 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/SGHive_test.cxx @@ -0,0 +1,180 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifdef ATHENAHIVE +/*************************************************************************** + test SGHiveMgrSvc functionality + ------------------------------ + ATLAS Collaboration + ***************************************************************************/ + +// $Id: SGHive_test.cxx 704712 2015-10-29 21:48:11Z leggett $ + + +#include <string> +#include "TestTools/initGaudi.h" +using namespace Athena_test; +#include "TestTools/SGassert.h" +#include "GaudiKernel/IHiveWhiteBoard.h" +#include "../src/SGHiveMgrSvc.h" +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/SGtests.h" + + +using namespace std; +namespace SG { +class Foo { +public: + Foo() : m_i(0), m_d(0.0) {} + Foo(int i) : m_i(i), m_d(0.0) {} + int i() const { return m_i; } + ~Foo() { + } +private: + int m_i; + double m_d; +}; +} + +#include "SGTools/CLASS_DEF.h" +CLASS_DEF(SG::Foo, 81010, 1) + + +namespace SG { +/*** a friend of SG::HiveMgrSvc */ +class TestSGHiveMgrSvc { +public: + /*** here we test finding the next empty store and assigning to an event */ + static void init(SG::HiveMgrSvc& rSGHM) + { + assert( rSGHM.m_slots.size() == rSGHM.m_nSlots ); + //this is specified in SGHive_test.txt + assert( rSGHM.m_slots.size() == 4 ); + + for (size_t evtNum=0; evtNum<rSGHM.m_nSlots; ++evtNum) { + assert( SG::TestSGHiveMgrSvc::next(rSGHM, evtNum)!=std::string::npos ); + } + } + + /*** here we test finding the next empty store and assigning to an event */ + static size_t next(::IHiveWhiteBoard& rWB, size_t eventNumber) + { + // size_t slot=string::npos; + // return (((slot=rWB.allocateStore(eventNumber)) != string::npos) && + // rWB.selectStore(slot).isSuccess()) ? slot : string::npos; + return rWB.allocateStore(eventNumber); + } + + /*** here we test the clearing and freeing of stores which are not needed anymory */ + static StatusCode clear(::IHiveWhiteBoard& rWB, size_t slot) + { + return ( rWB.clearStore(slot).isSuccess() && + rWB.freeStore(slot).isSuccess() ) ? + StatusCode::SUCCESS : + StatusCode::FAILURE; + } +}; + /*** a friend of StoreGateSvc */ + class TestHiveStoreSvc { + private: + HiveEventSlot* m_pSlot; + StoreGateSvc& m_rHSG; + public: + TestHiveStoreSvc(StoreGateSvc& rHSG) : + m_pSlot(StoreGateSvc::currentSlot()), + m_rHSG(rHSG){} + void testNewDataObjects(StoreGateSvc& rSG) + { + DataObjIDColl products; + rSG.getNewDataObjects(products).ignore(); //reset counter + assert( !rSG.newDataObjectsPresent() ); + assert( products.empty() ); + //direct call + rSG.currentStore()->addedNewTransObject(ClassID_traits<SG::Foo>::ID(), "blassed"); + rSG.commitNewDataObjects(); + rSG.getNewDataObjects(products).ignore(); + assert( 1 == products.size() ); + assert (products.count (DataObjID (81010,"blassed")) == 1); + + //add something to store + assert(rSG.record(new SG::Foo(1), "pFoo1").isSuccess()); + assert(rSG.record(new SG::Foo(2), "pFoo2").isSuccess()); + rSG.commitNewDataObjects(); + assert( rSG.newDataObjectsPresent() ); + rSG.getNewDataObjects(products).ignore(); + assert( 2 == products.size() ); + assert (products.count (DataObjID (81010,"pFoo1")) == 1); + //we have emptied newdataobject array with call to newDataObjects + assert( !rSG.newDataObjectsPresent() ); + assert(rSG.record(new SG::Foo(3), "pFoo3").isSuccess()); + rSG.commitNewDataObjects(); + assert( rSG.newDataObjectsPresent() ); + rSG.getNewDataObjects(products).ignore(); + assert( 1 == products.size() ); + // assert (products.count (DataObjID (81010,"pFoo3")) == 1); + assert (products.count (DataObjID ("SG::Foo","pFoo3")) == 1); + } + void testNoSlot() { + cout << "\n*** SGHive_test noSlot BEGINS ***" << endl; + StoreGateSvc::setSlot(0); + testNewDataObjects(m_rHSG); + cout << "\n*** SGHive_test noSlot ENDS ***" << endl; + } + void testWithSlot(SG::HiveEventSlot* pSlot=0) { + cout << "\n*** SGHive_test withSlot BEGINS ***" << endl; + if (pSlot) m_pSlot=pSlot; + StoreGateSvc::setSlot(m_pSlot); + testNewDataObjects(m_rHSG); + cout << "\n*** SGHive_test withSlot ENDS ***" << endl; + } + }; + + +} //ns SG + +int main() { + cout << "*** SGHiveTest BEGINS ***" << endl; + ISvcLocator* pSvcLoc; + initGaudi("SGHive_test.txt", pSvcLoc); + IHiveWhiteBoard* pWB(0); + assert( pSvcLoc->service("SG::HiveMgrSvc/HiveMgrSvc", pWB, true).isSuccess() ); + + SG::HiveMgrSvc* pSGHM(dynamic_cast<SG::HiveMgrSvc*>(pWB)); + assert( pSGHM ); + + //too late to change the number of stores + SGASSERTERROR( pWB->setNumberOfStores(99).isSuccess() ); + + SG::TestSGHiveMgrSvc::init(*pSGHM); + + //since we have used all slots this should fail + SGASSERTERROR( SG::TestSGHiveMgrSvc::next(*pWB, 123465)!=string::npos ); + //reallocating a slot for active event should fail + SGASSERTERROR( SG::TestSGHiveMgrSvc::next(*pWB, 0)!=string::npos ); + + //can not clear a non existing slot + SGASSERTERROR( SG::TestSGHiveMgrSvc::clear(*pWB, 222222).isSuccess() ); + //clear an existing one + assert( SG::TestSGHiveMgrSvc::clear(*pWB, 1).isSuccess() ); + //now that we cleared, we should be able to allocate another store + assert( SG::TestSGHiveMgrSvc::next(*pWB, 333333)!=string::npos ); + + //now test the HiveStoreSvc itself + + StoreGateSvc* pHSG(0); + assert( pSvcLoc->service("StoreGateSvc", pHSG, true).isSuccess() ); + + SG::TestHiveStoreSvc testHSG(*pHSG); + testHSG.testNoSlot(); + testHSG.testWithSlot(); + + assert( pHSG->finalize().isSuccess() ); + assert( pSGHM->finalize().isSuccess() ); + cout << "*** SGHiveTest OK ***\n\n" <<endl; + + return 0; +} +#else +int main() { return 0; } +#endif //ATHENAHIVE diff --git a/EDM/athena/Control/StoreGate/test/SGIterator_test.cxx b/EDM/athena/Control/StoreGate/test/SGIterator_test.cxx new file mode 100644 index 00000000..42c271ea --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/SGIterator_test.cxx @@ -0,0 +1,142 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TestTools/initGaudi.h" +#include "TestTools/FLOATassert.h" +#include "TestTools/SGassert.h" +#include "StoreGate/DataHandle.h" +#include "StoreGate/SGIterator.h" +#include "StoreGate/StoreGateSvc.h" +#include "SGTools/TransientAddress.h" +#include "SGTools/DataProxy.h" +#include "SGTools/StorableConversions.h" + +#include <algorithm> +#include <cassert> +#include <iostream> +#include <list> + +using SG::DataProxy; +using SG::TransientAddress; +using std::list; +using std::cerr; +using std::cout; +using std::endl; + + +struct MyDataObj { + MyDataObj() : m_i(3), m_f(3.14) {} + int m_i; + double m_f; + double f() { return m_f; } +}; +bool operator==(const MyDataObj& lhs, const MyDataObj& rhs) { + return ( (lhs.m_i == rhs.m_i) && Athena_test::floatEQ(lhs.m_f,rhs.m_f) ); +} + +typedef std::list<int> IntList; +/** @file DataHandle_test.cxx unit test for DataHandle + * @author ATLAS Collaboration + * $Id: SGIterator_test.cxx,v 1.1 2008-09-26 23:37:53 calaf Exp $ + ***************************************************************************/ + +#include "SGTools/CLASS_DEF.h" +CLASS_DEF(IntList, 8001, 3) +CLASS_DEF(MyDataObj, 8000, 1) + +namespace Athena_test { + void iteratorTest() { + //empty handles + DataHandle<MyDataObj> empty; + SG::Iterator<MyDataObj> emptyIter(empty); + + //init with an empty proxy + DataProxy* emProxy(new DataProxy()); + const DataHandle<IntList> emptyProxy(emProxy); + SGASSERTERROR(emptyProxy.isValid()); + //delete emProxy; + //init with a valid proxy + DataProxy* pMyProxy(new DataProxy(SG::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo"))); + DataHandle<MyDataObj> hMy(pMyProxy); + assert(hMy.isValid()); + assert(hMy->m_i==3); + assert(hMy!=empty); + SG::Iterator<MyDataObj> iterMy(hMy); + assert(iterMy->m_i==3); + assert(iterMy!=emptyIter); + + + + //copy it and test + SG::Iterator<MyDataObj> iterMyCopy(iterMy); + assert(iterMyCopy->m_i==3); + assert(iterMy==iterMyCopy); + + //assign it and test + SG::Iterator<MyDataObj> iterMyCopy2; + iterMyCopy2 = iterMy; + assert(iterMyCopy2->m_i==3); + assert(iterMy==iterMyCopy2); + + //try a couple of stl algorithms to check the typedefs + std::distance(iterMy, iterMyCopy); + cout << "*** SGIterator test OK ***" <<endl; + } + void constIteratorTest() { + //empty handles + DataHandle<MyDataObj> empty; + SG::ConstIterator<MyDataObj> emptyIter(empty); + + //init with an empty proxy + DataProxy* emProxy(new DataProxy()); + const DataHandle<IntList> emptyProxy(emProxy); + SGASSERTERROR(emptyProxy.isValid()); + //delete emProxy; + //init with a valid proxy + DataProxy* pMyProxy(new DataProxy(SG::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo"))); + DataHandle<MyDataObj> hMy(pMyProxy); + assert(hMy.isValid()); + assert(hMy->m_i==3); + assert(hMy!=empty); + SG::ConstIterator<MyDataObj> iterMy(hMy); + assert(iterMy->m_i==3); + assert(iterMy!=emptyIter); + + + + //copy it and test + SG::ConstIterator<MyDataObj> iterMyCopy(iterMy); + assert(iterMyCopy->m_i==3); + assert(iterMy==iterMyCopy); + + //assign it and test + SG::ConstIterator<MyDataObj> iterMyCopy2; + iterMyCopy2 = iterMy; + assert(iterMyCopy2->m_i==3); + assert(iterMy==iterMyCopy2); + + //try a couple of stl algorithms to check the typedefs + std::distance(iterMy, iterMyCopy); + //needs ordering predicate std::sort(iterMy, iterMyCopy); + cout << "*** SGConstIterator test OK ***" <<endl; + } + +} + +using namespace Athena_test; + +//#include "Reflex/PluginService.h" + +int main() { + // ROOT::Reflex::PluginService::SetDebug(8); + cout << "*** SGIterator_test starts ***" <<endl; + ISvcLocator* pDum; + initGaudi(pDum); //need MessageSvc + iteratorTest(); + constIteratorTest(); + cout << "*** SGIterator_test OK ***" <<endl; + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/SGtests.cxx b/EDM/athena/Control/StoreGate/test/SGtests.cxx new file mode 100644 index 00000000..54e9e43c --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/SGtests.cxx @@ -0,0 +1,1096 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + "library" of SG test functions + ------------------------------ + ATLAS Collaboration + ***************************************************************************/ + +#undef NDEBUG + +// $Id: SGtests.cxx,v 1.42 2009-01-09 21:24:20 calaf Exp $ + +// INCLUDES +#include <algorithm> +#include <cassert> +#include <iostream> +#include <stdexcept> + +#include <boost/config.hpp> + +#include "StoreGate/SGtests.h" +#include "TestTools/SGassert.h" + +#ifndef NOGAUDI + +#include "SGTools/DataHandleBase.h" +#include "StoreGate/DataHandle.h" +#include "StoreGate/SGWPtr.h" +#include "StoreGate/WriteHandle.h" +#include "StoreGate/ReadHandle.h" +#include "StoreGate/StoreGate.h" +#include "StoreGate/StoreGateSvc.h" +#include "SGTools/DataStore.h" +#include "SGTools/SGVersionedKey.h" +#include "AthenaKernel/IProxyProviderSvc.h" +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/IConversionSvc.h" +#include "GaudiKernel/IOpaqueAddress.h" + +using namespace std; +using namespace SG; + +using SG::DataStore; +#if __cplusplus > 201100 +using CxxUtils::make_unique; +#endif + +class Base {}; +class Foo : public Base { +public: + static std::vector<int> dtor_log; + Foo() : m_i(0), m_d(0.0) {} + Foo(int i) : m_i(i), m_d(0.0) {} + int i() const { return m_i; } + ~Foo() { + dtor_log.push_back (m_i); +#ifdef MAKEITBOMB + //int* ifg(0); + //std::cout << *ifg << std::endl; +#endif + // std::cout << "~Foo @" << this << " i() " << i() << std::endl; + } +private: + int m_i; + double m_d; +}; +std::vector<int> Foo::dtor_log; +class Bar : public Base {}; +class NotThere {}; + +class SillyKey { +public: + SillyKey(const std::string& aString) : m_string(aString) {} + operator std::string() const {return m_string;} + +private: + std::string m_string; + +}; + +//----------------------------------- +static int b1_dtor = 0; +struct B1 { B1() : b(0){} virtual ~B1() { ++b1_dtor; } int b; }; +struct D1 : virtual public B1 { int d; }; +CLASS_DEF(B1, 8111, 1) +CLASS_DEF(D1, 8112, 1) +SG_BASE (D1, B1); + + + +#include "SGTools/CLASS_DEF.h" +CLASS_DEF(Base, 8100, 1) +CLASS_DEF(Foo, 8101, 1) +CLASS_DEF(Bar, 8107, 1) +CLASS_DEF(NotThere, 8103, 1) + +#include "AthContainersInterfaces/IAuxElement.h" +struct BX + : public IAuxElement +{ + int x; + BX(int the_x=0) : x(the_x), m_store(0), m_constStore(nullptr) {} + + bool hasStore() const { return m_store != 0; } + void setStore (SG::IAuxStore* store) { m_store = store; } + void setStore (SG::IConstAuxStore* store) { m_constStore = store; } + bool usingStandaloneStore() const { return hasStore(); } + SG::IAuxStore* getStore() { return m_store; } + + SG::IAuxStore* m_store; + SG::IConstAuxStore* m_constStore; +}; +struct BBX + : public IAuxElement +{ + int x; + BBX(int the_x=0) : x(the_x) {} +}; +template <class T> +class TestVector + : public std::vector<T*> +{ +public: + typedef T base_value_type; + TestVector() : m_constStore(0) {} + void setStore (SG::IAuxStore* s) { m_constStore = s; } + void setStore (const SG::IConstAuxStore* s) { m_constStore = s; } + bool hasStore() const { return m_constStore != 0; } +private: + const SG::IConstAuxStore* m_constStore; +}; +CLASS_DEF( BX , 82835621, 1 ) +CLASS_DEF( TestVector<BX> , 82735621, 1 ) +CLASS_DEF( TestVector<BBX> , 125040193 , 1 ) + +class TestAuxStore + : public SG::IAuxStore, public ILockable +{ +public: + TestAuxStore() : m_locked(false) {} + virtual const void* getData (SG::auxid_t /*auxid*/) const { return 0; } + virtual const SG::auxid_set_t& getAuxIDs() const { return m_set; } + virtual void* getData (auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) { return 0; } + virtual const SG::auxid_set_t& getWritableAuxIDs() const { return m_set; } + virtual bool resize (size_t /*sz*/) { return false; } + virtual void reserve (size_t /*sz*/) {} + virtual void shift (size_t /*pos*/, ptrdiff_t /*offs*/) {} + virtual bool insertMove (size_t, IAuxStore&, const SG::auxid_set_t&) { std::abort(); } + virtual void* getDecoration (auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) { std::abort(); } + virtual void lock() { m_locked = true; } + virtual void clearDecorations() { std::abort(); } + virtual size_t size() const { std::abort(); } + + bool m_locked; + +private: + SG::auxid_set_t m_set; +}; +CLASS_DEF( TestAuxStore , 125030194 , 1 ) + + +#include "AthContainersInterfaces/CLASS_AUXSTORE.h" +CLASS_AUXSTORE3( TestVector<BBX> , TestAuxStore, TestAuxStore ) + +namespace Athena_test +{ + static const bool LOCKED(false); + static const bool RESET(true), DELETE(false); + + void testRecord(::StoreGateSvc& rSG) + { + cout << "*** StoreGateSvcClient_test record BEGINS ***" << endl; + Foo* pFoo = new Foo(1); + // cout << "pFoo=" << hex << pFoo << dec << endl; + assert(rSG.record(pFoo, "pFoo1").isSuccess()); + //can't record with same key + SGASSERTERROR(rSG.record(new Foo(3), "pFoo1", LOCKED).isSuccess()); + //can'r record same object twice + SGASSERTERROR(rSG.record(pFoo, "pFoo2", !LOCKED).isSuccess()); + //check we haven't left any trace of "pFoo2" in DataStore + assert(rSG.record(new Foo(2), "pFoo2", !LOCKED).isSuccess()); + + const Foo* cpFoo = new Foo; + assert(rSG.record(cpFoo, "cpFoo").isSuccess()); + + /// cpFoo CLID is 8101 : check it + assert (8101 == rSG.clid("cpFoo")); + vector<CLID> ids(rSG.clids("cpFoo")); + assert(1 == ids.size()); + + SillyKey key("silly"); + assert(rSG.record(new Foo(4), key).isSuccess()); + //can't record with same key + SGASSERTERROR(rSG.record(new Foo(5), key).isSuccess()); + SGASSERTERROR(rSG.record(new Foo(6), key, LOCKED).isSuccess()); +#if __cplusplus > 201100 + { + std::unique_ptr<Foo> foo5 (new Foo(5)); + SGASSERTERROR(rSG.record(std::move(foo5), key).isSuccess()); + assert (foo5.get() == 0); + } +#endif + + assert(rSG.record(new Foo(7), "UnLocked", !LOCKED).isSuccess()); + assert(rSG.record(new Foo(8), "Locked", LOCKED).isSuccess()); + assert(rSG.record(new Foo(9), "LockedReset", LOCKED, RESET).isSuccess()); + assert(rSG.record(new Foo(10), "UnLockedReset", !LOCKED, RESET).isSuccess()); + assert(rSG.record(new Foo(11), "LockedDelete", LOCKED, DELETE).isSuccess()); + +#if __cplusplus > 201100 + { + std::unique_ptr<Foo> foo12 (new Foo(12)); + assert(rSG.record(std::move(foo12), + "UnLockedDelete", !LOCKED, DELETE).isSuccess()); + assert(foo12.get() == 0); + } +#else + assert(rSG.record(new Foo(12), "UnLockedDelete", !LOCKED, DELETE).isSuccess()); +#endif + + assert(rSG.record(cpFoo=new Foo(13), "Const").isSuccess()); + +#if __cplusplus > 201100 + std::unique_ptr<const Foo> foo13a (new Foo(130)); + assert(rSG.record(std::move(foo13a), "Const2").isSuccess()); + assert(foo13a.get() == 0); +#else + assert(rSG.record(cpFoo=new Foo(130), "Const2").isSuccess()); +#endif + + //FIXME!!! assert(rSG.record(cpFoo=new Foo(14), "ConstUnLocked", !LOCKED).isSuccess()); + SGASSERTERROR(rSG.record(cpFoo=new Foo(15), "Const").isSuccess()); + + + /// Test overwriting. + assert (rSG.record(new Foo(101), "ow").isSuccess()); + assert (rSG.overwrite(new Foo(102), "ow").isSuccess()); +#if __cplusplus > 201100 + assert (rSG.overwrite(make_unique<Foo>(103), "ow").isSuccess()); +#else + assert (rSG.overwrite(new Foo(103), "ow").isSuccess()); +#endif + + assert (rSG.record(new Foo(104), "ow2", LOCKED).isSuccess()); + assert (rSG.overwrite(new Foo(105), "ow2", LOCKED).isSuccess()); +#if __cplusplus > 201100 + assert (rSG.overwrite(make_unique<Foo>(106), "ow2", LOCKED).isSuccess()); +#else + assert (rSG.overwrite(new Foo(106), "ow2", LOCKED).isSuccess()); +#endif + + /// 14 Foo objects recorded above : check it + assert(rSG.typeCount<Foo>() == 14); + + + cout << "*** StoreGateSvcClient_test records OK ***\n\n" <<endl; + } + + void testRemove(::StoreGateSvc& rSG) + { + cout << "*** StoreGateSvcClient_test remove BEGINS ***" << endl; + // retrieve a keyless object: Should fail because ambiguous retrieve + Foo* pFoo; + SGASSERTERROR(rSG.retrieve(pFoo).isSuccess()); + + /// retrieve a keyless object with default key: should also fail + /// becaus of ambiguity + SGASSERTERROR(rSG.retrieve(pFoo, SG::DEFAULTKEY).isSuccess()); + + // record a keyed object and remove. this will only reset proxy + pFoo = new Foo(); + assert(rSG.record(pFoo, "pFooKey").isSuccess()); + assert(rSG.remove(pFoo).isSuccess()); + cout << " Now we expect to see an error for invalid proxy >>> " << endl; + assert(rSG.retrieve(pFoo, "pFooKey").isFailure()); + cout << " end of error >>>>>>>>>>>>> " << endl; + + pFoo = new Foo(); + assert(rSG.record(pFoo, "pFooKey").isSuccess()); + assert(rSG.remove(pFoo).isSuccess()); + assert(0 == rSG.proxy(pFoo)); + assert(0 != rSG.proxy(ClassID_traits<Foo>::ID(), "pFooKey")); + const bool DONTCHECK(false); + assert(0 != rSG.proxy(ClassID_traits<Foo>::ID(), "pFooKey", DONTCHECK)); + + pFoo = new Foo(); + assert(rSG.record(pFoo, "pFooKey").isSuccess()); + assert(rSG.removeDataAndProxy(pFoo).isSuccess()); + assert(0 == rSG.proxy(pFoo)); + assert(0 == rSG.proxy(ClassID_traits<Foo>::ID(), "pFooKey")); + assert(0 == rSG.proxy(ClassID_traits<Foo>::ID(), "pFooKey", DONTCHECK)); + cout << "*** StoreGateSvcClient_test removes OK ***\n\n" <<endl; + } + + void testSymLink(::StoreGateSvc& rSG) + { + const Foo *cFoo; + Foo *noFoo(0); + Base* bDum(0); + + cout << "*** StoreGateSvcClient_test symlinks BEGINS ***" <<endl; + SGASSERTERROR(rSG.retrieve(cFoo).isSuccess()); + SGASSERTERROR(rSG.symLink(cFoo, bDum).isSuccess()); + +#ifdef TEST_BOOST_CONCEPT_CHECK + NotThere* notDum; + //line below should not compile: Foo is not convertible to a NotThere! + rSG.symLink(cFoo, notDum); +#endif + + SGASSERTERROR(rSG.symLink(noFoo, bDum).isSuccess()); + + + assert(rSG.symLink(ClassID_traits<Foo>::ID(), + "UnLocked", + ClassID_traits<Base>::ID()).isSuccess()); + //let's check we got all clids for "UnLocked" + vector<CLID> unids(rSG.clids("UnLocked")); + assert (1 == count(unids.begin(), unids.end(), ClassID_traits<Foo>::ID())); + assert (1 == count(unids.begin(), unids.end(), ClassID_traits<Base>::ID())); + assert (2 == rSG.clids("UnLocked").size()); + + Base* pB; + assert(rSG.retrieve(pB, "UnLocked").isSuccess()); + + //FIXME this will work when we'll have the inher tree from reflection + //FIXME SGASSERTERROR(rSG.symLink(ClassID_traits<Foo>::ID(), + //FIXME "UnLocked", + //FIXME ClassID_traits<NotThere>::ID()).isSuccess()); + SGASSERTERROR(rSG.symLink(ClassID_traits<Foo>::ID(), "is not there", + ClassID_traits<Base>::ID()).isSuccess()); + + + + // assert(rSG.contains<Base>()); + assert(rSG.contains<Base>("UnLocked")); + + const Base* base; + assert(rSG.retrieve(base).isSuccess()); + assert(rSG.retrieve(base, "UnLocked").isSuccess()); + SGASSERTERROR(rSG.retrieve(base, "modSully").isSuccess()); + +#ifdef TEST_DEPRECATED + const DataHandle<Base> chBase; + assert(rSG.retrieve(chBase).isSuccess()); + assert(rSG.retrieve(chBase, "UnLocked").isSuccess()); + + DataHandle<Base> hBase; + assert(rSG.retrieve(hBase).isSuccess()); + assert(rSG.retrieve(hBase, "UnLocked").isSuccess()); + + const DataHandle<Base> chBaseBeg, chBaseEnd; + assert(rSG.retrieve(chBaseBeg, chBaseEnd).isSuccess()); + assert(chBaseBeg != chBaseEnd); +#endif +#ifdef DHR_COMPILEERROR + DataHandle<Base> hBaseBeg, hBaseEnd; + assert(rSG.retrieve(hBaseBeg, hBaseEnd).isSuccess()); + assert(hBaseBeg != hBaseEnd); +#endif + + SG::ConstIterator<Base> ciBaseBeg,ciBaseEnd; + assert(rSG.retrieve(ciBaseBeg, ciBaseEnd).isSuccess()); + assert(ciBaseBeg != ciBaseEnd); + + cout << "*** StoreGateSvcClient_test symlinks OK ***\n\n" <<endl; + + } + + void test_symlink2 (::StoreGateSvc& sg) + { + // More symlink tests. + // Check that we can put an object in and get the properly converted + // base type out via the symlink. Also tests auto symlink making. + D1* d1 = new D1; + B1* b1a = d1; + assert ((void*)b1a != (void*)d1); + + assert (sg.record (d1, "d1", true, false).isSuccess()); + B1* b1b = 0; + assert (sg.retrieve (b1b, "d1").isSuccess()); + assert (b1b == b1a); + //get d1 proxy + SG::DataProxy* dp = sg.proxy (ClassID_traits<D1>::ID(), std::string("d1")); + assert (dp != 0); + assert (dp->refCount() == 2); // since auto-symLink made + std::cout << dp->store() << std::endl; + std::cout << &sg << sg.name() << std::endl; + // assert (dp->store() == &sg); + + // create alias with type, key + assert (sg.setAlias(d1, "d1Alias").isSuccess()); + D1* d1Alias = 0; + assert (sg.retrieve(d1Alias, "d1Alias").isSuccess()); + assert(d1Alias == d1); + assert (dp->refCount() == 3); // add one alias + + // create alias with pointer + assert (sg.setAlias(d1, "d1AnotherAlias").isSuccess()); + D1* d1AnotherAlias = 0; + assert (sg.retrieve(d1AnotherAlias, "d1AnotherAlias").isSuccess()); + assert (d1AnotherAlias == d1); + assert (dp->refCount() == 4); // add another alias + + // record another object + D1* d2 = new D1; + assert (sg.record(d2, "d2", true, false).isSuccess()); + + // retrieve it + D1* d2b = 0; + assert (sg.retrieve(d2b, "d2").isSuccess()); + + // set same alias as D1 + assert (sg.setAlias(d2, "d1Alias").isSuccess()); + + // retrieve with alias and make sure that you get the new one. + d1Alias = 0; + assert (sg.retrieve(d1Alias, "d1Alias").isSuccess()); + assert (d1Alias == d2); + + // Check refcount handling for making duplicate symlinks. + + assert (dp->refCount() == 3); + + assert (sg.symLink (d1, (B1*)0).isSuccess()); + // Refcount should be the same. + assert (dp->refCount() == 3); + + // Loop up by transient addr. Both should work. + assert (dp == sg.proxy (d1)); + assert (dp == sg.proxy (b1a)); + + // Now remove it. The symlink needs to go away too. + assert (b1_dtor == 0); + assert (sg.removeDataAndProxy(d1).isSuccess()); + assert (b1_dtor == 1); + + assert (!sg.contains<D1> ("d1")); + assert (!sg.contains<B1> ("d1")); + assert (0 == sg.proxy (d1)); + assert (0 == sg.proxy (b1a)); + + // print all keys + std::vector<std::string> keyList; + sg.keys<D1>(keyList, true); + std::vector<std::string>::const_iterator iter = keyList.begin(); + for (; iter != keyList.end(); iter++) { + std::cout << "Found key = " << *iter << " for object D1 in StoreGate " + << std::endl; + } + /// type D1 was recorded with "d1" and "d2" + /// two alias to d1 but sg.remove() remove alled d1 + /// one alias to d2... so size must be 2 after remove. + assert(keyList.size() == 2); + + } + + + //************************************************************************ + + class TestConversion + : public IConversionSvc + { + public: + virtual StatusCode addConverter(IConverter*) { abort(); } + virtual StatusCode addConverter(const CLID&) { abort(); } + virtual StatusCode removeConverter(const CLID&) { abort(); } + virtual IConverter* converter(const CLID&) { abort(); } + virtual StatusCode connectOutput(const std::string&) { abort(); } + virtual StatusCode connectOutput(const std::string&, + const std::string&) { abort(); } + virtual StatusCode commitOutput(const std::string&, + bool) { abort(); } + virtual StatusCode initialize() { abort(); } + virtual StatusCode finalize() { abort(); } + virtual const CLID& objType() const { abort(); } + virtual long repSvcType() const { abort(); } + virtual StatusCode setDataProvider(IDataProviderSvc*) { abort(); } +#ifdef ATLAS_GAUDI_V21 + virtual SmartIF<IDataProviderSvc>& dataProvider() const { abort(); } + virtual StatusCode setConversionSvc(IConversionSvc*) { abort(); } + virtual SmartIF<IConversionSvc>& conversionSvc() const { abort(); } + virtual StatusCode setAddressCreator(IAddressCreator*) { abort(); } + virtual SmartIF<IAddressCreator>& addressCreator() const { abort(); } +#else + virtual IDataProviderSvc* dataProvider() const { abort(); } + virtual StatusCode setConversionSvc(IConversionSvc*) { abort(); } + virtual IConversionSvc* conversionSvc() const { abort(); } + virtual StatusCode setAddressCreator(IAddressCreator*) { abort(); } + virtual IAddressCreator* addressCreator() const { abort(); } +#endif + virtual StatusCode fillObjRefs(IOpaqueAddress*, DataObject*) { abort(); } + virtual StatusCode updateObj(IOpaqueAddress*, DataObject*) { abort(); } + virtual StatusCode updateObjRefs(IOpaqueAddress*, DataObject*) { abort(); } + virtual StatusCode createRep(DataObject*, IOpaqueAddress*&) { abort(); } + virtual StatusCode fillRepRefs(IOpaqueAddress*, DataObject*) { abort(); } + virtual StatusCode updateRep(IOpaqueAddress*, DataObject*) { abort(); } + virtual StatusCode updateRepRefs(IOpaqueAddress*, DataObject*) { abort(); } + virtual StatusCode queryInterface(const InterfaceID&, + void**) { abort(); } + + virtual StatusCode createObj(IOpaqueAddress*, DataObject*&); + virtual unsigned long addRef() { return 0; } + virtual unsigned long release() { return 0; } + }; + + + StatusCode TestConversion::createObj (IOpaqueAddress* /*pAddress*/, + DataObject*& refpObject) + { + D1* d1 = new D1; + refpObject = SG::asStorable (d1); + return StatusCode::SUCCESS; + } + + + class TestIOA + : public IOpaqueAddress + { + public: + virtual unsigned long addRef () { return 0; } + virtual unsigned long release () { return 0; } + virtual const CLID& clID () const { abort(); } + virtual long svcType () const { abort(); } + virtual IRegistry* registry () const { abort(); } + virtual void setRegistry(IRegistry*) { abort(); } + virtual const std::string* par () const { abort(); } + virtual const unsigned long* ipar () const { abort(); } + }; +} // namespace Athena_test + + + +// Hack to get store from sg svc --- this is declared as a friend. +class EventDumperSvc +{ +public: + static SG::DataStore* get_store (::StoreGateSvc& sg) + { return sg.store(); } +}; + + +namespace Athena_test { + void test_symlink3 (::StoreGateSvc& sg) + { + // Test that t->proxy map is set correctly for auto-created + // objs with symlinks. + TestConversion cnv; + + IOpaqueAddress *pIOA(new TestIOA); + + SG::TransientAddress* taddr = + new SG::TransientAddress (ClassID_traits<D1>::ID(), "dd", + pIOA, false); + DataProxy* dp = new SG::DataProxy (taddr, &cnv); + SG::DataStore* store = EventDumperSvc::get_store (sg); + assert (store->addToStore (ClassID_traits<D1>::ID(), dp).isSuccess()); + IOpaqueAddress *pIOAB(new TestIOA); + taddr = + new SG::TransientAddress (ClassID_traits<D1>::ID(), "dd", + pIOAB, false); + taddr->setTransientID (ClassID_traits<B1>::ID()); + DataProxy* dpB = new SG::DataProxy (taddr, &cnv); + assert (store->addToStore (ClassID_traits<B1>::ID(), dpB).isSuccess()); + + D1* d1 = 0; + B1* b1 = 0; + + assert (sg.retrieve(d1, "dd").isSuccess()); + assert (sg.retrieve(b1, "dd").isSuccess()); + // assert (d1 == b1); + assert (d1->b == 0); + d1->b = 1; + + assert (sg.proxy(d1) == dp); + assert (sg.proxy(b1) == dpB); + + sg.clearStore(); + assert (sg.retrieve(d1, "dd").isSuccess()); + assert (sg.retrieve(b1, "dd").isSuccess()); + // assert (d1 == b1); + assert (d1->b == 0); + + assert (sg.proxy(d1) == dp); + assert (sg.proxy(b1) == dpB); + + sg.removeDataAndProxy(d1); + sg.removeDataAndProxy(b1); + //FIXME WHY? + delete pIOA; + delete pIOAB; + } + + + + //************************************************************************ + + void testContains(::StoreGateSvc& rSG) + { + cout << "*** StoreGateSvcClient_test contains BEGINS ***" << endl; + // assert(rSG.contains<Foo>()); + // assert(!rSG.contains<NotThere>()); + + assert(rSG.contains<Foo>("UnLocked")); + assert(!rSG.contains<Foo>("sully")); + assert(rSG.transientContains<Foo>("UnLocked")); + assert(!rSG.transientContains<Foo>("sully")); + + cout << "*** StoreGateSvcClient_test contains OK ***\n\n" <<endl; + } + +#ifdef FOLDERS_ASDOBJ +#include "SGTools/SGIFolder.h" + void testFolders(::StoreGateSvc& rSG) + { + cout << "*** StoreGateSvcClient_test folders BEGINS ***" <<endl; + //this of course depend on the job opts + SG::IFolder *pMyFolder, *pYourFolder, *pNotFolder; + assert(rSG.retrieve(pMyFolder, "MyFolder").isSuccess()); + assert( 2 == std::distance(pMyFolder->begin(), pMyFolder->end()) ); + assert(rSG.retrieve(pYourFolder, "YourFolder").isSuccess()); + SGASSERTERROR((rSG.retrieve(pNotFolder, "NotAFolder").isSuccess())); + + cout << "*** StoreGateSvcClient_test folders OK ***\n\n" <<endl; + } +#endif + + void testRetrieve(::StoreGateSvc& rSG) { + + cout << "*** StoreGateSvcClient_test retrieve BEGINS ***" <<endl; + const Foo *cFoo; + const NotThere* notThere; + SGASSERTERROR(rSG.retrieve(cFoo).isSuccess()); + SGASSERTERROR(rSG.retrieve(notThere).isSuccess()); + SGASSERTERROR(rSG.retrieve<Foo> () != 0); + SGASSERTERROR(rSG.retrieve<const Foo> () != 0); + + assert(rSG.retrieve(cFoo, "UnLocked").isSuccess()); + assert (rSG.retrieve<const Foo> ("UnLocked") == cFoo); + SGASSERTERROR(rSG.retrieve<const Foo> ("UnLockedxxx") != 0); + +#ifdef TEST_DEPRECATED + const DataHandle<Foo> chFoo; + const DataHandle<NotThere> chNotThere; + SGASSERTERROR(rSG.retrieve(chFoo).isSuccess()); + SGASSERTERROR(rSG.retrieve(chNotThere).isSuccess()); + + assert(rSG.retrieve(chFoo, "UnLocked").isSuccess()); + SGASSERTERROR(rSG.retrieve(chFoo, "modSully").isSuccess()); + + DataHandle<Foo> hFoo; + SGASSERTERROR(rSG.retrieve(hFoo).isSuccess()); + + assert(rSG.retrieve(hFoo, "silly").isSuccess()); + assert(rSG.setConst(hFoo.cptr()).isSuccess()); + SGASSERTERROR(rSG.retrieve(hFoo, "silly").isSuccess()); +#endif + + SG::ConstIterator<Foo> ciFooBeg, ciFooEnd; + assert(rSG.retrieve(ciFooBeg, ciFooEnd).isSuccess()); + assert(ciFooBeg != ciFooEnd); + SG::ConstIterator<NotThere> ciNotThereBeg, ciNotThereEnd; + assert(rSG.retrieve(ciNotThereBeg, ciNotThereEnd).isFailure()); + assert(ciNotThereBeg == ciNotThereEnd); + + cout << "*** StoreGateSvcClient_test retrieve OK ***\n\n" <<endl; + } + + void testTryRetrieve(::StoreGateSvc& rSG) { + + cout << "*** StoreGateSvcClient_test tryRetrieve BEGINS ***" <<endl; + cout << "we should see no WARNING message for failed retrieves" <<endl; + assert(rSG.tryRetrieve<Foo> () == 0); + assert(rSG.tryConstRetrieve<Foo> () == 0); + + const Foo *cFoo; + assert(rSG.retrieve(cFoo, "UnLocked").isSuccess()); + assert (rSG.retrieve<const Foo> ("UnLocked") == cFoo); + assert(rSG.tryConstRetrieve<Foo> ("UnLockedxxx") == 0); + + cout << "*** StoreGateSvcClient_test tryRetrieve OK ***\n\n" <<endl; + } + + + void testReadPrivateCopy(::StoreGateSvc& rSG) { + cout << "*** StoreGateSvcClient_test readPrivateCopy BEGINS ***" <<endl; + const Foo *cFoo(0); + assert(rSG.retrieve<Foo>(cFoo,"silly").isSuccess()); + std::unique_ptr<Foo> apFoo(rSG.readUniquePrivateCopy<Foo>("silly")); + assert(cFoo != apFoo.get()); + assert(rSG.retrieve(cFoo, "silly").isSuccess()); + cout << "*** StoreGateSvcClient_test readPrivateCopy OK ***" <<endl; + } + + + void testRetrievePrivateCopy(::StoreGateSvc& rSG) { + cout << "*** StoreGateSvcClient_test retrievePrivateCopy BEGINS ***" <<endl; + const Foo *cFoo(0); + assert(rSG.retrieve<Foo>(cFoo,"silly").isSuccess()); + std::unique_ptr<Foo> apFoo(rSG.retrieveUniquePrivateCopy<Foo>("silly")); + assert(cFoo == apFoo.get()); + SGASSERTERROR(rSG.retrieve(cFoo, "silly").isSuccess()); + cout << "*** StoreGateSvcClient_test retrievePrivateCopy OK ***" <<endl; + } + + + void testBind(::StoreGateSvc& rSG) { + + cout << "*** StoreGateSvcClient_test bind BEGINS ***" <<endl; + DataHandle<Foo> chFoo; + Foo *cFoo = new Foo; + std::string dbKey="fooKey"; + + assert(rSG.record(cFoo,dbKey).isSuccess()); + + assert(rSG.bind(chFoo,dbKey).isSuccess()); + assert(chFoo.ptr() == cFoo); + +//FIXME cout << "** bind it a second time with same key" << endl; +// // try to bind it twice +//FIXME assert(rSG.bind(chFoo,dbKey).isSuccess()); + +//FIXME Foo *cFoo2 = new Foo; +//FIXME std::string dbKey2="fooKey2"; +//FIXME assert(rSG.record(cFoo2,dbKey2).isSuccess()); +//FIXME cout << "** bind it a third time with a different key, obj: " +//FIXME << hex << cFoo << " " << cFoo2 << dec << endl; +// // try to bind it twice with a different key +//FIXME assert(rSG.bind(chFoo,dbKey2).isSuccess()); + + IProxyProviderSvc* pIPPSvc; + assert((rSG.serviceLocator()->service("ProxyProviderSvc", pIPPSvc, true)).isSuccess()); + +//FIXME TransientID id(ClassID_traits<Foo>::ID(), dbKey); +//FIXME DataProxy *dp = pIPPSvc->getProxy(id, rSG); +//FIXME assert (dp != 0); + +//FIXME // rSG.clearStore().ignore(); +//FIXME dp->reset(); + +//FIXME SGASSERTERROR(chFoo.ptr() != 0); + + cout << "*** StoreGateSvcClient_test bind OK ***\n\n" <<endl; + + } + + void testClear(::StoreGateSvc& rSG) { + + Foo* pFoo; + assert(rSG.record(pFoo=new Foo, "LockReset", LOCKED, RESET).isSuccess()); + assert(rSG.record(pFoo=new Foo, "UnLockReset", !LOCKED, RESET).isSuccess()); + assert(rSG.record(pFoo=new Foo, "LockDelete", LOCKED, DELETE).isSuccess()); + assert(rSG.record(pFoo=new Foo, "UnLockDelete", !LOCKED, DELETE).isSuccess()); + Bar* pBar = new Bar(); + Base* bDum(0); + assert(rSG.record(pBar, "aBar", LOCKED, DELETE).isSuccess()); + assert(rSG.symLink(pBar, bDum).isSuccess()); + + + rSG.clearStore(true).ignore(); + rSG.clearStore().ignore(); + } + + void testTransientSwap(::StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test transientSwap BEGINS ***" << endl; + Foo* pFoo1 = new Foo(1); + // cout << "pFoo1=" << hex << pFoo1 << dec << endl; + assert(rSG.record(pFoo1, "pSwapFoo1").isSuccess()); + assert(pFoo1->i() == 1); + pFoo1 = 0; + + Foo* pFoo2 = new Foo(2); + // cout << "p2Foo2=" << hex << pFoo2 << dec << endl; + assert(rSG.record(pFoo2, "pSwapFoo2").isSuccess()); + assert(pFoo2->i() == 2); + pFoo2 = 0; + + assert(rSG.transientSwap( 8101, "pSwapFoo1", "pSwapFoo2" )); + assert(rSG.retrieve( pFoo1, "pSwapFoo1" ).isSuccess()); + assert(rSG.retrieve( pFoo2, "pSwapFoo2" ).isSuccess()); + assert(pFoo1->i() == 2); + assert(pFoo2->i() == 1); + + cout << "*** StoreGateSvcClient_test transientSwap OK ***\n\n" <<endl; + } + + void testVersionedKey(::StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test VersionedKey BEGINS ***" << endl; + //start by creating an unversioned object to test handling of legacy keys + assert(rSG.record(new Foo(11), "aVersObj").isSuccess()); + const Foo* pFoo(0); + assert(0 != (pFoo = rSG.retrieve<Foo>("aVersObj"))); + assert(pFoo->i() == 11); + + //try to put a VersionedKey on top + VersionedKey myKey("aVersObj", 77); + assert(rSG.record(new Foo(77), (std::string)myKey).isSuccess()); + const Foo* pFoo77(0); + assert(0 != (pFoo77 = rSG.retrieve<Foo>(myKey))); + assert(pFoo77->i() == 77); + //test that we can retrieve the same object with an unversioned key + assert(0 != (pFoo = rSG.retrieve<Foo>("aVersObj"))); + assert(pFoo->i() == 77); + + //check we can retrieve the old object with a default unversioned key + VersionedKey defVK("aVersObj"); + assert(0 != (pFoo = rSG.retrieve<Foo>((std::string)defVK))); + assert(pFoo->i() == 11); + + + const std::string baseKey("aVersObj"); + VersionedKey my2Key(baseKey, 88); + assert(rSG.record(new Foo(88), (std::string)my2Key).isSuccess()); + const Foo* pFoo88(0); + assert(0 != (pFoo88 = rSG.retrieve<Foo>(my2Key))); + assert(pFoo88->i() == 88); + + SGASSERTERROR(rSG.record(new Foo(66), (std::string)my2Key).isSuccess()); + VersionedKey my3Key(baseKey, 66); + assert(rSG.record(new Foo(66), (std::string)my3Key).isSuccess()); + + //test that a generic retrieve now returns the third recorded object + //Notice how a generic retrieve will always return the last recorded + //object with that key, independent from the numeric value of its version + assert(0 != (pFoo = rSG.retrieve<Foo>(baseKey))); + assert(pFoo->i() == 66); + + + + std::list<SG::ObjectWithVersion<Foo> > allVersions; + assert(rSG.retrieveAllVersions(allVersions, baseKey)); + SG::ObjectWithVersion<Foo> highest; + assert(rSG.retrieveHighestVersion(highest, baseKey)); + assert(highest.versionedKey.version() == 88); + + cout << "*** StoreGateSvcClient_test VersionedKey OK ***\n\n" <<endl; + } + + void testKeys(::StoreGateSvc& rSG) { + + cout << "\n*** StoreGateSvcClient_test Keys BEGINS ***" << endl; + rSG.clearStore().ignore(); + + Foo* pFoo; + assert(rSG.record(pFoo=new Foo, "LockReset", LOCKED, RESET).isSuccess()); + assert(rSG.record(pFoo=new Foo, "UnLockReset", !LOCKED, RESET).isSuccess()); + assert(rSG.record(pFoo=new Foo, "LockDelete", LOCKED, DELETE).isSuccess()); + assert(rSG.record(pFoo=new Foo, "UnLockDelete", !LOCKED, DELETE).isSuccess()); + assert (rSG.setAlias(pFoo, "fooAlias").isSuccess()); + + std::vector<std::string> keys; + rSG.keys<Foo>(keys); + // copy(keys.begin(), keys.end(),ostream_iterator<string>(cout," - ")); + // cout << endl; + assert(4==keys.size()); + rSG.keys<Foo>(keys, /*allKeys=*/true); + // copy(keys.begin(), keys.end(),ostream_iterator<string>(cout," - ")); + // cout << endl; + assert(5==keys.size()); + + rSG.clearStore().ignore(); + rSG.keys<Foo>(keys, /*allKeys=*/true, /*onlyValid=*/false); + // copy(keys.begin(), keys.end(),ostream_iterator<string>(cout," - ")); + // cout << endl; + assert(2==keys.size()); + + rSG.keys<Foo>(keys); + // copy(keys.begin(), keys.end(),ostream_iterator<string>(cout," - ")); + // cout << endl; + assert(0==keys.size()); + + //get rid of the two RESET dobjs + rSG.clearStore(/*force=*/true).ignore(); + + assert(rSG.record(pFoo=new Foo, "LockReset", LOCKED, DELETE).isSuccess()); + assert(rSG.record(pFoo=new Foo, "UnLockReset", !LOCKED, DELETE).isSuccess()); + assert(rSG.record(pFoo=new Foo, "LockDelete", LOCKED, DELETE).isSuccess()); + assert(rSG.record(pFoo=new Foo, "UnLockDelete", !LOCKED, DELETE).isSuccess()); + rSG.clearStore().ignore(); + rSG.keys<Foo>(keys); + // copy(keys.begin(), keys.end(),ostream_iterator<string>(cout," - ")); + // cout << endl; + + assert(0==keys.size()); + + rSG.keys<Foo>(keys, /*allKeys=*/true, /*onlyValid=*/false); + // copy(keys.begin(), keys.end(),ostream_iterator<string>(cout," - ")); + // cout << endl; + assert(0==keys.size()); + + rSG.clearStore(/*force=*/true).ignore(); + + cout << "\n*** StoreGateSvcClient_test Keys ENDS ***" << endl; + + } + + void testRetrieveAux(::StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test retrieveAux BEGINS ***" << endl; + TestVector<BX>* pVec = new TestVector<BX>; + pVec->push_back(new BX(1)); + pVec->push_back(new BX(2)); + assert(rSG.record(pVec, "BVec").isSuccess()); + TestAuxStore* pAux = new TestAuxStore; + assert(rSG.record(pAux, "BVecAux.").isSuccess()); + + //testing const objects (locked as if coming from disk) + pVec = new TestVector<BX>; + pVec->push_back(new BX(21)); + pVec->push_back(new BX(22)); + assert(rSG.record(pVec, "CVec", /*allowMods=*/false).isSuccess()); + pAux = new TestAuxStore; + assert(rSG.record(pAux, "CVecAux.", /*allowMods=*/false).isSuccess()); + + //testing missing AuxStore + pVec = new TestVector<BX>; + assert(rSG.record(pVec, "ErrorVec").isSuccess()); + + //testing CLASS_AUX3 + TestVector<BBX>* pVecc = new TestVector<BBX>; + pVecc->push_back(new BBX(1)); + pVecc->push_back(new BBX(2)); + assert(rSG.record(pVecc, "BBVec").isSuccess()); + pAux = new TestAuxStore; + assert(rSG.record(pAux, "BBVecAux.").isSuccess()); + + assert(rSG.retrieve(pVec,"BVec").isSuccess()); + //second retrieve does not trigger retrieve of AuxStore + assert( 0 != (pVec=rSG.retrieve<TestVector<BX> >("BVec")) ); + + const TestVector<BX>* cpVec(0); + assert(rSG.retrieve(cpVec, "CVec").isSuccess()); + // a regular retrieve ignores a missing aux store + assert( 0 != (cpVec=rSG.retrieve<const TestVector<BX> >("ErrorVec")) ); + // while a retrieveAux fails + SGASSERTERROR( (cpVec=rSG.constRetrieveAux<TestVector<BX> >("ErrorVec")) ); + + //deprecated but we need to test it nonetheless... +#ifdef TEST_DEPRECATED + DataHandle<TestVector<BBX> > hBBX; + assert(rSG.retrieve(hBBX, "BBVec").isSuccess()); +#endif + + // Test standalone object. + BX* pb = new BX; + assert(rSG.record(pb, "BStand").isSuccess()); + TestAuxStore* pAux_b = new TestAuxStore; + assert(rSG.record(pAux_b, "BStandAux.").isSuccess()); + + assert( 0 != (pb=rSG.retrieve<BX>("BStand")) ); + //assert (pb->usingStandAloneStore()); + //assert (pb->getStore() == pAux_b); + + cout << "*** StoreGateSvcClient_test retrieveAux OK ***\n\n" <<endl; + } + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + void testCreate(::StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test testCreate BEGINS ***" << endl; + + //recommended usage + auto pFooD = rSG.create<Foo>("pCreateFooDefault"); + assert(rSG.contains<Foo>("pCreateFooDefault")); + assert(pFooD->i() == 0); + //if you really need to know the return type... + SG::WPtr<Foo> pFoo1 = rSG.create<Foo>("pCreateFoo1", 1); + assert(rSG.transientContains<Foo>("pCreateFoo1")); + assert(pFoo1->i() == 1); + //not allowed to overwrite an existing object + SGASSERTERROR(rSG.create<Foo>("pCreateFoo1",3)); + //make sure we left the old one alone + assert(rSG.retrieve<Foo>("pCreateFoo1")->i() == 1); + + cout << "*** StoreGateSvcClient_test testCreate OK ***\n\n" <<endl; + } +#else + void testCreate(::StoreGateSvc&) + { + } +#endif + + + void testBoundReset(StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test testBoundReset BEGINS ***" << endl; + rSG.commitNewDataObjects(); + + { + SG::WriteHandle<int> h ("testBoundReset", rSG.name()); + h = CxxUtils::make_unique<int> (10); + assert (h.isValid()); + assert (*h.cachedPtr() == 10); + rSG.commitNewDataObjects(); + assert (h.cachedPtr() == nullptr); + } + + { + SG::ReadHandle<int> h ("testBoundReset", rSG.name()); + assert (h.isValid()); + assert (*h.cachedPtr() == 10); + } + + // Force the existing proxy to be deleted. + assert (rSG.overwrite (CxxUtils::make_unique<int> (20), + "testBoundReset", + true)); + rSG.commitNewDataObjects(); + + cout << "\n*** StoreGateSvcClient_test testBoundReset OK ***\n\n" << endl; + } + + + void testRecordObject(StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test testRecordObject BEGINS ***" << endl; + Foo::dtor_log.clear(); + + SG::DataObjectSharedPtr<DataObject> obj101 = + SG::asStorable (CxxUtils::make_unique<Foo> (101)); + SG::DataProxy* proxy101 = rSG.recordObject (obj101, "obj101", false, false); + assert (proxy101->name() == "obj101"); + assert (proxy101->object() == obj101.get()); + assert (obj101->refCount() == 2); + assert (proxy101->refCount() == 1); + assert (proxy101->isConst()); + + SG::DataObjectSharedPtr<DataObject> obj102 = + SG::asStorable (CxxUtils::make_unique<Foo> (102)); + SG::DataProxy* proxy102 = rSG.recordObject (obj102, "obj102", true, false); + assert (proxy102->name() == "obj102"); + assert (proxy102->object() == obj102.get()); + assert (obj102->refCount() == 2); + assert (!proxy102->isConst()); + + assert (Foo::dtor_log.empty()); + + std::cout << ">>> test duplicate record1\n"; + SG::DataObjectSharedPtr<DataObject> obj103 = + SG::asStorable (CxxUtils::make_unique<Foo> (103)); + SG::DataProxy* proxy103 = rSG.recordObject (obj103, "obj101", false, false); + assert (proxy103 == nullptr); + assert (obj103->refCount() == 2); // Held by m_trash + std::cout << "<<< test duplicate record1\n"; + + SG::DataObjectSharedPtr<DataObject> obj104= + SG::asStorable (CxxUtils::make_unique<Foo> (104)); + SG::DataProxy* proxy104 = rSG.recordObject (obj104, "obj101", false, true); + assert (proxy104 == proxy101); + assert (obj104->refCount() == 1); + + std::cout << ">>> test duplicate record2\n"; + SG::DataProxy* proxy999 = rSG.recordObject (obj101, "obj999", false, false); + assert (proxy999 == nullptr); + assert (obj101->refCount() == 3); // Held by m_trash + std::cout << "<<< test duplicate record2\n"; + + assert (proxy101->refCount() == 1); + proxy999 = rSG.recordObject (obj101, "obj999", false, true); + assert (proxy999 == proxy101); + assert (proxy101->refCount() == 2); + assert (obj101->refCount() == 3); + + rSG.clearStore(); + assert (obj101->refCount() == 1); + assert (obj102->refCount() == 1); + assert (obj103->refCount() == 1); + assert (obj104->refCount() == 1); + + cout << "\n*** StoreGateSvcClient_test testRecordObject OK ***" << endl; + } + + + void testWriteAux(StoreGateSvc& rSG) + { + cout << "\n*** StoreGateSvcClient_test testWriteAux BEGINS ***" << endl; + + TestAuxStore* paux = nullptr; + { + SG::WriteHandle<BX> h ("testWriteAux", rSG.name()); + auto obj = CxxUtils::make_unique<BX> (10); + auto objAux = CxxUtils::make_unique<TestAuxStore>(); + paux = objAux.get(); + assert (h.record (std::move(obj), std::move(objAux)).isSuccess()); + assert (!paux->m_locked); + } + cout << "\n*** StoreGateSvcClient_test testWriteAux OK ***" << endl; + } + +} //end namespace +#endif /*NOGAUDI*/ + diff --git a/EDM/athena/Control/StoreGate/test/SegMemSvc_test.cxx b/EDM/athena/Control/StoreGate/test/SegMemSvc_test.cxx new file mode 100644 index 00000000..8bab258f --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/SegMemSvc_test.cxx @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TestTools/initGaudi.h" +#include "StoreGate/SegMemSvc.h" + +#include <cassert> +#include <iostream> + +namespace Athena_test { + + void segmem_test (ISvcLocator *psvc) { + + SegMemSvc* p_sms(0); + assert((psvc->service("SegMemSvc", p_sms, true)).isSuccess()); + + int* p_int = new ( p_sms->allocate<int>(SegMemSvc::EVENT) ) int(1001); + + // cppcheck doesn't seem to understand placement new. + // cppcheck-suppress uninitdata + assert ( *p_int == 1001 ); + + } + + +} + + +using namespace Athena_test; + +//#include "Reflex/PluginService.h" + +int main() { + // ROOT::Reflex::PluginService::SetDebug(8); + ISvcLocator* pDum; + initGaudi(pDum); //need MessageSvc + segmem_test(pDum); + std::cout << "*** SegMemSvc_test OK ***" << std::endl; + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/StoreClearedIncident_test.cxx b/EDM/athena/Control/StoreGate/test/StoreClearedIncident_test.cxx new file mode 100644 index 00000000..42fb3860 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/StoreClearedIncident_test.cxx @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: StoreClearedIncident_test.cxx,v 1.2 2008-09-10 04:07:14 ssnyder Exp $ +/** + * @file StoreGate/test/StoreClearedIncident_test.cxx + * @author scott snyder + * @date Sep 2008 + * @brief Regression test for StoreClearedIncident. + */ + + +#undef NDEBUG + +#include "StoreGate/StoreClearedIncident.h" +#include <cassert> + + +void test1() +{ + StoreGateSvc* sg = reinterpret_cast<StoreGateSvc*> (0x1234); + StoreClearedIncident i1 (sg, "i1"); + StoreClearedIncident i2 (sg, "i2", "inc"); + assert (i1.store() == sg); + assert (i2.store() == sg); + assert (i1.source() == "i1"); + assert (i2.source() == "i2"); + assert (i1.type() == "StoreCleared"); + assert (i2.type() == "inc"); +} + + +int main() +{ + test1(); +} + diff --git a/EDM/athena/Control/StoreGate/test/StoreGate.xml b/EDM/athena/Control/StoreGate/test/StoreGate.xml new file mode 100644 index 00000000..2a3a1dec --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/StoreGate.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="StoreGateTest" type="makecheck" suite="Examples"> + <package>Control/StoreGate</package> + <timelimit>10</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov, srinir@bnl.gov </mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/EDM/athena/Control/StoreGate/test/UpdateHandleKey_test.cxx b/EDM/athena/Control/StoreGate/test/UpdateHandleKey_test.cxx new file mode 100644 index 00000000..bea17e64 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/UpdateHandleKey_test.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/UpdateHandleKey_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for UpdateHandleKey. + */ + + +#undef NDEBUG +#include "StoreGate/UpdateHandleKey.h" +#include "StoreGate/exceptions.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include <cassert> +#include <iostream> + + +class MyObj {}; +CLASS_DEF (MyObj, 293847295, 1) + + +void test1() +{ + std::cout << "test1\n"; + + SG::UpdateHandleKey<MyObj> k1 ("aaa"); + assert (k1.clid() == 293847295); + assert (k1.key() == "aaa"); + assert (k1.mode() == Gaudi::DataHandle::Updater); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (!k1.storeHandle().isSet()); + assert (k1.initialize().isSuccess()); + assert (k1.storeHandle().isSet()); + + k1 = "aab"; + assert (k1.clid() == 293847295); + assert (k1.key() == "aab"); + assert (k1.mode() == Gaudi::DataHandle::Updater); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (k1.storeHandle().isSet()); + + k1 = "FeeSvc/aac"; + assert (k1.clid() == 293847295); + assert (k1.key() == "aac"); + assert (k1.mode() == Gaudi::DataHandle::Updater); + assert (k1.storeHandle().name() == "FeeSvc"); + assert (!k1.storeHandle().isSet()); + + SG::UpdateHandleKey<MyObj> k2 ("bbb", "FooSvc"); + assert (k2.clid() == 293847295); + assert (k2.key() == "bbb"); + assert (k2.mode() == Gaudi::DataHandle::Updater); + assert (k2.storeHandle().name() == "FooSvc"); + assert (!k2.storeHandle().isSet()); +} + + +int main() +{ + ISvcLocator* pDum; + Athena_test::initGaudi(pDum); //need MessageSvc + + test1(); +} diff --git a/EDM/athena/Control/StoreGate/test/UpdateHandle_test.cxx b/EDM/athena/Control/StoreGate/test/UpdateHandle_test.cxx new file mode 100644 index 00000000..77eae2f2 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/UpdateHandle_test.cxx @@ -0,0 +1,281 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/UpdateHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for UpdateHandle. + */ + + +#undef NDEBUG +#include "StoreGate/UpdateHandle.h" +#include "StoreGate/exceptions.h" +#include "SGTools/TestStore.h" +#include "SGTools/CLASS_DEF.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include "AthenaKernel/errorcheck.h" +#include "CxxUtils/unused.h" +#include <cassert> +#include <iostream> + + +class MyObj +{ +public: + MyObj(int x=0) : x(x) {} + int x; +}; +CLASS_DEF (MyObj, 293847295, 1) +static const CLID MyCLID = 293847295; + + +// Ctors. +void test1() +{ + std::cout << "test1\n"; + SG::UpdateHandle<MyObj> h1; + assert (h1.clid() == MyCLID); + assert (h1.key() == ""); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Updater); + + SG::UpdateHandle<MyObj> h2 ("foo", "FooSvc"); + assert (h2.clid() == MyCLID); + assert (h2.key() == "foo"); + assert (h2.name() == "foo"); + assert (h2.storeHandle().name() == "FooSvc"); + assert (h2.mode() == Gaudi::DataHandle::Updater); + + SG::UpdateHandleKey<MyObj> k3 ("asd"); + assert (k3.initialize().isSuccess()); + SG::UpdateHandle<MyObj> h3 (k3); + assert (h3.clid() == MyCLID); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "StoreGateSvc"); + assert (h3.mode() == Gaudi::DataHandle::Updater); + + { + SG::UpdateHandleKey<MyObj> k4 ("asd", "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::UpdateHandle<MyObj> h4 (k4)); + } + + SGTest::TestStore dumstore; + EventContext ctx5; + ctx5.setProxy (&dumstore); + SG::UpdateHandle<MyObj> h5 (k3, ctx5); + assert (h5.clid() == MyCLID); + assert (h5.key() == "asd"); + assert (h5.storeHandle().name() == "StoreGateSvc"); + assert (h5.mode() == Gaudi::DataHandle::Updater); + assert (h5.store() == "TestStore"); + + SG::UpdateHandleKey<MyObj> k6 ("asd", "OtherStore"); + assert (k6.initialize().isSuccess()); + SG::UpdateHandle<MyObj> h6 (k6, ctx5); + assert (h6.clid() == MyCLID); + assert (h6.key() == "asd"); + assert (h6.storeHandle().name() == "OtherStore"); + assert (h6.mode() == Gaudi::DataHandle::Updater); + assert (h6.store() == "OtherStore" || h6.store() == "OtherStore_Impl"); + + { + SG::UpdateHandleKey<MyObj> k7 ("asd", "BazSvc"); + k7.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::UpdateHandle<MyObj> h7 (k7, ctx5)); + } +} + + +// Copy. +void test2() +{ + std::cout << "test2\n"; + SGTest::TestStore testStore; + + MyObj* fooptr = new MyObj(13); + testStore.record (fooptr, "foo"); + SG::DataProxy* foo_proxy = testStore.proxy (MyCLID, "foo"); + assert (foo_proxy->refCount() == 1); + + MyObj* barptr = new MyObj(14); + testStore.record (barptr, "bar"); + SG::DataProxy* bar_proxy = testStore.proxy (MyCLID, "bar"); + assert (bar_proxy->refCount() == 1); + + SG::UpdateHandle<MyObj> h1 ("foo", "FooSvc"); + assert (h1.store() == "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (h1.store() == "TestStore"); + assert (h1.cptr() == fooptr); + assert (foo_proxy->refCount() == 2); + + SG::UpdateHandle<MyObj> h2 (h1); + assert (h2.key() == "foo"); + assert (h2.store() == "TestStore"); + assert (h2.isInitialized()); + assert (h2.cptr() == fooptr); + assert (foo_proxy->refCount() == 3); + + SG::UpdateHandle<MyObj> h3 (std::move(h2)); + assert (h3.key() == "foo"); + assert (h3.store() == "TestStore"); + assert (h3.isInitialized()); + assert (h3.cptr() == fooptr); + assert (foo_proxy->refCount() == 3); + assert (h2.key() == "foo"); + assert (h2.store() == "TestStore"); + assert (!h2.isInitialized()); + assert (h2.cachedPtr() == nullptr); + + SG::UpdateHandle<MyObj> h4 ("bar", "FooSvc"); + assert (h4.setProxyDict (&testStore).isSuccess()); + assert (h4.cptr() == barptr); + assert (bar_proxy->refCount() == 2); + + h3 = h4; + assert (h3.key() == "bar"); + assert (h3.store() == "TestStore"); + assert (h3.isInitialized()); + assert (h3.cptr() == barptr); + assert (h4.key() == "bar"); + assert (h4.store() == "TestStore"); + assert (h4.isInitialized()); + assert (h4.cptr() == barptr); + + assert (foo_proxy->refCount() == 2); + assert (bar_proxy->refCount() == 3); + + // h1: foo, h2: unint, h3: bar, h4: bar + + h2 = std::move(h3); + assert (h2.key() == "bar"); + assert (h2.store() == "TestStore"); + assert (h2.isInitialized()); + assert (h2.cptr() == barptr); + assert (h3.key() == "bar"); + assert (h3.store() == "TestStore"); + assert (!h3.isInitialized()); + assert (h3.cachedPtr() == nullptr); + + assert (foo_proxy->refCount() == 2); + assert (bar_proxy->refCount() == 3); +} + + +// Retrieve +void test3() +{ + std::cout << "test3\n"; + SGTest::TestStore testStore; + + MyObj* fooptr = new MyObj(23); + testStore.record (fooptr, "foo"); + SG::DataProxy* foo_proxy = testStore.proxy (MyCLID, "foo"); + assert (foo_proxy->refCount() == 1); + + testStore.m_updated.clear(); + SG::UpdateHandle<MyObj> h1 ("foo", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (!h1.isInitialized()); + assert (h1.cachedPtr() == nullptr); + assert (h1.cptr() == fooptr); + assert (h1.isInitialized()); + assert (h1.isValid()); + assert (h1.cachedPtr() == fooptr); + assert (testStore.m_updated.empty()); + assert (h1.ptr() == fooptr); + assert (testStore.m_updated == std::vector<std::string>{"foo"}); + assert (h1->x == 23); + assert ((*h1).x == 23); + assert (foo_proxy->refCount() == 2); + testStore.m_updated.clear(); + h1.reset(false); + assert (foo_proxy->refCount() == 2); + assert (h1.isInitialized()); + assert (h1.cachedPtr() == nullptr); + assert (h1.ptr() == fooptr); + assert (testStore.m_updated == std::vector<std::string>{"foo"}); + + testStore.m_updated.clear(); + SG::UpdateHandle<MyObj> h2 ("foox", "FooSvc"); + assert (h2.setProxyDict (&testStore).isSuccess()); + assert (h2.cachedPtr() == nullptr); + assert (!h2.isInitialized()); + assert (!h2.isValid()); + assert (h2.cachedPtr() == nullptr); + assert (h2.ptr() == nullptr); + assert (h2.cptr() == nullptr); + int UNUSED(xx) = 0; + EXPECT_EXCEPTION (SG::ExcNullUpdateHandle, xx = (*h2).x); + EXPECT_EXCEPTION (SG::ExcNullUpdateHandle, xx = h2->x); + assert (testStore.m_updated.empty()); + + SG::UpdateHandle<MyObj> h3 ("foo", "FooSvc"); + assert (h3.setProxyDict (&testStore).isSuccess()); + testStore.m_failUpdatedObject = true; + EXPECT_EXCEPTION (SG::ExcUpdatedObjectFailure, h3.ptr()); +} + + +// makeHandle +void test4() +{ + std::cout << "test4\n"; + SGTest::TestStore testStore; + + SG::UpdateHandleKey<MyObj> k1 ("asd"); + assert (k1.initialize().isSuccess()); + auto h1 = SG::makeHandle (k1); + assert (h1.clid() == MyCLID); + assert (h1.key() == "asd"); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Updater); + + SG::UpdateHandleKey<MyObj> k2 ("asd", "BazSvc"); + k2.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::makeHandle (k2)); + + SGTest::TestStore dumstore; + EventContext ctx; + ctx.setProxy (&dumstore); + auto h2 = SG::makeHandle (k1, ctx); + assert (h2.clid() == MyCLID); + assert (h2.key() == "asd"); + assert (h2.storeHandle().name() == "StoreGateSvc"); + assert (h2.mode() == Gaudi::DataHandle::Updater); + assert (h2.store() == "TestStore"); + + SG::UpdateHandleKey<MyObj> k3 ("asd", "OtherStore"); + assert (k3.initialize().isSuccess()); + auto h3 = SG::makeHandle (k3, ctx); + assert (h3.clid() == MyCLID); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "OtherStore"); + assert (h3.mode() == Gaudi::DataHandle::Updater); + assert (h3.store() == "OtherStore" || h3.store() == "OtherStore_Impl"); + + SG::UpdateHandleKey<MyObj> k4 ("asd", "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::makeHandle (k4, ctx)); +} + + +int main() +{ + errorcheck::ReportMessage::hideErrorLocus(); + errorcheck::ReportMessage::hideFunctionNames(); + ISvcLocator* svcloc; + Athena_test::initGaudi("VarHandleBase_test.txt", svcloc); //need MessageSvc + + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/VarHandleBase_test.cxx b/EDM/athena/Control/StoreGate/test/VarHandleBase_test.cxx new file mode 100644 index 00000000..2ee146cd --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/VarHandleBase_test.cxx @@ -0,0 +1,555 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/VarHandleBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for VarHandleBase. + */ + + +#undef NDEBUG +#include "StoreGate/VarHandleBase.h" +#include "StoreGate/exceptions.h" +#include "SGTools/TestStore.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/DataProxy.h" +#include "SGTools/TestStore.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include "AthenaKernel/errorcheck.h" +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/ThreadLocalContext.h" +#include <cassert> +#include <iostream> + + +class MyObj {}; +CLASS_DEF (MyObj, 293847295, 1) +class MyObj2 {}; +CLASS_DEF (MyObj2, 293847296, 1) + + +class TestHandle + : public SG::VarHandleBase +{ +public: + using SG::VarHandleBase::VarHandleBase; + + virtual bool isValid() override { return true; } + + using SG::VarHandleBase::setState; + using SG::VarHandleBase::typeless_dataPointer; + using SG::VarHandleBase::typeless_dataPointer_impl; + using SG::VarHandleBase::typeless_cptr; + using SG::VarHandleBase::typeless_ptr; + using SG::VarHandleBase::record_impl; + using SG::VarHandleBase::m_store; + using SG::VarHandleBase::m_proxy; + using SG::VarHandleBase::m_ptr; +}; + + +// Ctors. +void test1() +{ + std::cout << "test1\n"; + + TestHandle h1 (1234, Gaudi::DataHandle::Reader); + assert (h1.clid() == 1234); + assert (h1.key() == ""); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Reader); + assert (h1.m_store == nullptr); + + TestHandle h2 (1234, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h2.clid() == 1234); + assert (h2.key() == "foo"); + assert (h2.name() == "foo"); + assert (h2.storeHandle().name() == "FooSvc"); + assert (h2.mode() == Gaudi::DataHandle::Writer); + + SGTest::TestStore dumstore2; + EventContext ctx3; + ctx3.setProxy (&dumstore2); + Gaudi::Hive::setCurrentContext (ctx3); + + SG::VarHandleKey k3 (1234, "asd", Gaudi::DataHandle::Updater); + k3.initialize().ignore(); + TestHandle h3 (k3); + assert (h3.clid() == 1234); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "StoreGateSvc"); + assert (h3.mode() == Gaudi::DataHandle::Updater); + assert (h3.m_store == &dumstore2); + + { + SG::VarHandleKey k4 (1234, "asd", Gaudi::DataHandle::Updater, "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, TestHandle h4 (k4)); + } + + SGTest::TestStore dumstore; + EventContext ctx5; + ctx5.setProxy (&dumstore); + TestHandle h5 (k3, ctx5); + assert (h5.clid() == 1234); + assert (h5.key() == "asd"); + assert (h5.storeHandle().name() == "StoreGateSvc"); + assert (h5.mode() == Gaudi::DataHandle::Updater); + assert (h5.m_store == &dumstore); + + SG::VarHandleKey k6 (1234, "asd", Gaudi::DataHandle::Updater, + "OtherStore"); + k6.initialize().ignore(); + TestHandle h6 (k6, ctx5); + assert (h6.clid() == 1234); + assert (h6.key() == "asd"); + assert (h6.storeHandle().name() == "OtherStore"); + assert (h6.mode() == Gaudi::DataHandle::Updater); + assert (h6.m_store != &dumstore); + + { + SG::VarHandleKey k7 (1234, "asd", Gaudi::DataHandle::Updater, "BazSvc"); + k7.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, TestHandle h7 (k7, ctx5)); + } +} + + +// Setting, copy, reset +void test2() +{ + std::cout << "test2\n"; + + auto obj = CxxUtils::make_unique<MyObj>(); + MyObj* objptr = obj.get(); + auto taddr = CxxUtils::make_unique<SG::TransientAddress> (293847295, "foo"); + SG::DataProxy* proxy = new SG::DataProxy (SG::asStorable (std::move(obj)), + taddr.release()); + SGTest::TestStore testStore; + proxy->setStore (&testStore); + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h1.store() == "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (h1.store() == "TestStore"); + + h1.setState (proxy); + + assert (proxy->refCount() == 1); + assert (objptr == h1.typeless_dataPointer()); + assert (testStore.m_boundHandles == std::vector<IResetable*>{&h1}); + + { + TestHandle h2 (h1); + assert (h2.clid() == 293847295); + assert (h2.key() == "foo"); + assert (h2.storeHandle().name() == "FooSvc"); + assert (h2.mode() == Gaudi::DataHandle::Writer); + assert (h2.m_store == &testStore); + assert (h2.m_ptr == objptr); + assert (h2.m_proxy == proxy); + assert (proxy->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1, &h2})); + + TestHandle h3 (std::move(h2)); + assert (h3.clid() == 293847295); + assert (h3.key() == "foo"); + assert (h3.storeHandle().name() == "FooSvc"); + assert (h3.mode() == Gaudi::DataHandle::Writer); + assert (h3.m_store == &testStore); + assert (h3.m_ptr == objptr); + assert (h3.m_proxy == proxy); + assert (proxy->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1, &h3})); + + assert (h2.m_store == &testStore); + assert (h2.m_ptr == nullptr); + assert (h2.m_proxy == nullptr); + + h2 = h3; + assert (h2.clid() == 293847295); + assert (h2.key() == "foo"); + assert (h2.storeHandle().name() == "FooSvc"); + assert (h2.mode() == Gaudi::DataHandle::Writer); + assert (h2.m_store == &testStore); + assert (h2.m_ptr == objptr); + assert (h2.m_proxy == proxy); + assert (proxy->refCount() == 3); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1, &h3, &h2})); + + h1.reset(); + assert (h1.clid() == 293847295); + assert (h1.key() == "foo"); + assert (h1.storeHandle().name() == "FooSvc"); + assert (h1.mode() == Gaudi::DataHandle::Writer); + assert (h1.m_store == &testStore); + assert (h1.m_ptr == nullptr); + assert (h1.m_proxy == proxy); + assert (proxy->refCount() == 3); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1, &h3, &h2})); + + h1.reset(true); + assert (h1.clid() == 293847295); + assert (h1.key() == "foo"); + assert (h1.storeHandle().name() == "FooSvc"); + assert (h1.mode() == Gaudi::DataHandle::Writer); + assert (h1.m_store == nullptr); + assert (h1.m_ptr == nullptr); + assert (h1.m_proxy == nullptr); + assert (proxy->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h3, &h2})); + + h1 = std::move(h3); + assert (h1.clid() == 293847295); + assert (h1.key() == "foo"); + assert (h1.storeHandle().name() == "FooSvc"); + assert (h1.mode() == Gaudi::DataHandle::Writer); + assert (h1.m_store == &testStore); + assert (h1.m_ptr == objptr); + assert (h1.m_proxy == proxy); + assert (proxy->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h2, &h1})); + + assert (h3.m_store == &testStore); + assert (h3.m_ptr == nullptr); + assert (h3.m_proxy == nullptr); + } + // h2, h3 went away + assert (proxy->refCount() == 1); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1})); + + // Test a !resetOnly proxy. + auto obj5 = CxxUtils::make_unique<MyObj>(); + //MyObj* objptr5 = obj5.get(); + auto taddr5 = CxxUtils::make_unique<SG::TransientAddress> (293847295, "foo"); + SG::DataProxy* proxy5 = new SG::DataProxy (SG::asStorable (std::move(obj5)), + taddr5.release(), + false, false); + proxy5->setStore (&testStore); + proxy->addRef(); + h1.setState (proxy5); + assert (proxy->refCount() == 1); + assert (proxy5->refCount() == 1); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1})); + + proxy5->addRef(); + h1.reset(); + assert (h1.m_proxy == nullptr); + assert (proxy5->refCount() == 1); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{})); + + proxy->release(); + proxy5->release(); +} + + +// isPresent, isInitialized, isSet, isConst +void test3() +{ + std::cout << "test3\n"; + + SGTest::TestStore store; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + assert (!h1.isPresent()); + + assert (h1.setProxyDict (&store).isSuccess()); + assert (!h1.isPresent()); + + store.record (new MyObj, "foo"); + assert (h1.isPresent()); + + store.proxy(293847295, "foo")->reset(); + assert (!h1.isPresent()); + + assert (!h1.isInitialized()); + assert (h1.setState (store.proxy(293847295, "foo")).isFailure()); + assert (!h1.isInitialized()); + assert (!h1.isSet()); + assert (!h1.isConst()); + + store.record (new MyObj, "bar"); + assert (h1.setState (store.proxy(293847295, "bar")).isSuccess()); + assert (h1.isInitialized()); + assert (h1.isSet()); + assert (!h1.isConst()); + + store.proxy(293847295, "bar")->setConst(); + assert (h1.isConst()); +} + + +// initialize(), setStore() +void test4() +{ + std::cout << "test4\n"; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h1.initialize().isFailure()); + + SGTest::TestStore store; + assert (h1.setProxyDict (&store).isSuccess()); + assert (h1.initialize().isSuccess()); // ok because it's a writer. + + TestHandle h2 (293847295, "foo", Gaudi::DataHandle::Reader, "FooSvc"); + assert (h2.setProxyDict (&store).isSuccess()); + assert (h2.initialize().isFailure()); + store.record (new MyObj, "foo"); + assert (h2.setState().isSuccess()); + + assert (h2.isInitialized()); + assert (h2.setProxyDict (&store).isSuccess()); + assert (!h2.isInitialized()); + + assert (h2.setState().isSuccess()); + assert (h2.isInitialized()); + h2.reset(); + assert (h2.isInitialized()); + h2.finalReset(); + assert (!h2.isInitialized()); + assert (h2.m_store == 0); +} + + +// setConst +void test5() +{ + std::cout << "test5\n"; + SGTest::TestStore testStore; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + auto obj = CxxUtils::make_unique<MyObj>(); + //MyObj* objptr = obj.get(); + auto taddr = CxxUtils::make_unique<SG::TransientAddress> (293847295, "foo"); + SG::DataProxy* proxy = new SG::DataProxy (SG::asStorable (std::move(obj)), + taddr.release()); + assert (h1.setConst().isFailure()); + proxy->setStore (&testStore); + + assert (h1.setState (proxy).isSuccess()); + assert (h1.isInitialized()); + assert (!h1.isConst()); + assert (!proxy->isConst()); + + assert (h1.setConst().isSuccess()); + assert (h1.isConst()); + assert (proxy->isConst()); +} + + +// setState +void test6() +{ + std::cout << "test6\n"; + SGTest::TestStore testStore; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + + SG::DataProxy* proxy1 = nullptr; + assert (h1.setState(proxy1).isFailure()); + + auto taddr1 = CxxUtils::make_unique<SG::TransientAddress> (293847295, "foo"); + proxy1 = new SG::DataProxy (taddr1.release(), nullptr); + proxy1->addRef(); + proxy1->setStore (&testStore); + assert (proxy1->refCount() == 1); + assert (h1.setState(proxy1).isFailure()); + assert (proxy1->refCount() == 1); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{})); + + auto obj1 = CxxUtils::make_unique<MyObj>(); + proxy1->setObject (SG::asStorable (std::move(obj1))); + assert (h1.setState(proxy1).isSuccess()); + assert (proxy1->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1})); + assert (h1.m_proxy == proxy1); + + assert (h1.setState(proxy1).isSuccess()); + assert (proxy1->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1})); + assert (h1.m_proxy == proxy1); + + auto taddr2 = CxxUtils::make_unique<SG::TransientAddress> (293847295, "foo"); + SG::DataProxy* proxy2 = new SG::DataProxy (taddr2.release(), nullptr); + proxy2->addRef(); + proxy2->setStore (&testStore); + assert (proxy2->refCount() == 1); + auto obj2 = CxxUtils::make_unique<MyObj>(); + proxy2->setObject (SG::asStorable (std::move(obj2))); + + assert (h1.setState(proxy2).isSuccess()); + assert (proxy1->refCount() == 1); + assert (proxy2->refCount() == 2); + assert ((testStore.m_boundHandles == std::vector<IResetable*>{&h1})); + assert (h1.m_proxy == proxy2); + + proxy1->release(); + proxy2->release(); + + assert (h1.setState (nullptr, "bar").isFailure()); + assert (h1.setState (&testStore, "bar").isFailure()); + testStore.record (new MyObj, "bar"); + assert (h1.setState (&testStore, "bar").isSuccess()); + assert (h1.isInitialized()); + assert (h1.m_proxy->transientAddress()->name() == "bar"); +} + + +// record_impl +void test7() +{ + std::cout << "test7\n"; + + SGTest::TestStore testStore; + + std::unique_ptr<MyObj> obj; + MyObj* objptr = nullptr; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + obj = CxxUtils::make_unique<MyObj>(); + objptr = obj.get(); + assert (h1.record_impl (std::unique_ptr<DataObject>(SG::asStorable(std::move(obj))), + objptr, + true, false).isFailure()); + + assert (h1.setProxyDict (&testStore).isSuccess()); + obj = CxxUtils::make_unique<MyObj>(); + objptr = obj.get(); + assert (h1.record_impl (std::unique_ptr<DataObject>(SG::asStorable(std::move(obj))), + objptr, + true, false).isSuccess()); + MyObj* fooptr = objptr; + assert (h1.m_ptr == fooptr); + + TestHandle h2 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h2.setProxyDict (&testStore).isSuccess()); + obj = CxxUtils::make_unique<MyObj>(); + objptr = obj.get(); + assert (h2.record_impl (std::unique_ptr<DataObject>(SG::asStorable(std::move(obj))), + objptr, + true, false).isFailure()); + assert (!h2.isInitialized()); + assert (h2.m_ptr == nullptr); + + + obj = CxxUtils::make_unique<MyObj>(); + objptr = obj.get(); + assert (h2.record_impl (std::unique_ptr<DataObject>(SG::asStorable(std::move(obj))), + objptr, + true, true).isSuccess()); + assert (h2.isInitialized()); + assert (h2.m_ptr == fooptr); + assert (!h2.isConst()); + + obj = CxxUtils::make_unique<MyObj>(); + objptr = obj.get(); + assert (h2.record_impl (std::unique_ptr<DataObject>(SG::asStorable(std::move(obj))), + objptr, + false, true).isSuccess()); + assert (h2.isInitialized()); + assert (h2.m_ptr == fooptr); + assert (h2.isConst()); + + TestHandle h3 (293847295, "", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h3.setProxyDict (&testStore).isSuccess()); + obj = CxxUtils::make_unique<MyObj>(); + objptr = obj.get(); + assert (h3.record_impl (std::unique_ptr<DataObject>(SG::asStorable(std::move(obj))), + objptr, + true, false).isFailure()); +} + + +// typeless_dataPointer_impl, etc +void test8() +{ + std::cout << "test8\n"; + SGTest::TestStore testStore; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + + auto obj = CxxUtils::make_unique<MyObj>(); + assert (h1.m_ptr == nullptr); + h1.m_ptr = obj.get(); + assert (h1.typeless_dataPointer_impl(false) == obj.get()); + h1.m_ptr = nullptr; + + assert (h1.typeless_dataPointer_impl(false) == nullptr); + assert (h1.typeless_dataPointer_impl(true) == nullptr); + + testStore.record (obj.release(), "foo"); + assert (h1.initialize().isSuccess()); + testStore.proxy(293847295, "foo")->reset(); + + assert (h1.typeless_dataPointer_impl(false) == nullptr); + assert (h1.typeless_dataPointer_impl(true) == nullptr); + + TestHandle h2 (293847295, "bar", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h2.setProxyDict (&testStore).isSuccess()); + obj = CxxUtils::make_unique<MyObj>(); + MyObj* objptr = obj.get(); + testStore.record (obj.release(), "bar"); + + assert (h2.typeless_dataPointer_impl(false) == objptr); + + auto obj2 = CxxUtils::make_unique<MyObj2>(); + MyObj2* obj2ptr = obj2.get(); + testStore.record (obj2.release(), "fee"); + + SG::sgkey_t sgkey = testStore.stringToKey ("fee", 293847295); + testStore.m_kmap[sgkey] = testStore.proxy (293847296, "fee"); + + TestHandle h3 (293847295, "fee", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h3.setProxyDict (&testStore).isSuccess()); + assert (h3.typeless_dataPointer_impl(false) == nullptr); + assert (h3.typeless_dataPointer_impl(true) == nullptr); + + testStore.proxy (293847296, "fee")->transientAddress()->setTransientID(293847295); + assert (h3.typeless_dataPointer_impl(false) == obj2ptr); + assert (h3.typeless_dataPointer(false) == obj2ptr); + assert (h3.typeless_cptr() == obj2ptr); + + assert (h3.typeless_ptr(false) == obj2ptr); + testStore.proxy (293847296, "fee")->setConst(); + EXPECT_EXCEPTION (SG::ExcConstObject, h3.typeless_ptr(false)); +} + + +// free functions +void test9() +{ + std::cout << "test9\n"; + + TestHandle h1 (293847295, "foo", Gaudi::DataHandle::Writer, "FooSvc"); + std::cout << h1 << "\n"; + + assert (h1 == h1); + TestHandle h2 (293847295, "foe", Gaudi::DataHandle::Writer, "FooSvc"); + assert (h1 != h2); +} + + +int main() +{ + errorcheck::ReportMessage::hideErrorLocus(); + ISvcLocator* svcloc; + Athena_test::initGaudi("VarHandleBase_test.txt", svcloc); //need MessageSvc + + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + return 0; +} + diff --git a/EDM/athena/Control/StoreGate/test/VarHandleKeyProperty_test.cxx b/EDM/athena/Control/StoreGate/test/VarHandleKeyProperty_test.cxx new file mode 100644 index 00000000..2cbe0607 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/VarHandleKeyProperty_test.cxx @@ -0,0 +1,237 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/VarHandleKeyProperty_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for VarHandleKeyProperty. + */ + + +#undef NDEBUG +#include "StoreGate/VarHandleKeyProperty.h" +#include "StoreGate/exceptions.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include "GaudiKernel/PropertyMgr.h" +#include "GaudiKernel/IProperty.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/ServiceHandle.h" +#include <cassert> +#include <iostream> +#include <sstream> + + +class MyObj {}; +CLASS_DEF (MyObj, 293847295, 1) + + +void test1() +{ + std::cout << "test1\n"; + + SG::VarHandleKey k (1234, "", Gaudi::DataHandle::Reader); + assert (Gaudi::Parsers::parse (k, "aaa").isSuccess()); + assert (k.key() == "aaa"); + assert (k.storeHandle().name() == "StoreGateSvc"); + + std::ostringstream ss; + Gaudi::Utils::toStream (k, ss); + assert (ss.str() == "'StoreGateSvc/aaa'"); + + assert (Gaudi::Parsers::parse (k, "FooSvc/bbb").isSuccess()); + assert (k.key() == "bbb"); + assert (k.storeHandle().name() == "FooSvc"); + + assert (Gaudi::Parsers::parse (k, "BarSvc/c/bbb").isFailure()); +} + + +void test2() +{ + std::cout << "test2\n"; + + SG::VarHandleKey k (1234, "", Gaudi::DataHandle::Reader); + SG::VarHandleKeyProperty p ("prop", k); + + assert (p.fromString ("aaa").isSuccess()); + assert (k.key() == "aaa"); + assert (k.storeHandle().name() == "StoreGateSvc"); + + assert (p.fromString ("FooSvc/bbb").isSuccess()); + assert (k.key() == "bbb"); + assert (k.storeHandle().name() == "FooSvc"); + + assert (p.fromString ("FooSvc/c/bbb").isFailure()); + + SG::VarHandleKey k2 (1234, "ccc", Gaudi::DataHandle::Reader, "BarSvc"); + p.setValue (k2); + assert (k.clid() == 1234); + assert (k.key() == "ccc"); + assert (k.storeHandle().name() == "BarSvc"); + + assert (p.toString() == "'BarSvc/ccc'"); + std::ostringstream ss; + p.toStream (ss); + assert (ss.str() == "'BarSvc/ccc'"); + + std::unique_ptr<SG::VarHandleKeyProperty> p2 (p.clone()); + assert (p2->value().clid() == 1234); + assert (p2->value().key() == "ccc"); + assert (p2->value().storeHandle().name() == "BarSvc"); + + SG::VarHandleKey k3 (1234, "ddd", Gaudi::DataHandle::Reader, "BazSvc"); + *p2 = k3; + assert (p2->value().clid() == 1234); + assert (p2->value().key() == "ddd"); + assert (p2->value().storeHandle().name() == "BazSvc"); + assert (k.clid() == 1234); + assert (k.key() == "ddd"); + assert (k.storeHandle().name() == "BazSvc"); + + SG::VarHandleKey k4 (1234, "", Gaudi::DataHandle::Reader); + SG::VarHandleKeyProperty p4 ("prop4", k4); + assert (p.load (p4)); + assert (k4.clid() == 1234); + assert (k4.key() == "ddd"); + assert (k4.storeHandle().name() == "BazSvc"); + + p.setValue (k2); + assert (p4.assign (p)); + assert (k4.clid() == 1234); + assert (k4.key() == "ccc"); + assert (k4.storeHandle().name() == "BarSvc"); +} + + +void test3() +{ + std::cout << "test3\n"; + + SG::VarHandleKey k1 (1234, "", Gaudi::DataHandle::Reader); + SimplePropertyRef<SG::VarHandleKey > p1 ("p1", k1); + assert (p1.fromString ("FeeSvc/aaa").isSuccess()); + assert (k1.clid() == 1234); + assert (k1.key() == "aaa"); + assert (k1.storeHandle().name() == "FeeSvc"); + + SG::ReadHandleKey<MyObj> k2; + SimplePropertyRef<SG::ReadHandleKey<MyObj> > p2 ("p2", k2); + assert (p2.fromString ("FooSvc/bbb").isSuccess()); + assert (k2.clid() == 293847295); + assert (k2.key() == "bbb"); + assert (k2.storeHandle().name() == "FooSvc"); + + SG::WriteHandleKey<MyObj> k3; + SimplePropertyRef<SG::WriteHandleKey<MyObj> > p3 ("p3", k3); + assert (p3.fromString ("BarSvc/ccc").isSuccess()); + assert (k3.clid() == 293847295); + assert (k3.key() == "ccc"); + assert (k3.storeHandle().name() == "BarSvc"); + + SG::UpdateHandleKey<MyObj> k4; + SimplePropertyRef<SG::UpdateHandleKey<MyObj> > p4 ("p4", k4); + assert (p4.fromString ("BazSvc/ddd").isSuccess()); + assert (k4.clid() == 293847295); + assert (k4.key() == "ddd"); + assert (k4.storeHandle().name() == "BazSvc"); +} + + +class PropTest + : public IProperty +{ +public: + virtual unsigned long addRef() override { std::abort(); } + virtual unsigned long release() override { std::abort(); } + virtual unsigned long refCount() const override { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override + { std::abort(); } + + virtual StatusCode setProperty( const Property& p ) override + { return mgr.setProperty(p); } + virtual StatusCode setProperty( const std::string& s ) override + { return mgr.setProperty(s); } + virtual StatusCode setProperty( const std::string& n, const std::string& v ) override + { return mgr.setProperty(n, v); } + virtual StatusCode getProperty( Property* p ) const override + { return mgr.getProperty (p); } + virtual const Property& getProperty( const std::string& name) const override + { return mgr.getProperty (name); } + virtual StatusCode getProperty( const std::string& n, std::string& v ) const override + { return mgr.getProperty (n, v); } + virtual const std::vector<Property*>& getProperties( ) const override + { return mgr.getProperties(); } + virtual bool hasProperty(const std::string& name) const override + { return mgr.hasProperty(name); } + + PropertyMgr mgr; +}; + + +void test4() +{ + std::cout << "test4\n"; + + PropTest ptest; + + SG::ReadHandleKey<MyObj> k1; + ptest.mgr.declareProperty ("k1", k1); + SG::WriteHandleKey<MyObj> k2; + ptest.mgr.declareProperty ("k2", k2); + SG::UpdateHandleKey<MyObj> k3; + ptest.mgr.declareProperty ("k3", k3); + SG::VarHandleKey k4 (1234, "", Gaudi::DataHandle::Reader); + ptest.mgr.declareProperty ("k4", k4); + + ServiceHandle<IJobOptionsSvc> jo ("JobOptionsSvc", "test"); + assert (jo.retrieve().isSuccess()); + assert (jo->setMyProperties ("test4", &ptest).isSuccess()); + + assert (k1.clid() == 293847295); + assert (k1.key() == "aaa"); + assert (k1.storeHandle().name() == "FooSvc"); + + assert (k2.clid() == 293847295); + assert (k2.key() == "bbb"); + assert (k2.storeHandle().name() == "StoreGateSvc"); + + assert (k3.clid() == 293847295); + assert (k3.key() == "ccc"); + assert (k3.storeHandle().name() == "BarSvc"); + + assert (k4.clid() == 1234); + assert (k4.key() == "ddd"); + assert (k4.storeHandle().name() == "BazSvc"); +} + + +void test5() +{ + std::cout << "test5\n"; + + PropTest ptest; + + SG::ReadHandleKey<MyObj> k1; + ptest.mgr.declareProperty ("k1", k1); + + ServiceHandle<IJobOptionsSvc> jo ("JobOptionsSvc", "test"); + assert (jo.retrieve().isSuccess()); + assert (jo->setMyProperties ("test5", &ptest).isFailure()); +} + + +int main() +{ + ISvcLocator* pDum; + Athena_test::initGaudi("VarHandleKeyProperty_test.txt", pDum); + + test1(); + test2(); + test3(); + test4(); + test5(); +} diff --git a/EDM/athena/Control/StoreGate/test/VarHandleKey_test.cxx b/EDM/athena/Control/StoreGate/test/VarHandleKey_test.cxx new file mode 100644 index 00000000..430d434a --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/VarHandleKey_test.cxx @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/VarHandleKey_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for VarHandleKey. + */ + + +#undef NDEBUG +#include "StoreGate/VarHandleKey.h" +#include "StoreGate/exceptions.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include <cassert> +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + + SG::VarHandleKey k1 (1234, "aaa", Gaudi::DataHandle::Reader); + assert (k1.clid() == 1234); + assert (k1.key() == "aaa"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (!k1.storeHandle().isSet()); + assert (k1.initialize().isSuccess()); + assert (k1.storeHandle().isSet()); + + k1 = "aab"; + assert (k1.clid() == 1234); + assert (k1.key() == "aab"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (k1.storeHandle().isSet()); + + assert (k1.assign ("FeeSvc/aac").isSuccess()); + assert (k1.clid() == 1234); + assert (k1.key() == "aac"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "FeeSvc"); + assert (!k1.storeHandle().isSet()); + + assert (k1.assign ("/Feedir/aac").isSuccess()); + assert (k1.clid() == 1234); + assert (k1.key() == "/Feedir/aac"); + assert (k1.mode() == Gaudi::DataHandle::Reader); + assert (k1.storeHandle().name() == "FeeSvc"); + assert (!k1.storeHandle().isSet()); + + assert (k1.assign ("FeeSvc/foo/aac").isFailure()); + EXPECT_EXCEPTION (SG::ExcBadHandleKey, + k1 = "FeeSvc/foo/aac"); + + SG::VarHandleKey k2 (1235, "bbb", Gaudi::DataHandle::Writer, "FooSvc"); + assert (k2.clid() == 1235); + assert (k2.key() == "bbb"); + assert (k2.mode() == Gaudi::DataHandle::Writer); + assert (k2.storeHandle().name() == "FooSvc"); + assert (!k2.storeHandle().isSet()); + assert (k2.initialize().isFailure()); + assert (!k2.storeHandle().isSet()); + + SG::VarHandleKey k3 (1236, "BarSvc/ccc", Gaudi::DataHandle::Updater, "FooSvc"); + assert (k3.clid() == 1236); + assert (k3.key() == "ccc"); + assert (k3.mode() == Gaudi::DataHandle::Updater); + assert (k3.storeHandle().name() == "BarSvc"); + assert (!k3.storeHandle().isSet()); + + SG::VarHandleKey k4 (1237, "", Gaudi::DataHandle::Updater); + assert (k4.clid() == 1237); + assert (k4.key() == ""); + assert (k4.mode() == Gaudi::DataHandle::Updater); + assert (k4.storeHandle().name() == "StoreGateSvc"); + assert (!k4.storeHandle().isSet()); + assert (k4.initialize().isFailure()); + + EXPECT_EXCEPTION (SG::ExcBadHandleKey, + SG::VarHandleKey (1237, "a/b/c", Gaudi::DataHandle::Updater)); +} + + +int main() +{ + ISvcLocator* pDum; + Athena_test::initGaudi(pDum); //need MessageSvc + + test1(); +} diff --git a/EDM/athena/Control/StoreGate/test/VarHandleProperty_test.cxx b/EDM/athena/Control/StoreGate/test/VarHandleProperty_test.cxx new file mode 100644 index 00000000..1fbd9ffd --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/VarHandleProperty_test.cxx @@ -0,0 +1,106 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/VarHandleProperty_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for VarHandlerPoperty specializations. + */ + + +#undef NDEBUG +#include "StoreGate/VarHandleProperty.h" +#include "StoreGate/exceptions.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include "GaudiKernel/PropertyMgr.h" +#include "GaudiKernel/IProperty.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/ServiceHandle.h" +#include <cassert> +#include <iostream> +#include <sstream> + + +class MyObj {}; +CLASS_DEF (MyObj, 293847295, 1) + + +class PropTest + : public IProperty +{ +public: + virtual unsigned long addRef() override { std::abort(); } + virtual unsigned long release() override { std::abort(); } + virtual unsigned long refCount() const override { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override + { std::abort(); } + + virtual StatusCode setProperty( const Property& p ) override + { return mgr.setProperty(p); } + virtual StatusCode setProperty( const std::string& s ) override + { return mgr.setProperty(s); } + virtual StatusCode setProperty( const std::string& n, const std::string& v ) override + { return mgr.setProperty(n, v); } + virtual StatusCode getProperty( Property* p ) const override + { return mgr.getProperty (p); } + virtual const Property& getProperty( const std::string& name) const override + { return mgr.getProperty (name); } + virtual StatusCode getProperty( const std::string& n, std::string& v ) const override + { return mgr.getProperty (n, v); } + virtual const std::vector<Property*>& getProperties( ) const override + { return mgr.getProperties(); } + virtual bool hasProperty(const std::string& name) const override + { return mgr.hasProperty(name); } + + PropertyMgr mgr; +}; + + +void test1() +{ + std::cout << "test1\n"; + + PropTest ptest; + + SG::ReadHandle<MyObj> k1; + ptest.mgr.declareProperty ("k1", k1); + SG::WriteHandle<MyObj> k2; + ptest.mgr.declareProperty ("k2", k2); + SG::UpdateHandle<MyObj> k3; + ptest.mgr.declareProperty ("k3", k3); + //SG::VarHandleBase k4 (1234, "", Gaudi::DataHandle::Reader); + //ptest.mgr.declareProperty ("k4", k4); + + ServiceHandle<IJobOptionsSvc> jo ("JobOptionsSvc", "test"); + assert (jo.retrieve().isSuccess()); + assert (jo->setMyProperties ("test1", &ptest).isSuccess()); + + assert (k1.clid() == 293847295); + assert (k1.key() == "aaa"); + assert (k1.storeHandle().name() == "FooSvc"); + + assert (k2.clid() == 293847295); + assert (k2.key() == "bbb"); + assert (k2.storeHandle().name() == "StoreGateSvc"); + + assert (k3.clid() == 293847295); + assert (k3.key() == "ccc"); + assert (k3.storeHandle().name() == "BarSvc"); + + //assert (k4.clid() == 1234); + //assert (k4.key() == "ddd"); + //assert (k4.storeHandle().name() == "BazSvc"); +} + + +int main() +{ + ISvcLocator* pDum; + Athena_test::initGaudi("VarHandleProperty_test.txt", pDum); + + test1(); +} diff --git a/EDM/athena/Control/StoreGate/test/VarHandles_test.cxx b/EDM/athena/Control/StoreGate/test/VarHandles_test.cxx new file mode 100644 index 00000000..c6d62486 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/VarHandles_test.cxx @@ -0,0 +1,316 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TestTools/initGaudi.h" +#include "TestTools/SGassert.h" +#include "StoreGate/ReadHandle.h" +#include "StoreGate/WriteHandle.h" +#include "StoreGate/UpdateHandle.h" +#include "StoreGate/StoreGateSvc.h" +#include "SGTools/TransientAddress.h" +#include "SGTools/DataProxy.h" +#include "SGTools/TestStore.h" +#include "CxxUtils/make_unique.h" + +#include <cassert> +#include <iostream> +#include <list> + +using SG::ReadHandle; +using SG::WriteHandle; +using SG::UpdateHandle; +using SG::DataProxy; +using SG::TransientAddress; +using std::list; +using std::cerr; +using std::cout; +using std::endl; + + +struct MyDataObj { + MyDataObj(int i=3, double f=3.14) : m_i(i), m_f(f) {} + int m_i; + double m_f; + int i() const { return m_i; } + double f() const { return m_f; } +}; +bool operator==(const MyDataObj& lhs, const MyDataObj& rhs) { + return ((lhs.m_i==rhs.m_i) && (lhs.m_f==rhs.m_f)); +} + +typedef std::list<int> IntList; +/** @file DataHandle_test.cxx unit test for DataHandle + * @author ATLAS Collaboration + * $Id: VarHandles_test.cxx 757253 2016-06-23 13:01:18Z ssnyder $ + ***************************************************************************/ + +#include "SGTools/CLASS_DEF.h" +CLASS_DEF(IntList, 8001, 3) +CLASS_DEF(MyDataObj, 8000, 1) + +namespace Athena_test { + template<class BYVALUE> + BYVALUE sillyFunc(BYVALUE in) { + return in; + } + + void varHandleTest() { + //empty handles + ReadHandle<MyDataObj> empty; + ReadHandle<MyDataObj> copy(empty); + assert(copy==empty); + + //init with an empty proxy + ReadHandle<IntList> emptyProxy("foo"); + assert(!emptyProxy.isInitialized()); + assert(emptyProxy.setState(new DataProxy()).isFailure()); //we are friends + assert(!emptyProxy.isInitialized()); + assert(!emptyProxy.isSet()); + assert(!emptyProxy.isConst()); + assert(emptyProxy.cachedPtr() == nullptr); + SGASSERTERROR(emptyProxy.isValid()); + + //init with a valid proxy + DataProxy* pMyProxy(new DataProxy(StoreGateSvc::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo"))); + pMyProxy->addRef(); + ReadHandle<MyDataObj> hMyR; + assert(!hMyR.isInitialized()); + assert(hMyR.setState(pMyProxy).isSuccess()); + assert(hMyR.isInitialized()); + assert(hMyR.isSet()); + assert(!hMyR.isConst()); + assert(hMyR.isValid()); + assert(hMyR->m_i==3); + assert(*hMyR.cachedPtr() == 3); + assert(hMyR==empty); //this may be counterintutive but handles pointing to the same store/clid/key are == + + UpdateHandle<MyDataObj> hMyU; + assert(!hMyU.isInitialized()); + assert(hMyU.cachedPtr() == nullptr); + assert(hMyU.setState(pMyProxy).isSuccess()); + assert(hMyU.isInitialized()); + assert(hMyU.isSet()); + assert(!hMyU.isConst()); + assert(hMyU.isValid()); + assert(hMyU->m_i==3); + assert(*hMyU.cachedPtr() == 3); + assert(hMyU!=empty); + + WriteHandle<MyDataObj> hMy ("hMy"); + assert(!hMy.isInitialized()); + assert(hMy.cachedPtr() == nullptr); + hMy.setProxyDict (&SGTest::store); + hMy = CxxUtils::make_unique<MyDataObj>(4); + //assert(hMy.setState(pMyProxy).isSuccess()); + assert(hMy.isInitialized()); + assert(hMy.isSet()); + assert(!hMy.isConst()); + assert(hMy.isValid()); + assert(hMy->m_i==4); + assert(*hMy.cachedPtr() == 4); + assert(hMy!=empty); + + //copy it and test + WriteHandle<MyDataObj> hMyCopy(hMy); + assert(hMyCopy.isInitialized()); + assert(hMyCopy.isSet()); + assert(*hMyCopy.cachedPtr() == 4); + assert(!hMyCopy.isConst()); + assert(hMyCopy.isValid()); + assert(hMyCopy->m_i==4); + assert(hMy==hMyCopy); + + //assign it and test + WriteHandle<MyDataObj> hMyCopy2; + hMyCopy2 = hMyCopy; + assert(hMyCopy2.isValid()); + assert(hMyCopy2->m_i==4); + assert(hMy==hMyCopy2); + + //move it and test + WriteHandle<MyDataObj> hMove(std::move(hMyCopy2)); + assert(hMove.isValid()); + assert(hMove->m_i==4); + assert(hMy==hMove); + + //assign from a temp and test + { + ReadHandle<MyDataObj> hMove2; + hMove2 = sillyFunc(std::move(hMyR)); + assert(hMove2.isValid()); + assert(hMove2->m_i==3); + assert(hMyR==hMove2); + } + { + WriteHandle<MyDataObj> hMove21; + hMove21 = sillyFunc(std::move(hMyCopy)); + assert(hMove21.isValid()); + assert(hMove21->m_i==4); + assert(hMy==hMove21); + } + { + UpdateHandle<MyDataObj> hMove22; + hMove22 = sillyFunc(std::move(hMyU)); + assert(hMove22.isValid()); + assert(hMove22->m_i==3); + assert(hMyU==hMove22); + } + + //init with another copy of the same object and compare + DataProxy* pMyProxy2(new DataProxy(StoreGateSvc::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo2"))); + UpdateHandle<MyDataObj> hMy2; + assert(!hMy2.isInitialized()); + assert(hMy2.setState(pMyProxy2).isSuccess()); + assert(hMy2.isInitialized()); + assert(hMy2.isSet()); + assert(!hMy2.isConst()); + assert(hMy2.isValid()); + assert(hMy2->m_i==3); + assert(hMy!=hMy2); + //assert(*hMy==*hMy2); + + const bool CONSTPROXY(true); + DataProxy* pMyProxy3(new DataProxy(StoreGateSvc::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo3"), CONSTPROXY)); + ReadHandle<MyDataObj> hMy3; + assert(hMy3.setState(pMyProxy3).isSuccess()); + assert(hMy3.isConst()); + assert(hMy3.isValid()); + assert(hMy3->m_i==3); +#ifdef CHECKCOMPILER + assert(hMy3->f()==3.14); +#endif + assert(hMy!=hMy3); + //assert(*hMy==*hMy3); + + + //init with another proxy referring to the same object and compare + WriteHandle<MyDataObj> hMySameProxy; + assert(hMySameProxy.setState(pMyProxy).isSuccess()); + assert(!hMySameProxy.isValid()); + //assert(hMySameProxy->m_i==3); + //assert(hMy==hMySameProxy); + //assert(*hMy==*hMySameProxy); + cout << "*** VarHandles_test static handle test OK ***" <<endl; + return; + } + + void resetableTest() { + const bool CONSTPROXY(true); + const bool RESETONLY(true); + + DataProxy* pNR(new DataProxy(StoreGateSvc::asStorable(new MyDataObj(33)), + new TransientAddress(CLID(8000), "noReset"), + CONSTPROXY, !RESETONLY) ); + ReadHandle<MyDataObj> hNR ("noReset"); + assert(hNR.setState(pNR).isSuccess()); + assert(hNR.isValid()); + assert(33 == hNR->i()); + hNR.reset(true); + assert(!hNR.isInitialized()); + SGASSERTERROR(hNR.isValid()); + + pNR = new DataProxy(StoreGateSvc::asStorable(new MyDataObj(33)), + new TransientAddress(CLID(8000), "noReset"), + CONSTPROXY, !RESETONLY); + assert(hNR.setState(pNR).isSuccess()); + assert(hNR.isValid()); + assert(33 == hNR->i()); + hNR.reset(false); + assert(!hNR.isInitialized()); + SGASSERTERROR(hNR.isValid()); + + //now with the RESETONLY + DataProxy* pRO(new DataProxy(StoreGateSvc::asStorable(new MyDataObj(44)), + new TransientAddress(CLID(8000), "noReset"), + !CONSTPROXY, RESETONLY) ); + pRO->addRef(); + UpdateHandle<MyDataObj> hRO ("noReset"); + assert(hRO.setState(pRO).isSuccess()); + assert(hRO.isValid()); + assert(44 == hRO->i()); + hRO.reset(true); + assert(!hRO.isInitialized()); + assert(hRO.setState(pRO).isSuccess()); + assert(hRO.isValid()); + assert(44 == hRO->i()); + hRO.reset(false); + assert(hRO.isInitialized()); + + assert(hRO.setState(pRO).isSuccess()); + assert(hRO.isValid()); + assert(44 == hRO->i()); + delete pRO; + assert(!hRO.isInitialized()); + assert(!hRO.isValid()); + //kaboom assert(44 == hRO->i()); + + std::cout << "*** VarHandles_test resetable test OK ***" <<std::endl; + return; + } + + void refCountTest () { + std::vector<DataProxy*> vp; + for (int i=0; i < 4; i++) { + DataProxy* dp = new DataProxy(StoreGateSvc::asStorable(new MyDataObj), + new TransientAddress(CLID(8000), "foo")); + vp.push_back (dp); + } + for (unsigned int i=0; i < vp.size(); ++i) { + //bump up the ref count to check the effects of handle destructor + assert (1 == vp[i]->addRef()); + } + + { + WriteHandle<MyDataObj> dh; + assert(dh.setState(vp[0]).isSuccess()); + assert (vp[0]->refCount() == 2); + assert(dh.setState(vp[0]).isSuccess()); + assert (vp[0]->refCount() == 2); + WriteHandle<MyDataObj> dh2 (dh); + assert (vp[0]->refCount() == 3); + WriteHandle<MyDataObj> dh3; + dh3=dh2; + assert (vp[0]->refCount() == 4); + + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 1); + + dh2 = dh3; + assert (vp[0]->refCount() == 4); + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 1); + + dh2 = dh; + assert (vp[0]->refCount() == 4); + for (int i=1; i < 4; i++) + assert (vp[i]->refCount() == 1); + } //invoke handles destructor + + for (unsigned int i=0; i < vp.size(); ++i) { + assert (0==vp[i]->release()); + } + + std::cout << "*** VarHandles_test ref count test OK ***" <<std::endl; + return; + } +} + +using namespace Athena_test; + +//#include "Reflex/PluginService.h" + +int main() { + SGTest::initTestStore(); + ISvcLocator* pDum; + initGaudi(pDum); //need MessageSvc + cout << "*** VarHandles_test starts ***" <<endl; + varHandleTest(); + resetableTest(); + refCountTest(); + cout << "*** VarHandles_test OK ***" <<endl; + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/WriteHandleKey_test.cxx b/EDM/athena/Control/StoreGate/test/WriteHandleKey_test.cxx new file mode 100644 index 00000000..9be874b1 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/WriteHandleKey_test.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/WriteHandleKey_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for WriteHandleKey. + */ + + +#undef NDEBUG +#include "StoreGate/WriteHandleKey.h" +#include "StoreGate/exceptions.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include <cassert> +#include <iostream> + + +class MyObj {}; +CLASS_DEF (MyObj, 293847295, 1) + + +void test1() +{ + std::cout << "test1\n"; + + SG::WriteHandleKey<MyObj> k1 ("aaa"); + assert (k1.clid() == 293847295); + assert (k1.key() == "aaa"); + assert (k1.mode() == Gaudi::DataHandle::Writer); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (!k1.storeHandle().isSet()); + assert (k1.initialize().isSuccess()); + assert (k1.storeHandle().isSet()); + + k1 = "aab"; + assert (k1.clid() == 293847295); + assert (k1.key() == "aab"); + assert (k1.mode() == Gaudi::DataHandle::Writer); + assert (k1.storeHandle().name() == "StoreGateSvc"); + assert (k1.storeHandle().isSet()); + + k1 = "FeeSvc/aac"; + assert (k1.clid() == 293847295); + assert (k1.key() == "aac"); + assert (k1.mode() == Gaudi::DataHandle::Writer); + assert (k1.storeHandle().name() == "FeeSvc"); + assert (!k1.storeHandle().isSet()); + + SG::WriteHandleKey<MyObj> k2 ("bbb", "FooSvc"); + assert (k2.clid() == 293847295); + assert (k2.key() == "bbb"); + assert (k2.mode() == Gaudi::DataHandle::Writer); + assert (k2.storeHandle().name() == "FooSvc"); + assert (!k2.storeHandle().isSet()); +} + + +int main() +{ + ISvcLocator* pDum; + Athena_test::initGaudi(pDum); //need MessageSvc + + test1(); +} diff --git a/EDM/athena/Control/StoreGate/test/WriteHandle_test.cxx b/EDM/athena/Control/StoreGate/test/WriteHandle_test.cxx new file mode 100644 index 00000000..5093c09e --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/WriteHandle_test.cxx @@ -0,0 +1,517 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/WriteHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Tests for WriteHandle. + */ + + +#undef NDEBUG +#include "StoreGate/WriteHandle.h" +#include "StoreGate/ReadHandle.h" +#include "StoreGate/exceptions.h" +#include "SGTools/TestStore.h" +#include "SGTools/CLASS_DEF.h" +#include "SGTools/StorableConversions.h" +#include "SGTools/DataProxy.h" +#include "TestTools/initGaudi.h" +#include "TestTools/expect_exception.h" +#include "AthContainersInterfaces/IConstAuxStore.h" +#include "AthenaKernel/errorcheck.h" +#include "CxxUtils/make_unique.h" +#include "CxxUtils/unused.h" +#include <cassert> +#include <iostream> + + +class MyObjAux + : public SG::IConstAuxStore, public ILockable +{ +public: + MyObjAux(int x=0) : x(x) {} + ~MyObjAux() { deleted.push_back (x); } + int x; + bool m_locked = false; + + virtual const void* getData (SG::auxid_t /*auxid*/) const override { return 0; } + virtual void* getDecoration (SG::auxid_t /*auxid*/, size_t /*size*/, size_t /*capacity*/) override { return 0; } + virtual const SG::auxid_set_t& getAuxIDs() const override { std::abort(); } + virtual void lock() override { m_locked = true; } + virtual void clearDecorations() override { } + virtual size_t size() const override { return 0; } + + static std::vector<int> deleted; +}; +std::vector<int> MyObjAux::deleted; +CLASS_DEF (MyObjAux, 293847296, 1) + +class MyObj +{ +public: + MyObj(int x=0) : x(x) {} + ~MyObj() { deleted.push_back (x); } + SG::IAuxStore* getStore() const { return nullptr; } + void setStore (SG::IConstAuxStore* store) {aux = dynamic_cast<MyObjAux*>(store); } + int x; + MyObjAux* aux {nullptr}; + + static std::vector<int> deleted; +}; +std::vector<int> MyObj::deleted; +CLASS_DEF (MyObj, 293847295, 1) +static const CLID MyCLID = 293847295; + + +class MyDObj : public DataObject +{ +public: + MyDObj(int x=0) : x(x) {} + ~MyDObj() { deleted.push_back (x); } + int x; + + static std::vector<int> deleted; +}; +std::vector<int> MyDObj::deleted; +CLASS_DEF (MyDObj, 293847297, 1) + + +std::pair<std::unique_ptr<MyObj>, std::unique_ptr<MyObjAux> > +makeWithAux (int x=0) +{ + auto obj = CxxUtils::make_unique<MyObj>(x); + auto aux = CxxUtils::make_unique<MyObjAux>(x+100); + obj->setStore (aux.get()); + return std::make_pair (std::move(obj), std::move(aux)); +} + + + +class TestHandle + : public SG::WriteHandle<MyObj> +{ +public: + using SG::WriteHandle<MyObj>::WriteHandle; + using SG::WriteHandle<MyObj>::setState; + using SG::WriteHandle<MyObj>::m_store; +}; + + +// Ctors. +void test1() +{ + std::cout << "test1\n"; + + SG::WriteHandle<MyObj> h1; + assert (h1.clid() == MyCLID); + assert (h1.key() == ""); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Writer); + + SG::WriteHandle<MyObj> h2 ("foo", "FooSvc"); + assert (h2.clid() == MyCLID); + assert (h2.key() == "foo"); + assert (h2.name() == "foo"); + assert (h2.storeHandle().name() == "FooSvc"); + assert (h2.mode() == Gaudi::DataHandle::Writer); + + SG::WriteHandleKey<MyObj> k3 ("asd"); + assert (k3.initialize().isSuccess()); + SG::WriteHandle<MyObj> h3 (k3); + assert (h3.clid() == MyCLID); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "StoreGateSvc"); + assert (h3.mode() == Gaudi::DataHandle::Writer); + + { + SG::WriteHandleKey<MyObj> k4 ("asd", "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::WriteHandle<MyObj> h4 (k4)); + } + + SGTest::TestStore dumstore; + EventContext ctx5; + ctx5.setProxy (&dumstore); + SG::WriteHandle<MyObj> h5 (k3, ctx5); + assert (h5.clid() == MyCLID); + assert (h5.key() == "asd"); + assert (h5.storeHandle().name() == "StoreGateSvc"); + assert (h5.mode() == Gaudi::DataHandle::Writer); + assert (h5.store() == "TestStore"); + + SG::WriteHandleKey<MyObj> k6 ("asd", "OtherStore"); + assert (k6.initialize().isSuccess()); + SG::WriteHandle<MyObj> h6 (k6, ctx5); + assert (h6.clid() == MyCLID); + assert (h6.key() == "asd"); + assert (h6.storeHandle().name() == "OtherStore"); + assert (h6.mode() == Gaudi::DataHandle::Writer); + assert (h6.store() == "OtherStore" || h6.store() == "OtherStore_Impl"); + + { + SG::WriteHandleKey<MyObj> k7 ("asd", "BazSvc"); + k7.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::WriteHandle<MyObj> h7 (k7, ctx5)); + } +} + + +// Copy +void test2() +{ + std::cout << "test2\n"; + SGTest::TestStore testStore; + + SG::WriteHandle<MyObj> h1 ("foo", "FooSvc"); + assert (h1.store() == "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (h1.store() == "TestStore"); + + auto fooobj = CxxUtils::make_unique<MyObj>(); + MyObj* fooptr = fooobj.get(); + assert (h1.record (std::move(fooobj)).isSuccess()); + assert (h1.isInitialized()); + assert (h1.cptr() == fooptr); + + SG::DataProxy* foo_proxy = testStore.proxy (MyCLID, "foo"); + assert (foo_proxy->refCount() == 2); + + SG::WriteHandle<MyObj> h2 (h1); + assert (h2.key() == "foo"); + assert (h2.store() == "TestStore"); + assert (h2.isInitialized()); + assert (h2.cptr() == fooptr); + assert (foo_proxy->refCount() == 3); + + SG::WriteHandle<MyObj> h3 (std::move(h2)); + assert (h3.key() == "foo"); + assert (h3.store() == "TestStore"); + assert (h3.isInitialized()); + assert (h3.cptr() == fooptr); + assert (foo_proxy->refCount() == 3); + assert (h2.key() == "foo"); + assert (h2.store() == "TestStore"); + assert (!h2.isInitialized()); + assert (h2.cptr() == nullptr); + + SG::WriteHandle<MyObj> h4 ("bar", "FooSvc"); + assert (h4.setProxyDict (&testStore).isSuccess()); + + auto barobj = CxxUtils::make_unique<MyObj>(); + MyObj* barptr = barobj.get(); + assert (h4.record (std::move(barobj)).isSuccess()); + assert (h4.isInitialized()); + assert (h4.cptr() == barptr); + + SG::DataProxy* bar_proxy = testStore.proxy (MyCLID, "bar"); + assert (bar_proxy->refCount() == 2); + + h3 = h4; + assert (h3.key() == "bar"); + assert (h3.store() == "TestStore"); + assert (h3.isInitialized()); + assert (h3.cptr() == barptr); + assert (h4.key() == "bar"); + assert (h4.store() == "TestStore"); + assert (h4.isInitialized()); + assert (h4.cptr() == barptr); + + assert (foo_proxy->refCount() == 2); + assert (bar_proxy->refCount() == 3); + + // h1: foo, h2: unint, h3: bar, h4: bar + + h2 = std::move(h3); + assert (h2.key() == "bar"); + assert (h2.store() == "TestStore"); + assert (h2.isInitialized()); + assert (h2.cptr() == barptr); + assert (h3.key() == "bar"); + assert (h3.store() == "TestStore"); + assert (!h3.isInitialized()); + assert (h3.cptr() == nullptr); + + assert (foo_proxy->refCount() == 2); + assert (bar_proxy->refCount() == 3); +} + + +// Retrieve +void test3() +{ + std::cout << "test3\n"; + + SGTest::TestStore testStore; + SG::WriteHandle<MyObj> h1 ("foo", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + + assert (!h1.isValid()); + assert (h1.cachedPtr() == nullptr); + assert (h1.ptr() == nullptr); + assert (h1.cptr() == nullptr); + int UNUSED(xx) = 0; + EXPECT_EXCEPTION (SG::ExcNullWriteHandle, xx = (*h1).x); + EXPECT_EXCEPTION (SG::ExcNullWriteHandle, xx = h1->x); + + auto obj = CxxUtils::make_unique<MyObj>(10); + MyObj* objptr = obj.get(); + assert (h1.record(std::move(obj)).isSuccess()); + + assert (h1.isValid()); + assert (h1.cachedPtr() == objptr); + assert (h1.ptr() == objptr); + assert (h1.cptr() == objptr); + assert ((*h1).x == 10); + assert (h1->x == 10); +} + + +// record (unique_ptr) +void test4() +{ + std::cout << "test4\n"; + SGTest::TestStore testStore; + + SG::WriteHandle<MyObj> h1 ("foo1", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + + assert (!h1.isInitialized()); + assert (!h1.isValid()); + + assert (h1.recordNonConst (CxxUtils::make_unique<MyObj>(20)).isSuccess()); + assert (h1.isInitialized()); + assert (h1.isValid()); + assert (h1->x == 20); + assert (!h1.isConst()); + + SG::WriteHandle<MyObj> h4 ("foo4", "FooSvc"); + assert (h4.setProxyDict (&testStore).isSuccess()); + assert (h4.record (CxxUtils::make_unique<MyObj>(23)).isSuccess()); + assert (h4.isInitialized()); + assert (h4.isValid()); + assert (h4->x == 23); + assert (h4.isConst()); + + // Record existing object --- should fail. + MyObj::deleted.clear(); + SG::WriteHandle<MyObj> h5 ("foo1", "FooSvc"); + assert (h5.setProxyDict (&testStore).isSuccess()); + assert (h5.record (CxxUtils::make_unique<MyObj>(25)).isFailure()); + assert (MyObj::deleted == std::vector<int>{25}); +} + + +// record (with aux store) +void test5() +{ + std::cout << "test5\n"; + SGTest::TestStore testStore; + + SG::WriteHandle<MyObj> h1 ("foo1", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + auto ptrs1 = makeWithAux(30); + assert (h1.recordNonConst (std::move(ptrs1.first), std::move(ptrs1.second)).isSuccess()); + assert (h1.isInitialized()); + assert (h1.isValid()); + assert (h1->x == 30); + assert (!h1.isConst()); + + SG::ReadHandle<MyObjAux> h1a ("foo1Aux.", "FooSvc"); + assert (h1a.setProxyDict (&testStore).isSuccess()); + assert (h1a.isValid()); + assert (h1a.isInitialized()); + assert (h1a->x == 130); + assert (!h1a.isConst()); + assert (h1->aux->x == 130); + + SG::WriteHandle<MyObj> h4 ("foo4", "FooSvc"); + assert (h4.setProxyDict (&testStore).isSuccess()); + auto ptrs4 = makeWithAux(33); + assert (h4.record (std::move(ptrs4.first), std::move(ptrs4.second)).isSuccess()); + assert (h4.isInitialized()); + assert (h4.isValid()); + assert (h4->x == 33); + assert (h4.isConst()); + + SG::ReadHandle<MyObjAux> h4a ("foo4Aux.", "FooSvc"); + assert (h4a.setProxyDict (&testStore).isSuccess()); + assert (h4a.isValid()); + assert (h4a.isInitialized()); + assert (h4a->x == 133); + assert (!h4a.isConst()); + + MyObj::deleted.clear(); + MyObjAux::deleted.clear(); + SG::WriteHandle<MyObj> h5 ("foo4", "FooSvc"); + assert (h5.setProxyDict (&testStore).isSuccess()); + auto ptrs5 = makeWithAux(34); + assert (h5.record (std::move(ptrs5.first), std::move(ptrs5.second)).isFailure()); + assert (!h5.isInitialized()); + assert (MyObj::deleted == std::vector<int>{34}); + assert (MyObjAux::deleted == std::vector<int>{134}); + + testStore.record (new MyObjAux(200), "barAux."); + MyObj::deleted.clear(); + MyObjAux::deleted.clear(); + SG::WriteHandle<MyObj> h6 ("bar", "FooSvc"); + assert (h6.setProxyDict (&testStore).isSuccess()); + auto ptrs6 = makeWithAux(35); + assert (h6.record (std::move(ptrs6.first), std::move(ptrs6.second)).isFailure()); + assert (h6.isInitialized()); + assert (h6.isValid()); + assert (h6->x == 35); + assert (h6->aux == nullptr); + assert (MyObj::deleted == std::vector<int>{}); + assert (MyObjAux::deleted == std::vector<int>{135}); + + MyObjAux* paux = nullptr; + { + SG::WriteHandle<MyObj> h7 ("foo7", "FooSvc"); + assert (h7.setProxyDict (&testStore).isSuccess()); + auto ptrs7 = makeWithAux(30); + paux = ptrs7.second.get(); + assert (h7.record (std::move(ptrs7.first), std::move(ptrs7.second)).isSuccess()); + assert (!paux->m_locked); + } + assert (paux->m_locked); +} + + +// record (shared ptr) +void test6() +{ + std::cout << "test6\n"; + SGTest::TestStore testStore; + + SG::DataObjectSharedPtr<MyDObj> p1 (new MyDObj (300)); + assert (p1->refCount() == 1); + + SG::WriteHandle<MyDObj> h1 ("foo1", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + assert (h1.recordNonConst (p1).isSuccess()); + assert (p1->refCount() == 2); + assert (h1.isValid()); + assert (h1->x == 300); + assert (!h1.isConst()); + assert (h1.ptr() == p1.get()); + + SG::WriteHandle<MyDObj> h4 ("foo4", "FooSvc"); + assert (h4.setProxyDict (&testStore).isSuccess()); + assert (h4.record (p1).isSuccess()); + assert (p1->refCount() == 3); + assert (h4.isValid()); + assert (h4->x == 300); + assert (h4.isConst()); + assert (h4.ptr() == p1.get()); + + SG::WriteHandle<MyDObj> h5 ("foo4", "FooSvc"); + assert (h5.setProxyDict (&testStore).isSuccess()); + assert (h5.record (p1).isFailure()); + assert (p1->refCount() == 3); + assert (!h5.isValid()); +} + + +#if 0 +// recordOrRetrieve +void test7() +{ + std::cout << "test7\n"; + SGTest::TestStore testStore; + + SG::WriteHandle<MyObj> h1 ("foo1", "FooSvc"); + assert (h1.setProxyDict (&testStore).isSuccess()); + auto obj1 = CxxUtils::make_unique<MyObj>(400); + MyObj* objptr = obj1.get(); + assert (h1.recordOrRetrieve (std::move(obj1)).isSuccess()); + assert (h1.isValid()); + assert (h1->x == 400); + assert (h1.ptr() == objptr); + assert (!h1.isConst()); + + MyObj::deleted.clear(); + SG::WriteHandle<MyObj> h2 ("foo1", "FooSvc"); + assert (h2.setProxyDict (&testStore).isSuccess()); + auto obj2 = CxxUtils::make_unique<MyObj>(401); + assert (h2.recordOrRetrieve (std::move(obj2)).isSuccess()); + assert (h2.isValid()); + assert (h2->x == 400); + assert (h2.ptr() == objptr); + assert (MyObj::deleted == std::vector<int>{401}); + assert (!h2.isConst()); + + MyObj::deleted.clear(); + assert (h1.setConst().isSuccess()); + SG::WriteHandle<MyObj> h3 ("foo1", "FooSvc"); + assert (h3.setProxyDict (&testStore).isSuccess()); + auto obj3 = CxxUtils::make_unique<MyObj>(402); + assert (h3.recordOrRetrieve (std::move(obj3)).isFailure()); + assert (MyObj::deleted == std::vector<int>{402}); +} +#endif + + +// makeHandle +void test8() +{ + std::cout << "test8\n"; + SGTest::TestStore testStore; + + SG::WriteHandleKey<MyObj> k1 ("asd"); + assert (k1.initialize().isSuccess()); + auto h1 = SG::makeHandle (k1); + assert (h1.clid() == MyCLID); + assert (h1.key() == "asd"); + assert (h1.storeHandle().name() == "StoreGateSvc"); + assert (h1.mode() == Gaudi::DataHandle::Writer); + + SG::WriteHandleKey<MyObj> k2 ("asd", "BazSvc"); + k2.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::makeHandle (k2)); + + SGTest::TestStore dumstore; + EventContext ctx; + ctx.setProxy (&dumstore); + auto h2 = SG::makeHandle (k1, ctx); + assert (h2.clid() == MyCLID); + assert (h2.key() == "asd"); + assert (h2.storeHandle().name() == "StoreGateSvc"); + assert (h2.mode() == Gaudi::DataHandle::Writer); + assert (h2.store() == "TestStore"); + + SG::WriteHandleKey<MyObj> k3 ("asd", "OtherStore"); + assert (k3.initialize().isSuccess()); + auto h3 = SG::makeHandle (k3, ctx); + assert (h3.clid() == MyCLID); + assert (h3.key() == "asd"); + assert (h3.storeHandle().name() == "OtherStore"); + assert (h3.mode() == Gaudi::DataHandle::Writer); + assert (h3.store() == "OtherStore" || h3.store() == "OtherStore_Impl"); + + SG::WriteHandleKey<MyObj> k4 ("asd", "BazSvc"); + k4.initialize().ignore(); + EXPECT_EXCEPTION (SG::ExcUninitKey, SG::makeHandle (k4, ctx)); +} + + +int main() +{ + errorcheck::ReportMessage::hideErrorLocus(); + errorcheck::ReportMessage::hideFunctionNames(); + ISvcLocator* svcloc; + Athena_test::initGaudi("VarHandleBase_test.txt", svcloc); //need MessageSvc + + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + //test7(); + test8(); + return 0; +} diff --git a/EDM/athena/Control/StoreGate/test/exceptions_test.cxx b/EDM/athena/Control/StoreGate/test/exceptions_test.cxx new file mode 100644 index 00000000..3b039b49 --- /dev/null +++ b/EDM/athena/Control/StoreGate/test/exceptions_test.cxx @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file StoreGate/test/exceptions_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Feb, 2016 + * @brief Regression tests for exceptions. + */ + + +#undef NDEBUG +#include "StoreGate/exceptions.h" +#include <iostream> + + +void test1() +{ + std::cout << "test1\n"; + + std::cout << SG::ExcNullHandleKey().what() << "\n"; + std::cout << SG::ExcBadHandleKey("xkey").what() << "\n"; + std::cout << SG::ExcForbiddenMethod("meth").what() << "\n"; + std::cout << SG::ExcHandleInitError(123, "foo", "FooSvc").what() << "\n"; + std::cout << SG::ExcUninitKey (123, "foo", "FooSvc").what() << "\n"; + std::cout << SG::ExcConstObject(123, "foo", "FooSvc").what() << "\n"; + std::cout << SG::ExcNullWriteHandle(123, "foo", "FooSvc").what() << "\n"; + std::cout << SG::ExcNullReadHandle(123, "foo", "FooSvc").what() << "\n"; + std::cout << SG::ExcNullUpdateHandle(123, "foo", "FooSvc").what() << "\n"; + std::cout << SG::ExcUpdatedObjectFailure (123, "foo", "FooSvc").what() << "\n"; +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/Projects/Calypso/CMakeLists.txt b/EDM/athena/Projects/Calypso/CMakeLists.txt new file mode 100644 index 00000000..a52af646 --- /dev/null +++ b/EDM/athena/Projects/Calypso/CMakeLists.txt @@ -0,0 +1,101 @@ + +# The minimum required CMake version: +cmake_minimum_required( VERSION 3.2 FATAL_ERROR ) + +# Read in the project's version from a file called version.txt. But let it be +# overridden from the command line if necessary. +file( READ ${CMAKE_SOURCE_DIR}/version.txt _version ) +string( STRIP ${_version} _version ) +set( ATHENA_PROJECT_VERSION ${_version} + CACHE STRING "Version of the Athena project to build" ) +unset( _version ) + +# Set the versions of the TDAQ externals to pick up for the build: +set( TDAQ-COMMON_VERSION "02-03-00" ) +set( TDAQ-COMMON_ROOT + "$ENV{TDAQ_RELEASE_BASE}/tdaq-common/tdaq-common-${TDAQ-COMMON_VERSION}" ) + +set( DQM-COMMON_VERSION "01-03-00" ) +set( DQM-COMMON_ROOT + "$ENV{TDAQ_RELEASE_BASE}/dqm-common/dqm-common-${DQM-COMMON_VERSION}" ) + +set( TDAQ_PROJECT_NAME "tdaq") +set( TDAQ_VERSION "07-01-00" ) +set( TDAQ_ROOT "$ENV{TDAQ_RELEASE_BASE}/${TDAQ_PROJECT_NAME}/${TDAQ_PROJECT_NAME}-${TDAQ_VERSION}" ) + +# Find the ATLAS CMake code: +find_package( AtlasCMake QUIET ) + +# Find the base project(s): +find_package( AthenaExternals REQUIRED ) +find_package( Gaudi REQUIRED ) + +# Load all the files from the externals/ subdirectory: +file( GLOB _externals "${CMAKE_CURRENT_SOURCE_DIR}/externals/*.cmake" ) +foreach( _external ${_externals} ) + include( ${_external} ) + get_filename_component( _extName ${_external} NAME_WE ) + string( TOUPPER ${_extName} _extNameUpper ) + message( STATUS "Taking ${_extName} from: ${${_extNameUpper}_ROOT}" ) + unset( _extName ) + unset( _extNameUpper ) +endforeach() +unset( _external ) +unset( _externals ) + +# Disable the usage of the --no-undefined linker flag: +atlas_disable_no_undefined() + +# Set up CTest: +atlas_ctest_setup() + +# Declare project name and version +atlas_project( Athena ${ATHENA_PROJECT_VERSION} + USE AthenaExternals 0.0.1 + PROJECT_ROOT ${CMAKE_SOURCE_DIR}/../../ + FORTRAN ) + +# Install the external configurations: +install( DIRECTORY ${CMAKE_SOURCE_DIR}/externals + DESTINATION ${CMAKE_INSTALL_CMAKEDIR} USE_SOURCE_PERMISSIONS ) + +# Generate the environment setup for the externals, to be used during the build: +lcg_generate_env( SH_FILE ${CMAKE_BINARY_DIR}/${ATLAS_PLATFORM}/env_setup.sh ) + +# Generate replacement rules for the installed paths: +set( _replacements ) +if( NOT "$ENV{NICOS_PROJECT_HOME}" STREQUAL "" ) + get_filename_component( _buildDir $ENV{NICOS_PROJECT_HOME} PATH ) + list( APPEND _replacements ${_buildDir} "\${Athena_DIR}/../../../.." ) +endif() +if( NOT "$ENV{NICOS_PROJECT_RELNAME}" STREQUAL "" ) + list( APPEND _replacements $ENV{NICOS_PROJECT_RELNAME} + "\${Athena_VERSION}" ) +endif() +if( NOT "$ENV{TDAQ_RELEASE_BASE}" STREQUAL "" ) + list( APPEND _replacements $ENV{TDAQ_RELEASE_BASE} + "\${TDAQ_RELEASE_BASE}" ) +endif() + +# Now generate and install the installed setup files: +lcg_generate_env( SH_FILE ${CMAKE_BINARY_DIR}/env_setup_install.sh + REPLACE ${_replacements} ) +install( FILES ${CMAKE_BINARY_DIR}/env_setup_install.sh + DESTINATION . RENAME env_setup.sh ) + +# Configure and install the post-configuration file: +string( REPLACE "$ENV{TDAQ_RELEASE_BASE}" "\$ENV{TDAQ_RELEASE_BASE}" + TDAQ-COMMON_ROOT "${TDAQ-COMMON_ROOT}" ) +string( REPLACE "${TDAQ-COMMON_VERSION}" "\${TDAQ-COMMON_VERSION}" + TDAQ-COMMON_ROOT "${TDAQ-COMMON_ROOT}" ) +string( REPLACE "$ENV{TDAQ_RELEASE_BASE}" "\$ENV{TDAQ_RELEASE_BASE}" + DQM-COMMON_ROOT "${DQM-COMMON_ROOT}" ) +string( REPLACE "${DQM-COMMON_VERSION}" "\${DQM-COMMON_VERSION}" + DQM-COMMON_ROOT "${DQM-COMMON_ROOT}" ) +configure_file( ${CMAKE_SOURCE_DIR}/PostConfig.cmake.in + ${CMAKE_BINARY_DIR}/PostConfig.cmake @ONLY ) +install( FILES ${CMAKE_BINARY_DIR}/PostConfig.cmake + DESTINATION ${CMAKE_INSTALL_CMAKEDIR} ) + +# Package up the release using CPack: +atlas_cpack_setup() diff --git a/EDM/athena/Projects/Calypso/PostConfig.cmake.in b/EDM/athena/Projects/Calypso/PostConfig.cmake.in new file mode 100644 index 00000000..7b813da7 --- /dev/null +++ b/EDM/athena/Projects/Calypso/PostConfig.cmake.in @@ -0,0 +1,31 @@ +# +# File taking care of pointing the downstream projects at the right +# version of the externals. +# + +# Set the versions of the TDAQ projects: +set( TDAQ-COMMON_VERSION "@TDAQ-COMMON_VERSION@" ) +set( TDAQ-COMMON_ROOT "@TDAQ-COMMON_ROOT@" ) + +set( DQM-COMMON_VERSION "@DQM-COMMON_VERSION@" ) +set( DQM-COMMON_ROOT "@DQM-COMMON_ROOT@" ) + +# Find Gaudi: +find_package( Gaudi REQUIRED ) + +# Load all the files from the externals/ subdirectory: +get_filename_component( _thisdir ${CMAKE_CURRENT_LIST_FILE} PATH ) +file( GLOB _externals "${_thisdir}/externals/*.cmake" ) +unset( _thisdir ) +foreach( _external ${_externals} ) + include( ${_external} ) + get_filename_component( _extName ${_external} NAME_WE ) + string( TOUPPER ${_extName} _extNameUpper ) + if( NOT AtlasExternals_FIND_QUIETLY ) + message( STATUS "Taking ${_extName} from: ${${_extNameUpper}_ROOT}" ) + endif() + unset( _extName ) + unset( _extNameUpper ) +endforeach() +unset( _external ) +unset( _externals ) diff --git a/EDM/athena/Projects/Calypso/README.md b/EDM/athena/Projects/Calypso/README.md new file mode 100644 index 00000000..59582d57 --- /dev/null +++ b/EDM/athena/Projects/Calypso/README.md @@ -0,0 +1,44 @@ +The Full ATLAS Offline Software Project +======================================= + +This is the configuration for building the full offline software from the +repository. + +Build Instructions +------------------ + +To build the externals necessary for building this project itself, use the + + build_externals.sh + +script. It will build all the externals necessary for this project into a +subdirectory of the directory holding this repository, called `build`. + +The sources of the externals will be checked out under `build/src`, the +build of the projects will commence under `build/build`, and the results of +the build will be installed under `build/install`. + +RPMs created from the externals are copied under `build/` by the script. + +Once the externals have finished building, you can initiate the full build +of the project against these newly built externals by executing the + + build.sh + +script. It uses the same directory layout inside the `build` directory as +was used for the externals. + +Custom Builds +------------- + +Of course it is perfectly allowed to set up a build by hand, not using the +`build.sh` script as well. In that case you have to make sure to have a +functional version of AthenaExternals set up in your environment, and point +the `GAUDI_ROOT` environment variable against the Gaudi version that you +want to use for the build. + +You will also need to set the `TDAQ_RELEASE_BASE` environment variable for +the build to be successful. The simplest way of doing this is to use the +helper script: + + Build/AtlasBuildScripts/TDAQ_RELEASE_BASE.sh diff --git a/EDM/athena/Projects/Calypso/build.sh b/EDM/athena/Projects/Calypso/build.sh new file mode 100755 index 00000000..79767850 --- /dev/null +++ b/EDM/athena/Projects/Calypso/build.sh @@ -0,0 +1,133 @@ +#!/bin/bash +# +# Script for building the release on top of externals built using one of the +# scripts in this directory. +# +_time_() { local c="time -p " ; while test "X$1" != "X" ; do c+=" \"$1\"" ; shift; done; ( eval "$c" ) 2>&1 | sed "s,^real[[:space:]],time::${c}:: real ," ; } + +# Function printing the usage information for the script +usage() { + echo "Usage: build.sh [-t build type] [-b build dir] [-c] [-m] [-i] [-p] [-a]" + echo " -c: Execute CMake step" + echo " -m: Execute make step" + echo " -i: Execute install step" + echo " -p: Execute CPack step" + echo " -a: Abort on error" + echo "If none of the c, m, i or p options are set then the script will do" + echo "*all* steps. Otherwise only the enabled steps are run - it's your" + echo "reponsibility to ensure that precusors are in good shape" +} + +# Parse the command line arguments: +BUILDDIR="" +BUILDTYPE="RelWithDebInfo" +EXE_CMAKE="" +EXE_MAKE="" +EXE_INSTALL="" +EXE_CPACK="" +NIGHTLY=true +while getopts ":t:b:hcmipa" opt; do + case $opt in + t) + BUILDTYPE=$OPTARG + ;; + b) + BUILDDIR=$OPTARG + ;; + c) + EXE_CMAKE="1" + ;; + m) + EXE_MAKE="1" + ;; + i) + EXE_INSTALL="1" + ;; + p) + EXE_CPACK="1" + ;; + a) + NIGHTLY=false + ;; + h) + usage + exit 0 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +# If no step was explicitly specified, turn them all on: +if [ -z "$EXE_CMAKE" -a -z "$EXE_MAKE" -a -z "$EXE_INSTALL" -a -z "$EXE_CPACK" ]; then + EXE_CMAKE="1" + EXE_MAKE="1" + EXE_INSTALL="1" + EXE_CPACK="1" +fi + +# Stop on errors from here on out: +set -e + +# Source in our environment +AthenaSrcDir=$(dirname ${BASH_SOURCE[0]}) +if [ -z "$BUILDDIR" ]; then + BUILDDIR=${AthenaSrcDir}/../../../build +fi +mkdir -p ${BUILDDIR} +BUILDDIR=$(cd ${BUILDDIR} && pwd) +source $AthenaSrcDir/build_env.sh -b $BUILDDIR >& ${BUILDDIR}/build_env.log +cat ${BUILDDIR}/build_env.log + +# Set Gaudi's version to the same value as this project's version: +export GAUDI_VERSION=`cat ${AthenaSrcDir}/version.txt` + +# create the actual build directory +mkdir -p ${BUILDDIR}/build/Athena +cd ${BUILDDIR}/build/Athena + +# consider a pipe failed if ANY of the commands fails +set -o pipefail + +# CMake: +if [ -n "$EXE_CMAKE" ]; then + # Remove the CMakeCache.txt file, to force CMake to find externals + # from scratch in an incremental build. + rm -f CMakeCache.txt + # Now run the actual CMake configuration: + _time_ cmake -DCMAKE_BUILD_TYPE:STRING=${BUILDTYPE} \ + -DCTEST_USE_LAUNCHERS:BOOL=TRUE \ + ${AthenaSrcDir} 2>&1 | tee cmake_config.log +fi + +# for nightly builds we want to get as far as we can +if [ "$NIGHTLY" = true ]; then + # At this point stop worrying about errors: + set +e +fi + +# make: +if [ -n "$EXE_MAKE" ]; then + _time_ make -k 2>&1 | tee cmake_build.log +fi + +# Install the results: +if [ -n "$EXE_INSTALL" ]; then + _time_ make install/fast \ + DESTDIR=${BUILDDIR}/install/Athena/${NICOS_PROJECT_VERSION} 2>&1 | tee cmake_install.log +fi + +# Build an RPM for the release: +if [ -n "$EXE_CPACK" ]; then + _time_ cpack 2>&1 | tee cmake_cpack.log + cp Athena*.rpm ${BUILDDIR}/ +fi + diff --git a/EDM/athena/Projects/Calypso/build_env.sh b/EDM/athena/Projects/Calypso/build_env.sh new file mode 100755 index 00000000..f146511b --- /dev/null +++ b/EDM/athena/Projects/Calypso/build_env.sh @@ -0,0 +1,105 @@ +# This script sets up the build enironment for an Athena +# build, on top of a built set of externals (including Gaudi) +# +# This script is kept separate from the build.sh +# wrapper so it can be sourced separately from it when +# clients want to manage their own build and just want +# to setup the build environment + +env_usage() { + echo "Usage: build_env.sh [-b build dir]" +} + +# This function actually sets up the environment for us +# (factorise it here in case it needs skipped) +env_setup() { + startdir=$(pwd) + # As this script can be sourced we need to support zsh and + # possibly other Bourne shells + if [ "x${BASH_SOURCE[0]}" = "x" ]; then + # This trick should do the right thing under ZSH: + thisdir=$(dirname `print -P %x`) + if [ $? != 0 ]; then + echo "ERROR: This script must be sourced from BASH or ZSH" + return 1 + fi + else + # The BASH solution is a bit more straight forward: + thisdir=$(dirname ${BASH_SOURCE[0]}) + fi + AthenaSrcDir=$(cd ${thisdir};pwd) + + # The directory holding the helper scripts: + scriptsdir=${AthenaSrcDir}/../../Build/AtlasBuildScripts + + # Go to the main directory of the repository: + cd ${AthenaSrcDir}/../.. + + # Check if the user specified any source/build directories: + if [ "$BUILDDIR" = "" ]; then + BUILDDIR=${AthenaSrcDir}/../../../build + fi + + # Set up the environment for the build: + export NICOS_PROJECT_VERSION=`cat ${AthenaSrcDir}/version.txt` + export NICOS_ATLAS_RELEASE=${NICOS_PROJECT_VERSION} + export NICOS_PROJECT_RELNAME=${NICOS_PROJECT_VERSION} + export NICOS_PROJECT_HOME=$(cd ${BUILDDIR}/install;pwd)/Athena + + # Set up the environment variables for finding LCG and the TDAQ externals: + source ${scriptsdir}/LCG_RELEASE_BASE.sh + source ${scriptsdir}/TDAQ_RELEASE_BASE.sh + + # Set up the AthenaExternals project: + extDir=${BUILDDIR}/install/AthenaExternals/${NICOS_PROJECT_VERSION}/InstallArea + if [ ! -d ${extDir} ]; then + echo "Didn't find the AthenaExternals project under ${extDir}" + fi + echo "Setting up AthenaExternals from: ${extDir}" + source ${extDir}/*/setup.sh + + # Get the "platform name" from the directory created by the AthenaExternals + # build: + platform=$(cd ${extDir};ls) + + # Point to Gaudi: + export GAUDI_ROOT=${BUILDDIR}/install/GAUDI/${NICOS_PROJECT_VERSION}/InstallArea/${platform} + echo "Taking Gaudi from: ${GAUDI_ROOT}" + + cd $startdir +} + +# we need to reset the option index as we are sourcing this script +# http://stackoverflow.com/questions/23581368/bug-in-parsing-args-with-getopts-in-bash +OPTIND=1 + +# Parse the command line arguments: +BUILDDIR="" +while getopts "b:h" opt; do + case $opt in + b) + BUILDDIR=$OPTARG + ;; + h) + env_usage + ABORT=1 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + env_usage + ABORT=1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + env_usage + ABORT=1 + ;; + esac +done + +# Put a big wrapper around bad argument case, because +# a sourced script should not call "exit". This is quite +# annoying... +if [ -z "$ABORT" ]; then + env_setup +fi diff --git a/EDM/athena/Projects/Calypso/build_externals.sh b/EDM/athena/Projects/Calypso/build_externals.sh new file mode 100755 index 00000000..1d693182 --- /dev/null +++ b/EDM/athena/Projects/Calypso/build_externals.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# +# Script building all the externals necessary for the nightly build. +# + +# Function printing the usage information for the script +usage() { + echo "Usage: build_externals.sh [-t build_type] [-b build_dir] [-f] [-c]" + echo " -f: Force rebuild of externals from scratch, otherwise if script" + echo " finds an external build present it will only do an incremental" + echo " build" + echo " -c: Build the externals for the continuous integration (CI) system," + echo " skipping the build of the externals RPMs." + echo "If a build_dir is not given the default is '../build'" + echo "relative to the athena checkout" +} + +# Parse the command line arguments: +BUILDDIR="" +BUILDTYPE="RelWithDebInfo" +FORCE="" +CI="" +while getopts ":t:b:fch" opt; do + case $opt in + t) + BUILDTYPE=$OPTARG + ;; + b) + BUILDDIR=$OPTARG + ;; + f) + FORCE="1" + ;; + c) + CI="1" + ;; + h) + usage + exit 0 + ;; + :) + echo "Argument -$OPTARG requires a parameter!" + usage + exit 1 + ;; + ?) + echo "Unknown argument: -$OPTARG" + usage + exit 1 + ;; + esac +done + +# Version comparison function. Taken from a StackOverflow article. +verlte() { + if [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]; then + return 1 + fi + return 0 +} + +# First off, check that we are using a new enough version of Git. We need +# at least version 1.8.1. +git_min_version=1.8.1 +git_version=`git --version | awk '{print $3}'` +verlte "${git_min_version}" "${git_version}" +if [ $? = 0 ]; then + echo "Detected git version (${git_version}) not new enough." + echo "Need at least: ${git_min_version}" + exit 1 +fi + +# Stop on errors from here on out: +set -e +set -o pipefail + +# We are in BASH, get the path of this script in a simple way: +thisdir=$(dirname ${BASH_SOURCE[0]}) +thisdir=$(cd ${thisdir};pwd) + +# Go to the main directory of the repository: +cd ${thisdir}/../.. + +# Check if the user specified any source/build directories: +if [ "$BUILDDIR" = "" ]; then + BUILDDIR=${thisdir}/../../../build +fi +mkdir -p ${BUILDDIR} +BUILDDIR=$(cd $BUILDDIR; pwd) + +if [ "$FORCE" = "1" ]; then + echo "Force deleting existing build area..." + rm -fr ${BUILDDIR}/install/AthenaExternals ${BUILDDIR}/install/GAUDI + rm -fr ${BUILDDIR}/src/AthenaExternals ${BUILDDIR}/src/GAUDI + rm -fr ${BUILDDIR}/build/AthenaExternals ${BUILDDIR}/build/GAUDI +fi + +# Create some directories: +mkdir -p ${BUILDDIR}/{src,install} + +# Set some environment variables that the builds use internally: +export NICOS_PROJECT_VERSION=`cat ${thisdir}/version.txt` +export NICOS_ATLAS_RELEASE=${NICOS_PROJECT_VERSION} +export NICOS_PROJECT_RELNAME=${NICOS_PROJECT_VERSION} + +# The directory holding the helper scripts: +scriptsdir=${thisdir}/../../Build/AtlasBuildScripts +scriptsdir=$(cd ${scriptsdir}; pwd) + +# Set the environment variable for finding LCG releases: +source ${scriptsdir}/LCG_RELEASE_BASE.sh + +# Flag for triggering the build of RPMs for the externals: +RPMOPTIONS="-r ${BUILDDIR}" +if [ "$CI" = "1" ]; then + RPMOPTIONS= +fi + +# Read in the tag/branch to use for AthenaExternals: +AthenaExternalsVersion=$(awk '/^AthenaExternalsVersion/{print $3}' ${thisdir}/externals.txt) + +# Check out AthenaExternals from the right branch/tag: +${scriptsdir}/checkout_atlasexternals.sh \ + -t ${AthenaExternalsVersion} \ + -s ${BUILDDIR}/src/AthenaExternals 2>&1 | tee ${BUILDDIR}/src/checkout.AthenaExternals.log + +# Build AthenaExternals: +export NICOS_PROJECT_HOME=$(cd ${BUILDDIR}/install;pwd)/AthenaExternals +${scriptsdir}/build_atlasexternals.sh \ + -s ${BUILDDIR}/src/AthenaExternals \ + -b ${BUILDDIR}/build/AthenaExternals \ + -i ${BUILDDIR}/install/AthenaExternals/${NICOS_PROJECT_VERSION} \ + -p AthenaExternals ${RPMOPTIONS} -t ${BUILDTYPE} \ + -v ${NICOS_PROJECT_VERSION} + +# Get the "platform name" from the directory created by the AthenaExternals +# build: +platform=$(cd ${BUILDDIR}/install/AthenaExternals/${NICOS_PROJECT_VERSION}/InstallArea;ls) + +# Read in the tag/branch to use for Gaudi: +GaudiVersion=$(awk '/^GaudiVersion/{print $3}' ${thisdir}/externals.txt) + +# Check out Gaudi from the right branch/tag: +${scriptsdir}/checkout_Gaudi.sh \ + -t ${GaudiVersion} \ + -s ${BUILDDIR}/src/GAUDI 2>&1 | tee ${BUILDDIR}/src/checkout.GAUDI.log + +# Build Gaudi: +export NICOS_PROJECT_HOME=$(cd ${BUILDDIR}/install;pwd)/GAUDI +${scriptsdir}/build_Gaudi.sh \ + -s ${BUILDDIR}/src/GAUDI \ + -b ${BUILDDIR}/build/GAUDI \ + -i ${BUILDDIR}/install/GAUDI/${NICOS_PROJECT_VERSION} \ + -e ${BUILDDIR}/install/AthenaExternals/${NICOS_PROJECT_VERSION}/InstallArea/${platform} \ + -p AthenaExternals -f ${platform} ${RPMOPTIONS} -t ${BUILDTYPE} diff --git a/EDM/athena/Projects/Calypso/externals.txt b/EDM/athena/Projects/Calypso/externals.txt new file mode 100644 index 00000000..467bc0b2 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals.txt @@ -0,0 +1,9 @@ +# Versions of the various externals to build before starting the build of +# this project, when doing a full stack nightly build. +# +# Remember that when specifying the name of a branch, you *must* put +# an "origin/" prefix before it. For tags however this is explicitly +# forbidden. + +AthenaExternalsVersion = 1.0.48 +GaudiVersion = v27r1.019 diff --git a/EDM/athena/Projects/Calypso/externals/Crmc.cmake b/EDM/athena/Projects/Calypso/externals/Crmc.cmake new file mode 100644 index 00000000..25c348f2 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Crmc.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Crmc to use. +# + +set( CRMC_VERSION 1.5.4 ) +set( CRMC_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/crmc/${CRMC_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/EvtGen.cmake b/EDM/athena/Projects/Calypso/externals/EvtGen.cmake new file mode 100644 index 00000000..fa4c1afb --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/EvtGen.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of EvtGen to use. +# + +set( EVTGEN_VERSION 1.4.0 ) +set( EVTGEN_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/evtgen/${EVTGEN_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/HEPUtils.cmake b/EDM/athena/Projects/Calypso/externals/HEPUtils.cmake new file mode 100644 index 00000000..f16c2e48 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/HEPUtils.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of HEPUtils to use. +# + +set( HEPUTILS_VERSION 1.1.0 ) +set( HEPUTILS_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/heputils/${HEPUTILS_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Herwig.cmake b/EDM/athena/Projects/Calypso/externals/Herwig.cmake new file mode 100644 index 00000000..6edc8f04 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Herwig.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Herwig to use. +# + +set( HERWIG_VERSION 6.520.2 ) +set( HERWIG_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/herwig/${HERWIG_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Herwig3.cmake b/EDM/athena/Projects/Calypso/externals/Herwig3.cmake new file mode 100644 index 00000000..cb52ba21 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Herwig3.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Herwig3 to use. +# + +set( HERWIG3_VERSION 7.0.3 ) +set( HERWIG3_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/herwig++/${HERWIG3_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Hydjet.cmake b/EDM/athena/Projects/Calypso/externals/Hydjet.cmake new file mode 100644 index 00000000..a0ff58d0 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Hydjet.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Hydjet to use. +# + +set( HYDJET_VERSION 1.6 ) +set( HYDJET_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/hydjet/${HYDJET_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Lhapdf.cmake b/EDM/athena/Projects/Calypso/externals/Lhapdf.cmake new file mode 100644 index 00000000..9f22e14d --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Lhapdf.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Lhapdf to use. +# + +set( LHAPDF_VERSION 6.1.5 ) +set( LHAPDF_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/lhapdf/${LHAPDF_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/MCUtils.cmake b/EDM/athena/Projects/Calypso/externals/MCUtils.cmake new file mode 100644 index 00000000..5fd191cf --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/MCUtils.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of MCUtils to use. +# + +set( MCUTILS_VERSION 1.2.1 ) +set( MCUTILS_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/mcutils/${MCUTILS_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/MadGraph5Amc.cmake b/EDM/athena/Projects/Calypso/externals/MadGraph5Amc.cmake new file mode 100644 index 00000000..a410e52e --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/MadGraph5Amc.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of MadGraph to use. +# + +set( MADGRAPH5AMC_VERSION 2.6.1.atlas ) +set( MADGRAPH5AMC_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/madgraph5amc/${MADGRAPH5AMC_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Photospp.cmake b/EDM/athena/Projects/Calypso/externals/Photospp.cmake new file mode 100644 index 00000000..3e6761fd --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Photospp.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Photos++ to use. +# + +set( PHOTOSPP_VERSION 3.61 ) +set( PHOTOSPP_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/photos++/${PHOTOSPP_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Pythia6.cmake b/EDM/athena/Projects/Calypso/externals/Pythia6.cmake new file mode 100644 index 00000000..bc6307fb --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Pythia6.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Pythia 6 to use. +# + +set( PYTHIA6_VERSION 428.2 ) +set( PYTHIA6_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/pythia6/${PYTHIA6_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Pythia8.cmake b/EDM/athena/Projects/Calypso/externals/Pythia8.cmake new file mode 100644 index 00000000..fddc85fc --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Pythia8.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Pythia 8 to use. +# + +set( PYTHIA8_VERSION 226 ) +set( PYTHIA8_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/pythia8/${PYTHIA8_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/README.md b/EDM/athena/Projects/Calypso/externals/README.md new file mode 100644 index 00000000..421329e5 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/README.md @@ -0,0 +1,20 @@ +Directory collecting external package declarations +================================================== + +This directory is used to collect simple CMake files that get included by +the CMake configuration to set up the locations of all the externals used +for the offline release build. + +Each external should be defined by its own CMake file. The files should +have a name <Bla> corresponding to the Find<Bla> module name used to find +the external in question. + +The files should define all the variables expected by the Find<Bla> modules, +which normally boil down to variables: + +`EXTNAME_ROOT` +`EXTNAME_VERSION` + +But some modules may require other variables. In which case the `_ROOT` +variable should still be set, to get a nice printout from the AtlasExternals +code during the build about the location of the used external. diff --git a/EDM/athena/Projects/Calypso/externals/Rivet.cmake b/EDM/athena/Projects/Calypso/externals/Rivet.cmake new file mode 100644 index 00000000..5f1f6849 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Rivet.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Rivet to use. +# + +set( RIVET_VERSION 2.5.2 ) +set( RIVET_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/rivet/${RIVET_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Sherpa.cmake b/EDM/athena/Projects/Calypso/externals/Sherpa.cmake new file mode 100644 index 00000000..7c321a18 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Sherpa.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Sherpa to use. +# + +set( SHERPA_VERSION 2.2.4 ) +set( SHERPA_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/sherpa/${SHERPA_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Starlight.cmake b/EDM/athena/Projects/Calypso/externals/Starlight.cmake new file mode 100644 index 00000000..4ac46cb1 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Starlight.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Starlight to use. +# + +set( STARLIGHT_VERSION r193 ) +set( STARLIGHT_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/starlight/${STARLIGHT_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/Tauolapp.cmake b/EDM/athena/Projects/Calypso/externals/Tauolapp.cmake new file mode 100644 index 00000000..f7ccd72d --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/Tauolapp.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of Tauola++ to use. +# + +set( TAUOLAPP_VERSION 1.1.6 ) +set( TAUOLAPP_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/tauola++/${TAUOLAPP_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/ThePEG.cmake b/EDM/athena/Projects/Calypso/externals/ThePEG.cmake new file mode 100644 index 00000000..0d1a7236 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/ThePEG.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of ThePEG to use. +# + +set( THEPEG_VERSION 2.0.3 ) +set( THEPEG_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/thepeg/${THEPEG_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/externals/YODA.cmake b/EDM/athena/Projects/Calypso/externals/YODA.cmake new file mode 100644 index 00000000..4ab8a085 --- /dev/null +++ b/EDM/athena/Projects/Calypso/externals/YODA.cmake @@ -0,0 +1,7 @@ +# +# File specifying the location of YODA to use. +# + +set( YODA_VERSION 1.6.5 ) +set( YODA_ROOT + ${LCG_RELEASE_DIR}/MCGenerators/yoda/${YODA_VERSION}/${LCG_PLATFORM} ) diff --git a/EDM/athena/Projects/Calypso/package_filters.txt b/EDM/athena/Projects/Calypso/package_filters.txt new file mode 100644 index 00000000..fe176568 --- /dev/null +++ b/EDM/athena/Projects/Calypso/package_filters.txt @@ -0,0 +1,7 @@ +# +# Package filtering rules for the Athena project build. +# + +# Don't pick up anything from the Projects directory: ++ xAOD/.* +- Projects/.* diff --git a/EDM/athena/Projects/Calypso/version.txt b/EDM/athena/Projects/Calypso/version.txt new file mode 100644 index 00000000..afaf360d --- /dev/null +++ b/EDM/athena/Projects/Calypso/version.txt @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/EDM/athena/Projects/WorkDir/CMakeLists.txt b/EDM/athena/Projects/WorkDir/CMakeLists.txt new file mode 100644 index 00000000..e06ced64 --- /dev/null +++ b/EDM/athena/Projects/WorkDir/CMakeLists.txt @@ -0,0 +1,75 @@ +# +# Project file for building a selected set of packages against an +# installed ATLAS release/nightly. +# + +# Set the minimum required CMake version: +cmake_minimum_required( VERSION 3.2 FATAL_ERROR ) + +# Let the user pick up updated AtlasCMake/AtlasLCG versions for testing. +# Remember that it's not a problem if AtlasCMake is not found, that's why +# we use the QUIET keyword. +find_package( AtlasCMake QUIET ) + +# Try to figure out what project is our parent. Just using a hard-coded list +# of possible project names. Basically the names of all the other +# sub-directories inside the Projects/ directory in the repository. +set( _parentProjectNames Athena AthenaP1 AnalysisBase AthAnalysisBase AthDataQuality + AthSimulation ) +set( _defaultParentProject Athena ) +set( _defaultUseFortran TRUE ) +foreach( _pp ${_parentProjectNames} ) + if( NOT "$ENV{${_pp}_DIR}" STREQUAL "" ) + set( _defaultParentProject ${_pp} ) + # Only turn off Fortran support for the AnalysisBase project for now: + if( "${_pp}" STREQUAL "AnalysisBase" ) + set( _defaultUseFortran FALSE ) + endif() + break() + endif() +endforeach() + +# Set the parent project name based on the previous findings: +set( ATLAS_PROJECT ${_defaultParentProject} + CACHE STRING "The name of the parent project to build against" ) +# Set whether to use Fortran, based on the previous simple logic: +option( ATLAS_USE_FORTRAN + "Whether the WorkDir project should provide support for Fortran" + ${_defaultUseFortran} ) + +# Clean up: +unset( _parentProjectNames ) +unset( _defaultParentProject ) +unset( _defaultUseFortran ) + +# Find the project that we depend on: +find_package( ${ATLAS_PROJECT} REQUIRED ) + +# Set up CTest: +atlas_ctest_setup() + +# Set up a work directory project: +set( _useFortran ) +if( ATLAS_USE_FORTRAN ) + set( _useFortran FORTRAN ) +endif() +atlas_project( WorkDir ${${ATLAS_PROJECT}_VERSION} + USE ${ATLAS_PROJECT} ${${ATLAS_PROJECT}_VERSION} + PROJECT_ROOT ${CMAKE_SOURCE_DIR}/../.. + ${_useFortran} ) +unset( _useFortran ) + +# Set up the runtime environment setup script(s): +lcg_generate_env( SH_FILE ${CMAKE_BINARY_DIR}/${ATLAS_PLATFORM}/env_setup.sh ) +install( FILES ${CMAKE_BINARY_DIR}/${ATLAS_PLATFORM}/env_setup.sh + DESTINATION . ) + +# Set up CPack: +atlas_cpack_setup() + +# Remind to set up the environment +message( STATUS "") +message( STATUS " In order to test your updates, please don't forget to" ) +message( STATUS " set up the environment with e.g.:" ) +message( STATUS " ---> source x86_64-slc6-gcc62-opt/setup.sh" ) +message( STATUS "") diff --git a/EDM/athena/Projects/WorkDir/README.md b/EDM/athena/Projects/WorkDir/README.md new file mode 100644 index 00000000..71478a39 --- /dev/null +++ b/EDM/athena/Projects/WorkDir/README.md @@ -0,0 +1,53 @@ +ATLAS WorkDir Project +===================== + +This project can be used to build just a few packages from the repository +against an installed ATLAS release/nightly. That means any base project, +offline, trigger, simulation or analysis. + +The project can be used in two ways. + +Using a fully checked out repository +------------------------------------ + +If you have the entire `athena` repository checked out, you need to tell +the CMake configuration which packages you actually want to build. Otherwise +it will go ahead and attempt to build everything. Even packages not part of +the selected base release itself. + +You should make a copy of the `package_filters_example.txt` file found in +this directory, and modify it to select the packages you're interested in, +for compilation. There is some documentation in the file explaining its +format. + +Then, configure the build of the project like: + + asetup ... + mkdir build + cd build/ + cmake -DATLAS_PACKAGE_FILTER_FILE=/your/specific/package_filters.txt \ + ../athena/Projects/WorkDir/ + +Using a partially checked out repository +---------------------------------------- + +If you only checked out the packages that you want to compile, along with +this `Projects/WorkDir` directory, then you don't need to worry about +setting up a package filtering file. You can simply just do: + + asetup ... + mkdir build + cd build/ + cmake ../athena/Projects/WorkDir/ + +This will set up the build of all checked out packages. + +Using the local build +--------------------- + +After being done with the build, you have to remember to source the +`setup.sh` file of the build area to pick up your modifications! So, you +would do something like this to set up your runtime environment from scratch: + + asetup ... + source build/x86_64-slc6-gcc49-opt/setup.sh diff --git a/EDM/athena/Projects/WorkDir/package_filters_example.txt b/EDM/athena/Projects/WorkDir/package_filters_example.txt new file mode 100644 index 00000000..f4497d38 --- /dev/null +++ b/EDM/athena/Projects/WorkDir/package_filters_example.txt @@ -0,0 +1,19 @@ +# +# This is an example file for setting up which packages to pick up +# for a sparse build, when you have a full checkout of the repository, +# but only wish to rebuild some packages. +# +# The syntax is very simple: +# +# + REGEXP will include the package in the build +# - REGEXP will exclude the package from the build +# +# The first match against the package path wins, so list +# more specific matches above more general ones. +# +# Note that when you use git-atlas to make a sparse checkout, you will +# only have the packages available that you want to compile anyway. +# So in that case you should not bother with using such a filter file. +# ++ Control/AthenaExamples/AthExHelloWorld +- .* diff --git a/EDM/athena/xAOD/xAODCore/CMakeLists.txt b/EDM/athena/xAOD/xAODCore/CMakeLists.txt new file mode 100644 index 00000000..f5525901 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/CMakeLists.txt @@ -0,0 +1,94 @@ +# $Id: CMakeLists.txt 793737 2017-01-24 20:11:10Z ssnyder $ +################################################################################ +# Package: xAODCore +################################################################################ + +# Declare the package name: +atlas_subdir( xAODCore ) + +# Extra dependencies based on what environment we are in: +if( XAOD_STANDALONE ) + set( extra_deps PRIVATE Control/AthLinks ) + set( extra_libs ) +else() + set( extra_deps Control/SGTools ) + set( extra_libs SGTools ) +endif() + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/AthContainers + Control/AthContainersInterfaces + Control/AthLinks + Control/CxxUtils + ${extra_deps} ) + +# External dependencies: +find_package( ROOT COMPONENTS Core Hist Tree RIO ) + +# Component(s) in the package: +atlas_add_root_dictionary( xAODCore + xAODCoreDictSource + ROOT_HEADERS xAODCore/tools/ReadStats.h xAODCore/tools/PerfStats.h + Root/LinkDef.h + EXTERNAL_PACKAGES ROOT ) + +atlas_add_library( xAODCore + xAODCore/*.h xAODCore/*.icc xAODCore/tools/*.h Root/*.cxx + ${xAODCoreDictSource} + PUBLIC_HEADERS xAODCore + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers AthLinks CxxUtils + ${extra_libs} ) + +atlas_add_dictionary( xAODCoreRflxDict + xAODCore/xAODCoreRflxDict.h + xAODCore/selection.xml + LINK_LIBRARIES xAODCore ) + +# Test(s) in the package: +atlas_add_test( ut_xaodcore_class_def_test + SOURCES test/ut_class_def.cxx + LINK_LIBRARIES xAODCore ) + +atlas_add_test( ut_xaodcore_auxselection_test + SOURCES test/ut_xaodcore_auxselection_test.cxx + LINK_LIBRARIES AthContainers xAODCore ) + +atlas_add_test( ut_xaodcore_clearDecorations_test + SOURCES test/ut_xaodcore_clearDecorations_test.cxx + LINK_LIBRARIES AthContainers xAODCore ) + +atlas_add_test( ut_xaodcore_floatcompression_test + SOURCES test/ut_xaodcore_floatcompression_test.cxx + LINK_LIBRARIES xAODCore ) + +atlas_add_test( ut_xaodcore_printhelpers_test + SOURCES test/ut_xaodcore_printhelpers_test.cxx + LINK_LIBRARIES AthContainers xAODCore ) + +atlas_add_test( ut_xaodcore_safedeepcopy_test + SOURCES test/ut_xaodcore_safedeepcopy_test.cxx + LINK_LIBRARIES AthContainers xAODCore ) + +atlas_add_test( ut_xaodcore_auxcontainerbase_test + SOURCES test/ut_xaodcore_auxcontainerbase_test.cxx + LINK_LIBRARIES AthContainers xAODCore ) + +if( XAOD_STANDALONE ) + atlas_add_test( ut_xaodcore_shallowcopy_test + SOURCES test/ut_xaodcore_shallowcopy.cxx + LINK_LIBRARIES AthContainers AthLinks xAODCore ) +endif() + +# Declare the "include tests": +foreach( header AddDVProxy AuxContainerBase AuxSelection BaseInfo CLASS_DEF + ClassID_traits ShallowAuxContainer ShallowAuxInfo ShallowCopy + tools_AuxPersInfo tools_AuxPersVector tools_IOStats tools_PerfStats + tools_PrintHelpers tools_ReadStats tools_SafeDeepCopy + tools_TDVCollectionProxy tools_Utils ) + atlas_add_test( inc_${header} + SOURCES test/inc_${header}.cxx + LINK_LIBRARIES xAODCore ) +endforeach() diff --git a/EDM/athena/xAOD/xAODCore/Root/AddDVProxy.cxx b/EDM/athena/xAOD/xAODCore/Root/AddDVProxy.cxx new file mode 100644 index 00000000..44424236 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/AddDVProxy.cxx @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AddDVProxy.cxx 591472 2014-04-05 11:23:29Z krasznaa $ + +// ROOT include(s): +#include <TClass.h> +#include <TError.h> + +// Local include(s): +#include "xAODCore/AddDVProxy.h" + +namespace xAOD { + + /// The constructor of TDVCollectionProxy needs the dictionary of + /// DataVector<xAOD::TDVCollectionProxyDummy> to be loaded already. + /// This function makes sure that this is the case. + /// + void AddDVProxy::loadDictionaries() { + + // Make sure that the minimal set of dictionaries are loaded: + TClass* dummyCl = + TClass::GetClass( "DataVector<xAOD::TDVCollectionProxyDummy>" ); + if( ! dummyCl ) { + ::Error( "xAOD::AddDVProxy::loadDictionaries", + "Couldn't load the dictionary for " + "DataVector<xAOD::TDVCollectionProxyDummy>" ); + } + + return; + } + +} // namespace edm diff --git a/EDM/athena/xAOD/xAODCore/Root/AuxContainerBase.cxx b/EDM/athena/xAOD/xAODCore/Root/AuxContainerBase.cxx new file mode 100644 index 00000000..c22b1ee7 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/AuxContainerBase.cxx @@ -0,0 +1,668 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxContainerBase.cxx 800293 2017-03-10 17:46:57Z ssnyder $ + +// System include(s): +#include <iostream> + +// EDM include(s): +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" + +// Local include(s): +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/tools/IOStats.h" +#include "xAODCore/tools/ReadStats.h" + +using namespace std; + +namespace xAOD { + + AuxContainerBase::AuxContainerBase( bool allowDynamicVars ) + : SG::IAuxStore(), + m_selection(), + m_auxids(), m_vecs(), m_store( 0 ), m_storeIO( 0 ), + m_ownsStore( true ), + m_locked( false ), + m_tick( 0 ), + m_name( "UNKNOWN" ) { + + if( allowDynamicVars ) { + m_store = new SG::AuxStoreInternal(); + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + } + } + + /// This is an interesting one. The internal variables of AuxContainerBase + /// are set up by the derived class(es) at construction. So, this internal + /// state is not to be copied! + /// + /// However, since the derived classes (the contents of their regular + /// members) are allowed to be copied, let's not make this constructor + /// private. + /// + AuxContainerBase::AuxContainerBase( const AuxContainerBase& parent ) + : SG::IAuxStore(), + m_selection( parent.m_selection ), + m_auxids(), m_vecs(), m_store( 0 ), m_storeIO( 0 ), + m_ownsStore( true ), + m_locked( false ), + m_tick( 1 ), + m_name( parent.m_name ) { + + // Unfortunately the dynamic variables can not be copied this easily... + if( parent.m_store ) { + m_store = parent.m_store; + m_ownsStore = false; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + m_selection = parent.m_selection; + m_auxids = m_store->getAuxIDs(); + } + } + + /// This constructor is used to wrap another object that is stored + /// in StoreGate, and hence we should not take ownership of. + /// + /// @param store Another store that should be wrapped, but not owned + /// + AuxContainerBase::AuxContainerBase( const SG::IAuxStore* store ) + : SG::IAuxStore(), + m_selection(), + m_auxids(), m_vecs(), + m_store( const_cast< SG::IAuxStore* >( store ) ), + m_storeIO( 0 ), m_ownsStore( false ), + m_locked( false), + m_tick( 1 ), + m_name( "UNKNOWN" ) { + + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + if( m_store ) { + m_auxids = m_store->getAuxIDs(); + } + } + + AuxContainerBase::~AuxContainerBase() { + + std::vector< SG::IAuxTypeVector* >::iterator itr = m_vecs.begin(); + std::vector< SG::IAuxTypeVector* >::iterator end = m_vecs.end(); + for( ; itr != end; ++itr ) { + if( ! *itr ) continue; + delete *itr; + } + + if( m_store && m_ownsStore ) delete m_store; + } + + /// Just like the copy constructor, this operator doesn't actually copy + /// anything either. It's just here to make it clear to C++ that the + /// internal state of these objects is not to be messed with. + /// + /// @returns A reference to this same object + /// + AuxContainerBase& + AuxContainerBase::operator=( const AuxContainerBase& rhs ) { + + // Protect against self-assignment: + if( this == &rhs ) return *this; + + m_selection = rhs.m_selection; + + // Clean up after the old dynamic store: + if( m_store && m_ownsStore ) { + const auxid_set_t& auxids = m_store->getAuxIDs(); + auxid_set_t::const_iterator itr = auxids.begin(); + auxid_set_t::const_iterator end = auxids.end(); + for( ; itr != end; ++itr ) { + m_auxids.erase( *itr ); + } + ++m_tick; + delete m_store; + } + m_store = 0; + m_storeIO = 0; + m_ownsStore = true; + + // Take posession of the new dynamic store: + if( rhs.m_store ) { + m_store = rhs.m_store; + m_ownsStore = false; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + const auxid_set_t& auxids = m_store->getAuxIDs(); + m_auxids.insert( auxids.begin(), auxids.end() ); + ++m_tick; + } + + m_name = rhs.m_name; + + return *this; + } + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStoreHolder functions + // + + SG::IAuxStore* AuxContainerBase::getStore() const { + + return m_store; + } + + /// This function is used by the I/O infrastructure to possibly put a store + /// object into this one, which can interact with dynamic variables + /// directly. + /// + /// Note that the object takes ownership of the received store. + /// + /// @param store The store that should be used for dynamic variable handling + /// inside the object from now on + /// + void AuxContainerBase::setStore( SG::IAuxStore* store ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check that no funny business is going on: + if( m_store == store ) return; + + // Clean up the current store object: + if( m_store && m_ownsStore ) { + const auxid_set_t& auxids = m_store->getAuxIDs(); + auxid_set_t::const_iterator itr = auxids.begin(); + auxid_set_t::const_iterator end = auxids.end(); + for( ; itr != end; ++itr ) { + m_auxids.erase( *itr ); + } + ++m_tick; + delete m_store; + } + m_store = 0; + m_storeIO = 0; + + // Take posession of the new object: + m_store = store; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + m_ownsStore = true; + if( m_store ) { + const auxid_set_t& auxids = m_store->getAuxIDs(); + m_auxids.insert( auxids.begin(), auxids.end() ); + ++m_tick; + } + + return; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IConstAuxStore functions + // + + const void* AuxContainerBase::getData( auxid_t auxid ) const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + if( m_store ) { + size_t nids = m_store->getAuxIDs().size(); + const void* result = m_store->getData( auxid ); + if( result && nids != m_store->getAuxIDs().size() ) { + m_auxids.insert( auxid ); + ++m_tick; + } + return result; + } else { + std::cout << "ERROR xAOD::AuxContainerBase::getData " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + + // Update the statistics for this variable. The dynamic store registers + // its own variable accesses. + IOStats::instance().stats().readBranch( m_name, auxid ); + + return m_vecs[ auxid ]->toPtr(); + } + + const AuxContainerBase::auxid_set_t& + AuxContainerBase::getAuxIDs() const { + + // Return the full list of IDs: + return getWritableAuxIDs(); + } + + void* AuxContainerBase::getDecoration( auxid_t auxid, size_t size, + size_t capacity ) { + { + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check if we have it as a static variable: + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + // If not, but we have a dynamic store, push it in there: + if( m_store ) { + size_t nids = m_store->getAuxIDs().size(); + void* result = m_store->getDecoration( auxid, size, capacity ); + if( result && ( nids != m_store->getAuxIDs().size() ) ) { + m_auxids.insert( auxid ); + ++m_tick; + } + return result; + } + // If we don't have a dynamic store, complain: + else { + std::cout << "ERROR xAOD::AuxContainerBase::getDecoration " + << "Can't provide variable " + << SG::AuxTypeRegistry::instance().getName( auxid ) + << std::endl; + return 0; + } + } + + // If the container is locked, static variables can't be accessed this + // way: + if( m_locked ) { + throw SG::ExcStoreLocked( auxid ); + } + } + + // If the container is not locked, then fall back on the normal accessor + // function: + return getData( auxid, size, capacity ); + } + + void AuxContainerBase::lock() { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Lock the object and its dynamic store: + m_locked = true; + if( m_store ) { + m_store->lock(); + } + + return; + } + + void AuxContainerBase::clearDecorations() { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Clear the decorations from the dynamic store: + if( m_store ) { + m_store->clearDecorations(); + } + + // Construct the list of managed auxiliary variables from scratch after + // the cleanup: + m_auxids.clear(); + for( auxid_t auxid = 0; auxid < m_vecs.size(); ++auxid ) { + if( m_vecs[ auxid ] ) { + m_auxids.insert( auxid ); + } + } + if( m_store ) { + for( auto auxid : m_store->getAuxIDs() ) { + m_auxids.insert( auxid ); + } + } + + // Remember that the auxiliary IDs were updated: + ++m_tick; + + return; + } + + size_t AuxContainerBase::size() const { + + // Guard against multi-threaded execution: + guard_t guard (m_mutex); + + // Try to find a variable: + auxid_set_t::const_iterator i = m_auxids.begin(); + auxid_set_t::const_iterator end = m_auxids.end(); + for( ; i != end; ++i ) { + if( ( *i < m_vecs.size() ) && m_vecs[ *i ] ) { + size_t sz = m_vecs[ *i ]->size(); + if( sz > 0 ) { + return sz; + } + } + } + + // If we didn't find any, let's ask the dynamic store: + if( m_store ) { + return m_store->size(); + } + + // If we don't have any variables, then the size must be null: + return 0; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStore functions + // + + void* AuxContainerBase::getData( auxid_t auxid, size_t size, + size_t capacity ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + + if( m_store ) { + size_t nids = m_store->getAuxIDs().size(); + void* result = m_store->getData( auxid, size, capacity ); + if( result && nids != m_store->getAuxIDs().size() ) { + m_auxids.insert( auxid ); + ++m_tick; + } + return result; + } else { + std::cout << "ERROR xAOD::AuxContainerBase::getData " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + m_vecs[ auxid ]->reserve( capacity ); + m_vecs[ auxid ]->resize( size ); + + return m_vecs[ auxid ]->toPtr(); + } + + const AuxContainerBase::auxid_set_t& + AuxContainerBase::getWritableAuxIDs() const { + + // Return the full list of known IDs. The constness of this object's + // members comes from the object being const or not. + guard_t guard( m_mutex ); + if (m_tsAuxids.get() == 0) { + m_tsAuxids.reset (new TSAuxidSet (m_tick, m_auxids)); + } + else if (m_tsAuxids->m_tick != m_tick) { + m_tsAuxids->m_set = m_auxids; // May need to optimize this! + m_tsAuxids->m_tick = m_tick; + } + return m_tsAuxids->m_set; + } + + bool AuxContainerBase::resize( size_t size ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // This operation is not allowed on a locked container: + if( m_locked ) { + throw SG::ExcStoreLocked( "resize" ); + } + + // Do the operation on the static variables: + bool nomoves = true; + for (SG::IAuxTypeVector* v : m_vecs) { + if(v) { + if (!v->resize( size )) + nomoves = false; + } + } + + // Do the operation on the dynamic variables: + if( m_store ) { + if (!m_store->resize( size )) + nomoves = false; + } + + return nomoves; + } + + void AuxContainerBase::reserve( size_t size ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // This operation is not allowed on a locked container: + if( m_locked ) { + throw SG::ExcStoreLocked( "reserve" ); + } + + // Do the operation on the static variables: + std::vector< SG::IAuxTypeVector* >::iterator itr = m_vecs.begin(); + std::vector< SG::IAuxTypeVector* >::iterator end = m_vecs.end(); + for( ; itr != end; ++itr ) { + if( *itr ) ( *itr )->reserve( size ); + } + + // Do the operation on the dynamic variables: + if( m_store ) { + m_store->reserve( size ); + } + + return; + } + + void AuxContainerBase::shift( size_t pos, ptrdiff_t offs ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // This operation is not allowed on a locked container: + if( m_locked ) { + throw SG::ExcStoreLocked( "shift" ); + } + + // Do the operation on the static variables: + std::vector< SG::IAuxTypeVector* >::iterator itr = m_vecs.begin(); + std::vector< SG::IAuxTypeVector* >::iterator end = m_vecs.end(); + for( ; itr != end; ++itr ) { + if( *itr ) ( *itr )->shift( pos, offs ); + } + + // Do the operation on the dynamic variables: + if( m_store ) { + m_store->shift( pos, offs ); + } + + return; + } + + + bool AuxContainerBase::insertMove( size_t pos, + IAuxStore& other, + const SG::auxid_set_t& ignore_in ) { + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // This operation is not allowed on a locked container: + if( m_locked ) { + throw SG::ExcStoreLocked( "insertMove" ); + } + + const SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + bool nomove = true; + size_t other_size = other.size(); + + SG::auxid_set_t ignore = ignore_in; + + // Do the operation on the static variables: + 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; + } + } + } + + // Do the operation on the dynamic variables: + if( m_store ) { + if (!m_store->insertMove( pos, other, ignore )) + nomove = false; + + // Notice any new variables added as a result of this. + const AuxContainerBase::auxid_set_t& dynids = m_store->getAuxIDs(); + m_auxids.insert (dynids.begin(), dynids.end()); + ++m_tick; + } + + return nomove; + } + + + bool AuxContainerBase::setOption( auxid_t id, + const SG::AuxDataOption& option ) { + + guard_t guard (m_mutex); + if (id < m_vecs.size() && m_vecs[id] != 0) + return m_vecs[id]->setOption (option); + + if (m_store) + return m_store->setOption (id, option); + return false; + } + + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStoreIO functions + // + + const void* AuxContainerBase::getIOData( auxid_t auxid ) const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // If the variable is not static, look for it in the dynamic store: + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + if( m_storeIO ) { + return m_storeIO->getIOData( auxid ); + } else { + std::cout << "ERROR xAOD::AuxContainerBase::getIOData " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + + // Update the statistics for this variable. The dynamic store registers + // its own variable accesses. + IOStats::instance().stats().readBranch( m_name, auxid ); + + return m_vecs[ auxid ]->toVector(); + } + + const std::type_info* AuxContainerBase::getIOType( auxid_t auxid ) const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // If the variable is not static, ask the dynamic store: + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + if( m_storeIO ) { + return m_storeIO->getIOType( auxid ); + } + } + + // Fall back on getting the information from the registry: + return SG::AuxTypeRegistry::instance().getVecType( auxid ); + } + + const AuxContainerBase::auxid_set_t& + AuxContainerBase::getDynamicAuxIDs() const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // All the variables handled by the internal store are dynamic + // if such a store exists: + if( m_storeIO ) { + // I mean, all the variables. Not just the ones reported as dynamic + // by the internal object. Because the internal object may be something + // that was put into this one in order to achieve data slimming. + return m_store->getAuxIDs(); + } + // In case we don't use an internal store, there are no dynamic + // variables: + static const auxid_set_t dummy {}; + return dummy; + } + + void + AuxContainerBase::selectAux( const std::set< std::string >& attributes ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + m_selection.selectAux( attributes ); + return; + } + + const AuxContainerBase::auxid_set_t& + AuxContainerBase::getSelectedAuxIDs() const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // All the variables handled by the internal store are dynamic + // if such a store exists: + if( m_storeIO ) { + // I mean, all the variables. Not just the ones reported as dynamic + // by the internal object. Because the internal object may be something + // that was put into this one in order to achieve data slimming. + return m_selection.getSelectedAuxIDs( m_store->getAuxIDs() ); + } + + // In case we don't use an internal store, there are no dynamic + // variables: + static auxid_set_t dummy; + return dummy; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + const char* AuxContainerBase::name() const { + + return m_name.c_str(); + } + + void AuxContainerBase::setName( const char* name ) { + + m_name = name; + return; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/AuxInfoBase.cxx b/EDM/athena/xAOD/xAODCore/Root/AuxInfoBase.cxx new file mode 100644 index 00000000..ee7dd21d --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/AuxInfoBase.cxx @@ -0,0 +1,631 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxInfoBase.cxx 793737 2017-01-24 20:11:10Z ssnyder $ + +// System include(s): +#include <iostream> +#include <stdexcept> + +// EDM include(s): +#include "AthContainersInterfaces/AuxDataOption.h" +#include "AthContainers/AuxStoreStandalone.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" + +// Local include(s): +#include "xAODCore/AuxInfoBase.h" +#include "xAODCore/tools/IOStats.h" +#include "xAODCore/tools/ReadStats.h" + +namespace xAOD { + + AuxInfoBase::AuxInfoBase( bool allowDynamicVars ) + : SG::IAuxStore(), + m_selection(), + m_auxids(), m_vecs(), m_store( 0 ), m_storeIO( 0 ), + m_ownsStore( true ), + m_locked( false ), + m_tick( 0 ), + m_name( "UNKNOWN" ) { + + if( allowDynamicVars ) { + m_store = new SG::AuxStoreStandalone(); + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + } + } + + /// This is an interesting one. The internal variables of AuxInfoBase + /// are set up by the derived class(es) at construction. So, this internal + /// state is not to be copied! + /// + /// However, since the derived classes (the contents of their regular + /// members) are allowed to be copied, let's not make this constructor + /// private. + /// + AuxInfoBase::AuxInfoBase( const AuxInfoBase& parent ) + : SG::IAuxStore(), + m_selection( parent.m_selection ), + m_auxids(), m_vecs(), m_store( 0 ), m_storeIO( 0 ), + m_ownsStore( true ), + m_locked( false ), + m_tick( 1 ), + m_name( parent.m_name ) { + + // Unfortunately the dynamic variables can not be copied this easily... + if( parent.m_store ) { + m_store = parent.m_store; + m_ownsStore = false; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + m_selection = parent.m_selection; + m_auxids.insert( m_store->getAuxIDs().begin(), + m_store->getAuxIDs().end() ); + } + } + + /// This constructor is used to wrap another object that is stored + /// in StoreGate, and hence we should not take ownership of. + /// + /// @param store Another store that should be wrapped, but not owned + /// + AuxInfoBase::AuxInfoBase( const SG::IAuxStore* store ) + : SG::IAuxStore(), + m_selection(), + m_auxids(), m_vecs(), + m_store( const_cast< SG::IAuxStore* >( store ) ), + m_storeIO( 0 ), m_ownsStore( false ), + m_locked( false ), + m_tick( 1 ), + m_name( "UNKNOWN" ) { + + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + if( m_store ) { + m_auxids.insert( m_store->getAuxIDs().begin(), + m_store->getAuxIDs().end() ); + } + } + + AuxInfoBase::~AuxInfoBase() { + + std::vector< SG::IAuxTypeVector* >::iterator itr = m_vecs.begin(); + std::vector< SG::IAuxTypeVector* >::iterator end = m_vecs.end(); + for( ; itr != end; ++itr ) { + if( ! *itr ) continue; + delete *itr; + } + + if( m_store && m_ownsStore ) delete m_store; + } + + /// Just like the copy constructor, this operator doesn't actually copy + /// anything either. It's just here to make it clear to C++ that the + /// internal state of these objects is not to be messed with. + /// + /// @returns A reference to this same object + /// + AuxInfoBase& + AuxInfoBase::operator=( const AuxInfoBase& rhs ) { + + // Protect against self-assignment: + if( this == &rhs ) return *this; + + m_selection = rhs.m_selection; + + // Clean up after the old dynamic store: + if( m_store && m_ownsStore ) { + auxid_set_t::const_iterator itr = m_store->getAuxIDs().begin(); + auxid_set_t::const_iterator end = m_store->getAuxIDs().end(); + for( ; itr != end; ++itr ) { + m_auxids.erase( *itr ); + } + ++m_tick; + delete m_store; + } + m_store = 0; + m_storeIO = 0; + m_ownsStore = true; + + // Take posession of the new dynamic store: + if( rhs.m_store ) { + m_store = rhs.m_store; + m_ownsStore = false; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + m_auxids.insert( m_store->getAuxIDs().begin(), + m_store->getAuxIDs().end() ); + ++m_tick; + } + + m_name = rhs.m_name; + + return *this; + } + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStoreHolder functions + // + + SG::IAuxStore* AuxInfoBase::getStore() const { + + return m_store; + } + + /// This function is used by the I/O infrastructure to possibly put a store + /// object into this one, which can interact with dynamic variables + /// directly. + /// + /// Note that the object takes ownership of the received store. + /// + /// @param store The store that should be used for dynamic variable handling + /// inside the object from now on + /// + void AuxInfoBase::setStore( SG::IAuxStore* store ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check that no funny business is going on: + if( m_store == store ) return; + + // Clean up the current store object: + if( m_store && m_ownsStore ) { + auxid_set_t::const_iterator itr = m_store->getAuxIDs().begin(); + auxid_set_t::const_iterator end = m_store->getAuxIDs().end(); + for( ; itr != end; ++itr ) { + m_auxids.erase( *itr ); + } + delete m_store; + ++m_tick; + } + m_store = 0; + m_storeIO = 0; + + // Take posession of the new object: + m_store = store; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + m_ownsStore = true; + if( m_store ) { + m_auxids.insert( m_store->getAuxIDs().begin(), + m_store->getAuxIDs().end() ); + ++m_tick; + } + + return; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IConstAuxStore functions + // + + const void* AuxInfoBase::getData( auxid_t auxid ) const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + if( m_store ) { + size_t nids = m_store->getAuxIDs().size(); + const void* result = m_store->getData( auxid ); + if( result && ( nids != m_store->getAuxIDs().size() ) ) { + m_auxids.insert( auxid ); + ++m_tick; + } + return result; + } else { + std::cout << "ERROR xAOD::AuxInfoBase::getData " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + + // Update the statistics for this variable. The dynamic store registers + // its own variable accesses. + IOStats::instance().stats().readBranch( m_name, auxid ); + + return m_vecs[ auxid ]->toPtr(); + } + + const AuxInfoBase::auxid_set_t& + AuxInfoBase::getAuxIDs() const { + + // Return the full list of IDs: + return getWritableAuxIDs(); + } + + void* AuxInfoBase::getDecoration( auxid_t auxid, size_t size, + size_t capacity ) { + { + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check if we have it as a static variable: + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + // If not, but we have a dynamic store, push it in there: + if( m_store ) { + size_t nids = m_store->getAuxIDs().size(); + void* result = m_store->getDecoration( auxid, size, capacity ); + if( result && ( nids != m_store->getAuxIDs().size() ) ) { + m_auxids.insert( auxid ); + ++m_tick; + } + return result; + } + // If we don't have a dynamic store, complain: + else { + std::cout << "ERROR xAOD::AuxInfoBase::getDecoration " + << "Can't provide variable " + << SG::AuxTypeRegistry::instance().getName( auxid ) + << std::endl; + return 0; + } + } + + // If the container is locked, static variables can't be accessed this + // way: + if( m_locked ) { + throw SG::ExcStoreLocked( auxid ); + } + } + + // If the container is not locked, then fall back on the normal accessor + // function: + return getData( auxid, size, capacity ); + } + + void AuxInfoBase::lock() { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Lock the container and the dynamic store: + m_locked = true; + if( m_store ) { + m_store->lock(); + } + + return; + } + + void AuxInfoBase::clearDecorations() { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Clear the decorations that are in the dynamic store: + if( m_store ) { + m_store->clearDecorations(); + } + + // Reconstruct the list of managed auxiliary IDs from scratch: + m_auxids.clear(); + for( auxid_t auxid = 0; auxid < m_vecs.size(); ++auxid ) { + if( m_vecs[ auxid ] ) { + m_auxids.insert( auxid ); + } + } + if( m_store ) { + for( auto auxid : m_store->getAuxIDs() ) { + m_auxids.insert( auxid ); + } + } + + // Remember that the auxiliary IDs were updated: + ++m_tick; + + return; + } + + size_t AuxInfoBase::size() const { + + // Should really always be 1, but do the general thing anyway... + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Try to find a variable: + auxid_set_t::const_iterator i = m_auxids.begin(); + auxid_set_t::const_iterator end = m_auxids.end(); + for( ; i != end; ++i ) { + if( ( *i < m_vecs.size() ) && m_vecs[ *i ] ) { + size_t sz = m_vecs[ *i ]->size(); + if( sz > 0 ) { + return sz; + } + } + } + + // If we didn't find any statically defined variables, then we just + // need to claim 1. Because pool::AuxStoreAPR at the moment always + // returns 0 for the size. + return 1; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStore functions + // + + void* AuxInfoBase::getData( auxid_t auxid, size_t size, + size_t capacity ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + + if( m_store ) { + size_t nids = m_store->getAuxIDs().size(); + void* result = m_store->getData( auxid, size, capacity ); + if( result && ( nids != m_store->getAuxIDs().size() ) ) { + m_auxids.insert( auxid ); + ++m_tick; + } + return result; + } else { + std::cout << "ERROR xAOD::AuxInfoBase::getData " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + m_vecs[ auxid ]->reserve( capacity ); + m_vecs[ auxid ]->resize( size ); + + return m_vecs[ auxid ]->toPtr(); + } + + const AuxInfoBase::auxid_set_t& + AuxInfoBase::getWritableAuxIDs() const { + + // Return the full list of known IDs. The constness of this object's + // members comes from the object being const or not. + guard_t guard (m_mutex); + if (m_tsAuxids.get() == 0) { + m_tsAuxids.reset (new TSAuxidSet (m_tick, m_auxids)); + } + else if (m_tsAuxids->m_tick != m_tick) { + m_tsAuxids->m_set = m_auxids; // May need to optimize this! + m_tsAuxids->m_tick = m_tick; + } + return m_tsAuxids->m_set; + } + + bool AuxInfoBase::resize( size_t size ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check if the container is locked: + if( m_locked ) { + throw SG::ExcStoreLocked( "resize" ); + } + + // Do a test already here: + if( size != 1 ) { + throw std::runtime_error( "Calling resize with != 1 on a " + "non-vector" ); + } + + // Do the operation on the static variables: + bool nomoves = true; + for (SG::IAuxTypeVector* v : m_vecs) { + if(v) { + if (!v->resize( size )) + nomoves = false; + } + } + + // Do the operation on the dynamic variables: + if( m_store ) { + if (!m_store->resize( size )) + nomoves = false; + } + + return nomoves; + } + + void AuxInfoBase::reserve( size_t size ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check if the container is locked: + if( m_locked ) { + throw SG::ExcStoreLocked( "reserve" ); + } + + // Do a test already here: + if( size != 1 ) { + throw std::runtime_error( "Calling reserve with != 1 on a " + "non-vector" ); + } + + // Do the operation on the static variables: + std::vector< SG::IAuxTypeVector* >::iterator itr = m_vecs.begin(); + std::vector< SG::IAuxTypeVector* >::iterator end = m_vecs.end(); + for( ; itr != end; ++itr ) { + if( *itr ) ( *itr )->reserve( size ); + } + + // Do the operation on the dynamic variables: + if( m_store ) { + m_store->reserve( size ); + } + + return; + } + + void AuxInfoBase::shift( size_t /*pos*/, ptrdiff_t /*offs*/ ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check if the container is locked: + if( m_locked ) { + throw SG::ExcStoreLocked( "shift" ); + } + + // We are just not allowed to do this... + throw std::runtime_error( "Calling shift on a non-vector" ); + + return; + } + + + bool AuxInfoBase::insertMove( size_t /*pos*/, IAuxStore& /*other*/, + const SG::auxid_set_t& /*ignore*/ ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // Check if the container is locked: + if( m_locked ) { + throw SG::ExcStoreLocked( "insertMove" ); + } + + // We are just not allowed to do this... + throw std::runtime_error( "Calling insertMove on a non-vector" ); + + return false; + } + + + bool AuxInfoBase::setOption( auxid_t id, const SG::AuxDataOption& option ) { + + if (id < m_vecs.size() && m_vecs[id] != 0) + return m_vecs[id]->setOption( option ); + if (m_store) + return m_store->setOption( id, option ); + return false; + } + + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStoreIO functions + // + + const void* AuxInfoBase::getIOData( auxid_t auxid ) const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + if( m_storeIO ) { + return m_storeIO->getIOData( auxid ); + } else { + std::cout << "ERROR xAOD::AuxInfoBase::getIOData " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + + // Update the statistics for this variable. The dynamic store registers + // its own variable accesses. + IOStats::instance().stats().readBranch( m_name, auxid ); + + return m_vecs[ auxid ]->toPtr(); + } + + const std::type_info* AuxInfoBase::getIOType( auxid_t auxid ) const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + if( ( auxid >= m_vecs.size() ) || ( ! m_vecs[ auxid ] ) ) { + if( m_storeIO ) { + return m_storeIO->getIOType( auxid ); + } else { + std::cout << "ERROR xAOD::AuxInfoBase::getIOType " + << "Unknown variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + } + + return SG::AuxTypeRegistry::instance().getType( auxid ); + } + + const AuxInfoBase::auxid_set_t& + AuxInfoBase::getDynamicAuxIDs() const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // All the variables handled by the internal store are dynamic + // if such a store exists: + if( m_storeIO ) { + // I mean, all the variables. Not just the ones reported as dynamic + // by the internal object. Because the internal object may be something + // that was put into this one in order to achieve data slimming. + return m_store->getAuxIDs(); + } + + // In case we don't use an internal store, there are no dynamic + // variables: + static const auxid_set_t dummy {}; + return dummy; + } + + void AuxInfoBase::selectAux( const std::set< std::string >& attributes ) { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + m_selection.selectAux( attributes ); + return; + } + + const AuxInfoBase::auxid_set_t& + AuxInfoBase::getSelectedAuxIDs() const { + + // Guard against multi-threaded execution: + guard_t guard( m_mutex ); + + // All the variables handled by the internal store are dynamic + // if such a store exists: + if( m_storeIO ) { + // I mean, all the variables. Not just the ones reported as dynamic + // by the internal object. Because the internal object may be something + // that was put into this one in order to achieve data slimming. + return m_selection.getSelectedAuxIDs( m_store->getAuxIDs() ); + } + + // In case we don't use an internal store, there are no dynamic + // variables: + static auxid_set_t dummy; + return dummy; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + const char* AuxInfoBase::name() const { + + return m_name.c_str(); + } + + void AuxInfoBase::setName( const char* name ) { + + m_name = name; + return; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/AuxSelection.cxx b/EDM/athena/xAOD/xAODCore/Root/AuxSelection.cxx new file mode 100644 index 00000000..b6e503b2 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/AuxSelection.cxx @@ -0,0 +1,136 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxSelection.cxx 653257 2015-03-11 11:26:15Z krasznaa $ + +// System include(s): +#include <iostream> +#include <map> + +// EDM include(s): +#include "AthContainers/AuxTypeRegistry.h" + +// Local include(s): +#include "xAODCore/AuxSelection.h" + +namespace { + + /// Helper variable to only print warning about missing variables once + static std::set< std::string > mentionnedVariableNames; + +} // private namespace + +namespace xAOD { + + AuxSelection::AuxSelection() + : m_names(), + m_auxids() { + + } + + /// Sets which variables should be selected from a store object. + /// The formalism is the following: + /// - An empty set, or a set containing "*" will select all the dynamic + /// attributes passed to the object. + /// - A single "-" attribute will not select any of the dynamic attributes. + /// - A set of variables (without "-" as the first character of the + /// variable names) will select just the variables listed. + /// - A set of variable names, each prefixed by "-", will select all + /// variables but the ones listed. + /// + /// @param attributes The attributes from ItemList or TEvent + /// + void AuxSelection::selectAux( const std::set< std::string >& attributes ) { + + m_names = attributes; + return; + } + + /// This function takes care of interpreting the options passed to + /// ItemList in Athena, and TEvent in ROOT. It filters the list of variables + /// passed to it, and returns the IDs of just the variables that should + /// be written out. + /// + /// @param fullset The variables to be filtered based on the rules received + /// @returns The list of variables to be written out + /// + const SG::auxid_set_t& + AuxSelection::getSelectedAuxIDs( const SG::auxid_set_t& fullset ) const { + + // Check for the simplest case... all variables selected: + if( m_names.empty() || ( m_names.find( "*" ) != m_names.end() ) ) { + return fullset; + } + + // Start from an empty list: + m_auxids.clear(); + + // Check if everything should be disregarded: + if( m_names.find( "-" ) != m_names.end() ) { + return m_auxids; + } + + // Check that the user only put positive or negative selections on the + // list. They can't be mixed. + bool sub = false, add = false; + std::set< std::string >::const_iterator name_itr = m_names.begin(); + std::set< std::string >::const_iterator name_end = m_names.end(); + for( ; name_itr != name_end; ++name_itr ) { + if( ( *name_itr )[ 0 ] == '-' ) { + sub = true; + } else { + add = true; + } + } + if( sub && add ) { + std::cerr << "xAOD::AuxSelection ERROR Mixing + and - options for " + << "dynamic attributes" << std::endl; + return fullset; //better safe than sorry + } + + if( add ) { + // Start with an empty list, and loop over the selected names: + name_itr = m_names.begin(); + name_end = m_names.end(); + for( ; name_itr != name_end; ++name_itr ) { + // Get the ID of this name: + const SG::auxid_t auxid = + SG::AuxTypeRegistry::instance().findAuxID( *name_itr ); + if( auxid != SG::null_auxid ) { + // Add this variable if it exists: + if( fullset.find( auxid ) != fullset.end() ) { + m_auxids.insert( auxid ); + } + } else { + // Check if a warning should be printed at this time or not: + if( ::mentionnedVariableNames.insert( *name_itr ).second ) { + // Apparently we didn't complain about this name yet... + std::cerr << "xAOD::AuxSelection WARNING Selected dynamic " + << "Aux atribute \"" << *name_itr + << "\" not found in the registry" << std::endl; + } + } + } + } else { + // Start from the full list: + m_auxids = fullset; + // ...and check which variables should be removed: + SG::auxid_set_t::const_iterator id_itr = fullset.begin(); + SG::auxid_set_t::const_iterator id_end = fullset.end(); + for( ; id_itr != id_end; ++id_itr ) { + // Construct the name that we need to look for: + const std::string attrname = + "-" + SG::AuxTypeRegistry::instance().getName( *id_itr ); + // Check if it is in the list to be removed: + if( m_names.find( attrname ) != m_names.end() ) { + m_auxids.erase( *id_itr ); + } + } + } + + // Return the list of variables to be written out: + return m_auxids; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/FloatCompressor.cxx b/EDM/athena/xAOD/xAODCore/Root/FloatCompressor.cxx new file mode 100644 index 00000000..b13f7559 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/FloatCompressor.cxx @@ -0,0 +1,68 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: FloatCompressor.cxx 789425 2016-12-13 10:50:12Z krasznaa $ + +// System include(s): +#include <cmath> + +// Local include(s): +#include "xAODCore/tools/FloatCompressor.h" + +namespace xAOD { + + /// Total number of total mantissa bits + static const unsigned int NMANTISSA = 23; + + FloatCompressor::FloatCompressor( unsigned int mantissaBits ) + : m_mantissaBits( mantissaBits ), m_mantissaBitmask( 0 ) { + + // IEEE754 single-precision float + // SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM + // F F 8 0 0 0 7 F + + // Adjust the received bit number to some reasonable value: + if( m_mantissaBits < 5 ) { + m_mantissaBits = 5; + } + if( m_mantissaBits > NMANTISSA ) { + m_mantissaBits = NMANTISSA; + } + + // Fill up the lower N bits: + for( unsigned int i = 0; i < ( NMANTISSA - m_mantissaBits ); ++i ) { + m_mantissaBitmask |= ( 0x1 << i ); + } + // And now negate it to get the correct mask: + m_mantissaBitmask = ~m_mantissaBitmask; + } + + float FloatCompressor::reduceFloatPrecision( float value ) const { + + // Check if any compression is to be made: + if( m_mantissaBits == NMANTISSA ) { + return value; + } + + // Check for NaN, etc: + if( ! std::isfinite( value ) ) { + return value; + } + + // Create the helper object: + floatint_t fi; + fi.fvalue = value; + + //safety-check if value (omitting the sign-bit) is lower than vmax + //(avoid overflow) + if( ( fi.ivalue & 0x7ffffff ) < m_vmax ) { + fi.ivalue += m_rounding; + } + + // Do the compression: + fi.ivalue &= m_mantissaBitmask; + return fi.fvalue; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/IOStats.cxx b/EDM/athena/xAOD/xAODCore/Root/IOStats.cxx new file mode 100644 index 00000000..a2e8ecc6 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/IOStats.cxx @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IOStats.cxx 778387 2016-10-14 00:02:04Z krasznaa $ + +// Local include(s): +#include "xAODCore/tools/IOStats.h" +#include "xAODCore/tools/ReadStats.h" + +namespace xAOD { + + IOStats::~IOStats() { + + // The ReadStats object is not deleted. Since the object may be needed + // during the finalisation of the application. In which case it can lead + // to a race condition which object is deleted first. This one, or the one + // trying to use this one in its destructor. + // delete m_stats; + } + + IOStats& IOStats::instance() { + + static IOStats obj; + return obj; + } + + ReadStats& IOStats::stats() { + + return *m_stats; + } + + const ReadStats& IOStats::stats() const { + + return *m_stats; + } + + IOStats::IOStats() + : m_stats( new ReadStats() ) { + + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/LinkDef.h b/EDM/athena/xAOD/xAODCore/Root/LinkDef.h new file mode 100644 index 00000000..d18f7def --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/LinkDef.h @@ -0,0 +1,38 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: LinkDef.h 750677 2016-05-30 10:24:50Z krasznaa $ +#ifndef XAODCORE_LINKDEF_H +#define XAODCORE_LINKDEF_H + +#ifdef ROOTCORE +// MN: includes needed by RootCore but posing problems in ROOT 6.6.1. remove protection when ROOT-7879 fixed +// Local include(s): +#include "xAODCore/tools/ReadStats.h" +#include "xAODCore/tools/PerfStats.h" +#endif + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ nestedclass; + +#pragma link C++ class xAOD::BranchStats+; +#pragma link C++ class xAOD::ReadStats+; +#pragma link C++ class map<string,xAOD::BranchStats>+; +#pragma link C++ class pair<string,xAOD::BranchStats>+; +#pragma link C++ class xAOD::PerfStats+; + +#ifdef XAOD_STANDALONE +#pragma link C++ class vector<vector<float> >+; +#pragma link C++ class vector<vector<int> >+; +#endif + +#endif // __CINT__ +#endif // XAODCORE_LINKDEF_H diff --git a/EDM/athena/xAOD/xAODCore/Root/PerfStats.cxx b/EDM/athena/xAOD/xAODCore/Root/PerfStats.cxx new file mode 100644 index 00000000..2328445d --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/PerfStats.cxx @@ -0,0 +1,334 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PerfStats.cxx 634033 2014-12-05 14:46:38Z krasznaa $ + +// ROOT include(s): +#include <TTree.h> +#include <TFile.h> +#include <TTimeStamp.h> + +// Local include(s): +#include "xAODCore/tools/PerfStats.h" +#include "xAODCore/tools/Utils.h" +#include "xAODCore/tools/IOStats.h" +#include "xAODCore/tools/ReadStats.h" + +ClassImp( xAOD::PerfStats ) + +namespace xAOD { + + // Initialize the static variable(s): + PerfStats* PerfStats::m_instance = 0; + + /// The destructor is a quite important function in this class. + /// it makes sure that the static m_instance variable gets reset, + /// and that all TVirtualPerfStats objects really get deleted. + /// + PerfStats::~PerfStats() { + + // Since this object can only be deleted by deleting the global + // gPerfStats object, make sure that all the objects get deleted + // if the user asked for it... + m_instance = 0; + if( m_otherPerfStats ) { + delete m_otherPerfStats; + } + } + + /// Everywhere in the code this function should be used to access + /// the one and only PerfStats object in memory. + /// + /// @returns A pointer to the PerfStats singleton + /// + PerfStats& PerfStats::instance() { + + // Construct the object if it is now available at the moment: + if( ! m_instance ) { + m_instance = new PerfStats(); + } + + // Make sure that this is still the object that receives + // monitoring information: + gPerfStats = m_instance; + + return *m_instance; + } + + /// The user is supposed to call this function after the initialization of + /// his/her analysis code finished, but before the event processing starts. + /// + /// @param clear Clear the statistics gathered so far + /// + void PerfStats::start( bool clear ) { + + // Return right away if we are running already: + if( m_running ) return; + + // Clear the statistics collected so far if required: + if( clear ) IOStats::instance().stats().Clear(); + + // Let the user know what we're doing: + Info( "start", "Starting performance monitoring" ); + + // Record the starting time: + m_startTime = TTimeStamp(); + // Remember that we are running: + m_running = true; + + return; + } + + /// The user is supposed to call this function once his/her analysis code + /// finished with the event processing. + /// + void PerfStats::stop() { + + // Return right away if we are not running: + if( ! m_running ) return; + + // Calculate the time elapsed from when the analysis started: + const ::Double_t elapsed = TTimeStamp().AsDouble() - + m_startTime; + // Save it: + ReadStats& stats = IOStats::instance().stats(); + stats.setProcessTime( stats.processTime() + elapsed ); + + // Remember that we are stopped: + m_running = false; + + // Let the user know what we've done: + Info( "stop", "Performance monitoring stopped after %s", + Utils::timeToString( elapsed ).c_str() ); + + return; + } + + void PerfStats::SimpleEvent( EEventType type ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->SimpleEvent( type ); + } + + return; + } + + void PerfStats::PacketEvent( const char* slave, const char* slavename, + const char* filename, + ::Long64_t eventsprocessed, + ::Double_t latency, + ::Double_t proctime, ::Double_t cputime, + ::Long64_t bytesRead ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->PacketEvent( slave, slavename, filename, + eventsprocessed, latency, proctime, + cputime, bytesRead ); + } + + return; + } + + void PerfStats::FileEvent( const char* slave, const char* slavename, + const char* nodename, const char* filename, + ::Bool_t isStart ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->FileEvent( slave, slavename, nodename, filename, + isStart ); + } + + return; + } + + void PerfStats::FileOpenEvent( ::TFile* file, const char* filename, + ::Double_t start ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->FileOpenEvent( file, filename, start ); + } + + return; + } + + /// This function does most of the work of the class. It is called every + /// time ROOT does a file I/O operation. The function takes care of + /// registering this operation in its statistics, and checks if a new file + /// was opened since the last I/O operation. + /// + /// @param file The file object that was read from + /// @param len The number of bytes that were read from the file + /// @param start The time when the read operation started + /// + void PerfStats::FileReadEvent( ::TFile* file, ::Int_t len, + ::Double_t start ) { + + // Do the calculation without delay: + const ::Double_t tnow = TTimeStamp(); + const ::Double_t dtime = tnow - start; + + // Accumulate the reading time statistics: + ReadStats& stats = IOStats::instance().stats(); + stats.setReadTime( stats.readTime() + dtime ); + + // Accumulate the amount of read data: + stats.setBytesRead( stats.bytesRead() + len ); + stats.setFileReads( stats.fileReads() + 1 ); + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->FileReadEvent( file, len, start ); + } + + return; + } + + /// This function is called by ROOT when it needs to unzip some data from a + /// given inpout file. + /// + /// @param file The file the information was read from + /// @param pos Position inside the input file? (Not used.) + /// @param start The time when the unzipping operation started + /// @param complen Not sure. (Not used.) + /// @param objlen Not sure. (Not used.) + /// +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 34, 19 ) + void PerfStats::FileUnzipEvent( ::TFile* file, ::Long64_t pos, + ::Double_t start, ::Int_t complen, + ::Int_t objlen ) { +#else + void PerfStats::UnzipEvent( ::TObject* tree, ::Long64_t pos, + ::Double_t start, ::Int_t complen, + ::Int_t objlen ) { +#endif // ROOT_VERSION + + // Do the calculation without delay: + const ::Double_t tnow = TTimeStamp(); + const ::Double_t dtime = tnow - start; + + // Just accumulate the zipping time statistics: + ReadStats& stats = IOStats::instance().stats(); + stats.setUnzipTime( stats.unzipTime() + dtime ); + +#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 34, 19 ) + // Get the cache size from the tree: + ::TTree* t = dynamic_cast< ::TTree* >( tree ); + if( ! t ) { + Warning( "UnzipEvent", "Couldn't cast object to TTree" ); + } else { + stats.setCacheSize( t->GetCacheSize() ); + } +#endif // ROOT_VERSION + + // Forward the call if possible: + if( m_otherPerfStats ) { +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 34, 19 ) + m_otherPerfStats->FileUnzipEvent( file, pos, start, complen, objlen ); +#else + m_otherPerfStats->UnzipEvent( tree, pos, start, complen, objlen ); +#endif // ROOT_VERSION + } + + return; + } + + void PerfStats::RateEvent( ::Double_t proctime, ::Double_t deltatime, + ::Long64_t eventsprocessed, + ::Long64_t bytesRead ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->RateEvent( proctime, deltatime, eventsprocessed, + bytesRead ); + } + + return; + } + + /// In single process running this function is basically never called. + /// It's only active when running on PROOF, in which case we should not + /// care about the values given to it, but just forward it to + /// TPerfStats. The actual amount of data read for xAOD monitoring + /// is coming in through the FileReadEvent(...) function... + /// + /// @param num Number of bytes read in "some operation" + /// + void PerfStats::SetBytesRead( ::Long64_t num ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->SetBytesRead( num ); + } + + return; + } + + ::Long64_t PerfStats::GetBytesRead() const { + + // Forward the call if possible: + if( m_otherPerfStats ) { + return m_otherPerfStats->GetBytesRead(); + } else { + return IOStats::instance().stats().bytesRead(); + } + } + + /// This function is not called with anything meaningful in standalone + /// ROOT analyses, so it just forwards the call to a possible other + /// TVirtualPerfStats object. + /// + /// @param num Number of processed events + /// + void PerfStats::SetNumEvents( ::Long64_t num ) { + + // Forward the call if possible: + if( m_otherPerfStats ) { + m_otherPerfStats->SetNumEvents( num ); + } + + return; + } + + /// The function just gets the number of events from the other + /// TVirtualPerfStats object if it exists, otherwise it just returns + /// zero. + /// + /// @returns The number of processed events + /// + ::Long64_t PerfStats::GetNumEvents() const { + + // Forward the call if possible: + if( m_otherPerfStats ) { + return m_otherPerfStats->GetNumEvents(); + } + + return 0; + } + + /// The constructor needs to do a few things. If there is already + /// another TVirtualPerfStats object defined under gPerfStats, then + /// it stores that pointer in order to be able to forward monitoring + /// information to that object later on. It then overwrites + /// gPerfStats to point to this object. + /// + PerfStats::PerfStats() + : m_otherPerfStats( 0 ), m_running( false ), m_startTime( 0.0 ), + m_tree( 0 ), m_file( 0 ), m_treeWarningPrinted( false ) { + + // Remember a possible former performance monitoring object: + if( gPerfStats && ( gPerfStats != this ) ) { + m_otherPerfStats = gPerfStats; + Info( "PerfStats", + "Will forward calls to former gPerfStats object" ); + } + + // This object is now the performance monitoring object: + gPerfStats = this; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/PrintHelpers.cxx b/EDM/athena/xAOD/xAODCore/Root/PrintHelpers.cxx new file mode 100644 index 00000000..7c0ccd8d --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/PrintHelpers.cxx @@ -0,0 +1,149 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PrintHelpers.cxx 780624 2016-10-26 22:41:13Z ssnyder $ + +// System include(s): +#include <iostream> +#include <stdint.h> + +// EDM include(s): +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxTypeRegistry.h" + +// Local include(s): +#include "xAODCore/tools/PrintHelpers.h" + +/// Helper operator to pretty-print the values of vectors +template< typename T > +std::ostream& operator<< ( std::ostream& out, const std::vector< T >& vec ) { + + out << "["; + for( size_t i = 0; i < vec.size(); ++i ) { + out << vec[ i ]; + if( i < vec.size() - 1 ) { + out << ", "; + } + } + out << "]"; + + // Return the same stream: + return out; +} + +std::ostream& operator<< ( std::ostream& out, const SG::AuxElement& obj ) { + + // Start off with some basic information: + out << "SG::AuxElement\n"; + out << " "; + if( obj.usingStandaloneStore() ) { + out << "using standalone store " << obj.getConstStore() << "\n"; + } else if( obj.usingPrivateStore() ) { + out << "using private store " << obj.getConstStore() << "\n"; + } else if( obj.container() ) { + out << "in container " << obj.container() << "\n"; + } else { + // If there's no auxiliary store, bail now: + out << "standalone object, without auxiliary store"; + return out; + } + + // If the container doesn't have an auxiliary store, bail now: + if( ! obj.container()->getConstStore() ) { + return out; + } + + out << " Variables:"; + + // Get a convenience pointer to the aux type registry: + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + // Get the auxiliary IDs of the object: + const SG::auxid_set_t& auxids = + ( obj.container()->getConstStore() ? + obj.container()->getConstStore()->getAuxIDs() : + obj.getConstStore()->getAuxIDs() ); + + // Sort auxids to get predictable ordering. + std::vector<SG::auxid_t> auxids_v (auxids.begin(), auxids.end()); + std::sort (auxids_v.begin(), auxids_v.end()); + + for( SG::auxid_t auxid : auxids_v ) { + + out << "\n - type: " << reg.getTypeName( auxid ) + << ", \tname: \"" << reg.getName( auxid ); + out << "\", \tvalue: "; + +/// Helper macro to make the code slightly shorter +#define PRINTER( TYPE ) \ + do { \ + if( obj.isAvailable< TYPE >( reg.getName( auxid ) ) ) { \ + out << obj.auxdata< TYPE >( reg.getName( auxid ) ); \ + } \ + } while( 0 ) + + // The type of the variable: + const std::type_info* ti = reg.getType( auxid ); + if( *ti == typeid( int8_t ) ) { + out << static_cast< int >( obj.auxdata< int8_t >( reg.getName( auxid ) ) ); + } else if( *ti == typeid( uint8_t ) ) { + out << static_cast< int >( obj.auxdata< uint8_t >( reg.getName( auxid ) ) ); + } else if( *ti == typeid( int16_t ) ) { + PRINTER( int16_t ); + } else if( *ti == typeid( uint16_t ) ) { + PRINTER( uint16_t ); + } else if( *ti == typeid( int32_t ) ) { + PRINTER( int32_t ); + } else if( *ti == typeid( uint32_t ) ) { + PRINTER( uint32_t ); + } else if( *ti == typeid( int64_t ) ) { + PRINTER( int64_t ); + } else if( *ti == typeid( uint64_t ) ) { + PRINTER( uint64_t ); + } else if( *ti == typeid( long ) ) { + PRINTER( long ); + } else if( *ti == typeid( unsigned long ) ) { + PRINTER( unsigned long ); + } else if( *ti == typeid( float ) ) { + PRINTER( float ); + } else if( *ti == typeid( double ) ) { + PRINTER( double ); + } else if( *ti == typeid( std::vector< float > ) ) { + PRINTER( std::vector< float > ); + } else if( *ti == typeid( std::vector< double > ) ) { + PRINTER( std::vector< double > ); + } else if( *ti == typeid( std::vector< int16_t > ) ) { + PRINTER( std::vector< int16_t > ); + } else if( *ti == typeid( std::vector< uint16_t > ) ) { + PRINTER( std::vector< uint16_t > ); + } else if( *ti == typeid( std::vector< int32_t > ) ) { + PRINTER( std::vector< int32_t > ); + } else if( *ti == typeid( std::vector< uint32_t > ) ) { + PRINTER( std::vector< uint32_t > ); + } else if( *ti == typeid( std::vector< int64_t > ) ) { + PRINTER( std::vector< int64_t > ); + } else if( *ti == typeid( std::vector< uint64_t > ) ) { + PRINTER( std::vector< uint64_t > ); + } else { + out << "N/A"; + } + +// Get rid of the temporary macro... +#undef PRINTER + } + + // Return the same stream: + return out; +} + +namespace xAOD { + + void dump( const SG::AuxElement& obj ) { + + // Do the printout simply using the operator: + std::cout << obj << std::endl; + return; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/ReadStats.cxx b/EDM/athena/xAOD/xAODCore/Root/ReadStats.cxx new file mode 100644 index 00000000..a7100bdf --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/ReadStats.cxx @@ -0,0 +1,1456 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ReadStats.cxx 642099 2015-01-27 16:43:18Z krasznaa $ + +// System include(s): +#include <cstring> +#include <functional> +#include <algorithm> + +// ROOT include(s): +#include <TCollection.h> +#include <TTree.h> +#include <TH1.h> + +// EDM include(s): +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/normalizedTypeinfoName.h" + +// Local include(s): +#include "xAODCore/tools/ReadStats.h" +#include "xAODCore/tools/Utils.h" + +ClassImp( xAOD::BranchStats ) +ClassImp( xAOD::ReadStats ) + +namespace { + + /// Strict weak ordering based on the number of entries read from a branch + /// + /// This helper function is used together with the STL std::sort algorithm + /// to sort the xAOD branches based on how many events were read in from + /// them. + /// + /// @param b1 The first branch's access statistics + /// @param b2 The second branch's access statistics + /// @returns <code>true</code> if the first branch was accessed more times + /// than the second one. <code>false</code> otherwise. + /// + bool sortByEntries( const xAOD::BranchStats& b1, + const xAOD::BranchStats& b2 ) { + + return ( b1.readEntries() > b2.readEntries() ); + } + + /// Strict weak ordering based on the number of bytes unpacked from a branch + /// + /// This helper function is used together with the STL std::sort algorithm + /// to sort the xAOD branches based on how much data was unpacked from them. + /// + /// @param b1 The first branch's access statistics + /// @param b2 The second branch's access statistics + /// @returns <code>true</code> if the first variable unpacked more data + /// than the second one. <code>true</code> otherwise. + /// + bool sortByUnzippedBytes( const xAOD::BranchStats& b1, + const xAOD::BranchStats& b2 ) { + + return ( b1.unzippedBytesRead() > b2.unzippedBytesRead() ); + } + + /// Smart class for selecting branches for caching + /// + /// This class can be used to select branches for the cache which + /// were accessed more than some number of times in a previous job. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 642099 $ + /// $Date: 2015-01-27 17:43:18 +0100 (Tue, 27 Jan 2015) $ + /// + class SelectByEntries : + public std::unary_function< const xAOD::BranchStats&, bool > { + + public: + /// Constructor specifying the minimum number of entries + SelectByEntries( ::Long64_t entries ) : m_entries( entries ) {} + /// Constructor finding the minimum number of entries + SelectByEntries( const xAOD::ReadStats::Map_t& branches, + ::Double_t minEvFrac ) + : m_entries( 0 ) { + + ::Long64_t maxEntries = 0; + xAOD::ReadStats::Vector_t::const_iterator vitr, vend; + xAOD::ReadStats::Map_t::const_iterator itr = branches.begin(); + xAOD::ReadStats::Map_t::const_iterator end = branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + if( ( *vitr )->readEntries() > maxEntries ) { + maxEntries = ( *vitr )->readEntries(); + } + } + } + + m_entries = static_cast< ::Long64_t >( minEvFrac * maxEntries ); + } + + /// Operator evaluating if a variable should be selected + result_type operator()( argument_type var ) const { + + if( var.readEntries() < m_entries ) { + return false; + } else { + return true; + } + } + + private: + ::Long64_t m_entries; ///< Minimum number of entries for the branch + + }; // class SelectByEntries + + /// Smart class for selecting branches for caching + /// + /// This class can be used to select branches for the cache from which + /// more than some number bytes were read in a previous job. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 642099 $ + /// $Date: 2015-01-27 17:43:18 +0100 (Tue, 27 Jan 2015) $ + /// + class SelectByBytes : + public std::unary_function< const xAOD::BranchStats&, bool > { + + public: + /// Constructor specifying the minimum number of bytes read + SelectByBytes( ::Long64_t bytes ) : m_bytes( bytes ) {} + + /// Constructor finding the minimum number of bytes read + SelectByBytes( const xAOD::ReadStats::Map_t& branches, + ::Double_t minByteFrac ) + : m_bytes( 0 ) { + + ::Long64_t maxBytes = 0; + xAOD::ReadStats::Vector_t::const_iterator vitr, vend; + xAOD::ReadStats::Map_t::const_iterator itr = branches.begin(); + xAOD::ReadStats::Map_t::const_iterator end = branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + if( ( *vitr )->zippedBytesRead() > maxBytes ) { + maxBytes = ( *vitr )->zippedBytesRead(); + } + } + } + + m_bytes = static_cast< ::Long64_t >( minByteFrac * maxBytes ); + } + + /// Operator evaluating if a variable should be selected + result_type operator()( argument_type var ) const { + + if( var.zippedBytesRead() < m_bytes ) { + return false; + } else { + return true; + } + } + + private: + ::Long64_t m_bytes; ///< Minimum number of bytes read from the branch + + }; // class SelectByBytes + + /// Function adding branches to the TTreeCache + /// + /// The code internally uses this function to select which branches to add + /// to the TTreeCache. + /// + /// @param tree The TTree to enable the caching for + /// @param branches All the xAOD branches we know about + /// @param selector Functor selecting the branches to cache + /// @returns The number of branches added to the cache + /// + template< class SELECTOR > + int addToCache( ::TTree* tree, const xAOD::ReadStats::Map_t& branches, + const SELECTOR& selector ) { + + int result = 0; + + xAOD::ReadStats::Map_t::const_iterator itr = branches.begin(); + xAOD::ReadStats::Map_t::const_iterator end = branches.end(); + for( ; itr != end; ++itr ) { + for( size_t auxid = 0; auxid < itr->second.size(); ++auxid ) { + if( ! itr->second[ auxid ] ) continue; + if( ! selector( *( itr->second[ auxid ] ) ) ) continue; + if( tree ) { + const std::string brName = itr->first + + SG::AuxTypeRegistry::instance().getName( auxid ); + tree->AddBranchToCache( brName.c_str(), kTRUE ); + } + ++result; + } + } + + return result; + } + + /// Function selecting branches with some condition + /** + * This function is used internally to select branch names. + * + * @param branches All the xAOD branches we know about + * @param selector Functor selecting the variables + * @returns The selected branch names + */ + template< class SELECTOR > + std::vector< std::string > + getBranches( const xAOD::ReadStats::Map_t& branches, + const SELECTOR& selector ) { + + // The result object: + std::vector< std::string > result; + + // Iterate over all the variables: + xAOD::ReadStats::Map_t::const_iterator itr = branches.begin(); + xAOD::ReadStats::Map_t::const_iterator end = branches.end(); + for( ; itr != end; ++itr ) { + for( size_t auxid = 0; auxid < itr->second.size(); ++auxid ) { + // Check if the object exists: + if( ! itr->second[ auxid ] ) continue; + // Ignore the ones failing the selection: + if( ! selector( *( itr->second[ auxid ] ) ) ) continue; + // Add this variable to the result: + const std::string brName = itr->first + + SG::AuxTypeRegistry::instance().getName( auxid ); + result.push_back( brName ); + } + } + + return result; + } + +} // private namespace + +namespace xAOD { + + /// The constructor can specify all properties of the object in one go. All + /// the parameters take a default value, to make it possible to create the + /// object without giving the constructor any parameters. (Needed by CINT.) + /// + /// @param name Name of the variable being described + /// @param type Full type name of the variable being described + /// @param nTreesAccessed Number of TTrees accessed to read this variable + /// @param nReadEntries Number of GetEntry(...) operations performed on this + /// branch + /// @param nUnzippedBytes Number of bytes read after decompression + /// @param nZippedBytes Number of bytes physically read from disk + /// + BranchStats::BranchStats( const char* name, const char* type, + ::Int_t nTreesAccessed, ::Long64_t nReadEntries, + ::Long64_t nUnzippedBytes, ::Long64_t nZippedBytes ) + : TNamed( name, type ), m_treesAccessed( nTreesAccessed ), + m_readEntries( nReadEntries ), m_unzippedBytes( nUnzippedBytes ), + m_zippedBytes( nZippedBytes ) { + + } + + /// It's probably not needed actually, but I wanted to be explicit about + /// how the copy constructor should behave. + /// + /// @param parent The object that's being copied + /// + BranchStats::BranchStats( const BranchStats& parent ) + : TNamed( parent ), m_treesAccessed( parent.m_treesAccessed ), + m_readEntries( parent.m_readEntries ), + m_unzippedBytes( parent.m_unzippedBytes ), + m_zippedBytes( parent.m_zippedBytes ) { + + } + + /// The assignment operator is quite an important piece of code, as it's + /// used all the time when using such objects in STL containers. + /// + /// @param parent The object that's being copied + /// @returns A reference to the copied object + /// + BranchStats& BranchStats::operator= ( const BranchStats& parent ) { + + // Check for self-assignment: + if( &parent == this ) { + return *this; + } + + // Set the properties of TNamed: + SetName( parent.GetName() ); + SetTitle( parent.GetTitle() ); + + // Set the properties of this class: + m_treesAccessed = parent.m_treesAccessed; + m_readEntries = parent.m_readEntries; + m_unzippedBytes = parent.m_unzippedBytes; + m_zippedBytes = parent.m_zippedBytes; + + return *this; + } + + ::Int_t BranchStats::treesAccessed() const { + + return m_treesAccessed; + } + + void BranchStats::setTreesAccessed( ::Int_t nTreesAccessed ) { + + m_treesAccessed = nTreesAccessed; + return; + } + + ::Long64_t BranchStats::readEntries() const { + + return m_readEntries; + } + + void BranchStats::setReadEntries( ::Long64_t nReadEntries ) { + + m_readEntries = nReadEntries; + return; + } + + ::Long64_t BranchStats::unzippedBytesRead() const { + + return m_unzippedBytes; + } + + void BranchStats::setUnzippedBytesRead( ::Long64_t nUnzippedBytes ) { + + m_unzippedBytes = nUnzippedBytes; + return; + } + + ::Long64_t BranchStats::zippedBytesRead() const { + + return m_zippedBytes; + } + + void BranchStats::setZippedBytesRead( ::Long64_t nZippedBytes ) { + + m_zippedBytes = nZippedBytes; + return; + } + + BranchStats& BranchStats::add( const BranchStats& rh ) { + + // Set the properties of TNamed: + SetName( rh.GetName() ); + SetTitle( rh.GetTitle() ); + + // Accumulate the gathered statistics: + m_treesAccessed += rh.m_treesAccessed; + m_readEntries += rh.m_readEntries; + m_unzippedBytes += rh.m_unzippedBytes; + m_zippedBytes += rh.m_zippedBytes; + + return *this; + } + + BranchStats& BranchStats::operator+= ( const BranchStats& rh ) { + + return add( rh ); + } + + /// This function makes it possible to properly merge objects coming from + /// PROOF workers, or to properly merge objects saved in ROOT files. + /// + /// @param coll A collection of xAOD::BranchStats objects + /// @returns <code>0</code> in case of failure, a positive number + /// in case of success + /// + ::Int_t BranchStats::Merge( ::TCollection* coll ) { + + // Some security checks: + if( ! coll ) return 0; + if( coll->IsEmpty() ) return 0; + + // Iterate over the elements of the collection: + ::TIter next( coll ); + ::TObject* obj = 0; + ::Int_t result = 0; + while( ( obj = next() ) ) { + + // Check that the element is of the right type: + BranchStats* vobj = dynamic_cast< BranchStats* >( obj ); + if( ! vobj ) { + Error( "Merge", "Unknown object type encountered: %s", + obj->ClassName() ); + return 0; + } + + // Add this element to this object: + add( *vobj ); + ++result; + } + + // Return how many objects were merged into this one: + return result; + } + + /// Standard ROOT printing function. It prints all information about the + /// statistics gathered about a single xAOD branch. + /// + /// The option parameter understands the following value(s): + /// - "All": Prints the most verbose information available + /// + /// @param option Possible options for the printing verbosity + /// + void BranchStats::Print( ::Option_t* option ) const { + + // Print the most basic info: + Info( "Print", "Branch name \"%s\", type \"%s\", read %lli times", + GetName(), GetTitle(), m_readEntries ); + + // Print the access statistics only if requested: + if( ! ::strcmp( option, "All" ) ) { + Info( "Print", " TTrees accessed for this branch: %i", + m_treesAccessed ); + Info( "Print", " Number of entries read : %lli", + m_readEntries ); + Info( "Print", " Number of unzipped bytes read : %lli", + m_unzippedBytes ); + Info( "Print", " Number of zipped bytes read : %lli", + m_zippedBytes ); + } + + return; + } + + /// In order to be able to stream such objects, they have to have an + /// explicit name. It can be specified using this constructor, but + /// usually leaving the default is just fine. + /// + /// @param name Name for the object + /// @param title Optional title for the object (not used for anything) + /// + ReadStats::ReadStats( const char* name, const char* title ) + : ::TNamed( name, title ), m_branches(), m_containers(), + m_bytesRead( 0 ), m_branchNum( 0 ), + m_fileReads( 0 ), m_cacheSize( 0 ), m_readTime( 0.0 ), + m_unzipTime( 0.0 ), m_processTime( 0.0 ), + m_nEvents( 0 ), m_nEventsProcessed ( 0 ) { + + } + + /// It's probably not needed actually, but I wanted to be explicit about + /// how the copy constructor should behave. + /// + /// @param parent The object that's being copied + /// + ReadStats::ReadStats( const ReadStats& parent ) + : ::TNamed( parent ), m_branches( parent.m_branches ), + m_containers(parent.m_containers), + m_bytesRead( parent.m_bytesRead ), m_branchNum( parent.m_branchNum ), + m_fileReads( parent.m_fileReads ), m_cacheSize( parent.m_cacheSize ), + m_readTime( parent.m_readTime ), + m_unzipTime( parent.m_unzipTime ), + m_processTime( parent.m_processTime ), + m_nEvents( parent.m_nEvents ), + m_nEventsProcessed( parent.m_nEventsProcessed ){ + + } + + /// The destructor needs to clean up all the BranchStats objects that were + /// created on the heap. + /// + ReadStats::~ReadStats() { + + Map_t::iterator mitr = m_branches.begin(); + Map_t::iterator mend = m_branches.end(); + for( ; mitr != mend; ++mitr ) { + Vector_t::iterator vitr = mitr->second.begin(); + Vector_t::iterator vend = mitr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + delete *vitr; + } + } + } + + /// This is probably not needed either, but again, I wanted to be + /// explicit. + /// + /// @param parent The object that's being copied + /// @returns A reference to the copied object + /// + ReadStats& ReadStats::operator= ( const ReadStats& parent ) { + + // Check for self-assignment: + if( &parent == this ) { + return *this; + } + + // Set the properties of TNamed: + SetName( parent.GetName() ); + SetTitle( parent.GetTitle() ); + + // Set the properties of this class: + m_branches = parent.m_branches; + m_containers = parent.m_containers; + m_bytesRead = parent.m_bytesRead; + m_branchNum = parent.m_branchNum; + m_fileReads = parent.m_fileReads; + m_cacheSize = parent.m_cacheSize; + m_readTime = parent.m_readTime; + m_unzipTime = parent.m_unzipTime; + m_processTime = parent.m_processTime; + m_nEvents = parent.m_nEvents; + m_nEventsProcessed = parent.m_nEventsProcessed; + + return *this; + } + + void ReadStats::Clear( ::Option_t* ) { + + // Clear all accumulated statistics: + m_branches.clear(); + m_containers.clear(); + m_bytesRead = 0; + m_branchNum = 0; + m_fileReads = 0; + m_cacheSize = 0; + m_readTime = 0.0; + m_unzipTime = 0.0; + m_processTime = 0.0; + m_nEvents = 0; + m_nEventsProcessed = 0; + + return; + } + + void ReadStats::setBytesRead( ::Long64_t num ) { + + m_bytesRead = num; + return; + } + + ::Long64_t ReadStats::bytesRead() const { + + return m_bytesRead; + } + + void ReadStats::setBranchNum( ::Int_t num ) { + + m_branchNum = num; + return; + } + + ::Int_t ReadStats::branchNum() const { + + return m_branchNum; + } + + void ReadStats::setFileReads( ::Int_t num ) { + + m_fileReads = num; + return; + } + + ::Int_t ReadStats::fileReads() const { + + return m_fileReads; + } + + void ReadStats::setCacheSize( ::Int_t size ) { + + m_cacheSize = size; + return; + } + + ::Int_t ReadStats::cacheSize() const { + + return m_cacheSize; + } + + void ReadStats::setReadTime( ::Double_t time ) { + + m_readTime = time; + return; + } + + ::Double_t ReadStats::readTime() const { + + return m_readTime; + } + + void ReadStats::setUnzipTime( ::Double_t time ) { + + m_unzipTime = time; + return; + } + + ::Double_t ReadStats::unzipTime() const { + + return m_unzipTime; + } + + void ReadStats::setProcessTime( ::Double_t time ) { + + m_processTime = time; + return; + } + + ::Double_t ReadStats::processTime() const { + + return m_processTime; + } + + /// This function is used to access a branch's description for modification. + /// The function creates the description object if it doesn't exist yet. + /// + /// @param prefix The prefix for the xAOD branch + /// @param auxid The auxiliary ID of the variable belonging to the branch + /// @returns A pointer to the object holding the access statistics + /// + BranchStats* ReadStats::branch( const std::string& prefix, + SG::auxid_t auxid ) { + + Vector_t& vec = m_branches[ prefix ]; + // Check if it's big enough: + if( vec.size() <= auxid ) { + vec.resize( auxid + 1 ); + } + // Check if the object exists already: + if( ! vec[ auxid ] ) { + // Construct its name, mangling needed for dynamic variables: + const std::string brName = prefix + + SG::AuxTypeRegistry::instance().getName( auxid ); + const std::type_info* brType = + SG::AuxTypeRegistry::instance().getType( auxid ); + if( ! brType ) { + Error( "branch", "Coudln't find type_info for aux ID %i", + static_cast< int >( auxid ) ); + return 0; + } + const std::string brTypeName = SG::normalizedTypeinfoName( *brType ); + + // Construct the new object: + vec[ auxid ] = new BranchStats( brName.c_str(), brTypeName.c_str() ); + } + + // Return the object: + return vec[ auxid ]; + } + + /// Get the access statistics of a single xAOD branch + /// + /// @param prefix The prefix for the xAOD branch + /// @param auxid The auxiliary ID of the variable belonging to the branch + /// @returns A pointer to the object describing the access statistics, + /// or a null pointer if the branch is unknown + /// + const BranchStats* ReadStats::branch( const std::string& prefix, + SG::auxid_t auxid ) const { + + // Search for the variable: + Map_t::const_iterator itr = m_branches.find( prefix ); + if( itr != m_branches.end() ) { + const Vector_t& vec = itr->second; + if( ( vec.size() > auxid ) && vec[ auxid ] ) { + return vec[ auxid ]; + } + } + + // Return a null pointer if the object was not found: + return 0; + } + + BranchStats* ReadStats::container( const std::string& name ) { + + // If it doesn't exist yet, create it now: + if( m_containers.find( name ) == m_containers.end() ) { + // Give it a starting value: + m_containers[ name ] = BranchStats( name.c_str(), "CONTAINER" ); + } + + // Return a pointer to the object: + return &( m_containers[ name ] ); + } + + const BranchStats* ReadStats::container( const std::string& name ) const { + + // Try to find it: + MapC_t::const_iterator itr = m_containers.find( name ); + if( itr != m_containers.end() ) { + return &( itr->second ); + } + + // We didn't find it: + return 0; + } + + const ReadStats::Map_t& ReadStats::branches() const { + + return m_branches; + } + + const ReadStats::MapC_t& ReadStats::containers() const { + + return m_containers; + } + + /// This function checks whether two objects are "compatible" with + /// each other. This just means that it checks whether it appears as + /// if the two statistics objects would've been recorded from the same + /// input type or not. + /// + /// @param rh Object to compare to this object + /// @returns <code>true</code> if the two objects are compatible, + /// <code>false</code> otherwise + /// + bool ReadStats::isCompatible( const ReadStats& rh ) const { + + if( ( m_branchNum == rh.branchNum() ) && + ( m_cacheSize == rh.cacheSize() ) ) { + return true; + } else { + return false; + } + } + + /// This function is used to merge the information from two objects. + /// + /// @param rh The object to be merged into this one + /// @returns A reference to the merged object + /// + ReadStats& ReadStats::add( const ReadStats& rh ) { + + // Merge the variable statistics one by one: + Map_t::const_iterator itr = rh.m_branches.begin(); + Map_t::const_iterator end = rh.m_branches.end(); + for( ; itr != end; ++itr ) { + const Vector_t& rhvec = itr->second; + Vector_t& vec = m_branches[ itr->first ]; + if( vec.size() < rhvec.size() ) { + vec.resize( rhvec.size() ); + } + for( size_t auxid = 0; auxid < rhvec.size(); ++auxid ) { + if( ! rhvec[ auxid ] ) continue; + if( ! vec[ auxid ] ) { + vec[ auxid ] = new BranchStats(); + } + vec[ auxid ]->add( *( rhvec[ auxid ] ) ); + } + } + + // Sum up the simple statistics: + m_bytesRead += rh.m_bytesRead; + m_fileReads += rh.m_fileReads; + m_readTime += rh.m_readTime; + m_unzipTime += rh.m_unzipTime; + m_processTime += rh.m_processTime; + + return *this; + } + + ReadStats& ReadStats::operator+= ( const ReadStats& rh ) { + + return add( rh ); + } + + /// This function can be used to add all the branches that this object + /// knows about, to the cache of the TTree given to the function. + /// + /// It can be useful for blankly enabling caching for all the variables + /// that an xAOD analysis accessed previously. + /// + /// @param tree Tree for which the caching should be configured + /// + void ReadStats::addToTreeCache( ::TTree* tree ) const { + + // Add all the branches to the cache: + const int counter = addToCache( tree, m_branches, + SelectByEntries( 0 ) ); + + // Let the user know what we did: + Info( "addToTreeCache", "Added %i branches to the TTreeCache", + counter ); + + return; + } + + /// This should be one of the most useful functions of this class. It can + /// be used to selectively enable the caching for the branches which were + /// accessed more than a specified number of times in a previous running. + /// + /// @param tree Tree for which the caching should be configured + /// @param minEntries Minimum number of entries read from the variable to + /// qualify for caching + /// + void ReadStats::addToTreeCacheByEntries( ::TTree* tree, + ::Long64_t minEntries ) const { + + // Add the selected branches to the cache: + const int counter = addToCache( tree, m_branches, + SelectByEntries( minEntries ) ); + + // Let the user know what we did: + Info( "addToTreeCacheByEntries", "Added %i branches to the TTreeCache", + counter ); + + return; + } + + /// This should be one of the most useful functions of this class. It can + /// be used to selectively enable the caching for the branches which were + /// accessed more than a specified fraction of times in a previous running. + /// This is slightly more general than the version of this function expecting + /// an absolute entry number. + /// + /// @param tree Tree for which the caching should be configured + /// @param minEvFraction Minimum fraction of entries read from the branches + /// that should be added to the cache + /// + void ReadStats::addToTreeCacheByEntryFrac( ::TTree* tree, + ::Double_t minEvFraction ) const { + + // Add the selected branches to the cache: + const int counter = addToCache( tree, m_branches, + SelectByEntries( m_branches, + minEvFraction ) ); + + // Let the user know what we did: + Info( "addToTreeCacheByEntries", "Added %i branches to the TTreeCache", + counter ); + + return; + } + + /// This function can be used to add all the variables to the cache + /// from which more than some bytes were read in a previous running. + /// + /// @param tree Tree for which the caching should be configured + /// @param minBytes Minimum number of bytes read from the variable to + /// qualify for caching + /// + void ReadStats::addToTreeCacheByBytes( ::TTree* tree, + ::Long64_t minBytes ) const { + + // Add the selected branches to the cache: + const int counter = addToCache( tree, m_branches, + SelectByBytes( minBytes ) ); + + // Let the user know what we did: + Info( "addToTreeCacheByBytes", "Added %i branches to the TTreeCache", + counter ); + + return; + } + + /// This function can be used to add all the variables to the cache + /// from which more than some fraction of the bytes were read in a + /// previous running. + /// + /// @param tree Tree for which the caching should be configured + /// @param minByteFraction Minimum fraction of bytes read from the + /// variable to qualify for caching + /// + void + ReadStats::addToTreeCacheByByteFrac( ::TTree* tree, + ::Double_t minByteFraction ) const { + + // Add the selected branches to the cache: + const int counter = addToCache( tree, m_branches, + SelectByBytes( m_branches, + minByteFraction ) ); + + // Let the user know what we did: + Info( "addToTreeCacheByBytes", "Added %i branches to the TTreeCache", + counter ); + + return; + } + + /// This function can be used to get a list of branch names that were + /// accessed more than a specified number of times in the analysis. + /// + /// @param minEntries Minimum number of entries read from the variables + /// @returns A list of branch names fulfilling the requirement + /// + std::vector< std::string > + ReadStats::branchesByEntries( ::Long64_t minEntries ) const { + + return getBranches( m_branches, SelectByEntries( minEntries ) ); + } + + /// This function can be used to get a list of branch names that were + /// accessed more than some fraction of times in the analysis. + /// + /// @param minEvFrac Minimum fraction of entries read from the variables + /// @returns A list of branch names fulfilling the requirement + /// + std::vector< std::string > + ReadStats::branchesByEntryFrac( ::Double_t minEvFrac ) const { + + return getBranches( m_branches, + SelectByEntries( m_branches, minEvFrac ) ); + } + + /// This function can be used to get a list of branch names from which + /// more than a specified number of bytes were read in the analysis. + /// + /// @param minBytes Minimum number of bytes read from the variables + /// @returns A list of branch names fulfilling the requirement + /// + std::vector< std::string > + ReadStats::branchesByBytes( ::Long64_t minBytes ) const { + + return getBranches( m_branches, SelectByBytes( minBytes ) ); + } + + /// This function can be used to get a list of branch names from which + /// more than a specified fraction of bytes were read in the analysis. + /// + /// @param minByteFraction Minimum fraction of bytes read from the + /// variables + /// @returns A list of branch names fulfilling the requirement + /// + std::vector< std::string > + ReadStats::branchesByByteFrac( ::Double_t minByteFraction ) const { + + return getBranches( m_branches, + SelectByBytes( m_branches, minByteFraction ) ); + } + + /// This function can be used to produce a nice histogram showing how many + /// TTrees were accessed by how many of the branches. + /// + /// Note that the caller is responsible for deleting the created histogram. + /// + /// @returns The histogram showing the distribution + /// + ::TH1* ReadStats::treeAccessStat() const { + + // Find the branch(es) which accessed the most trees: + ::Long64_t maxTrees = 0; + Vector_t::const_iterator vitr, vend; + Map_t::const_iterator itr = m_branches.begin(); + Map_t::const_iterator end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + if( ( *vitr )->treesAccessed() > maxTrees ) { + maxTrees = ( *vitr )->treesAccessed(); + } + } + } + + // Create the histogram: + ::TH1* result = new ::TH1D( "TreeAccessStat", + "TTree access statistics;TTrees;Branches", + 100, 0.0, ( ( ::Double_t ) maxTrees ) * 1.1 ); + + // Fill the histogram by looping over the variables once more: + itr = m_branches.begin(); + end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + result->Fill( ( ::Double_t ) ( *vitr )->treesAccessed() ); + } + } + + return result; + } + + /// This function can be used to produce a nice histogram showing how many + /// entries were accessed by how many of the branches. + /// + /// Note that the caller is responsible for deleting the created histogram. + /// + /// @returns The histogram showing the distribution + /// + ::TH1* ReadStats::entryReadStat() const { + + // Find the branch(es) which accessed the most entries: + ::Long64_t maxEntries = 0; + Vector_t::const_iterator vitr, vend; + Map_t::const_iterator itr = m_branches.begin(); + Map_t::const_iterator end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + if( ( *vitr )->readEntries() > maxEntries ) { + maxEntries = ( *vitr )->readEntries(); + } + } + } + + // Create the histogram: + ::TH1* result = new ::TH1D( "EntryAccessStat", + "Entry access statistics;Entries;Branches", + 100, 0.0, + ( ( ::Double_t ) maxEntries ) * 1.1 ); + + // Fill the histogram by looping over the variables once more: + itr = m_branches.begin(); + end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + result->Fill( ( ::Double_t ) ( *vitr )->readEntries() ); + } + } + + return result; + } + + /// This function can be used to produce a nice histogram showing how many + /// raw bytes were accessed by how many of the branches. + /// + /// Note that the caller is responsible for deleting the created histogram. + /// + /// @returns The histogram showing the distribution + /// + ::TH1* ReadStats::zippedByteReadStat() const { + + // Find the branch(es) which accessed the most bytes: + ::Long64_t maxBytes = 0; + Vector_t::const_iterator vitr, vend; + Map_t::const_iterator itr = m_branches.begin(); + Map_t::const_iterator end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + if( ( *vitr )->zippedBytesRead() > maxBytes ) { + maxBytes = ( *vitr )->zippedBytesRead(); + } + } + } + + // Create the histogram: + ::TH1* result = new ::TH1D( "ZippedByteAccessStat", + "Zipped byte access statistics;Bytes;Branches", + 100, 0.0, ( ( ::Double_t ) maxBytes ) * 1.1 ); + + // Fill the histogram by looping over the variables once more: + itr = m_branches.begin(); + end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + result->Fill( ( ::Double_t ) ( *vitr )->zippedBytesRead() ); + } + } + + return result; + } + + /// This function can be used to produce a nice histogram showing how many + /// uncompressed bytes were accessed by how many of the branches. + /// + /// Note that the caller is responsible for deleting the created histogram. + /// + /// @returns The histogram showing the distribution + /// + ::TH1* ReadStats::unzippedByteReadStat() const { + + // Find the branch(es) which accessed the most bytes: + ::Long64_t maxBytes = 0; + Vector_t::const_iterator vitr, vend; + Map_t::const_iterator itr = m_branches.begin(); + Map_t::const_iterator end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + if( ( *vitr )->unzippedBytesRead() > maxBytes ) { + maxBytes = ( *vitr )->unzippedBytesRead(); + } + } + } + + // Create the histogram: + ::TH1* result = + new ::TH1D( "UnzippedByteAccessStat", + "Unzipped byte access statistics;Bytes;Branches", + 100, 0.0, ( ( ::Double_t ) maxBytes ) * 1.1 ); + + // Fill the histogram by looping over the variables once more: + itr = m_branches.begin(); + end = m_branches.end(); + for( ; itr != end; ++itr ) { + vitr = itr->second.begin(); + vend = itr->second.end(); + for( ; vitr != vend; ++vitr ) { + if( ! *vitr ) continue; + result->Fill( ( ::Double_t ) ( *vitr )->unzippedBytesRead() ); + } + } + + return result; + } + + /// This function makes it possible to properly merge objects coming from + /// PROOF workers, or from separate ROOT files. + /// + /// @param coll A collection of xAOD::ReadStats objects + /// @returns <code>0</code> in case of failure, a positive number + /// in case of success + /// + ::Int_t ReadStats::Merge( ::TCollection* coll ) { + + // Some security checks: + if( ! coll ) return 0; + if( coll->IsEmpty() ) return 0; + + // Iterate over the elements of the collection: + ::TIter next( coll ); + ::TObject* obj = 0; + ::Int_t result = 0; + while( ( obj = next() ) ) { + + // Check that the element is of the right type: + ReadStats* dobj = dynamic_cast< ReadStats* >( obj ); + if( ! dobj ) { + Error( "Merge", "Unknown object type encountered: %s", + obj->ClassName() ); + return 0; + } + + // The compatibility of the objects is no longer checked. When + // processing a large dataset, it's probable that the objects + // created by the different PROOF workers will not be "compatible". + + // Add this element to this object: + add( *dobj ); + ++result; + } + + return result; + } + + /// Standard ROOT printing function. It prints the gathered information + /// about the variables accessed in an analysis. + /// + /// The option parameter understands the following value(s): + /// - "Summary": Only the summary information is printed. + /// - "ByEntries": Order the variables by the number of entries + /// read from them. + /// - "ByBytes": Order the variables by the number of bytes + /// read from them. + /// + /// @param option Possible options for the printing + /// + void ReadStats::Print( ::Option_t* option ) const { + + Info( "Print", "Printing xAOD I/O statistics" ); + + // Create a temporary vector of the containers, so they can be ordered + // if necessary: + std::vector< BranchStats > conts; + MapC_t::const_iterator cont_itr = m_containers.begin(); + MapC_t::const_iterator cont_end = m_containers.end(); + for( ; cont_itr != cont_end; ++cont_itr ) { + conts.push_back( cont_itr->second ); + } + + // Create a temporary vector of the branches, so they can be ordered + // if necessary: + std::vector< BranchStats > vars; + Vector_t::const_iterator vec_itr, vec_end; + Map_t::const_iterator map_itr = m_branches.begin(); + Map_t::const_iterator map_end = m_branches.end(); + for( ; map_itr != map_end; ++map_itr ) { + vec_itr = map_itr->second.begin(); + vec_end = map_itr->second.end(); + for( ; vec_itr != vec_end; ++vec_itr ) { + if( ! *vec_itr ) continue; + vars.push_back( **vec_itr ); + } + } + + // Container and branch access summary + if( ! ::strcmp( option, "SmartSlimming" ) ) { + + Info( "Print", " " ); + Info( "Print", "Smart Slimming Statistics" ); + Info( "Print", " " ); + + const Double_t proFrac = ( ( Double_t ) m_nEventsProcessed / + ( Double_t ) m_nEvents ) * 100.0; + Info( "Print", " Processed %lli events from %lli (%g%%)", + m_nEventsProcessed, m_nEvents, proFrac ); + + Info( "Print", " Number of containers in on the input: %i", + static_cast< int >( m_containers.size() ) ); + Info( "Print", " Number of branches on the input: %i", + static_cast< int >( vars.size() ) ); + + // Sort the containers by number of accesses: + std::sort( conts.begin(), conts.end(), sortByEntries ); + + // Print which containers got accessed: + Info( "Print", " " ); + Info( "Print", "Accessed containers:" ); + Info( "Print", " " ); + std::vector< BranchStats >::const_iterator itr = conts.begin(); + std::vector< BranchStats >::const_iterator end = conts.end(); + for( ; itr != end; ++itr ) { + if( ! itr->readEntries() ) continue; + itr->Print( option ); + } + + // Sort the branches by number of accesses: + std::sort( vars.begin(), vars.end(), sortByEntries ); + + // Print which branches got accessed: + Info( "Print", " " ); + Info( "Print", "Accessed branches:" ); + Info( "Print", " " ); + itr = vars.begin(); + end = vars.end(); + for( ; itr != end; ++itr ) { + if( ! itr->readEntries() ) continue; + itr->Print( option ); + } + Info( "Print", " " ); + + // Let's exit at this point: + return; + } + + // Print the summary information: + Info( "Print", " Number of variables in the input xAOD : %i", + m_branchNum ); + const Double_t proFrac = ( ( Double_t ) m_nEventsProcessed / + ( Double_t ) m_nEvents ) * 100.0; + Info( "Print", " Processed events : " + "%lli/%lli (%g%%)", m_nEventsProcessed, m_nEvents, proFrac ); + Info( "Print", " TTreeCache size used : %s", + Utils::sizeToString( m_cacheSize ).c_str() ); + Info( "Print", " Total number of bytes read : %s", + Utils::sizeToString( m_bytesRead ).c_str() ); + Info( "Print", " Data reading speed per process : %s", + ( std::abs( m_processTime ) > 0.0001 ? + Utils::speedToString( m_bytesRead / m_processTime ).c_str() : + "N/A" ) ); + Info( "Print", " Total number of file read operations : %i", + m_fileReads ); + const ::Long64_t readInOneGo = + ( ::Long64_t ) ( ( ::Double_t ) m_bytesRead / + ( ::Double_t ) m_fileReads ); + Info( "Print", " Data read in one go (on average) : %s", + Utils::sizeToString( readInOneGo ).c_str() ); + Info( "Print", " Cumulative time spent processing data : %s (%s/event)", + Utils::timeToString( m_processTime ).c_str(), + ( m_nEventsProcessed ? + Utils::timeToString( m_processTime / m_nEventsProcessed ).c_str() : + "N/A" ) ); + Info( "Print", " Cumulative time spent reading data : %s (%s/event)", + Utils::timeToString( m_readTime ).c_str(), + ( m_nEventsProcessed ? + Utils::timeToString( m_readTime / m_nEventsProcessed ).c_str() : + "N/A" ) ); + Info( "Print", " Cumulative time spent unzipping data : %s (%s/event)", + Utils::timeToString( m_unzipTime ).c_str(), + ( m_nEventsProcessed ? + Utils::timeToString( m_unzipTime / m_nEventsProcessed ).c_str() : + "N/A" ) ); + + // If we just needed summary information, stop here: + if( ! ::strcmp( option, "Summary" ) ) { + return; + } + + // Select the kind of ordering for the containers: + if( ! ::strcmp( option, "ByEntries" ) ) { + Info( "Print", "Containers, sorted by number of accesses:" ); + std::sort( conts.begin(), conts.end(), sortByEntries ); + } else if( ! ::strcmp( option, "ByBytes" ) ) { + Info( "Print", "Containers, sorted by number of bytes read:" ); + std::sort( conts.begin(), conts.end(), sortByUnzippedBytes ); + } else { + Info( "Print", "Containers, sorted by name:" ); + } + + // Print the statistics from each container: + std::vector< BranchStats >::const_iterator itr = conts.begin(); + std::vector< BranchStats >::const_iterator end = conts.end(); + for( ; itr != end; ++itr ) { + itr->Print( option ); + } + + // Select the kind of ordering for the variables: + if( ! ::strcmp( option, "ByEntries" ) ) { + Info( "Print", "Variables, sorted by number of accesses:" ); + std::sort( vars.begin(), vars.end(), sortByEntries ); + } else if( ! ::strcmp( option, "ByBytes" ) ) { + Info( "Print", "Variables, sorted by number of bytes read:" ); + std::sort( vars.begin(), vars.end(), sortByUnzippedBytes ); + } else { + Info( "Print", "Variables, sorted by name:" ); + } + + // Print the statistics from each variable: + itr = vars.begin(); + end = vars.end(); + for( ; itr != end; ++itr ) { + itr->Print( option ); + } + + return; + } + + /// This is a tricky function. It prints the list of accessed variables in + /// a way that can be copy-pasted directly into the ItemList of a derivation + /// job. (Or into the C++ code of some analysis code.) + /// + /// @param autoIncludeLinks Since removing links from objects can cause + /// problems for slow-merging in Athena, one can + /// request all ElementLink variables to be added to + /// the variable list, irrespective whether they're + /// needed or not. + /// + void ReadStats::printSmartSlimmingBranchList( bool autoIncludeLinks ) const { + + /// Object used to collect the information + std::map< ::TString, ::TString > items; + + // Collect all the containers that were accessed during the job: + MapC_t::const_iterator cont_itr = m_containers.begin(); + MapC_t::const_iterator cont_end = m_containers.end(); + for( ; cont_itr != cont_end; ++cont_itr ) { + // Skip non-accessed containers: + if( ! cont_itr->second.readEntries() ) continue; + // Remember the container: + items[ cont_itr->first ] = ""; + } + + // Now look for variables in all these containers: + Map_t::const_iterator br_itr = m_branches.begin(); + Map_t::const_iterator br_end = m_branches.end(); + for( ; br_itr != br_end; ++br_itr ) { + // First check if any variables got accessed. It has an effect on what + // to do with the ElementLink types. + bool containerAccessed = false; + Vector_t::const_iterator itr = br_itr->second.begin(); + Vector_t::const_iterator end = br_itr->second.end(); + for( ; itr != end; ++itr ) { + if( ( *itr ) && ( *itr )->readEntries() ) { + containerAccessed = true; + break; + } + } + // If none were accessed, abandon this container: + if( ! containerAccessed ) continue; + // Now collect all the variables: + for( ; itr != end; ++itr ) { + // Check if it's an ElementLink type: + const bool linkType = + ( ( *itr ) && + ::TString( ( *itr )->GetTitle() ).Contains( "ElementLink" ) ); + // Skip non-existent, non-accessed, and not requested link + // variables: + if( ( ( ! *itr ) || ( ! ( *itr )->readEntries() ) ) && + ( ! ( autoIncludeLinks && linkType ) ) ) continue; + // Extract the name of the container and the variable from the + // branch's name: + const ::TString brname = ( *itr )->GetName(); + const ::Size_t dotPos = brname.First( '.' ); + if( dotPos == ::kNPOS ) { + // Ignore the unknown containers: + continue; + } + const ::TString cname = brname( 0, dotPos + 1 ); + const ::TString vname = brname( dotPos + 1, + brname.Length() - dotPos ); + // Access the current variable list: + ::TString& vars = items[ cname ]; + // Add a dot if there are already variables defined: + if( vars.Length() ) { + vars.Append( '.' ); + } + // Add this variable: + vars.Append( vname ); + } + } + + // Print the collected information: + Info( "printSmartSlimmingBranchList", "ItemList to use:" ); + if( autoIncludeLinks ) { + Info( "printSmartSlimmingBranchList", "(All link variables added)" ); + } + std::map< ::TString, ::TString >::const_iterator itr = items.begin(); + std::map< ::TString, ::TString >::const_iterator end = items.end(); + for( ; itr != end; ++itr ) { + if( itr->first.EndsWith( "Aux." ) ) { + Info( "printSmartSlimmingBranchList", " %s%s", + itr->first.Data(), + ( itr->second.Length() ? itr->second.Data() : "-" ) ); + } else { + Info( "printSmartSlimmingBranchList", " %s", + itr->first.Data() ); + } + } + + // Return gracefully: + return; + } + + void ReadStats::nextEvent(){ + + // event counters + ++m_nEventsProcessed; + return; + } + + ::Long64_t ReadStats::nEvents() const { + + return m_nEvents; + } + + void ReadStats::setNEvents( ::Long64_t nevents ) { + + m_nEvents = nevents; + return; + } + + void ReadStats::readBranch( const std::string& prefix, + SG::auxid_t auxid ){ + + // Access the branch: + BranchStats* stat = branch( prefix, auxid ); + // Increment its access counter: + stat->setReadEntries( stat->readEntries() + 1 ); + return; + } + + void ReadStats::readContainer( const std::string& name ){ + + // Access the branch: + BranchStats* stat = container( name ); + // Increment its access counter: + stat->setReadEntries( stat->readEntries() + 1 ); + return; + } + +} // namespace D3PDReader diff --git a/EDM/athena/xAOD/xAODCore/Root/SafeDeepCopy.cxx b/EDM/athena/xAOD/xAODCore/Root/SafeDeepCopy.cxx new file mode 100644 index 00000000..25a5eebf --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/SafeDeepCopy.cxx @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: SafeDeepCopy.cxx 676241 2015-06-18 06:15:44Z krasznaa $ + +// EDM include(s): +#define protected public +# include "AthContainers/AuxElement.h" +#undef protected +#include "AthContainers/exceptions.h" +#include "AthContainers/AuxTypeRegistry.h" + +// Local include(s): +#include "xAODCore/tools/SafeDeepCopy.h" + +namespace xAOD { + + void safeDeepCopy( const SG::AuxElement& orig, SG::AuxElement& copy ) { + + // + // Check that the target object is healthy: + // + if( ! copy.container() ) { + return; + } + if( ! copy.container()->hasStore() ) { + return; + } + if( ! copy.container()->hasNonConstStore() ) { + throw SG::ExcConstAuxData( "safeDeepCopy" ); + } + + // + // Access the original's data: + // + const SG::AuxVectorData* ocont = orig.container(); + if( ( ! ocont ) || ( ! ocont->hasStore() ) ) { + // In this case let the assignment operator of SG::AuxElement take + // care of clearing out the target object. + copy = orig; + return; + } + + // + // Do the copy: + // + const size_t iindex = orig.index(); + const size_t oindex = copy.index(); + const SG::auxid_set_t& other_ids = ocont->getAuxIDs(); + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + + // Copy the variables that exist on the input object: + for( SG::auxid_t auxid : other_ids ) { + void* dst = copy.container()->getDataArray( auxid ); + // This is the tricky part. In certain cases an input object/container + // can claim that it has a certain variable, but still not be able to + // provide it. Most usually this happens when reading a container from + // a file, in which not all elements were decorated consistently. + // This has to be caught here: + const void* src = 0; + try { + src = ocont->getDataArray( auxid ); + } catch( const SG::ExcBadAuxVar& ) { + // In this case just fill dummy values into the output: + r.clear( auxid, dst, oindex ); + continue; + } + // Apparently the copy *can* be done: + r.copy( auxid, dst, oindex, src, iindex ); + } + // Clear out the variables that only exist on the output object: + for( SG::auxid_t auxid : copy.container()->getWritableAuxIDs() ) { + if( other_ids.find( auxid ) == other_ids.end() ) { + void* dst = copy.container()->getDataArray( auxid ); + r.clear( auxid, dst, oindex ); + } + } + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/ShallowAuxContainer.cxx b/EDM/athena/xAOD/xAODCore/Root/ShallowAuxContainer.cxx new file mode 100644 index 00000000..dbb29b37 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/ShallowAuxContainer.cxx @@ -0,0 +1,509 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ShallowAuxContainer.cxx 793737 2017-01-24 20:11:10Z ssnyder $ + +// System include(s): +#include <iostream> + +// EDM include(s): +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" + +// Local include(s): +#include "xAODCore/ShallowAuxContainer.h" + +namespace xAOD { + + /// @param standalone <code>true</code> if the store will be used for a + /// standalone object, <code>false</code> for a container + /// + ShallowAuxContainer::ShallowAuxContainer( bool standalone ) + : m_selection(), + m_store( new SG::AuxStoreInternal( standalone ) ), + m_storeIO( 0 ), m_ownsStore( true ), m_locked( false ), + m_parentLink(), m_parentIO( 0 ), m_shallowIO( true ), m_tick( 1 ), + m_name( "UNKNOWN" ) { + + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + } + + ShallowAuxContainer::ShallowAuxContainer( const ShallowAuxContainer& parent ) + : SG::IAuxStore(), SG::IAuxStoreIO(), SG::IAuxStoreHolder(), + m_selection( parent.m_selection ), + m_store( parent.m_store ), m_storeIO( parent.m_storeIO ), + m_ownsStore( false ), m_locked( parent.m_locked ), + m_parentLink( parent.m_parentLink ), + m_parentIO( parent.m_parentIO ), m_shallowIO( parent.m_shallowIO ), + m_tick( 1 ), m_name( parent.m_name ) { + + } + + /// @param parent The parent object to make a shallow copy of + /// @param standalone <code>true</code> if the store will be used for a + /// standalone object, <code>false</code> for a container + /// + ShallowAuxContainer:: + ShallowAuxContainer( const DataLink< SG::IConstAuxStore >& parent, + bool standalone ) + : m_selection(), + m_store( new SG::AuxStoreInternal( standalone ) ), + m_storeIO( 0 ), m_ownsStore( true ), m_locked( false ), + m_parentLink( parent ), m_parentIO( 0 ), m_shallowIO( true ), + m_tick( 1 ), m_name( "UNKNOWN" ) { + + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + const SG::IAuxStoreIO* temp = + dynamic_cast< const SG::IAuxStoreIO* >( m_parentLink.cptr() ); + m_parentIO = const_cast< SG::IAuxStoreIO* >( temp ); + } + + ShallowAuxContainer::~ShallowAuxContainer() { + + if( m_ownsStore && m_store ) { + delete m_store; + } + } + + ShallowAuxContainer& + ShallowAuxContainer::operator= ( const ShallowAuxContainer& rhs ) { + + guard_t guard (m_mutex); + // Check if anything needs to be done: + if( this == &rhs ) { + return *this; + } + + // Clean up if necessary: + if( m_ownsStore && m_store ) { + delete m_store; + m_store = 0; + } + + m_selection = rhs.m_selection; + m_store = rhs.m_store; + m_storeIO = rhs.m_storeIO; + m_ownsStore = false; + m_locked = rhs.m_locked; + m_parentLink = rhs.m_parentLink; + m_parentIO = rhs.m_parentIO; + m_shallowIO = rhs.m_shallowIO; + m_name = rhs.m_name; + ++m_tick; + + // Return this object: + return *this; + } + + const DataLink< SG::IConstAuxStore >& ShallowAuxContainer::parent() const { + + return m_parentLink; + } + + void ShallowAuxContainer:: + setParent( const DataLink< SG::IConstAuxStore >& link ) { + + guard_t guard (m_mutex); + m_parentLink = link; + const SG::IAuxStoreIO* temp = + dynamic_cast< const SG::IAuxStoreIO* >( m_parentLink.cptr() ); + m_parentIO = const_cast< SG::IAuxStoreIO* >( temp ); + ++m_tick; + return; + } + + bool ShallowAuxContainer::shallowIO() const { + + return m_shallowIO; + } + + void ShallowAuxContainer::setShallowIO( bool value ) { + + guard_t guard (m_mutex); + m_shallowIO = value; + return; + } + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStoreHolder interface + // + + SG::IAuxStore* ShallowAuxContainer::getStore() const { + + return m_store; + } + + void ShallowAuxContainer::setStore( SG::IAuxStore* store ) { + + // Check if anything needs to be done: + guard_t guard (m_mutex); + if( store == m_store ) return; + + if( m_ownsStore && m_store ) { + delete m_store; + m_store = 0; + } + + // Do the assignment: + m_store = store; + m_storeIO = dynamic_cast< SG::IAuxStoreIO* >( m_store ); + m_ownsStore = true; + ++m_tick; + + return; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IConstAuxStore interface + // + + const void* ShallowAuxContainer::getData( auxid_t auxid ) const { + + guard_t guard( m_mutex ); + + // Check if we have this variable ourselves. I use getData(...) + // instead of getAuxIDs(), as a dynamic store may not have connected + // to all the variables yet that it has available... + size_t nids = m_store->getAuxIDs().size(); + const void* result = m_store->getData( auxid ); + if( result ) { + if( nids != m_store->getAuxIDs().size() ) { + ++m_tick; + } + return result; + } + + // If not, then leave it up to the parent object do deal with this: + if( m_parentLink.isValid() ) { + nids = m_parentLink->getAuxIDs().size(); + result = m_parentLink->getData( auxid ); + if( result && ( nids != m_parentLink->getAuxIDs().size() ) ) { + ++m_tick; + } + return result; + } + + // Apparently the variable wasn't found: + return 0; + } + + const ShallowAuxContainer::auxid_set_t& + ShallowAuxContainer::getAuxIDs() const { + + guard_t guard (m_mutex); + if( m_tsAuxids.get() == 0 ) { + m_tsAuxids.reset( new TSAuxidSet ); + } + + if( m_tsAuxids->m_tick != m_tick ) { + if( m_parentLink.isValid() ) { + m_tsAuxids->m_set = m_parentLink->getAuxIDs(); + } else { + m_tsAuxids->m_set.clear(); + } + const SG::auxid_set_t& store_auxids = m_store->getAuxIDs(); + m_tsAuxids->m_set.insert( store_auxids.begin(), store_auxids.end() ); + m_tsAuxids->m_tick = m_tick; + } + return m_tsAuxids->m_set; + } + + /// Return the data vector for one aux data decoration item. + void* ShallowAuxContainer::getDecoration( auxid_t auxid, + size_t size, + size_t capacity ) { + + guard_t guard( m_mutex ); + + // If the parent has such a variable, then we need to check one more + // thing. If it's a decoration on the parent, then we should be allowed + // to override it in this (possibly locked) shallow copy. But let's leave + // the logic of this up to the parent. We ask the parent to return this + // variable as a decoration. If this is not possible (because it's not a + // decoration, but a regular variable), then let the parent throw the + // exception. Otherwise we continue, and let the internal store return + // a pointer to this derivation. (Which may still throw an exception.) + // + // It's quite ugly, as we have to do a const_cast to do this. But the + // SG::IConstAuxStore interface doesn't provide any other way of figuring + // out whether a given variable is a regular variable or a decoration. + // + if( m_locked && m_parentLink.isValid() && + ( m_parentLink->getAuxIDs().count( auxid ) > 0 ) ) { + SG::IConstAuxStore* parent = + const_cast< SG::IConstAuxStore* >( m_parentLink.cptr() ); + parent->getDecoration( auxid, size, capacity ); + } + + // If we got this far without any exception, then let the internal store + // try to provide the decoration for us: + const size_t nids = m_store->getAuxIDs().size(); + void* result = m_store->getDecoration( auxid, size, capacity ); + if( result && ( nids != m_store->getAuxIDs().size() ) ) { + ++m_tick; + } + return result; + } + + + /// Lock the container. + void ShallowAuxContainer::lock() + { + guard_t guard (m_mutex); + m_locked = true; + m_store->lock(); + } + + + /// Clear all decorations. + void ShallowAuxContainer::clearDecorations() + { + guard_t guard (m_mutex); + m_store->clearDecorations(); + ++m_tick; + } + + size_t ShallowAuxContainer::size() const { + + guard_t guard( m_mutex ); + size_t sz = m_store->size(); + if( sz > 0 ) { + return sz; + } + if( m_parentLink.isValid() ) { + return m_parentLink->size(); + } + return 0; + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStore interface + // + + void* ShallowAuxContainer::getData( auxid_t auxid, size_t size, + size_t capacity ) { + + guard_t guard (m_mutex); + // Remember that we now manage this variable: + ++m_tick; + + // Create the variable in the dynamic store: + void* ptr = m_store->getData( auxid, size, capacity ); + + // If the parent doesn't have this variable, then we're done already: + if( ! m_parentLink.isValid() ) { + return ptr; + } + const void* pptr = m_parentLink->getData( auxid ); + if( ! pptr ) { + return ptr; + } + + // If the variable does exist in the parent, then copy it over to this + // store before returning. + + // Get the registry: + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + // Get the type of this variable: + const std::type_info* type = reg.getType( auxid ); + if( ! type ) { + std::cerr << "xAOD::ShallowAuxContainer::getData ERROR Couldn't find " + << "the type of auxiliary ID " << auxid << std::endl; + std::cerr << "xAOD::ShallowAuxContainer::getData ERROR Can't copy the " + << "contents of the parent's decoration" << std::endl; + return ptr; + } + + // First let's get the vector factory of this variable: + const SG::IAuxTypeVectorFactory* factory = + SG::AuxTypeRegistry::instance().getFactory( *type ); + if( ! factory ) { + std::cerr << "xAOD::ShallowAuxContainer::getData ERROR Couldn't find " + << "factory for type " << type->name() << std::endl; + std::cerr << "xAOD::ShallowAuxContainer::getData ERROR Can't copy the " + << "contents of the parent's decoration" << std::endl; + return ptr; + } + + // Copy each element of the parent's decoration: + for( size_t i = 0; i < size; ++i ) { + factory->copy( ptr, i, pptr, i ); + } + + // Now we're done: + return ptr; + } + + const ShallowAuxContainer::auxid_set_t& + ShallowAuxContainer::getWritableAuxIDs() const { + + // Only the variables in the dynamic store are writable. Maybe not + // even all of those... + return m_store->getWritableAuxIDs(); + } + + bool ShallowAuxContainer::resize( size_t /*size*/ ) { + + // Nope, not allowed... + throw std::runtime_error( "Trying to call resize on a shallow copy " + "container" ); + } + + void ShallowAuxContainer::reserve( size_t /*size*/ ) { + + // Nope, not allowed... + throw std::runtime_error( "Trying to call reserve on a shallow copy " + "container" ); + } + + void ShallowAuxContainer::shift( size_t /*pos*/, ptrdiff_t /*offs*/ ) { + + // Nope, not allowed... + throw std::runtime_error( "Trying to call shift on a shallow copy " + "container" ); + } + + bool ShallowAuxContainer::insertMove( size_t /*pos*/, + IAuxStore& /*other*/, + const SG::auxid_set_t& /*ignore*/) { + + // Nope, not allowed... + throw std::runtime_error( "Trying to call insertMove on a shallow copy " + "container" ); + } + + // + ///////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////// + // + // Implementation of the SG::IAuxStoreIO interface + // + + const void* ShallowAuxContainer::getIOData( auxid_t auxid ) const { + + guard_t guard (m_mutex); + // Do we have it? + const SG::auxid_set_t& store_auxids = m_store->getAuxIDs(); + if( m_storeIO && ( store_auxids.find( auxid ) != + store_auxids.end() ) ) { + return m_storeIO->getIOData( auxid ); + } + + // Do we have a parent that has it? + if( m_parentLink.isValid() ) { + if( ! m_parentIO ) { + const SG::IAuxStoreIO* temp = + dynamic_cast< const SG::IAuxStoreIO* >( m_parentLink.cptr() ); + m_parentIO = const_cast< SG::IAuxStoreIO* >( temp ); + } + if( m_parentIO ) { + return m_parentIO->getIOData( auxid ); + } + } + + // If not, then where did this variable come from?!? + std::cerr << "ERROR xAOD::ShallowAuxContainer::getIOData Unknown " + << "variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + + const std::type_info* ShallowAuxContainer::getIOType( auxid_t auxid ) const { + + guard_t guard (m_mutex); + // Do we have it? + const SG::auxid_set_t& store_auxids = m_store->getAuxIDs(); + if( m_storeIO && ( store_auxids.find( auxid ) != + store_auxids.end() ) ) { + return m_storeIO->getIOType( auxid ); + } + + // Do we have a parent that has it? + if( m_parentLink.isValid() ) { + if( ! m_parentIO ) { + const SG::IAuxStoreIO* temp = + dynamic_cast< const SG::IAuxStoreIO* >( m_parentLink.cptr() ); + m_parentIO = const_cast< SG::IAuxStoreIO* >( temp ); + } + if( m_parentIO ) { + return m_parentIO->getIOType( auxid ); + } + } + + // If not, then where did this variable come from?!? + std::cerr << "ERROR xAOD::ShallowAuxContainer::getIOType Unknown " + << "variable (" + << SG::AuxTypeRegistry::instance().getName( auxid ) + << ") requested" << std::endl; + return 0; + } + + const ShallowAuxContainer::auxid_set_t& + ShallowAuxContainer::getDynamicAuxIDs() const { + + if( m_shallowIO ) { + if( m_storeIO ) { + return m_store->getAuxIDs(); + } else { + static const auxid_set_t dummy {}; + return dummy; + } + } else { + return getAuxIDs(); + } + } + + void ShallowAuxContainer:: + selectAux( const std::set< std::string >& attributes ) { + + guard_t guard (m_mutex); + m_selection.selectAux( attributes ); + return; + } + + const ShallowAuxContainer::auxid_set_t& + ShallowAuxContainer::getSelectedAuxIDs() const { + + if( m_shallowIO ) { + if( m_storeIO ) { + return m_selection.getSelectedAuxIDs( m_store->getAuxIDs() ); + } else { + static const auxid_set_t dummy {}; + return dummy; + } + } else { + return m_selection.getSelectedAuxIDs( getAuxIDs() ); + } + } + + + // + ///////////////////////////////////////////////////////////////////////////// + + const char* ShallowAuxContainer::name() const { + + return m_name.c_str(); + } + + void ShallowAuxContainer::setName( const char* name ) { + + m_name = name; + return; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/ShallowAuxInfo.cxx b/EDM/athena/xAOD/xAODCore/Root/ShallowAuxInfo.cxx new file mode 100644 index 00000000..246c9002 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/ShallowAuxInfo.cxx @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ShallowAuxInfo.cxx 598261 2014-05-21 16:36:05Z krasznaa $ + +// Local include(s): +#include "xAODCore/ShallowAuxInfo.h" + +namespace xAOD { + + ShallowAuxInfo::ShallowAuxInfo() + : ShallowAuxContainer( true ) { + + } + + ShallowAuxInfo:: + ShallowAuxInfo( const DataLink< SG::IConstAuxStore >& parent ) + : ShallowAuxContainer( parent, true ) { + + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/TDVCollectionProxy.cxx b/EDM/athena/xAOD/xAODCore/Root/TDVCollectionProxy.cxx new file mode 100644 index 00000000..e3442a1b --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/TDVCollectionProxy.cxx @@ -0,0 +1,582 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: TDVCollectionProxy.cxx 660500 2015-04-14 14:04:12Z krasznaa $ + +// System include(s): +#include <cassert> + +// ROOT include(s): +#include <TError.h> +#include <TClassEdit.h> +#include <TClass.h> +#include <TBaseClass.h> +#include <TCollectionProxyInfo.h> +#include <TSystem.h> +#include <TList.h> + +// EDM include(s): +#include "AthContainers/DataVector.h" +#include "CxxUtils/no_sanitize_undefined.h" + +// Local include(s): +#include "xAODCore/tools/TDVCollectionProxy.h" + +namespace xAOD { + + /// Find base class offset using Reflex. + /// + /// Unlike @c TClass::GetBaseClassOffset, this should properly + /// handle virtual derivation. @a cls must have a default constructor. + /// + /// @param cls Class in which to find the base. + /// @param base The base for which to search. + /// @returns The offset of @a base in @a cls, or -1 if it's not a base. + int safeGetBaseOffset( TClass* cls, TClass* base ) { + + return cls->GetBaseClassOffset( base ); + } + + /// Find the contained class in a @c DataVector. + /// + /// @param dvclass The @c TClass for a @c DataVector class. + /// @return The @c TClass for the @c DataVector's element type. + TClass* classFromDVClass( TClass* dvclass ) { + + // Split up the class name into template arguments. + std::vector< std::string > args; + int tailloc; + TClassEdit::GetSplit( dvclass->GetName(), args, tailloc ); + assert( args.size() > 1 ); + + // This should be the element type name. + std::string elname = args[ 1 ]; + assert( elname.size() > 0 ); + + // Look up the element class. + TClass* elclass = TClass::GetClass( elname.c_str() ); + if (!elclass) { + ::Error( "xAOD::TDVCollectionProxy", "Cannot find class %s", + elname.c_str() ); + } + + return elclass; + } + + /// Find the unique base @c DataVector class. + /// + /// Note: @c DataVector\<T> can derive from @c DataVector\<U>. + /// But there can also be helper classes in between + /// that start with `DataVector' (note: no `<'). + /// + /// @param dvclass The @c TClass for a @c DataVector class. + /// @return The @c TClass for the unique base @c DataVector class. + /// Returns 0 if there is no such base, or if it + /// is the same as @a dvclass. + TClass* findDVBase( TClass* dvclass ) { + + TIter next( dvclass->GetListOfBases() ); + while( TBaseClass* bcl = dynamic_cast< TBaseClass* >( next() ) ) { + TClass* cc = bcl->GetClassPointer(); + if( strncmp( cc->GetName(), "DataVector", 10 ) == 0 ) { + TClass* bdv = findDVBase( cc ); + if( bdv ) return bdv; + if( strncmp( cc->GetName(), "DataVector<", 11 ) == 0 ) + return cc; + } + } + + return 0; + } + + /// Find the element type of a @c DataVector class. + /// + /// If @a cl is a @c DataVector class, or derives from one, then we return + /// the name of the element type (including a trailing `*'). Otherwise, + /// we return an empty string. + /// + /// @param cl The @c TClass to test. + /// @return The name of the element type if @a cl is a DV class, or empty. + /// + std::string findDVElement( TClass* cl ) { + + // Make sure that the minimal set of dictionaries are loaded: + TClass* dummyCl = + TClass::GetClass( "DataVector<xAOD::TDVCollectionProxyDummy>" ); + if( ! dummyCl ) { + Error( "xAOD::findDVElement", + "Couldn't load the dictionary for " + "DataVector<xAOD::TDVCollectionProxyDummy>" ); + return ""; + } + + // Is this a DV class? + std::string elt; + const char* name = cl->GetName(); + if( strncmp( name, "DataVector<", 11 ) == 0 ) { + + elt = std::string( name + 11, strlen( name ) - 11 - 1 ); + + // Usually the full DataVector name includes two template + // arguments. But we only need the first one, before the first comma. + const std::string::size_type comma = elt.find( "," ); + if( comma != std::string::npos ) { + elt = elt.substr( 0, comma ); + } + + return elt; + } + + // Scan base classes too. + TIter next( cl->GetListOfBases() ); + while( TBaseClass* bcl = dynamic_cast< TBaseClass* >( next() ) ) { + TClass* cc = bcl->GetClassPointer(); + elt = findDVElement( cc ); + if( ! elt.empty() ) { + break; + } + } + + return elt; + } + + /// Helper functions for accessing the container data via the proxy. + class TDVCollectionFuncs { + + public: + /// @brief The container type. + /// We alias this with the real vector that lives inside the + /// @c DataVector. + typedef std::vector< char* > Cont_t; + + /// Proxy environment buffer. + /// + /// The first 64 bytes of the environment structure are a scratch area. + /// The Root proxies put a collection iterator there, but we instead + /// lay it out like this. + /// + /// This is slightly different in newer versions of root. + /// Rather than having the 64-byte buffer, Environ takes a template + /// argument giving the payload. + /// + struct TEnvBuff { + + /// The index of the last element retrieved. + size_t fIndex; + + /// @brief Pointer to the container. + /// (Note that the object pointer from the environment will point at + /// the top-level @c DataVector class; this points directly at the vector.) + Cont_t* fCont; + + /// The last element pointer to have been returned. + void* fEltPtr; + + /// Offset between the pointer held by the DV and the start of the + /// object + int fOffset; + + }; // struct TEnvBuff + + /// The Root proxy environment structure. + typedef ROOT::TCollectionProxyInfo::Environ< TEnvBuff > Env_t; + + /// Fetch the container from a proxy environment. + /// + /// @param env The proxy environment. + static Cont_t* cont( void* env ) { + + Env_t& e = *reinterpret_cast< Env_t* >( env ); + TEnvBuff& buff = e.fIterator; + return buff.fCont; + } + + /// Return the first element of the container. + /// + /// This resets the internal pointer to 0. + /// + /// @param env The proxy environment. + /// @return A pointer to the first element, or 0 if the container is empty. + static void* first( void* env ) { + + Env_t& e = *reinterpret_cast< Env_t* >( env ); + Cont_t& c = *cont( env ); + TEnvBuff& buff = e.fIterator; + buff.fIndex = 0; + e.fSize = c.size(); + if( 0 == e.fSize ) { + return 0; + } + char* start = c[ 0 ]; + buff.fEltPtr = start + buff.fOffset; + return buff.fEltPtr; + } + + /// Return a following element of the container. + /// + /// The internal pointer will be advanced by the value of @c e.idx + /// (after which @c e.idx will be reset to 0). A pointer to the element + /// referenced by this new index will be returned. + /// + /// @param env The proxy environment. + /// @return A pointer to the following element, or 0 if we're past the end. + static void* next( void* env ) { + + Env_t& e = *reinterpret_cast< Env_t* >( env ); + Cont_t& c = *cont( env ); + TEnvBuff& buff = e.fIterator; + buff.fIndex += e.fIdx; + e.fIdx = 0; + if( buff.fIndex >= e.fSize ) { + return 0; + } + char* ptr = c[ buff.fIndex ]; + buff.fEltPtr = ptr + buff.fOffset; + return buff.fEltPtr; + } + + /// Return the size of the container. + /// + /// @param env The proxy environment. + static void* size( void* env ) { + + Env_t* e = reinterpret_cast< Env_t* >( env ); + e->fSize = cont( env )->size(); + return &( e->fSize ); + } + + /// Erase the container. + /// + /// @param env The proxy environment. + static void* clear( void* env ) { + + cont( env )->clear(); + return 0; + } + + /// Return a new environment structure. + static void* create_env() { + + return new Env_t; + } + + //************************************************************************* + // These methods are not needed for the xAOD usage, + // and are not implemented. + + /// Not implemented for xAOD + // template <typname T> // T will be equal to final class + static void resize( void* /*obj*/, size_t /*size*/ ) { + ::Fatal( "xAOD::TDVCollectionProxy", "resize function not specified!" ); + } + + /// Not implemented for xAOD + static void* construct( void* /*from*/, size_t /*size*/ ) { + ::Fatal( "xAOD::TDVCollectionProxy", "construct not implemented" ); + return 0; + } + + /// Not implemented for xAOD + static void destruct( void* /*obj*/, size_t /*size*/ ) { + ::Fatal( "xAOD::TDVCollectionProxy", "destruct not implemented" ); + } + + /// Not implemented for xAOD + static void* feed( void* /*from*/, void* /*to*/, size_t /*size*/ ) { + ::Fatal( "xAOD::TDVCollectionProxy", "feed not implemented" ); + return 0; + } + + /// Not implemented for xAOD +#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 34, 6 ) + static void* collect( void* /*from*/, void* /*to*/ ) { + ::Fatal( "xAOD::TDVCollectionProxy", "collect not implemented" ); + return 0; + } +#else + static void* collect( void* /*env*/ ) { + ::Fatal( "xAOD::TDVCollectionProxy", "collect not implemented" ); + return 0; + } +#endif + + }; // class TDVCollectionFuncs + + /// Constructor. + /// + /// @param conttype The name of the container type we're proxying. + /// Note that this may be different from + /// a @c DataVector of @a elttype for classes which + /// derive from @c DataVector. + /// + TDVCollectionProxy::TDVCollectionProxy( const char* conttype ) + : TGenCollectionProxy( typeid( DataVector< TDVCollectionProxyDummy > ), + sizeof( char* ) ), + fName( conttype ), fInitialized( kFALSE ), + fContoff( 0 ), fOffset( 0 ), fEltBase( 0 ), fEltType( 0 ) { + + // Set up the element size. No offset, since this isn't a map. + fValDiff = sizeof( void* ); + fValOffset = 0; + + // Set up the worker functions. + fSize.call = TDVCollectionFuncs::size; + fNext.call = TDVCollectionFuncs::next; + fFirst.call = TDVCollectionFuncs::first; + fClear.call = TDVCollectionFuncs::clear; +#if ROOT_VERSION_CODE >= ROOT_VERSION(5,34,6) + fCollect = TDVCollectionFuncs::collect; +#else + fCollect.call = TDVCollectionFuncs::collect; +#endif + fCreateEnv.call = TDVCollectionFuncs::create_env; + fResize = TDVCollectionFuncs::resize; + fConstruct = TDVCollectionFuncs::construct; + fDestruct = TDVCollectionFuncs::destruct; + fFeed = TDVCollectionFuncs::feed; + + // Make sure that TGenCollectionProxy knows that it's not + // fully set up yet: + if( fValue ) { +#if ROOT_VERSION_CODE > ROOT_VERSION(6,2,5) + delete fValue.exchange( 0 ); +#else + delete fValue; + fValue = 0; +#endif // ROOT_VERSION + } + if( fVal ) { + delete fVal; + fVal = 0; + } + + // This container pretends to hold objects, not pointers: + fPointers = kFALSE; + + // Remember that we are not initialized yet: + fProperties = 0; + } + + /// Copy constructor. + /// + /// @param rhs The proxy to copy. + TDVCollectionProxy::TDVCollectionProxy( const TDVCollectionProxy& rhs ) + : TGenCollectionProxy( rhs ), + fName( rhs.fName ), + fInitialized( rhs.fInitialized ), + fContoff( rhs.fContoff ), + fOffset( rhs.fOffset ), + fEltBase( rhs.fEltBase ), + fEltType( rhs.fEltType ) { + + // If we're not initialised yet, make sure that the base class is + // on the same page... + if( ! fInitialized ) { + if( fValue ) { +#if ROOT_VERSION_CODE > ROOT_VERSION(6,2,5) + delete fValue.exchange( 0 ); +#else + delete fValue; + fValue = 0; +#endif // ROOT_VERSION + } + if( fVal ) { + delete fVal; + fVal = 0; + } + } + } + + /// Start working with a new collection. + /// + /// @param objstart The address of the collection. + void TDVCollectionProxy::PushProxy NO_SANITIZE_UNDEFINED ( void* objstart ) { + + // Do the base class stuff. + // This will create an environment buffer if needed. + ::TGenCollectionProxy::PushProxy( objstart ); + + // Save the calculated element offset in the environment buffer. + TDVCollectionFuncs::TEnvBuff& buff = + reinterpret_cast< TDVCollectionFuncs::Env_t* >( fEnv )->fIterator; + + // Get the offset needed for the pointer operations: + buff.fOffset = fOffset; + + // Save the address of the underlying vector of the DataVector. + // First, adjust the address to the base DataVector. + char* dvstart = reinterpret_cast< char* >( objstart ) + fContoff; + // Cast to DV. + // This gets a ubsan warning about casting between types. + // However, this is deliberate, so suppress ubsan warnings + // for this function. + DataVector< char >* dv = + reinterpret_cast< DataVector< char >* >( dvstart ); + // Find the underlying vector. + const std::vector< char* >& vec = dv->stdcont(); + // And store its address. + buff.fCont = const_cast< std::vector< char* >* >( &vec ); + + return; + } + + /// Clone this object. + TVirtualCollectionProxy* TDVCollectionProxy::Generate() const { + + return new TDVCollectionProxy( *this ); + } + + /// The resize(...) functions need to be specific for the different classes. + /// This function is used to supply a specific resize(...) function for this + /// proxy's class. + /// + /// @param func The function to use + /// + void TDVCollectionProxy::SetResize( Sizing_t func ) { + + fResize = func; + return; + } + + TGenCollectionProxy* TDVCollectionProxy::InitializeEx( Bool_t silent ) { + + // Check if we're initialised already: + if( fInitialized ) return this; + + // Check for the class's dictionary, and for its element type: + TClass* cl = TClass::GetClass( fName ); + if( ! cl ) { + ::Fatal( "xAOD::TDVCollectionProxy::InitializeEx", + "Couldn't find dictionary for class %s", + fName.Data() ); + return 0; + } + + // Check if it is a DataVector: + const std::string eltname = findDVElement( cl ); + if( eltname.empty() ) { + ::Fatal( "xAOD::TDVCollectionProxy::InitializeEx", + "Class \"%s\" doesn't seem to be a DataVector", + cl->GetName() ); + return 0; + } + + // Find the container and element offsets. + FindOffsets( eltname.c_str(), fName ); + + // Set up the element size. No offset, since this isn't a map. + fValDiff = sizeof( void* ); + fValOffset = 0; + + // Do the base class initialization. + CheckFunctions(); + TGenCollectionProxy::InitializeEx( silent ); + fSTL_type = TClassEdit::kList; + + // Need to override what that set up for fValue and fVal. + if( fValue ) { +#if ROOT_VERSION_CODE > ROOT_VERSION(6,2,5) + delete fValue.exchange( 0 ); +#else + delete fValue; + fValue = 0; +#endif // ROOT_VERSION + } + if( fVal ) delete fVal; + fValue = new TGenCollectionProxy::Value( eltname.c_str(), false ); + fVal = new TGenCollectionProxy::Value( *fValue ); + fClass = cl; + + // This container pretends to hold objects, not pointers: + fPointers = kFALSE; + + // Remember that the initialisation succeeded: + fInitialized = kTRUE; +#if ROOT_VERSION_CODE <= ROOT_VERSION( 6, 2, 5 ) + fProperties |= kIsInitialized; +#endif // ROOT_VERSION + + return this; + } + + /// Initialize the cached pointer offsets. + /// + /// Suppose we have @c D deriving from @c B, and thus + /// @c DataVector\<D> deriving from @c DataVector\<B>. + /// In general, inheritance may be multiple or virtual, + /// so we need to adjust the pointer offsets. + /// + /// Suppose we're setting up the proxy for @c DataVector\<D>. + /// Then @c fContoff will be set to the offset of the @c DataVector\<B> base + /// within @c DataVector\<D> --- this is the amount we need to shift the + /// container pointer by before applying the proxy. + /// Originally, we cached an offset for the element conversions + /// as well. But that doesn't work for the case of virtual derivation. + /// Instead, we save the Reflex types for the base and derived types, + /// and use Reflex to convert. (We can get away with caching the + /// offset for the container because we know what the fully-derived + /// type will be. We don't know that for the elements.) + /// + /// @param elttype The name of the contained type (including a trailing '*'). + /// @param conttype The name of the container type we're proxying. + /// Note that this may be different from + /// a @c DataVector of @a elttype for classes which + /// derive from @c DataVector. + void TDVCollectionProxy::FindOffsets( const char* elttype, + const char* conttype ) { + + // Start by assuming no offsets. + fContoff = 0; + fOffset = 0; + + // Find its TClass. + TClass* dvclass = TClass::GetClass( conttype ); + if( ! dvclass ) { + ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets", + "Cannot find class %s", conttype ); + return; + } + + // Find the TClass for the base DataVector class. + TClass* dvbase = findDVBase( dvclass ); + if( ! dvbase ) { + TClass* elclass = classFromDVClass( dvclass ); + if( ! elclass ) { + ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets", + "Couldn't find element type of %s", + dvclass->GetName() ); + return; + } + fEltBase = elclass; + fEltType = fEltBase; + + // No inheritance --- offsets are zero. + return; + } + + // Find the container offset. + fContoff = safeGetBaseOffset( dvclass, dvbase ); + + // Now, find the base and derived element classes. + std::string elttype2 = elttype; + if( elttype2[ elttype2.size() - 1 ] == '*' ) { + elttype2.erase( elttype2.size() - 1 ); + } + fEltType = TClass::GetClass( elttype2.c_str() ); + fEltBase = classFromDVClass( dvbase ); + + if( ( ! fEltType ) || ( ! fEltBase ) ) { + ::Fatal( "xAOD::TDVCollectionProxy::FindOffsets", + "Couldn't find dictionaries for DV element " + "type(s) for %s", conttype ); + return; + } + + // Get the offset needed for the pointer operations: + fOffset = safeGetBaseOffset( fEltType, fEltBase ); + + return; + } + +} // namespace xAOD diff --git a/EDM/athena/xAOD/xAODCore/Root/Utils.cxx b/EDM/athena/xAOD/xAODCore/Root/Utils.cxx new file mode 100644 index 00000000..73c88d6c --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/Root/Utils.cxx @@ -0,0 +1,170 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Utils.cxx 672864 2015-06-05 16:55:45Z ssnyder $ + +// System include(s): +#include <cmath> +#include <sstream> + +// Local include(s): +#include "xAODCore/tools/Utils.h" + +namespace { + + /// Simple structure describing an elapsed amount of time + /// + /// In order to print some elapsed times in a nice way, the + /// private functions of this source file use this structure. + /// + /// The amount of times measured by the code should be + /// representable by this structure. (We shouldn't care about + /// sub-milisecond times, or longer running periods than a + /// few days...) + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 672864 $ + /// $Date: 2015-06-05 18:55:45 +0200 (Fri, 05 Jun 2015) $ + /// + struct TimeStruct { + int miliseconds; ///< Elapsed milisecods + int seconds; ///< Elapsed seconds + int minutes; ///< Elapsed minutes + int hours; ///< Elapsed hours + int days; ///< Elapsed days + }; // struct TimeStruct + + /// Function creating a time structure + /// + /// This function is used to break down a simple elapsed time expressed in + /// seconds into an easy-to-print structure. Shame that I couldn't find + /// something in standard C/C++ to do it... + /// + /// @param secs The elapsed time expressed in seconds + /// @returns A structure describing the elapsed time + /// + TimeStruct timeToStruct( ::Double_t secs ) { + + // Create the structure, fill its miliseconds variable, + // and reset all the rest: + TimeStruct result = { + static_cast< ::Int_t >( std::fmod( secs, 1.0 ) * 1000.0 ), + 0, 0, 0, 0 }; + + // If the elapsed time was less than a second, finish here: + secs -= ( result.miliseconds * 1e-3 ); + if( std::abs( secs ) < 0.5 ) return result; + + // Calculate the number of seconds passed, and finish if the + // amount of time passed was less than a minute: + result.seconds = + static_cast< ::Int_t >( std::fmod( secs, 60.0 ) ); + secs -= result.seconds; + if( std::abs( secs ) < 0.5 ) return result; + + // Calculate the number of minutes passed, and finish if the + // amount of time passed was less than an hour: + result.minutes = + static_cast< ::Int_t >( std::fmod( secs, 3600.0 ) * (1./60.) ); + secs -= result.minutes * 60.0; + if( std::abs( secs ) < 0.5 ) return result; + + // Calculate the number of hours passed, and finish if the + // amount of time passed was less than a day: + result.hours = + static_cast< ::Int_t >( std::fmod( secs, 86400.0 ) * (1./3600.) ); + secs -= result.hours * 3600.0; + if( std::abs( secs ) < 0.5 ) return result; + + // Calculate the number of days passed. The function should + // not expect to have to express a larger order of magnitude... + result.days = static_cast< ::Int_t >( secs * (1./86400.)); + + return result; + } + +} // private namespace + +namespace xAOD { + + /// Since I wasn't able to find a nice function printing elapsed times + /// in a human-readable format, I ended up writing one. This function + /// is used in printing the statistics about an analysis. + /// + /// @param secs An amount of time passed, expressed in seconds + /// @returns A formatted, human-readable version of the amount of time passed + /// + std::string Utils::timeToString( ::Double_t secs ) { + + // Do meat of the calculation: + const TimeStruct ts = timeToStruct( secs ); + + // Construct the string: + std::ostringstream result; + if( ts.days ) { + result << ts.days << "d "; + } + if( ts.hours || ts.days ) { + result << ts.hours << "h "; + } + if( ts.minutes || ts.hours || ts.days ) { + result << ts.minutes << "m "; + } + if( ts.seconds || ts.minutes || ts.hours || ts.days ) { + result << ts.seconds << "s "; + } + result << ts.miliseconds << "ms"; + + return result.str(); + } + + /// This function is used to produce nicely readable printouts for + /// amounts of data. + /// + /// @param bytes The amount of data expressed in bytes + /// @returns A human-readable printout of the data size + /// + std::string Utils::sizeToString( ::Long64_t bytes ) { + + std::ostringstream result; + + if( std::abs( bytes ) > 1e12 ) { + result << ( bytes * 1e-12 ) << " TB"; + } else if( std::abs( bytes ) > 1e9 ) { + result << ( bytes * 1e-9 ) << " GB"; + } else if( std::abs( bytes ) > 1e6 ) { + result << ( bytes * 1e-6 ) << " MB"; + } else if( std::abs( bytes ) > 1e3 ) { + result << ( bytes * 1e-3 ) << " kB"; + } else { + result << bytes << " bytes"; + } + + return result.str(); + } + + /// @param bytespersec The speed expressed in bytes / seconds + /// @returns A human-readable printout of the data processing speed + /// + std::string Utils::speedToString( ::Double_t bytespersec ) { + + std::ostringstream result; + + if( ::fabs( bytespersec ) > 1e12 ) { + result << ( bytespersec * 1e-12 ) << " TB/s"; + } else if( ::fabs( bytespersec ) > 1e9 ) { + result << ( bytespersec * 1e-9 ) << " GB/s"; + } else if( ::fabs( bytespersec ) > 1e6 ) { + result << ( bytespersec * 1e-6 ) << " MB/s"; + } else if( ::fabs( bytespersec ) > 1e3 ) { + result << ( bytespersec * 1e-3 ) << " kB/s"; + } else { + result << bytespersec << " B/s"; + } + + return result.str(); + } + +} // namespace D3PDReader diff --git a/EDM/athena/xAOD/xAODCore/cmt/Makefile.RootCore b/EDM/athena/xAOD/xAODCore/cmt/Makefile.RootCore new file mode 100644 index 00000000..79f74ff1 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/cmt/Makefile.RootCore @@ -0,0 +1,24 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = xAODCore +PACKAGE_PRELOAD = RIO +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = AthContainersInterfaces AthContainers +PACKAGE_TRYDEP = +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 1 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 0 +PACKAGE_REFLEX = 1 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/EDM/athena/xAOD/xAODCore/cmt/requirements b/EDM/athena/xAOD/xAODCore/cmt/requirements new file mode 100644 index 00000000..4a27b8c7 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/cmt/requirements @@ -0,0 +1,52 @@ +package xAODCore +# $Id: requirements 793737 2017-01-24 20:11:10Z ssnyder $ + +author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + +public + +use AtlasPolicy AtlasPolicy-* +use AthenaKernel AthenaKernel-* Control +use SGTools SGTools-* Control +use AthLinks AthLinks-* Control +use AthContainersInterfaces AthContainersInterfaces-* Control +use AthContainers AthContainers-* Control + +use AtlasROOT AtlasROOT-* External + +use CxxUtils CxxUtils-* Control + +# This library and all its children have to use Cintex: +apply_tag ROOTCintexLibs +macro_append xAODCore_shlibflags $(rootCintexLibs) +macro_append xAODCore_linkopts $(rootCintexLibs) + +library xAODCore ../Root/*.cxx +apply_pattern installed_library + +private + +use AtlasReflex AtlasReflex-* External +apply_tag ROOTGenVectorLibs + +apply_pattern lcgdict dict=xAODCoreRflx selectionfile=selection.xml \ + headerfiles="../xAODCore/xAODCoreRflxDict.h" \ + extraselection="selectionAthSuppress.xml" + +pattern xAODCoreAthenaDict_patt \ + apply_pattern lcgdict dict=xAODCoreAthena selectionfile=selectionAthena.xml \ + headerfiles="../xAODCore/xAODCoreAthenaDict.h" + +# ROOT::Math dicts only for ROOT5 +apply_pattern root5only_pattern pattern_name="xAODCoreAthenaDict_patt" + +apply_pattern have_root_headers root_headers="tools/ReadStats.h \ + tools/PerfStats.h \ + ../Root/LinkDef.h" \ + headers_lib=xAODCore + +# Declare the unit tests of the package: +use TestTools TestTools-* AtlasTest +apply_pattern UnitTest_run unit_test=ut_xaodcore_auxselection +apply_pattern UnitTest_run unit_test=ut_xaodcore_printhelpers +apply_pattern UnitTest_run unit_test=ut_xaodcore_auxcontainerbase diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxcontainerbase_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxcontainerbase_test.ref new file mode 100644 index 00000000..a5bce3fd --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxcontainerbase_test.ref @@ -0,0 +1 @@ +test1 diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxselection_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxselection_test.ref new file mode 100644 index 00000000..e2b55237 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_auxselection_test.ref @@ -0,0 +1,4 @@ +xAOD::AuxSelection ERROR Mixing + and - options for dynamic attributes +xAOD::AuxSelection ERROR Mixing + and - options for dynamic attributes +xAOD::AuxSelection ERROR Mixing + and - options for dynamic attributes +xAOD::AuxSelection WARNING Selected dynamic Aux atribute "NonExistent" not found in the registry diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_class_def_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_class_def_test.ref new file mode 100644 index 00000000..c5d883d7 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_class_def_test.ref @@ -0,0 +1,4 @@ +Class ID worked +Class typeName worked +Namespaces class typeName worked +Test ok diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_clearDecorations_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_clearDecorations_test.ref new file mode 100644 index 00000000..a46eb5c0 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_clearDecorations_test.ref @@ -0,0 +1,77 @@ +Container contents at the start: + +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 0 + - type: float, name: "FloatVar1", value: 0 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 1 + - type: float, name: "FloatVar1", value: 1 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 2 + - type: float, name: "FloatVar1", value: 2 + +Container contents after clearDecorations(): + +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 0 + - type: float, name: "FloatVar1", value: 0 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 1 + - type: float, name: "FloatVar1", value: 1 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 2 + - type: float, name: "FloatVar1", value: 2 + +Container contents after decoration: + +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 0 + - type: float, name: "FloatVar1", value: 0 + - type: int, name: "IntVar2", value: 2 + - type: float, name: "FloatVar2", value: 3.14159 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 1 + - type: float, name: "FloatVar1", value: 1 + - type: int, name: "IntVar2", value: 2 + - type: float, name: "FloatVar2", value: 3.14159 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 2 + - type: float, name: "FloatVar1", value: 2 + - type: int, name: "IntVar2", value: 2 + - type: float, name: "FloatVar2", value: 3.14159 + +Container contents after clearDecorations(): + +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 0 + - type: float, name: "FloatVar1", value: 0 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 1 + - type: float, name: "FloatVar1", value: 1 +SG::AuxElement + in container 0x7fff48c5a970 + Variables: + - type: int, name: "IntVar1", value: 2 + - type: float, name: "FloatVar1", value: 2 diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_floatcompression_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_floatcompression_test.ref new file mode 100644 index 00000000..7b224592 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_floatcompression_test.ref @@ -0,0 +1,12 @@ +Original value: 1.2345 +Compressed value: 1.23438 (hex: 3f9e0000) +Original value: 3.1415 +Compressed value: 3.14062 (hex: 40490000) +Original value: 2.7182 +Compressed value: 2.72598 (hex: 402e7680) +Original value: 0.5 +Compressed value: 0.501953 (hex: 3f008000) +Original value: 2.3456 +Compressed value: 2.3456 (hex: 40161e4f) +Original value: 0.1234 +Compressed value: 0.1234 (hex: 3dfcb924) diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_printhelpers_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_printhelpers_test.ref new file mode 100644 index 00000000..58e93087 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_printhelpers_test.ref @@ -0,0 +1,25 @@ +SG::AuxElement + standalone object, without auxiliary store +SG::AuxElement + using private store 0x2688440 + Variables: + - type: int, name: "IntValue", value: 12 + - type: float, name: "FloatValue", value: 3.14 + - type: std::vector<int>, name: "VecIntValue", value: [1, 2, 3] + - type: std::vector<float>, name: "VecFloatValue", value: [1.2, 2.3, 3.4] + - type: TypeA, name: "TypeAValue", value: N/A + - type: std::vector<TypeA>, name: "VecTypeAValue", value: N/A +SG::AuxElement + in container 0x7fff8e753090 + Variables: + - type: long, name: "LongValue", value: 234 + - type: unsigned int, name: "UInt32Value", value: 291 +SG::AuxElement + using private store 0x2688440 + Variables: + - type: int, name: "IntValue", value: 12 + - type: float, name: "FloatValue", value: 3.14 + - type: std::vector<int>, name: "VecIntValue", value: [1, 2, 3] + - type: std::vector<float>, name: "VecFloatValue", value: [1.2, 2.3, 3.4] + - type: TypeA, name: "TypeAValue", value: N/A + - type: std::vector<TypeA>, name: "VecTypeAValue", value: N/A diff --git a/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_safedeepcopy_test.ref b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_safedeepcopy_test.ref new file mode 100644 index 00000000..53f358b1 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/share/ut_xaodcore_safedeepcopy_test.ref @@ -0,0 +1,97 @@ +Content of healthyCont: + SG::AuxElement + in container 0x7ffc308bd100 + Variables: + - type: int, name: "testVar1", value: 0 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 0 + SG::AuxElement + in container 0x7ffc308bd100 + Variables: + - type: int, name: "testVar1", value: 1 + - type: float, name: "testVar2", value: 1.5 + - type: short, name: "testVar3", value: 2 + SG::AuxElement + in container 0x7ffc308bd100 + Variables: + - type: int, name: "testVar1", value: 2 + - type: float, name: "testVar2", value: 3 + - type: short, name: "testVar3", value: 4 +Content of brokenCont (before breaking): + SG::AuxElement + in container 0x7ffc308bd210 + Variables: + - type: int, name: "testVar1", value: 0 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 0 + SG::AuxElement + in container 0x7ffc308bd210 + Variables: + - type: int, name: "testVar1", value: 1 + - type: float, name: "testVar2", value: 1.5 + - type: short, name: "testVar3", value: 2 + SG::AuxElement + in container 0x7ffc308bd210 + Variables: + - type: int, name: "testVar1", value: 2 + - type: float, name: "testVar2", value: 3 + - type: short, name: "testVar3", value: 4 +Content of copyCont after healthy deep copy: + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 0 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 0 + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 1 + - type: float, name: "testVar2", value: 1.5 + - type: short, name: "testVar3", value: 2 + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 2 + - type: float, name: "testVar2", value: 3 + - type: short, name: "testVar3", value: 4 +Content of copyCont after healthy safe deep copy: + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 0 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 0 + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 1 + - type: float, name: "testVar2", value: 1.5 + - type: short, name: "testVar3", value: 2 + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 2 + - type: float, name: "testVar2", value: 3 + - type: short, name: "testVar3", value: 4 +Content of copyCont after broken safe deep copy: + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 0 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 0 + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 1 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 2 + SG::AuxElement + in container 0x7ffc308bd320 + Variables: + - type: int, name: "testVar1", value: 2 + - type: float, name: "testVar2", value: 0 + - type: short, name: "testVar3", value: 4 +The assignment operator is no longer broken +All tests succeeded! diff --git a/EDM/athena/xAOD/xAODCore/src/README b/EDM/athena/xAOD/xAODCore/src/README new file mode 100644 index 00000000..899ef3d2 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/src/README @@ -0,0 +1,3 @@ +CMT compilation needs an src/ directory in order to generate CINT +dictionaries without printing an error message. So let's keep this +empty directory around for now... diff --git a/EDM/athena/xAOD/xAODCore/test/inc_AddDVProxy.cxx b/EDM/athena/xAOD/xAODCore/test/inc_AddDVProxy.cxx new file mode 100644 index 00000000..46ddcc59 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_AddDVProxy.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_AddDVProxy.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/AddDVProxy.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/AddDVProxy.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_AuxContainerBase.cxx b/EDM/athena/xAOD/xAODCore/test/inc_AuxContainerBase.cxx new file mode 100644 index 00000000..b7b65227 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_AuxContainerBase.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_AuxContainerBase.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/AuxContainerBase.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/AuxContainerBase.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_AuxSelection.cxx b/EDM/athena/xAOD/xAODCore/test/inc_AuxSelection.cxx new file mode 100644 index 00000000..7b736053 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_AuxSelection.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_AuxSelection.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/AuxSelection.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/AuxSelection.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_BaseInfo.cxx b/EDM/athena/xAOD/xAODCore/test/inc_BaseInfo.cxx new file mode 100644 index 00000000..009f7460 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_BaseInfo.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_BaseInfo.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/BaseInfo.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/BaseInfo.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_CLASS_DEF.cxx b/EDM/athena/xAOD/xAODCore/test/inc_CLASS_DEF.cxx new file mode 100644 index 00000000..8c242744 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_CLASS_DEF.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_CLASS_DEF.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/CLASS_DEF.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/CLASS_DEF.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_ClassID_traits.cxx b/EDM/athena/xAOD/xAODCore/test/inc_ClassID_traits.cxx new file mode 100644 index 00000000..1f75855a --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_ClassID_traits.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_ClassID_traits.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/ClassID_traits.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/ClassID_traits.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxContainer.cxx b/EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxContainer.cxx new file mode 100644 index 00000000..56180f98 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxContainer.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_ShallowAuxContainer.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/ShallowAuxContainer.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/ShallowAuxContainer.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxInfo.cxx b/EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxInfo.cxx new file mode 100644 index 00000000..697dc7be --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_ShallowAuxInfo.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_ShallowAuxInfo.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/ShallowAuxInfo.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/ShallowAuxInfo.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_ShallowCopy.cxx b/EDM/athena/xAOD/xAODCore/test/inc_ShallowCopy.cxx new file mode 100644 index 00000000..9b1153b3 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_ShallowCopy.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_ShallowCopy.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/ShallowCopy.h" can be successfully included +// on its own. + +// Local include(s): +#include "xAODCore/ShallowCopy.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersInfo.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersInfo.cxx new file mode 100644 index 00000000..c9dcb01f --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersInfo.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_AuxPersInfo.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/AuxPersInfo.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/AuxPersInfo.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersVector.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersVector.cxx new file mode 100644 index 00000000..70f2a64b --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_AuxPersVector.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_AuxPersVector.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/AuxPersVector.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/AuxPersVector.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_IOStats.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_IOStats.cxx new file mode 100644 index 00000000..70fd0a9a --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_IOStats.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_IOStats.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/IOStats.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/IOStats.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_PerfStats.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_PerfStats.cxx new file mode 100644 index 00000000..64055f5e --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_PerfStats.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_PerfStats.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/PerfStats.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/PerfStats.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_PrintHelpers.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_PrintHelpers.cxx new file mode 100644 index 00000000..8b9fa2ba --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_PrintHelpers.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_PrintHelpers.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/PrintHelpers.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/PrintHelpers.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_ReadStats.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_ReadStats.cxx new file mode 100644 index 00000000..c7d3a440 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_ReadStats.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_ReadStats.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/ReadStats.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/ReadStats.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_SafeDeepCopy.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_SafeDeepCopy.cxx new file mode 100644 index 00000000..524435bd --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_SafeDeepCopy.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_SafeDeepCopy.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/SafeDeepCopy.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/SafeDeepCopy.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_TDVCollectionProxy.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_TDVCollectionProxy.cxx new file mode 100644 index 00000000..a5cb5228 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_TDVCollectionProxy.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_TDVCollectionProxy.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/TDVCollectionProxy.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/TDVCollectionProxy.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/inc_tools_Utils.cxx b/EDM/athena/xAOD/xAODCore/test/inc_tools_Utils.cxx new file mode 100644 index 00000000..238aac70 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/inc_tools_Utils.cxx @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: inc_tools_Utils.cxx 687601 2015-08-05 10:23:25Z krasznaa $ +// +// File testing that "xAODCore/tools/Utils.h" can be successfully +// included on its own. + +// Local include(s): +#include "xAODCore/tools/Utils.h" + +int main() { + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_class_def.cxx b/EDM/athena/xAOD/xAODCore/test/ut_class_def.cxx new file mode 100644 index 00000000..2c53152f --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_class_def.cxx @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_class_def.cxx 613558 2014-08-26 17:16:16Z krasznaa $ +// +// Simple unit testing for the standalone CLASS_DEF/ClassID_traits code. +// + +// System include(s): +#include <iostream> + +// Local include(s): +#include "xAODCore/CLASS_DEF.h" + +class TestClassA { +public: + TestClassA() {} +}; +class TestClassB{}; + +namespace xAOD { + class TestClassC {}; +} + +CLASS_DEF( TestClassA, 887887, 1 ) +CLASS_DEF( xAOD::TestClassC, 11223344, 1 ) + +int main() { + + if( ClassID_traits< TestClassA >::ID() != 887887 ) { + std::cout << "Wrong class ID for TestClassA" << std::endl; + return -1; + } + std::cout << "Class ID worked" << std::endl; + + if( ClassID_traits< TestClassA >::typeName() != "TestClassA" ) { + std::cout << "Wrong type name for TestClassA" << std::endl; + return -1; + } + std::cout << "Class typeName worked" << std::endl; + + if( ClassID_traits< xAOD::TestClassC >::typeName() != "xAOD::TestClassC" ) { + std::cout << "Wrong type name for xAOD::TestClassC" << std::endl; + return -1; + } + std::cout << "Namespaces class typeName worked" << std::endl; + + //ClassID_traits<TestClassB>::ID(); // this should fail to compile with readable message + + std::cout << "Test ok" << std::endl; + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxcontainerbase_test.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxcontainerbase_test.cxx new file mode 100644 index 00000000..2b88d238 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxcontainerbase_test.cxx @@ -0,0 +1,193 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file xAODCore/test/AuxContainerBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2016 + * @brief Unit tests for AuxContainerBase. (sadly incomplete) + */ + + +#undef NDEBUG +#include "xAODCore/AuxContainerBase.h" +#include <iostream> +#include <sstream> +#include <cassert> + + +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(); } + + +class AuxContainerTest + : public xAOD::AuxContainerBase +{ +public: + AuxContainerTest(); + + std::vector<int> i1; + std::vector<MoveTest> m1; +}; + + +AuxContainerTest::AuxContainerTest() +{ + AUX_VARIABLE(i1); + AUX_VARIABLE(m1); +} + + +bool operator== (const SG::auxid_set_t& s1, + const SG::auxid_set_t& s2) +{ + std::set<SG::auxid_t> x1 (s1.begin(), s1.end()); + std::set<SG::auxid_t> x2 (s2.begin(), s2.end()); + return x1 == x2; +} + + +// Test insertMove. +void test1() +{ + std::cout << "test1\n"; + + SG::auxid_t ityp1 = SG::AuxTypeRegistry::instance().getAuxID<int> ("i1"); + SG::auxid_t ityp2 = SG::AuxTypeRegistry::instance().getAuxID<int> ("i2"); + SG::auxid_t ityp3 = SG::AuxTypeRegistry::instance().getAuxID<int> ("i3"); + SG::auxid_t ityp4 = SG::AuxTypeRegistry::instance().getAuxID<int> ("i4"); + SG::auxid_t mtyp1 = SG::AuxTypeRegistry::instance().getAuxID<MoveTest> ("m1"); + AuxContainerTest s1; + s1.reserve(20); + 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); + } + + AuxContainerTest 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 exp1; + exp1.insert (ityp1); + exp1.insert (ityp2); + exp1.insert (mtyp1); + assert (s1.getAuxIDs() == exp1); + + SG::auxid_set_t exp2 = exp1; + exp2.insert (ityp3); + + SG::auxid_set_t ignore; + ignore.insert (ityp4); + assert (! s1.insertMove (3, s2, ignore)); // false due to added vbl + assert (s1.getAuxIDs() == exp2); + 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); + 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); + } + assert (s1.insertMove (10, s2, ignore)); + assert (s1.size() == 15); + 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])); + } + + SG::auxid_set_t set2; + set2.insert (ityp2); + set2.insert (ityp3); + assert (s1.getStore()->getAuxIDs() == set2); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxselection_test.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxselection_test.cxx new file mode 100644 index 00000000..7d47937f --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_auxselection_test.cxx @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_xaodcore_auxselection_test.cxx 653257 2015-03-11 11:26:15Z krasznaa $ +// +// Unit test for the xAOD::AuxSelection class. +// + +// System include(s): +#include <iostream> + +// Core include(s): +#include "AthContainers/AuxTypeRegistry.h" + +// Local include(s): +#include "xAODCore/AuxSelection.h" + +/// Helper macro for evaluating logical tests +#define SIMPLE_ASSERT( EXP ) \ + do { \ + const bool result = EXP; \ + if( ! result ) { \ + std::cerr << "Expression \"" << #EXP \ + << "\" failed the evaluation" << std::endl; \ + return 1; \ + } \ + } while( 0 ) + +/// Helper operator that is apparently missing from the base code +bool operator== ( const SG::auxid_set_t& id1, const SG::auxid_set_t& id2 ) { + + // Check that they are of the same size: + if( id1.size() != id2.size() ) { + return false; + } + // Check that all elements of the first set appear in the second set: + for( SG::auxid_t id : id1 ) { + if( ! id2.count( id ) ) { + return false; + } + } + // If all of these succeeded, then let's consider them equal: + return true; +} + +int main() { + + // Access the type registry: + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + // Construct some example variable lists: + SG::auxid_set_t idset1; + idset1.insert( reg.getAuxID< int >( "IntVar1" ) ); + idset1.insert( reg.getAuxID< int >( "IntVar2" ) ); + SG::auxid_set_t idset2; + idset2.insert( reg.getAuxID< float >( "FloatVar1" ) ); + idset2.insert( reg.getAuxID< float >( "FloatVar2" ) ); + SG::auxid_set_t idset3; + idset3.insert( idset1.begin(), idset1.end() ); + idset3.insert( idset2.begin(), idset2.end() ); + + // Construct the objects to be tested: + xAOD::AuxSelection sel1; + sel1.selectAux( std::set< std::string >{ "IntVar1", "FloatVar2" } ); + xAOD::AuxSelection sel2; + sel2.selectAux( std::set< std::string >{ "IntVar2", "FloatVar1" } ); + xAOD::AuxSelection sel3; + sel3.selectAux( std::set< std::string >{} ); + xAOD::AuxSelection sel4; + sel4.selectAux( std::set< std::string >{ "-" } ); + xAOD::AuxSelection sel5; + sel5.selectAux( std::set< std::string >{ "-IntVar1", "-FloatVar2" } ); + xAOD::AuxSelection sel6; + sel6.selectAux( std::set< std::string >{ "-IntVar2", "-FloatVar1" } ); + xAOD::AuxSelection sel7; + sel7.selectAux( std::set< std::string >{ "IntVar1", "-FloatVar1" } ); + xAOD::AuxSelection sel8; + sel8.selectAux( std::set< std::string >{ "NonExistent", "IntVar1" } ); + xAOD::AuxSelection sel9; + sel9.selectAux( std::set< std::string >{ "NonExistent", "FloatVar2" } ); + + // Construct the variables that should come out of the processing: + SG::auxid_set_t idref1; + idref1.insert( reg.getAuxID< int >( "IntVar1" ) ); + idref1.insert( reg.getAuxID< float >( "FloatVar2" ) ); + SG::auxid_set_t idref2; + idref2.insert( reg.getAuxID< int >( "IntVar2" ) ); + idref2.insert( reg.getAuxID< float >( "FloatVar1" ) ); + SG::auxid_set_t idref3; + idref3.insert( reg.getAuxID< int >( "IntVar1" ) ); + SG::auxid_set_t idref4; + idref4.insert( reg.getAuxID< int >( "IntVar2" ) ); + SG::auxid_set_t idref5; + idref5.insert( reg.getAuxID< float >( "FloatVar1" ) ); + SG::auxid_set_t idref6; + idref6.insert( reg.getAuxID< float >( "FloatVar2" ) ); + SG::auxid_set_t idref7; + + // Now check that the selections behave as we expected: + SIMPLE_ASSERT( sel1.getSelectedAuxIDs( idset1 ) == idref3 ); + SIMPLE_ASSERT( sel1.getSelectedAuxIDs( idset2 ) == idref6 ); + SIMPLE_ASSERT( sel1.getSelectedAuxIDs( idset3 ) == idref1 ); + + SIMPLE_ASSERT( sel2.getSelectedAuxIDs( idset1 ) == idref4 ); + SIMPLE_ASSERT( sel2.getSelectedAuxIDs( idset2 ) == idref5 ); + SIMPLE_ASSERT( sel2.getSelectedAuxIDs( idset3 ) == idref2 ); + + SIMPLE_ASSERT( sel3.getSelectedAuxIDs( idset1 ) == idset1 ); + SIMPLE_ASSERT( sel3.getSelectedAuxIDs( idset2 ) == idset2 ); + SIMPLE_ASSERT( sel3.getSelectedAuxIDs( idset3 ) == idset3 ); + + SIMPLE_ASSERT( sel4.getSelectedAuxIDs( idset1 ) == idref7 ); + SIMPLE_ASSERT( sel4.getSelectedAuxIDs( idset2 ) == idref7 ); + SIMPLE_ASSERT( sel4.getSelectedAuxIDs( idset3 ) == idref7 ); + + SIMPLE_ASSERT( sel5.getSelectedAuxIDs( idset1 ) == idref4 ); + SIMPLE_ASSERT( sel5.getSelectedAuxIDs( idset2 ) == idref5 ); + SIMPLE_ASSERT( sel5.getSelectedAuxIDs( idset3 ) == idref2 ); + + SIMPLE_ASSERT( sel6.getSelectedAuxIDs( idset1 ) == idref3 ); + SIMPLE_ASSERT( sel6.getSelectedAuxIDs( idset2 ) == idref6 ); + SIMPLE_ASSERT( sel6.getSelectedAuxIDs( idset3 ) == idref1 ); + + SIMPLE_ASSERT( sel7.getSelectedAuxIDs( idset1 ) == idset1 ); + SIMPLE_ASSERT( sel7.getSelectedAuxIDs( idset2 ) == idset2 ); + SIMPLE_ASSERT( sel7.getSelectedAuxIDs( idset3 ) == idset3 ); + + SIMPLE_ASSERT( sel8.getSelectedAuxIDs( idset1 ) == idref3 ); + SIMPLE_ASSERT( sel8.getSelectedAuxIDs( idset2 ) == idref7 ); + SIMPLE_ASSERT( sel8.getSelectedAuxIDs( idset3 ) == idref3 ); + + SIMPLE_ASSERT( sel9.getSelectedAuxIDs( idset1 ) == idref7 ); + SIMPLE_ASSERT( sel9.getSelectedAuxIDs( idset2 ) == idref6 ); + SIMPLE_ASSERT( sel9.getSelectedAuxIDs( idset3 ) == idref6 ); + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_clearDecorations_test.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_clearDecorations_test.cxx new file mode 100644 index 00000000..a649d45c --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_clearDecorations_test.cxx @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_xaodcore_clearDecorations_test.cxx 696772 2015-09-25 08:09:13Z krasznaa $ + +// System include(s): +#include <iostream> + +// Core include(s): +#include "AthContainers/DataVector.h" +#include "AthContainers/AuxElement.h" + +// Local include(s): +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/tools/PrintHelpers.h" + +/// Convenience function to print the payload of the test container +template< class CONTAINER > +void printContainer( const CONTAINER& c ) { + + for( const auto* obj : c ) { + std::cout << *obj << std::endl; + } + + return; +} + +int main() { + + // Create the container to be tested: + DataVector< SG::AuxElement > interface; + xAOD::AuxContainerBase aux; + interface.setStore( &aux ); + + // Add some simple objects to it: + for( int i = 0; i < 3; ++i ) { + SG::AuxElement* obj = new SG::AuxElement(); + interface.push_back( obj ); + obj->auxdata< int >( "IntVar1" ) = i; + obj->auxdata< float >( "FloatVar1" ) = static_cast< float >( i ); + } + + // Print what it looks like now: + std::cout << "Container contents at the start:\n" << std::endl; + printContainer( interface ); + + // Clear the decorations, and see what happens: + interface.clearDecorations(); + std::cout << "\nContainer contents after clearDecorations():\n" << std::endl; + printContainer( interface ); + + // Lock the container: + interface.lock(); + + // Create some decorations: + for( const SG::AuxElement* obj : interface ) { + + obj->auxdecor< int >( "IntVar2" ) = 2; + obj->auxdecor< float >( "FloatVar2" ) = 3.141592; + } + + // Print what it looks like now: + std::cout << "\nContainer contents after decoration:\n" << std::endl; + printContainer( interface ); + + // Clear the decorations, and see what happens: + interface.clearDecorations(); + std::cout << "\nContainer contents after clearDecorations():\n" << std::endl; + printContainer( interface ); + + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_floatcompression_test.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_floatcompression_test.cxx new file mode 100644 index 00000000..8eaa2b2f --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_floatcompression_test.cxx @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_xaodcore_floatcompression_test.cxx 789425 2016-12-13 10:50:12Z krasznaa $ +// +// Unit test for the xAOD::FloatCompressor class. +// + +// System include(s): +#include <iostream> +#include <iomanip> + +// Local include(s): +#include "xAODCore/tools/FloatCompressor.h" + +/// Helper function printing the results of some compressions +void testCompression( const xAOD::FloatCompressor& fc, float value ) { + + std::cout << "Original value: " << std::dec << value << std::endl; + xAOD::FloatCompressor::floatint_t compressed; + compressed.fvalue = fc.reduceFloatPrecision( value ); + std::cout << "Compressed value: " << compressed.fvalue + << " (hex: " << std::hex << std::setw( 8 ) << std::setfill( '0' ) + << compressed.ivalue << ")" << std::endl; + return; +} + +int main() { + + // Create a compressor leaving only 7 mantissa bits: + const xAOD::FloatCompressor fc1( 7 ); + + // Try to compress some numbers, and see what we get: + testCompression( fc1, 1.2345 ); + testCompression( fc1, 3.1415 ); + + // Now test a compressor leaving 16 mantissa bits: + const xAOD::FloatCompressor fc2( 16 ); + + // Try some numbers with this as well: + testCompression( fc2, 2.7182 ); + testCompression( fc2, 0.5 ); + + // Finally, test that when we use the maximal number of mantissa bits for + // a float, the number doesn't get changed. + const xAOD::FloatCompressor fc3( 23 ); + + // Look at some numbers with this as well: + testCompression( fc3, 2.3456 ); + testCompression( fc3, 0.1234 ); + + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_printhelpers_test.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_printhelpers_test.cxx new file mode 100644 index 00000000..be61e13c --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_printhelpers_test.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_xaodcore_printhelpers_test.cxx 646509 2015-02-12 16:43:18Z krasznaa $ + +// System include(s): +#include <iostream> +#include <vector> +#include <stdint.h> + +// EDM include(s): +#include "AthContainers/AuxElement.h" +#include "AthContainers/DataVector.h" +#include "AthContainers/AuxStoreInternal.h" + +// Local include(s): +#include "xAODCore/tools/PrintHelpers.h" + +/// Dummy type +struct TypeA { + int m_value; +}; + +int main() { + + // Construct a standalone, empty object: + SG::AuxElement empty; + std::cout << empty << std::endl; + + // Create an object with a private store, and fill it with some variables: + SG::AuxElement standalone; + standalone.makePrivateStore(); + standalone.auxdata< int >( "IntValue" ) = 12; + standalone.auxdata< float >( "FloatValue" ) = 3.14; + standalone.auxdata< std::vector< int > >( "VecIntValue" ) = + std::vector< int >{ 1, 2, 3 }; + standalone.auxdata< std::vector< float > >( "VecFloatValue" ) = + std::vector< float >{ 1.2, 2.3, 3.4 }; + standalone.auxdata< TypeA >( "TypeAValue" ) = TypeA{ 5 }; + standalone.auxdata< std::vector< TypeA > >( "VecTypeAValue" ) = + std::vector< TypeA >{ TypeA{ 6 }, TypeA{ 7 } }; + std::cout << standalone << std::endl; + + // Create a vector, and decorate its first element: + DataVector< SG::AuxElement > vec; + SG::AuxStoreInternal store; + vec.setStore( &store ); + SG::AuxElement* element = new SG::AuxElement(); + vec.push_back( element ); + element->auxdata< long >( "LongValue" ) = 234; + element->auxdata< uint32_t >( "UInt32Value" ) = 0x123; + std::cout << *element << std::endl; + + // Finally, do one test with the dump(...) function as well: + xAOD::dump( standalone ); + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_safedeepcopy_test.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_safedeepcopy_test.cxx new file mode 100644 index 00000000..3049536e --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_safedeepcopy_test.cxx @@ -0,0 +1,160 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_xaodcore_safedeepcopy_test.cxx 682039 2015-07-10 09:15:16Z krasznaa $ + +// System include(s): +#include <vector> +#include <iostream> + +// Core include(s): +#include "AthContainers/AuxElement.h" +#include "AthContainers/DataVector.h" + +// Local include(s): +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/tools/SafeDeepCopy.h" +#include "xAODCore/tools/PrintHelpers.h" + +/// Auxiliary container used during the tests +class BreakableAuxContainer : public xAOD::AuxContainerBase { + +public: + /// Default constructor + BreakableAuxContainer() { + + AUX_VARIABLE( testVar1 ); + AUX_VARIABLE( testVar2 ); + AUX_VARIABLE( testVar3 ); + } + + /// @name Functions "breaking" various variables in the container + /// @{ + void breakTestVar1() { + testVar1.clear(); + } + void breakTestVar2() { + testVar2.clear(); + } + void breakTestVar3() { + testVar3.clear(); + } + /// @} + +private: + /// @name Test variables + /// @{ + std::vector< int > testVar1; + std::vector< float > testVar2; + std::vector< short > testVar3; + /// @} + +}; // class BreakableAuxContainer + +int main() { + + // Create a healthy and a "broken" container: + BreakableAuxContainer healthyAux, brokenAux; + DataVector< SG::AuxElement > healthyCont, brokenCont; + healthyCont.setStore( &healthyAux ); + brokenCont.setStore( &brokenAux ); + + // Fill them with the same data: + float j = 0.0; + short k = 0; + for( int i = 0; i < 3; ++i, j += 1.5, k += 2 ) { + healthyCont.push_back( new SG::AuxElement() ); + healthyCont.back()->auxdata< int >( "testVar1" ) = i; + healthyCont.back()->auxdata< float >( "testVar2" ) = j; + healthyCont.back()->auxdata< short >( "testVar3" ) = k; + brokenCont.push_back( new SG::AuxElement() ); + brokenCont.back()->auxdata< int >( "testVar1" ) = i; + brokenCont.back()->auxdata< float >( "testVar2" ) = j; + brokenCont.back()->auxdata< short >( "testVar3" ) = k; + } + + // Print their contents: + std::cout << "Content of healthyCont:" << std::endl; + for( const SG::AuxElement* el : healthyCont ) { + std::cout << " " << *el << std::endl; + } + std::cout << "Content of brokenCont (before breaking):" << std::endl; + for( const SG::AuxElement* el : brokenCont ) { + std::cout << " " << *el << std::endl; + } + + // And now break one variable in the container: + brokenAux.breakTestVar2(); + brokenCont.setStore( &brokenAux ); // Needed to clear internal caches... + + // Create a container that will hold the deep copies: + xAOD::AuxContainerBase copyAux; + DataVector< SG::AuxElement > copyCont; + copyCont.setStore( ©Aux ); + + // Try to make a deep copy of the healthy container. This should work with + // the usual method. + for( const SG::AuxElement* orig : healthyCont ) { + SG::AuxElement* copy = new SG::AuxElement(); + copyCont.push_back( copy ); + *copy = *orig; + } + + // Print the content of the copy: + std::cout << "Content of copyCont after healthy deep copy:" << std::endl; + for( const SG::AuxElement* el : copyCont ) { + std::cout << " " << *el << std::endl; + } + + // Use the safe copy function to do the same copy: + copyCont.clear(); + for( const SG::AuxElement* orig : healthyCont ) { + SG::AuxElement* copy = new SG::AuxElement(); + copyCont.push_back( copy ); + xAOD::safeDeepCopy( *orig, *copy ); + } + + // Print the content of the copy: + std::cout << "Content of copyCont after healthy safe deep copy:" + << std::endl; + for( const SG::AuxElement* el : copyCont ) { + std::cout << " " << *el << std::endl; + } + + // Make a safe deep copy of the broken container: + copyCont.clear(); + for( const SG::AuxElement* orig : brokenCont ) { + SG::AuxElement* copy = new SG::AuxElement(); + copyCont.push_back( copy ); + xAOD::safeDeepCopy( *orig, *copy ); + } + + // Print the content of the copy: + std::cout << "Content of copyCont after broken safe deep copy:" + << std::endl; + for( const SG::AuxElement* el : copyCont ) { + std::cout << " " << *el << std::endl; + } + + // Finally, just as a double-check, make sure that normal deep copying + // would've broken for the doctored container: + bool brokenAsExpected = false; + try { + SG::AuxElement* copy = new SG::AuxElement(); + copyCont.push_back( copy ); + *copy = *( brokenCont[ 0 ] ); + } catch( const SG::ExcBadAuxVar& ) { + brokenAsExpected = true; + } + if( ! brokenAsExpected ) { + std::cout << "The assignment operator is no longer broken" + << std::endl; + } + + // Tell the user what happened: + std::cout << "All tests succeeded!" << std::endl; + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_shallowcopy.cxx b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_shallowcopy.cxx new file mode 100644 index 00000000..a571c405 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/ut_xaodcore_shallowcopy.cxx @@ -0,0 +1,120 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ut_xaodcore_shallowcopy.cxx 673658 2015-06-09 12:45:34Z krasznaa $ +// +// This is a unit test for xAOD::ShallowAuxContainer that can only run in +// standalone mode. As it needs to access some internals of DataLink +// unfortunately. + +// System include(s): +#include <iostream> +#include <cmath> + +// EDM include(s): +#define private public +#define protected public +# include "AthLinks/DataLink.h" +#undef protected +#undef private +#include "AthContainers/AuxElement.h" +#include "AthContainers/DataVector.h" + +// Local include(s): +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/ShallowAuxContainer.h" + +/// Helper macro for evaluating logical tests +#define SIMPLE_ASSERT( EXP ) \ + do { \ + const bool result = EXP; \ + if( ! result ) { \ + std::cerr << "Expression \"" << #EXP << "\" failed the evaluation" \ + << std::endl; \ + return 1; \ + } \ + } while( 0 ) + +int main() { + + // Create a test container that we'll make a copy of later on: + xAOD::AuxContainerBase origAux; + DataVector< SG::AuxElement > origVec; + origVec.setStore( &origAux ); + for( int i = 0; i < 10; ++i ) { + SG::AuxElement* e = new SG::AuxElement(); + origVec.push_back( e ); + e->auxdata< int >( "IntVar" ) = i; + e->auxdata< float >( "FloatVar" ) = i + 1; + } + + // Make a shallow copy of it: + xAOD::ShallowAuxContainer copyAux; + DataLink< SG::IConstAuxStore > link; + link.m_object = &origAux; + copyAux.setParent( link ); + DataVector< SG::AuxElement > copyVec; + for( size_t i = 0; i < origVec.size(); ++i ) { + copyVec.push_back( new SG::AuxElement() ); + } + copyVec.setStore( ©Aux ); + + // Some starting tests: + copyAux.setShallowIO( true ); + SIMPLE_ASSERT( copyAux.getAuxIDs().size() == 2 ); + SIMPLE_ASSERT( copyAux.getDynamicAuxIDs().size() == 0 ); + SIMPLE_ASSERT( copyAux.getSelectedAuxIDs().size() == 0 ); + copyAux.setShallowIO( false ); + SIMPLE_ASSERT( copyAux.getAuxIDs().size() == 2 ); + SIMPLE_ASSERT( copyAux.getDynamicAuxIDs().size() == 2 ); + SIMPLE_ASSERT( copyAux.getSelectedAuxIDs().size() == 2 ); + + int index = 0; + for( const SG::AuxElement* el : copyVec ) { + SIMPLE_ASSERT( el->auxdata< int >( "IntVar" ) == index ); + SIMPLE_ASSERT( std::abs( el->auxdata< float >( "FloatVar" ) - + static_cast< float >( index + 1 ) ) < 0.0001 ); + ++index; + } + + // Create some modifications + for( size_t i = 0; i < copyVec.size(); ++i ) { + copyVec[ i ]->auxdata< int >( "IntVar" ) = i + 2; + copyVec[ i ]->auxdata< double >( "DoubleVar" ) = 3.14; + } + + // Check what happened: + copyAux.setShallowIO( true ); + SIMPLE_ASSERT( copyAux.getAuxIDs().size() == 3 ); + SIMPLE_ASSERT( copyAux.getDynamicAuxIDs().size() == 2 ); + SIMPLE_ASSERT( copyAux.getSelectedAuxIDs().size() == 2 ); + copyAux.setShallowIO( false ); + SIMPLE_ASSERT( copyAux.getAuxIDs().size() == 3 ); + SIMPLE_ASSERT( copyAux.getDynamicAuxIDs().size() == 3 ); + SIMPLE_ASSERT( copyAux.getSelectedAuxIDs().size() == 3 ); + + index = 0; + for( const SG::AuxElement* el : copyVec ) { + SIMPLE_ASSERT( el->auxdata< int >( "IntVar" ) == index + 2 ); + SIMPLE_ASSERT( std::abs( el->auxdata< float >( "FloatVar" ) - + static_cast< float >( index + 1 ) ) < 0.0001 ); + SIMPLE_ASSERT( std::abs( el->auxdata< double >( "DoubleVar" ) - + 3.14 ) < 0.0001 ); + ++index; + } + + // Finally, test variable filtering: + copyAux.selectAux( std::set< std::string >( { "FloatVar", "DoubleVar" } ) ); + copyAux.setShallowIO( true ); + SIMPLE_ASSERT( copyAux.getSelectedAuxIDs().size() == 1 ); + copyAux.setShallowIO( false ); + SIMPLE_ASSERT( copyAux.getSelectedAuxIDs().size() == 2 ); + + // Tell the user that everything went okay: + std::cout << "All tests with xAOD::ShallowAuxContainer succeeded" + << std::endl; + + // Return gracefully: + return 0; +} diff --git a/EDM/athena/xAOD/xAODCore/test/xAODCore_test.xml b/EDM/athena/xAOD/xAODCore/test/xAODCore_test.xml new file mode 100644 index 00000000..645cf1ce --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/test/xAODCore_test.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!DOCTYPE unifiedTestConfiguration SYSTEM "http://www.hep.ucl.ac.uk/atlas/AtlasTesting/DTD/unifiedTestConfiguration.dtd"> +<unifiedTestConfiguration> + <atn> + <TEST name="xAODCore_test" type="makecheck"> + <timelimit>5</timelimit> + <author>Attila Krasznahorkay</author> + <mailto>Attila.Krasznahorkay at cern.ch</mailto> + <expectations> + <errorMessage> # WARNING_MESSAGE : post.sh> ERROR</errorMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> + </atn> +</unifiedTestConfiguration> diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AddDVProxy.h b/EDM/athena/xAOD/xAODCore/xAODCore/AddDVProxy.h new file mode 100644 index 00000000..5ad92626 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AddDVProxy.h @@ -0,0 +1,263 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AddDVProxy.h 599963 2014-06-02 16:44:36Z ssnyder $ +#ifndef XAODCORE_ADDDVPROXY_H +#define XAODCORE_ADDDVPROXY_H + +// STL include(s): +#include <vector> +#include <set> + +// ROOT include(s): +#include <TClass.h> +#include <TError.h> +#include <TInterpreter.h> +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) +# include <Cintex/Cintex.h> +#endif // ROOT_VERSION + +// EDM include(s): +#include "AthContainers/DataVector.h" + +// Local include(s): +#include "xAODCore/tools/TDVCollectionProxy.h" + +#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 99, 0 ) + +/// Macro for setting up proxying for a specific DataVector<T> type +/// +/// In the xAOD packages that use DataVector classes, one must attach +/// "collection proxies" to the container dictionaries. This collection +/// proxy describes to ROOT how to navigate the contents of the +/// DataVector container. +/// +/// This is set up by adding a file called +/// "src/dict/CollectionProxies.cxx" to the package (well, all files +/// under "src/dict/" are taken into account in the end...), and for each +/// DataVector type defined by a package, adding a line like: +/// +/// <code> +/// ADD_DV_PROXY( MySuperContainer ); +/// </code> +/// +#define ADD_DV_PROXY( TYPE ) \ + namespace ROOT { \ + TGenericClassInfo* GenerateInitInstance( const TYPE* ); \ + } \ + int register_##TYPE##_CollectionProxy() { \ + xAOD::AddDVProxy::add< TYPE >( ROOT::GenerateInitInstance( ( TYPE* ) 0x0 ) ); \ + return 1; \ + } \ + static int _R__UNIQUE_( dummy_##TYPE##_Var ) = \ + register_##TYPE##_CollectionProxy(); \ + R__UseDummy( _R__UNIQUE_( dummy_##TYPE##_Var ) ) + +/// Macro for setting up proxying for a specific namespaced DataVector<T> type +/// +/// In the xAOD packages that use DataVector classes, one must attach +/// "collection proxies" to the container dictionaries. This collection +/// proxy describes to ROOT how to navigate the contents of the +/// DataVector container. +/// +/// This is set up by adding a file called +/// "src/dict/CollectionProxies.cxx" to the package (well, all files +/// under "src/dict/" are taken into account in the end...), and for each +/// DataVector type defined by a package, adding a line like: +/// +/// <code> +/// ADD_DV_PROXY( xAOD, MySuperContainer ); +/// </code> +/// +#define ADD_NS_DV_PROXY( NS, TYPE ) \ + namespace ROOT { \ + TGenericClassInfo* GenerateInitInstance( const NS::TYPE* ); \ + } \ + int register_##NS##_##TYPE##_CollectionProxy() { \ + xAOD::AddDVProxy::add< NS::TYPE >( ROOT::GenerateInitInstance( ( NS::TYPE* ) 0x0 ) ); \ + return 1; \ + } \ + static int _R__UNIQUE_( dummy_##NS##_##TYPE##_Var ) = \ + register_##NS##_##TYPE##_CollectionProxy(); \ + R__UseDummy( _R__UNIQUE_( dummy_##NS##_##TYPE##_Var ) ) + +#else + +/// Macro for setting up proxying for a specific DataVector<T> type +/// +/// In the xAOD packages that use DataVector classes, one must attach +/// "collection proxies" to the container dictionaries. This collection +/// proxy describes to ROOT how to navigate the contents of the +/// DataVector container. +/// +/// This is set up by adding a file called +/// "src/dict/CollectionProxies.cxx" to the package (well, all files +/// under "src/dict/" are taken into account in the end...), and for each +/// DataVector type defined by a package, adding a line like: +/// +/// <code> +/// ADD_DV_PROXY( MySuperContainer ); +/// </code> +/// +#define ADD_DV_PROXY( TYPE ) \ + int register_##TYPE##_CollectionProxy() { \ + xAOD::AddDVProxy::add< TYPE >( 0 ); \ + return 1; \ + } \ + static int _R__UNIQUE_( dummy_##TYPE##_Var ) = \ + register_##TYPE##_CollectionProxy(); \ + R__UseDummy( _R__UNIQUE_( dummy_##TYPE##_Var ) ) + +/// Macro for setting up proxying for a specific namespaced DataVector<T> type +/// +/// In the xAOD packages that use DataVector classes, one must attach +/// "collection proxies" to the container dictionaries. This collection +/// proxy describes to ROOT how to navigate the contents of the +/// DataVector container. +/// +/// This is set up by adding a file called +/// "src/dict/CollectionProxies.cxx" to the package (well, all files +/// under "src/dict/" are taken into account in the end...), and for each +/// DataVector type defined by a package, adding a line like: +/// +/// <code> +/// ADD_DV_PROXY( xAOD, MySuperContainer ); +/// </code> +/// +#define ADD_NS_DV_PROXY( NS, TYPE ) \ + int register_##NS##_##TYPE##_CollectionProxy() { \ + xAOD::AddDVProxy::add< NS::TYPE >( 0 ); \ + return 1; \ + } \ + static int _R__UNIQUE_( dummy_##NS##_##TYPE##_Var ) = \ + register_##NS##_##TYPE##_CollectionProxy(); \ + R__UseDummy( _R__UNIQUE_( dummy_##NS##_##TYPE##_Var ) ) + +#endif // ROOT_VERSION + +namespace xAOD { + + /// Set up collection proxy for a @c DataVector class. + /// + /// If @a cl is a @c DataVector class, or derives from one, then we attach + /// an appropriate Root collection proxy to it. This is required for Root + /// to recognize the class as a collection in, eg, @c TTree::Draw. + /// + class AddDVProxy { + + private: + /// Helper structure implementing the resize(...) function + /// + /// When reading a branch of DataVector<T>, one needs to use a non-generic + /// version of the resize(...) function. This implementation should work + /// fine for all DataVector<T> types. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 599963 $ + /// $Date: 2014-06-02 18:44:36 +0200 (Mon, 02 Jun 2014) $ + /// + template< class T > + struct Helper { + + /// Type of the DataVector container + typedef T Cont_t; + /// Type of the elements in the DataVector + typedef typename Cont_t::base_value_type Value_t; + + /// Function taking care of resizing DataVector<T> objects in memory + /// when branches are read from a TTree. + /// + /// @param obj A pointer to the full-blown DataVector object + /// @param size The size to re-size the vector to + static void resize( void* obj, size_t size ) { + + // Cast the container to the right type: + Cont_t* c = reinterpret_cast< Cont_t* >( obj ); + + // Detach the DataVector from its auxiliary store: + c->setStore( ( SG::IAuxStore* ) 0 ); + + // Resize the container: + c->resize( size ); + + // Make sure that all elements exist and are usable: + for( size_t i = 0; i < size; ++i ) { + + // If the element already exists, we're done: + if( ( *c )[ i ] ) continue; + + // Create a new element: + ( *c )[ i ] = new Value_t(); + } + + return; + } + + }; // struct Helper + + /// Helper function force-loading all the needed dictionaries + static void loadDictionaries(); + + public: + /// Set up collection proxy for a @c DataVector class. + /// + /// If @a cl is a @c DataVector class, or derives from one, then we attach + /// an appropriate Root collection proxy to it. This is required for Root + /// to recognize the class as a collection in, eg, @c TTree::Draw. + template < typename T > + static void add( ROOT::TGenericClassInfo* clInfo ) { + + // Enable library auto-loading: + gInterpreter->EnableAutoLoading(); +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 99, 0 ) + ROOT::Cintex::Cintex::Enable(); +#endif // ROOT_VERSION + + // Load the minimal amount of required dictionaries: + loadDictionaries(); + + // Create the collection proxy instance: + TDVCollectionProxy* proxy = + new TDVCollectionProxy( ClassName< T >::name().c_str() ); + proxy->SetResize( Helper< T >::resize ); + + if( clInfo ) { + + // This is where we go with ROOT 6... + + // Add it to the class info: + clInfo->AdoptCollectionProxy( proxy ); + + } else { + + // This is where we go with ROOT 5... + + // Try to access the class's dictionary: + TClass* cl = TClass::GetClass( typeid( T ) ); + if( ! cl ) { + ::Error( "xAOD::AddDVProxy::add", + "Couldn't find dictionary for type \"%s\"", + ClassName< T >::name().c_str() ); + delete proxy; + return; + } + + // Attach the proxy to the dictionary: + cl->CopyCollectionProxy( *proxy ); + // We don't need this instance anymore: + delete proxy; + + } + + return; + } + + }; // struct AddDVProxy + +} // namespace xAOD + +#endif // XAODCORE_ADDDVPROXY_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.h b/EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.h new file mode 100644 index 00000000..23f620bd --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.h @@ -0,0 +1,235 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxContainerBase.h 793737 2017-01-24 20:11:10Z ssnyder $ +#ifndef XAODCORE_AUXCONTAINERBASE_H +#define XAODCORE_AUXCONTAINERBASE_H + +// STL include(s): +#include <vector> +#include <string> + +// EDM include(s): +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IAuxStoreIO.h" +#include "AthContainersInterfaces/IAuxStoreHolder.h" +#include "AthContainers/tools/threading.h" +#include "AthContainers/PackedContainer.h" +#ifndef XAOD_STANDALONE +# include "AthenaKernel/ILockable.h" +#endif // not XAOD_STANDALONE + +// Local include(s): +#include "xAODCore/AuxSelection.h" + +// Forward declaration(s): +namespace SG { + class IAuxTypeVector; +} + +/// Namespace holding all the xAOD EDM classes +namespace xAOD { + + /// Common base class for the auxiliary containers + /// + /// To make the development of auxiliary containers simpler, + /// they can all inherit from this one class. Then all they + /// need to do is just to declare their data members, everything + /// else is taken care of by this transient base class. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 793737 $ + /// $Date: 2017-01-24 21:11:10 +0100 (Tue, 24 Jan 2017) $ + /// + class AuxContainerBase : public SG::IAuxStore, + public SG::IAuxStoreIO, + public SG::IAuxStoreHolder +#ifndef XAOD_STANDALONE + , public ILockable +#endif // not XAOD_STANDALONE + { + + public: + /// The aux ID type definition + typedef SG::auxid_t auxid_t; + /// The aux ID set type definition + typedef SG::auxid_set_t auxid_set_t; + + /// Default constructor + AuxContainerBase( bool allowDynamicVars = true ); + /// Copy constructor + AuxContainerBase( const AuxContainerBase& parent ); + /// Constructor receiving a "dynamic auxiliary store" + AuxContainerBase( const SG::IAuxStore* store ); + /// Destructor + ~AuxContainerBase(); + + /// Assignment operator + AuxContainerBase& operator=( const AuxContainerBase& rhs ); + + /// @name Functions implementing the SG::IAuxStoreHolder interface + /// @{ + + /// Get the currently used internal store object + virtual SG::IAuxStore* getStore() const; + /// Set a different internal store object + virtual void setStore( SG::IAuxStore* store ); + /// Return the type of the store object + virtual AuxStoreType getStoreType() const { return AST_ContainerStore; } + + /// @} + + /// @name Functions implementing the SG::IConstAuxStore interface + /// @{ + + /// Get a pointer to a given array + virtual const void* getData( auxid_t auxid ) const; + + /// Get the types(names) of variables handled by this container + virtual const auxid_set_t& getAuxIDs() const; + + /// Get a pointer to a given array, as a decoration. + virtual void* getDecoration( auxid_t auxid, size_t size, + size_t capacity ); + + /// Lock the container. + virtual void lock(); + + /// Clear all decorations. + virtual void clearDecorations(); + + /// Get the size of the container. + virtual size_t size() const; + + /// @} + + /// @name Functions implementing the SG::IAuxStore interface + /// @{ + + /// Get a pointer to a given array, creating the array if necessary + virtual void* getData( auxid_t auxid, size_t size, + size_t capacity ); + + /// Return a set of writable data identifiers + virtual const auxid_set_t& getWritableAuxIDs() const; + + /// Resize the arrays to a given size + virtual bool resize( size_t size ); + /// Reserve a given size for the arrays + 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); + /// Make an option setting on an aux variable. + virtual bool setOption( auxid_t id, const SG::AuxDataOption& option ); + + /// @} + + /// @name Functions implementing the SG::IAuxStoreIO interface + /// @{ + + /// Get a pointer to the data being stored for one aux data item + virtual const void* getIOData( auxid_t auxid ) const; + + /// Return the type of the data to be stored for one aux data item + virtual const std::type_info* getIOType( auxid_t auxid ) const; + + /// Get the types(names) of variables created dynamically + virtual const auxid_set_t& getDynamicAuxIDs() const; + + /// Select dynamic Aux attributes by name (for writing) + virtual void selectAux( const std::set< std::string >& attributes ); + + /// Get the IDs of the selected dynamic Aux variables (for writing) + virtual const SG::auxid_set_t& getSelectedAuxIDs() const; + + /// @} + + /// @name Functions managing the instance name of the container + /// @{ + + /// Get the name of the container instance + const char* name() const; + /// Set the name of the container instance + void setName( const char* name ); + + /// @} + + protected: + /// Register one of the persistent variables internally + template< typename T > + void regAuxVar( const std::string& name, + std::vector< T >& vec ); + + /// Register one of the persistent variables internally + template< typename T > + void regAuxVar( const std::string& name, + SG::PackedContainer< T >& vec ); + + private: + /// Common code between regAuxVar cases. + template< typename ELT, typename CONT > + void regAuxVar1( const std::string& name, + CONT& vec ); + + /// Dynamic attributes selection implementation + AuxSelection m_selection; + /// Internal list of all available variables + mutable auxid_set_t m_auxids; + /// Internal list of all managed variables + std::vector< SG::IAuxTypeVector* > m_vecs; + + /// Internal dynamic auxiliary store object + SG::IAuxStore* m_store; + /// The IO interface to the internal auxiliary store + SG::IAuxStoreIO* m_storeIO; + /// Flag deciding if the object owns the dynamic store or not + bool m_ownsStore; + /// Has the container been locked? + bool m_locked; + + /// Count changes to @c m_auxids. + mutable size_t m_tick; + + /// Mutex for multithread synchronization. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard< mutex_t > guard_t; + mutable mutex_t m_mutex; + + /// Helper class for the thread-local auxid set implementation + struct TSAuxidSet { + size_t m_tick; + auxid_set_t m_set; + TSAuxidSet( size_t tick, const auxid_set_t& set ) + : m_tick( tick ), m_set( set ) { } + }; // struct TSAuxidSet + /// Thread-local versions of the auxid set + mutable AthContainers_detail::thread_specific_ptr< TSAuxidSet > m_tsAuxids; + + /// Name of the container in memory. Set externally. + std::string m_name; + + }; // class AuxContainerBase + +} // namespace xAOD + +// Declare a class ID for the class: +#include "xAODCore/CLASS_DEF.h" +CLASS_DEF( xAOD::AuxContainerBase, 1225080690, 1 ) + +// Describe the inheritance of the class: +#include "xAODCore/BaseInfo.h" +SG_BASES3( xAOD::AuxContainerBase, SG::IAuxStore, SG::IAuxStoreIO, + SG::IAuxStoreHolder ); + +// Include the template implementation: +#include "AuxContainerBase.icc" + +#endif // XAODCORE_AUXCONTAINERBASE_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.icc b/EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.icc new file mode 100644 index 00000000..c519c847 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AuxContainerBase.icc @@ -0,0 +1,90 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxContainerBase.icc 633391 2014-12-03 15:58:38Z ssnyder $ +#ifndef XAODCORE_AUXCONTAINERBASE_ICC +#define XAODCORE_AUXCONTAINERBASE_ICC + +// System include(s): +#include <iostream> + +// EDM include(s): +#include "AthContainers/AuxTypeRegistry.h" + +// Local include(s): +#include "xAODCore/tools/AuxPersVector.h" + +#ifndef AUX_VARIABLE + +/// Convenience macro for declaring an auxiliary variable +/// +/// Should be used in the constructor of the derived class, like: +/// <code> +/// AUX_VARIABLE( etcone20 ); +/// </code> +#define AUX_VARIABLE( VAR ) regAuxVar( #VAR, VAR ) + +#endif // not AUX_VARIABLE + +namespace xAOD { + + /// Common code between vector and PackedContainer cases. + template< typename ELT, typename CONT > + void AuxContainerBase::regAuxVar1( const std::string& name, + CONT& vec ) { + + // Ask the registry for the number of this variable: + const auxid_t auxid = + SG::AuxTypeRegistry::instance().template getAuxID< ELT >( name ); + + // Make sure that the internal vector is big enough: + if( m_vecs.size() <= auxid ) { + m_vecs.resize( auxid + 1 ); + } + + // Check if this variable name was already registered: + if( m_vecs[ auxid ] ) { + std::cout << "WARNING xAOD::AuxContainerBase::regAuxVec " + << "Re-registering variable with name \"" + << name.c_str() << std::endl; + delete m_vecs[ auxid ]; + } + + // Register the variable: + m_vecs[ auxid ] = new AuxPersVector< ELT, CONT >( vec ); + + // Remember that we are now handling this variable: + m_auxids.insert( auxid ); + ++m_tick; + + return; + } + + /// The user is expected to use this function inside the constructor of + /// the derived class. + /// + /// @param name The name of the variable. Same as the C++ variable's name. + /// @param vec A reference to the auxiliary variable inside the object + template< typename T > + void AuxContainerBase::regAuxVar( const std::string& name, + std::vector< T >& vec ) { + regAuxVar1<T> (name, vec); + } + + /// The user is expected to use this function inside the constructor of + /// the derived class. + /// + /// @param name The name of the variable. Same as the C++ variable's name. + /// @param vec A reference to the auxiliary variable inside the object + template< typename T > + void AuxContainerBase::regAuxVar( const std::string& name, + SG::PackedContainer< T >& vec ) { + regAuxVar1<T> (name, vec); + } + +} // namespace xAOD + +#endif // XAODCORE_AUXCONTAINERBASE_ICC diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.h b/EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.h new file mode 100644 index 00000000..03bf8b0a --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.h @@ -0,0 +1,222 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxInfoBase.h 793737 2017-01-24 20:11:10Z ssnyder $ +#ifndef XAODCORE_AUXINFOBASE_H +#define XAODCORE_AUXINFOBASE_H + +// System include(s): +#include <vector> + +// EDM include(s): +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IAuxStoreIO.h" +#include "AthContainersInterfaces/IAuxStoreHolder.h" +#include "AthContainers/tools/threading.h" +#ifndef XAOD_STANDALONE +# include "AthenaKernel/ILockable.h" +#endif // not XAOD_STANDALONE + +// Local include(s): +#include "xAODCore/AuxSelection.h" + +// Forward declaration(s): +namespace SG { + class IAuxTypeVector; + class AuxDataOption; +} + +namespace xAOD { + + /// Common base class for auxiliary info objects + /// + /// This class should be used as the base for classes describing + /// auxiliary information about standalone objects. The most important + /// example of this is the xAOD::EventInfo object... + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 793737 $ + /// $Date: 2017-01-24 21:11:10 +0100 (Tue, 24 Jan 2017) $ + /// + class AuxInfoBase : public SG::IAuxStore, + public SG::IAuxStoreIO, + public SG::IAuxStoreHolder +#ifndef XAOD_STANDALONE + , public ILockable +#endif // not XAOD_STANDALONE + { + + public: + /// The aux ID type definition + typedef SG::auxid_t auxid_t; + /// The aux ID set type definition + typedef SG::auxid_set_t auxid_set_t; + + /// Default constructor + AuxInfoBase( bool allowDynamicVars = true ); + /// Copy constructor + AuxInfoBase( const AuxInfoBase& parent ); + /// Constructor receiving a "dynamic auxiliary store" + AuxInfoBase( const SG::IAuxStore* store ); + /// Destructor + ~AuxInfoBase(); + + /// Assignment operator + AuxInfoBase& operator=( const AuxInfoBase& rhs ); + + /// @name Functions implementing the SG::IAuxStoreHolder interface + /// @{ + + /// Get the currently used internal store object + virtual SG::IAuxStore* getStore() const; + /// Set a different internal store object + virtual void setStore( SG::IAuxStore* store ); + /// Return the type of the store object + virtual AuxStoreType getStoreType() const { return AST_ObjectStore; } + + /// @} + + /// @name Functions implementing the SG::IConstAuxStore interface + /// @{ + + /// Get a pointer to a given array + virtual const void* getData( auxid_t auxid ) const; + + /// Get the types(names) of variables handled by this container + virtual const auxid_set_t& getAuxIDs() const; + + /// Get a pointer to a given array, as a decoration + virtual void* getDecoration( auxid_t auxid, size_t size, + size_t capacity ); + + /// Lock the container + virtual void lock(); + + /// Clear all decorations + virtual void clearDecorations(); + + /// Get the size of the container + virtual size_t size() const; + + /// @} + + /// @name Functions implementing the SG::IAuxStore interface + /// @{ + + /// Get a pointer to a given array, creating the array if necessary + virtual void* getData( auxid_t auxid, size_t size, + size_t capacity ); + + /// Return a set of writable data identifiers + virtual const auxid_set_t& getWritableAuxIDs() const; + + /// Resize the arrays to a given size + virtual bool resize( size_t size ); + /// Reserve a given size for the arrays + 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); + /// Make an option setting on an aux variable. + virtual bool setOption( auxid_t id, const SG::AuxDataOption& option ); + + /// @} + + /// @name Functions implementing the SG::IAuxStoreIO interface + /// @{ + + /// Get a pointer to the data being stored for one aux data item + virtual const void* getIOData( auxid_t auxid ) const; + + /// Return the type of the data to be stored for one aux data item + virtual const std::type_info* getIOType( auxid_t auxid ) const; + + /// Get the types(names) of variables created dynamically + virtual const auxid_set_t& getDynamicAuxIDs() const; + + /// Select dynamic Aux attributes by name (for writing) + virtual void selectAux( const std::set< std::string >& attributes ); + + /// Get the IDs of the selected dynamic Aux variables (for writing) + virtual const SG::auxid_set_t& getSelectedAuxIDs() const; + + /// @} + + /// @name Functions managing the instance name of the container + /// @{ + + /// Get the name of the container instance + const char* name() const; + /// Set the name of the container instance + void setName( const char* name ); + + /// @} + + protected: + /// Register one of the persistent variables internally + template< typename T > + void regAuxVar( const std::string& name, + T& info ); + + private: + /// Dynamic attributes selection implementation + AuxSelection m_selection; + /// Internal list of all available variables + mutable auxid_set_t m_auxids; + /// Internal list of all managed variables + std::vector< SG::IAuxTypeVector* > m_vecs; + + /// Internal dynamic auxiliary store object + SG::IAuxStore* m_store; + /// The IO interface to the internal auxiliary store + SG::IAuxStoreIO* m_storeIO; + /// Flag deciding if the object owns the dynamic store or not + bool m_ownsStore; + /// Has the container been locked? + bool m_locked; + + /// Count changes to @c m_auxids. + mutable size_t m_tick; + + /// Mutex for multithread synchronization. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard< mutex_t > guard_t; + mutable mutex_t m_mutex; + + /// Helper class for the thread-local auxid set implementation + struct TSAuxidSet { + size_t m_tick; + auxid_set_t m_set; + TSAuxidSet( size_t tick, const auxid_set_t& set ) + : m_tick( tick ), m_set( set ) { } + }; // class TSAuxidSet + /// Thread-local versions of the auxid set + mutable AthContainers_detail::thread_specific_ptr< TSAuxidSet > m_tsAuxids; + + /// Name of the container in memory. Set externally. + std::string m_name; + + }; // class AuxInfoBase + +} // namespace xAOD + +// Declare a class ID for the class: +#include "xAODCore/CLASS_DEF.h" +CLASS_DEF( xAOD::AuxInfoBase, 226113180, 1 ) + +// Describe the inheritance of the class: +#include "xAODCore/BaseInfo.h" +SG_BASES3( xAOD::AuxInfoBase, SG::IAuxStore, SG::IAuxStoreIO, + SG::IAuxStoreHolder ); + +// Include the template implementation: +#include "AuxInfoBase.icc" + +#endif // XAODCORE_AUXINFOBASE_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.icc b/EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.icc new file mode 100644 index 00000000..a95eb03d --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AuxInfoBase.icc @@ -0,0 +1,72 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxInfoBase.icc 600059 2014-06-03 09:55:09Z ssnyder $ +#ifndef XAODCORE_AUXINFOBASE_ICC +#define XAODCORE_AUXINFOBASE_ICC + +// System include(s): +#include <iostream> + +// EDM include(s): +#include "AthContainers/AuxTypeRegistry.h" + +// Local include(s): +#include "xAODCore/tools/AuxPersInfo.h" + +#ifndef AUX_VARIABLE + +/// Convenience macro for declaring an auxiliary variable +/// +/// Should be used in the constructor of the derived class, like: +/// <code> +/// AUX_VARIABLE( RunNumber ); +/// </code> +# define AUX_VARIABLE( VAR ) regAuxVar( #VAR, VAR ) + +#endif // not AUX_VARIABLE + +namespace xAOD { + + /// The user is expected to use this function inside the constructor of + /// the derived class. + /// + /// @param name The name of the variable. Same as the C++ variable's name. + /// @param vec A reference to the auxiliary variable inside the object + template< typename T > + void AuxInfoBase::regAuxVar( const std::string& name, + T& info ) { + + // Ask the registry for the number of this variable: + const auxid_t auxid = + SG::AuxTypeRegistry::instance().template getAuxID< T >( name ); + + // Make sure that the internal vector is big enough: + if( m_vecs.size() <= auxid ) { + m_vecs.resize( auxid + 1 ); + } + + // Check if this variable name was already registered: + if( m_vecs[ auxid ] ) { + std::cout << "WARNING xAOD::AuxInfoBase::regAuxVar " + << "Re-registering variable with name \"" + << name.c_str() << "\"" << std::endl; + delete m_vecs[ auxid ]; + } + + // Register the variable: + m_vecs[ auxid ] = new AuxPersInfo< T >( info ); + + // Remember that we are now handling this variable: + m_auxids.insert( auxid ); + ++m_tick; + + return; + } + +} // namespace xAOD + +#endif // XAODCORE_AUXINFOBASE_ICC diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AuxSelection.h b/EDM/athena/xAOD/xAODCore/xAODCore/AuxSelection.h new file mode 100644 index 00000000..9136c337 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AuxSelection.h @@ -0,0 +1,53 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxSelection.h 583607 2014-02-17 11:02:08Z krasznaa $ +#ifndef XAODCORE_AUXSELECTION_H +#define XAODCORE_AUXSELECTION_H + +// System include(s): +#include <set> +#include <string> + +// EDM include(s): +#include "AthContainersInterfaces/AuxTypes.h" + +namespace xAOD { + + /// Class helping in dealing with dynamic branch selection + /// + /// This class is used by the code internally to select which of the + /// dynamic branches should be written out into an output file. + /// + /// @author Marcin Nowak <Marcin.Nowak@cern.ch> + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 583607 $ + /// $Date: 2014-02-17 12:02:08 +0100 (Mon, 17 Feb 2014) $ + /// + class AuxSelection { + + public: + /// Default constructor + AuxSelection(); + + /// Select which variables should be written out + virtual void selectAux( const std::set< std::string >& attributes ); + /// Return which variables were selected to be written out + virtual const SG::auxid_set_t& + getSelectedAuxIDs( const SG::auxid_set_t& fullset ) const; + + protected: + /// Properties following the variable selection convention + std::set< std::string > m_names; + /// Auxiliary IDs of the variables that were selected from the last list + mutable SG::auxid_set_t m_auxids; + + }; // class AuxSelection + +} // namespace xAOD + +#endif // XAODCORE_AUXSELECTION_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/AuxStoreAccessorMacros.h b/EDM/athena/xAOD/xAODCore/xAODCore/AuxStoreAccessorMacros.h new file mode 100644 index 00000000..aca0d9fb --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/AuxStoreAccessorMacros.h @@ -0,0 +1,172 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxStoreAccessorMacros.h 633587 2014-12-04 09:09:41Z ssnyder $ +#ifndef XAODCORE_AUXSTOREACCESSORMACROS_H +#define XAODCORE_AUXSTOREACCESSORMACROS_H + +/// Macro creating the accessors of primitive auxiliary properties +/// +/// The idea with this macro is to save ourselves a bit of time +/// and typing. The macro assumes that for a given auxiliary +/// variable, like a floating point variable of name "sthg", we +/// define the functions: +/// +/// <code> +/// float sthg() const;<br/> +/// void setSthg( float value ); +/// </code> +/// +/// in the xAOD class's header. This macro provides the implementation +/// code for these two functions. +/// +/// So, in the previous case, we would use: +/// <code> +/// AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( Dummy, float, sthg, setSthg ) +/// </code> +/// +/// @param CL The name of the xAOD class +/// @param TYPE The (primitive) type name +/// @param NAME The name of the auxiliary variable +/// @param SETTER The name of the "setter function" +/// +#define AUXSTORE_PRIMITIVE_SETTER_AND_GETTER(CL, TYPE, NAME, \ + SETTER) \ + TYPE CL::NAME() const { \ + static Accessor< TYPE > acc( #NAME ); \ + return acc( *this ); \ + } \ + void CL::SETTER( TYPE value ) { \ + static Accessor< TYPE > acc( #NAME ); \ + acc( *this ) = value; \ + return; \ + } + +/// Macro creating the reader function for a primitive auxiliary property +/// +/// This macro is a simplified version of the previous one. It just provides +/// the accessor function for reading an auxiliary variable. It can be +/// useful when setting an auxiliary variable is done in a more involved +/// function, but reading it is done through a simple accessor function. +/// +/// @param CL The name of the xAOD class +/// @param TYPE The (primitive) type name +/// @param NAME The name of the auxiliary variable +/// +#define AUXSTORE_PRIMITIVE_GETTER(CL, TYPE, NAME ) \ + TYPE CL::NAME() const { \ + static Accessor< TYPE > acc( #NAME ); \ + return acc( *this ); \ + } + +/// Macro creating the accessors of complex auxiliary properties +/// +/// This macro should be used in the same way as the +/// AUXSTORE_PRIMITIVE_SETTER_AND_GETTER one. However in contrary to that +/// one, it assumes that the type given to it is heavy enough that it should +/// be passed around using constant references instead of by value. +/// +/// @param CL The name of the xAOD class +/// @param TYPE The (complex) type name +/// @param NAME The name of the auxiliary variable +/// @param SETTER The name of the "setter function" +/// +#define AUXSTORE_OBJECT_SETTER_AND_GETTER(CL, TYPE, NAME, SETTER) \ + const TYPE& CL::NAME() const { \ + static Accessor< TYPE > acc( #NAME ); \ + return acc( *this ); \ + } \ + void CL::SETTER( const TYPE& value ) { \ + static Accessor< TYPE > acc( #NAME ); \ + acc( *this ) = value; \ + return; \ + } + + +/// Macro creating a move accessor for complex auxiliary properties. +/// +/// This macro should be used in the same way as the +/// AUXSTORE_OBJECT_SETTER_AND_GETTER one. In C++11, this will create +/// a setter that takes its argument using move semantics. +/// It is a no-op in C++98. +/// +/// @param CL The name of the xAOD class +/// @param TYPE The (complex) type name +/// @param NAME The name of the auxiliary variable +/// @param SETTER The name of the "setter function" +/// +#if __cplusplus < 201100 +# define AUXSTORE_OBJECT_MOVE(CL, TYPE, NAME, SETTER) +#else +# define AUXSTORE_OBJECT_MOVE(CL, TYPE, NAME, SETTER) \ + void CL::SETTER( typename SG::AuxDataTraits<TYPE>::element_type&& value ) { \ + static Accessor< TYPE > acc( #NAME ); \ + acc( *this ) = std::move(value); \ + return; \ + } +#endif + + +/// Macro creating the reader function for a complex auxiliary property +/// +/// Just like AUXSTORE_OBJECT_SETTER_AND_GETTER, this macro also handles +/// an auxiliary property that should be passed around using constant +/// references. +/// +/// @param CL The name of the xAOD class +/// @param TYPE The (complex) type name +/// @param NAME The name of the auxiliary variable +/// +#define AUXSTORE_OBJECT_GETTER(CL, TYPE, NAME ) \ + const TYPE& CL::NAME() const { \ + static Accessor< TYPE > acc( #NAME ); \ + return acc( *this ); \ + } + +/// Macro creating a getter function with a type conversion +/// +/// In a number of cases we use a different primitive type in the interface +/// classes than what we end up putting into the auxiliary store. In most +/// cases we do double<->float, and enum<->int conversions in these cases. +/// +/// This macro can be used to slightly lower the number of lines needed +/// for implementing such a function. +/// +/// @param CL The name of the xAOD class +/// @param PERSTYPE The persistent (primitive) type name +/// @param TRANSTYPE The transient (primitive) type name +/// @param NAME The name of the auxiliary variable +/// +#define AUXSTORE_PRIMITIVE_GETTER_WITH_CAST(CL, PERSTYPE, TRANSTYPE, \ + NAME) \ + TRANSTYPE CL::NAME() const { \ + static Accessor< PERSTYPE > acc( #NAME ); \ + return static_cast< TRANSTYPE >( acc( *this ) ); \ + } + +/// Macro creating a setter function with a type conversion +/// +/// In a number of cases we use a different primitive type in the interface +/// classes than what we end up putting into the auxiliary store. In most +/// cases we do double<->float, and enum<->int conversions in these cases. +/// +/// This macro can be used to slightly lower the number of lines needed +/// for implementing such a function. +/// +/// @param CL The name of the xAOD class +/// @param PERSTYPE The persistent (primitive) type name +/// @param TRANSTYPE The transient (primitive) type name +/// @param NAME The name of the auxiliary variable +/// +#define AUXSTORE_PRIMITIVE_SETTER_WITH_CAST(CL, PERSTYPE, TRANSTYPE, \ + NAME, SETTER) \ + void CL::SETTER( TRANSTYPE value ) { \ + static Accessor< PERSTYPE > acc( #NAME ); \ + acc( *this ) = static_cast< PERSTYPE >( value ); \ + return; \ + } + +#endif // XAODCORE_AUXSTOREACCESSORMACROS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/BaseInfo.h b/EDM/athena/xAOD/xAODCore/xAODCore/BaseInfo.h new file mode 100644 index 00000000..a000f080 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/BaseInfo.h @@ -0,0 +1,62 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.h 611441 2014-08-12 14:53:49Z krasznaa $ +#ifndef XAODCORE_BASEINFO_H +#define XAODCORE_BASEINFO_H + +/// @file xAODCore/CLASS_DEF.h +/// @author Scott Snyder <snyder@bnl.gov> +/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> +/// +/// @short File providing the different SG_BASE macros +/// +/// In Athena the inheritance relationships of the EDM classes are declared +/// to StoreGate using some simple macros that are used like: +/// +/// <code> +/// #include "xAODCore/BaseInfo.h"<br/> +/// SG_BASE( xAOD::HighLevelClass, xAOD::LowLevelClass );<br/> +/// SG_BASES2( xAOD::LowLevelClass, SG::IAuxStore, SG::IAuxStoreIO ); +/// </code> +/// +/// In ROOT we don't need this extra information, there we rely purely on the +/// ROOT dictionaries of the EDM classes. +/// +/// All the xAOD packages should use this header for declaring SG inheritance +/// relationships for their classes, instead of pulling in these macros from +/// SGTools directly. +/// +/// $Revision: 611441 $ +/// $Date: 2014-08-12 16:53:49 +0200 (Tue, 12 Aug 2014) $ + +#ifdef XAOD_STANDALONE + +// Dummy macro definitions +#ifndef SG_BASE +# define SG_BASE( D, B ) class xAODCoreDummy +#endif // not SG_BASE +#ifndef SG_BASES1 +# define SG_BASES1( D, B ) class xAODCoreDummy +#endif // not SG_BASES1 +#ifndef SG_BASES2 +# define SG_BASES2( D, B1, B2 ) class xAODCoreDummy +#endif // not SG_BASES2 +#ifndef SG_BASES3 +# define SG_BASES3( D, B1, B2, B3 ) class xAODCoreDummy +#endif // not SG_BASES3 +#ifndef SG_ADD_BASE +# define SG_ADD_BASE( D, B ) class xAODCoreDummy +#endif // not SG_ADD_BASE + +#else // not XAOD_STANDALONE + +// Pull in the proper macro definitions +#include "SGTools/BaseInfo.h" + +#endif // not XAOD_STANDALONE + +#endif // not XAODCORE_BASEINFO_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/CLASS_DEF.h b/EDM/athena/xAOD/xAODCore/xAODCore/CLASS_DEF.h new file mode 100644 index 00000000..5b7f0790 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/CLASS_DEF.h @@ -0,0 +1,79 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: CLASS_DEF.h 613558 2014-08-26 17:16:16Z krasznaa $ +#ifndef XAODCORE_CLASS_DEF_H +#define XAODCORE_CLASS_DEF_H + +/// @file xAODCore/CLASS_DEF.h +/// @author Scott Snyder <snyder@bnl.gov> +/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> +/// +/// @short File providing the CLASS_DEF macro +/// +/// In Athena all the EDM classes are identified using an ATLAS specific +/// system that assigns "class IDs" to the different classes. We do this by +/// using the CLASS_DEF macro in the headers of the EDM classes like: +/// +/// <code> +/// #include "xAODCore/CLASS_DEF.h"<br/> +/// CLASS_DEF( xAOD::ClassName, 123456, 1 ) +/// </code> +/// +/// In a ROOT analysis we need much less information about the classes in such +/// a ROOT-independent way. We mostly just make use of that information to +/// decode the trigger navigation EDM. +/// +/// All xAOD packages should use this header for declaring class IDs for their +/// EDM classes instead of using SGTools directly. +/// +/// $Revision: 613558 $ +/// $Date: 2014-08-26 19:16:16 +0200 (Tue, 26 Aug 2014) $ + +#ifdef XAOD_STANDALONE + +// Include the ClassID_traits class: +#include "xAODCore/ClassID_traits.h" + +// Make sure that we get rid of the definitions from other places. +// From AsgTools for instance... +#undef CLASS_DEF + +// Present a dummy macro to ROOT 6's dictionary generator. Otherwise +// it becomes over-eager, and starts generating dictionaries for types +// that it should just ignore. +#ifdef __CLING__ + +/// Dummy version of the macro +#define CLASS_DEF( __type, __clid, __version ) + +#else // __CLING__ + +/// Macro defining a specialisation for the ClassID_traits type +#define CLASS_DEF( __type, __clid, __version ) \ + template<> \ + struct ClassID_traits< __type > { \ + static CLID ID() { \ + return __clid; \ + } \ + static const std::string& typeName() { \ + static std::string name( #__type ); \ + return name; \ + } \ + static const std::type_info& typeId() { \ + return typeid( __type ); \ + } \ + }; + +#endif // __CLING__ + +#else // not XAOD_STANDALONE + +// Pull in the proper macro definition +#include "SGTools/CLASS_DEF.h" + +#endif // not XAOD_STANDALONE +#endif // not XAODCORE_CLASS_DEF_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/ClassID_traits.h b/EDM/athena/xAOD/xAODCore/xAODCore/ClassID_traits.h new file mode 100644 index 00000000..aff7ede6 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/ClassID_traits.h @@ -0,0 +1,83 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ClassID_traits.h 613558 2014-08-26 17:16:16Z krasznaa $ +#ifndef XAODCORE_CLASSID_TRAITS_H +#define XAODCORE_CLASSID_TRAITS_H + +/// @file xAODCore/ClassID_traits.h +/// @author Tomasz Bold <tomasz.bold@cern.ch> +/// +/// @short File providing the ClassID_traits traits class +/// +/// In Athena all the EDM classes are identified using an ATLAS specific +/// system that assigns "class IDs" to the different classes. We do this by +/// using the CLASS_DEF macro in the headers of the EDM classes like: +/// +/// <code> +/// #include "xAODCore/CLASS_DEF.h"<br/> +/// CLASS_DEF( xAOD::ClassName, 123456, 1 ) +/// </code> +/// +/// So made association between the type and identifier is helpful in varous +/// places, trigger among them. It is used in there in order to navigate from +/// the type to the CLID and thanks to that, to RoIs. +/// +/// Code to do it is <code>ClassID_traits<xAOD::ClassName>::ID()</code> and +/// <code>ClassID_traits<xAOD::ClassName>::typeName()</code>. +/// This functionality is provided below. +/// +/// To help developers in figurng out that the CLASS_DEF has not been made for +/// a given class, a compile time error is emitted. +/// +/// $Revision: 613558 $ +/// $Date: 2014-08-26 19:16:16 +0200 (Tue, 26 Aug 2014) $ + +// System include(s): +extern "C" { +# include <stdint.h> +} +#include <string> +#include <typeinfo> + +/// The Class ID type +typedef uint32_t CLID; + +/// Helper used in order to get the clear error message for the developer +template< class T > +struct ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION {}; + +/// Default, invalid implementation of ClassID_traits +/// +/// The CLASS_DEF macro specialises this class in order to provide functional +/// descriptions of the EDM classes. This default class is non-functional on +/// purpose, to generate compile-time errors in case some code tries using +/// CLID information on a type that doesn't provide one. +/// +/// @author Tomasz Bold <tomasz.bold@cern.ch> +/// +/// $Revision: 613558 $ +/// $Date: 2014-08-26 19:16:16 +0200 (Tue, 26 Aug 2014) $ +/// +template< class T > +struct ClassID_traits { + + /// Function returning a unique integer identifier for the selected type + static CLID ID() { + return ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION< T >::please_correct; + } + /// Function returning a user-readable type name for the selected type + static const std::string& typeName() { + return ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION< T >::please_correct; + } + /// Function returning a type identifier for the selected type + static const std::type_info& typeId() { + return ERROR_you_should_use_the_CLASS_DEF_macro_to_define_CLID_and_VERSION< T >::please_correct; + } + +}; // struct ClassID_traits + +#endif // not XAODCORE_CLASSID_TRAITS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxContainer.h b/EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxContainer.h new file mode 100644 index 00000000..8c24e731 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxContainer.h @@ -0,0 +1,224 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ShallowAuxContainer.h 793737 2017-01-24 20:11:10Z ssnyder $ +#ifndef XAODCORE_SHALLOWAUXCONTAINER_H +#define XAODCORE_SHALLOWAUXCONTAINER_H + +// EDM include(s): +#include "AthLinks/DataLink.h" +#include "AthContainersInterfaces/IAuxStore.h" +#include "AthContainersInterfaces/IAuxStoreIO.h" +#include "AthContainersInterfaces/IAuxStoreHolder.h" +#include "AthContainers/tools/threading.h" +#ifndef XAOD_STANDALONE +# include "AthenaKernel/ILockable.h" +#endif // not XAOD_STANDALONE + +// Local include(s): +#include "xAODCore/AuxSelection.h" + +namespace xAOD { + + /// Class creating a shallow copy of an existing auxiliary container + /// + /// During analysis, in order to create objects that override just some + /// of the properties of an original, it's wasteful to make full copies + /// of the objects. Not to mention that the full copies have generally + /// issues with dynamic variables. + /// + /// The behaviour of this class is that it takes all the properties that + /// it doesn't know about from the parent auxiliary store, but the ones + /// that it has an override for, it provides itself. + /// + /// The object is persistifiable. The user can choose whether to only + /// write out the variables that were modified wrt. the original container, + /// or possibly all the variables. (In case the original container is + /// not getting written out.) + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 793737 $ + /// $Date: 2017-01-24 21:11:10 +0100 (Tue, 24 Jan 2017) $ + /// + class ShallowAuxContainer : public SG::IAuxStore, + public SG::IAuxStoreIO, + public SG::IAuxStoreHolder +#ifndef XAOD_STANDALONE + , public ILockable +#endif // not XAOD_STANDALONE + { + + public: + /// The aux ID type definition + typedef SG::auxid_t auxid_t; + /// The aux ID set type definition + typedef SG::auxid_set_t auxid_set_t; + + /// Default constructor + ShallowAuxContainer( bool standalone = false ); + /// Copy constructor + ShallowAuxContainer( const ShallowAuxContainer& parent ); + /// Constructor with a parent object + ShallowAuxContainer( const DataLink< SG::IConstAuxStore >& parent, + bool standalone = false ); + /// Destructor + ~ShallowAuxContainer(); + + /// Assignment operator + ShallowAuxContainer& operator= ( const ShallowAuxContainer& rhs ); + + /// Get the parent store + const DataLink< SG::IConstAuxStore >& parent() const; + /// Set the parent store + void setParent( const DataLink< SG::IConstAuxStore >& link ); + + /// Check whether only the overriden parameters will be written out or not + bool shallowIO() const; + /// Set whether only the overriden parameters should be written out + void setShallowIO( bool value ); + + /// @name Functions implementing the SG::IAuxStoreHolder interface + /// @{ + + /// Get the currently used internal store object + virtual SG::IAuxStore* getStore() const; + /// Set a different internal store object + virtual void setStore( SG::IAuxStore* store ); + /// Return the type of the store object + virtual AuxStoreType getStoreType() const { return AST_ContainerStore; } + + /// @} + + /// @name Functions implementing the SG::IConstAuxStore interface + /// @{ + + /// Get a pointer to a given array + virtual const void* getData( auxid_t auxid ) const; + + /// Get the types(names) of variables handled by this container + virtual const auxid_set_t& getAuxIDs() const; + + /// Return the data vector for one aux data decoration item. + virtual void* getDecoration (auxid_t auxid, size_t size, size_t capacity); + /// Lock the container. + virtual void lock(); + /// Clear all decorations. + virtual void clearDecorations(); + /// Get the size of the container. + virtual size_t size() const; + /// @} + + /// @name Functions implementing the SG::IAuxStore interface + /// @{ + + /// Get a pointer to a given array, creating the array if necessary + virtual void* getData( auxid_t auxid, size_t size, + size_t capacity ); + + /// Return a set of writable data identifiers + virtual const auxid_set_t& getWritableAuxIDs() const; + + /// Resize the arrays to a given size + virtual bool resize( size_t size ); + /// Reserve a given size for the arrays + 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); + + /// @} + + /// @name Functions implementing the SG::IAuxStoreIO interface + /// @{ + + /// Get a pointer to the data being stored for one aux data item + virtual const void* getIOData( auxid_t auxid ) const; + + /// Return the type of the data to be stored for one aux data item + virtual const std::type_info* getIOType( auxid_t auxid ) const; + + /// Get the types(names) of variables created dynamically + virtual const auxid_set_t& getDynamicAuxIDs() const; + + /// Select dynamic Aux attributes by name (for writing) + virtual void selectAux( const std::set< std::string >& attributes ); + + /// Get the IDs of the selected dynamic Aux variables (for writing) + virtual const auxid_set_t& getSelectedAuxIDs() const; + + /// @} + + /// @name Functions managing the instance name of the container + /// @{ + + /// Get the name of the container instance + const char* name() const; + /// Set the name of the container instance + void setName( const char* name ); + + /// @} + + private: + /// Dynamic attributes selection implementation + AuxSelection m_selection; + + /// Internal dynamic auxiliary store object + SG::IAuxStore* m_store; + /// The IO interface to the internal auxiliary store + SG::IAuxStoreIO* m_storeIO; + /// Flag deciding if the object owns the dynamic store or not + bool m_ownsStore; + /// Flag keeping track of whether this object is locked or not + bool m_locked; + + /// Link to the parent object + DataLink< SG::IConstAuxStore > m_parentLink; + /// Optional pointer to the IO interface of the parent object + mutable SG::IAuxStoreIO* m_parentIO; + /// Flag for whether to do "shallow IO" or not + bool m_shallowIO; + + /// Count changes to @c m_auxids. + mutable size_t m_tick; + + /// Mutex for multithread synchronization. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard<mutex_t> guard_t; + mutable mutex_t m_mutex; + + /// Thread-local versions of the auxid set. + struct TSAuxidSet + { + size_t m_tick; + auxid_set_t m_set; + TSAuxidSet (size_t tick, const auxid_set_t& set) + : m_tick (tick), m_set (set) {} + TSAuxidSet () + : m_tick (0) {} + }; + mutable AthContainers_detail::thread_specific_ptr<TSAuxidSet> m_tsAuxids; + + /// Name of the container in memory. Set externally. + std::string m_name; + + }; // class ShallowAuxContainer + +} // namespace xAOD + +// Declare a class ID for the class: +#include "xAODCore/CLASS_DEF.h" +CLASS_DEF( xAOD::ShallowAuxContainer, 1111823638, 1 ) + +// Describe the inheritance of the class: +#include "xAODCore/BaseInfo.h" +SG_BASES3( xAOD::ShallowAuxContainer, SG::IAuxStore, SG::IAuxStoreIO, + SG::IAuxStoreHolder ); + +#endif // XAODCORE_SHALLOWAUXCONTAINER_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxInfo.h b/EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxInfo.h new file mode 100644 index 00000000..711d30f0 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/ShallowAuxInfo.h @@ -0,0 +1,52 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ShallowAuxInfo.h 671678 2015-06-02 12:28:46Z krasznaa $ +#ifndef XAODCORE_SHALLOWAUXINFO_H +#define XAODCORE_SHALLOWAUXINFO_H + +// Local include(s): +#include "xAODCore/ShallowAuxContainer.h" + +namespace xAOD { + + /// Shallow copy for the auxiliary store of standalone objects + /// + /// The design of this is exactly the same as for the + /// <code>SG::AuxStoreInternal</code> - <code>SG::AuxStoreStandalone</code> + /// pair. All the code is in <code>xAOD::ShallowAuxContainer</code>, this + /// class is just a convenience shorthand for calling + /// <code>xAOD::ShallowAuxContainer(true)</code> in the code. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 671678 $ + /// $Date: 2015-06-02 14:28:46 +0200 (Tue, 02 Jun 2015) $ + /// + class ShallowAuxInfo : public ShallowAuxContainer { + + public: + /// Default constructor + ShallowAuxInfo(); + /// Constructor with a parent object + ShallowAuxInfo( const DataLink< SG::IConstAuxStore >& parent ); + + /// Return the type of the store object + virtual AuxStoreType getStoreType() const { return AST_ObjectStore; } + + }; // class ShallowAuxInfo + +} // namespace xAOD + +// Declare a class ID for the class: +#include "xAODCore/CLASS_DEF.h" +CLASS_DEF( xAOD::ShallowAuxInfo, 196927374, 1 ) + +// Describe the inheritance of the class: +#include "xAODCore/BaseInfo.h" +SG_BASE( xAOD::ShallowAuxInfo, xAOD::ShallowAuxContainer ); + +#endif // XAODCORE_SHALLOWAUXINFO_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/ShallowCopy.h b/EDM/athena/xAOD/xAODCore/xAODCore/ShallowCopy.h new file mode 100644 index 00000000..d07cd03e --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/ShallowCopy.h @@ -0,0 +1,137 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ShallowCopy.h 766390 2016-08-04 11:18:59Z wlampl $ +#ifndef XAODCORE_SHALLOWCOPY_H +#define XAODCORE_SHALLOWCOPY_H + +// System include(s): +#include <map> +#include <iostream> + +//Core includes +#include "CxxUtils/make_unique.h" + +// EDM include(s): +#include "AthLinks/DataLink.h" +#include "AthContainersInterfaces/IConstAuxStore.h" + +// Local include(s): +#include "xAODCore/ShallowAuxContainer.h" +#include "xAODCore/ShallowAuxInfo.h" + +namespace xAOD { + + /// Function to prepare an object to be stored in a shallow-copy container + /// + /// To be used by shallowCopyContainer. The default implementation + /// here is dummy, just calling the default constructor. Can be + /// overloaded for types that require special treatment + /// (like xAOD::CaloCluster) + /// @param elem: Input object, ignored in this implementation + /// @returns A uniqe_ptr to the object to be push_back'ed into the + /// shallow-copy container. + + template< class T > + std::unique_ptr<T> prepareElementForShallowCopy(const T* /*elem*/) { + return CxxUtils::make_unique<T>(); + } + + + /// Function making a shallow copy of a constant container + /// + /// This function can be used to make a shallow copy of an existing + /// (constant) container. It is most useful when reading an input file, + /// and/or applying systematic variations on a container. + /// + /// @param cont The container to make a shallow copy of + /// @returns A pair of pointers to the created objects. The caller takes + /// ownership of the created objects + /// + template< class T > + std::pair< T*, ShallowAuxContainer* > shallowCopyContainer( const T& cont ) { + + // Create a DataLink, to check if we'll be successful: + DataLink< SG::IConstAuxStore > link( cont.getConstStore() ); + if( ! link.cptr() ) { + // This can happen when we read the input file in standalone + // mode in branch access mode. That's unfortunately not + // compatible with using a shallow copy auxiliary store. + std::cout << "xAOD::shallowCopyContainer ERROR Couldn't set up " + << "DataLink to the original container's auxiliary store" + << std::endl; + std::cout << "xAOD::shallowCopyContainer ERROR Are you using the " + << "xAOD::TEvent::kBranchAccess access mode?" + << std::endl; + std::pair< T*, ShallowAuxContainer* > dummy; + return dummy; + } + + // Create the new DV container: + T* newCont = new T(); + + // Add the required number of elements to it: + newCont->reserve( cont.size() ); + for( size_t i = 0; i < cont.size(); ++i ) { + newCont->push_back(prepareElementForShallowCopy(cont[i])); + } + + // Create a new shallow auxiliary container: + ShallowAuxContainer* aux = new ShallowAuxContainer( link ); + + // Connect it to the interface container: + newCont->setStore( aux ); + + // Return the new objects: + return std::make_pair( newCont, aux ); + } + + /// Function making a shallow copy of a constant standalone object + /// + /// This function can be used to make a shallow copy of an existing + /// (constant) object. It is most useful when reading an input file, + /// and/or applying systematic variations on a standalone object. Not + /// entirely clear yet how much use case there will be for it though... + /// + /// @param obj The object to make a shallow copy of + /// @returns A pair of pointers to the created objects. The caller takes + /// ownership of the created objects + /// + template< class T > + std::pair< T*, ShallowAuxInfo* > shallowCopyObject( const T& obj ) { + + // Create a DataLink, to check if we'll be successful: + DataLink< SG::IConstAuxStore > link( obj.getConstStore() ); + if( ! link.cptr() ) { + // This can happen when we read the input file in standalone + // mode in branch access mode. That's unfortunately not + // compatible with using a shallow copy auxiliary store. + std::cout << "xAOD::shallowCopyObject ERROR Couldn't set up " + << "DataLink to the original object's auxiliary store" + << std::endl; + std::cout << "xAOD::shallowCopyObject ERROR Are you using the " + << "xAOD::TEvent::kBranchAccess access mode?" + << std::endl; + std::pair< T*, ShallowAuxInfo* > dummy; + return dummy; + } + + // Create a new object using its default constructor: + T* newObj = new T(); + + // Create a new shallow auxiliary store: + ShallowAuxInfo* aux = new ShallowAuxInfo( link ); + + // Connect it to the interface object: + newObj->setStore( aux ); + + // Return the new objects: + return std::make_pair( newObj, aux ); + } + +} // namespace xAOD + +#endif // XAODCORE_SHALLOWCOPY_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/selection.xml b/EDM/athena/xAOD/xAODCore/xAODCore/selection.xml new file mode 100644 index 00000000..d391bc1f --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/selection.xml @@ -0,0 +1,102 @@ +<!-- $Id: selection.xml 750677 2016-05-30 10:24:50Z krasznaa $ --> +<lcgdict> + + <!-- Auxiliary container base: --> + <class name="xAOD::AuxContainerBase" + id="C87C71B3-B03F-42FC-AF99-DF497F148397" > + <field name="m_auxids" transient="true" /> + <field name="m_vecs" transient="true" /> + <field name="m_store" transient="true" /> + <field name="m_storeIO" transient="true" /> + <field name="m_ownsStore" transient="true" /> + <field name="m_selection" transient="true" /> + <field name="m_tick" transient="true" /> + <field name="m_mutex" transient="true" /> + <field name="m_tsAuxids" transient="true" /> + <field name="m_locked" transient="true" /> + <field name="m_name" transient="true" /> + </class> + <read sourceClass="xAOD::AuxContainerBase" version="[1-]" + targetClass="xAOD::AuxContainerBase" source="" target="" > + <![CDATA[ + newObj->clearDecorations(); + newObj->lock(); + ]]> + </read> + + <!-- Auxiliary info base: --> + <class name="xAOD::AuxInfoBase" + id="47FE21D1-5196-4961-A8A1-1DC1B4104DD8" > + <field name="m_auxids" transient="true" /> + <field name="m_vecs" transient="true" /> + <field name="m_store" transient="true" /> + <field name="m_storeIO" transient="true" /> + <field name="m_ownsStore" transient="true" /> + <field name="m_selection" transient="true" /> + <field name="m_tick" transient="true" /> + <field name="m_mutex" transient="true" /> + <field name="m_tsAuxids" transient="true" /> + <field name="m_locked" transient="true" /> + <field name="m_name" transient="true" /> + </class> + <read sourceClass="xAOD::AuxInfoBase" version="[1-]" + targetClass="xAOD::AuxInfoBase" source="" target="" > + <![CDATA[ + newObj->clearDecorations(); + newObj->lock(); + ]]> + </read> + + <!-- Shallow auxiliary container: --> + <class name="xAOD::ShallowAuxContainer" + id="C63C39D7-9501-49DC-B1B0-6AD98B1AEEFA" > + <field name="m_selection" transient="true" /> + <field name="m_store" transient="true" /> + <field name="m_storeIO" transient="true" /> + <field name="m_ownsStore" transient="true" /> + <field name="m_parentIO" transient="true" /> + <field name="m_shallowIO" transient="true" /> + <field name="m_tick" transient="true" /> + <field name="m_mutex" transient="true" /> + <field name="m_tsAuxids" transient="true" /> + <field name="m_name" transient="true" /> + </class> + <read sourceClass="xAOD::ShallowAuxContainer" version="[1-]" + targetClass="xAOD::ShallowAuxContainer" source="" target="" > + <![CDATA[ + newObj->clearDecorations(); + newObj->lock(); + ]]> + </read> + + <!-- Shallow auxiliary info: --> + <class name="xAOD::ShallowAuxInfo" + id="BE505E75-8760-4F39-9331-689CB5443DB1" /> + + <!-- The DataVector collection proxy classes: --> + <class name="xAOD::TDVCollectionProxy" /> + <class name="xAOD::TDVCollectionProxyDummy" /> + <class name="DataVector<xAOD::TDVCollectionProxyDummy>" /> + + <!-- Additional dictionaries used in multiple locations: --> + <class name="std::vector<ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<double> > >" /> + <class name="std::vector<unsigned char>" /> + <class name="std::vector<std::vector<unsigned char> >" /> + <class name="std::vector<signed char>" /> + <class name="std::vector<std::vector<signed char> >" /> + <class name="std::vector<char>" /> + <class name="std::vector<std::vector<char> >" /> + <class name="std::vector<uint32_t>" /> + <class name="std::vector<std::vector<uint32_t> >" /> + + <!-- Helper function printing the properties of xAOD objects: --> + <function proto_name="xAOD::dump(const SG::AuxElement&)" /> + + <!-- Suppress the unwanted classes found by ROOT 6. --> + <!-- Hopefully we can remove these extra lines at one point... --> + <exclusion> + <class name="SG::IConstAuxStore" /> + <class name="DataLink<SG::IConstAuxStore>" /> + </exclusion> + +</lcgdict> diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/selectionAthSuppress.xml b/EDM/athena/xAOD/xAODCore/xAODCore/selectionAthSuppress.xml new file mode 100644 index 00000000..f8c52394 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/selectionAthSuppress.xml @@ -0,0 +1,12 @@ + <exclusion> + <class name="std::vector<char>"/> + <class name="std::vector<signed char>"/> + <class name="std::vector<unsigned char>"/> + <class name="std::vector<unsigned int>"/> + <class name="std::vector<std::vector<char> >"/> + <class name="std::vector<std::vector<unsigned char> >"/> + <class name="std::vector<std::vector<int> >"/> + <class name="std::vector<std::vector<unsigned int> >"/> + <class name="std::vector<std::vector<float> >"/> + </exclusion> + diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/selectionAthena.xml b/EDM/athena/xAOD/xAODCore/xAODCore/selectionAthena.xml new file mode 100644 index 00000000..3fe9ebb4 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/selectionAthena.xml @@ -0,0 +1,24 @@ +<!-- $Id: selectionAthena.xml 572298 2013-11-25 15:22:26Z krasznaa $ --> +<lcgdict> + + <!-- These are dictionaries that we need until we can make proper use --> + <!-- of the ROOT CINT dictionaries while writing a POOL file. --> + + <class name="ROOT::Math::PtEtaPhiM4D<double>" > + <field name="fEta" iotype="Double32_t" /> + <field name="fM" iotype="Double32_t" /> + <field name="fPhi" iotype="Double32_t" /> + <field name="fPt" iotype="Double32_t" /> + </class> + <class name="ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<double> >" /> + + <exclusion> + <class name="ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<double> >" > + <method name="SetPz"/> + <method name="SetPy"/> + <method name="SetPx"/> + <method name="SetE"/> + </class> + </exclusion> + +</lcgdict> diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersInfo.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersInfo.h new file mode 100644 index 00000000..65618a97 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersInfo.h @@ -0,0 +1,87 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxPersInfo.h 793737 2017-01-24 20:11:10Z ssnyder $ +#ifndef XAODCORE_TOOLS_AUXPERSINFO_H +#define XAODCORE_TOOLS_AUXPERSINFO_H + +// System include(s): +#include <stdexcept> + +// EDM include(s): +#include "AthContainersInterfaces/IAuxTypeVector.h" + +namespace xAOD { + + /// Class managing concrete persistent variables + /// + /// This class is used internally by the "special" auxiliary store + /// objects to manage the auxiliary variables handled by them. User + /// code probably doesn't want to touch it directly... + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 793737 $ + /// $Date: 2017-01-24 21:11:10 +0100 (Tue, 24 Jan 2017) $ + /// + template< class T > + class AuxPersInfo : public SG::IAuxTypeVector { + + public: + /// Convenience type definition + typedef T& info_type; + + /// Constructor + AuxPersInfo( info_type info ) : m_info( info ) {} + + virtual SG::IAuxTypeVector* clone() const { + return new AuxPersInfo<T>(*this); + } + + virtual void* toPtr() { + return &m_info; + } + virtual void* toVector() { + return &m_info; + } + virtual size_t size() const { + return 1; + } + virtual bool resize( size_t sz ) { + if( sz != 1 ) { + throw std::runtime_error( "Calling resize with != 1 on a " + "non-vector" ); + } + return true; + } + virtual void reserve( size_t sz ) { + if( sz != 1 ) { + throw std::runtime_error( "Calling reserve with != 1 on a " + "non-vector" ); + } + } + virtual void shift( size_t /*pos*/, ptrdiff_t /*offs*/ ) { + throw std::runtime_error( "Calling shift on a non-vector" ); + } + + virtual bool insertMove (size_t /*pos*/, void* /*beg*/, void* /*end*/) + { + throw std::runtime_error( "Calling insertMove on a non-vector" ); + } + + virtual const std::type_info* objType() const { + return &typeid(T); + } + + private: + /// Reference to the info being handled + info_type m_info; + + }; // class AuxPersInfo + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_AUXPERSINFO_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersVector.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersVector.h new file mode 100644 index 00000000..cba85065 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/AuxPersVector.h @@ -0,0 +1,48 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: AuxPersVector.h 793737 2017-01-24 20:11:10Z ssnyder $ +#ifndef XAODCORE_AUXPERSVECTOR_H +#define XAODCORE_AUXPERSVECTOR_H + +// EDM include(s): +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/tools/AuxTypeVector.h" +#include "AthContainersInterfaces/IAuxSetOption.h" + +namespace xAOD { + + /// Class managing concrete vector variables + /// + /// This class is used internally by the "special" auxiliary store + /// objects to manage the auxiliary variables handled by them. User + /// code probably doesn't want to touch it directly... + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 793737 $ + /// $Date: 2017-01-24 21:11:10 +0100 (Tue, 24 Jan 2017) $ + /// + template< class T, class VEC=std::vector< T > > + class AuxPersVector : public SG::AuxTypeVectorHolder<T, VEC> { + + public: + /// Convenience type definition + typedef VEC& vector_type; + + /// Constructor + AuxPersVector( vector_type vec ) + : SG::AuxTypeVectorHolder<T, VEC> (&vec, false) {} + + virtual SG::IAuxTypeVector* clone() const { + return new AuxPersVector<T, VEC>(*this); + } + + }; // class AuxPersVector + +} // namespace xAOD + +#endif // XAODCORE_AUXPERSVECTOR_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/FloatCompressor.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/FloatCompressor.h new file mode 100644 index 00000000..e529ed28 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/FloatCompressor.h @@ -0,0 +1,65 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: FloatCompressor.h 789425 2016-12-13 10:50:12Z krasznaa $ +#ifndef XAODCORE_TOOLS_FLOATCOMPRESSOR_H +#define XAODCORE_TOOLS_FLOATCOMPRESSOR_H + +// System include(s): +extern "C" { +# include <stdint.h> +} + +namespace xAOD { + + /// Class implementing a lossy float compression + /// + /// This is just a copy of the code implemented first in CaloUtils. + /// Used to reduce the precision of select floating point quantities during + /// the POOL conversion. + /// + /// @author Scott Snyder <snyder@bnl.gov> + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 789425 $ + /// $Date: 2016-12-13 11:50:12 +0100 (Tue, 13 Dec 2016) $ + /// + class FloatCompressor { + + public: + /// Constructor with the number of mantissa bits to retain + FloatCompressor( unsigned int mantissaBits = 7 ); + + /// Function returning a reduced precision float value + float reduceFloatPrecision( float value ) const; + + /// Type used in the compression + union floatint_t { + float fvalue; + uint32_t ivalue; + }; + + private: + /// Number of mantissa bits to keep + unsigned int m_mantissaBits; + /// Bitmask for zeroing out the non-interesting bits + uint32_t m_mantissaBitmask; + + /// @name Magic numbers + /// @{ + + // Half of the LSB-value after cutting the lower 16 bits + const uint32_t m_rounding=0x00008000; + /// Largest possible positive 32bit float minus the rounding + const uint32_t m_vmax=0x7f7f7fff; + + /// @} + + }; // class FloatCompressor + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_FLOATCOMPRESSOR_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/IOStats.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/IOStats.h new file mode 100644 index 00000000..f49de3a5 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/IOStats.h @@ -0,0 +1,52 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: IOStats.h 621105 2014-10-10 12:34:11Z krasznaa $ +#ifndef XAODCORE_TOOLS_IOSTATS_H +#define XAODCORE_TOOLS_IOSTATS_H + +namespace xAOD { + + // Forward declaration(s): + class ReadStats; + + /// Singleton object holding on to the process's I/O statistics + /// + /// This singleton class holds the xAOD file access statistics object + /// describing the auxiliary variable access pattern of the current + /// process. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 621105 $ + /// $Date: 2014-10-10 14:34:11 +0200 (Fri, 10 Oct 2014) $ + /// + class IOStats { + + public: + /// Destructor + ~IOStats(); + + /// Singleton object accessor + static IOStats& instance(); + + /// Access the object describing the file access pattern + ReadStats& stats(); + /// Access the object describing the file access pattern (const version) + const ReadStats& stats() const; + + private: + /// The constructor of the object is made private + IOStats(); + + /// The object describing the file access pattern + ReadStats* m_stats; + + }; // class IOStats + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_IOSTATS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/PerfStats.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/PerfStats.h new file mode 100644 index 00000000..7bb05aff --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/PerfStats.h @@ -0,0 +1,125 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PerfStats.h 634033 2014-12-05 14:46:38Z krasznaa $ +#ifndef XAODCORE_TOOLS_PERFSTATS_H +#define XAODCORE_TOOLS_PERFSTATS_H + +// ROOT include(s): +#include <TVirtualPerfStats.h> + +// Forward declaration(s): +class TTree; + +namespace xAOD { + + /// Class for collecting information about the xAOD file access pattern + /// + /// This class is used for collecting the basic information about the file + /// access during an xAOD analysis. It was first developed for the + /// D3PDReader code, and was later adopted to be used with xAOD files. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 634033 $ + /// $Date: 2014-12-05 15:46:38 +0100 (Fri, 05 Dec 2014) $ + /// + class PerfStats : public ::TVirtualPerfStats { + + public: + /// Destructor, sometimes called by PROOF + ~PerfStats(); + + /// Function accessing the singleton instance + static PerfStats& instance(); + + /// Start the statistics collection + void start( bool clear = true ); + /// Stop the statistics collection + void stop(); + + /// @name Functions inherited from TVirtualPerfStats: + /// @{ + + /// Generic function called when a specified event happens + virtual void SimpleEvent( EEventType type ); + /// PROOF specific function, not implemented here + virtual void PacketEvent( const char *slave, const char *slavename, + const char *filename, + ::Long64_t eventsprocessed, + ::Double_t latency, ::Double_t proctime, + ::Double_t cputime, ::Long64_t bytesRead ); + /// PROOF specific function, not implemented here + virtual void FileEvent( const char *slave, const char *slavename, + const char *nodename, const char *filename, + ::Bool_t isStart ); + /// Function called by PROOF when a file is opened + virtual void FileOpenEvent( ::TFile *file, const char *filename, + ::Double_t start ); + /// Function called in general when a file reading operation happens + virtual void FileReadEvent( ::TFile *file, ::Int_t len, + ::Double_t start ); + +#ifndef __CINT__ +#if ROOT_VERSION_CODE < ROOT_VERSION( 5, 34, 19 ) + /// Function called in general when a file unzipping operation happens + virtual void FileUnzipEvent( ::TFile *file, ::Long64_t pos, + ::Double_t start, ::Int_t complen, + ::Int_t objlen ); +#else + /// Function called in general when a file unzipping operation happens + virtual void UnzipEvent( ::TObject *tree, ::Long64_t pos, + ::Double_t start, ::Int_t complen, + ::Int_t objlen ); +#endif // ROOT_VERSION +#endif // not __CINT__ + + /// PROOF specific function, not implemented here + virtual void RateEvent( ::Double_t proctime, ::Double_t deltatime, + ::Long64_t eventsprocessed, + ::Long64_t bytesRead ); + /// Function used by PROOF to set the read bytes correctly on the master + virtual void SetBytesRead( ::Long64_t num ); + /// Function used by PROOF to set the read bytes correctly on the master + virtual ::Long64_t GetBytesRead() const; + /// Function used by PROOF to set the number of processed events correctly + virtual void SetNumEvents( ::Long64_t num ); + /// Function used by PROOF to set the number of processed events correctly + virtual ::Long64_t GetNumEvents() const; + + /// @} + + protected: + /// The constructor is protected, as it's a singleton + PerfStats(); + + private: + /// The single instance of the object + static PerfStats* m_instance; + + /// Another performance monitoring object + ::TVirtualPerfStats* m_otherPerfStats; + + /// Flag showing whether the statistic collection is ongoing or not + bool m_running; + /// Time when the statistics collection was started + ::Double_t m_startTime; + + /// The tree we're currently investigating + ::TTree* m_tree; + /// The currently open xAOD file + ::TFile* m_file; + + /// Flag showing whether some information message has already been printed + bool m_treeWarningPrinted; + + ClassDef( xAOD::PerfStats, 0 ) + + }; // class PerfStats + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_PERFSTATS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/PrintHelpers.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/PrintHelpers.h new file mode 100644 index 00000000..cf28bc7e --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/PrintHelpers.h @@ -0,0 +1,47 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: PrintHelpers.h 646509 2015-02-12 16:43:18Z krasznaa $ +#ifndef XAODCORE_TOOLS_PRINTHELPERS_H +#define XAODCORE_TOOLS_PRINTHELPERS_H + +// System include(s): +#include <iosfwd> + +// Forward declaration(s): +namespace SG { + class AuxElement; +} + +/// Operator printing the payload of an xAOD object +/// +/// This function can be used to quickly get an idea about the payload held +/// by any type of xAOD object. It prints the type and name of each auxiliary +/// variable associated with the object. And for some simple types (primitives +/// and some vectors of primitives) it even prints the values of these +/// variables. +/// +/// @param out The stream to write the information to +/// @param obj The object to write the information about +/// @returns The same stream object that was given to the function +/// +std::ostream& operator<< ( std::ostream& out, const SG::AuxElement& obj ); + +namespace xAOD { + + /// Helper function for dumping xAOD objects on the screen in PyROOT + /// + /// Regular C++ code should just use the operator declared in this header. + /// But in interactive ROOT and PyROOT this simple function, which always + /// prints the information to std::cout, should come in handy. + /// + /// @param obj The object to dump information about to std::cout + /// + void dump( const SG::AuxElement& obj ); + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_PRINTHELPERS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/ReadStats.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/ReadStats.h new file mode 100644 index 00000000..8cd27e5f --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/ReadStats.h @@ -0,0 +1,341 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ReadStats.h 642099 2015-01-27 16:43:18Z krasznaa $ +#ifndef XAODCORE_TOOLS_READSTATS_H +#define XAODCORE_TOOLS_READSTATS_H + +// System include(s): +#include <map> +#include <vector> +#include <string> + +// ROOT include(s): +#include <TNamed.h> + +// EDM include(s): +#ifndef __MAKECINT__ +#ifndef __ROOTCLING__ +# include "AthContainersInterfaces/AuxTypes.h" +#endif // not __ROOTCLING__ +#endif // not __MAKECINT__ + +// Forward declaration(s): +class TCollection; +class TTree; +class TH1; + +namespace xAOD { + + /// Class describing the access statistics of one (sub-)branch + /// + /// Objects of this class are used to describe a single xAOD branch's + /// access pattern. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 642099 $ + /// $Date: 2015-01-27 17:43:18 +0100 (Tue, 27 Jan 2015) $ + /// + class BranchStats : public ::TNamed { + + public: + /// Constructor specifying all parameters + BranchStats( const char* name = "xAODBranch", + const char* type = "Int_t", + ::Int_t nTreesAccessed = 0, ::Long64_t nReadEntries = 0, + ::Long64_t nUnzippedBytes = 0, ::Long64_t nZippedBytes = 0 ); + /// Copy constructor + BranchStats( const BranchStats& parent ); + + /// Assignment operator + BranchStats& operator= ( const BranchStats& parent ); + + /// @name Accessor/setter functions for the kept information + /// @{ + + /// Get how many trees/files were accessed to read this branch + ::Int_t treesAccessed() const; + /// Set how many trees were accessed to read this branch + void setTreesAccessed( ::Int_t nTreesAccessed ); + + /// Get how many entries were read from this branch + ::Long64_t readEntries() const; + /// Set how many entries were read from this branch + void setReadEntries( ::Long64_t nReadEntries ); + + /// Get how many unzipped bytes were read from this branch in total + ::Long64_t unzippedBytesRead() const; + /// Set how many unzipped bytes were read from this branch in total + void setUnzippedBytesRead( ::Long64_t nUnzippedBytes ); + + /// Get how many zipped bytes were read from this branch in total + ::Long64_t zippedBytesRead() const; + /// Set how many zipped bytes were read from this branch in total + void setZippedBytesRead( ::Long64_t nZippedBytes ); + + /// @} + + /// Function merging two objects + BranchStats& add( const BranchStats& rh ); + /// Operator merging two objects + BranchStats& operator+= ( const BranchStats& rh ); + + /// @name "ROOT-specific" functions + /// @{ + + /// Function merging the information from multiple objects + ::Int_t Merge( ::TCollection* coll ); + + /// Print information about the collected statistics + void Print( ::Option_t* option = "" ) const; + + /// @} + + private: + /// Number of trees/files accessed for this branch + ::Int_t m_treesAccessed; + /// Number of entries read from this branch + ::Long64_t m_readEntries; + /// Number of unzipped bytes read from this branch + ::Long64_t m_unzippedBytes; + /// Number of zipped bytes read from this branch + ::Long64_t m_zippedBytes; + + ClassDef( xAOD::BranchStats, 1 ) + + }; // class BranchStats + + /// Class describing the access statistics of a collection of branches + /// + /// Objects of this class are used to describe the access pattern of an xAOD + /// analysis. The object can also be used to optimize the caching for the + /// analysis in subsequent runs. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 642099 $ + /// $Date: 2015-01-27 17:43:18 +0100 (Tue, 27 Jan 2015) $ + /// + class ReadStats : public ::TNamed { + + public: + /// Type of the internal vectors describing one auxiliary store + typedef std::vector< BranchStats* > Vector_t; + /// Type of the internal object gathering information on aux branches + typedef std::map< std::string, Vector_t > Map_t; + + /// Type of the internal object gathering information on containers + typedef std::map< std::string, BranchStats > MapC_t; + + /// Constructor just specifying the name of the object + ReadStats( const char* name = "xAODReadStats", + const char* title = "xAOD reading statistics" ); + /// Copy constructor + ReadStats( const ReadStats& parent ); + /// Destructor + ~ReadStats(); + + /// Assignment operator + ReadStats& operator= ( const ReadStats& parent ); + + /// Clear the statistics information (inherited from TNamed...) + void Clear( ::Option_t* opt = "" ); + + /// @name Raw information accessor/setter functions + /// @{ + + /// Set how many bytes were read in total during the analysis + void setBytesRead( ::Long64_t num ); + /// Get how many bytes were read in total during the analysis + ::Long64_t bytesRead() const; + + /// Set the total number of branches on the input + void setBranchNum( ::Int_t num ); + /// Get the total number of branches on the input + ::Int_t branchNum() const; + + /// Set the total number of file read calls + void setFileReads( ::Int_t num ); + /// Get the total number of file read calls + ::Int_t fileReads() const; + + /// Set the TTreeCache size used + void setCacheSize( ::Int_t size ); + /// Get the TTreeCache size used + ::Int_t cacheSize() const; + + /// Set the time spent in reading the data + void setReadTime( ::Double_t time ); + /// Get the time spent in reading the data + ::Double_t readTime() const; + + /// Set the time spent in unzipping the data + void setUnzipTime( ::Double_t time ); + /// Get the time spent in unzipping the data + ::Double_t unzipTime() const; + + /// Set the time spent in processing events + void setProcessTime( ::Double_t time ); + /// Get the time spent in processing events + ::Double_t processTime() const; + + /// @} + + /// @name Functions used for filling the object + /// @{ + +#ifndef __MAKECINT__ +#ifndef __ROOTCLING__ + /// Access the description of a branch. Creating it if necessary. + BranchStats* branch( const std::string& prefix, + SG::auxid_t auxid ); + /// Get information about a specific variable + const BranchStats* branch( const std::string& prefix, + SG::auxid_t auxid ) const; +#endif // not __ROOTCLING__ +#endif // not __MAKECINT__ + + /// Access the description of a container. Creating it if necessary. + BranchStats* container( const std::string& name ); + /// Access the description of a container. + const BranchStats* container( const std::string& name ) const; + + /// Get all variable information + const Map_t& branches() const; + /// Get information about all the containers + const MapC_t& containers() const; + + /// @} + + /// @name Function used for merging objects of this type + /// @{ + + /// Function checking if two objects are "compatible" + bool isCompatible( const ReadStats& rh ) const; + /// Function merging two objects + ReadStats& add( const ReadStats& rh ); + /// Operator merging two objects + ReadStats& operator+= ( const ReadStats& rh ); + + /// Function merging the information from multiple objects + ::Int_t Merge( ::TCollection* coll ); + + /// @} + + /// @name Function for setting up a TTreeCache object + /// @{ + + /// Add all branches that were ever accessed, to the TTreeCache + void addToTreeCache( ::TTree* tree ) const; + /// Add the branches accessed more than n times to the TTreeCache + void addToTreeCacheByEntries( ::TTree* tree, + ::Long64_t minEntries ) const; + /// Add the branches accessed more than a given fraction of times to the + /// TTreeCache + void addToTreeCacheByEntryFrac( ::TTree* tree, + ::Double_t minEvFraction ) const; + /// Add the branches from which more than x bytes were read, to the + /// TTreeCache + void addToTreeCacheByBytes( ::TTree* tree, ::Long64_t minBytes ) const; + /// Add the branches from whith more than a given fraction of the bytes + /// were read, to the TTreeCache + void addToTreeCacheByByteFrac( ::TTree* tree, + ::Double_t minByteFraction ) const; + + /// @} + + /// @name Functions accessing branch names according to certain rules + /// @{ + + /// Get the branches accessed more than n times + std::vector< std::string > + branchesByEntries( ::Long64_t minEntries ) const; + /// Get the branches accessed more than a given fraction of times + std::vector< std::string > + branchesByEntryFrac( ::Double_t minEvFraction ) const; + /// Get the branches from which more than x bytes were read + std::vector< std::string > + branchesByBytes( ::Long64_t minBytes ) const; + /// Get the branches from which more than a given fraction of bytes were + /// read + std::vector< std::string > + branchesByByteFrac( ::Double_t minByteFraction ) const; + + /// @} + + /// @name Functions getting the statistics as histograms + /// @{ + + /// Get a histogram with the TTree access statistics + ::TH1* treeAccessStat() const; + /// Get a histogram with the entry reading statistics + ::TH1* entryReadStat() const; + /// Get a histogram with the zipped byte reading statistics + ::TH1* zippedByteReadStat() const; + /// Get a histogram with the unzipped byte reading statistics + ::TH1* unzippedByteReadStat() const; + + /// @} + + /// Print information about the collected statistics + void Print( ::Option_t* option = "" ) const; + + /// Print the accessed variables, formatted for smart slimming + void printSmartSlimmingBranchList( bool autoIncludeLinks = false ) const; + + /// Function incrementing the processed event counter + void nextEvent(); + + /// Function getting the total number of input event + ::Long64_t nEvents() const; + /// Function setting the total number of input events + void setNEvents( ::Long64_t nevents ); + +#ifndef __MAKECINT__ +#ifndef __ROOTCLING__ + /// Function incrementing the read counter on a specific branch + void readBranch( const std::string& prefix, + SG::auxid_t auxid ); +#endif // not __ROOTCLING__ +#endif // not __MAKECINT__ + + /// Function incrementing the read counter on a specific container + void readContainer( const std::string& name ); + + private: + /// Full Statistics about the branches + Map_t m_branches; + /// Statistics about the containers + MapC_t m_containers; + + /// Total number of bytes read + ::Long64_t m_bytesRead; + /// Total number of branches in the input xAOD TTree + ::Int_t m_branchNum; + /// Total number of file reading operations during the analysis + ::Int_t m_fileReads; + /// Cache size used in the analysis + ::Int_t m_cacheSize; + /// Time spent reading the events + ::Double_t m_readTime; + /// Time spent unzipping the events + ::Double_t m_unzipTime; + /// Time spent in processing the events + ::Double_t m_processTime; + + /// Total num events + ::Long64_t m_nEvents; + /// Total processed events + ::Long64_t m_nEventsProcessed; + + ClassDef( xAOD::ReadStats, 1 ) + + }; // class ReadStats + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_READSTATS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/SafeDeepCopy.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/SafeDeepCopy.h new file mode 100644 index 00000000..3cee4928 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/SafeDeepCopy.h @@ -0,0 +1,42 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: SafeDeepCopy.h 676241 2015-06-18 06:15:44Z krasznaa $ +#ifndef XAODCORE_TOOLS_SAFEDEEPCOPY_H +#define XAODCORE_TOOLS_SAFEDEEPCOPY_H + +// Forward declaration(s): +namespace SG { + class AuxElement; +} + +namespace xAOD { + + /// Function that can deep-copy "problematic" objects + /// + /// Due to a number of different issues we can produce xAOD files that have + /// some variables only filled in certain events. When this happens, the xAOD + /// object still reports the variable to be present in all the events, though + /// the auxiliary store's getAuxIDs() function. Only when one asks for the + /// auxiliary ID, does the code detect that there's no such variable in the + /// event after all. + /// + /// When this happens, the assignment operator in <code>SG::AuxElement</code> + /// throws an exception. + /// + /// In order to be able to make deep copies of objects even from such + /// problematic files, this function can be used instead. This function + /// silently ignores these sort of issues, allowing analysis code to make + /// use of buggy files. + /// + /// @param orig The original object that a copy is being made of + /// @param copy The object to fill with the original's parameters + /// + void safeDeepCopy( const SG::AuxElement& orig, SG::AuxElement& copy ); + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_SAFEDEEPCOPY_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/TDVCollectionProxy.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/TDVCollectionProxy.h new file mode 100644 index 00000000..5883c534 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/TDVCollectionProxy.h @@ -0,0 +1,101 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: TDVCollectionProxy.h 687822 2015-08-06 07:58:06Z krasznaa $ +#ifndef XAODCORE_TDVCOLLECTIONPROXY_H +#define XAODCORE_TDVCOLLECTIONPROXY_H + +// System include(s): +#include <cstddef> + +// ROOT include(s): +#include <TGenCollectionProxy.h> + +// Forward declaration(s): +class TClass; + +namespace xAOD { + + /// @brief Dummy class to use as the @c DataVector template argument + /// for the class we give to the Root proxy. + class TDVCollectionProxyDummy {}; + + /// A Root collection proxy for @c DataVector containers. + /// + /// In order for a container type to be treated properly by @c TTree::Draw + /// and friends, Root must recognize that it is in fact a container type, + /// and generate an appropriate proxy for it. This doesn't happen + /// automatically, though. This class serves as an appropriate proxy + /// for @c DataVector classes. Like the Root proxy classes, it's based + /// on making a hard cast to a dummy @c DataVector type. But because + /// @c DataVector's can inherit, we need to be careful about pointer + /// conversions, something the Root proxy classes could ignore. + /// We extend the Root environment buffer to cache information + /// about the pointer offsets. + /// + /// @author Scott Snyder <Scott.Snyder@cern.ch> + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + /// $Revision: 687822 $ + /// $Date: 2015-08-06 09:58:06 +0200 (Thu, 06 Aug 2015) $ + /// + class TDVCollectionProxy + : public TGenCollectionProxy { + + public: + /// Make the definition of Sizing_t public + typedef TGenCollectionProxy::Sizing_t Sizing_t; + + /// Constructor. + /// @param conttype The name of the container type we're proxying. + /// Note that this may be different from + /// a @c DataVector of @a elttype for classes which + /// derive from @c DataVector. + TDVCollectionProxy( const char* conttype ); + /// Copy constructor. + /// @param rhs The proxy to copy. + TDVCollectionProxy( const TDVCollectionProxy& rhs ); + + /// Start working with a new collection. + /// @param objstart The address of the collection. + virtual void PushProxy( void* objstart ); + + /// Clone this object. + virtual TVirtualCollectionProxy* Generate() const; + + /// Set the resize(...) function used by the proxy + void SetResize( Sizing_t func ); + + private: + /// Function initialising the proxy just in time + virtual TGenCollectionProxy* InitializeEx( Bool_t silent ); + /// Initialize the cached pointer offsets. + void FindOffsets( const char* elttype, + const char* conttype ); + + /// Name of the container that this class proxies + TString fName; + /// Flag for knowing whether the class was initialised already + Bool_t fInitialized; + + /// The offset of the underlying @c DataVector in the declared type. + ptrdiff_t fContoff; + /// Offset between the DV base pointer and the full DV pointer + ptrdiff_t fOffset; + + /// The element type to which the DV representation points. + TClass* fEltBase; + /// The declared element type of the DV. + TClass* fEltType; + + // Disallow copying. + TDVCollectionProxy& operator=( const TDVCollectionProxy& ); + + }; // class TDVCollectionProxy + +} // namespace xAOD + +#endif // XAODCORE_TDVCOLLECTIONPROXY_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/tools/Utils.h b/EDM/athena/xAOD/xAODCore/xAODCore/tools/Utils.h new file mode 100644 index 00000000..a2d0be88 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/tools/Utils.h @@ -0,0 +1,34 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Utils.h 573032 2013-11-29 13:33:57Z krasznaa $ +#ifndef XAODCORE_TOOLS_UTILS_H +#define XAODCORE_TOOLS_UTILS_H + +// System include(s): +#include <string> + +// ROOT include(s): +#include <Rtypes.h> + +namespace xAOD { + + namespace Utils { + + /// Function creating a human-readable elapsed time printout + std::string timeToString( ::Double_t secs ); + + /// Function for printing data sizes in human-readable format + std::string sizeToString( ::Long64_t bytes ); + + /// Function for printing data processing speeds in a human-readable format + std::string speedToString( ::Double_t bytespersec ); + + } // namespace Utils + +} // namespace xAOD + +#endif // XAODCORE_TOOLS_UTILS_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreAthenaDict.h b/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreAthenaDict.h new file mode 100644 index 00000000..4da729df --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreAthenaDict.h @@ -0,0 +1,25 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: xAODCoreAthenaDict.h 591472 2014-04-05 11:23:29Z krasznaa $ +#ifndef XAODCORE_XAODCOREATHENADICT_H +#define XAODCORE_XAODCOREATHENADICT_H + +// These are classes for which we need Reflex dictionaries just in Athena. + +// ROOT include(s): +#include <Rtypes.h> +#include <Math/Vector4D.h> + +#ifdef __GCCXML__ +namespace { + struct GCCXML_DUMMY_INSTANTIATION_XAODCORE2 { + ROOT::Math::PtEtaPhiM4D< Double_t > dummy1; + ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< Double_t > > dummy2; + }; +} +#endif // __GCCXML__ +#endif // XAODCORE_XAODCOREATHENADICT_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreDict.h b/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreDict.h new file mode 100644 index 00000000..5a238f65 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreDict.h @@ -0,0 +1,18 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: xAODCoreDict.h 579782 2014-01-23 15:40:31Z krasznaa $ +#ifndef XAODCORE_XAODCOREDICT_H +#define XAODCORE_XAODCOREDICT_H + +// This header is here for technical reasons. It is needed for a +// successful RootCore compilation. (But it would mess up if used +// in a CMT compilation.) + +// Local include(s): +#include "xAODCore/xAODCoreRflxDict.h" + +#endif // XAODCORE_XAODCOREDICT_H diff --git a/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreRflxDict.h b/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreRflxDict.h new file mode 100644 index 00000000..4fa44cc1 --- /dev/null +++ b/EDM/athena/xAOD/xAODCore/xAODCore/xAODCoreRflxDict.h @@ -0,0 +1,51 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: xAODCoreRflxDict.h 750677 2016-05-30 10:24:50Z krasznaa $ +#ifndef XAODCORE_XAODCORERFLXDICT_H +#define XAODCORE_XAODCORERFLXDICT_H + +// System include(s): +#include <vector> +extern "C" { +# include <stdint.h> +} + +// ROOT include(s): +#include <Rtypes.h> +#include <Math/Vector4D.h> + +// EDM include(s): +#include "AthContainers/DataVector.h" + +// Local include(s): +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/AuxInfoBase.h" +#include "xAODCore/ShallowAuxContainer.h" +#include "xAODCore/ShallowAuxInfo.h" +#include "xAODCore/tools/TDVCollectionProxy.h" +#include "xAODCore/tools/PrintHelpers.h" + +namespace { + struct GCCXML_DUMMY_INSTANTIATION_XAODCORE1 { + DataVector< xAOD::TDVCollectionProxyDummy > dummy1; + // Instantiations necessary for the std::vector<ROOT::Math::LorentzVector> + // dictionary: + ROOT::Math::PtEtaPhiM4D< Double_t > root1; + ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< Double_t > > root2; + std::vector< ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< Double_t > > > root3; + // Additional ROOT-only dictionaries: + std::vector< unsigned char > root4; + std::vector< std::vector< unsigned char > > root5; + std::vector<signed char> root6; + std::vector< std::vector<signed char> > root7; + std::vector< std::vector<char> > root8; + std::vector< uint32_t > root9; + std::vector< std::vector< uint32_t > > root10; + }; +} // private namespace + +#endif // XAODCORE_XAODCORERFLXDICT_H diff --git a/EDM/athena/xAOD/xAODTracking/CMakeLists.txt b/EDM/athena/xAOD/xAODTracking/CMakeLists.txt new file mode 100755 index 00000000..8ab80d67 --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/CMakeLists.txt @@ -0,0 +1,38 @@ +# $Id: CMakeLists.txt 782296 2016-11-04 09:12:22Z krasznaa $ +################################################################################ +# Package: xAODTracking +################################################################################ + +# Declare the package name: +atlas_subdir( xAODTracking ) + + +# Declare the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/AthContainers + Control/AthLinks + Event/xAOD/xAODCore + ${extra_deps} ) + +# External dependencies: +find_package( Eigen ) +find_package( ROOT COMPONENTS Core GenVector ) + +# Component(s) in the package: +atlas_add_library( xAODTracking + xAODTracking/*.h Root/*.cxx + PUBLIC_HEADERS xAODTracking + INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS} + LINK_LIBRARIES ${EIGEN_LIBRARIES} ${ROOT_LIBRARIES} AthContainers AthLinks xAODCore ${extra_libs} ) + +atlas_add_dictionary( xAODTrackingDict + xAODTracking/xAODTrackingDict.h + xAODTracking/selection.xml + LINK_LIBRARIES xAODTracking + EXTRA_FILES Root/dict/*.cxx ) + +# Test(s) in the package: +atlas_add_test( xAODTracking_StripCluster_test + SOURCES test/xAODTracking_StripCluster_test.cxx + LINK_LIBRARIES xAODTracking ) diff --git a/EDM/athena/xAOD/xAODTracking/Root/StripCluster.cxx b/EDM/athena/xAOD/xAODTracking/Root/StripCluster.cxx new file mode 100644 index 00000000..70f5e1eb --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/Root/StripCluster.cxx @@ -0,0 +1,58 @@ +/* + FASER Collaboration +*/ + +// EDM include(s): +#include "xAODCore/AuxStoreAccessorMacros.h" + +// Local include(s): +#include "xAODTracking/StripCluster.h" + +namespace xAOD { + + StripCluster::StripCluster() + : SG::AuxElement() { + } + + AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( StripCluster, uint64_t, id, setId) + AUXSTORE_OBJECT_SETTER_AND_GETTER( StripCluster, std::vector< uint64_t >, + rdoIdentifierList, + setRdoIdentifierList ) + + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, localX ) + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, localY ) + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, localXError ) + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, localYError ) + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, localXYCorrelation ) + + void StripCluster::setLocalPosition(float localX, float localY) { + static const Accessor< float > acc1( "localX" ); + acc1( *this ) = localX; + static const Accessor< float > acc2( "localY" ); + acc2( *this ) = localY; + } + + void StripCluster::setLocalPositionError(float localXError, float localYError, float localXYCorrelation) { + static const Accessor< float > acc1( "localXError" ); + acc1( *this ) = localXError; + static const Accessor< float > acc2( "localYError" ); + acc2( *this ) = localYError; + static const Accessor< float > acc3( "localXYCorrelation" ); + acc3( *this ) = localXYCorrelation; + } + + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, globalX ) + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, globalY ) + AUXSTORE_PRIMITIVE_GETTER( StripCluster, float, globalZ ) + + void StripCluster::setGlobalPosition(float globalX, float globalY, float globalZ) { + static const Accessor< float > acc1( "globalX" ); + acc1( *this ) = globalX; + static const Accessor< float > acc2( "globalY" ); + acc2( *this ) = globalY; + static const Accessor< float > acc3( "globalZ" ); + acc3( *this ) = globalZ; + } + + +} // namespace xAOD \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/Root/StripClusterAuxContainer.cxx b/EDM/athena/xAOD/xAODTracking/Root/StripClusterAuxContainer.cxx new file mode 100644 index 00000000..cebb6190 --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/Root/StripClusterAuxContainer.cxx @@ -0,0 +1,58 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Local include(s): +#include "xAODTracking/StripClusterAuxContainer.h" + +namespace xAOD { + + StripClusterAuxContainer::StripClusterAuxContainer() + : AuxContainerBase() { + AUX_VARIABLE( id ); + AUX_VARIABLE( rdoIdentifierList ); + + AUX_VARIABLE( localX ); + AUX_VARIABLE( localY ); + AUX_VARIABLE( localXError ); + AUX_VARIABLE( localYError ); + AUX_VARIABLE( localXYCorrelation ); + + AUX_VARIABLE( globalX ); + AUX_VARIABLE( globalY ); + AUX_VARIABLE( globalZ ); + } + + void StripClusterAuxContainer::dump() const { + std::cout<<" Dumping StripClusterAuxContainer"<<std::endl; + std::cout<<"id:"; + std::copy(id.begin(), id.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"localX:"; + std::copy(localX.begin(), localX.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"localY:"; + std::copy(localY.begin(), localY.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"localXError:"; + std::copy(localXError.begin(), localXError.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"localYError:"; + std::copy(localYError.begin(), localYError.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"localXYCorrelation:"; + std::copy(localXYCorrelation.begin(), localXYCorrelation.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"globalX:"; + std::copy(globalX.begin(), globalX.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"globalY:"; + std::copy(globalY.begin(), globalY.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<"globalZ:"; + std::copy(globalZ.begin(), globalZ.end(), + std::ostream_iterator<float>(std::cout, ", ")); + std::cout<<std::endl; + } + +} // namespace xAOD \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/Root/dict/ContainerProxies.cxx b/EDM/athena/xAOD/xAODTracking/Root/dict/ContainerProxies.cxx new file mode 100644 index 00000000..5e9ce433 --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/Root/dict/ContainerProxies.cxx @@ -0,0 +1,10 @@ +// EDM include(s): +#include "xAODCore/AddDVProxy.h" + +// Local include(s): +#include "xAODTracking/StripClusterContainer.h" +//#include "xAODTracking/versions/SCTRawHitValidationContainer_v1.h" + +// Set up the collection proxies: +ADD_NS_DV_PROXY( xAOD, StripClusterContainer ); +//ADD_NS_DV_PROXY( xAOD, SCTRawHitValidationContainer_v1 ); \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/cmt/Makefile.RootCore b/EDM/athena/xAOD/xAODTracking/cmt/Makefile.RootCore new file mode 100644 index 00000000..4099dbae --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/cmt/Makefile.RootCore @@ -0,0 +1,27 @@ +# Dear emacs, this is a -*- Makefile -*- +# $Id: Makefile.RootCore 582079 2014-02-07 10:34:06Z krasznaa $ +# +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = xAODTracking +PACKAGE_PRELOAD = +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = AthContainers AthLinks EventPrimitives GeoPrimitives xAODBase xAODCore +PACKAGE_TRYDEP = +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 0 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 0 +PACKAGE_REFLEX = 1 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/EDM/athena/xAOD/xAODTracking/cmt/requirements b/EDM/athena/xAOD/xAODTracking/cmt/requirements new file mode 100644 index 00000000..65e572fd --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/cmt/requirements @@ -0,0 +1,50 @@ +package xAODTracking +# $Id: requirements 744435 2016-05-03 12:16:04Z krasznaa $ + +author Edward.Moyse@cern.ch +author Markus.Elsing@cern.ch + +public +use AtlasPolicy AtlasPolicy-* +use AthContainers AthContainers-* Control +use AthLinks AthLinks-* Control +use AtlasROOT AtlasROOT-* External +use EventPrimitives EventPrimitives-* Event +use GeoPrimitives GeoPrimitives-* DetectorDescription +#use TrkNeutralParameters TrkNeutralParameters-* Tracking/TrkEvent +#use TrkParameters TrkParameters-* Tracking/TrkEvent +#use TrkTrack TrkTrack-* Tracking/TrkEvent +#use VxVertex VxVertex-* Tracking/TrkEvent +use_ifndef pplist="XAOD_MANACORE" pkg="Tracking/TrkEvent/TrkNeutralParameters" +use_ifndef pplist="XAOD_MANACORE" pkg="Tracking/TrkEvent/TrkParameters" +use_ifndef pplist="XAOD_MANACORE" pkg="Tracking/TrkEvent/TrkTrack" +use_ifndef pplist="XAOD_MANACORE" pkg="Tracking/TrkEvent/VxVertex" +use xAODBase xAODBase-* Event/xAOD +use xAODCore xAODCore-* Event/xAOD + +# Specify the required ROOT components for cmake (transparent to CMT) +apply_pattern cmake_add_command command="find_package(ROOT COMPONENTS Physics)" + +library xAODTracking ../Root/*.cxx +apply_pattern installed_library + +private + +use AtlasReflex AtlasReflex-* External + +apply_pattern lcgdict dict=xAODTracking selectionfile=selection.xml \ + headerfiles="../xAODTracking/xAODTrackingDict.h" \ + extralibfiles=../Root/dict/*.cxx + +private + +use TestTools TestTools-* AtlasTest + +apply_pattern UnitTest_run unit_test="xAODTracking_TrackParticle" +apply_pattern UnitTest_run unit_test="xAODTracking_TrackParticlexAODHelpers" extrapatterns="^DEBUG" + +private +# macro cppdebugflags '$(cppdebugflags_s)' +# macro_remove componentshr_linkopts "-Wl,-s" + +apply_pattern do_genCLIDDB library=xAODTracking diff --git a/EDM/athena/xAOD/xAODTracking/doc/mainpage.h b/EDM/athena/xAOD/xAODTracking/doc/mainpage.h new file mode 100644 index 00000000..cf105644 --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/doc/mainpage.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + @mainpage xAODTracking package + + @author Edward Moyse <Edward.Moyse@cern.ch> + @author Andreas Salzburger <Andreas.Salzburger@cern.ch> + @author Markus Elsing <Markus.Elsing@cern.ch> + @author Ruslan Mashinistov <Ruslan.Mashinistov@cern.ch> + @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + + $Revision: 588420 $ + $Date: 2014-03-19 15:15:25 +0100 (Wed, 19 Mar 2014) $ + + @section xAODTrackingOverview Overview + + This package holds the data model to describe the output of the + tracking/vertexing reconstruction for analysis users. + + @section xAODTrackingClasses Classes + + The main classes of the package are the following: + - xAOD::TrackParticle: Class describing a chaged track. + - xAOD::NeutralParticle: Class describing a neutral particle; + - xAOD::Vertex: Class describing a reconstructed vertex. + + @htmlinclude used_packages.html + + @include requirements +*/ diff --git a/EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticle_test.ref b/EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticle_test.ref new file mode 100644 index 00000000..fc7c48f3 --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticle_test.ref @@ -0,0 +1,18 @@ +d0 = 1, z0 = 2, phi0 = 1.23, theta = 0.5, qOverP = 0.25 +definingParametersCovMatrixVec = [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3] +vx = 0, vy = 1, vz = 2 +numberOfParameters = 2 + - x = 0, y = 1, z = 2, px = 3, py = 4, pz = 5 + - x = 6, y = 7, z = 8, px = 9, py = 10, pz = 11 +parameterPosition( 0 ) = 1 +parameterPosition( 1 ) = 3 + Dumping TrackParticleAuxContainer_v3 +d0:1, z0:2, phi:1.23, theta:0.5, qOverP:0.25, definingParametersCovMatrix: [0x7fffa0474140]1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, +d0 = 1, z0 = 2, phi0 = 1.23, theta = 0.5, qOverP = 0.25 +definingParametersCovMatrixVec = [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3] +vx = 0, vy = 1, vz = 2 +numberOfParameters = 2 + - x = 0, y = 1, z = 2, px = 3, py = 4, pz = 5 + - x = 6, y = 7, z = 8, px = 9, py = 10, pz = 11 +parameterPosition( 0 ) = 1 +parameterPosition( 1 ) = 3 diff --git a/EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticlexAODHelpers_test.ref b/EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticlexAODHelpers_test.ref new file mode 100644 index 00000000..f58064ad --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/share/xAODTracking_TrackParticlexAODHelpers_test.ref @@ -0,0 +1 @@ +PASSED. diff --git a/EDM/athena/xAOD/xAODTracking/test/xAODTracking_StripCluster_test.cxx b/EDM/athena/xAOD/xAODTracking/test/xAODTracking_StripCluster_test.cxx new file mode 100644 index 00000000..faceebe9 --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/test/xAODTracking_StripCluster_test.cxx @@ -0,0 +1,69 @@ +// System include(s): +#include <iostream> + +// Local include(s): +#include "xAODTracking/StripClusterContainer.h" +#include "xAODTracking/StripClusterAuxContainer.h" + +template< typename T > +std::ostream& operator<< ( std::ostream& out, + const std::vector< T >& vec ) { + + out << "["; + for( size_t i = 0; i < vec.size(); ++i ) { + out << vec[ i ]; + if( i < vec.size() - 1 ) { + out << ", "; + } + } + out << "]"; + return out; +} + +/// Function filling one StripCluster with information +void fill( xAOD::StripCluster& sc ) { + + sc.setLocalPosition( 1.0, 2.0); + + sc.setLocalPositionError( 0.2, 0.2, 0.05 ); + + sc.setGlobalPosition( 225.0, -151.4, 144.4 ); + + return; +} + +/// Function printing the properties of a StripCluster +void print( const xAOD::StripCluster& sc ) { + + std::cout << "id = " << sc.id() << std::endl; + std::cout << "local x = " << sc.localX() << ", local y = " << sc.localY() + << ", local x error = " << sc.localXError() << ", local y error = " << sc.localYError() + << ", local xy correlation = " << sc.localXYCorrelation() << std::endl; + std::cout << "global x = " << sc.globalX() << ", global y = " << sc.globalY() << ", global z = " << sc.globalZ() << std::endl; + + return; +} + +int main() { + + // Create the main containers to test: + xAOD::StripClusterAuxContainer aux; + xAOD::StripClusterContainer tpc; + tpc.setStore( &aux ); + + // Add one strip cluster to the container: + xAOD::StripCluster* p = new xAOD::StripCluster(); + tpc.push_back( p ); + + // Fill it with information: + fill( *p ); + + // Print the information: + print( *p ); + + // Print the contents of the auxiliary store: + aux.dump(); + + // Return gracefully: + return 0; +} \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/xAODTracking/StripCluster.h b/EDM/athena/xAOD/xAODTracking/xAODTracking/StripCluster.h new file mode 100644 index 00000000..5e8ee7eb --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/xAODTracking/StripCluster.h @@ -0,0 +1,72 @@ +/* + FASER Collaboration +*/ +#ifndef XAODTRACKING_STRIPCLUSTER_H +#define XAODTRACKING_STRIPCLUSTER_H +#ifndef STRIPCLUSTER_H +#define STRIPCLUSTER_H + +#include <iostream> +#include <vector> +#include <Eigen/Dense> + +// Core include(s): +#include "AthContainers/AuxElement.h" + +using namespace Eigen; +using namespace std; + +namespace xAOD { + + class StripCluster : public SG::AuxElement { + + public: + + /// Default constructor + StripCluster(); + + /// Returns the identifier + uint64_t id() const; + /// Returns the list of RDO identifiers + const std::vector<uint64_t>& rdoIdentifierList() const; + /// Sets the identifier + void setId(uint64_t id); + /// Sets the list of RDO identifiers + void setRdoIdentifierList(const std::vector< uint64_t >& rdoIdentifierList); + + /// @name Local position functions + /// Returns the local position + /// @{ + /// Returns the x position + float localX() const; + /// Returns the y position + float localY() const; + /// Returns the x position error + float localXError() const; + /// Returns the y position error + float localYError() const; + /// Returns the xy position correlation + float localXYCorrelation() const; + /// Sets the local position + void setLocalPosition(float localX, float localY); + /// Sets the local position error + void setLocalPositionError(float localXError, float localYError, float localXYCorrelation); + /// @} + /// @name Global position functions + /// Returns the global position + /// @{ + /// Returns the x position + float globalX() const; + /// Returns the y position + float globalY() const; + /// Returns the z position + float globalZ() const; + /// Sets the global position + void setGlobalPosition(float globalX, float globalY, float globalZ); + /// @} + + }; + #endif // STRIPCLUSTER_H + +} // end of the xAOD namespace +#endif // XAODTRACKING_STRIPCLUSTER_H \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterAuxContainer.h b/EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterAuxContainer.h new file mode 100644 index 00000000..93da640a --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterAuxContainer.h @@ -0,0 +1,48 @@ +#ifndef XAODTRACKING_STRIPCLUSTERAUXCONTAINER_H +#define XAODTRACKING_STRIPCLUSTERAUXCONTAINER_H + +// System include(s): +#include <vector> + +// Core include(s): +#include "xAODCore/AuxContainerBase.h" +#include "AthLinks/ElementLink.h" + +namespace xAOD { + /// Definition of the current Strip Cluster auxiliary container + /// + /// All reconstruction code should attach the typedefed auxiliary + /// container to the xAOD::StripClusterContainer, so it will be easy to change + /// the container type as we get new I/O technologies for these + /// objects. + /// + class StripClusterAuxContainer : public AuxContainerBase { + + public: + /// Default constructor + StripClusterAuxContainer(); + /// Dumps contents (for debugging) + void dump() const; + + private: + std::vector< uint64_t > id; + std::vector< std::vector< uint64_t > > rdoIdentifierList; + + std::vector< float > localX; + std::vector< float > localY; + std::vector< float > localXError; + std::vector< float > localYError; + std::vector< float > localXYCorrelation; + + std::vector< float > globalX; + std::vector< float > globalY; + std::vector< float > globalZ; + + }; // class StripClusterAuxContainer +} + +// Set up a CLID for the container: +#include "xAODCore/CLASS_DEF.h" +CLASS_DEF( xAOD::StripClusterAuxContainer , 1311112289 , 1 ) + +#endif // XAODTRACKING_STRIPCLUSTERAUXCONTAINER_H \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterContainer.h b/EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterContainer.h new file mode 100644 index 00000000..f9e8792f --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/xAODTracking/StripClusterContainer.h @@ -0,0 +1,18 @@ +#ifndef XAODTRACKING_STRIPCLUSTERCONTAINER_H +#define XAODTRACKING_STRIPCLUSTERCONTAINER_H + +// Core include(s): +#include "AthContainers/DataVector.h" +// Local include(s): +#include "xAODTracking/StripCluster.h" + +namespace xAOD { + /// The container is a simple typedef for now + typedef DataVector< xAOD::StripCluster > StripClusterContainer; +} + +// Set up a CLID for the container: +#include "xAODCore/CLASS_DEF.h" +CLASS_DEF( xAOD::StripClusterContainer , 1123888166 , 1 ) + +#endif // XAODTRACKING_STRIPCLUSTERCONTAINER_H \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/xAODTracking/selection.xml b/EDM/athena/xAOD/xAODTracking/xAODTracking/selection.xml new file mode 100644 index 00000000..c3eb20ca --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/xAODTracking/selection.xml @@ -0,0 +1,47 @@ +<lcgdict> + <!-- SCTRawHitValidation_v1 dictionaries: --> + <!-- <class name="xAOD::SCTRawHitValidationAuxContainer_v1" --> + <!-- id="788781DA-FE8A-414A-A72B-6E846094FCF8" /> --> + <!-- <class name="xAOD::SCTRawHitValidationContainer_v1" --> + <!-- id="4F8042A1-64B0-42AB-B0A4-C9716C15336A" /> --> + <!-- --> + <!-- <class name="DataLink<xAOD::SCTRawHitValidationContainer_v1>" /> --> + <!-- <class name="std::vector<DataLink<xAOD::SCTRawHitValidationContainer_v1> >" /> --> + <!-- --> + <!-- <class name="ElementLink<xAOD::SCTRawHitValidationContainer_v1>" /> --> + <!-- <class name="std::vector<ElementLink<xAOD::SCTRawHitValidationContainer_v1> >" /> --> + <!-- <class name="std::vector<std::vector<ElementLink<xAOD::SCTRawHitValidationContainer_v1> > >" /> --> + + <!-- StripCluster dictionaries: --> + <class name="xAOD::StripCluster"/> + <class name="xAOD::StripClusterAuxContainer" + id="61B62A1A-4C51-43A2-9623-1B9E910A81E8"/> + <class name="xAOD::StripClusterContainer" + id="868F1FD8-AFE7-4B40-B12E-73716C37A6B0"/> + + <!-- Smart pointers to objects: --> + <class name="DataLink<xAOD::StripClusterContainer>" /> + <class name="std::vector<DataLink<xAOD::StripClusterContainer> >" /> + + <class name="ElementLink<xAOD::StripClusterContainer>" /> + <class name="std::vector<ElementLink<xAOD::StripClusterContainer> >" /> + <class name="std::vector<std::vector<ElementLink<xAOD::StripClusterContainer> > >" /> + + <!-- Enums --> + <enum pattern="xAOD::*" /> + + <class name="std::vector<std::vector<std::vector<int> > >"/> + <class name="std::vector<std::vector<std::vector<float> > >"/> + <class name="std::vector<std::vector<unsigned long> >"/> + + + <!-- Suppress the unwanted classes found by ROOT 6. --> + <!-- Hopefully we can remove these extra lines at one point... --> + <exclusion> + <class name="SG::IConstAuxStore" /> + <class name="DataLink<SG::IConstAuxStore>" /> + <class name="DataVector<xAOD::IParticle>" /> + <enum name="xAOD::Type::ObjectType" /> + </exclusion> + +</lcgdict> \ No newline at end of file diff --git a/EDM/athena/xAOD/xAODTracking/xAODTracking/xAODTrackingDict.h b/EDM/athena/xAOD/xAODTracking/xAODTracking/xAODTrackingDict.h new file mode 100644 index 00000000..6d8fe7ef --- /dev/null +++ b/EDM/athena/xAOD/xAODTracking/xAODTracking/xAODTrackingDict.h @@ -0,0 +1,59 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef XAODTRACKING_XAODTRACKINGDICT_H +#define XAODTRACKING_XAODTRACKINGDICT_H + +// Needed to successfully generate the dictionary in standalone mode: +#if defined(__GCCXML__) and not defined(EIGEN_DONT_VECTORIZE) +# define EIGEN_DONT_VECTORIZE +#endif // __GCCXML__ + +// System include(s): +#include <bitset> + +// EDM include(s): +#include "AthLinks/DataLink.h" +#include "AthLinks/ElementLink.h" + +// Local include(s): +#include "xAODTracking/StripClusterContainer.h" +#include "xAODTracking/StripClusterAuxContainer.h" + +//#include "xAODTracking/SCTRawHitValidation.h" +//#include "xAODTracking/SCTRawHitValidationContainer.h" +//#include "xAODTracking/SCTRawHitValidationAuxContainer.h" +//#include "xAODTracking/versions/SCTRawHitValidation_v1.h" +//#include "xAODTracking/versions/SCTRawHitValidationContainer_v1.h" +//#include "xAODTracking/versions/SCTRawHitValidationAuxContainer_v1.h" + +namespace { + struct GCCXML_DUMMY_INSTANTIATION_XAODTRACKING { + + // Container(s): + xAOD::StripClusterContainer c4; + // Data link(s): + DataLink< xAOD::StripClusterContainer > pdl1; + std::vector< DataLink< xAOD::StripClusterContainer > > pdl2; + // Element link(s): + ElementLink< xAOD::StripClusterContainer > pel1; + std::vector< ElementLink< xAOD::StripClusterContainer > > pel2; + std::vector< std::vector< ElementLink< xAOD::StripClusterContainer > > > pel3; + + // // Container(s): + // xAOD::SCTRawHitValidationContainer_v1 c6; + // // Data link(s): + // DataLink< xAOD::SCTRawHitValidationContainer_v1 > rdodl1; + // std::vector< DataLink< xAOD::SCTRawHitValidationContainer_v1 > > rdodl2; + // // Element link(s): + // ElementLink< xAOD::SCTRawHitValidationContainer > rdoel1; + // std::vector< ElementLink< xAOD::SCTRawHitValidationContainer_v1 > > rdoel2; + // std::vector< std::vector< ElementLink< xAOD::SCTRawHitValidationContainer_v1 > > > rdoel3; + + }; +} + +#endif // XAODTRACKPARTICLE_XAODTRACKPARTICLEDICT_H \ No newline at end of file -- GitLab