    // @(#)root/cont:$Name:  $:$Id: TGenCollectionProxy.h,v 1.8 2005/06/01 15:43:18 pcanal Exp $
    // Author: Markus Frank  28/10/04

    /*************************************************************************
     * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/
    #ifndef ROOT_TGenCollectionProxy
    #define ROOT_TGenCollectionProxy

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TGenCollectionProxy
    //
    // Proxy around an arbitrary container, which implements basic
    // functionality and iteration.
    //
    // In particular this is used to implement splitting and abstract
    // element access of any container. Access to compiled code is necessary
    // to implement the abstract iteration sequence and functionality like
    // size(), clear(), resize(). resize() may be a void operation.
    //
    //////////////////////////////////////////////////////////////////////////

    #include "TVirtualCollectionProxy.h"
    #include "TCollectionProxy.h"
    #include <typeinfo>
    #include <string>

    class TGenCollectionProxy
      : public TVirtualCollectionProxy,
        public TCollectionProxy
    {

      /// Friend declaration
      friend class TCollectionProxy;

    public:

      enum {
        // Those 'bits' are used in conjunction with CINT's bit to store the 'type'
        // info into one int
        R__BIT_ISSTRING   = 0x20000000,  // We can optimized a value operation when the content are strings
        R__BIT_ISTSTRING  = 0x40000000,
        kBOOL_t = 21
      };

      /** @class TGenCollectionProxy::Value TGenCollectionProxy.h TGenCollectionProxy.h
        *
        * Small helper to describe the Value_type or the key_type
        * of an STL container.
        *
        * @author  M.Frank
        * @version 1.0
        * @date    10/10/2004
        */
      struct Value  {
        ROOT::NewFunc_t fCtor;      // Method cache for containee constructor
        ROOT::DesFunc_t fDtor;      // Method cache for containee destructor
        ROOT::DelFunc_t fDelete;    // Method cache for containee delete
        unsigned int    fCase;      // type of data of Value_type
        TClassRef       fType;      // TClass reference of Value_type in collection
        EDataType       fKind;      // kind of ROOT-fundamental type
        size_t          fSize;      // fSize of the contained object

        /// Copy constructor
        Value(const Value& inside);
        /// Initializing constructor
        Value(const std::string& info);
        /// Delete individual item from STL container
        void DeleteItem(void* ptr);
      };

      /**@class StreamHelper
        *
        * Helper class to facilitate I/O
        *
        * @author  M.Frank
        * @version 1.0
        * @date    10/10/2004
        */
      union StreamHelper  {
        bool         boolean;
        Char_t       s_char;
        Short_t      s_short;
        Int_t        s_int;
        Long_t       s_long;
        Long64_t     s_longlong;
        Float_t      flt;
        Double_t     dbl;
        UChar_t      u_char;
        UShort_t     u_short;
        UInt_t       u_int;
        ULong_t      u_long;
        ULong64_t    u_longlong;
        void*        p_void;
        void**       pp_void;
        char*        kchar;
        TString*     tstr;
        void* ptr()  {
          return *(&this->p_void);
        }
        std::string* str()  {
          return (std::string*)this;
        }
        const char* c_str()  {
          return ((std::string*)this)->c_str();
        }
        const char* c_pstr()  {
          return (*(std::string**)this)->c_str();
        }
        void set(void* p)  {
          *(&this->p_void) = p;
        }
        void read_std_string(TBuffer& b) {
          TString s;
          s.Streamer(b);
          ((std::string*)this)->assign(s.Data());
        }
        void* read_tstring(TBuffer& b)  {
          *((TString*)this) = "";
          ((TString*)this)->Streamer(b);
          return this;
        }
        void read_std_string_pointer(TBuffer& b) {
          TString s;
          std::string* str = (std::string*)ptr();
          if (!str) str = new std::string();
          s.Streamer(b);
          *str = s;
          set(str);
        }
        void write_std_string_pointer(TBuffer& b)  {
          const char* c;
          if (ptr()) {
             std::string* strptr = (*(std::string**)this);
             c = (const char*)(strptr->c_str());
          } else c = "";
          TString(c).Streamer(b);
        }
        void read_any_object(Value* v, TBuffer& b)  {
          void* p = ptr();
          if ( p )  {
            if ( v->fDelete )  {    // Compiled content: call Destructor
              (*v->fDelete)(p);
            }
            else if ( v->fType )  { // Emulated content: call TClass::Delete
              v->fType->Destructor(p);
            }
            else if ( v->fDtor )  {
              (*v->fDtor)(p);
              ::operator delete(p);
            }
            else  {
              ::operator delete(p);
            }
          }
          set( b.ReadObjectAny(v->fType) );
        }

        void read_tstring_pointer(bool vsn3, TBuffer& b)  {
          TString* s = (TString*)ptr();
          if ( vsn3 )  {
            if ( !s ) s = new TString();
            s->Replace(0, s->Length(), 0, 0);
            s->Streamer(b);
            set(s);
            return;
          }
          if ( s ) delete s;
          set( b.ReadObjectAny(TString::Class()) );
        }
        void write_tstring_pointer(TBuffer& b)  {
          b.WriteObjectAny(ptr(), TString::Class());
        }
      };

      /** @class TGenCollectionProxy::Method TGenCollectionProxy.h TGenCollectionProxy.h
        *
        * Small helper to execute (compiler) generated function for the
        * access to STL or other containers.
        *
        * @author  M.Frank
        * @version 1.0
        * @date    10/10/2004
        */
      struct Method  {
        typedef void* (*Call_t)(void*);
        Call_t call;
        Method() : call(0)                       {      }
        Method(Call_t c) : call(c)               {      }
        Method(const Method& m) : call(m.call)   {      }
        void* invoke(void* obj) const { return (*call)(obj); }
      };

    protected:
      typedef ROOT::Environ<char[64]> Env_t;
      typedef std::vector<Env_t*>     Proxies_t;

      std::string   fName;      // Name of the class being proxied.
      bool          fPointers;  // Flag to indicate if containee has pointers (key or value)
      Method        fClear;     // Method cache for container accessors: clear container
      Method        fSize;      // Container accessors: size of container
      Method        fResize;    // Container accessors: resize container
      Method        fFirst;     // Container accessors: generic iteration: first
      Method        fNext;      // Container accessors: generic iteration: next
      Method        fConstruct; // Container accessors: block construct
      Method        fDestruct;  // Container accessors: block destruct
      Method        fFeed;      // Container accessors: block feed
      Method        fCollect;   // Method to collect objects from container
      Value*        fValue;     // Descriptor of the container value type
      Value*        fVal;       // Descriptor of the Value_type
      Value*        fKey;       // Descriptor of the key_type
      Env_t*        fEnv;       // Address of the currently proxied object
      int           fValOffset; // Offset from key to value (in maps)
      int           fValDiff;   // Offset between two consecutive value_types (memory layout).
      Proxies_t     fProxyList; // Stack of recursive proxies
      Proxies_t     fProxyKept; // Optimization: Keep proxies once they were created
      int           fSTL_type;  // STL container type
      Info_t        fTypeinfo;  // Type information

      /// Late initialization of collection proxy
      TGenCollectionProxy* Initialize() const;
      /// Some hack to avoid const-ness
      virtual TGenCollectionProxy* InitializeEx();
      /// Call to delete/destruct individual contained item
      virtual void DeleteItem(bool force, void* ptr) const;
      /// Allow to check function pointers
      void CheckFunctions()  const;

    public:

      /// Virtual copy constructor
      virtual TVirtualCollectionProxy* Generate() const;

      /// Copy constructor
      TGenCollectionProxy(const TGenCollectionProxy& copy);

      /// Initializing constructor
      TGenCollectionProxy(Info_t typ, size_t iter_size);

      /// Standard destructor
      virtual ~TGenCollectionProxy();

      /// Return a pointer to the TClass representing the container
      virtual TClass *GetCollectionClass();

      /// Return the sizeof the collection object.
      virtual UInt_t Sizeof() const;

      /// Push new proxy environment
      virtual void PushProxy(void *objstart);

      /// Pop old proxy environment
      virtual void PopProxy();

      /// Return true if the content is of type 'pointer to'
      virtual Bool_t HasPointers() const;

      /// Return a pointer to the TClass representing the content.
      virtual TClass *GetValueClass();

      /// Set pointer to the TClass representing the content.
      virtual void SetValueClass(TClass *newcl);

      /// If the content is a simple numerical value, return its type (see TDataType)
      virtual EDataType GetType();

      /// Return the address of the value at index 'idx'
      virtual void *At(UInt_t idx);

      /// Clear the container
      virtual void Clear(const char *opt = "");

      /// Resize the container
      virtual void Resize(UInt_t n, Bool_t force_delete);

      /// Return the current size of the container
      virtual UInt_t Size() const;

      /// Block allocation of containees
      virtual void* Allocate(UInt_t n, Bool_t forceDelete);

      /// Block commit of containees
      virtual void Commit(void* env);

      /// Streamer function
      virtual void Streamer(TBuffer &refBuffer);

      /// Streamer I/O overload
      virtual void Streamer(TBuffer &refBuffer, void *pObject, int siz);

      /// TClassStreamer I/O overload
      virtual void operator()(TBuffer &refBuffer, void *pObject);
    };

    template <typename T>
    struct AnyCollectionProxy : public TGenCollectionProxy  {
      AnyCollectionProxy()
      : TGenCollectionProxy(typeid(T::Cont_t),sizeof(T::Iter_t))
      {
        fValDiff        = sizeof(T::Value_t);
        fValOffset      = T::value_offset();
        fSize.call      = T::size;
        fResize.call    = T::resize;
        fNext.call      = T::next;
        fFirst.call     = T::first;
        fClear.call     = T::clear;
        fConstruct.call = T::construct;
        fDestruct.call  = T::destruct;
        fFeed.call      = T::feed;
        CheckFunctions();
      }
      virtual ~AnyCollectionProxy() {  }
    };

    #endif