Blame libevent/minheap-internal.h

Packit e9ba0d
/*
Packit e9ba0d
 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
Packit e9ba0d
 *
Packit e9ba0d
 * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
Packit e9ba0d
 *
Packit e9ba0d
 * Redistribution and use in source and binary forms, with or without
Packit e9ba0d
 * modification, are permitted provided that the following conditions
Packit e9ba0d
 * are met:
Packit e9ba0d
 * 1. Redistributions of source code must retain the above copyright
Packit e9ba0d
 *    notice, this list of conditions and the following disclaimer.
Packit e9ba0d
 * 2. Redistributions in binary form must reproduce the above copyright
Packit e9ba0d
 *    notice, this list of conditions and the following disclaimer in the
Packit e9ba0d
 *    documentation and/or other materials provided with the distribution.
Packit e9ba0d
 * 3. The name of the author may not be used to endorse or promote products
Packit e9ba0d
 *    derived from this software without specific prior written permission.
Packit e9ba0d
 *
Packit e9ba0d
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Packit e9ba0d
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit e9ba0d
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit e9ba0d
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit e9ba0d
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit e9ba0d
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit e9ba0d
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit e9ba0d
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit e9ba0d
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit e9ba0d
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit e9ba0d
 */
Packit e9ba0d
#ifndef _MIN_HEAP_H_
Packit e9ba0d
#define _MIN_HEAP_H_
Packit e9ba0d
Packit e9ba0d
#include "event2/event-config.h"
Packit e9ba0d
#include "event2/event.h"
Packit e9ba0d
#include "event2/event_struct.h"
Packit e9ba0d
#include "event2/util.h"
Packit e9ba0d
#include "util-internal.h"
Packit e9ba0d
#include "mm-internal.h"
Packit e9ba0d
Packit e9ba0d
typedef struct min_heap
Packit e9ba0d
{
Packit e9ba0d
	struct event** p;
Packit e9ba0d
	unsigned n, a;
Packit e9ba0d
} min_heap_t;
Packit e9ba0d
Packit e9ba0d
static inline void	     min_heap_ctor(min_heap_t* s);
Packit e9ba0d
static inline void	     min_heap_dtor(min_heap_t* s);
Packit e9ba0d
static inline void	     min_heap_elem_init(struct event* e);
Packit e9ba0d
static inline int	     min_heap_elt_is_top(const struct event *e);
Packit e9ba0d
static inline int	     min_heap_elem_greater(struct event *a, struct event *b);
Packit e9ba0d
static inline int	     min_heap_empty(min_heap_t* s);
Packit e9ba0d
static inline unsigned	     min_heap_size(min_heap_t* s);
Packit e9ba0d
static inline struct event*  min_heap_top(min_heap_t* s);
Packit e9ba0d
static inline int	     min_heap_reserve(min_heap_t* s, unsigned n);
Packit e9ba0d
static inline int	     min_heap_push(min_heap_t* s, struct event* e);
Packit e9ba0d
static inline struct event*  min_heap_pop(min_heap_t* s);
Packit e9ba0d
static inline int	     min_heap_erase(min_heap_t* s, struct event* e);
Packit e9ba0d
static inline void	     min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
Packit e9ba0d
static inline void	     min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
Packit e9ba0d
Packit e9ba0d
int min_heap_elem_greater(struct event *a, struct event *b)
Packit e9ba0d
{
Packit e9ba0d
	return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
Packit e9ba0d
void min_heap_dtor(min_heap_t* s) { if (s->p) mm_free(s->p); }
Packit e9ba0d
void min_heap_elem_init(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; }
Packit e9ba0d
int min_heap_empty(min_heap_t* s) { return 0u == s->n; }
Packit e9ba0d
unsigned min_heap_size(min_heap_t* s) { return s->n; }
Packit e9ba0d
struct event* min_heap_top(min_heap_t* s) { return s->n ? *s->p : 0; }
Packit e9ba0d
Packit e9ba0d
int min_heap_push(min_heap_t* s, struct event* e)
Packit e9ba0d
{
Packit e9ba0d
	if (min_heap_reserve(s, s->n + 1))
Packit e9ba0d
		return -1;
Packit e9ba0d
	min_heap_shift_up_(s, s->n++, e);
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct event* min_heap_pop(min_heap_t* s)
Packit e9ba0d
{
Packit e9ba0d
	if (s->n)
Packit e9ba0d
	{
Packit e9ba0d
		struct event* e = *s->p;
Packit e9ba0d
		min_heap_shift_down_(s, 0u, s->p[--s->n]);
Packit e9ba0d
		e->ev_timeout_pos.min_heap_idx = -1;
Packit e9ba0d
		return e;
Packit e9ba0d
	}
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int min_heap_elt_is_top(const struct event *e)
Packit e9ba0d
{
Packit e9ba0d
	return e->ev_timeout_pos.min_heap_idx == 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int min_heap_erase(min_heap_t* s, struct event* e)
Packit e9ba0d
{
Packit e9ba0d
	if (-1 != e->ev_timeout_pos.min_heap_idx)
Packit e9ba0d
	{
Packit e9ba0d
		struct event *last = s->p[--s->n];
Packit e9ba0d
		unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
Packit e9ba0d
		/* we replace e with the last element in the heap.  We might need to
Packit e9ba0d
		   shift it upward if it is less than its parent, or downward if it is
Packit e9ba0d
		   greater than one or both its children. Since the children are known
Packit e9ba0d
		   to be less than the parent, it can't need to shift both up and
Packit e9ba0d
		   down. */
Packit e9ba0d
		if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
Packit e9ba0d
			min_heap_shift_up_(s, e->ev_timeout_pos.min_heap_idx, last);
Packit e9ba0d
		else
Packit e9ba0d
			min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
Packit e9ba0d
		e->ev_timeout_pos.min_heap_idx = -1;
Packit e9ba0d
		return 0;
Packit e9ba0d
	}
Packit e9ba0d
	return -1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int min_heap_reserve(min_heap_t* s, unsigned n)
Packit e9ba0d
{
Packit e9ba0d
	if (s->a < n)
Packit e9ba0d
	{
Packit e9ba0d
		struct event** p;
Packit e9ba0d
		unsigned a = s->a ? s->a * 2 : 8;
Packit e9ba0d
		if (a < n)
Packit e9ba0d
			a = n;
Packit e9ba0d
		if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
Packit e9ba0d
			return -1;
Packit e9ba0d
		s->p = p;
Packit e9ba0d
		s->a = a;
Packit e9ba0d
	}
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
Packit e9ba0d
{
Packit e9ba0d
    unsigned parent = (hole_index - 1) / 2;
Packit e9ba0d
    while (hole_index && min_heap_elem_greater(s->p[parent], e))
Packit e9ba0d
    {
Packit e9ba0d
	(s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
Packit e9ba0d
	hole_index = parent;
Packit e9ba0d
	parent = (hole_index - 1) / 2;
Packit e9ba0d
    }
Packit e9ba0d
    (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
Packit e9ba0d
{
Packit e9ba0d
    unsigned min_child = 2 * (hole_index + 1);
Packit e9ba0d
    while (min_child <= s->n)
Packit e9ba0d
	{
Packit e9ba0d
	min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
Packit e9ba0d
	if (!(min_heap_elem_greater(e, s->p[min_child])))
Packit e9ba0d
	    break;
Packit e9ba0d
	(s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index;
Packit e9ba0d
	hole_index = min_child;
Packit e9ba0d
	min_child = 2 * (hole_index + 1);
Packit e9ba0d
	}
Packit e9ba0d
    (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#endif /* _MIN_HEAP_H_ */