// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright (C) 2025  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//2
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

#include <fennec/lang/detail/_stdlib.h>

#include <fennec/memory/new.h>

#ifdef FENNEC_MEMORY_DEBUGGER

// TODO: Memory Debugging

// General concept is to create a table of allocated memory addresses.

#else

// Windows does not define ISO C aligned allocation functions
#ifdef FENNEC_COMPILER_MSVC
void operator delete  (void* ptr) noexcept { _aligned_free(ptr); }
void operator delete[](void* ptr) noexcept { _aligned_free(ptr); }
void operator delete  (void* ptr, fennec::align_t) noexcept { ::_aligned_free(ptr); }
void operator delete[](void* ptr, fennec::align_t) noexcept { ::_aligned_free(ptr); }
void operator delete  (void* ptr, fennec::size_t, fennec::align_t) noexcept { ::_aligned_free(ptr); }
void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { ::_aligned_free(ptr); }
void operator delete  (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { _aligned_free(ptr); }
void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { _aligned_free(ptr); }

void* operator new  (fennec::size_t size, fennec::align_t align)                           { return _aligned_malloc(static_cast<size_t>(align), size); }
void* operator new[](fennec::size_t size, fennec::align_t align)                           { return _aligned_malloc(static_cast<size_t>(align), size); }
void* operator new  (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast<size_t>(align), size); }
void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast<size_t>(align), size); }

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace fennec
{

	inline size_T pagesize() {
		SYSTEM_INFO sysInfo;
		GetSystemInfo(&sysInfo);
		return sysInfo.dwPageSize;
	}

}
#else

void operator delete  (void* ptr) noexcept { ::free(ptr); }
void operator delete[](void* ptr) noexcept { ::free(ptr); }
void operator delete  (void* ptr, fennec::align_t) noexcept { ::free(ptr); }
void operator delete[](void* ptr, fennec::align_t) noexcept { ::free(ptr); }
void operator delete  (void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); }
void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); }
void operator delete  (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { ::free(ptr); }
void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { ::free(ptr); }

void* operator new  (fennec::size_t size, fennec::align_t align)                           { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }
void* operator new[](fennec::size_t size, fennec::align_t align)                           { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }
void* operator new  (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }
void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast<fennec::size_t>(align), size); }

#endif

// Allocation functions
void* operator new  (fennec::size_t size)                           { return ::calloc(size, 1); }
void* operator new[](fennec::size_t size)                           { return ::calloc(size, 1); }
void* operator new  (fennec::size_t size, const fennec::nothrow_t&) { return ::calloc(size, 1); }
void* operator new[](fennec::size_t size, const fennec::nothrow_t&) { return ::calloc(size, 1); }

// Deallocation Functions
void operator delete  (void* ptr, fennec::size_t)                            noexcept { ::free(ptr); }
void operator delete[](void* ptr, fennec::size_t)                            noexcept { ::free(ptr); }
void operator delete  (void* ptr, const fennec::nothrow_t&)                  noexcept { ::free(ptr); }
void operator delete[](void* ptr, const fennec::nothrow_t&)                  noexcept { ::free(ptr); }
void operator delete  (void* ptr, fennec::size_t, const fennec::nothrow_t&)  noexcept { ::free(ptr); }
void operator delete[](void* ptr, fennec::size_t, const fennec::nothrow_t&)  noexcept { ::free(ptr); }

#include <unistd.h>

namespace fennec
{

size_t pagesize() {
	return sysconf(_SC_PAGESIZE);
}

}
#endif