/*
 * MARS Long Distance Replication Software
 *
 * This file is part of MARS project: http://schoebel.github.io/mars/
 *
 * Copyright (C) 2010-2014 Thomas Schoebel-Theuer
 * Copyright (C) 2011-2014 1&1 Internet AG
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef PAIRING_HEAP_H
#define PAIRING_HEAP_H

/* Algorithm: see http://en.wikipedia.org/wiki/Pairing_heap
 * This is just an efficient translation from recursive to iterative form.
 *
 * Note: find_min() is so trivial that we don't implement it.
 */

/* generic version: KEYDEF is kept separate, allowing you to
 * embed this structure into other container structures already
 * possessing some key (just provide an empty KEYDEF in this case).
 */
#define _PAIRING_HEAP_TYPEDEF(KEYTYPE,KEYDEF)		\
							\
struct pairing_heap_##KEYTYPE {			        \
	KEYDEF						\
	struct pairing_heap_##KEYTYPE *next;	        \
	struct pairing_heap_##KEYTYPE *subheaps;	\
};

/* less generic version: define the key inside.
 */
#define PAIRING_HEAP_TYPEDEF(KEYTYPE)			\
	_PAIRING_HEAP_TYPEDEF(KEYTYPE, KEYTYPE key;)

/* generic methods: allow arbitrary CMP() functions.
 */
#define _PAIRING_HEAP_FUNCTIONS(_STATIC,KEYTYPE,CMP)			\
									\
_STATIC								        \
struct pairing_heap_##KEYTYPE *_ph_merge_##KEYTYPE(struct pairing_heap_##KEYTYPE *heap1, struct pairing_heap_##KEYTYPE *heap2) \
{									\
	if (!heap1)							\
		return heap2;						\
	if (!heap2)							\
		return heap1;						\
	if (CMP(heap1, heap2) < 0) {					\
		heap2->next = heap1->subheaps;				\
		heap1->subheaps = heap2;				\
		return heap1;						\
	}								\
	heap1->next = heap2->subheaps;					\
	heap2->subheaps = heap1;					\
	return heap2;							\
}									\
									\
_STATIC								        \
void ph_insert_##KEYTYPE(struct pairing_heap_##KEYTYPE **heap, struct pairing_heap_##KEYTYPE *new) \
{									\
	new->next = NULL;						\
	new->subheaps = NULL;						\
	*heap = _ph_merge_##KEYTYPE(*heap, new);			\
}									\
									\
_STATIC								        \
void ph_delete_min_##KEYTYPE(struct pairing_heap_##KEYTYPE **heap)	\
{									\
	struct pairing_heap_##KEYTYPE *tmplist = NULL;			\
	struct pairing_heap_##KEYTYPE *ptr;				\
	struct pairing_heap_##KEYTYPE *next;				\
	struct pairing_heap_##KEYTYPE *res;				\
	if (!*heap) {							\
		return;							\
	}								\
	for (ptr = (*heap)->subheaps; ptr; ptr = next) {			\
		struct pairing_heap_##KEYTYPE *p2 = ptr->next;		\
		next = p2;						\
		if (p2) {						\
			next = p2->next;				\
			ptr = _ph_merge_##KEYTYPE(ptr, p2);		\
		}							\
		ptr->next = tmplist;					\
		tmplist = ptr;						\
	}								\
	res = NULL;							\
	for (ptr = tmplist; ptr; ptr = next) {				\
		next = ptr->next;					\
		res = _ph_merge_##KEYTYPE(res, ptr);			\
	}								\
	*heap = res;							\
}

/* some default CMP() function */
#define PAIRING_HEAP_COMPARE(a,b) ((a)->key < (b)->key ? -1 : ((a)->key > (b)->key ? 1 : 0))

/* less generic version: use the default CMP() function */
#define PAIRING_HEAP_FUNCTIONS(_STATIC,KEYTYPE)				\
	_PAIRING_HEAP_FUNCTIONS(_STATIC,KEYTYPE,PAIRING_HEAP_COMPARE)

#endif