/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2016-2018 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

#include "../../std.hpp"
#include "../../debug.hpp"
#include "../../view.hpp"

#include <utility>


namespace cruft::alloc::aligned {
    /// wraps a child allocator and enforces a fixed alignment
    template <typename ChildT>
    class direct {
    public:
        ///////////////////////////////////////////////////////////////////////
        template <typename ...Args>
        direct (
            cruft::view<u08*> _data,
            std::size_t _alignment,
            Args &&...args
        )
            : m_successor (_data, std::forward<Args> (args)...)
            , m_alignment (_alignment)
        { ; }


        ///////////////////////////////////////////////////////////////////////
        auto allocate (std::size_t bytes)
        {
            return m_successor.allocate (bytes, m_alignment);
        }


        //---------------------------------------------------------------------
        auto allocate (std::size_t bytes, std::size_t alignment)
        {
            (void)alignment;
            return m_successor.allocate (bytes, m_alignment);
        }


        //---------------------------------------------------------------------
        auto deallocate (u08 *ptr, std::size_t bytes, std::size_t alignment)
        {
            (void)alignment;
            return m_successor.deallocate (ptr, bytes, m_alignment);
        }


        //---------------------------------------------------------------------
        auto deallocate (u08 *ptr, std::size_t bytes)
        {
            return m_successor.deallocate (ptr, bytes, m_alignment);
        }


        ///////////////////////////////////////////////////////////////////////
        constexpr auto alignment (void) const noexcept { return m_alignment; }


        ///////////////////////////////////////////////////////////////////////
        auto data (void) { return m_successor.data (); }

        //---------------------------------------------------------------------
        auto begin (void)       { return m_successor.begin (); }
        auto begin (void) const { return m_successor.begin (); }

        auto end (void)       { return m_successor.end (); }
        auto end (void) const { return m_successor.end (); }

        //---------------------------------------------------------------------
        auto
        offset (const void *ptr) const
        {
            return m_successor.offset (ptr);
        }


        ///////////////////////////////////////////////////////////////////////
        auto reset (void) { return m_successor.reset (); }


        ///////////////////////////////////////////////////////////////////////
        auto capacity (void) const { return m_successor.capacity (); }
        auto used     (void) const { return m_successor.used     (); }
        auto remain   (void) const { return m_successor.remain   (); }


    private:
        ChildT m_successor;
        std::size_t m_alignment;
    };
}