#include <stddef.h>
#include <stdint.h>

extern "C"
{
#include "FreeRTOS.h"
}

extern "C"
{
volatile size_t g_cpp_allocation_count;
volatile size_t g_cpp_deallocation_count;
volatile size_t g_cpp_live_allocations;
volatile uintptr_t g_cpp_allocation_addresses[ 4 ];
volatile uintptr_t g_cpp_deallocation_addresses[ 4 ];
}

namespace
{

void * allocate_or_fail( size_t bytes )
{
    void * const memory = pvPortMalloc( bytes == 0U ? 1U : bytes );
    configASSERT( memory != nullptr );

    if( g_cpp_allocation_count < 4U )
    {
        g_cpp_allocation_addresses[ g_cpp_allocation_count ] =
            reinterpret_cast< uintptr_t >( memory );
    }
    ++g_cpp_allocation_count;
    ++g_cpp_live_allocations;
    return memory;
}

void release( void * memory ) noexcept
{
    if( memory == nullptr )
    {
        return;
    }

    if( g_cpp_deallocation_count < 4U )
    {
        g_cpp_deallocation_addresses[ g_cpp_deallocation_count ] =
            reinterpret_cast< uintptr_t >( memory );
    }
    ++g_cpp_deallocation_count;
    --g_cpp_live_allocations;
    vPortFree( memory );
}

} // namespace

void * operator new( size_t bytes )
{
    return allocate_or_fail( bytes );
}

void * operator new[]( size_t bytes )
{
    return allocate_or_fail( bytes );
}

void operator delete( void * memory ) noexcept
{
    release( memory );
}

void operator delete[]( void * memory ) noexcept
{
    release( memory );
}

void operator delete( void * memory, size_t ) noexcept
{
    release( memory );
}

void operator delete[]( void * memory, size_t ) noexcept
{
    release( memory );
}

