//
// Copyright © 2019-2023 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "RefTensorHandle.hpp"

namespace armnn
{

RefTensorHandle::RefTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr<RefMemoryManager>& memoryManager):
    m_TensorInfo(tensorInfo),
    m_MemoryManager(memoryManager),
    m_Pool(nullptr),
    m_UnmanagedMemory(nullptr),
    m_ImportedMemory(nullptr),
    m_Decorated()
{
}

RefTensorHandle::RefTensorHandle(const TensorInfo& tensorInfo)
                                 : m_TensorInfo(tensorInfo),
                                   m_Pool(nullptr),
                                   m_UnmanagedMemory(nullptr),
                                   m_ImportedMemory(nullptr),
                                   m_Decorated()
{
}

RefTensorHandle::RefTensorHandle(const TensorInfo& tensorInfo, const RefTensorHandle& parent)
        : m_TensorInfo(tensorInfo),
          m_MemoryManager(parent.m_MemoryManager),
          m_Pool(parent.m_Pool),
          m_UnmanagedMemory(parent.m_UnmanagedMemory),
          m_ImportedMemory(parent.m_ImportedMemory),
          m_Decorated()
{
}

RefTensorHandle::~RefTensorHandle()
{
    ::operator delete(m_UnmanagedMemory);
}

void RefTensorHandle::Manage()
{
    ARMNN_ASSERT_MSG(!m_Pool, "RefTensorHandle::Manage() called twice");
    ARMNN_ASSERT_MSG(!m_UnmanagedMemory, "RefTensorHandle::Manage() called after Allocate()");

    if (m_MemoryManager)
    {
        m_Pool = m_MemoryManager->Manage(m_TensorInfo.GetNumBytes());
    }
}

void RefTensorHandle::Allocate()
{
    if (!m_UnmanagedMemory)
    {
        if (!m_Pool)
        {
            // unmanaged
            m_UnmanagedMemory = ::operator new(m_TensorInfo.GetNumBytes());
        }
        else
        {
            m_MemoryManager->Allocate(m_Pool);
        }
    }
    else
    {
        throw InvalidArgumentException("RefTensorHandle::Allocate Trying to allocate a RefTensorHandle"
                                       "that already has allocated memory.");
    }
}

const void* RefTensorHandle::Map(bool /*unused*/) const
{
    return GetPointer();
}

void* RefTensorHandle::GetPointer() const
{
    if (m_ImportedMemory)
    {
        return m_ImportedMemory;
    }
    else if (m_UnmanagedMemory)
    {
        return m_UnmanagedMemory;
    }
    else if (m_Pool)
    {
        return m_MemoryManager->GetPointer(m_Pool);
    }
    else
    {
        throw NullPointerException("RefTensorHandle::GetPointer called on unmanaged, unallocated tensor handle");
    }
}

void RefTensorHandle::CopyOutTo(void* dest) const
{
    const void *src = GetPointer();
    ARMNN_ASSERT(src);
    memcpy(dest, src, m_TensorInfo.GetNumBytes());
}

void RefTensorHandle::CopyInFrom(const void* src)
{
    void *dest = GetPointer();
    ARMNN_ASSERT(dest);
    memcpy(dest, src, m_TensorInfo.GetNumBytes());
}

MemorySourceFlags RefTensorHandle::GetImportFlags() const
{
    return static_cast<MemorySourceFlags>(MemorySource::Malloc);
}

bool RefTensorHandle::Import(void* memory, MemorySource source)
{
    if (source == MemorySource::Malloc)
    {
        // Check memory alignment
        if(!CanBeImported(memory, source))
        {
            m_ImportedMemory = nullptr;
            return false;
        }

        m_ImportedMemory = memory;
        return true;
    }

    return false;
}

bool RefTensorHandle::CanBeImported(void *memory, MemorySource source)
{
    if (source == MemorySource::Malloc)
    {
        uintptr_t alignment = GetDataTypeSize(m_TensorInfo.GetDataType());
        if (reinterpret_cast<uintptr_t>(memory) % alignment)
        {
            return false;
        }
        return true;
    }
    return false;
}

std::shared_ptr<ITensorHandle> RefTensorHandle::DecorateTensorHandle(const TensorInfo& tensorInfo)
{
    auto decorated = std::make_shared<RefTensorHandleDecorator>(tensorInfo, *this);
    m_Decorated.emplace_back(decorated);
    return decorated;
}

RefTensorHandleDecorator::RefTensorHandleDecorator(const TensorInfo& tensorInfo, const RefTensorHandle& parent)
: RefTensorHandle(tensorInfo)
, m_TensorInfo(tensorInfo)
, m_Parent(parent)
{
}

void RefTensorHandleDecorator::Manage()
{
}

void RefTensorHandleDecorator::Allocate()
{
}

const void* RefTensorHandleDecorator::Map(bool unused) const
{
    return m_Parent.Map(unused);
}

MemorySourceFlags RefTensorHandleDecorator::GetImportFlags() const
{
    return static_cast<MemorySourceFlags>(MemorySource::Malloc);
}

bool RefTensorHandleDecorator::Import(void*, MemorySource )
{
    return false;
}

bool RefTensorHandleDecorator::CanBeImported(void* , MemorySource)
{
    return false;
}

std::shared_ptr<ITensorHandle> RefTensorHandleDecorator::DecorateTensorHandle(const TensorInfo&)
{
    return nullptr;
}


}
