// QUEUE.C
// Queue functions
// © 2021 Peter J. Meyer
// A circular queue is used, that is, when the queue pointers
// exceed queue memory space they wrap around.
#include "iss.h"
#define queue_size stack_size
// Queue and stack use same memory.
// stack_size = number of short ints, not number of bytes.
#define abs_queue_start stack
// address of queue memory space.
#define abs_queue_end (stack+stack_size)
// address of 1st short int beyond queue memory space.
short int *queue_start;
// address of 1st short int in queue.
short int *queue_end;
// address of 1st short int beyond last item in queue
// Thes are referenced by allocate_memory_for_stack().
int max_num_items_in_queue;
unsigned int queue_limit_reached;
unsigned int queue_limit_reached_overflow;
unsigned long total_queue_pushes;
static int num_items_in_queue(void);
static int num_free_places_in_queue(void);
static void queue_increment(short int **queue_ptr);
/*------------------*/
void clear_queue(void)
{
if ( !queue_size )
{
printf("\nQueue not allocated!\n");
exit(1);
}
queue_start = queue_end = abs_queue_start;
}
/*-----------------*/
int queue_empty(void)
{
return ( queue_end == queue_start );
}
/*-------------------------------------*/
void check_queue_is_empty(char *location)
{
if ( !queue_empty() )
{
printf("\nQueue not empty (in %s).\n",location);
exit(1);
}
}
#if false
/*----------------------------------------------*/
int push_onto_queue(short int i, short int j, ...)
{
// int k, l;
if ( stack_ptr + dimensionality > end_of_stack )
{
if ( stack_limit_reached + 1 == 0 )
stack_limit_reached_overflow = true;
else
stack_limit_reached++;
return ( false );
}
total_stack_pushes++;
*(stack_ptr++) = i;
*(stack_ptr++) = j;
switch ( dimensionality )
{
case 3:
// k = *(((int *)(&j))+1);
*(stack_ptr++) = *(((int *)(&j))+1);
break;
case 4:
// k = *(((int *)(&j))+1);
// l = *(((int *)(&j))+2);
*(stack_ptr++) = *(((int *)(&j))+1);
*(stack_ptr++) = *(((int *)(&j))+2);
break;
}
if ( stack_ptr > max_stack_ptr )
max_stack_ptr = stack_ptr;
return ( true );
}
/*-----------------------------------------------------*/
int pop_from_stack(short int *iptr, short int *jptr, ...)
{
short int *kptr, *lptr;
if ( stack_ptr < stack + dimensionality )
return ( false );
// Must decrement stack pointer *before* popping stack value.
switch ( dimensionality )
{
case 3:
kptr = *(((short int **)(&jptr))+1);
*kptr = *(--stack_ptr);
break;
case 4:
kptr = *(((short int **)(&jptr))+1);
lptr = *(((short int **)(&jptr))+2);
*lptr = *(--stack_ptr);
*kptr = *(--stack_ptr);
break;
}
*jptr = *(--stack_ptr);
*iptr = *(--stack_ptr);
return ( true );
}
#endif
/*-------------------------------*/
static int num_items_in_queue(void)
{
if ( queue_start <= queue_end )
return ( queue_end - queue_start );
else
// queue_end < queue_start, so queue wraps around.
return ( queue_end + queue_size - queue_start );
}
/*-------------------------------------*/
static int num_free_places_in_queue(void)
{
return ( queue_size - num_items_in_queue() );
}
// This adds items to the end of the queue.
/*------------------------------------------------------------------*/
int push_onto_queue_with_n(short int n, short int i, short int j, ...)
{
int k, l;
if ( num_free_places_in_queue() < dimensionality + 1 )
{
if ( queue_limit_reached + 1 == 0 )
queue_limit_reached_overflow = true;
else
queue_limit_reached++;
return ( false );
}
total_queue_pushes++;
*queue_end = n;
queue_increment(&queue_end);
*queue_end = i;
queue_increment(&queue_end);
*queue_end = j;
queue_increment(&queue_end);
switch ( dimensionality )
{
case 3:
k = *(((int *)(&j))+1);
*queue_end = k;
queue_increment(&queue_end);
break;
case 4:
k = *(((int *)(&j))+1);
l = *(((int *)(&j))+2);
// *(stack_ptr++) = *(((int *)(&j))+1);
// *(stack_ptr++) = *(((int *)(&j))+2);
*queue_end = k;
queue_increment(&queue_end);
*queue_end = l;
queue_increment(&queue_end);
break;
}
if ( num_items_in_queue() > max_num_items_in_queue )
max_num_items_in_queue = num_items_in_queue();
return ( true );
}
// This removes items from the start of the queue.
// Unlike with a stack, with a queue items are popped
// in the order in which they were pushed.
/*-----------------------------------------------------------------------------*/
int pop_from_queue_with_n(short int *nptr, short int *iptr, short int *jptr, ...)
{
short int *kptr, *lptr;
if ( num_items_in_queue() < dimensionality + 1 )
return ( false );
*nptr = *queue_start;
queue_increment(&queue_start);
*iptr = *queue_start;
queue_increment(&queue_start);
*jptr = *queue_start;
queue_increment(&queue_start);
switch ( dimensionality )
{
case 3:
kptr = *(((short int **)(&jptr))+1);
*kptr = *queue_start;
queue_increment(&queue_start);
break;
case 4:
kptr = *(((short int **)(&jptr))+1);
lptr = *(((short int **)(&jptr))+2);
*kptr = *queue_start;
queue_increment(&queue_start);
*lptr = *queue_start;
queue_increment(&queue_start);
break;
}
return ( true );
}
// This adds 1 to queue_ptr with wrap-around
// if new queue_ptr is out of queue memory.
// This function assumes that queue_ptr is within queue memory space.
/*---------------------------------------*/
void queue_increment(short int **queue_ptr)
{
if ( ++(*queue_ptr) == abs_queue_end )
*queue_ptr = abs_queue_start;
}
// This assumes that we are writing to a file already.
/*---------------------------*/
void write_queue_data(FILE *of)
{
int queue_size_in_bytes = queue_size*sizeof(short int);
int short_ints_per_queue_push;
fprintf(of,"\n\nTotal number of queue pushes = %s",ultoa_commas(total_queue_pushes,temp));
// short_ints_per_stack_push = ( dynamics_is_swendsen_wang ?
// SHORT_INTS_PER_SWENDSEN_WANG_STACK_PUSH : SHORT_INTS_PER_WOLFF_STACK_PUSH );
short_ints_per_queue_push = dimensionality + 1;
fprintf(of,"\nMaximum consecutive stack pushes = %s",
ultoa_commas(max_num_items_in_queue/short_ints_per_queue_push,temp1));
fprintf(of,"\n%.2f%% of the queue was used (queue size = ",
((double)max_num_items_in_queue*100)/queue_size);
if ( queue_size_in_bytes < 10000 )
fprintf(of,"%d bytes).",queue_size_in_bytes);
else
{
ultoa_commas(queue_size_in_bytes/1024,temp);
fprintf(of,"%s KB).",temp);
}
if ( queue_limit_reached )
{
fprintf(of,"\nQueue limit was reached ");
if ( queue_limit_reached_overflow )
fprintf(of,"more than ");
fprintf(of,"%s time%s.\n",ultoa_commas(queue_limit_reached,temp),
(queue_limit_reached==1 ? "" : "s" ));
}
fprintf(of,"\n");
}
#if false
// Queue and stack use same memory.
// stack_size is a global variable.
/*--------------------------------*/
void allocate_memory_for_stack(void)
{
int err_flag;
// stack_size = number of short ints, not number of bytes.
if ( !stack_size )
{
printf("\nAttempt to allocate stack of zero size.\n");
exit(1);
}
stack = (A1(short int))array_alloc(&err_flag, sizeof(short int),
NULL, 1, stack_size);
if ( err_flag )
{
printf("\nError %d when attempting to allocate an array of %d short ints for stack.\n",
err_flag,stack_size);
exit(1);
}
end_of_stack = stack + stack_size; // These are pointers to ints.
max_stack_ptr = stack;
stack_limit_reached = 0;
stack_limit_reached_overflow = false;
total_stack_pushes = 0;
}
#endif