/*---------------------------------------------------------------------------
* Arraylist utility functions.
*
*---------------------------------------------------------------------------
* These functions help to assemble an array whose length is unknown at the
* beginning. So at first all elements are kept in a singly linked list
* until finalize_arraylist is called.
*
* The linked list is saved as an error handler in a svalue_t, so it will
* destruct itself and all of its elements automatically when the svalue_t
* is freed.
*
* This structure is not designed to survive a garbage_collection.
* It should always be finalized or freed in the same execution thread.
*---------------------------------------------------------------------------
*/
#include "driver.h"
#include "typedefs.h"
#include "array.h"
#include "arraylist.h"
#include "interpret.h"
#include "simulate.h"
#include "svalue.h"
#include "xalloc.h"
/*-------------------------------------------------------------------------*/
/* Types */
typedef struct arraylist_s arraylist_t;
typedef struct arraylist_element_s arraylist_element_t;
struct arraylist_s
{
svalue_t head; /* The error handler. */
arraylist_element_t *first;
arraylist_element_t *last;
int num;
};
struct arraylist_element_s
{
svalue_t value;
arraylist_element_t * next;
};
/*-------------------------------------------------------------------------*/
static void
cleanup_arraylist (svalue_t * list)
/* Our cleanup handler, called when the arraylist is freed.
*/
{
arraylist_t * data = (arraylist_t *) list;
arraylist_element_t * element = data->first;
while (element)
{
arraylist_element_t * temp = element;
element = element->next;
free_svalue(&(temp->value));
xfree(temp);
}
xfree(data);
}
/*-------------------------------------------------------------------------*/
void
put_arraylist (svalue_t * list)
/* Create an arraylist and put it into <list>.
*/
{
arraylist_t * data;
memsafe(data = xalloc(sizeof(*data)), sizeof(*data), "arraylist");
data->head.type = T_ERROR_HANDLER;
data->head.u.error_handler = cleanup_arraylist;
data->num = 0;
data->first = NULL;
data->last = NULL;
list->type = T_LVALUE;
list->u.lvalue = &(data->head);
} /* put_arraylist() */
/*-------------------------------------------------------------------------*/
svalue_t *
enhance_arraylist (svalue_t * list)
/* Add an element to the arraylist to <list>.
* It is the responsibility of the caller to ensure
* that <list> is in fact an arraylist.
*/
{
arraylist_t * data = (arraylist_t *) list->u.lvalue;
arraylist_element_t * element;
memsafe(element = xalloc(sizeof(*element)), sizeof(*element), "arraylist element");
element->next = NULL;
put_number(&(element->value), 0);
if (data->last == NULL)
{
data->first = element;
data->last = element;
}
else
{
data->last->next = element;
data->last = element;
}
data->num++;
return &(element->value);
} /* enhance_arraylist() */
/*-------------------------------------------------------------------------*/
void
finalize_arraylist (svalue_t * list)
/* Turn the arraylist in <list> into a proper array.
*/
{
arraylist_t * data = (arraylist_t *) list->u.lvalue;
arraylist_element_t * element;
vector_t * result;
svalue_t * item;
result = allocate_array(data->num);
element = data->first;
item = result->item;
while (element)
{
arraylist_element_t * temp = element;
*item = element->value;
item++;
element = element->next;
xfree(temp);
}
xfree(data);
put_array(list, result);
} /* finalize_arraylist() */