Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-14 09:23:38

0001 // @(#)root/io:$Id$
0002 // Author: Markus Frank  28/10/04
0003 
0004 /*************************************************************************
0005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
0006  * All rights reserved.                                                  *
0007  *                                                                       *
0008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0010  *************************************************************************/
0011 #ifndef ROOT_TEmulatedCollectionProxy
0012 #define ROOT_TEmulatedCollectionProxy
0013 
0014 #include "TGenCollectionProxy.h"
0015 #include "ROOT/RAlignmentUtils.hxx"
0016 
0017 #include <type_traits>
0018 #include <vector>
0019 
0020 class TEmulatedCollectionProxy : public TGenCollectionProxy  {
0021 
0022    // Friend declaration
0023    friend class TCollectionProxy;
0024 
0025 public:
0026    /// Storage type whose alignment matches \a Align bytes.
0027    /// Used to instantiate std::vector specializations with guaranteed buffer alignment.
0028    template <std::size_t Align>
0029    struct alignas(Align) AlignedStorage {
0030       char data[Align] = {};
0031    };
0032 
0033    // Convenience vector aliases for each supported alignment.
0034    using Cont1_t    = std::vector<AlignedStorage<   1>>;
0035    using Cont2_t    = std::vector<AlignedStorage<   2>>;
0036    using Cont4_t    = std::vector<AlignedStorage<   4>>;
0037    using Cont8_t    = std::vector<AlignedStorage<   8>>;
0038    using Cont16_t   = std::vector<AlignedStorage<  16>>;
0039    using Cont32_t   = std::vector<AlignedStorage<  32>>;
0040    using Cont64_t   = std::vector<AlignedStorage<  64>>;
0041    using Cont128_t  = std::vector<AlignedStorage< 128>>;
0042    using Cont256_t  = std::vector<AlignedStorage< 256>>;
0043    using Cont512_t  = std::vector<AlignedStorage< 512>>;
0044    using Cont1024_t = std::vector<AlignedStorage<1024>>;
0045    using Cont2048_t = std::vector<AlignedStorage<2048>>;
0046    using Cont4096_t = std::vector<AlignedStorage<4096>>;
0047 
0048    // Canonical container type (used for sizeof/typeid; actual alignment is
0049    // selected at runtime via the alignment switch in each method).
0050    using Cont_t  = std::vector<char>;
0051    using PCont_t = Cont_t *;
0052 
0053    /// Invoke \a fn(typed_ptr, elemSize) where typed_ptr is the container
0054    /// pointer cast to the correct AlignedStorage<N>* for the value class
0055    /// alignment.  \a fn receives the element size (N) as a second argument
0056    /// so it can convert byte counts to element counts.
0057    template <typename F>
0058    void WithCont(void *obj, F &&fn) const
0059    {
0060       auto *vcl = GetValueClass();
0061       std::size_t align = alignof(std::max_align_t);
0062       if (!fKey && (fVal->fCase & kIsPointer)) {
0063          // If the collection contains pointers, we need to use the alignment of a pointer, not of the value class.
0064          align = alignof(void*);
0065       } else if (vcl) {
0066          assert(ROOT::Internal::IsValidAlignment(vcl->GetClassAlignment()));
0067          align = vcl->GetClassAlignment();
0068       } else {
0069          switch( int(fVal->fKind) ) {
0070             case kChar_t:
0071             case kUChar_t:  align = alignof(char); break;
0072             case kShort_t:
0073             case kUShort_t: align = alignof(short); break;
0074             case kInt_t:
0075             case kUInt_t:   align = alignof(int); break;
0076             case kLong_t:
0077             case kULong_t:  align = alignof(long); break;
0078             case kLong64_t:
0079             case kULong64_t:align = alignof(long long); break;
0080             case kFloat16_t:
0081             case kFloat_t:  align = alignof(float); break;
0082             case kDouble32_t:
0083             case kDouble_t: align = alignof(double); break;
0084             default:
0085                Fatal("TEmulatedCollectionProxy::WithCont", "Unsupported value type %d for value class %s", fVal->fKind,
0086                      vcl ? vcl->GetName() : "<unknown>");
0087          }
0088       }
0089       switch (align) {
0090          // When adding new cases here, also update the static_assert in TClingUtils.cxx
0091          // to explicitly allow the new alignment and to update the error message accordingly.
0092          case 4096: fn(reinterpret_cast<Cont4096_t*>(obj), std::size_t(4096)); break;
0093          case 2048: fn(reinterpret_cast<Cont2048_t*>(obj), std::size_t(2048)); break;
0094          case 1024: fn(reinterpret_cast<Cont1024_t*>(obj), std::size_t(1024)); break;
0095          case  512: fn(reinterpret_cast<Cont512_t *>(obj), std::size_t( 512)); break;
0096          case  256: fn(reinterpret_cast<Cont256_t *>(obj), std::size_t( 256)); break;
0097          case  128: fn(reinterpret_cast<Cont128_t *>(obj), std::size_t( 128)); break;
0098          case   64: fn(reinterpret_cast<Cont64_t  *>(obj), std::size_t(  64)); break;
0099          case   32: fn(reinterpret_cast<Cont32_t  *>(obj), std::size_t(  32)); break;
0100          case   16: fn(reinterpret_cast<Cont16_t  *>(obj), std::size_t(  16)); break;
0101          case    8: fn(reinterpret_cast<Cont8_t   *>(obj), std::size_t(   8)); break;
0102          case    4: fn(reinterpret_cast<Cont4_t   *>(obj), std::size_t(   4)); break;
0103          case    2: fn(reinterpret_cast<Cont2_t   *>(obj), std::size_t(   2)); break;
0104          case    1: fn(reinterpret_cast<Cont1_t   *>(obj), std::size_t(   1)); break;
0105          default:
0106             Fatal("TEmulatedCollectionProxy::WithCont", "Unsupported alignment %zu for value class %s",
0107                   align, vcl ? vcl->GetName() : "<unknown>");
0108       }
0109    }
0110 protected:
0111 
0112    // Some hack to avoid const-ness
0113    TGenCollectionProxy* InitializeEx(Bool_t silent) override;
0114 
0115    // Object input streamer
0116    void ReadItems(int nElements, TBuffer &b);
0117 
0118    // Object output streamer
0119    void WriteItems(int nElements, TBuffer &b);
0120 
0121    // Shrink the container
0122    void Shrink(UInt_t nCurr, UInt_t left, Bool_t force);
0123 
0124    // Expand the container
0125    void Expand(UInt_t nCurr, UInt_t left);
0126 
0127 private:
0128    TEmulatedCollectionProxy &operator=(const TEmulatedCollectionProxy &); // Not implemented.
0129 
0130 public:
0131    // Virtual copy constructor
0132    TVirtualCollectionProxy* Generate() const override;
0133 
0134    // Copy constructor
0135    TEmulatedCollectionProxy(const TEmulatedCollectionProxy& copy);
0136 
0137    // Initializing constructor
0138    TEmulatedCollectionProxy(const char* cl_name, Bool_t silent);
0139 
0140    // Standard destructor
0141    ~TEmulatedCollectionProxy() override;
0142 
0143    // Virtual constructor
0144    void *New() const override
0145    {
0146       void *mem = ::operator new(sizeof(Cont_t));
0147       WithCont(mem, [](auto *c, std::size_t) { new (c) std::decay_t<decltype(*c)>(); });
0148       return mem;
0149    }
0150 
0151    // Virtual in-place constructor
0152    void *New(void *memory) const override
0153    {
0154       WithCont(memory, [](auto *c, std::size_t) { new (c) std::decay_t<decltype(*c)>(); });
0155       return memory;
0156    }
0157 
0158    // Virtual constructor
0159    TClass::ObjectPtr NewObject() const override { return {New(), nullptr}; }
0160 
0161    // Virtual in-place constructor
0162    TClass::ObjectPtr NewObject(void *memory) const override { return {New(memory), nullptr}; }
0163 
0164    // Virtual array constructor
0165    void *NewArray(Int_t nElements) const override
0166    {
0167       void *arr = ::operator new(nElements * sizeof(Cont_t));
0168       for (Int_t i = 0; i < nElements; ++i)
0169          WithCont(static_cast<char *>(arr) + i * sizeof(Cont_t),
0170                   [](auto *c, std::size_t) { new (c) std::decay_t<decltype(*c)>(); });
0171       return arr;
0172    }
0173 
0174    // Virtual in-place array constructor
0175    void *NewArray(Int_t nElements, void *memory) const override
0176    {
0177       for (Int_t i = 0; i < nElements; ++i)
0178          WithCont(static_cast<char *>(memory) + i * sizeof(Cont_t),
0179                   [](auto *c, std::size_t) { new (c) std::decay_t<decltype(*c)>(); });
0180       return memory;
0181    }
0182 
0183    // Virtual array constructor
0184    TClass::ObjectPtr NewObjectArray(Int_t nElements) const override { return {NewArray(nElements), nullptr}; }
0185 
0186    // Virtual in-place array constructor
0187    TClass::ObjectPtr NewObjectArray(Int_t nElements, void *memory) const override
0188    {
0189       return {NewArray(nElements, memory), nullptr};
0190    }
0191 
0192    // Virtual destructor
0193    void  Destructor(void* p, Bool_t dtorOnly = kFALSE) const override;
0194 
0195    // Virtual array destructor
0196    void  DeleteArray(void* p, Bool_t dtorOnly = kFALSE) const override;
0197 
0198    // TVirtualCollectionProxy overload: Return the sizeof the collection object.
0199    UInt_t Sizeof() const override { return sizeof(Cont_t); }
0200 
0201    // Return the address of the value at index 'idx'
0202    void *At(UInt_t idx) override;
0203 
0204    // Clear the container
0205    void Clear(const char *opt = "") override;
0206 
0207    // Resize the container
0208    void Resize(UInt_t n, Bool_t force_delete) override;
0209 
0210    // Return the current size of the container
0211    UInt_t Size() const override;
0212 
0213    // Block allocation of containees
0214    void* Allocate(UInt_t n, Bool_t forceDelete) override;
0215 
0216    // Block commit of containees
0217    void Commit(void* env) override;
0218 
0219    // Insert data into the container where data is a C-style array of the actual type contained in the collection
0220    // of the given size.   For associative container (map, etc.), the data type is the pair<key,value>.
0221    void  Insert(const void *data, void *container, size_t size) override;
0222 
0223    // Read portion of the streamer
0224    void ReadBuffer(TBuffer &buff, void *pObj) override;
0225    void ReadBuffer(TBuffer &buff, void *pObj, const TClass *onfile) override;
0226 
0227    // Streamer for I/O handling
0228    void Streamer(TBuffer &refBuffer) override;
0229 
0230    // Streamer I/O overload
0231    void Streamer(TBuffer &buff, void *pObj, int siz) override
0232    {
0233       TGenCollectionProxy::Streamer(buff,pObj,siz);
0234    }
0235 
0236    // Check validity of the proxy itself
0237    Bool_t IsValid() const;
0238 };
0239 
0240 
0241 namespace ROOT::Internal::TEmulatedProxyHelpers {
0242 inline void PrintWriteStlWithoutProxyMsg(const char *where, const char *clName, const char *BranchName)
0243 {
0244    const char *writeStlWithoutProxyMsg =
0245       "The class requested (%s) for the branch \"%s\" "
0246       "is an instance of an stl collection and does not have a compiled CollectionProxy. "
0247       "Please generate the dictionary for this collection (%s) to avoid writing corrupted data.";
0248    // This error message is repeated several times in the code. We write it once.
0249    Error(where, writeStlWithoutProxyMsg, clName, BranchName, clName);
0250 }
0251 
0252 inline bool HasEmulatedProxy(TClass *cl){
0253    return cl && cl->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy *>(cl->GetCollectionProxy());
0254 }
0255 } // namespace ROOT::Internal::TEmulatedProxyHelpers
0256 
0257 
0258 #endif