/******************************************************************
 * Atom.h
 * The atom definition and assorted miscellania, ie: futures, etc.
 ******************************************************************/
#ifndef __ATOM
#define __ATOM

/******************************************************************
 * PROTO DEFS
 ******************************************************************/
uMonitor SYMTABLE;
uTask EVALUATE;
struct ATOM_HEAP;
uMonitor ATOM_MNGR;

/******************************************************************
 * DEFINES
 ******************************************************************/
#define SMALL_ATOM_HEAP_SIZE 127
// Applies with the atom management utilities of THIS thread, NOT the
// atoms actual thread - must be careful to only operate on atoms
// with same thread created on.  Communication to/from external
// tasks goes through external thread.  Future results are copied
// into the global thread... (Is this a hit to concurrency?)
#define GLB_GetAtomHeap (*(((EVALUATE *) &uThisTask())->getAtomManager()))

/******************************************************************
 * STRUCTURES
 ******************************************************************/
union DATA
{
    int      i;
    void    *p;     // ASCIZ, or FUTURE
    float     f;
};

struct ATOM
{
    int type;
    int quote;
    DATA data;
    ATOM *next;
#ifdef ATOM_DEBUG
    ATOM_MNGR *owner;
#endif
};

struct ATOM_SMALL_HEAP
{
    ATOM_HEAP *next;
    ATOM atoms[SMALL_ATOM_HEAP_SIZE];
};

/******************************************************************
 * CLASSES
 ******************************************************************/
// The atom manager is responsible for creating/destroying atoms
// in a thread safe fashion.
// This is likely to be the biggest hit to concurrency.
uMonitor ATOM_MNGR
{
    ATOM_HEAP *m_heap;      // Storage for atoms....
    ATOM *m_freelist;
    int   m_hasstartheap;   // Is initial stack heap present?
public:
    ATOM_MNGR(ATOM_SMALL_HEAP *startheap = NULL);
    ~ATOM_MNGR();

    void Destroy(ATOM *atom);
    ATOM *Alloc();
    ATOM *CreateFalse();
    ATOM *CreateTrue();
    ATOM *Duplicate(ATOM *atom);
};

// The future monitor is responsible for blocking fetches until it
// is completed.
uMonitor FUTURE
{
    int          m_refcnt;
    ATOM        *m_result;          // Result of calculation
    uCondition   m_wait;

    ~FUTURE();              // Handled by refcnts.
public:
    FUTURE();

    void addRef();
    void removeRef();

    ATOM *getData();        // Blocks if not availaible!
    void writeData(ATOM *data);     // Alert it is done!
    uNoMutex bool isReady() const;		// Test if done yet?
};

/******************************************************************
 * GLOBAL VARIABLES
 ******************************************************************/
extern ATOM_MNGR glbAtomMgr;

/******************************************************************
 * FUNCTION PROTOTYPES
 ******************************************************************/
void PrintAtom(ATOM *atom, uOStream &output);
void PrintExpandAtom(ATOM *atom, SYMTABLE *local, uOStream &output);
ATOM *ParseLine(char *in, int *pos, int onexpr=0);

#endif
