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

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

/*!
 * @file Abstract representation of a GEN code procedure in GTPin
 */

#ifndef IGT_GEN_PROCEDURE_H_
#define IGT_GEN_PROCEDURE_H_

#include "gt_basic_defs.h"
#include "igt_ins.h"

namespace gtpin
{
#pragma pack(push, 8)

/* ===================================================================================================== */
// Class IGtInsHandler
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_INSTRUCTION
 * @brief Abstract interface of a class that handles instructions (of a procedure)
 */
class IGtInsHandler
{
public:
    virtual void Handle(IGtIns& ins) = 0;           ///< Handle the specified instruction
    virtual void Handle(const IGtIns& ins) = 0;     ///< Handle the specified instruction

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

/* ===================================================================================================== */
// Class IGtGenProcedure
/* ===================================================================================================== */
/*! @ingroup GTPIN_INSTRUMENT_PROC
 * @brief Abstract representation of the GTPin code procedure.
 * 
 * Mainly, the IGtGenProcedure objects are used to represent instrumentation procedures inserted into
 * original code of the kernel. See @ref IGtKernelInstrument::InstrumentInstruction for an example of
 * using IGtGenProcedure in the kernel instrumentation interface.
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtGenProcedure
{
public:
    /// Append the specified instruction at the end of this procedure
    virtual void Append(IGtIns& ins) = 0;

    /// Append instructions of this procedure at the end of 'otherProc' 
    virtual void AppendTo(IGtGenProcedure& otherProc) const = 0;

    /// Append 'otherProc' instructions at the end of this procedure
    inline void Append(const IGtGenProcedure& otherProc) { otherProc.AppendTo(*this); }

    /// Remove (not delete) all instructions from this procedure
    virtual void Clear() = 0;

    /// Return number of instructions in the procedure
    virtual uint32_t Size() const = 0;

    /// Return true if there is no instructions in the procedure
    virtual bool IsEmpty() const = 0;

    /// Iterate instructions of this procedure and process them with the specified handler
    virtual void IterateInstructions(IGtInsHandler& handler) const = 0;

    /// Iterate instructions of this procedure and process them with the specified handler
    virtual void IterateInstructions(IGtInsHandler& handler)       = 0;

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

/*! @addtogroup GTPIN_INSTRUMENT_PROC 
    @{
 */
/// Append instruction 'ins' at the end of procedure 'proc'
inline IGtGenProcedure& operator +=(IGtGenProcedure& proc, IGtIns& ins) { proc.Append(ins); return proc;}

/// Append 'rProc' at the end of 'lProc'
inline IGtGenProcedure& operator +=(IGtGenProcedure& lProc, const IGtGenProcedure& rProc) { lProc.Append(rProc); return lProc;}
/*! @} */

#pragma pack(pop)
}
#endif
