// 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