/**
 * @file Heap.h
 * @author apio (cloudapio.eu)
 * @brief libluna implementations of malloc-family functions.
 *
 * @copyright Copyright (c) 2023, the Luna authors.
 *
 */

#pragma once
#include <luna/Result.h>

/**
 * @brief Freestanding definitions of std::nothrow and std::align_val_t.
 *
 */
namespace std
{
    struct nothrow_t
    {
        explicit nothrow_t() = default;
    };

    extern const nothrow_t nothrow;

    enum class align_val_t : usize
    {
    };
};

/**
 * @brief Freestanding implementation of new (std::nothrow).
 *
 * @param size The amount of memory to allocate.
 * @return void* A pointer to allocated memory, or nullptr on failure.
 */
void* operator new(usize size, const std::nothrow_t&) noexcept;

/**
 * @brief Freestanding implementation of new (std::nothrow) [].
 *
 * @param size The amount of memory to allocate.
 * @return void* A pointer to allocated memory, or nullptr on failure.
 */
void* operator new[](usize size, const std::nothrow_t&) noexcept;

/**
 * @brief Freestanding implementation of aligned delete.
 *
 * @param ptr The memory to delete.
 * @param size The amount of memory to deallocate.
 * @param alignment The alignment of the memory to delete.
 */
void operator delete(void* ptr, usize size, std::align_val_t alignment) noexcept;

/**
 * @brief Called to allocate pages of memory. Some targets already have implementations of this function, but
 * otherwise it must be implemented by the user.
 *
 * In the kernel, the implementation is in src/memory/Heap.cpp.
 * For POSIX systems, libluna provides an implementation in src/ImplPOSIX.cpp.
 *
 * @param count The number of memory pages to allocate.
 * @return Result<void*> An error, or a pointer to the beginning of the first allocated page.
 */
extern Result<void*> allocate_pages_impl(usize count);

/**
 * @brief Called to free pages of memory. Some targets already have implementations of this function, but
 * otherwise it must be implemented by the user.
 *
 * In the kernel, the implementation is in src/memory/Heap.cpp.
 * For POSIX systems, libluna provides an implementation in src/ImplPOSIX.cpp.
 *
 * @param address The address of the first allocated page.
 * @param count The number of memory pages to free.
 * @return Result<void> Whether the operation succeeded.
 */
extern Result<void> release_pages_impl(void* address, usize count);

/**
 * @brief libluna's malloc implementation.
 *
 * @param size The amount of bytes to allocate.
 * @param may_realloc Specifies whether the program may call realloc() on the returned memory in the future. Enables
 * some optimizations if false.
 * @param should_scrub Specifies whether the memory should be scrubbed with a uniform pattern, helpful for debugging
 * purposes.
 * @return Result<void*> An error, or the allocated memory.
 */
Result<void*> malloc_impl(usize size, bool may_realloc = true, bool should_scrub = true);

/**
 * @brief libluna's calloc implementation.
 *
 * @param nmemb The number of elements to allocate.
 * @param size The size in bytes of each element.
 * @param may_realloc Specifies whether the program may call realloc() on the returned memory in the future. Enables
 * some optimizations if false.
 * @return Result<void*> An error, or the allocated memory.
 */
Result<void*> calloc_impl(usize nmemb, usize size, bool may_realloc = true);

/**
 * @brief libluna's realloc implementation.
 *
 * @param ptr The memory to resize.
 * @param size The new size in bytes.
 * @param may_realloc_again Specifies whether the program may call realloc() again on the returned memory in the future.
 * Enables some optimizations if false.
 * @return Result<void*> An error, or the resized memory (may not be the same pointer, the caller should use this
 * instead of ptr from now on).
 */
Result<void*> realloc_impl(void* ptr, usize size, bool may_realloc_again = true);

/**
 * @brief libluna's free implementation.
 *
 * @param ptr The memory to free.
 * @return Result<void> Whether the operation succeeded.
 */
Result<void> free_impl(void* ptr);

/**
 * @brief Dump heap usage stats to debug output.
 */
void dump_heap_usage();