Josh Dybnis on 18 Jun 2003 21:56:01 -0000


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [ALACPP] Singleton clarification


More C macro fun. Singleton this time; much simpler than functors.

-Josh Dybnis
/****************************************************************************/
/******* C port of Singleton from Chapter 6 of "Modern C++ Design" **********/
/****************************************************************************/

/** singleton.h *************************************************************/

#define DECLARE_SINGLETON(type, name) \
    type get_##name (void);

#define  DEFINE_SINGLETON(type, name, destructor, longevity, constructor, ...) \
    static type I_##name;               \
    static int  I_##name##_initialized; \
    static int  I_##name##_destroyed;   \
    static void I_destroy_##name (void) \
    {                                   \
        destructor(get_##name());       \
        I_##name##_destroyed = 1;       \
    }                                   \
    type get_##name (void)                              \
    {                                                   \
        assert(!I_##name##_destroyed);                  \
        if (!I_##name##_initialized)                    \
        {                                               \
            I_##name = constructor(__VA_ARGS__);        \
            DestroyAtExit(I_destroy_##name, longevity); \
            I_##name##_initialized = 1;                 \
        }                                               \
        return I_##name;                                \
    }

typedef double longevity_t;

void DestroyAtExit (void (*destroyer)(void), longevity_t longevity);

/** singleton.c *************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

typedef struct tracker
{   void (*destroyer)(void);
    longevity_t  longevity;
} Tracker;

static Tracker      *TrackerArray = NULL;
static unsigned int  TrackerCount = 0;
static unsigned int  TrackerMax   = 16;

static void DestroyTop (void)
{
    Tracker top;
    
    assert(TrackerArray);
    assert(TrackerCount);

    top = TrackerArray[--TrackerCount];
    top.destroyer();
}

void DestroyAtExit (void (*destroyer)(void), longevity_t longevity)
{
    Tracker *t, *end;
    
    /* ensure that TrackerArray is large enough to hold one more element */
    if (TrackerCount == TrackerMax || !TrackerArray)
    {
        TrackerMax  *= 2;
        TrackerArray = realloc(TrackerArray, sizeof(Tracker) * TrackerMax);
        if (!TrackerArray) 
            printf("SetLongevity(): alloc failed\n");
    }
    assert(TrackerArray);
    
    /* make room for a new element at the right place in the TrackerArray */
    t   = TrackerArray;
    end = TrackerArray + TrackerCount; /* points to one past last element */
    while (t < end && t->longevity > longevity) 
        ++t;
    if (t != end) 
        memmove(t+1, t, (end - t) * sizeof(*t));
    TrackerCount++;

    /* initialize new element in the TrackerArray and register with atexit */
    t->destroyer = destroyer;
    t->longevity = longevity;
    atexit(DestroyTop);
}

/** test.c ******************************************************************/

DECLARE_SINGLETON(int *, alpha);
DECLARE_SINGLETON(int *, beta);

int *newFoo (int i) 
{ 
    int *p;
    
    p = (int *) malloc(sizeof(int));
    *p = i;
    return p;
}

void deleteInt(int *p) 
{ 
    printf("deleteInt(): %d\n", *p); 
    free(p); 
};

DEFINE_SINGLETON (int *, alpha, deleteInt, 1, newFoo, 5);
DEFINE_SINGLETON (int *, beta, deleteInt, 2, newFoo, 6);

int main(void)
{
    get_beta();
    get_alpha();
    return 0;
}