/*
 * 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 Danny Robson <danny@nerdcruft.net>
 */

#include "map.hpp"

#include "posix/except.hpp"

using cruft::posix::map;


///////////////////////////////////////////////////////////////////////////////
map::map (size_t size, int prot, int flags):
    m_addr (mmap (nullptr, size, prot, flags, -1, 0)),
    m_size (size)
{
    if (MAP_FAILED == m_addr)
        ::cruft::posix::error::throw_code ();
}


//-----------------------------------------------------------------------------
map::map (size_t size, int prot, int flags, const fd &src, off_t offset):
    m_addr (mmap (nullptr, size, prot, flags, src, offset)),
    m_size (size)
{
    if (MAP_FAILED == m_addr)
        ::cruft::posix::error::throw_code ();
}


//-----------------------------------------------------------------------------
map::map (map &&rhs) noexcept:
    m_addr (MAP_FAILED),
    m_size (rhs.m_size)
{
    std::swap (m_addr, rhs.m_addr);
}


//-----------------------------------------------------------------------------
map::~map ()
{
    if (MAP_FAILED == m_addr)
        return;

    if (munmap (m_addr, m_size))
        ::cruft::posix::error::throw_code ();
}


//-----------------------------------------------------------------------------
map&
map::operator= (map &&rhs) noexcept
{
    std::swap (m_addr, rhs.m_addr);
    std::swap (m_size, rhs.m_size);

    return *this;
}


///////////////////////////////////////////////////////////////////////////////
uint8_t*
map::begin (void)
{
    return static_cast<uint8_t*> (m_addr);
}


//-----------------------------------------------------------------------------
uint8_t*
map::end (void)
{
    return static_cast<uint8_t*> (m_addr) + m_size;
}


///////////////////////////////////////////////////////////////////////////////
void*
map::data (void)
{
    return m_addr;
}


//-----------------------------------------------------------------------------
const void*
map::data (void) const
{
    return m_addr;
}


///////////////////////////////////////////////////////////////////////////////
bool
map::empty (void) const
{
    return size () == 0;
}


//-----------------------------------------------------------------------------
size_t
map::size (void) const
{
    return m_size;
}


//-----------------------------------------------------------------------------
void
map::resize (size_t newsize, resize_t op)
{
    int flags = 0;
    switch (op) {
    case resize_t::MOVE:
        flags = flags | MREMAP_MAYMOVE;
        break;

    case resize_t::NOMOVE:
        break;
    }

    auto res = mremap (m_addr, m_size, newsize, flags);
    if (res == MAP_FAILED)
        ::cruft::posix::error::throw_code ();
}