/*
 * Author: Radovan Cerveny
 */

#include <cstdlib>
#include <new>
#include <algorithm>
#include "MeasurementNew.hpp"
#include "measurements.hpp"

void * operator new( std::size_t n, bool measure ) {
	void * ptr = nullptr;

	for ( ; ; ) {
		 // allocate little more for extra info
		ptr = std::malloc ( n + std::max ( sizeof ( std::size_t ), 16ul ) ); // 16 is minimal safe alignment

		if ( ptr != nullptr ) {
			 // store requested size before the block
			* static_cast < std::size_t * > ( ptr ) = n;

			 // send it to the engine if it does not come from stealth allocation
			if ( measure )
				measurements::hint ( measurements::MemoryHint { measurements::MemoryHint::Type::NEW, static_cast < measurements::MemoryHint::value_type > ( n ) } );

			return static_cast < void * > ( static_cast < char * > ( ptr ) + std::max ( sizeof ( std::size_t ), 16ul ) );
		}

		auto cur_handler = std::set_new_handler ( 0 );
		std::set_new_handler ( cur_handler );

		if ( cur_handler != nullptr )
			cur_handler ( );
		else
			throw std::bad_alloc ( );
	}
}

void operator delete( void * ptr, bool measure ) noexcept {
	if ( ptr == nullptr ) return;

	ptr = static_cast < void * > ( static_cast < char * > ( ptr ) - std::max ( sizeof ( std::size_t ), 16ul ) );

	std::size_t n = * static_cast < std::size_t * > ( ptr );

	 // read the block size and send it to the engine if it does not come from stealth allocation
	if ( measure )
		measurements::hint ( measurements::MemoryHint { measurements::MemoryHint::Type::DELETE, static_cast < measurements::MemoryHint::value_type > ( n ) } );

	std::free ( ptr );
}
