Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:34

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
0010 \***********************************************************************************/
0011 // ============================================================================
0012 #ifndef GAUDIALG_TUPLEOBJ_H
0013 #define GAUDIALG_TUPLEOBJ_H 1
0014 // ============================================================================
0015 // Include files
0016 // ============================================================================
0017 // STD&STL
0018 // ============================================================================
0019 #include <array>
0020 #include <cstddef>
0021 #include <fmt/format.h>
0022 #include <functional>
0023 #include <limits>
0024 #include <numeric>
0025 #include <set>
0026 #include <sstream>
0027 #include <string>
0028 
0029 // ============================================================================
0030 // GaudiKernel
0031 // ============================================================================
0032 #include "GaudiKernel/NTuple.h"
0033 #include "GaudiKernel/SerializeSTL.h"
0034 #include "GaudiKernel/VectorMap.h"
0035 // ============================================================================
0036 // GaudiAlg
0037 // ============================================================================
0038 #include "GaudiAlg/Maps.h"
0039 #include "GaudiAlg/Tuples.h"
0040 // ============================================================================
0041 // ROOT
0042 // ============================================================================
0043 #include "Math/Point3D.h"
0044 #include "Math/SMatrix.h"
0045 #include "Math/SVector.h"
0046 #include "Math/Vector3D.h"
0047 #include "Math/Vector4D.h"
0048 // ============================================================================
0049 // forward declaration
0050 // ============================================================================
0051 // GaudiKernel
0052 // ============================================================================
0053 class IOpaqueAddress;
0054 // ============================================================================
0055 /** @file TupleObj.h
0056  *
0057  *  Header file for class TupleObj
0058  *
0059  *  @date 2004-01-23
0060  *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
0061  */
0062 
0063 // ============================================================================
0064 /** @namespace Tuples
0065  *
0066  *  General namespace for Tuple properties
0067  *
0068  *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
0069  *  @date   2004-01-23
0070  */
0071 namespace Tuples {
0072   namespace detail {
0073     template <typename T>
0074     struct to_ {
0075       template <typename Arg>
0076       T operator()( Arg&& i ) const {
0077         return T( std::forward<Arg>( i ) );
0078       }
0079     };
0080     constexpr to_<float> to_float{};
0081 
0082     template <typename Iterator>
0083     using const_ref_t = std::add_const_t<typename std::iterator_traits<Iterator>::reference>;
0084   } // namespace detail
0085   // ==========================================================================
0086   /** @enum Type
0087    *  the list of available types for ntuples
0088    *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
0089    *  @date   2004-01-23
0090    */
0091   enum Type {
0092     NTUPLE, // Analysis nTuple
0093     EVTCOL  // Event Collection
0094   };
0095   // ==========================================================================
0096   /** @enum ErrorCodes
0097    *
0098    *  Tuple error codes
0099    *
0100    *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
0101    *  @date   2004-01-23
0102    */
0103   enum class ErrorCodes : StatusCode::code_t {
0104     InvalidTuple = 100,
0105     InvalidColumn,
0106     InvalidOperation,
0107     InvalidObject,
0108     InvalidItem,
0109     TruncateValue = 200
0110   };
0111 } // namespace Tuples
0112 
0113 STATUSCODE_ENUM_DECL( Tuples::ErrorCodes )
0114 
0115 namespace Tuples {
0116   // ==========================================================================
0117   /** @class TupleObj TupleObj.h GaudiAlg/TupleObj.h
0118    *
0119    *  @brief A simple wrapper class over standard
0120    *                        Gaudi NTuple::Tuple facility
0121    *
0122    *  The design and implementation are imported from LoKi package
0123    *
0124    *  One should not use lass TupleObj directly.
0125    *  The special handler Tuples::Tuple should be used instead,
0126    *  which is simultaneously 'proxy' an d'smart pointer' for
0127    *  real (and heavy!) TupleObj class.
0128    *
0129    *  The main advantages of local ntuples with respect to 'standard'
0130    *  Gaudi NTuples ( NTuple::Tuple ) is their "locality".
0131    *  For 'standard' ntuples one need
0132    * <ol>
0133    * <li> Define all ntuple columns/items as
0134    *      data members of the algorithm </li>
0135    * <li> Book the  <tt>NTuple::Tuple</tt> object using
0136    *      <tt>INTupleSvc</tt></li>
0137    * <li> Add all defined columns/items to the booked ntuple </li>
0138    * <li> Fill ntuple records
0139    * </ol>
0140    *  Usually the first step is done in the header file (separate file!)
0141    *  of the algorithm, the second and the third steps are done in
0142    *  <tt>initialize()</tt> method of the algorithm and
0143    *  the fourth step is done somewhere in <tt>execute()</tt> method of
0144    *  the same algorithm. Such approach requires to keep track of the
0145    *  tuple structure through different method and event through different
0146    *  files. And even minor modification of the structure of the ntuple
0147    *  will require the modification of at least 2 methods and 2 files.
0148    *
0149    *  The <tt>Tuples::Tuple</tt> wrapper over standard Gaudi
0150    *  <tt>NTuple::Tuple</tt> class solves all above listed problems with
0151    *  "non-local" nature of Gaudi <tt>NTuple::Tuple</tt> objects.
0152    *
0153    *  <tt>Tuples::Tuple</tt> object is booked and used 'locally'.
0154    *  One does not need to pre-book the ntuple or its columns/items
0155    *  somewhere in different compilation units or other methods different
0156    *  from the actual point of using the ntuple.
0157    *
0158    *  The simplest example of usage Tuples::Tuple object:
0159    *  @code
0160    *  Tuple tuple = nTuple( "some more or less unique tuple title ");
0161    *  for( Loop D0 = loop( "K- pi+", "D0" ) , D0 , ++D0 )
0162    *  {
0163    *     tuple -> column ( "mass" , M  ( D0 ) / GeV ) ;
0164    *     tuple -> column ( "pt"   , PT ( D0 ) / GeV ) ;
0165    *     tuple -> column ( "p"    , P  ( D0 ) / GeV ) ;
0166    *     tuple -> write  () ;
0167    *  }
0168    *  @endcode
0169    *
0170    *  One could fill some Tuple variables in one go
0171    *  @code
0172    *  Tuple tuple = nTuple( "some more or less unique tuple title ");
0173    *  for( Loop D0 = loop( "K- pi+", "D0" ) , D0 , ++D0 )
0174    *  {
0175    *     tuple -> column ( "mass"      , M  ( D0 ) / GeV ) ;
0176    *     tuple -> fill   ( "pt , p "   , PT ( D0 ) / GeV , P(D0) / GeV ) ;
0177    *     tuple -> write  () ;
0178    *  }
0179    *  @endcode
0180    *
0181    *  Even ALL variables could be filled in one go:
0182    *  @code
0183    *  Tuple tuple = nTuple( "some more or less unique tuple title ");
0184    *  for( Loop D0 = loop( "K- pi+", "D0" ) , D0 , ++D0 )
0185    *  {
0186    *     tuple -> fill   ( "mass pt , p ", M(D0)/GeV,PT(D0)/GeV,P(D0)/GeV ) ;
0187    *     tuple -> write  () ;
0188    *  }
0189    *  @endcode
0190    *
0191    *  The 'array-like' columns are also supported ( see methods 'farray')
0192    *
0193    *  All these techniques could be easily combined in arbitrary ways
0194    *
0195    *  class TupleObj is an abstract class with 3 pure abstract functions
0196    *  Error and Warning , which need to be reimplemented
0197    *  in any 'concrete class.
0198    *   Helper classes TupleObjImp, ErrorHandler and functions
0199    *   createTupleObj and make_handler allows to
0200    *   create concrete objects 'on-flight'
0201    *
0202    *  @attention
0203    *    <c>long long</c> and <c>unsigned long long</c>
0204    *    types are not supported. One needs to convert the data
0205    *    into some other representation (e.g. as 2 separate fields,
0206    *    or perform the explicitly cast to <c>long</c>)
0207    *
0208    *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
0209    *  @date   2004-01-23
0210    */
0211   class GAUDI_API TupleObj {
0212   public:
0213     // ========================================================================
0214     /// basics type for various items
0215     using Bool      = NTuple::Item<bool>;
0216     using Char      = NTuple::Item<char>;
0217     using UChar     = NTuple::Item<unsigned char>;
0218     using Short     = NTuple::Item<short>;
0219     using UShort    = NTuple::Item<unsigned short>;
0220     using Int       = NTuple::Item<int>;
0221     using UInt      = NTuple::Item<unsigned int>;
0222     using LongLong  = NTuple::Item<long long>;
0223     using ULongLong = NTuple::Item<unsigned long long>;
0224     using Float     = NTuple::Item<float>;
0225     using Double    = NTuple::Item<double>;
0226     using Address   = NTuple::Item<IOpaqueAddress*>;
0227     using FArray    = NTuple::Array<float>;
0228     using FMatrix   = NTuple::Matrix<float>;
0229     // ========================================================================
0230     // the actual type for variable size matrix indices
0231     typedef unsigned short MIndex;
0232     // ========================================================================
0233     // the map of all items
0234     typedef std::map<std::string, std::string, std::less<>> ItemMap;
0235     // ========================================================================
0236   protected:
0237     // ========================================================================
0238     /** Standard constructor
0239      *  @see   NTuple:Tuple
0240      *  @param name  name of the object
0241      *  @param tuple pointer to standard Gaudi NTuple::Tuple object
0242      *  @param clid  CLID_ColumnWiseTuple or CLID_RowWiseTuple
0243      *  @param type the type of the tuple
0244      */
0245     TupleObj( std::string name, NTuple::Tuple* tuple, const CLID& clid = CLID_ColumnWiseTuple,
0246               const Tuples::Type type = Tuples::NTUPLE );
0247     // ========================================================================
0248   public:
0249     // ========================================================================
0250     virtual ~TupleObj();
0251     // ========================================================================
0252     /** Set the value for selected tuple column.
0253      *  If column does not exist, it will be automatically created
0254      *  and appended to the tuple
0255      *
0256      *  @code
0257      *  //
0258      *  const float mass = ... ;
0259      *  tuple->column( "m", mass );
0260      *  //
0261      *  @endcode
0262      *
0263      *  @param  name  the name of the column
0264      *  @param  value the value of the variable
0265      *  @return status code
0266      */
0267     StatusCode column( std::string_view name, float value );
0268     // ========================================================================
0269   public:
0270     // ========================================================================
0271     /** Set the value for the selected tuple column
0272      *  If the column does not exist, it will be automatically created
0273      *  and appended to the tuple
0274      *
0275      *  @code
0276      *  //
0277      *  const double mass = ... ;
0278      *  tuple->column( "m", mass );
0279      *  //
0280      *  @endcode
0281      *  @warning the value is truncated to float
0282      *
0283      *  @param  name     the name of the column
0284      *  @param  value    the value of the variable
0285      *  @return status code
0286      */
0287     StatusCode column( std::string_view name, double value );
0288     // ========================================================================
0289   public:
0290     // ========================================================================
0291     /** Set the value for selected tuple column.
0292      *  If the column does not exist yet, it will be
0293      *  automatically created and appended to the tuple
0294      *
0295      *  @code
0296      *
0297      *  short number = ... ;
0298      *  tuple -> column ( "num" , number );
0299      *
0300      *  @endcode
0301      *
0302      *  @param name   the name of the column
0303      *  @param value  the value of the variable
0304      *  @return status code
0305      */
0306     StatusCode column( std::string_view name, short value );
0307     // ========================================================================
0308     /** Set the value for selected tuple column.
0309      *  If the column does not exist yet, it will be
0310      *  automatically created and appended to the tuple
0311      *
0312      *  @code
0313      *
0314      *  short number = ... ;
0315      *  tuple->column( "num", number );
0316      *
0317      *  @endcode
0318      *
0319      *  @param name   name of the column
0320      *  @param value  value of the variable
0321      *  @param minv   minimum value of the variable
0322      *  @param maxv   maximum value of the variable
0323      *  @return status code
0324      */
0325     StatusCode column( std::string_view name, short value, short minv, short maxv );
0326     // ========================================================================
0327   public:
0328     // ========================================================================
0329     /** Set the value for selected tuple column.
0330      *  If the column does not exist yet, it will be
0331      *  automatically created and appended to the tuple
0332      *
0333      *  @code
0334      *
0335      *  unsigned short number = ... ;
0336      *  tuple -> column ( "num" , number );
0337      *
0338      *  @endcode
0339      *
0340      *  @param name   the name of the column
0341      *  @param value  the value of the variable
0342      *  @return status code
0343      */
0344     StatusCode column( std::string_view name, unsigned short value );
0345     // ========================================================================
0346     /** Set the value for selected tuple column.
0347      *  If the column does not exist yet, it will be
0348      *  automatically created and appended to the tuple
0349      *
0350      *  @code
0351      *
0352      *  unsigned short number = ... ;
0353      *  tuple->column( "num", number );
0354      *
0355      *  @endcode
0356      *
0357      *  @param name   name of the column
0358      *  @param value  value of the variable
0359      *  @param minv   minimum value of the variable
0360      *  @param maxv   maximum value of the variable
0361      *  @return status code
0362      */
0363     StatusCode column( std::string_view name, unsigned short value, unsigned short minv, unsigned short maxv );
0364     // ========================================================================
0365   public:
0366     // ========================================================================
0367     /** Set the value for selected tuple column.
0368      *  If the column does not exist yet, it will be
0369      *  automatically created and appended to the tuple
0370      *
0371      *  @code
0372      *
0373      *  char number = ... ;
0374      *  tuple -> column ( "num" , number );
0375      *
0376      *  @endcode
0377      *
0378      *  @param name   the name of the column
0379      *  @param value  the value of the variable
0380      *  @return status code
0381      */
0382     StatusCode column( std::string_view name, char value );
0383     // ========================================================================
0384     /** Set the value for selected tuple column.
0385      *  If the column does not exist yet, it will be
0386      *  automatically created and appended to the tuple
0387      *
0388      *  @code
0389      *
0390      *  char number = ... ;
0391      *  tuple->column( "num", number );
0392      *
0393      *  @endcode
0394      *
0395      *  @param name   name of the column
0396      *  @param value  value of the variable
0397      *  @param minv   minimum value of the variable
0398      *  @param maxv   maximum value of the variable
0399      *  @return status code
0400      */
0401     StatusCode column( std::string_view name, char value, char minv, char maxv );
0402     // ========================================================================
0403   public:
0404     // ========================================================================
0405     /** Set the value for selected tuple column.
0406      *  If the column does not exist yet, it will be
0407      *  automatically created and appended to the tuple
0408      *
0409      *  @code
0410      *
0411      *  unsigned char number = ... ;
0412      *  tuple -> column ( "num" , number );
0413      *
0414      *  @endcode
0415      *
0416      *  @param name   the name of the column
0417      *  @param value  the value of the variable
0418      *  @return status code
0419      */
0420     StatusCode column( std::string_view name, unsigned char value );
0421     // ========================================================================
0422     /** Set the value for selected tuple column.
0423      *  If the column does not exist yet, it will be
0424      *  automatically created and appended to the tuple
0425      *
0426      *  @code
0427      *
0428      *  unsigned char number = ... ;
0429      *  tuple->column( "num", number );
0430      *
0431      *  @endcode
0432      *
0433      *  @param name   name of the column
0434      *  @param value  value of the variable
0435      *  @param minv   minimum value of the variable
0436      *  @param maxv   maximum value of the variable
0437      *  @return status code
0438      */
0439     StatusCode column( std::string_view name, unsigned char value, unsigned char minv, unsigned char maxv );
0440     // ========================================================================
0441   public:
0442     // ========================================================================
0443     /** Set the value for selected tuple column.
0444      *  If the column does not exist yet, it will be
0445      *  automatically created and appended to the tuple
0446      *
0447      *  @code
0448      *
0449      *  int number = ... ;
0450      *  tuple->column("num", number );
0451      *
0452      *  @endcode
0453      *
0454      *  @param name   name of the column
0455      *  @param value  value of the variable
0456      *  @return status code
0457      */
0458     StatusCode column( std::string_view name, int value );
0459     // ========================================================================
0460     /** Set the value for selected tuple column.
0461      *  If the column does not exist yet, it will be
0462      *  automatically created and appended to the tuple
0463      *
0464      *  @code
0465      *
0466      *  int number = ... ;
0467      *  tuple->column( "num", number );
0468      *
0469      *  @endcode
0470      *
0471      *  @param name   name of the column
0472      *  @param value  value of the variable
0473      *  @param minv   minimum value of the variable
0474      *  @param maxv   maximum value of the variable
0475      *  @return status code
0476      */
0477     StatusCode column( std::string_view name, int value, int minv, int maxv );
0478     // ========================================================================
0479   public:
0480     // ========================================================================
0481     /** Set the value for selected tuple column.
0482      *  If the column does not exist yet, it will be
0483      *  automatically created and appended to the tuple
0484      *
0485      *  @code
0486      *
0487      *  unsigned int number = ... ;
0488      *  tuple->column("num", number );
0489      *
0490      *  @endcode
0491      *
0492      *  @param name   name of the column
0493      *  @param value  value of the variable
0494      *  @return status code
0495      */
0496     StatusCode column( std::string_view name, unsigned int value );
0497     // ========================================================================
0498     /** Set the value for selected tuple column.
0499      *  If the column does not exist yet, it will be
0500      *  automatically created and appended to the tuple
0501      *
0502      *  @code
0503      *
0504      *  unsigned int number = ... ;
0505      *  tuple->column("num", number );
0506      *
0507      *  @endcode
0508      *
0509      *  @param name   name of the column
0510      *  @param value  value of the variable
0511      *  @param minv   minimum value of the variable
0512      *  @param maxv   maximum value of the variable
0513      *  @return status code
0514      */
0515     StatusCode column( std::string_view name, unsigned int value, unsigned int minv, unsigned int maxv );
0516     // ========================================================================
0517   public:
0518     // ========================================================================
0519     /** Set the value for the selected tuple column.
0520      *  If the column does not exist yet, it will be
0521      *  automatically created and appended to the tuple
0522      *
0523      *  @code
0524      *
0525      *  long number = ... ;
0526      *  tuple -> column ( "num", number );
0527      *
0528      *  @endcode
0529      *  @warning the value could be truncated to int
0530      *
0531      *  @param name    the name of the column
0532      *  @param value   the value of the variable
0533      *  @return status code
0534      */
0535     StatusCode column( std::string_view name, long value );
0536     // ========================================================================
0537     /** Set the value for selected tuple column.
0538      *  If the column does not exist yet, it will be
0539      *  automatically created and appended to the tuple
0540      *
0541      *  @code
0542      *
0543      *  long number = ... ;
0544      *  tuple->column("num", number );
0545      *
0546      *  @endcode
0547      *
0548      *  @param name   name of the column
0549      *  @param value  value of the variable
0550      *  @param minv   minimum value of the variable
0551      *  @param maxv   maximum value of the variable
0552      *  @return status code
0553      */
0554     StatusCode column( std::string_view name, long value, long minv, long maxv );
0555     // ========================================================================
0556   public:
0557     // ========================================================================
0558     /** Set the value for selected tuple column.
0559      *  If the column does not exist yet, it will be
0560      *  automatically created and appended to the tuple
0561      *
0562      *  @code
0563      *
0564      *  unsigned long number = ... ;
0565      *  tuple -> column ( "num" , number );
0566      *
0567      *  @endcode
0568      *  @warning the value could be truncated to int
0569      *
0570      *  @param name   the name of the column
0571      *  @param value  the value of the variable
0572      *  @return status code
0573      */
0574     StatusCode column( std::string_view name, unsigned long value );
0575     // ========================================================================
0576     /** Set the value for selected tuple column.
0577      *  If the column does not exist yet, it will be
0578      *  automatically created and appended to the tuple
0579      *
0580      *  @code
0581      *
0582      *  unsigned long number = ... ;
0583      *  tuple->column( "num", number );
0584      *
0585      *  @endcode
0586      *
0587      *  @param name   name of the column
0588      *  @param value  value of the variable
0589      *  @param minv   minimum value of the variable
0590      *  @param maxv   maximum value of the variable
0591      *  @return status code
0592      */
0593     StatusCode column( std::string_view name, unsigned long value, unsigned long minv, unsigned long maxv );
0594     // ========================================================================
0595   public:
0596     // ========================================================================
0597     /** Set the value for selected tuple column.
0598      *  If the column does not exist yet, it will be
0599      *  automatically created and appended to the tuple
0600      *
0601      *  @code
0602      *
0603      *  long long number = ... ;
0604      *  tuple->column( "num", number );
0605      *
0606      *  @endcode
0607      *
0608      *  @param name   name of the column
0609      *  @param value  value of the variable
0610      *  @return status code
0611      */
0612     StatusCode column( std::string_view name, long long value );
0613     // ========================================================================
0614     /** Set the value for selected tuple column.
0615      *  If the column does not exist yet, it will be
0616      *  automatically created and appended to the tuple
0617      *
0618      *  @code
0619      *
0620      *  long long number = ... ;
0621      *  tuple->column( "num", number );
0622      *
0623      *  @endcode
0624      *
0625      *  @param name   name of the column
0626      *  @param value  value of the variable
0627      *  @param minv   minimum value of the variable
0628      *  @param maxv   maximum value of the variable
0629      *  @return status code
0630      */
0631     StatusCode column( std::string_view name, long long value, long long minv, long long maxv );
0632     // ========================================================================
0633   public:
0634     // ========================================================================
0635     /** Set the value for selected tuple column.
0636      *  If the column does not exist yet, it will be
0637      *  automatically created and appended to the tuple
0638      *
0639      *  @code
0640      *
0641      *  unsigned long long number = ... ;
0642      *  tuple->column( "num", number );
0643      *
0644      *  @endcode
0645      *
0646      *  @param name   name of the column
0647      *  @param value  value of the variable
0648      *  @return status code
0649      */
0650     StatusCode column( std::string_view name, unsigned long long value );
0651     // ========================================================================
0652     /** Set the value for selected tuple column.
0653      *  If the column does not exist yet, it will be
0654      *  automatically created and appended to the tuple
0655      *
0656      *  @code
0657      *
0658      *  unsigned long long number = ... ;
0659      *  tuple->column( "num", number );
0660      *
0661      *  @endcode
0662      *
0663      *  @param name   name of the column
0664      *  @param value  value of the variable
0665      *  @param minv   minimum value of the variable
0666      *  @param maxv   maximum value of the variable
0667      *  @return status code
0668      */
0669     StatusCode column( std::string_view name, unsigned long long value, unsigned long long minv,
0670                        unsigned long long maxv );
0671     // ========================================================================
0672   public:
0673     // ========================================================================
0674     /** Set the value for the selected tuple column.
0675      *  If the column does not exist yet, it will be
0676      *  automatically created and appended to the tuple
0677      *
0678      *  @code
0679      *
0680      *  signed char number = ... ;
0681      *  tuple->column("num", number );
0682      *
0683      *  @endcode
0684      *
0685      *  @param name   the name of the column
0686      *  @param value  the value of tve variable
0687      *  @return status code
0688      */
0689     StatusCode column( std::string_view name, signed char value ) {
0690       return column( name, value, std::numeric_limits<signed char>::min(), std::numeric_limits<signed char>::max() );
0691     }
0692     // ========================================================================
0693   public:
0694     // ========================================================================
0695     /** Set the value for selected tuple column.
0696      *  If the column does not exist yet, it will be
0697      *  automatically create and appended to the tuple
0698      *
0699      *  @code
0700      *
0701      *  tuple->column( "empty" , v.empty()  );
0702      *
0703      *  @endcode
0704      *
0705      *  @param name   the name of the column
0706      *  @param value  the value of the variable
0707      *  @return status code
0708      */
0709     StatusCode column( std::string_view name, bool value );
0710     // ========================================================================
0711   public:
0712     // ========================================================================
0713     /** Put IOpaqueAddress in POOL-based NTuple.
0714      *  If the column does not exist,
0715      *  it will be automatically created
0716      *  and appended to the tuple.
0717      *
0718      *  @code
0719      *
0720      *  IOpaqueAddress* address  = ... ;
0721      *  tuple->column( "Address", address );
0722      *
0723      *  @endcode
0724      *  @warning It has sense only for Event tag collection N-Tuples
0725      *
0726      *  @param name name of the column
0727      *                       ("Address" is a recommended convention!)
0728      *  @param address IOpaqueAddress
0729      *  @return status code
0730      */
0731     StatusCode column( std::string_view name, IOpaqueAddress* address );
0732     // ========================================================================
0733     /** Put IOpaqueAddress in NTuple.
0734      *  If the column does not exist,
0735      *  it will be automatically created and appended to the tuple.
0736      *  The column name is set to be <c>"Address"</c>
0737      *
0738      *  @code
0739      *
0740      *  IOpaqueAddress* address  = ... ;
0741      *  tuple->column ( address  );
0742      *
0743      *  @endcode
0744      *  @warning It has sense only for Event tag collection N-Tuples
0745      *
0746      *  @param address IOpaqueAddress
0747      *  @return status code
0748      */
0749     StatusCode column( IOpaqueAddress* address );
0750     // ========================================================================
0751   public:
0752     // ========================================================================
0753     /** Set the values for several columns simultaneously, for the same object
0754      *  Non-existing columns will be automatically created
0755      *  and appended to the ntuple.
0756      *
0757      *  @code
0758      *
0759      *  Gaudi::XYZPoint p;
0760      *  tuple->columns( p, std::pair{ "X", &Gaudi::XYZPoint::X},
0761      *                     std::pair{ "Y", &Gaudi::XYZPoint::Y},
0762      *                     std::pair{ "Z", &Gaudi::XYZPoint::Z} );
0763      *
0764      *  @endcode
0765      *
0766      *  @warning the type of column is set (implicitly) by the type returned by the 'callable'
0767      *           for that column, i.e. in the above the return type of eg. `Gaudi::XYZPoint::X()`
0768      *
0769      *  @author Gerhard Raven
0770      */
0771 
0772     template <typename Value, typename... Args>
0773     StatusCode columns( Value&& value, Args&&... args ) {
0774       if ( sizeof...( Args ) == 0 ) return StatusCode::SUCCESS;
0775       std::initializer_list<StatusCode> scs{
0776           this->column( std::get<0>( args ), std::invoke( std::get<1>( args ), value ) )... };
0777       return std::accumulate( std::next( begin( scs ) ), end( scs ), *begin( scs ),
0778                               []( StatusCode sc, const StatusCode& i ) {
0779                                 i.ignore();                     // make sure there are no unchecked StatusCodes...
0780                                 return sc.isFailure() ? sc : i; // latch to the first non-success case
0781                               } );
0782     }
0783     // ========================================================================
0784   public:
0785     // ========================================================================
0786     /** Set the values for several columns simultaneously.
0787      *  Number of columns is arbitrary, but it should match
0788      *  the number of blank, or comma, or semi-column separated tags
0789      *  in <tt>format</tt> string.
0790      *  Non-existing columns will be automatically created
0791      *  and appended to the ntuple.
0792      *
0793      *  @code
0794      *
0795      *  double r1 , r2 , r3 , r4 , mass , length ;
0796      *  tuple->fill( "var1 var2, radius  rad4 mass  len" ,
0797      *                r1,  r2,   r3,     r4,  mass, length);
0798      *
0799      *  @endcode
0800      *
0801      *  @param format blank-separated list of variables,
0802      *          followed by variable number of arguments.
0803      *  @author Vanya Belyaev Ivan.Belyaev@itep.ru
0804      *  @date 2002-10-30
0805      */
0806     template <typename Arg, typename... Args>
0807     StatusCode fill( std::string_view fmt, Arg arg, Args... args ) {
0808       constexpr auto separators = " ,;";
0809       // split into token, and remainder
0810       auto token = fmt.substr( 0, fmt.find_first_of( separators ) );
0811       fmt.remove_prefix( std::min( token.size() + 1, fmt.size() ) );
0812 
0813       if ( !token.empty() ) {
0814         // check the underlying tuple
0815         if ( invalid() ) return ErrorCodes::InvalidTuple;
0816         return column( token, arg ).andThen( [&] {
0817           if constexpr ( sizeof...( Args ) != 0 ) { return fill( fmt, args... ); }
0818           // no more args to deal with -- so check that there is nothing usefull left in fmt, and if so, call it a
0819           // success...
0820           if ( fmt.find_first_not_of( separators ) != std::string_view::npos )
0821             throw std::runtime_error{ "TupleObj::fill: bad format -- too few arguments for specified format" };
0822           return StatusCode{ StatusCode::SUCCESS };
0823         } );
0824       } else if ( !fmt.empty() ) {
0825         // got a separator at the front of fmt -- try again now that it is removed from fmt...
0826         return fill( fmt, arg, args... );
0827       } else {
0828         // empty token, and nothing left in fmt -- but we still where called with (at least) one argument...
0829         throw std::runtime_error{ "TupleObj::fill: bad format -- too many arguments for specified format" };
0830         return StatusCode::SUCCESS;
0831       }
0832     }
0833 
0834     // =======================================================================
0835   public:
0836     // =======================================================================
0837     /** Add an indexed array (of type float) to N-tuple.
0838      *  The method is not VERY efficient since it copies the data.
0839      *
0840      *  @code
0841      *
0842      *   std::vector<double> values  = ... ;
0843      *
0844      *   tuple->farray( "Values"        ,  // item name
0845      *                  values.begin () ,  // begin of sequence
0846      *                  values.end   () ,  // end of sequence
0847      *                  "Length"        ,  // name of "length" item
0848      *                  10000           ) ;
0849      *
0850      *  @endcode
0851      *
0852      *  The name of "length" item can be reused for several arrays.
0853      *  The last assignement "wins"
0854      *
0855      *   @code
0856      *
0857      *   std::vector<double> val1 = ... ;
0858      *   std::vector<double> val2 = ... ;
0859      *
0860      *   tuple->farray( "Val1"          ,   // item name
0861      *                   val1.begin  () ,   // begin of sequence
0862      *                   val1.end    () ,   // end of sequence
0863      *                  "Length"        ,   // name of "length" item
0864      *                  10000           ) ; // maximal length
0865      *
0866      *   tuple->farray( "Val2"          ,   // item name
0867      *                   val2.begin  () ,   // begin of sequence
0868      *                   val2.end    () ,   // end of sequence
0869      *                  "Length"        ,   // name of "length" item
0870      *                  10000           ) ; // maximal length
0871      *
0872      *  @endcode
0873      *
0874      *  Any sequence <tt>[first:last[</tt> of objects
0875      *  which can be converted to type <tt>float</tt> can
0876      *  be used as input data, e.g. <tt>std::vector<double></tt>,
0877      *     <tt>std::vector<float></tt>, plain C-array, or whatever else
0878      *
0879      *  @param name   name of N-tuple item
0880      *  @param first  begin of data sequence
0881      *  @param last   end of data sequence
0882      *  @param length name of "length" item
0883      *  @param maxv   maximal length of array
0884      */
0885     template <typename ITERATOR1, typename ITERATOR2>
0886     StatusCode farray( std::string_view name, ITERATOR1&& first, ITERATOR2&& last, std::string_view length,
0887                        size_t maxv ) {
0888       return farray( name, detail::to_float, std::forward<ITERATOR1>( first ), std::forward<ITERATOR2>( last ), length,
0889                      maxv );
0890     }
0891     // =======================================================================
0892     /** Add an indexed array (of type float) to N-tuple.
0893      *  it is just a small adaptor for the previous method
0894      *
0895      *  @code
0896      *
0897      *   std::vector<double> values  = ... ;
0898      *
0899      *   tuple->farray( "Values"        ,  // item name
0900      *                  values          ,  // sequence
0901      *                  "Length"        ,  // name of "length" item
0902      *                  10000           ) ;
0903      *
0904      *  @endcode
0905      *
0906      *  The name of "length" item can be reused for several arrays.
0907      *  The last assignment "wins"
0908      *
0909      *   @code
0910      *
0911      *   std::vector<double> val1 = ... ;
0912      *   std::vector<double> val2 = ... ;
0913      *
0914      *   tuple->farray( "Val1"          ,   // item name
0915      *                   val1           ,   // begin of sequence
0916      *                  "Length"        ,   // name of "length" item
0917      *                  10000           ) ; // maximal length
0918      *
0919      *   tuple->farray( "Val2"          ,   // item name
0920      *                   val2           ,   // begin of sequence
0921      *                  "Length"        ,   // name of "length" item
0922      *                  10000           ) ; // maximal length
0923      *
0924      *  @endcode
0925      *
0926      *  Any sequence which provides  <tt>begin()</tt> and
0927      *  <tt>end()</tt> methods can be used.
0928      *
0929      *  @param name   name of N-tuple item
0930      *  @param data   data sequence
0931      *  @param length name of "length" item
0932      *  @param maxv   maximal length of array
0933      */
0934     template <class DATA>
0935     StatusCode farray( std::string_view name, const DATA& data, std::string_view length, const size_t maxv ) {
0936       return farray( name, std::begin( data ), std::end( data ), length, maxv );
0937     }
0938     // =======================================================================
0939     /** Put an indexed array into LoKi-style N-Tuple
0940      *
0941      *  @code
0942      *
0943      *  std::vector<double> data = ... ;
0944      *
0945      *  Tuple tuple = ntuple( "My Ntuple" );
0946      *
0947      *  tuple->farray( "data"         ,   // data item name
0948      *                  sqrt          ,   // "function" to be applied
0949      *                  data.begin () ,   // begin of data sequence
0950      *                  data.end   () ,   // end of data sequence
0951      *                  "length"      ,   // name of "length" tuple item
0952      *                  10000         ) ; // maximal array length
0953      *
0954      *  @endcode
0955      *
0956      *  Since the method is templated, one can use arbitrary
0957      *  combinations of "sequences" and "functions", e.g. one can
0958      *  directly manipulate with complex objects.
0959      *  The only one thing is required - the result of
0960      *   <tt>FUNCTION(*DATA)</tt>  formal operation
0961      *  MUST be convertible to type <tt>float</tt>
0962      *
0963      *  @code
0964      *
0965      *  // some container of particles.
0966      *  ParticleVector particles = ... ;
0967      *
0968      *  Tuple tuple = ntuple( "My Ntuple" );
0969      *
0970      *  // put the transverse momentum of all particles into N-Tuple
0971      *  tuple->farray( "pt"                , // data item name
0972      *                  PT                 , // function object
0973      *                  particles.begin () , // begin of data sequence
0974      *                  particles.end   () , // end of data sequence
0975      *                  "num"              ,   // name of "length" tuple item
0976      *                  10000              ) ; // maximal array length
0977      *
0978      *
0979      *  // create the appropriate function object
0980      *  Fun fun =  Q / P ;
0981      *
0982      *  // put Q/P of all particles into N-Tuple
0983      *  tuple->farray( "qp"                , // data item name
0984      *                  fun                , // function object
0985      *                  particles.begin () , // begin of data sequence
0986      *                  particles.end   () , // end of data sequence
0987      *                  "num"              ,   // name of "length" tuple item
0988      *                  10000              ) ; // maximal array length
0989      *
0990      *
0991      *  @endcode
0992      *
0993      *  @param name     tuple item name
0994      *  @param function function to be applied
0995      *  @param first    begin of data sequence
0996      *  @param last     end of data sequence
0997      *  @param length   name of "length" tuple name
0998      *  @param maxv     maximal length of the array
0999      *  @return status code
1000      */
1001     template <class FUNCTION, class ITERATOR>
1002     StatusCode farray( std::string_view name, const FUNCTION& function, ITERATOR first, ITERATOR last,
1003                        std::string_view length, size_t maxv ) {
1004       if ( invalid() ) return ErrorCodes::InvalidTuple;
1005       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1006 
1007       // adjust the length
1008       if ( std::distance( first, last ) > static_cast<std::ptrdiff_t>( maxv ) ) {
1009         Warning( fmt::format( "farray('{}'): array is overflow, skip extra entries", name ) )
1010             .ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
1011         last = std::next( first, maxv );
1012       }
1013 
1014       // get the length item
1015       Int* len = ints( length, 0, maxv );
1016       if ( !len ) return ErrorCodes::InvalidColumn;
1017 
1018       // adjust the length
1019       *len = std::distance( first, last );
1020 
1021       // get the array itself
1022       FArray* var = fArray( name, len );
1023       if ( !var ) return ErrorCodes::InvalidColumn;
1024 
1025       // fill the array
1026       std::transform( first, last, std::begin( *var ),
1027                       [&]( auto&& i ) { return std::invoke( function, std::forward<decltype( i )>( i ) ); } );
1028 
1029       return StatusCode::SUCCESS;
1030     }
1031     // =======================================================================
1032     /** Put arbitrary number of functions from one data array  into LoKi-style N-Tuple
1033      *  simultaneously (effective!)
1034      *
1035      *  @code
1036      *
1037      *  std::vector<double> data = ... ;
1038      *
1039      *  Tuple tuple = ntuple( "My Ntuple" );
1040      *
1041      *  tuple->farray( { { "sqrt", sqrt },     // name of 1st column, and function to use for it
1042      *                   { "sinus", sin } },   // name of the 2nd column, and corresponding function
1043      *                  data.begin () ,   // begin of data sequence
1044      *                  data.end   () ,   // end of data sequence
1045      *                  "length"      ,   // name of "length" tuple item
1046      *                  10000         ) ; // maximal array length
1047      *
1048      *  @endcode
1049      *
1050      *
1051      *  @param items    vector of pairs { name, callable }
1052      *  @param first    begin of data sequence
1053      *  @param last     end of data sequence
1054      *  @param length   name of "length" tuple name
1055      *  @param maxv     maximal length of the array
1056      *  @return status code
1057      */
1058 
1059     template <typename FunIterator, typename DataIterator>
1060     StatusCode farray_impl( FunIterator first_item, FunIterator last_item, DataIterator first, DataIterator last,
1061                             std::string_view length, size_t maxv ) {
1062       if ( invalid() ) return ErrorCodes::InvalidTuple;
1063       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1064 
1065       // adjust the length
1066       if ( std::distance( first, last ) > static_cast<std::ptrdiff_t>( maxv ) ) {
1067         using GaudiUtils::details::ostream_joiner;
1068         std::ostringstream os;
1069         ostream_joiner( os, first_item, last_item, ",",
1070                         []( std::ostream& os, const auto& i ) -> decltype( auto ) { return os << i.first; } );
1071         Warning( "farray('" + os.str() + "'): array overflow, skipping extra entries" ).ignore();
1072         last = std::next( first, maxv );
1073       }
1074 
1075       // get the length item
1076       Int* len = ints( length, 0, maxv );
1077       if ( !len ) return ErrorCodes::InvalidColumn;
1078 
1079       // adjust the length
1080       *len = std::distance( first, last );
1081 
1082       // get the arrays themselves
1083       std::vector<FArray*> vars;
1084       vars.reserve( std::distance( first_item, last_item ) );
1085       std::transform( first_item, last_item, std::back_inserter( vars ),
1086                       [&]( const auto& item ) { return this->fArray( item.first, len ); } );
1087       if ( std::any_of( vars.begin(), vars.end(), []( const FArray* f ) { return !f; } ) ) {
1088         return ErrorCodes::InvalidColumn;
1089       }
1090 
1091       // fill the array
1092       for ( size_t index = 0; first != last; ++first, ++index ) {
1093         auto item = first_item;
1094         for ( auto& var : vars ) { ( *var )[index] = std::invoke( ( item++ )->second, *first ); }
1095       }
1096 
1097       return StatusCode::SUCCESS;
1098     }
1099 
1100     template <
1101         typename DataIterator, template <typename, typename...> class Container = std::initializer_list,
1102         typename NamedFunction = std::pair<std::string_view, std::function<float( detail::const_ref_t<DataIterator> )>>,
1103         typename               = std::enable_if_t<!std::is_convertible_v<Container<NamedFunction>, std::string_view>>>
1104     StatusCode farray( const Container<NamedFunction>& funs, DataIterator first, DataIterator last,
1105                        std::string_view length, size_t maxv ) {
1106       return farray_impl( funs.begin(), funs.end(), std::forward<DataIterator>( first ),
1107                           std::forward<DataIterator>( last ), length, maxv );
1108     }
1109 
1110     template <typename NamedFunctions, typename DataIterator,
1111               typename = std::enable_if_t<!std::is_convertible_v<NamedFunctions, std::string_view>>>
1112     StatusCode farray( const NamedFunctions& funs, DataIterator first, DataIterator last, std::string_view length,
1113                        size_t maxv ) {
1114       return farray_impl( funs.begin(), funs.end(), std::forward<DataIterator>( first ),
1115                           std::forward<DataIterator>( last ), length, maxv );
1116     }
1117     // =======================================================================
1118     /** Put two functions from one data array  into LoKi-style N-Tuple
1119      *  simultaneously (effective!)
1120      *
1121      *  @code
1122      *
1123      *  std::vector<double> data = ... ;
1124      *
1125      *  Tuple tuple = ntuple( "My Ntuple" );
1126      *
1127      *  tuple->farray( "square_root"  ,   // the first data item name
1128      *                  sqrt          ,   // "func1" to be used
1129      *                 "sinus"        ,   // the second data item name
1130      *                  sin           ,   // "func2" to be used
1131      *                  data.begin () ,   // begin of data sequence
1132      *                  data.end   () ,   // end of data sequence
1133      *                  "length"      ,   // name of "length" tuple item
1134      *                  10000         ) ; // maximal array length
1135      *
1136      *  @endcode
1137      *
1138      *
1139      *  @param name1    the first tuple item name
1140      *  @param func1    the first function to be applied
1141      *  @param name2    the second tuple item name
1142      *  @param func2    the second function to be applied
1143      *  @param first    begin of data sequence
1144      *  @param last     end of data sequence
1145      *  @param length   name of "length" tuple name
1146      *  @param maxv     maximal length of the array
1147      *  @return status code
1148      */
1149     template <class FUNC1, class FUNC2, class Iterator>
1150     StatusCode farray( std::string_view name1, const FUNC1& func1, std::string_view name2, const FUNC2& func2,
1151                        Iterator&& first, Iterator&& last, std::string_view length, size_t maxv ) {
1152       return farray( { { name1, std::cref( func1 ) }, { name2, std::cref( func2 ) } }, std::forward<Iterator>( first ),
1153                      std::forward<Iterator>( last ), length, maxv );
1154     }
1155     // =======================================================================
1156     /** Put three functions from one data array  into LoKi-style N-Tuple
1157      *  simultaneously (effective!)
1158      *
1159      *
1160      *  @code
1161      *
1162      *  std::vector<double> data = ... ;
1163      *
1164      *  Tuple tuple = ntuple( "My Ntuple" );
1165      *
1166      *  tuple->farray( "square_root"    ,   // the first data item name
1167      *                  sqrt          ,   // "func1" to be used
1168      *                 "sinus"        ,   // the second data item name
1169      *                  sin           ,   // "func2" to be used
1170      *                 "tan"          ,   // the third data item name
1171      *                  tan           ,   // "func3" to be used
1172      *                  data.begin () ,   // begin of data sequence
1173      *                  data.end   () ,   // end of data sequence
1174      *                  "length"      ,   // name of "length" tuple item
1175      *                  10000         ) ; // maximal array length
1176      *
1177      *  @endcode
1178      *
1179      *
1180      *  @param name1    the first tuple item name
1181      *  @param func1    the first function to be applied
1182      *  @param name2    the second tuple item name
1183      *  @param func2    the second function to be applied
1184      *  @param name3    the third tuple item name
1185      *  @param func3    the third function to be applied
1186      *  @param first    begin of data sequence
1187      *  @param last     end of data sequence
1188      *  @param length   name of "length" tuple name
1189      *  @param maxv     maximal length of the array
1190      *  @return status code
1191      */
1192     template <class FUNC1, class FUNC2, class FUNC3, class Iterator>
1193     StatusCode farray( std::string_view name1, const FUNC1& func1, std::string_view name2, const FUNC2& func2,
1194                        std::string_view name3, const FUNC3& func3, Iterator&& first, Iterator&& last,
1195                        std::string_view length, size_t maxv ) {
1196       return farray( { { name1, std::cref( func1 ) }, { name2, std::cref( func2 ) }, { name3, std::cref( func3 ) } },
1197                      std::forward<Iterator>( first ), std::forward<Iterator>( last ), length, maxv );
1198     }
1199     // =======================================================================
1200     /** Put four functions from one data array  into LoKi-style N-Tuple
1201      *  simultaneously (effective!)
1202      *
1203      *  @code
1204      *
1205      *  std::vector<double>   data = ... ;
1206      *
1207      *  Tuple tuple = ntuple( "My Ntuple" );
1208      *
1209      *  tuple->farray( "square_root"    ,   // the first data item name
1210      *                  sqrt          ,   // "func1" to be used
1211      *                 "sinus"        ,   // the second data item name
1212      *                  sin           ,   // "func2" to be used
1213      *                 "tan"          ,   // the third data item name
1214      *                  tan           ,   // "func3" to be used
1215      *                 "tanh"         ,   //
1216      *                  tanh          ,   //
1217      *                  data.begin () ,   // begin of data sequence
1218      *                  data.end   () ,   // end of data sequence
1219      *                  "length"      ,   // name of "length" tuple item
1220      *                  10000         ) ; // maximal array length
1221      *
1222      *  @endcode
1223      *
1224      *
1225      *  @param name1    the first tuple item name
1226      *  @param func1    the first function to be applied
1227      *  @param name2    the second tuple item name
1228      *  @param func2    the second function to be applied
1229      *  @param name3    the third tuple item name
1230      *  @param func3    the third function to be applied
1231      *  @param name4    the fourth tuple item name
1232      *  @param func4    the fourth function to be applied
1233      *  @param first    begin of data sequence
1234      *  @param last     end of data sequence
1235      *  @param length   name of "length" tuple name
1236      *  @param maxv     maximal length of the array
1237      *  @return status code
1238      */
1239     template <class FUNC1, class FUNC2, class FUNC3, class FUNC4, class Iterator>
1240     StatusCode farray( std::string_view name1, const FUNC1& func1, std::string_view name2, const FUNC2& func2,
1241                        std::string_view name3, const FUNC3& func3, std::string_view name4, const FUNC4& func4,
1242                        Iterator&& first, Iterator&& last, std::string_view length, size_t maxv ) {
1243       return farray( { { name1, std::cref( func1 ) },
1244                        { name2, std::cref( func2 ) },
1245                        { name3, std::cref( func3 ) },
1246                        { name4, std::cref( func4 ) } },
1247                      std::forward<Iterator>( first ), std::forward<Iterator>( last ), length, maxv );
1248     }
1249     // =======================================================================
1250   public:
1251     // =======================================================================
1252     /** Fill N-Tuple with data from variable-size matrix
1253      *
1254      *  "Matrix" could be of any type, which supports
1255      *   data[iRow][iCol] indexing, e.g.
1256      *    - std::vector<std::vector<TYPE> >
1257      *    - CLHEP::HepMatrix, etc...
1258      *
1259      *  @code
1260      *
1261      *   typedef std::vector<double> Row  ;
1262      *   typedef std::vector<Row>    Mtrx ;
1263      *   // number of columns (fixed!)
1264      *   const size_t numCols = 5 ;
1265      *   // maximal number of rows
1266      *   const size_t maxRows = 300 ;
1267      *   // number of rows (variable)
1268      *   size_t numRows =  .... ;
1269      *   ...
1270      *   tuple -> fMatrix ( "mtrx"        , // "column" name
1271      *                      mtrx          , // matrix
1272      *                      numRows       , // number of rows (variable!)
1273      *                      numCols       , // number of columns (fixed)
1274      *                      "Length"      , // name for "length" column
1275      *                      maxRows       ) ; // maximal number of columns
1276      *
1277      *  @endcode
1278      *
1279      *  @code
1280      *
1281      *   CLHEP::HepMatrix mtrx = ... ;
1282      *   ...
1283      *   tuple -> fMatrix ( "mtrx"         , // "column" name
1284      *                      mtrx           , // matrix
1285      *                      mtrx.num_row() , // number of rows (variable!)
1286      *                      mtrx.num_col() , // number of columns (fixed)
1287      *                      "Length"       , // name for "length" column
1288      *                      maxRows        ) ; // maximal number of columns
1289      *
1290      *  @endcode
1291      *
1292      *  @param name   entry name in N-Tuple
1293      *  @param data   matrix itself
1294      *  @param rows   number of rows of matrix (variable)
1295      *  @param cols   number of columns of matrix (fixed)
1296      *  @param length entry name in NTuple for number of matrix column
1297      *  @param maxv   maximal number of rows in matrix
1298      *
1299      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1300      *  @date 2005-05-01
1301      */
1302     template <class MATRIX>
1303     StatusCode fmatrix( std::string_view name, const MATRIX& data, size_t rows, const MIndex& cols,
1304                         std::string_view length, size_t maxv ) {
1305       if ( invalid() ) return ErrorCodes::InvalidTuple;
1306       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1307 
1308       // adjust the length
1309       if ( rows >= maxv ) {
1310         Warning( fmt::format( "fmatrix('{}'): matrix is overflow, skip extra items", name ) ).ignore();
1311         rows = ( 0 < maxv ) ? ( maxv - 1 ) : 0;
1312       }
1313 
1314       // get the length item
1315       Int* len = ints( length, 0, maxv );
1316       if ( !len ) return ErrorCodes::InvalidColumn;
1317 
1318       // adjust the length item
1319       *len = rows;
1320 
1321       // get the array itself
1322       FMatrix* var = fMatrix( name, len, cols );
1323       if ( !var ) return ErrorCodes::InvalidColumn;
1324 
1325       /// fill the matrix
1326       for ( size_t iCol = 0; iCol < cols; ++iCol ) {
1327         for ( MIndex iRow = 0; iRow < rows; ++iRow ) { ( *var )[iRow][iCol] = data[iRow][iCol]; }
1328       }
1329 
1330       return StatusCode::SUCCESS;
1331     }
1332     // =======================================================================
1333     /** Fill N-Tuple with data from variable-size matrix
1334      *
1335      *  "Matrix" could be of any type, which supports
1336      *   iteration from the first column to the last column
1337      *   and for each iterating column supports the indexing:
1338      *    (*first)[iCol]
1339      *
1340      *  @code
1341      *    typedef std::vector<double> Row  ;
1342      *    typedef std::vector<Row>    Mtrx ;
1343      *    // number of rows (fixed!)
1344      *    const size_t numRows = 5 ;
1345      *    // maximal number of columns
1346      *    const size_t maxCols = 300 ;
1347      *    // number of columns (variable)
1348      *    size_t numCols =  .... ;
1349      *    ...
1350      *    tuple -> fMatrix ( "mtrx"         , // entry name
1351      *                        mtrx.begin()  , // first row of matrix
1352      *                        mtrx.end  ()  , // last  row of matrix
1353      *                        numCols       , // number of columns (fixed!)
1354      *                        "Length"      , // name for "length" column
1355      *                        maxRows       ) ; // maximal number of rows
1356      *
1357      *  @endcode
1358      *
1359      *  @param name  entry name in N-Tuple
1360      *  @param first iterator for the first row of matrix
1361      *  @param last  iterator for the last  row of matrix
1362      *  @param cols  number of columns for matrix (fixed!)
1363      *  @param length entry name in NTuple for number of matrix column
1364      *  @param maxv maximal number of rows in matrix
1365      *
1366      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1367      *  @date 2005-05-01
1368      */
1369     template <class DATA>
1370     StatusCode fmatrix( std::string_view name, DATA first, DATA last, const MIndex& cols, std::string_view length,
1371                         size_t maxv ) {
1372       if ( invalid() ) return ErrorCodes::InvalidTuple;
1373       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1374 
1375       // adjust the length
1376       if ( first + maxv < last ) {
1377         Warning( fmt::format( "fmatrix('{}'): matrix is overflow, skip extra items", name ) ).ignore();
1378         last = first + maxv;
1379       }
1380 
1381       // get the length item
1382       Int* len = ints( length, 0, maxv );
1383       if ( !len ) return ErrorCodes::InvalidColumn;
1384 
1385       // adjust the length item
1386       *len = last - first;
1387 
1388       // get the array itself
1389       FMatrix* var = fMatrix( name, len, cols );
1390       if ( !var ) return ErrorCodes::InvalidColumn;
1391 
1392       /// fill the matrix
1393       size_t iRow = 0;
1394       for ( ; first != last; ++first ) {
1395         //
1396         for ( MIndex iCol = 0; iCol < cols; ++iCol ) { ( *var )[iRow][iCol] = ( *first )[iCol]; }
1397         //
1398         ++iRow;
1399       }
1400 
1401       return StatusCode::SUCCESS;
1402     }
1403     // =======================================================================
1404     /** fill N-Tuple with matrix of "direct-product" of
1405      *  "data-vector"     [first,last) and
1406      *  "function-vector" [funF, funL)
1407      *
1408      *  The elements of effective matrix are:
1409      *
1410      *   mtrx[iCol][iRow] = (*(funF+iRow))( *(first+iCol) )
1411      *
1412      *  @attention
1413      *  The length of data-vector is variable, while
1414      *  the length of "function" vector is fixed!
1415      *
1416      *  @code
1417      *
1418      *    typedef std::vector<double> Array ;
1419      *    Array array  = ... ;
1420      *
1421      *    typedef double (*fun)( double ) ;
1422      *    typedef std::vector<fun>   Funs ;
1423      *
1424      *    Funs funs ;
1425      *    funs.push_back( sin  ) ;
1426      *    funs.push_back( cos  ) ;
1427      *    funs.push_back( tan  ) ;
1428      *    funs.push_back( sinh ) ;
1429      *    funs.push_back( cosh ) ;
1430      *    funs.push_back( tanh ) ;
1431      *
1432      *    tuple->fmatrix ( "mtrx"         , // N-Tuple entry name
1433      *                     funs.begin  () , // begin of "function-vector"
1434      *                     funs.end    () , // end of "function-vector"
1435      *                     array.begin () , // begin of "data-vector"
1436      *                     array.end   () , // end of "data-vector"
1437      *                     "Length"       ,
1438      *                     100            ) ;
1439      *  @endcode
1440      *
1441      *  This method is very convenient e.g. for using within LoKi:
1442      *
1443      *  @code
1444      *
1445      *   typedef std::vector<Fun>  VctFun ;
1446      *
1447      *   // sequence of Particles
1448      *   Range particles = .... ;
1449      *
1450      *   // vector of functions:
1451      *  VctFun funs ;
1452      *  funs.push_back( E  / GeV ) ;
1453      *  funs.push_back( PX / GeV ) ;
1454      *  funs.push_back( PY / GeV ) ;
1455      *  funs.push_back( PZ / GeV ) ;
1456      *  funs.push_back( PT / GeV ) ;
1457      *  funs.push_back( M  / GeV ) ;
1458      *  funs.push_back( ID       ) ;
1459      *
1460      *  // fill N-Tuple with information about each particle
1461      *  tuple -> fmatrix ( "vars"             ,
1462      *                     funs.begin      () ,
1463      *                     funs.end        () ,
1464      *                     particles.begin () ,
1465      *                     particles.end   () ,
1466      *                     "nParts"           ,
1467      *                     200                ) ;
1468      *
1469      *  @endcode
1470      *
1471      *  @param name  entry name in N-Tuple
1472      *  @param funF  "begin"-iterator for vector of functions
1473      *  @param funL  "end"-iterator for vector of functions
1474      *  @param first "begin"-iterator for vector of data
1475      *  @param last  "end"-iterator for vector of data
1476      *  @param length entry name in NTuple for number of matrix column
1477      *  @param maxv maximal number of rows in matrix
1478      *
1479      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1480      *  @date 2005-05-01
1481      */
1482     template <class FUN, class DATA>
1483     StatusCode fmatrix( std::string_view name, FUN funF, FUN funL, DATA first, DATA last, std::string_view length,
1484                         size_t maxv ) {
1485       if ( invalid() ) return ErrorCodes::InvalidTuple;
1486       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1487 
1488       // adjust the length
1489       if ( std::distance( first, last ) > static_cast<std::ptrdiff_t>( maxv ) ) {
1490         Warning( fmt::format( "fmatrix('{}'): matrix is overflow, skip extra items", name ) ).ignore();
1491         last = std::next( first, maxv );
1492       }
1493 
1494       // get the length item
1495       Int* len = ints( length, 0, maxv );
1496 
1497       if ( !len ) return ErrorCodes::InvalidColumn;
1498 
1499       // adjust the length item
1500       *len = std::distance( first, last );
1501 
1502       // get the array itself
1503       auto     cols = std::distance( funF, funL );
1504       FMatrix* var  = fMatrix( name, len, cols );
1505       if ( !var ) return ErrorCodes::InvalidColumn;
1506 
1507       /// fill the matrix
1508       size_t iRow = 0;
1509       for ( ; first != last; ++first ) {
1510         //
1511         for ( FUN fun = funF; fun < funL; ++fun ) { ( *var )[iRow][fun - funF] = std::invoke( *fun, *first ); }
1512         //
1513         ++iRow;
1514       }
1515 
1516       return StatusCode::SUCCESS;
1517     }
1518     // =======================================================================
1519   public:
1520     // =======================================================================
1521     /** fill N-Tuple with fixed-size array
1522      *
1523      *  @code
1524      *
1525      *   SEQUENCE  data( 10 ) ;
1526      *   ...
1527      *   tuple -> array("data"         ,
1528      *                   data.begin () ,
1529      *                   data.end   () ) ;
1530      *
1531      *  @endcode
1532      *
1533      *  Sequence may be of any objects, implicitly
1534      *  convertible into "float"
1535      *
1536      *  @param name N-Tuple entry name
1537      *  @param first begin-iterator for data sequence
1538      *  @param last  end-iterator for data sequence
1539      *
1540      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1541      *  @date 2005-05-01
1542      */
1543     template <class DATA>
1544     StatusCode array( std::string_view name, DATA first, DATA last )
1545 
1546     {
1547       if ( invalid() ) return ErrorCodes::InvalidTuple;
1548       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1549 
1550       // get the length (fixed!)
1551       auto length = std::distance( first, last );
1552 
1553       // get the array itself
1554       FArray* var = fArray( name, length );
1555       if ( !var ) return ErrorCodes::InvalidColumn;
1556 
1557       /// fill the array
1558       std::copy( first, last, std::begin( *var ) );
1559 
1560       return StatusCode::SUCCESS;
1561     }
1562     // =======================================================================
1563     /** fill N-Tuple with fixed-size array
1564      *
1565      *  "ARRAY" must support indexing operations:
1566      *   e.g it coudl be of type:
1567      *   - std::vector<TYPE>
1568      *   - CLHEP::HepVector, ...
1569      *   - "TYPE"[n]
1570      *
1571      *   The content of array should be implicitly
1572      *   convertible to "float"
1573      *
1574      *  @code
1575      *
1576      *  CLHEP::HepVector vct1(10) ;
1577      *  ...
1578      *  tuple -> array ( "vct1" , vct1 , 10 ) ;
1579      *
1580      *  double vct2[40];
1581      *  ...
1582      *  tuple -> array ( "vct2" , vct2 , 40 ) ;
1583      *
1584      *  long   vct3[4];
1585      *  ...
1586      *  tuple -> array ( "vct3" , vct4 ,  4 ) ;
1587      *
1588      *  std::vector<long double> vct4(15) ;
1589      *  ...
1590      *  tuple -> array ( "vct4" , vct4 , 15 ) ;
1591      *
1592      *  @endcode
1593      *
1594      *  @param name    N-Tuple entry name
1595      *  @param data    data sequence
1596      *  @param length  data length (fixed!)
1597      *
1598      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1599      *  @date 2005-05-01
1600      */
1601     template <class ARRAY>
1602     StatusCode array( std::string_view name, const ARRAY& data, const MIndex& length ) {
1603       using std::begin; // allow data to be eg. CLHEP::HepVector (which does not define HepVector::begin()!,
1604                         // in which case ADL prefers CLHEP::begin (yah! at least they (now) use a namespace)
1605                         // so one just to insure  double* CLHEP::begin(CLHEP::HepVector& v) { return &v[0]; }
1606                         // is visible when this function gets instantiated for CLHEP::HepVector...
1607       auto first = begin( data );
1608       return array( name, first, std::next( first, length ) );
1609     }
1610     // =======================================================================
1611     /** fill N-Tuple with fixed-size array
1612      *
1613      *  "ARRAY" is any sequence, which supports
1614      *   ARRAY::begin() and ARRAY::end() protocol, e.g.
1615      *
1616      *   - std::vector<TYPE>
1617      *   - ROOT::Math::SVector<double,15>
1618      *
1619      *  The content of array should be implicitly
1620      *  convertible to "float"
1621      *
1622      *  @code
1623      *
1624      *   typedef std::vector<double> Seq ;
1625      *   Seq data( 10 ) ;
1626      *   for ( int i = 0 ; i < 10 ; ++i )
1627      *    {
1628      *      data[i] = ... ;
1629      *    }
1630      *
1631      *  tuple -> array( "data" , data ) ;
1632      *
1633      *  @endcode
1634      *
1635      *  @param name N-Tupel entry name
1636      *  @param data  data sequence
1637      *
1638      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1639      *  @date 2005-05-01
1640      */
1641     template <class ARRAY>
1642     StatusCode array( std::string_view name, const ARRAY& data ) {
1643       using std::begin;
1644       using std::end;
1645       return array( name, begin( data ), end( data ) );
1646     }
1647     // =======================================================================
1648   public:
1649     // =======================================================================
1650     /** fill N-Tuple with fixed-size matrix
1651      *
1652      *  "MATRIX" must support indexing operations:
1653      *    data[iRow][iCol]
1654      *
1655      *   e.g it could be of type:
1656      *   - std::vector<std::vector<TYPE> >
1657      *   - CLHEP::HepMatrix , CLHEP::GenMatrix, etc ...
1658      *   - "TYPE"[n][m]
1659      *
1660      *  The content of MATRIX should be implicitly convertible
1661      *  to "float"
1662      *
1663      *  @code
1664      *
1665      *   CLHEP::HepMatrix mtrx1(3,20) ;
1666      *   ...
1667      *   tuple -> matrix ( "m1"             ,
1668      *                      mtrx1           ,
1669      *                      mtrx1.num_row() ,
1670      *                      mtrx1.num_col() ) ;
1671      *
1672      *   typedef std::vector<double> Row  ;
1673      *   typedef std:vector<Row>     Mtrx ;
1674      *   Mtrx mtrx2( 3 , Row(10) ) ;
1675      *   ...
1676      *   tuple -> matrix ( "m2"   ,
1677      *                      mtrx2 ,
1678      *                      3     ,
1679      *                      10    ) ;
1680      *
1681      *   float mtrx3[3][10] ;
1682      *   ...
1683      *   tuple -> matrix ( "m3"   ,
1684      *                      mtrx3 ,
1685      *                      3     ,
1686      *                      10    ) ;
1687      *
1688      *  @endcode
1689      *
1690      *  @param name N-Tuple entry name
1691      *  @param data data source (matrix)
1692      *  @param cols number of columns
1693      *  @param rows number of rows
1694      *
1695      *  @author Vanya BELYAEV Ivan.Belyaev@lapp.in2p3.fr
1696      *  @date 2005-05-01
1697      */
1698     template <class MATRIX>
1699     StatusCode matrix( std::string_view name, const MATRIX& data, const MIndex& rows, const MIndex& cols ) {
1700       if ( invalid() ) return ErrorCodes::InvalidTuple;
1701       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1702 
1703       // get the matrix itself
1704       FMatrix* var = fMatrix( name, rows, cols );
1705       if ( !var ) return ErrorCodes::InvalidColumn;
1706 
1707       /// fill the matrix
1708       for ( size_t iCol = 0; iCol < cols; ++iCol ) {
1709         for ( size_t iRow = 0; iRow < rows; ++iRow ) { ( *var )[iRow][iCol] = data[iRow][iCol]; }
1710       };
1711       return StatusCode::SUCCESS;
1712     }
1713     // =======================================================================
1714   public:
1715     // =======================================================================
1716     /** Useful shortcut to put LorentzVector directly into N-Tuple:
1717      *
1718      *  @code
1719      *
1720      *  const LHCb::Particle* B = ...
1721      *
1722      *  Tuple tuple = nTuple("My N-Tuple") ;
1723      *
1724      *  // put 4-vector of B-candidate into N-tuple:
1725      *  tuple -> column ("B" , B->momentum() ) ;
1726      *
1727      *  @endcode
1728      *
1729      *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
1730      *  @date 2006-11-26
1731      */
1732     template <class TYPE>
1733     StatusCode column( std::string_view name, const ROOT::Math::LorentzVector<TYPE>& v ) {
1734       return columns( v, std::pair{ fmt::format( "{}E", name ), &ROOT::Math::LorentzVector<TYPE>::E },
1735                       std::pair{ fmt::format( "{}X", name ), &ROOT::Math::LorentzVector<TYPE>::Px },
1736                       std::pair{ fmt::format( "{}Y", name ), &ROOT::Math::LorentzVector<TYPE>::Py },
1737                       std::pair{ fmt::format( "{}Z", name ), &ROOT::Math::LorentzVector<TYPE>::Pz } );
1738     }
1739     // =======================================================================
1740     /** Useful shortcut to put 3D-Vector directly into N-Tuple:
1741      *
1742      *  @code
1743      *
1744      *  const LHCb::Vertex* V = ...
1745      *
1746      *  Tuple tuple = nTuple("My N-Tuple") ;
1747      *
1748      *  // put vertex position into N-tuple:
1749      *  tuple -> column ("B" , B->position() ) ;
1750      *
1751      *  @endcode
1752      *
1753      *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
1754      *  @date 2006-11-26
1755      */
1756     template <class TYPE, class TAG>
1757     StatusCode column( std::string_view name, const ROOT::Math::DisplacementVector3D<TYPE, TAG>& v ) {
1758       return this->columns( v, std::pair{ fmt::format( "{}X", name ), &ROOT::Math::DisplacementVector3D<TYPE, TAG>::X },
1759                             std::pair{ fmt::format( "{}Y", name ), &ROOT::Math::DisplacementVector3D<TYPE, TAG>::Y },
1760                             std::pair{ fmt::format( "{}Z", name ), &ROOT::Math::DisplacementVector3D<TYPE, TAG>::Z } );
1761     }
1762     // =======================================================================
1763     /** Useful shortcut to put 3D-Vector directly into N-Tuple:
1764      *
1765      *  @code
1766      *
1767      *  const LHCb::Vertex* V = ...
1768      *
1769      *  Tuple tuple = nTuple("My N-Tuple") ;
1770      *
1771      *  // put vertex position into N-tuple:
1772      *  tuple -> column ("B" , B->position() ) ;
1773      *
1774      *  @endcode
1775      *
1776      *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
1777      *  @date 2006-11-26
1778      */
1779     template <class TYPE, class TAG>
1780     StatusCode column( std::string_view name, const ROOT::Math::PositionVector3D<TYPE, TAG>& v ) {
1781       return this->columns( v, std::pair{ fmt::format( "{}X", name ), &ROOT::Math::PositionVector3D<TYPE, TAG>::X },
1782                             std::pair{ fmt::format( "{}Y", name ), &ROOT::Math::PositionVector3D<TYPE, TAG>::Y },
1783                             std::pair{ fmt::format( "{}Z", name ), &ROOT::Math::PositionVector3D<TYPE, TAG>::Z } );
1784     }
1785     // =======================================================================
1786     /** shortcut to put Smatrix into N-tuple:
1787      *
1788      *  @code
1789      *  @endcode
1790      *
1791      *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
1792      *  @date 2006-11-26
1793      */
1794     template <class TYPE, unsigned int D1, unsigned int D2, class REP>
1795     StatusCode matrix( std::string_view name, const ROOT::Math::SMatrix<TYPE, D1, D2, REP>& mtrx ) {
1796       if ( invalid() ) return ErrorCodes::InvalidTuple;
1797       if ( rowWise() ) return ErrorCodes::InvalidOperation;
1798 
1799       // get the matrix itself
1800       FMatrix* var = fMatrix( name, (MIndex)D1, (MIndex)D2 );
1801       if ( !var ) return ErrorCodes::InvalidColumn;
1802 
1803       /// fill the matrix
1804       for ( size_t iCol = 0; iCol < D2; ++iCol ) {
1805         for ( size_t iRow = 0; iRow < D1; ++iRow ) { ( *var )[iRow][iCol] = mtrx( iRow, iCol ); }
1806       };
1807 
1808       return StatusCode::SUCCESS;
1809     }
1810     // =======================================================================
1811     /** shortcut to put "ExtraInfo" fields of major
1812      *  into N-Tuple
1813      *
1814      *  @code
1815      *
1816      *  const LHCb::Particle* B = ...
1817      *
1818      *  Tuple tuple = nTuple("My N-Tuple") ;
1819      *
1820      *  // put the vector into N-Tuple:
1821      *  tuple -> fmatrix ( "Info" , B->extraInfo() , "nInfo" , 100 ) ;
1822      *
1823      *  @endcode
1824      *
1825      *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
1826      *  @date 2006-11-26
1827      */
1828     template <class KEY, class VALUE>
1829     StatusCode fmatrix( std::string_view name, const GaudiUtils::VectorMap<KEY, VALUE>& info, std::string_view length,
1830                         const size_t maxv = 100 ) {
1831       using Info                                                 = std::pair<KEY, VALUE>;
1832       static const std::array<float ( * )( const Info& ), 2> fns = {
1833           { []( const Info& i ) -> float { return i.first; }, []( const Info& i ) -> float { return i.second; } } };
1834       return fmatrix( name, begin( fns ), end( fns ), begin( info ), end( info ), length, maxv );
1835     }
1836     // =======================================================================
1837   public:
1838     // =======================================================================
1839     /** The function allows to add almost arbitrary object into N-tuple
1840      *  @attention it requires POOL persistency
1841      *  @param name column name
1842      *  @param obj  pointer to the object
1843      *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
1844      *  @date 2007-04-08
1845      */
1846     template <class TYPE>
1847     StatusCode put( std::string_view name, const TYPE* obj );
1848     // =======================================================================
1849   public:
1850     // =======================================================================
1851     /** write a record to NTuple
1852      *  @return status code
1853      */
1854     StatusCode write();
1855     // =======================================================================
1856     /// get the name
1857     const std::string& name() const { return m_name; }
1858     // =======================================================================
1859     /** provide the access to underlying Gaudi N-tuple
1860      *  @return pointer to Gaudi N-tuple object
1861      */
1862     const NTuple::Tuple* tuple() const { return m_tuple; }
1863     // =======================================================================
1864     /** provide the access to underlying Gaudi N-tuple
1865      *  @return pointer to Gaudi N-tuple object
1866      */
1867     NTuple::Tuple* tuple() { return m_tuple; }
1868     // =======================================================================
1869     /// accessor to the N-Tuple CLID
1870     const CLID& clid() const { return m_clid; }
1871     // =======================================================================
1872     /// accessor to the N-Tuple type
1873     Tuples::Type type() const { return m_type; }
1874     // =======================================================================
1875     /// column wise NTuple ?
1876     bool columnWise() const { return CLID_ColumnWiseTuple == clid(); }
1877     // =======================================================================
1878     /// row wise NTuple ?
1879     bool rowWise() const { return CLID_RowWiseTuple == clid(); }
1880     // =======================================================================
1881     /// Event collection ?
1882     bool evtColType() const { return Tuples::EVTCOL == type(); }
1883     // =======================================================================
1884     /// valid pointer to tuple ?
1885     bool valid() const { return 0 != tuple(); }
1886     // =======================================================================
1887     /// invalid pointer to tuple ?
1888     bool invalid() const { return !valid(); }
1889     // =======================================================================
1890   public:
1891     // =======================================================================
1892     /** add the item name into the list of known items
1893      *  @param name the name of the item
1894      *  @param type the type of the item
1895      *  @return true if the name is indeed added
1896      */
1897     bool addItem( std::string name, std::string type ) {
1898       return m_items.emplace( std::move( name ), std::move( type ) ).second;
1899     }
1900     // =======================================================================
1901     /** check the uniqueness of the name
1902      *  @param name the name of the item
1903      *  @return true if the name is indeed unique
1904      */
1905     bool goodItem( std::string_view name ) const { return m_items.end() == m_items.find( name ); }
1906     // =======================================================================
1907     /// get the full list of booked items
1908     const ItemMap& items() const { return m_items; }
1909     // =======================================================================
1910   public:
1911     // =======================================================================
1912     virtual StatusCode Error( const std::string& msg, const StatusCode sc = StatusCode::FAILURE ) const = 0;
1913     // =======================================================================
1914     virtual StatusCode Warning( const std::string& msg, const StatusCode sc = StatusCode::FAILURE ) const = 0;
1915     // =======================================================================
1916   private:
1917     // =======================================================================
1918     /// get the column
1919     Int* ints( std::string_view name, int minv, int maxv );
1920     // =======================================================================
1921     /// get the column
1922     FArray* fArray( std::string_view name, Int* item );
1923     // =======================================================================
1924     /// get the column
1925     FArray* fArray( std::string_view name, const MIndex& rows );
1926     // =======================================================================
1927     /// get the column
1928     Address* addresses( std::string_view name );
1929     // =======================================================================
1930     /// get the column
1931     FMatrix* fMatrix( std::string_view name, Int* item, const MIndex& cols );
1932     // =======================================================================
1933     /// get the column
1934     FMatrix* fMatrix( std::string_view name, const MIndex& rows, const MIndex& cols );
1935     // =======================================================================
1936     /// delete the copy constructor and assignment
1937     TupleObj( const TupleObj& )            = delete;
1938     TupleObj& operator=( const TupleObj& ) = delete;
1939     // =======================================================================
1940   private:
1941     // =======================================================================
1942     /// name
1943     std::string m_name;
1944     // =======================================================================
1945     /// tuple itself
1946     NTuple::Tuple* m_tuple;
1947     // =======================================================================
1948     /// tuple CLID
1949     CLID m_clid;
1950     // =======================================================================
1951     /// tuple 'type'
1952     Tuples::Type m_type;
1953     // =======================================================================
1954     /// reference counter
1955     size_t m_refCount = 0;
1956     // =======================================================================
1957     // helper type to define the actual storage types
1958     template <typename T>
1959     class ColumnStorage {
1960       std::unordered_map<std::string_view, std::pair<T, std::string>> m_map;
1961 
1962     public:
1963       using element_type = T;
1964       T* find( std::string_view sv ) {
1965         auto i = m_map.find( sv );
1966         return i != m_map.end() ? &i->second.first : nullptr;
1967       }
1968       T*                  end() { return nullptr; }
1969       std::pair<T*, bool> emplace( std::string_view k, T v = T{} ) {
1970         // tricky way to insert a string_view key which points to the
1971         // string contained in the mapped type... all just to make find(string_view) work in C++17...
1972         auto [i, b] = m_map.try_emplace( k, std::move( v ), std::string{ k } );
1973         if ( !b ) return { static_cast<T*>( nullptr ), false };
1974         auto nh  = m_map.extract( i );
1975         nh.key() = nh.mapped().second; // "re-point" key to the string contained value_type
1976         auto r   = m_map.insert( std::move( nh ) );
1977         return { &r.position->second.first, r.inserted };
1978       }
1979     };
1980 
1981     // =======================================================================
1982     /// the actual storage of all 'bool' columns
1983     mutable ColumnStorage<Bool> m_bools;
1984     // =======================================================================
1985     /// the actual storage of all 'Int' columns
1986     mutable ColumnStorage<Char> m_chars;
1987     // =======================================================================
1988     /// the actual storage of all 'unsigned int' columns
1989     mutable ColumnStorage<UChar> m_uchars;
1990     // =======================================================================
1991     /// the actual storage of all 'Int' columns
1992     mutable ColumnStorage<Short> m_shorts;
1993     // =======================================================================
1994     /// the actual storage of all 'unsigned int' columns
1995     mutable ColumnStorage<UShort> m_ushorts;
1996     // =======================================================================
1997     /// the actual storage of all 'Int' columns
1998     mutable ColumnStorage<Int> m_ints;
1999     // =======================================================================
2000     /// the actual storage of all 'unsigned int' columns
2001     mutable ColumnStorage<UInt> m_uints;
2002     // =======================================================================
2003     /// the actual storage of all 'long long' columns
2004     mutable ColumnStorage<LongLong> m_longlongs;
2005     // =======================================================================
2006     /// the actual storage of all 'unsigned long long' columns
2007     mutable ColumnStorage<ULongLong> m_ulonglongs;
2008     // =======================================================================
2009     /// the actual storage of all 'Float'   columns
2010     mutable ColumnStorage<Float> m_floats;
2011     // =======================================================================
2012     /// the actual storage of all 'Double'   columns
2013     mutable ColumnStorage<Double> m_doubles;
2014     // =======================================================================
2015     /// the actual storage of all 'Address' columns
2016     mutable ColumnStorage<Address> m_addresses;
2017     // =======================================================================
2018     /// the actual storage of all 'FArray'  columns
2019     mutable ColumnStorage<FArray> m_farrays;
2020     // =======================================================================
2021     /// the actual storage of all 'FArray'  columns (fixed)
2022     mutable ColumnStorage<FArray> m_arraysf;
2023     // =======================================================================
2024     /// the actual storage of all 'FArray'  columns
2025     mutable ColumnStorage<FMatrix> m_fmatrices;
2026     // =======================================================================
2027     /// the actual storage of all 'FMatrix' columns (fixed)
2028     mutable ColumnStorage<FMatrix> m_matricesf;
2029     // =======================================================================
2030     /// all booked types:
2031     ItemMap m_items;
2032     // =======================================================================
2033   };
2034   // ==========================================================================
2035 } // end of namespace Tuples
2036 
2037 // ============================================================================
2038 // GaudiAlg
2039 // ============================================================================
2040 #include "GaudiAlg/TuplePut.h"
2041 // ============================================================================
2042 // The END
2043 // ============================================================================
2044 #endif // GAUDIALG_TUPLEOBJ_H