/**
 * Dynamic array of pointers with versioned handle. Entries are made accessible
 * through an handle; each handle contains both an index and a version counter.
 * 
 *    RATIONALE. When complex data structures are used in programs, with
 *    many cross references, versioned handles make easier to detect accesses
 *    to stale entries. Simple arrays and pointers are not safe to this aim.
 * 
 * Entries can be occupied or detached. The difference is that occupied entries
 * are freely accessible through their handle and can be scanned sequentially.
 * Detached entries can be recycled to reuse their space, but a brand new handle
 * is assigned to them. Any attempt to access a detached entry or invalid handle
 * is fatal.
 * 
 * The zero value is never a valid handle just like NULL for pointer, so it is
 * safe to initialize data structures to zero.
 * 
 * To add an entry, it is mandatory to first check if a detached entry is
 * available before attempting to allocate a new entry. Typical example:
 * 
 * <pre>
 * varray_Type *va = ...array of string buffers...
 * int handle = varray_getDetachedHandle(va);
 * if( handle == 0 )
 *     handle = varray_addValue(va, malloc(100));
 * </pre>
 * 
 * Retrieving an entry given its handle:
 * 
 * <pre>char *s = varray_getValue(va, handle);</pre>
 * 
 * Detaching an entry we may want to reuse later, but invalidating its current
 * handle so nobody can access it anymore and, if it does so, aborts:
 * 
 * <pre>varray_detach(s_handle);</pre>
 * 
 * Checking if an handle is still referring a fresh, occupied entry:
 * 
 * <pre>if( varray_isValidHandle(buffers, s_handle) ) ...</pre>
 * 
 * Sequential access to the elements of the array is allowed in constant time
 * through an internal cursor: varray_firstHandle() returns the handle of the
 * first occupied entry, and varray_nextHandle() moves the cursor to the next
 * entry:
 * 
 * <pre>
 * for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va))
 *     printf("%s\n", (char *) varray_getValue(va, i));
 * varray_releaseIterator(va);
 * </pre>
 * 
 * In this implementation, only one iteration at a time is allowed per array;
 * the firstHandle() method sets the internal lock on this iterator, and the
 * releaseIterator() release this lock, so each call to firstHandle() must be
 * balanced by a corresponding call to releaseHandle(); nested usage of the
 * same iterator is a fatal error.
 * 
 * The current entry under the cursor can be detached; scanning continues with
 * the next entry.
 * 
 * Note that dynamic arrays never attempt to access the values stored, and neither
 * attempt to release them from memory. Releasing entries is in charge of the
 * client. One safe way to do that is to detach the occupied entries and then
 * reclaim and release each entry:
 * 
 * <pre>
 * for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va)){
 *     programSpecificTurnOffProcedure(i);
 *     varray_detach(va, i);
 * }
 * varray_releaseIterator(va);
 * while( (i = varray_getDetacheddHandle) != 0 )
 *     memory_dispose( varray_getValue(va, i) );
 * memory_dispose(va);
 * </pre>
 * 
 * @file
 * @author Umberto Salsi <salsi@icosaedro.it>
 * @version $Date: 2017/10/29 01:28:37 $
 */

#ifndef VARRAY_H
#define VARRAY_H

#ifdef varray_IMPORT
	#define EXTERN
#else
	#define EXTERN extern
#endif

typedef struct varray_Type varray_Type;

/**
 * Allocates a new empty array.
 * @return New array. Must be released with memory_dispose().
 */
EXTERN varray_Type * varray_new(void);

/**
 * Returns the number of occupied entries, that is the number of entries that
 * would be returned in sequential scanning.
 * @param this
 * @return 
 */
EXTERN int varray_length(varray_Type *this);

/**
 * Returns the value at a specified handle of occupied entry. Aborts if:
 * invalid handle; entry is now detached; entry has been detached and reused
 * and then the handle is "stale".
 * See also: varray_isValidHandle().
 * @param this
 * @param handle
 * @return Value allocated in the specified entry.
 */
EXTERN void * varray_getValue(varray_Type *this, int handle);

/**
 * Returns the handle of a previously detached entry, making it 'occupied'
 * again. Note that the returned handle differs from that the entry had before.
 * If no detached entries available, returns 0 and the client has to add a new
 * entry.
 * See also: varray_addValue().
 * @param this
 * @return Handle of a previously detached entry, or 0 if no detached entries
 * are available.
 */
EXTERN int varray_getDetachedHandle(varray_Type *this);

/**
 * Adds a new entry, marking it as occupied. Client MUST always try to reuse
 * an existing detached entry by calling varray_getDetachedHandle() first;
 * invoking this function when detached entries are available is fatal.
 * @param this
 * @param value Value to set.
 * @return Handle of the newly allocated entry.
 */
EXTERN int varray_addValue(varray_Type *this, void *value);

/**
 * Sets the value of a currently occupied entry. Aborts if: invalid handle;
 * handle of detached entry.
 * @param this
 * @param handle Handle of the occupied entry.
 * @param value New value to set.
 */
EXTERN void varray_setValue(varray_Type *this, int handle, void *value);

/**
 * Returns true if the given handle refers to a occupied entry.
 * @param this
 * @param handle
 * @return True if the given handle refers to a occupied entry. False in any
 * other case.
 */
EXTERN int varray_isValidHandle(varray_Type *this, int handle);

/**
 * Detaches entry, so it is not returned in scanning.
 * @param this
 * @param handle
 */
EXTERN void varray_detach(varray_Type *this, int handle);

/**
 * Returns the handle to a first used entry from which to start
 * sequential scanning of the used entries. The exact order of the entries
 * returned in scanning is not specified, although it mostly follows the same
 * order the entries where added. Set a lock on the array iterator which MUST be
 * reset later with varray_releaseIterator().
 * See also: varray_nextHandle().
 * @param this
 * @return Handle of the first entry from which starting scanning, or 0 if there
 * are no currently used entries.
 */
EXTERN int varray_firstHandle(varray_Type *this);

/**
 * Returns the handle to the next used entry.
 * See also: varray_firstHandle().
 * @param this
 * @param handle Handle of the current entry being scanned, or 0 at the end of
 * the list of occupied entries.
 */
EXTERN int varray_nextHandle(varray_Type *this);

/**
 * Releases the lock on the iterator bound to this array.
 * @param this
 */
EXTERN void varray_releaseIterator(varray_Type *this);

#undef EXTERN
#endif
