diff --git a/GaudiKernel/include/GaudiKernel/SerializeSTL.h b/GaudiKernel/include/GaudiKernel/SerializeSTL.h index f8471fc227a1ddf6cf3f512bffd53eef75c363c6..b6db6913e1049426d9421241230dde90fbeb56a7 100644 --- a/GaudiKernel/include/GaudiKernel/SerializeSTL.h +++ b/GaudiKernel/include/GaudiKernel/SerializeSTL.h @@ -1,5 +1,5 @@ /***********************************************************************************\ -* (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations * +* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations * * * * This software is distributed under the terms of the Apache version 2 licence, * * copied verbatim in the file "LICENSE". * @@ -38,6 +38,10 @@ namespace GaudiUtils { template <class T1, class T2> std::ostream& operator<<( std::ostream& s, const std::pair<T1, T2>& p ); + /// Serialize an std::tuple in a python like format. E.g. "(1, 2)". + template <typename... Args> + std::ostream& operator<<( std::ostream& s, const std::tuple<Args...>& tuple ); + /// Serialize an std::vector in a python like format. E.g. "[1, 2, 3]". template <class T, class ALLOC> std::ostream& operator<<( std::ostream& s, const std::vector<T, ALLOC>& v ); @@ -50,6 +54,14 @@ namespace GaudiUtils { template <class T, class ALLOC> std::ostream& operator<<( std::ostream& s, const std::list<T, ALLOC>& l ); + /// Serialize an std::set in a python like format. E.g. "[1, 2, 3]". + template <class T, class ALLOC> + std::ostream& operator<<( std::ostream& s, const std::set<T, ALLOC>& l ); + + /// Serialize an std::unordered_set in a python like format. E.g. "{1, 2, 3}". + template <class T, class ALLOC> + std::ostream& operator<<( std::ostream& s, const std::unordered_set<T, ALLOC>& l ); + /// Serialize an std::map in a python like format. E.g. "{a: 1, b: 2}". template <class T1, class T2, class COMP, class ALLOC> std::ostream& operator<<( std::ostream& s, const std::map<T1, T2, COMP, ALLOC>& m ); @@ -91,6 +103,19 @@ namespace GaudiUtils { return s << '(' << p.first << ", " << p.second << ')'; } + template <typename... Args> + std::ostream& operator<<( std::ostream& s, const std::tuple<Args...>& tup ) { + return std::apply( + [&s]( const auto&... a ) -> decltype( auto ) { + unsigned n = sizeof...( a ); + if ( n == 1 ) n = 2; // special case in python... + s << " ("; + ( ( s << " " << a << ( --n == 0 ? "" : "," ) ), ... ); + return s << " )"; + }, + tup ); + } + template <class T, class ALLOC> std::ostream& operator<<( std::ostream& s, const std::vector<T, ALLOC>& v ) { return details::ostream_joiner( s << '[', v, ", " ) << ']'; diff --git a/GaudiKernel/include/GaudiKernel/ToStream.h b/GaudiKernel/include/GaudiKernel/ToStream.h index 49a4873b4de39780922fea310bfde37a90420204..e09df340cac6f2221ade05f501230e11d2676d1d 100644 --- a/GaudiKernel/include/GaudiKernel/ToStream.h +++ b/GaudiKernel/include/GaudiKernel/ToStream.h @@ -1,5 +1,5 @@ /***********************************************************************************\ -* (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations * +* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations * * * * This software is distributed under the terms of the Apache version 2 licence, * * copied verbatim in the file "LICENSE". * @@ -123,6 +123,10 @@ namespace Gaudi { inline std::ostream& toStream( const std::pair<KTYPE, VTYPE>& obj, std::ostream& s ) { return toStream( obj.second, toStream( obj.first, s << "( " ) << " , " ) << " )"; } + + template <typename... Args> + inline std::ostream& toStream( const std::tuple<Args...>& tuple, std::ostream& s ); + // ======================================================================== /** the partial template specialization of <c>std::vector<TYPE,ALLOCATOR></c> * printout. The vector is printed a'la Python list: "[ a, b, c ]" @@ -284,32 +288,6 @@ namespace Gaudi { return s << obj; } // ======================================================================== - /** the helper function to print the sequence - * @param first (INPUT) begin-iterator for the sequence - * @param last (INPUT) end-iterator for the sequence - * @param s (UPDATE) the stream itself - * @param open (INPUT) "open"-symbol - * @param close (INPUT) "close"-symbol - * @param delim (INPUT) "delimiter"-symbol - * @return the stream - * @author Vanya BELYAEV Ivan.BElyaev@nikhef.nl - * @date 2009-09-15 - */ - template <class ITERATOR> - inline std::ostream& toStream( ITERATOR first, // begin of the sequence - ITERATOR last, // end of the sequence - std::ostream& s, // the stream - const std::string& open, // opening - const std::string& close, // closing - const std::string& delim ) // delimiter - { - using ref_t = typename std::iterator_traits<ITERATOR>::reference; - using GaudiUtils::details::ostream_joiner; - return ostream_joiner( s << open, first, last, delim, - []( std::ostream& os, ref_t i ) -> std::ostream& { return toStream( i, os ); } ) - << close; - } - // ======================================================================== // helper function to print a tuple of any size template <class Tuple, std::size_t N> struct TuplePrinter { @@ -340,6 +318,32 @@ namespace Gaudi { } return out << " ) "; } + // ======================================================================== + /** the helper function to print the sequence + * @param first (INPUT) begin-iterator for the sequence + * @param last (INPUT) end-iterator for the sequence + * @param s (UPDATE) the stream itself + * @param open (INPUT) "open"-symbol + * @param close (INPUT) "close"-symbol + * @param delim (INPUT) "delimiter"-symbol + * @return the stream + * @author Vanya BELYAEV Ivan.BElyaev@nikhef.nl + * @date 2009-09-15 + */ + template <class ITERATOR> + inline std::ostream& toStream( ITERATOR first, // begin of the sequence + ITERATOR last, // end of the sequence + std::ostream& s, // the stream + const std::string& open, // opening + const std::string& close, // closing + const std::string& delim ) // delimiter + { + using ref_t = typename std::iterator_traits<ITERATOR>::reference; + using GaudiUtils::details::ostream_joiner; + return ostream_joiner( s << open, first, last, delim, + []( std::ostream& os, ref_t i ) -> std::ostream& { return toStream( i, os ); } ) + << close; + } // ======================================================================== /** the generic implementation of the type conversion to the string diff --git a/GaudiTestSuite/options/ExtendedProperties.opts b/GaudiTestSuite/options/ExtendedProperties.opts index 5c4b35d100f8be69d13b0f3b5530f20269ffd2fb..4e714a7920313ffd47be4b490ef099c7f6a560a9 100644 --- a/GaudiTestSuite/options/ExtendedProperties.opts +++ b/GaudiTestSuite/options/ExtendedProperties.opts @@ -123,6 +123,13 @@ xProps.StdArrayInt1 = (42); xProps.GaudiMapSS = {"a": "1", "b": "2"}; +xProps.PTupleVector = [("one", "two", "three"), ("a", "b", "c")]; +xProps.PIntVectorTuple = (42, ["one", "two", "three"]); +xProps.PTupleSet = [("one", "two", "three"), ("a", "b", "c")]; +xProps.PIntSetTuple = (42, ["one", "two", "three"]); +xProps.PTupleUnSet = {("one", "two", "three"), ("a", "b", "c")}; +xProps.PIntUnSetTuple = (42, {"one", "two", "three"}); + // ============================================================================ // ============================================================================ diff --git a/GaudiTestSuite/options/ExtendedProperties.py b/GaudiTestSuite/options/ExtendedProperties.py index 84a0377e80b61709f0185deb251964665b360d09..66aa787f80e65e00ee249ea815099f34a9d32091 100644 --- a/GaudiTestSuite/options/ExtendedProperties.py +++ b/GaudiTestSuite/options/ExtendedProperties.py @@ -1,5 +1,5 @@ ##################################################################################### -# (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations # +# (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations # # # # This software is distributed under the terms of the Apache version 2 licence, # # copied verbatim in the file "LICENSE". # @@ -96,6 +96,13 @@ xProps.GaudiMapSS = {"a": "1", "b": "2"} xProps.ExtraInputs = set() xProps.ExtraOutputs = {"a", ("a", "b"), (1, "a")} +xProps.PTupleVector = [("one", "two", "three"), ("a", "b", "c")] +xProps.PIntVectorTuple = (42, ["one", "two", "three"]) +xProps.PTupleSet = [("one", "two", "three"), ("a", "b", "c")] +xProps.PIntSetTuple = (42, ["one", "two", "three"]) +xProps.PTupleUnSet = {("one", "two", "three"), ("a", "b", "c")} +xProps.PIntUnSetTuple = (42, {"one", "two", "three"}) + # END of xProp configuration app = ApplicationMgr( diff --git a/GaudiTestSuite/src/ExtendedProperties/ExtendedProperties.cpp b/GaudiTestSuite/src/ExtendedProperties/ExtendedProperties.cpp index 7bfe394b123db35177e3e891bb4893e2ca6c1f5d..89256fea476462904cdec118ef03be65df3fbc18 100644 --- a/GaudiTestSuite/src/ExtendedProperties/ExtendedProperties.cpp +++ b/GaudiTestSuite/src/ExtendedProperties/ExtendedProperties.cpp @@ -1,5 +1,5 @@ /***********************************************************************************\ -* (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations * +* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations * * * * This software is distributed under the terms of the Apache version 2 licence, * * copied verbatim in the file "LICENSE". * @@ -101,72 +101,30 @@ private: Gaudi::Property<std::array<int, 1>> m_26{ this, "StdArrayInt1", { 0 } }; Gaudi::Property<GaudiUtils::Map<std::string, std::string>> m_24{ this, "GaudiMapSS" }; + + using Triplet = std::tuple<std::string, std::string, std::string>; + static std::hash<std::string> hasher; + struct HashFunction { + std::size_t operator()( Triplet const& entry ) const { + return hasher( std::get<0>( entry ) ) ^ hasher( std::get<1>( entry ) ) ^ hasher( std::get<2>( entry ) ); + } + }; + + Gaudi::Property<std::vector<Triplet>> m_tuplevector{ this, "PTupleVector" }; + Gaudi::Property<std::set<Triplet>> m_tupleset{ this, "PTupleSet" }; + Gaudi::Property<std::unordered_set<Triplet, HashFunction>> m_tupleunset{ this, "PTupleUnSet" }; + using VS = std::vector<std::string>; + Gaudi::Property<std::tuple<int, VS>> m_intvectortuple{ this, "PIntVectorTuple" }; + using SS = std::set<std::string>; + Gaudi::Property<std::tuple<int, SS>> m_intsettuple{ this, "PIntSetTuple" }; + using USS = std::unordered_set<std::string>; + Gaudi::Property<std::tuple<int, USS>> m_intunsettuple{ this, "PIntUnSetTuple" }; }; // ============================================================================ /// factory // ============================================================================ DECLARE_COMPONENT( ExtendedProperties ) // ============================================================================ -namespace { - template <class TYPE> - inline SimplePropertyRef<TYPE> _prop( TYPE& value ) { - // construct a readable name - std::string name = System::typeinfoName( typeid( value ) ); - std::string::size_type ipos = name.find( "std::" ); - while ( std::string::npos != ipos ) { - name.erase( ipos, 5 ); - ipos = name.find( "std::" ); - } - ipos = name.find( "__cxx11::" ); - while ( std::string::npos != ipos ) { - name.erase( ipos, 9 ); - ipos = name.find( "__cxx11::" ); - } - ipos = name.find( " " ); - while ( std::string::npos != ipos ) { - name.erase( ipos, 1 ); - ipos = name.find( " " ); - } - ipos = name.find( "const" ); - while ( std::string::npos != ipos ) { - name.erase( ipos, 5 ); - ipos = name.find( "const" ); - } - ipos = name.find( ",allocator<" ); - while ( std::string::npos != ipos ) { - std::string::size_type ip2 = ipos + 11; - int ip3 = 1; - for ( ; ip2 < name.size(); ++ip2 ) { - if ( '<' == name[ip2] ) { ip3 += 1; } - if ( '>' == name[ip2] ) { ip3 -= 1; } - if ( 0 == ip3 ) { break; } - } - name.erase( ipos, ip2 + 1 - ipos ); - ipos = name.find( ",allocator<" ); - } - if ( std::string::npos != name.find( "map<" ) ) { - ipos = name.find( ",less<" ); - while ( std::string::npos != ipos ) { - std::string::size_type ip2 = ipos + 6; - int ip3 = 1; - for ( ; ip2 < name.size(); ++ip2 ) { - if ( '<' == name[ip2] ) { ip3 += 1; } - if ( '>' == name[ip2] ) { ip3 -= 1; } - if ( 0 == ip3 ) { break; } - } - name.erase( ipos, ip2 + 1 - ipos ); - ipos = name.find( ",less<" ); - } - } - ipos = name.find( ">>" ); - while ( std::string::npos != ipos ) { - name.replace( ipos, 2, "> >" ); - ipos = name.find( ">>" ); - } - return SimplePropertyRef<TYPE>( name, value ); - } -} // namespace -// ============================================================================ StatusCode ExtendedProperties::execute() { always() << " My Properties : " << endmsg; @@ -201,6 +159,13 @@ StatusCode ExtendedProperties::execute() { always() << " \t" << m_30 << endmsg; always() << " \t" << m_31 << endmsg; + always() << " \t" << m_tuplevector << endmsg; + always() << " \t" << m_intvectortuple << endmsg; + always() << " \t" << m_tupleset << endmsg; + always() << " \t" << m_intsettuple << endmsg; + always() << " \t" << m_tupleunset << endmsg; + always() << " \t" << m_intunsettuple << endmsg; + // some properties could be created from other (convertible) types: Gaudi::Property<short> m1( "a", 0 ); Gaudi::Property<double> m2( "b", m1 ); diff --git a/GaudiTestSuite/tests/pytest/properties/ExtPropValidator.py b/GaudiTestSuite/tests/pytest/properties/ExtPropValidator.py index 447fe86a6d4ad101133ef3c7940c4bfd8cd37355..43e1f55904337e4c24d1c2e138708b184f2eb361 100644 --- a/GaudiTestSuite/tests/pytest/properties/ExtPropValidator.py +++ b/GaudiTestSuite/tests/pytest/properties/ExtPropValidator.py @@ -1,5 +1,5 @@ ##################################################################################### -# (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations # +# (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations # # # # This software is distributed under the terms of the Apache version 2 licence, # # copied verbatim in the file "LICENSE". # @@ -59,6 +59,12 @@ def validate(stdout): "StdArrayDouble3": (3.3, 2.2, 1.1), "StdArrayInt1": (42,), "GaudiMapSS": {"a": "1", "b": "2"}, + "PTupleVector": [("one", "two", "three"), ("a", "b", "c")], + "PIntVectorTuple": (42, ["one", "two", "three"]), + "PTupleSet": [("a", "b", "c"), ("one", "two", "three")], + "PIntSetTuple": (42, ["one", "three", "two"]), + "PTupleUnSet": {("a", "b", "c"), ("one", "two", "three")}, + "PIntUnSetTuple": (42, {"one", "two", "three"}), } import re