// =====================================================================================================================
//  I release this example code into the public domain
// =====================================================================================================================

// This file contains code that tests the efficiency of the assert macro scheme in
// fennec engine. This is purely looking at the branching aspect and not the private
// assert definition. The code only uses passing values to see any performance overhead
// from the conditional

// This code is based on the example code that cppreference provides at
// https://en.cppreference.com/w/cpp/language/attributes/likely

// To my surprise, the difference between them is negligible.
// Even when n is a crazy number like one billion, there isn't a conclusive difference.
// I checked that it isn't the lambdas, they are optimized out.

// In debug mode, the results are to be expected; release < experimental < control

#include <cassert>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>

#define assert_c(expression) \
if(not(expression)) { \
std::abort(); \
}

#define assert_e(expression) \
if(not(expression)) [[unlikely]] { \
std::abort(); \
}

#define assert_r(expression) (static_cast<void> (0))

volatile int sink{}; // ensures a side effect

int main() {
	auto benchmark = [](auto fun, auto rem) {
		srand(0);

		const auto start = std::chrono::high_resolution_clock::now();
		for (auto size{1ULL}; size != 10'000'000ULL; ++size)
			sink = fun(rand());
		const std::chrono::duration<double> diff =
			std::chrono::high_resolution_clock::now() - start;

		std::cout << "Time: " << std::fixed << std::setprecision(6) << diff.count()
				  << " sec " << rem << std::endl;
	};

	benchmark([](int x) {
		assert_c(0 <= x && x <= RAND_MAX);
		return x;
	}, "control");

	benchmark([](int x) {
		assert_r(0 <= x && x <= RAND_MAX);
		return x;
	}, "release");

	benchmark([](int x) {
		assert_e(0 <= x && x <= RAND_MAX);
		return x;
	}, "experimental");
}
