// @(#)root/cont:$Id$ // Author: Philippe Canal 20/08/2010 /************************************************************************* * Copyright (C) 1995-2003, Rene Brun, Fons Rademakers and al. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #ifndef ROOT_TVirtualCollectionIterators #define ROOT_TVirtualCollectionIterators /** \class TVirtualCollectionIterators \ingroup IO Small helper class to generically acquire and release iterators. */ #include "TVirtualCollectionProxy.h" #include "TError.h" #include class TVirtualCollectionIterators { private: TVirtualCollectionIterators() = delete; // Intentionally unimplemented. TVirtualCollectionIterators(const TVirtualCollectionIterators&) = delete; // Intentionally unimplemented. public: // Note when the collection is a vector, fBegin and fEnd points to // the start and end of the memory content rather than to the address // of iterators (saving one dereference when being used). typedef TVirtualCollectionProxy::CreateIterators_t CreateIterators_t; typedef TVirtualCollectionProxy::DeleteTwoIterators_t DeleteTwoIterators_t; char fBeginBuffer[TVirtualCollectionProxy::fgIteratorArenaSize]; char fEndBuffer[TVirtualCollectionProxy::fgIteratorArenaSize]; void *fBegin; // Pointer to the starting iterator (collection->begin()) void *fEnd; // Pointer to the ending iterator (collection->end()) CreateIterators_t fCreateIterators; DeleteTwoIterators_t fDeleteTwoIterators; TVirtualCollectionIterators(TVirtualCollectionProxy *proxy, Bool_t read_from_file = kTRUE) : fBegin( &(fBeginBuffer[0]) ), fEnd(&(fEndBuffer[0])), fCreateIterators(nullptr), fDeleteTwoIterators(nullptr) { // Constructor given a collection proxy. // memset(fBeginBuffer,0,TVirtualCollectionProxy::fgIteratorArenaSize); // memset(fEndBuffer,0,TVirtualCollectionProxy::fgIteratorArenaSize); if (proxy) { fCreateIterators = proxy->GetFunctionCreateIterators(read_from_file); fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(read_from_file); } else { ::Fatal("TIterators::TIterators","Created with out a collection proxy!\n"); } } TVirtualCollectionIterators(CreateIterators_t creator, DeleteTwoIterators_t destruct) : fBegin( &(fBeginBuffer[0]) ), fEnd(&(fEndBuffer[0])), fCreateIterators(creator), fDeleteTwoIterators(destruct) { // Constructor given the creation and delete routines. } inline void CreateIterators(void *collection, TVirtualCollectionProxy *proxy) { // Initialize the fBegin and fEnd iterators. fCreateIterators(collection, &fBegin, &fEnd, proxy); } inline ~TVirtualCollectionIterators() { // Destructor. if (fBegin != &(fBeginBuffer[0])) { // assert(end != endbuf); fDeleteTwoIterators(fBegin,fEnd); } } }; class TGenericCollectionIterator { protected: TVirtualCollectionIterators fIterators; // The actual implementation. class RegularIterator; class VectorIterator; TGenericCollectionIterator() = delete; TGenericCollectionIterator(const TGenericCollectionIterator&) = delete; TGenericCollectionIterator(void *collection, TVirtualCollectionProxy *proxy, Bool_t read_from_file = kTRUE) : fIterators(proxy,read_from_file) { // Regular constructor. fIterators.CreateIterators(collection,proxy); } virtual ~TGenericCollectionIterator() { // Regular destructor. } public: virtual void *Next() = 0; virtual void* operator*() const = 0; virtual operator bool() const = 0; TGenericCollectionIterator& operator++() { Next(); return *this; } static TGenericCollectionIterator *New(void *collection, TVirtualCollectionProxy *proxy); }; class TGenericCollectionIterator::RegularIterator : public TGenericCollectionIterator { typedef TVirtualCollectionProxy::Next_t Next_t; Next_t fNext; void *fCurrent; bool fStarted : 1; public: RegularIterator(void *collection, TVirtualCollectionProxy *proxy, Bool_t read_from_file) : TGenericCollectionIterator(collection,proxy,read_from_file), fNext( proxy->GetFunctionNext(read_from_file) ), fCurrent(nullptr), fStarted(kFALSE) { } void *Next() override { fStarted = kTRUE; fCurrent = fNext(fIterators.fBegin,fIterators.fEnd); return fCurrent; } void* operator*() const override { return fCurrent; } operator bool() const override { return fStarted ? fCurrent != nullptr : kTRUE; } }; class TGenericCollectionIterator::VectorIterator : public TGenericCollectionIterator { ULong_t fIncrement; Bool_t fHasPointer; inline void *GetValue() const { if ((bool)*this) return fHasPointer ? *(void**)fIterators.fBegin : fIterators.fBegin; else return nullptr; } public: VectorIterator(void *collection, TVirtualCollectionProxy *proxy, Bool_t read_from_file) : TGenericCollectionIterator(collection,proxy,read_from_file), fIncrement(proxy->GetIncrement()), fHasPointer(proxy->HasPointers()) { } void *Next() override { if ( ! (bool)*this ) return nullptr; void *result = GetValue(); fIterators.fBegin = ((char*)fIterators.fBegin) + fIncrement; return result; } void* operator*() const override { return GetValue(); } operator bool() const override { return fIterators.fBegin != fIterators.fEnd; } }; inline TGenericCollectionIterator *TGenericCollectionIterator::New(void *collection, TVirtualCollectionProxy *proxy) { if (proxy->GetCollectionType() == ROOT::kSTLvector) { return new VectorIterator(collection, proxy, kFALSE); } else { return new RegularIterator(collection, proxy, kFALSE); } } /** \class TVirtualCollectionPtrIterators \ingroup IO */ class TVirtualCollectionPtrIterators { public: typedef TVirtualCollectionProxy::Next_t Next_t; typedef TVirtualCollectionProxy::CopyIterator_t Copy_t; typedef TVirtualCollectionProxy::CreateIterators_t CreateIterators_t; typedef TVirtualCollectionProxy::DeleteIterator_t Delete_t; typedef TVirtualCollectionProxy::DeleteTwoIterators_t DeleteTwoIterators_t; private: TVirtualCollectionPtrIterators(); // Intentionally unimplemented. TVirtualCollectionPtrIterators(const TVirtualCollectionPtrIterators&); // Intentionally unimplemented. CreateIterators_t fCreateIterators; DeleteTwoIterators_t fDeleteTwoIterators; Bool_t fAllocated; char fRawBeginBuffer[TVirtualCollectionProxy::fgIteratorArenaSize]; char fRawEndBuffer[TVirtualCollectionProxy::fgIteratorArenaSize]; struct TInternalIterator { private: TInternalIterator &operator=(const TInternalIterator&); // intentionally not implemented public: TInternalIterator() : fCopy(nullptr), fDelete(nullptr), fNext(nullptr), fIter(nullptr) {} TInternalIterator(const TInternalIterator &source) : fCopy(source.fCopy), fDelete(source.fDelete), fNext(source.fNext), fIter(nullptr) {} Copy_t fCopy; Delete_t fDelete; Next_t fNext; void *fIter; }; TInternalIterator fBeginBuffer; TInternalIterator fEndBuffer; public: // Note when the collection is a vector, fBegin and fEnd points to // the start and end of the memory content rather than to the address // of iterators (saving one dereference when being used). void *fBegin; // Pointer to the starting iterator (collection->begin()) void *fEnd; // Pointer to the ending iterator (collection->end()) TVirtualCollectionPtrIterators(TVirtualCollectionProxy *proxy) : fCreateIterators(nullptr), fDeleteTwoIterators(nullptr), fAllocated(kFALSE), fBegin( &(fRawBeginBuffer[0]) ), fEnd( &(fRawEndBuffer[0]) ) { // memset(fBeginBuffer,0,TVirtualCollectionProxy::fgIteratorArenaSize); // memset(fEndBuffer,0,TVirtualCollectionProxy::fgIteratorArenaSize); if (proxy) { fCreateIterators = proxy->GetFunctionCreateIterators(); fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(); fEndBuffer.fCopy = fBeginBuffer.fCopy = proxy->GetFunctionCopyIterator(); fEndBuffer.fNext = fBeginBuffer.fNext = proxy->GetFunctionNext(); fEndBuffer.fDelete = fBeginBuffer.fDelete = proxy->GetFunctionDeleteIterator(); } else { ::Fatal("TIterators::TIterators","Created with out a collection proxy!\n"); } } inline void CreateIterators(void *collection, TVirtualCollectionProxy *proxy) { // Initialize the fBegin and fEnd iterators. fBegin = &(fRawBeginBuffer[0]); fEnd = &(fRawEndBuffer[0]); fCreateIterators(collection, &fBegin, &fEnd, proxy); if (fBegin != &(fRawBeginBuffer[0])) { // The iterator where too large to buffer in the buffer fAllocated = kTRUE; } fBeginBuffer.fIter = fBegin; fEndBuffer.fIter = fEnd; fBegin = &fBeginBuffer; fEnd = &fEndBuffer; } inline ~TVirtualCollectionPtrIterators() { if (fAllocated) { // assert(end != endbuf); fDeleteTwoIterators(fBeginBuffer.fIter,fEndBuffer.fIter); } } static void *Next(void *iter, const void *end) { TInternalIterator *internal_iter = (TInternalIterator*) iter; TInternalIterator *internal_end = (TInternalIterator*) end; void **ptr = (void**)internal_iter->fNext(internal_iter->fIter,internal_end->fIter); if(ptr) return *ptr; else return nullptr; } static void DeleteIterator(void *iter) { TInternalIterator *internal_iter = (TInternalIterator*) iter; if (internal_iter->fDelete) { internal_iter->fDelete(internal_iter->fIter); } } static void *CopyIterator(void *dest, const void *source) { TInternalIterator *internal_source = (TInternalIterator*)source; TInternalIterator *internal_dest = new TInternalIterator(*internal_source); void *newiter = internal_source->fCopy(dest,internal_source->fIter); if (newiter == dest) { internal_dest->fDelete = nullptr; } internal_dest->fIter = newiter; return internal_dest; } }; // Specialization of TVirtualCollectionIterators when we know the collection // to be a vector (hence there is nothing to delete at the end). struct TVirtualVectorIterators { private: TVirtualVectorIterators(const TVirtualVectorIterators&); // Intentionally unimplemented. public: // Note when the collection is a vector, fBegin and fEnd points to // the start and end of the memory content rather than to the address // of iterators (saving one dereference when being used). typedef TVirtualCollectionProxy::CreateIterators_t CreateIterators_t; void *fBegin; // Pointer to the starting iterator (collection->begin()) void *fEnd; // Pointer to the ending iterator (collection->end()) TVirtualVectorIterators(TVirtualCollectionProxy * /* proxy */) : fBegin(nullptr), fEnd(nullptr) { // fCreateIterators = proxy->GetFunctionCreateIterators(); } TVirtualVectorIterators(CreateIterators_t /* creator */) : fBegin(nullptr), fEnd(nullptr) { // fCreateIterators = creator; } TVirtualVectorIterators() : fBegin(nullptr), fEnd(nullptr) { // Default constructor. } inline void CreateIterators(void *collection) { // Initialize the fBegin and fEnd iterators. // We can safely assume that the std::vector layout does not really depend on // the content! std::vector *vec = (std::vector*)collection; if (vec->empty()) { fBegin = nullptr; fEnd = nullptr; return; } fBegin= &(*vec->begin()); #ifdef R__VISUAL_CPLUSPLUS fEnd = &(*(vec->end()-1)) + 1; // On windows we can not dererence the end iterator at all. #else // coverity[past_the_end] Safe on other platforms fEnd = &(*vec->end()); #endif //fCreateIterators(collection, &fBegin, &fEnd); } }; #endif // ROOT_TVirtualCollectionIterators