mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
2aecdd1a91
(All commit emails since 4.0.1 checked) This had to be done now, before the 4.1 tree changes to much, to make it easy to propagate bug fixes to the 4.1 tree.
187 lines
4.8 KiB
C
187 lines
4.8 KiB
C
/* Copyright (C) 2000 MySQL AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/*
|
|
Code for generell handling of priority Queues.
|
|
Implemention of queues from "Algoritms in C" by Robert Sedgewick.
|
|
*/
|
|
|
|
#include "mysys_priv.h"
|
|
#include "mysys_err.h"
|
|
#include <queues.h>
|
|
|
|
|
|
/* Init queue */
|
|
|
|
int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
|
|
pbool max_at_top, int (*compare) (void *, byte *, byte *),
|
|
void *first_cmp_arg)
|
|
{
|
|
DBUG_ENTER("init_queue");
|
|
if ((queue->root= (byte **) my_malloc((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->max_at_top= max_at_top ? (-1 ^ 1) : 0;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*
|
|
Reinitialize queue for new usage; Note that you can't currently resize
|
|
the number of elements! If you need this, fix it :)
|
|
*/
|
|
|
|
|
|
int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
|
|
pbool max_at_top, int (*compare) (void *, byte *, byte *),
|
|
void *first_cmp_arg)
|
|
{
|
|
DBUG_ENTER("reinit_queue");
|
|
if (queue->max_elements < max_elements)
|
|
/* It's real easy to do realloc here, just don't want to bother */
|
|
DBUG_RETURN(my_errno=EE_OUTOFMEMORY);
|
|
|
|
queue->elements=0;
|
|
queue->compare=compare;
|
|
queue->first_cmp_arg=first_cmp_arg;
|
|
queue->offset_to_key=offset_to_key;
|
|
queue->max_at_top= max_at_top ? (-1 ^ 1) : 0;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
void delete_queue(QUEUE *queue)
|
|
{
|
|
DBUG_ENTER("delete_queue");
|
|
if (queue->root)
|
|
{
|
|
my_free((gptr) queue->root,MYF(0));
|
|
queue->root=0;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/* Code for insert, search and delete of elements */
|
|
|
|
void queue_insert(register QUEUE *queue, byte *element)
|
|
{
|
|
reg2 uint idx,next;
|
|
int cmp;
|
|
|
|
#ifndef DBUG_OFF
|
|
if (queue->elements < queue->max_elements)
|
|
#endif
|
|
{
|
|
queue->root[0]=element;
|
|
idx= ++queue->elements;
|
|
|
|
/* max_at_top swaps the comparison if we want to order by desc */
|
|
while ((cmp=queue->compare(queue->first_cmp_arg,
|
|
element+queue->offset_to_key,
|
|
queue->root[(next=idx >> 1)] +
|
|
queue->offset_to_key)) &&
|
|
(cmp ^ queue->max_at_top) < 0)
|
|
{
|
|
queue->root[idx]=queue->root[next];
|
|
idx=next;
|
|
}
|
|
queue->root[idx]=element;
|
|
}
|
|
}
|
|
|
|
/* Remove item from queue */
|
|
/* Returns pointer to removed element */
|
|
|
|
byte *queue_remove(register QUEUE *queue, uint idx)
|
|
{
|
|
#ifndef DBUG_OFF
|
|
if (idx >= queue->max_elements)
|
|
return 0;
|
|
#endif
|
|
{
|
|
byte *element=queue->root[++idx]; /* Intern index starts from 1 */
|
|
queue->root[idx]=queue->root[queue->elements--];
|
|
_downheap(queue,idx);
|
|
return element;
|
|
}
|
|
}
|
|
|
|
/* Fix when element on top has been replaced */
|
|
|
|
#ifndef queue_replaced
|
|
void queue_replaced(queue)
|
|
QUEUE *queue;
|
|
{
|
|
_downheap(queue,1);
|
|
}
|
|
#endif
|
|
|
|
/* Fix heap when index have changed */
|
|
|
|
void _downheap(register QUEUE *queue, uint idx)
|
|
{
|
|
byte *element;
|
|
uint elements,half_queue,next_index,offset_to_key;
|
|
int cmp;
|
|
|
|
offset_to_key=queue->offset_to_key;
|
|
element=queue->root[idx];
|
|
half_queue=(elements=queue->elements) >> 1;
|
|
|
|
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 ((cmp=queue->compare(queue->first_cmp_arg,
|
|
queue->root[next_index]+offset_to_key,
|
|
element+offset_to_key)) == 0 ||
|
|
(cmp ^ queue->max_at_top) > 0)
|
|
break;
|
|
queue->root[idx]=queue->root[next_index];
|
|
idx=next_index;
|
|
}
|
|
queue->root[idx]=element;
|
|
}
|
|
|
|
|
|
static int queue_fix_cmp(QUEUE *queue, void **a, void **b)
|
|
{
|
|
return queue->compare(queue->first_cmp_arg,
|
|
(char*) (*a)+queue->offset_to_key,
|
|
(char*) (*b)+queue->offset_to_key);
|
|
}
|
|
|
|
/*
|
|
Fix heap when every element was changed
|
|
actually, it can be done in linear time,
|
|
not in n*log(n), but some code (myisam/ft_boolean_search.c)
|
|
requires a strict order here, not just a queue property
|
|
*/
|
|
|
|
void queue_fix(QUEUE *queue)
|
|
{
|
|
qsort2(queue->root+1,queue->elements, sizeof(void *),
|
|
(qsort2_cmp)queue_fix_cmp, queue);
|
|
}
|