#ifndef _REFCOUNT_H
#define _REFCOUNT_H

                 /*==================================*/
                 /*                                  */
                 /*            refcount.h            */
                 /*                                  */
                 /*  A SIMPLE REFCOUNTING TEMPLATE   */
                 /*                                  */
                 /*==================================*/

//#define REFCOUNT_THREADED 1

#ifdef REFCOUNT_THREADED

#include <pthread.h>
#define DECLARE_MUTEX  pthread_mutex_t mutex;
#define MUTEX_INIT     pthread_mutex_init(&mutex, NULL);
#define MUTEX_DESTROY  pthread_mutex_destroy(&mutex);
#define MUTEX_LOCK     pthread_mutex_lock(&mutex);
#define MUTEX_UNLOCK   pthread_mutex_unlock(&mutex);

#else // REFCOUNT_THREADED

#define DECLARE_MUTEX
#define MUTEX_INIT
#define MUTEX_DESTROY
#define MUTEX_LOCK
#define MUTEX_UNLOCK

#endif

//#include <syslog.h> // syslog(), LOG_INFO
//#include <unistd.h> // getpid()

// See Bruce Eckel's "Thinking in C++" for an explanation of the
// dummy (int) argument in the prototypes of the postfix versions
// of overloaded increment/decrement unary operators.
// The additional dummy (int) argument is a simple way to differentiate
// a postfix prototype from a prefix prototype (pre-increment, pre-decrement).
// The prefix prototypes don't have this dummy argument.

template<class holder_cls>

class ref_t // a generic reference-counter class
{
private:
   holder_cls* holder;
   int refcount;
   DECLARE_MUTEX
public:
   ref_t(holder_cls* _holder) : holder(_holder), refcount(0)
      { MUTEX_INIT }
   ~ref_t() { MUTEX_DESTROY }

   int operator++(int dummy)
   {
    int retval;
    
      MUTEX_LOCK
      retval = ++refcount;
      //syslog(LOG_INFO, "%s == %d called by %d", __PRETTY_FUNCTION__, retval, getpid());
      MUTEX_UNLOCK
      
      return(retval); 
   }


   int operator--(int dummy)
   {
    int retval;
    
      MUTEX_LOCK

      retval = --refcount;
      //syslog(LOG_INFO, "%s == %d called by %d", __PRETTY_FUNCTION__, retval, getpid());
      MUTEX_UNLOCK

      if (retval == 0)
         delete holder;

      return(retval);
   }


   int zap()
   {  // locking the mutex doesn't make sense, as this is just a single check
      // (a single instruction) and the holder is probably abandoned if count==0
      if (refcount == 0)
      {
         delete holder;
         return(1);
      }
      else return(0);
   }

   int count() { return(refcount); }
};


// See Bruce Eckel's "Thinking in C++" for an explanation of
// why template class method definitions need to reside *in the header file*,
// rather than in a proper .cc file.
// Please note you can do that, but it will isolate the template method defs
// inside that translation unit (.cc file).
// The compiler needs to see the template function definition at the point
// where it is used, in order to be able to instantiate the template...

// Also, GCC 2.96 doesn't seem to cope well with non-inlined template methods.
// Hence they're left inlined in this case, though their contents would seem
// to allow proper non-inlined definition.

#endif // _REFCOUNT_H

