/*
 * CppHeap.h
 *
 *   Created on: Jan 9, 2019
 *       Author: Jan Travnicek
 */

#ifndef CPP_HEAP_INCLUDED
#define CPP_HEAP_INCLUDED

#include <algorithm>
#include <vector>

namespace alib {

/// binomial heap used as mergeable priority queue
template < typename elem_t >
class CppHeap {
public:
	CppHeap( int (* compare)( const elem_t &, const elem_t & ) );

	~CppHeap();

	/// inserts a node with new value into the heap
	void insert( const elem_t & value );

	/// finds the maximum value in the heap
	const elem_t & getMax() const {
		return _data.front ( );
	}

	/// finds and removes the maximum value from the heap
	elem_t extractMax();

	/// merges this heap with another heap (!! this is a DESTRUCTIVE merge, heap in argument will be cleared !!)
	void mergeWith( CppHeap<elem_t> && that );

	size_t size() const {
		return _data.size ( );
	}

protected:
	int (* _compare)( const elem_t &, const elem_t & ); ///< user-defined comparator function
	std::vector < elem_t > _data;
};


template< typename elem_t >
CppHeap<elem_t>::CppHeap( int (* compare)( const elem_t &, const elem_t & ) ) : _compare( compare ) {
}

template< typename elem_t >
CppHeap<elem_t>::~CppHeap() {
}

template< typename elem_t >
void CppHeap<elem_t>::insert( const elem_t & value ) {
	_data.push_back ( value );
	std::push_heap ( _data.begin ( ), _data.end ( ), _compare );
}

template< typename elem_t >
elem_t CppHeap<elem_t>::extractMax() {
	if ( _data.size ( ) == 0 )
		throw std::out_of_range ( "Heap is empty." );

	elem_t res = _data.front ( );
	std::pop_heap ( _data.begin ( ), _data.end ( ), _compare );
	_data.pop_back ( );
	return res;
}

template< typename elem_t >
void CppHeap<elem_t>::mergeWith( CppHeap<elem_t> && that ) {
	_data.insert ( _data.end ( ), that._data.begin ( ), that._data.end ( ) );
	std::make_heap ( _data.begin ( ), _data.end ( ), _compare );
}

} /* namespace alib */

#endif // CPP_HEAP_INCLUDED
