#ifndef __DEBUG_H__
#define __DEBUG_H__

#include <iostream>
#include <stdlib.h>

#if !(defined(DEBUG) ^ defined(NDEBUG))
	#error "Neither or both DEBUG and NDEBUG are defined."
#endif

#ifdef DEBUG
	#define ASSERT(cond, msg) \
		do { \
			if(!(cond)) { \
				std::cerr << "ASSERT FAILED (" << __FILE__ \
					<< ":" << __LINE__ << "): " << msg << std::endl; \
				exit(EXIT_FAILURE); \
			} \
		} while(false);
#else
	#define ASSERT(cond, msg) ;
#endif

#if defined(DEBUG) && defined(VERBOSE)
    // #include "mex.h" // DEBUG
    // #include <sstream>
	#define MSG(msg) \
        do { std::cout << msg << std::endl; } while(false);
		// do { std::stringstream ss; ss << msg << std::endl; mexPrintf("%s", ss.str().c_str()); } while(false);
#else
	#define MSG(msg) ;
#endif

#ifdef DEBUG
	inline uint64_t ilog2(uint64_t x) {
		ASSERT(x > 0, "Log2 is undefined for non-positive arguments.");
		return (sizeof(uint64_t) << 3) - __builtin_clzll(x - 1);
	}

	inline void ASSERT_MINHEAP(std::vector<uint64_t> &items) {
		const uint64_t n = items.size() - 1;
		if(n <= 1) return;
		const uint64_t imax = (1 << (ilog2(n + 1) - 1)) - 1;
		for(uint64_t i = 1; i <= imax; ++i) {
			uint64_t ival = items[i];
			uint64_t ileft = i << 1;
			if(ileft <= n) {
				uint64_t leftval = items[ileft];
				ASSERT(leftval >= ival, "Heap invariant violated: "
					<< "h[" << i << "] = " << ival << " > h[" << ileft << "] = " << leftval);
			}
			uint64_t iright = ileft + 1;
			if(iright <= n) {
				uint64_t rightval = items[iright];
				ASSERT(rightval >= ival, "Heap invariant violated: "
					<< "h[" << i << "] = " << ival << " > h[" << iright << "] = " << rightval);
			}
		}
	}
#else
	#define ASSERT_MINHEAP(X) ;
#endif

#endif // __DEBUG_H__
