/*========================== begin_copyright_notice ============================
Copyright (C) 2021-2023 Intel Corporation

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/

/*!
 * @file GTPin core interface - tool registration and informational services
 */

#ifndef IGT_CORE_H_
#define IGT_CORE_H_

#include "gt_basic_defs.h"

namespace gtpin
{
#pragma pack(push, 8)

/* ===================================================================================================== */
// External/forward declarations
/* ===================================================================================================== */
class IGtTool;              ///< Class that defines interface of the GTPin tool
class IGtGenArch;           ///< Class that provides access to properties of the GEN architecture
class IGtKnobRegistry;      ///< Container of GTPin configuration arguments
class IGtEvent;             ///< Class that represents an event reported by GTPin
class IGtEventHandler;      ///< Handler of events reported by GTPin
class IGtHliLibrary;        ///< Collection of High-Level Instrumentation (HLI) modules

 /// @return Memory allocator of the GTPin core storage
inline IMemAllocator& GtCoreMemAllocator();

/// @brief Raw memory deleter in the GTPin core storage
struct GtCoreMemDeleter { void operator()(void* ptr) const noexcept { GtCoreMemAllocator().Deallocate(ptr); } };

/*! @addtogroup GTPIN_CORE
@{
*/

/* ===================================================================================================== */
// Class GtCoreString
/* ===================================================================================================== */
/*!
 * @brief C string allocated in the GTPin core storage and managed by UniquePtr
 */
class GtCoreString
{
public:
    GtCoreString()                  noexcept = default;              ///< Default constructor
    GtCoreString(GtCoreString&&)    noexcept = default;              ///< Move constructor

    /// Construct a GtCoreString object for a given C string 'cstr' which is allocated in the GTPin core storage
    explicit GtCoreString(UniquePtr<char, GtCoreMemDeleter>&& cstr) noexcept : _up(ToMove(cstr)) {}

    const char* Get()         const noexcept  { return _up.Get(); }  ///< Return constant C string managed by this object
    operator    std::string() const noexcept  { return _up ? _up.Get() : ""; }      ///< Convert this object to std::string
    bool        IsEmpty()     const noexcept  { return !_up || (*_up.Get() == 0); } ///< @return true for empty string

    void Swap(GtCoreString& str)    noexcept  { _up.Swap(str._up); } ///< Swap managed C strings
    void Reset()                    noexcept  { _up.Reset(); }       ///< Delete the managed C string

private:
    UniquePtr<char, GtCoreMemDeleter> _up;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtCoreString);

inline std::ostream& operator<<(std::ostream& os,         const GtCoreString& coreStr)  { return os << coreStr.Get(); }
inline std::string operator+(const GtCoreString& coreStr, const std::string& str)       { return coreStr.Get() + str; }
inline std::string operator+(const std::string& str,      const GtCoreString& coreStr)  { return str + coreStr.Get(); }
inline std::string operator+(const GtCoreString& coreStr, const char* cstr)             { return std::string(coreStr) + cstr; }
inline std::string operator+(const char* cstr,            const GtCoreString& coreStr)  { return cstr + std::string(coreStr); }

/* ===================================================================================================== */
// GtToolHandle
/* ===================================================================================================== */
using GtToolHandle = IGtTool*; ///< Handle to the tool registered with the GTPin core

/* ===================================================================================================== */
// Class IGtCore
/* ===================================================================================================== */
/*!
 * @brief Singleton that provides GTPin core interface: tool registration and other core services
 *
 * @par Availability:
 * - Anytime and anywhere
 */
class IGtCore : public IMemAllocator
{
public:
    /*!
     * @brief Register the specified tool with the GTPin core.
     *
     * The GTPin core checks the tool API version, and declines tools whose version is not supported.
     * @note In addition to registering GTPin tool, this function completes GTPin initialization.
     *       Therefore, any change to the default GTPin configuration (KNOBs) should be done prior to
     *       this function call.
     *
     * @param[in]    tool   Object that implements IGtTool interface (callbacks)
     * @return Handle to the registered tool, or nullptr if the tool registration failed.
     *         In case of error, the IGtCore::LastError() function provides the specific failure reason
     */
    virtual GtToolHandle RegisterTool(IGtTool& tool) = 0;

    /*!
     * @brief Remove the specified tool from the tool's registry of this GTPin core
     * @param[in]    toolHandle   Handle to the tool rergistered with this GTPin core
     * @return true - success, false - failure
     *         In case of error, the IGtCore::LastError() function provides the specific failure reason
     */
    virtual bool UnregisterTool(GtToolHandle toolHandle) = 0;

    /// Return the GTPin kit version
    virtual const char* Version() const = 0;

    /// Return the GTPin kit revision
    virtual const char* Revision() const = 0;

    /// Return the API version supported by this GTPin kit (see @ref GTPIN_API_VERSION)
    virtual uint32_t ApiVersion() const = 0;

    /// Return the default directory dedicated to profile data files
    virtual GtCoreString ProfileDir() const = 0;

    /*!
     * @brief Create the default directory dedicated to profile data files
     * @return true - success, false - failure
     *         In case of error, the IGtCore::LastError() function provides the specific failure reason
     */
    virtual bool CreateProfileDir() const = 0;

    /// Return Object that provides access to generic and model-specific properties of the GEN architecture
    virtual const IGtGenArch& GenArch() const = 0;

    /// Return Container of GTPin configuration arguments (KNOBs)
    virtual IGtKnobRegistry& Knobs() = 0;

    /*!
     * @brief Register the specified event handler with the GTPin core.
     * 
     * GTPin supports multiple event handlers that can be registered by a single tool or multiple tools.
     * The order in which events will be dispatched to handlers is not guaranteed
     */
    virtual void RegisterEventHandler(IGtEventHandler& eventHandler) = 0;
    
    /*!
     * @brief Get last error event reported by GTPin in the current thread
     * @return An event with the error status and the corresponding information. 
     *         If no error occurred - event with the GTPIN_STATUS_SUCCESS status.
     */
    virtual const IGtEvent& LastError() const = 0;

    /// Return Collection of the High-Level Instrumentation (HLI) modules
    virtual IGtHliLibrary& HliLibrary() const = 0;

protected:
    /// @internal Protected destructor
    virtual ~IGtCore() = default;
};
GTPIN_ASSERT_PURE_ABSTRACT(IGtCore);

/*!
 * @brief Return single instance of the IGtCore class
 *
 * @note This is the only interface function exported by the gtpin library. If a tool loads this library dynamically,
 * the indirect call to the GTPin_GetCore() function should be wrapped into a function with the exactly same signature,
 * implemented by the tool:
@code
    IGtCore* (*fpGTPin_GetCore)() = address_of_GTPin_GetCore; // Address of the GTPin_GetCore() function in the gtpin library
    IGtCore* GTPin_GetCore()
    {
        return fpGTPin_GetCore();
    }
@endcode
 * This is necessary because some other functions in the GTPin API have an inline implementation that uses GTPin_GetCore().
 * For example, see the @ref GetGenArch() function.
 */
extern "C" IGtCore* GTPin_GetCore();
/*! @} */

/// @return Memory allocator of the GTPin core memory storage
inline IMemAllocator& GtCoreMemAllocator() { return *GTPin_GetCore(); }

/* ===================================================================================================== */
// Class GtCoreObjDeleter
/* ===================================================================================================== */
/*!
 * @brief Deleter for a single (non-array) object allocated in the GTPin core storage
 * @param   T   type of the object to be deleted
 * @pre     T is not an array (std::is_array<T> == false)
 */
template<class T> struct GtCoreObjDeleter
{
    GTPIN_STATIC_ASSERT(!IsArray<T>::value);
    void operator()(T* ptr) const noexcept
    {
        if (ptr != nullptr)
        {
            ptr->~T();
            GtCoreMemAllocator().Deallocate(ptr);
        }
    }
};

/* ===================================================================================================== */
// Class GtCoreUniquePtr
/* ===================================================================================================== */
/*!
 * @brief Smart pointer with unique semantic, referencing an object of type 'T' in GTPin core memory storage
 */
template<typename T> using GtCoreUniquePtr = UniquePtr< T, GtCoreObjDeleter<T> >;

#pragma pack(pop)
}
#endif
