// @(#)root/cont:$Name:  $:$Id: TCollectionProxy.h,v 1.9 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_TCollectionProxy
#define ROOT_TCollectionProxy

//////////////////////////////////////////////////////////////////////////
//                                                                      //
//  Small helper to save proxy environment in the event of
//  recursive calls.
//
//////////////////////////////////////////////////////////////////////////

#include <typeinfo>

// Forward declarations
class TBuffer;
class TClassStreamer;
class TMemberStreamer;
class TGenCollectionProxy;
class TGenCollectionStreamer;
class TVirtualCollectionProxy;
class TEmulatedCollectionProxy;

#if defined(_WIN32) 
  #if _MSC_VER<1300
    #define TYPENAME
    #define R__VCXX6
  #else
    #define TYPENAME typename
  #endif
#else
  #define TYPENAME typename
#endif


namespace ROOT {
  /** @class TCollectionProxy::Environ TCollectionProxy.h TCollectionProxy.h 
    *
    * Small helper to save proxy environment in the event of
    * recursive calls.
    *
    * @author  M.Frank
    * @version 1.0
    * @date    10/10/2004
    */
#ifndef __CINT__
  template <typename T> struct Environ  {
    typedef T           Iter_t;
    char                buff[64];
    size_t              idx;
    size_t              size;
    void*               object;
    void*               start;
    void*               temp;
    bool                delete_temp;
    int                 refCount;
    size_t              space;
    T& iter() { return *(T*)buff; }
  };
#else 
  template <typename T> struct Environ;
#endif
#if defined(R__VCXX6)
  template <class T> void Destruct(T* obj) { obj->~T(); }
#endif
}

/** @class TCollectionProxy TCollectionProxy.h cont/TCollectionProxy.h
  *
  * TCollectionProxy
  * Interface to collection proxy and streamer generator.
  *
  * Proxy around an arbitrary container, which implements basic 
  * functionality and iteration. The purpose of this implementation 
  * is to shield any generated dictionary implementation from the
  * underlying streamer/proxy implementation and only expose
  * the creation fucntions.
  *
  * 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.
  *
  * @author  M.Frank
  * @version 1.0
  */
class TCollectionProxy  {
public:

  typedef TVirtualCollectionProxy Proxy_t;
#ifdef R__HPUX
  typedef const type_info&      Info_t;
#else
  typedef const std::type_info& Info_t;
#endif


  template <class T, class Q> struct pair_holder {
    T first;
    Q second;
    pair_holder() {}
    pair_holder(const pair_holder& c) : first(c.first), second(c.second) {}
    ~pair_holder() {}
  };

  template <class T> struct Address {
    static void* address(T ref) {
      return (void*)&ref;
    }
  };

  /** @class TCollectionProxy::fType TCollectionProxy.h TCollectionProxy.h 
    *
    * Small helper to encapsulate basic data accesses for 
    * all STL continers.
    *
    * @author  M.Frank
    * @version 1.0
    * @date    10/10/2004
    */
  template <class T> struct Type 
 #ifdef R__KCC
  : public Address<TYPENAME T::value_type&> 
 #else 
  : public Address<TYPENAME T::const_reference> 
 #endif 
  {
    typedef T                      Cont_t;
    typedef typename T::iterator   Iter_t;
    typedef typename T::value_type Value_t;
    typedef ROOT::Environ<Iter_t>  Env_t;
    typedef Env_t                 *PEnv_t;
    typedef Cont_t                *PCont_t;
    typedef Value_t               *PValue_t;

    static inline PCont_t object(void* ptr)   {
      return PCont_t(PEnv_t(ptr)->object);
    }
    static void* size(void* env)  {
      PEnv_t  e = PEnv_t(env);
      e->size   = PCont_t(e->object)->size();
      return &e->size;
    }
    static void* clear(void* env)  {
      object(env)->clear();
      return 0;
    }
    static void* first(void* env)  {
      PEnv_t  e = PEnv_t(env);
      PCont_t c = PCont_t(e->object);
      // Assume iterators do not need destruction
      ::new(e->buff) Iter_t(c->begin()); 
      e->size  = c->size();
      if ( 0 == e->size ) return e->start = 0;
#ifdef R__KCC
      TYPENAME T::value_type& ref = *(e->iter());
#else
      TYPENAME T::const_reference ref = *(e->iter());
#endif
      return e->start = address(ref);
    }
    static void* next(void* env)  {
      PEnv_t  e = PEnv_t(env);
      PCont_t c = PCont_t(e->object);
      for (; e->idx > 0 && e->iter() != c->end(); ++(e->iter()), --e->idx );
      // TODO: Need to find something for going backwards....
      if ( e->iter() == c->end() ) return 0;
#ifdef R__KCC
      TYPENAME T::value_type& ref = *(e->iter());
#else
      TYPENAME T::const_reference ref = *(e->iter());
#endif
      return address(ref);
    }
    static void* construct(void* env)  {
      PEnv_t  e = PEnv_t(env);
      PValue_t m = PValue_t(e->start);
      for (size_t i=0; i<e->size; ++i, ++m)  
        ::new(m) Value_t();
      return 0;
    }
    static void* collect(void* env)  {
      PEnv_t   e = PEnv_t(env);
      PCont_t  c = PCont_t(e->object);
      PValue_t m = PValue_t(e->start);
      for (Iter_t i=c->begin(); i != c->end(); ++i, ++m )
        ::new(m) Value_t(*i);
      return 0;
    }
    static void* destruct(void* env)  {
      PEnv_t   e = PEnv_t(env);
      PValue_t m = PValue_t(e->start);
#if defined(R__VCXX6)
      PCont_t  c = PCont_t(e->object);
      for (size_t i=0; i < e->size; ++i, ++m )
         ROOT::Destruct(m);
#else
      for (size_t i=0; i < e->size; ++i, ++m )
        m->~Value_t();
#endif
      return 0;
    }
  };

  /** @class TCollectionProxy::Map TCollectionProxy.h TCollectionProxy.h 
    *
    * Small helper to encapsulate all necessary data accesses for 
    * containers like vector, list, deque
    *
    * @author  M.Frank
    * @version 1.0
    * @date    10/10/2004
    */
  template <class T> struct Pushback : public Type<T> {
    typedef T                      Cont_t;
    typedef typename T::iterator   Iter_t;
    typedef typename T::value_type Value_t;
    typedef ROOT::Environ<Iter_t>  Env_t;
    typedef Env_t                 *PEnv_t;
    typedef Cont_t                *PCont_t;
    typedef Value_t               *PValue_t;
    static void* resize(void* env)  {
      PEnv_t  e = PEnv_t(env);
      PCont_t c = PCont_t(e->object);
      c->resize(e->size);
      e->idx = 0;
      return e->start = address(*c->begin());
    }
    static void* feed(void* env)  {
      PEnv_t   e = PEnv_t(env);
      PCont_t  c = PCont_t(e->object);
      PValue_t m = PValue_t(e->start);
      for (size_t i=0; i<e->size; ++i, ++m)
        c->push_back(*m);
      return 0;
    }
    static int value_offset()  {
      return 0;
    }
  };

  /** @class TCollectionProxy::Map TCollectionProxy.h TCollectionProxy.h 
    *
    * Small helper to encapsulate all necessary data accesses for 
    * containers like set, multiset etc.
    *
    * @author  M.Frank
    * @version 1.0
    * @date    10/10/2004
    */
  template <class T> struct Insert : public Type<T> {
    typedef T                      Cont_t;
    typedef typename T::iterator   Iter_t;
    typedef typename T::value_type Value_t;
    typedef ROOT::Environ<Iter_t>  Env_t;
    typedef Env_t                 *PEnv_t;
    typedef Cont_t                *PCont_t;
    typedef Value_t               *PValue_t;
    static void* feed(void* env)  {
      PEnv_t   e = PEnv_t(env);
      PCont_t  c = PCont_t(e->object);
      PValue_t m = PValue_t(e->start);
      for (size_t i=0; i<e->size; ++i, ++m)
        c->insert(*m);
      return 0;
    }
    static void* resize(void* /* env */ )  {
      return 0;
    }
    static int value_offset()  {
      return 0;
    }
  };

  /** @class TCollectionProxy::Map TCollectionProxy.h TCollectionProxy.h 
    *
    * Small helper to encapsulate all necessary data accesses for 
    * containers like set, multiset etc.
    *
    * @author  M.Frank
    * @version 1.0
    * @date    10/10/2004
    */
  template <class T> struct MapInsert : public Type<T> {
    typedef T                      Cont_t;
    typedef typename T::iterator   Iter_t;
    typedef typename T::value_type Value_t;
    typedef ROOT::Environ<Iter_t>  Env_t;
    typedef Env_t                 *PEnv_t;
    typedef Cont_t                *PCont_t;
    typedef Value_t               *PValue_t;
    static void* feed(void* env)  {
      PEnv_t   e = PEnv_t(env);
      PCont_t  c = PCont_t(e->object);
      PValue_t m = PValue_t(e->start);
      for (size_t i=0; i<e->size; ++i, ++m)
        c->insert(*m);
      return 0;
    }
    static void* resize(void* /* env */ )  {
      return 0;
    }
    static int value_offset()  {
      return ((char*)&((PValue_t(0x1000))->second)) - ((char*)PValue_t(0x1000));
    }
  };

  /// Generate emulated collection proxy for a given class
  static TVirtualCollectionProxy* genEmulatedProxy(const char* class_name);

  /// Generate emulated class streamer for a given collection class
  static TClassStreamer* genEmulatedClassStreamer(const char* class_name);

  /// Generate emulated member streamer for a given collection class
  static TMemberStreamer* genEmulatedMemberStreamer(const char* class_name);

  /// Generate proxy from static functions
  static Proxy_t* genExplicitProxy( Info_t info,
                                    size_t iter_size,
                                    size_t value_diff,
                                    int    value_offset,
                                    void*  (*size_func)(void*),
                                    void*  (*resize_func)(void*),
                                    void*  (*clear_func)(void*),
                                    void*  (*first_func)(void*),
                                    void*  (*next_func)(void*),
                                    void*  (*construct_func)(void*),
                                    void*  (*destruct_func)(void*),
                                    void*  (*feed_func)(void*),
                                    void*  (*collect_func)(void*)
                                    );

  /// Generate proxy from template
  template <class T> static Proxy_t* genProxy(const T&)  {
    pair_holder<TYPENAME T::Value_t, TYPENAME T::Value_t>* p = 
       (pair_holder<TYPENAME T::Value_t, TYPENAME T::Value_t>*)0x1000;
    return genExplicitProxy(typeid(TYPENAME T::Cont_t),
                            sizeof(TYPENAME T::Iter_t),
                            (((char*)&p->second)-((char*)&p->first)),
                            T::value_offset(),
                            T::size,
                            T::resize,
                            T::clear,
                            T::first,
                            T::next,
                            T::construct,
                            T::destruct,
                            T::feed,
                            T::collect);
  }

  /// Generate streamer from static functions
  static TGenCollectionStreamer* 
    genExplicitStreamer(  Info_t  info,
                          size_t  iter_size,
                          size_t  value_diff,
                          int     value_offset,
                          void*  (*size_func)(void*),
                          void*  (*resize_func)(void*),
                          void*  (*clear_func)(void*),
                          void*  (*first_func)(void*),
                          void*  (*next_func)(void*),
                          void*  (*construct_func)(void*),
                          void*  (*destruct_func)(void*),
                          void*  (*feed_func)(void*),
                          void*  (*collect_func)(void*)
                          );

  /// Generate class streamer from static functions
  static TClassStreamer* 
    genExplicitClassStreamer( Info_t  info,
                              size_t  iter_size,
                              size_t  value_diff,
                              int     value_offset,
                              void*  (*size_func)(void*),
                              void*  (*resize_func)(void*),
                              void*  (*clear_func)(void*),
                              void*  (*first_func)(void*),
                              void*  (*next_func)(void*),
                              void*  (*construct_func)(void*),
                              void*  (*destruct_func)(void*),
                              void*  (*feed_func)(void*),
                              void*  (*collect_func)(void*)
                              );

  /// Generate class streamer from template
  template <class T> static TClassStreamer* genClassStreamer(const T&)  {
    pair_holder<TYPENAME T::Value_t, TYPENAME T::Value_t>* p = 
       (pair_holder<TYPENAME T::Value_t, TYPENAME T::Value_t>*)0x1000;
    return genExplicitClassStreamer(typeid(TYPENAME T::Cont_t),
                                    sizeof(TYPENAME T::Iter_t),
                                    (((char*)&p->second)-((char*)&p->first)),
                                    T::value_offset(),
                                    T::size,
                                    T::resize,
                                    T::clear,
                                    T::first,
                                    T::next,
                                    T::construct,
                                    T::destruct,
                                    T::feed,
                                    T::collect);
  }

  /// Generate member streamer from static functions
  static TMemberStreamer* 
    genExplicitMemberStreamer(Info_t  info,
                              size_t  iter_size,
                              size_t  value_diff,
                              int     value_offset,
                              void*  (*size_func)(void*),
                              void*  (*resize_func)(void*),
                              void*  (*clear_func)(void*),
                              void*  (*first_func)(void*),
                              void*  (*next_func)(void*),
                              void*  (*construct_func)(void*),
                              void*  (*destruct_func)(void*),
                              void*  (*feed_func)(void*),
                              void*  (*collect_func)(void*)
                              );

  /// Generate member streamer from template
  template <class T> static TMemberStreamer* genMemberStreamer(const T&)  {
    pair_holder<TYPENAME T::Value_t, TYPENAME T::Value_t>* p = 
       (pair_holder<TYPENAME T::Value_t, TYPENAME T::Value_t>*)0x1000;
    return genExplicitMemberStreamer( typeid(TYPENAME T::Cont_t),
                                      sizeof(TYPENAME T::Iter_t),
                                      (((char*)&p->second)-((char*)&p->first)),
                                      T::value_offset(),
                                      T::size,
                                      T::resize,
                                      T::clear,
                                      T::first,
                                      T::next,
                                      T::construct,
                                      T::destruct,
                                      T::feed,
                                      T::collect);
  }
};

/** @class TCollectionStreamer TCollectionProxy.h cont/TCollectionProxy.h
  *
  * TEmulatedClassStreamer
  *
  * Class streamer object to implement TClassStreamr functionality
  * for I/O emulation.
  *
  * @author  M.Frank
  * @version 1.0
  */
class TCollectionStreamer   {
protected:
  TGenCollectionProxy* fStreamer;   /// Pointer to worker streamer

  /// Issue Error about invalid proxy
  void InvalidProxyError();

public:
  /// Initializing constructor
  TCollectionStreamer();
  /// Copy constructor
  TCollectionStreamer(const TCollectionStreamer& c);
  /// Standard destructor
  virtual ~TCollectionStreamer();
  /// Attach worker proxy
  void AdoptStreamer(TGenCollectionProxy* streamer);
  /// Streamer for I/O handling
  void Streamer(TBuffer &refBuffer, void *pObject, int siz);
};

#include "TClassStreamer.h"

/** @class TEmulatedClassStreamer TCollectionProxy.h cont/TCollectionProxy.h
  *
  * TEmulatedClassStreamer
  *
  * Class streamer object to implement TClassStreamr functionality
  * for I/O emulation.
  *
  * @author  M.Frank
  * @version 1.0
  */
class TCollectionClassStreamer : public TClassStreamer, public TCollectionStreamer {
public:
  /// Initializing constructor
  TCollectionClassStreamer() : TClassStreamer(0)     {                        }
  /// Copy constructor
  TCollectionClassStreamer(const TCollectionClassStreamer& c) 
    : TClassStreamer(c), TCollectionStreamer(c)      {                        }
  /// Standard destructor
  virtual ~TCollectionClassStreamer()                {                        }
  /// Streamer for I/O handling
  virtual void operator()(TBuffer &buff, void *pObj) { Streamer(buff,pObj,0); }
};

#include "TMemberStreamer.h"

/** @class TCollectionMemberStreamer TCollectionProxy.h cont/TCollectionProxy.h
  *
  * TCollectionMemberStreamer
  *
  * Class streamer object to implement TMemberStreamer functionality
  * for I/O emulation.
  *
  * @author  M.Frank
  * @version 1.0
  */
class TCollectionMemberStreamer : public TMemberStreamer, public TCollectionStreamer {
public:
  /// Initializing constructor
  TCollectionMemberStreamer() : TMemberStreamer(0) { }
  /// Copy constructor
  TCollectionMemberStreamer(const TCollectionMemberStreamer& c) 
    : TMemberStreamer(c), TCollectionStreamer(c)   { }
  /// Standard destructor
  virtual ~TCollectionMemberStreamer()             { }
  /// Streamer for I/O handling
  virtual void operator()(TBuffer &buff,void *pObj,Int_t siz=0)
  { Streamer(buff, pObj, siz);                       }
};

#ifndef __CINT__
// Need specialization for boolean references due to stupid STL vector<bool>
template<> inline void* TCollectionProxy::Address<std::vector<bool>::const_reference>::address(std::vector<bool>::const_reference ) {
  return 0;
}
#endif

#endif
