// ----------------------------------------------------------------------------
// FILE NAME: iperthr.hpp
//
// DESCRIPTION:
//
//  This header defines the IThreadLocalStorage class. This class has a
//  very tiny interface since its mostly implementation. The creation of an
//  object of this class will cause a per-thread instantiated pointer to
//  be created. The pointer associated with the calling thread is implicitly
//  used in all methods.
//
//  This class is a template so that its destructor can successfully delete
//  the data pointed to (i.e. its instantiated in terms of the type of data
//  it is to point to.
//
//  Note that creating an object of this type only manages the pointer
//  itself. It does not care about the contents other than to zero it on
//  creation. Setting the point to something meaningful is user's duty.
//
//  IThreadLocalBase is just a simple, non-temlatized class that provides
//  some static methods to manipulate the internal thread data slots
//
// COPYRIGHT:
//   IBM Open Class Library
//   Licensed Materials - Property of IBM
//
//   5645-001
//   (C) Copyright IBM Corporation 1992, 1997  All Rights Reserved.
//
// Revision: 13 1.12.1.3 source/core/base/iperthr.hpp, oss, ioc.v400, 980918 
// ----------------------------------------------------------------------------

#ifndef _IPERTHR_
#define _IPERTHR_

#include <ibase.hpp>

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

#pragma pack(push,4)
#pragma enum(4)

//
//  This is used to indicate that the slot index is not valid. Since 0 is
//  a valid index, just zeroing it out is not safe enough.
//
const unsigned long  gInvalidThreadSlotIndex    = 0xFFFFFFFFUL;


//
//  This class is just a non-templatized base for the actual thread local
//  storage class. It allows us to provide some non-templatized implementation
//  functionality. It is all static and manages local data within the Cpp
//  file. All access to that data is via this base class.
//
//  There is one public static to clean up all of the data for the calling
//  thread.
//
class IC_EXPORTB IThreadLocalBase
{
    public :
        static void freeAllStorage();

    protected :
        IThreadLocalBase();
        virtual ~IThreadLocalBase();

        IThreadLocalBase(const IThreadLocalBase&);
        IThreadLocalBase& operator=(const IThreadLocalBase);

        // Slot management methods
        unsigned long getNextSlot();
        void expandThreadSlots(const unsigned long newcount);
        void* getSlot(const unsigned long index) const;
        void setSlot(const unsigned long index, void* data);

        // To free storage virtually via this base class
        virtual void freeStorage() = 0;

    private :
        // Used internally to maintain a linked list of objects
        IThreadLocalBase*   next;

};


//
//  This class is the actual thread local storage class. It manages, in a
//  type safe way, a pointer to any type of desired thread local storage
//  object. Since the data is actuall per-thread, its all actually managed
//  locally within the Cpp file. This class uses its non-templatized base
//  class to do that work.
//
template <class AType> class IThreadLocalStorage : public IThreadLocalBase
{
    public :
        // --------------------------------------------------------------------
        //  Constructors and destructors
        // --------------------------------------------------------------------
                IThreadLocalStorage();
                IThreadLocalStorage(const bool resettable);
                ~IThreadLocalStorage();

        // --------------------------------------------------------------------
        //  Access methods for getting to the pointer.
        // --------------------------------------------------------------------
        AType*  get() const;
        AType*  storage() const;
        AType*  operator->() const;
        AType&  operator*() const;

        // --------------------------------------------------------------------
        //  Setter methods to set the pointer. Freeing the storage sets the
        //  pointer to 0 for this thread. It is virtual because it must be
        //  called via the base class.
        // --------------------------------------------------------------------
        void    adoptStorage(AType* toadopt);
        void    freeStorage();


    private :
        // --------------------------------------------------------------------
        //  We want to avoid copying of these objects and to avoid their
        //  dynamic creation.
        // --------------------------------------------------------------------
                IThreadLocalStorage(const IThreadLocalStorage<AType>&) {}
        void    operator=(const IThreadLocalStorage<AType>&) {}
        void*   operator new(size_t) {return 0;}


        // --------------------------------------------------------------------
        //  canReset
        //      Allow the creator to indicate whether this pointer allows for
        //      multiple sets of the object. If not, second attempt to set it
        //      will throw an exception.
        //
        //  index
        //      This is the array index (to a static array hidden in the
        //      implementation) of the pointer for this object. Its used
        //      to get/set the correct pointer. Its set internally by the
        //      implementation during construction, not by the caller.
        // --------------------------------------------------------------------
        bool            canReset;
        unsigned long   index;
};

#pragma enum(pop)
#pragma pack(pop)

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#include <iperthr.inl>

#endif // _IPERTHR_
