/*
 * Copyright (c) 2016-2019 ARM Limited.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "arm_compute/runtime/TensorAllocator.h"

#include "arm_compute/core/Coordinates.h"
#include "arm_compute/core/Error.h"
#include "arm_compute/core/TensorInfo.h"
#include "arm_compute/runtime/MemoryGroup.h"
#include "arm_compute/runtime/MemoryRegion.h"
#include "support/ToolchainSupport.h"

#include <cstddef>

using namespace arm_compute;

namespace
{
bool validate_subtensor_shape(const TensorInfo &parent_info, const TensorInfo &child_info, const Coordinates &coords)
{
    bool               is_valid     = true;
    const TensorShape &parent_shape = parent_info.tensor_shape();
    const TensorShape &child_shape  = child_info.tensor_shape();
    const size_t       parent_dims  = parent_info.num_dimensions();
    const size_t       child_dims   = child_info.num_dimensions();

    if(child_dims <= parent_dims)
    {
        for(size_t num_dimensions = child_dims; num_dimensions > 0; --num_dimensions)
        {
            const size_t child_dim_size = coords[num_dimensions - 1] + child_shape[num_dimensions - 1];

            if((coords[num_dimensions - 1] < 0) || (child_dim_size > parent_shape[num_dimensions - 1]))
            {
                is_valid = false;
                break;
            }
        }
    }
    else
    {
        is_valid = false;
    }

    return is_valid;
}
} // namespace

TensorAllocator::TensorAllocator(IMemoryManageable *owner)
    : _owner(owner), _associated_memory_group(nullptr), _memory()
{
}

TensorAllocator::~TensorAllocator()
{
    info().set_is_resizable(true);
}

TensorAllocator::TensorAllocator(TensorAllocator &&o) noexcept
    : ITensorAllocator(std::move(o)),
      _owner(o._owner),
      _associated_memory_group(o._associated_memory_group),
      _memory(std::move(o._memory))
{
    o._owner                   = nullptr;
    o._associated_memory_group = nullptr;
    o._memory                  = Memory();
}

TensorAllocator &TensorAllocator::operator=(TensorAllocator &&o) noexcept
{
    if(&o != this)
    {
        _owner   = o._owner;
        o._owner = nullptr;

        _associated_memory_group   = o._associated_memory_group;
        o._associated_memory_group = nullptr;

        _memory   = std::move(o._memory);
        o._memory = Memory();

        ITensorAllocator::operator=(std::move(o));
    }
    return *this;
}

void TensorAllocator::init(const TensorAllocator &allocator, const Coordinates &coords, TensorInfo &sub_info)
{
    // Get parent info
    const TensorInfo parent_info = allocator.info();

    // Check if coordinates and new shape are within the parent tensor
    ARM_COMPUTE_ERROR_ON(!validate_subtensor_shape(parent_info, sub_info, coords));
    ARM_COMPUTE_UNUSED(validate_subtensor_shape);

    // Copy pointer to buffer
    _memory = Memory(allocator._memory.region());

    // Init tensor info with new dimensions
    size_t total_size = parent_info.offset_element_in_bytes(coords) + sub_info.total_size() - sub_info.offset_first_element_in_bytes();
    sub_info.init(sub_info.tensor_shape(), sub_info.format(), parent_info.strides_in_bytes(), parent_info.offset_element_in_bytes(coords), total_size);

    // Set TensorInfo
    init(sub_info);
}

uint8_t *TensorAllocator::data() const
{
    return (_memory.region() == nullptr) ? nullptr : reinterpret_cast<uint8_t *>(_memory.region()->buffer());
}

void TensorAllocator::allocate()
{
    // Align to 64-byte boundaries by default if alignment is not specified
    const size_t alignment_to_use = (alignment() != 0) ? alignment() : 64;
    if(_associated_memory_group == nullptr)
    {
        _memory.set_owned_region(support::cpp14::make_unique<MemoryRegion>(info().total_size(), alignment_to_use));
    }
    else
    {
        _associated_memory_group->finalize_memory(_owner, _memory, info().total_size(), alignment_to_use);
    }
    info().set_is_resizable(false);
}

void TensorAllocator::free()
{
    _memory.set_region(nullptr);
    info().set_is_resizable(true);
}

Status TensorAllocator::import_memory(void *memory)
{
    ARM_COMPUTE_RETURN_ERROR_ON(memory == nullptr);
    ARM_COMPUTE_RETURN_ERROR_ON(_associated_memory_group != nullptr);
    ARM_COMPUTE_RETURN_ERROR_ON(alignment() != 0 && !arm_compute::utility::check_aligned(memory, alignment()));

    _memory.set_owned_region(support::cpp14::make_unique<MemoryRegion>(memory, info().total_size()));
    info().set_is_resizable(false);

    return Status{};
}

void TensorAllocator::set_associated_memory_group(IMemoryGroup *associated_memory_group)
{
    ARM_COMPUTE_ERROR_ON(associated_memory_group == nullptr);
    ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr && _associated_memory_group != associated_memory_group);
    ARM_COMPUTE_ERROR_ON(_memory.region() != nullptr && _memory.region()->buffer() != nullptr);

    _associated_memory_group = associated_memory_group;
}

uint8_t *TensorAllocator::lock()
{
    ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr);
    return reinterpret_cast<uint8_t *>(_memory.region()->buffer());
}

void TensorAllocator::unlock()
{
}
