mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 12:56:14 +01:00 
			
		
		
		
	Partial commit of the greater MDEV-34348 scope. MDEV-34348: MariaDB is violating clang-16 -Wcast-function-type-strict The functions queue_compare, qsort2_cmp, and qsort_cmp2 all had similar interfaces, and were used interchangable and unsafely cast to one another. This patch consolidates the functions all into the qsort_cmp2 interface. Reviewed By: ============ Marko Mäkelä <marko.makela@mariadb.com>
		
			
				
	
	
		
			386 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			386 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 2010 Monty Program Ab
 | 
						|
   All Rights reserved
 | 
						|
 | 
						|
   Redistribution and use in source and binary forms, with or without
 | 
						|
   modification, are permitted provided that the following conditions are met:
 | 
						|
    * Redistributions of source code must retain the above copyright
 | 
						|
      notice, this list of conditions and the following disclaimer.
 | 
						|
    * Redistributions in binary form must reproduce the following disclaimer
 | 
						|
      in the documentation and/or other materials provided with the
 | 
						|
      distribution.
 | 
						|
 | 
						|
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
						|
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 | 
						|
  <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
						|
  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
						|
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
						|
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
						|
  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
  SUCH DAMAGE.
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
  This code originates from the Unireg project.
 | 
						|
 | 
						|
  Code for generell handling of priority Queues.
 | 
						|
  Implementation of queues from "Algorithms in C" by Robert Sedgewick.
 | 
						|
 | 
						|
  The queue can optionally store the position in queue in the element
 | 
						|
  that is in the queue. This allows one to remove any element from the queue
 | 
						|
  in O(1) time.
 | 
						|
 | 
						|
  Optimisation of _downheap() and queue_fix() is inspired by code done
 | 
						|
  by Mikael Ronström, based on an optimisation of _downheap from
 | 
						|
  Exercise 7.51 in "Data Structures & Algorithms in C++" by Mark Allen
 | 
						|
  Weiss, Second Edition.
 | 
						|
*/
 | 
						|
 | 
						|
#include "mysys_priv.h"
 | 
						|
#include "mysys_err.h"
 | 
						|
#include <queues.h>
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Init queue
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    init_queue()
 | 
						|
    queue		Queue to initialise
 | 
						|
    max_elements	Max elements that will be put in queue
 | 
						|
    offset_to_key	Offset to key in element stored in queue
 | 
						|
			Used when sending pointers to compare function
 | 
						|
    max_at_top		Set to 1 if you want biggest element on top.
 | 
						|
    compare		Compare function for elements, takes 3 arguments.
 | 
						|
    first_cmp_arg	First argument to compare function
 | 
						|
    offset_to_queue_pos If <> 0, then offset+1 in element to store position
 | 
						|
                        in queue (for fast delete of element in queue)
 | 
						|
    auto_extent         When the queue is full and there is insert operation
 | 
						|
                        extend the queue.
 | 
						|
 | 
						|
  NOTES
 | 
						|
    Will allocate max_element pointers for queue array
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0	ok
 | 
						|
    1	Could not allocate memory
 | 
						|
*/
 | 
						|
 | 
						|
int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
 | 
						|
	       my_bool max_at_top, qsort_cmp2 compare,
 | 
						|
	       void *first_cmp_arg, uint offset_to_queue_pos,
 | 
						|
               uint auto_extent)
 | 
						|
{
 | 
						|
  DBUG_ENTER("init_queue");
 | 
						|
  if ((queue->root= (uchar **) my_malloc(key_memory_QUEUE,
 | 
						|
                                         (max_elements + 1) * sizeof(void*),
 | 
						|
					 MYF(MY_WME))) == 0)
 | 
						|
    DBUG_RETURN(1);
 | 
						|
  queue->elements=      	0;
 | 
						|
  queue->compare=       	compare;
 | 
						|
  queue->first_cmp_arg= 	first_cmp_arg;
 | 
						|
  queue->max_elements=  	max_elements;
 | 
						|
  queue->offset_to_key= 	offset_to_key;
 | 
						|
  queue->offset_to_queue_pos=   offset_to_queue_pos;
 | 
						|
  queue->auto_extent=   	auto_extent;
 | 
						|
  queue_set_max_at_top(queue, max_at_top);
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Reinitialize queue for other usage
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    reinit_queue()
 | 
						|
    queue		Queue to initialise
 | 
						|
    For rest of arguments, see init_queue() above
 | 
						|
 | 
						|
  NOTES
 | 
						|
    This will delete all elements from the queue.  If you don't want this,
 | 
						|
    use resize_queue() instead.
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0			ok
 | 
						|
    1			Wrong max_elements; Queue has old size
 | 
						|
*/
 | 
						|
 | 
						|
int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
 | 
						|
		 my_bool max_at_top, qsort_cmp2 compare,
 | 
						|
		 void *first_cmp_arg, uint offset_to_queue_pos,
 | 
						|
                 uint auto_extent)
 | 
						|
{
 | 
						|
  DBUG_ENTER("reinit_queue");
 | 
						|
  queue->elements=		0;
 | 
						|
  queue->compare=		compare;
 | 
						|
  queue->first_cmp_arg=		first_cmp_arg;
 | 
						|
  queue->offset_to_key=		offset_to_key;
 | 
						|
  queue->offset_to_queue_pos=   offset_to_queue_pos;
 | 
						|
  queue->auto_extent= 		auto_extent;
 | 
						|
  queue_set_max_at_top(queue, max_at_top);
 | 
						|
  DBUG_RETURN(resize_queue(queue, max_elements));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Resize queue
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    resize_queue()
 | 
						|
    queue			Queue
 | 
						|
    max_elements		New max size for queue
 | 
						|
 | 
						|
  NOTES
 | 
						|
    If you resize queue to be less than the elements you have in it,
 | 
						|
    the extra elements will be deleted
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0	ok
 | 
						|
    1	Error.  In this case the queue is unchanged
 | 
						|
*/
 | 
						|
 | 
						|
int resize_queue(QUEUE *queue, uint max_elements)
 | 
						|
{
 | 
						|
  uchar **new_root;
 | 
						|
  DBUG_ENTER("resize_queue");
 | 
						|
  if (queue->max_elements == max_elements)
 | 
						|
    DBUG_RETURN(0);
 | 
						|
  if ((new_root= (uchar **) my_realloc(key_memory_QUEUE, (void *)queue->root,
 | 
						|
                                       (max_elements + 1)* sizeof(void*),
 | 
						|
                                       MYF(MY_WME))) == 0)
 | 
						|
    DBUG_RETURN(1);
 | 
						|
  set_if_smaller(queue->elements, max_elements);
 | 
						|
  queue->max_elements= max_elements;
 | 
						|
  queue->root= new_root;
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Delete queue
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
   delete_queue()
 | 
						|
   queue		Queue to delete
 | 
						|
 | 
						|
  IMPLEMENTATION
 | 
						|
    Just free allocated memory.
 | 
						|
 | 
						|
  NOTES
 | 
						|
    Can be called safely multiple times
 | 
						|
*/
 | 
						|
 | 
						|
void delete_queue(QUEUE *queue)
 | 
						|
{
 | 
						|
  DBUG_ENTER("delete_queue");
 | 
						|
  my_free(queue->root);
 | 
						|
  queue->root=0;                              /* Allow multiple calls */
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void insert_at(QUEUE *queue, uchar *element, uint idx)
 | 
						|
{
 | 
						|
  uint next_index, offset_to_key= queue->offset_to_key;
 | 
						|
  uint offset_to_queue_pos= queue->offset_to_queue_pos;
 | 
						|
  /* max_at_top swaps the comparison if we want to order by desc */
 | 
						|
  while ((next_index= idx >> 1) > 0 &&
 | 
						|
          queue->compare(queue->first_cmp_arg,
 | 
						|
                         element + offset_to_key,
 | 
						|
                         queue->root[next_index] + offset_to_key) *
 | 
						|
          queue->max_at_top < 0)
 | 
						|
  {
 | 
						|
    queue->root[idx]= queue->root[next_index];
 | 
						|
    if (offset_to_queue_pos)
 | 
						|
      (*(uint*) (queue->root[idx] + offset_to_queue_pos-1))= idx;
 | 
						|
    idx= next_index;
 | 
						|
  }
 | 
						|
  queue->root[idx]= element;
 | 
						|
  if (offset_to_queue_pos)
 | 
						|
    (*(uint*) (element + offset_to_queue_pos-1))= idx;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Insert element in queue
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    queue_insert()
 | 
						|
    queue		Queue to use
 | 
						|
    element		Element to insert
 | 
						|
*/
 | 
						|
 | 
						|
void queue_insert(QUEUE *queue, uchar *element)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(queue->elements < queue->max_elements);
 | 
						|
  insert_at(queue, element, ++queue->elements);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Like queue_insert, but resize queue if queue is full
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    queue_insert_safe()
 | 
						|
    queue		Queue to use
 | 
						|
    element		Element to insert
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0	OK
 | 
						|
    1	Cannot allocate more memory
 | 
						|
    2   auto_extend is 0; No insertion done
 | 
						|
*/
 | 
						|
 | 
						|
int queue_insert_safe(QUEUE *queue, uchar *element)
 | 
						|
{
 | 
						|
 | 
						|
  if (queue->elements == queue->max_elements)
 | 
						|
  {
 | 
						|
    if (!queue->auto_extent)
 | 
						|
      return 2;
 | 
						|
    if (resize_queue(queue, queue->max_elements + queue->auto_extent))
 | 
						|
      return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  queue_insert(queue, element);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Remove item from queue
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    queue_remove()
 | 
						|
    queue		Queue to use
 | 
						|
    element		Index of element to remove.
 | 
						|
			First element in queue is 'queue_first_element(queue)'
 | 
						|
 | 
						|
  RETURN
 | 
						|
   pointer to removed element
 | 
						|
*/
 | 
						|
 | 
						|
uchar *queue_remove(QUEUE *queue, uint idx)
 | 
						|
{
 | 
						|
  uchar *element;
 | 
						|
  DBUG_ASSERT(idx >= 1);
 | 
						|
  DBUG_ASSERT(idx <= queue->elements);
 | 
						|
  element= queue->root[idx];
 | 
						|
  queue->root[idx]= queue->root[queue->elements--];
 | 
						|
  queue_replace(queue, idx);
 | 
						|
  return element;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Restores the heap property from idx down the heap
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    _downheap()
 | 
						|
    queue	Queue to use
 | 
						|
    idx         Index of element to change
 | 
						|
*/
 | 
						|
 | 
						|
void _downheap(QUEUE *queue, uint idx)
 | 
						|
{
 | 
						|
  uchar *element= queue->root[idx];
 | 
						|
  uint   next_index,
 | 
						|
         elements= queue->elements,
 | 
						|
         half_queue= elements >> 1,
 | 
						|
         offset_to_key= queue->offset_to_key,
 | 
						|
         offset_to_queue_pos= queue->offset_to_queue_pos;
 | 
						|
 | 
						|
  while (idx <= half_queue)
 | 
						|
  {
 | 
						|
    next_index= idx+idx;
 | 
						|
    if (next_index < elements &&
 | 
						|
        (queue->compare(queue->first_cmp_arg,
 | 
						|
                        queue->root[next_index]+offset_to_key,
 | 
						|
                        queue->root[next_index+1]+offset_to_key) *
 | 
						|
         queue->max_at_top) > 0)
 | 
						|
      next_index++;
 | 
						|
    if ((queue->compare(queue->first_cmp_arg,
 | 
						|
                        queue->root[next_index]+offset_to_key,
 | 
						|
                        element+offset_to_key) * queue->max_at_top) >= 0)
 | 
						|
      break;
 | 
						|
    queue->root[idx]= queue->root[next_index];
 | 
						|
    if (offset_to_queue_pos)
 | 
						|
      (*(uint*) (queue->root[idx] + offset_to_queue_pos-1))= idx;
 | 
						|
    idx= next_index;
 | 
						|
  }
 | 
						|
  queue->root[idx]=element;
 | 
						|
  if (offset_to_queue_pos)
 | 
						|
    (*(uint*) (element + offset_to_queue_pos-1))= idx;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Fix heap when every element was changed.
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    queue_fix()
 | 
						|
    queue	Queue to use
 | 
						|
*/
 | 
						|
 | 
						|
void queue_fix(QUEUE *queue)
 | 
						|
{
 | 
						|
  uint i;
 | 
						|
  for (i= queue->elements >> 1; i > 0; i--)
 | 
						|
    _downheap(queue, i);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Change element at fixed position
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    queue_replace()
 | 
						|
    queue	Queue to use
 | 
						|
    idx         Index of element to change
 | 
						|
 | 
						|
  NOTE
 | 
						|
    optimized for the case when the new position is close to the end of the
 | 
						|
    heap (typical for queue_remove() replacements).
 | 
						|
*/
 | 
						|
 | 
						|
void queue_replace(QUEUE *queue, uint idx)
 | 
						|
{
 | 
						|
  uchar *element= queue->root[idx];
 | 
						|
  uint next_index,
 | 
						|
       elements= queue->elements,
 | 
						|
       half_queue= elements>>1,
 | 
						|
       offset_to_key= queue->offset_to_key,
 | 
						|
       offset_to_queue_pos= queue->offset_to_queue_pos;
 | 
						|
  my_bool first= TRUE;
 | 
						|
 | 
						|
  while (idx <= half_queue)
 | 
						|
  {
 | 
						|
    next_index= idx + idx;
 | 
						|
    if (next_index < elements &&
 | 
						|
	queue->compare(queue->first_cmp_arg,
 | 
						|
			queue->root[next_index]+offset_to_key,
 | 
						|
			queue->root[next_index+1]+offset_to_key) *
 | 
						|
	 queue->max_at_top > 0)
 | 
						|
      next_index++;
 | 
						|
    if (first &&
 | 
						|
        queue->compare(queue->first_cmp_arg,
 | 
						|
                        queue->root[next_index]+offset_to_key,
 | 
						|
                        element+offset_to_key) * queue->max_at_top >= 0)
 | 
						|
    {
 | 
						|
      queue->root[idx]= element;
 | 
						|
      if (offset_to_queue_pos)
 | 
						|
        (*(uint*) (element + offset_to_queue_pos-1))= idx;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    first= FALSE;
 | 
						|
    queue->root[idx]= queue->root[next_index];
 | 
						|
    if (offset_to_queue_pos)
 | 
						|
      (*(uint*) (queue->root[idx] + offset_to_queue_pos-1))= idx;
 | 
						|
    idx=next_index;
 | 
						|
  }
 | 
						|
 | 
						|
  insert_at(queue, element, idx);
 | 
						|
}
 |