module;
#include <print>
#include <cstdlib>

// Makro für Debug-Ausgaben
// #define TRACE_METH
#ifdef TRACE_METH
#define TRACE(T_)   std::println("Obj-Nr:{} {}",objNum,T_);
#else
#define TRACE(T_)
#endif

export module CAny;

export class CAny
{
    int* pData = nullptr;   // Zeiger auf Datenfeld
    size_t dSize;           // Groesse Datenfeld
    // Objektzaehler fuer Debug-Zwecke
    inline static int objCount = 0;
    int objNum;             // Objektnummer
public:
    // Default-ctor (pData=nullptr!)
    CAny();
    // ctor mit Datenfeldgroesse
    CAny(size_t _dSize);
    // copy-ctor
    CAny(const CAny& src);
    // move-ctor
    CAny(CAny&& src);
    // Zuweisungsoperator
    CAny& operator = (const CAny& src);
    // move-Zuweisungsopertor
    CAny& operator = (CAny&& src);
    // dtor
    ~CAny();
    // Datenfeld belegen
    void SetData();
    // Ausgabe des Datenfeldes
    void Print() const;
};
CAny::CAny()
{
    objNum = ++objCount;
    TRACE(">>> ctor CAny()");
}
// ctor mit Datenfeldgroesse
CAny::CAny(size_t _dSize)
{
    dSize = _dSize;
    pData = new int[dSize];
    for (size_t index = 0; index < dSize; index++)
        pData[index] = std::rand() % 100;
    objNum = ++objCount;
    TRACE(">>> ctor CAny(size)");
}
// copy-ctor
CAny::CAny(const CAny& src) :
    CAny(src.dSize)
{
    for (size_t index = 0; index < dSize; index++)
        pData[index] = src.pData[index];
    TRACE(">>> copy-ctor")
}
// move ctor
CAny::CAny(CAny&& src)
{
    dSize = src.dSize;
    pData = std::move(src.pData);
    src.pData = nullptr;    // WICHTIG!!!!
    objNum = ++objCount;
    TRACE(">>> move-ctor");
}
// Zuweisungsoperator
CAny& CAny::operator = (const CAny& src)
{
    if (this == &src)   // keine Zuweisung auf sich selbst!
        return *this;
    delete[] pData;     // bisherige Daten freigeben
    dSize = src.dSize;  // neue Daten uebernehmen
    pData = new int[dSize];
    for (size_t index = 0; index < dSize; index++)
        pData[index] = src.pData[index];
    TRACE("operator =");
    return *this;
}
// move-Zuweisungsopertor
CAny& CAny::operator = (CAny&& src)
{
    if (this == &src)   // keine Zuweisung auf sich selbst!
        return *this;
    delete[] pData;     // bisherige Daten loeschen
    dSize = src.dSize;  // neue Daten uebernehmen
    pData = src.pData;  // durch Zuweisung des Zeigers
    src.pData = nullptr;    // WICHTIG!!!!
    TRACE("move-operator =");
    return *this;
}
// dtor
CAny::~CAny()
{
    delete[] pData;
    TRACE("<<< dtor");
}
// Datenfeld mit Zufallszahlen belegen
void CAny::SetData()
{
    for (size_t index = 0; index < dSize; index++)
        pData[index] = std::rand() % 100;
}
// Ausgabe des Datenfeldes
void CAny::Print() const
{
    std::println("Daten Objekt {}:\t", objNum);
    for (size_t index = 0; index < dSize; index++)
        std::print("{:3},", pData[index]);
    std::println();
}
