#include "alloc/aligned/foreign.hpp"
#include "alloc/linear.hpp"
#include "pointer.hpp"
#include "tap.hpp"

int
main ()
{
    static u08 buffer[1024*1024];
    static constexpr std::size_t alignment = 3;
    static constexpr std::size_t increment = 1;

    // ensure we have an base pointer that's off-by-one to a likely natural
    // system alignment
    u08* base = cruft::align::up (
        std::data (buffer),
        alignof (std::max_align_t)
    ) + increment;

    cruft::alloc::aligned::foreign<cruft::alloc::linear> alloc (
        cruft::view(base,std::end(buffer)),
        alignment
    );


    cruft::TAP::logger tap;

    // ensure the first element allocated falls at the base address
    tap.expect_eq (base, alloc.data (), "allocator base address is the supplied base address");
    tap.expect_eq (base, alloc.allocate (8).data (), "first allocation is the supplied base address");

    // allocate a range of values and make sure they all satisfy our alignment.
    // don't choose values which are likely to combine with the testing
    // alignment to produce a likely system alignment. eg, 3 + 5 == 8 which is
    // a power-of-2.

    static const struct {
        size_t size;
        const char *message;
    } TESTS[] = {
        {   9,  "just over a power of two" },
        {   1,  "a single byte" },
        {  64,  "a cache line" },
        { 250,  "multiple cache lines, but not a power of two" },
    };

    for (const auto &t: TESTS) {
        auto ptr = reinterpret_cast<uintptr_t> (alloc.allocate (t.size).data ());
        auto offset = ptr - reinterpret_cast<uintptr_t> (base);
        tap.expect_mod (offset, alignment, "%s", t.message);
    }

    return tap.status ();
};