#include "heap4_model.h"

enum {
    ARENA_BYTES = 256,
    REQUEST_BYTES = 13,
    WANTED_BYTES = (sizeof(ModelBlock) + REQUEST_BYTES + 7U) & ~7U
};

typedef struct {
    ModelBlock allocated;
    uint8_t payload[WANTED_BYTES - sizeof(ModelBlock)];
    ModelBlock remainder;
    uint8_t free_payload[ARENA_BYTES - WANTED_BYTES - sizeof(ModelBlock)];
} SplitArena;

typedef union {
    uint64_t force_alignment;
    SplitArena blocks;
} AlignedSplitArena;

AlignedSplitArena g_split_arena;
ModelBlock *g_free_head;
volatile size_t g_header_bytes;
volatile size_t g_wanted_bytes;
volatile size_t g_remainder_bytes;
volatile size_t g_payload_offset;
volatile int g_split_addresses_aligned;
volatile int g_task01_pass;

__attribute__((noinline)) void task01_debug_checkpoint(void)
{
#if defined(__GNUC__)
    __asm__ volatile("" ::: "memory");
#endif
}

int main(void)
{
    SplitArena *arena = &g_split_arena.blocks;
    uintptr_t base = (uintptr_t)&arena->allocated;
    uintptr_t remainder = (uintptr_t)&arena->remainder;

    arena->allocated.next = NULL;
    arena->allocated.size = WANTED_BYTES;
    arena->remainder.next = NULL;
    arena->remainder.size = ARENA_BYTES - WANTED_BYTES;
    arena->payload[0] = (uint8_t)'A';
    g_free_head = &arena->remainder;

    g_header_bytes = sizeof(ModelBlock);
    g_wanted_bytes = WANTED_BYTES;
    g_remainder_bytes = arena->remainder.size;
    g_payload_offset = (size_t)((uintptr_t)&arena->payload[0] - base);
    g_split_addresses_aligned =
        (base % MODEL_ALIGNMENT) == 0U &&
        (remainder % MODEL_ALIGNMENT) == 0U;
    g_task01_pass =
        g_wanted_bytes == model_align_up(sizeof(ModelBlock) + REQUEST_BYTES) &&
        (size_t)(remainder - base) == g_wanted_bytes &&
        g_remainder_bytes + g_wanted_bytes == ARENA_BYTES &&
        g_payload_offset == sizeof(ModelBlock) &&
        g_split_addresses_aligned;

    task01_debug_checkpoint();

#if defined(HOST_PRINTF)
    printf("header=%zu wanted=%zu remainder=%zu payload=%zu aligned=%d pass=%d\n",
           g_header_bytes, g_wanted_bytes, g_remainder_bytes,
           g_payload_offset, g_split_addresses_aligned, g_task01_pass);
#endif
    return g_task01_pass ? 0 : 1;
}
