
module;
#include <iostream>
#include <string>
#include <string_view>
#include <stdexcept>

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

export module CData3;

export class CData3
{
    std::string text;
    // Objektzaehler fuer Debug-Zwecke
    inline static int objCount = 0;
    int objNum;             // Objektnummer
public:
    // Standard-ctor
    CData3();
    // ctor mit Text
    CData3(std::string_view _text);
    // copy-ctor
    CData3(const CData3& src);
    // move-ctor
    CData3(CData3&& src);
    // Zuweisungsoperator
    CData3& operator = (this CData3& self, const CData3& src);
    // move-Zuweisungsopertor
    CData3& operator = (this CData3& self, CData3&& src);
    // dtor
    ~CData3();
    // Ausgabe des Datenfeldes
    friend std::ostream& operator << (std::ostream& out, const CData3& obj);
    // Ueberladener Indexoperator
    auto operator [] (size_t index);
    // space-operator
    auto operator <=> (this const CData3& self, const CData3& op2);
    // Vergleich auf Gleichheit
    bool operator == (const CData3& op2) const;
};
// Standard-ctor
CData3::CData3()
{
    objNum = ++objCount;
    TRACE(">>> ctor CData3()");
}
// ctor mit Datenfeldgroesse
CData3::CData3(std::string_view _text): text(_text)
{
    objNum = ++objCount;
    TRACE(">>> ctor CData3(text)");
}
// copy-ctor
CData3::CData3(const CData3& src): text(src.text)
{
    objNum = ++objCount;
    TRACE(">>> copy-ctor")
}
// move ctor
CData3::CData3(CData3&& src)
{
    // Der move-ctor von std::string versetzt das
    // Quellobjekt in einen gueltigen Zustand
    text = std::move(src.text);
    objNum = src.objNum;
    TRACE(">>> move-ctor");
}
// Zuweisungsoperator
CData3& CData3::operator = (this CData3& self, const CData3& src)
{
    if (&self == &src)   // keine Zuweisung auf sich selbst!
        return self;
    self.text = src.text;  // neue Daten uebernehmen
    TRACES("operator =");
    return self;
}
// move-Zuweisungsopertor
CData3& CData3::operator = (this CData3& self, CData3&& src)
{
    if (&self == &src)   // keine Zuweisung auf sich selbst!
        return self;
    self.text = std::move(src.text);  // neue Daten uebernehmen
    TRACES("move-operator =");
    return self;
}
// dtor
CData3::~CData3()
{
    TRACE("<<< dtor");
}
// Ueberladener Indexoperator
auto CData3::operator [] (size_t index)
{
    if ((index < 0) || (index >= text.length()))
        throw std::out_of_range("Index ausserhalb des Bereichs!");
    return text[index];
}
// Ausgabe des Datenfeldes
export std::ostream& operator << (std::ostream& out, const CData3& obj)
{
    out << obj.text;
    return out;
}
// space-operator
auto CData3::operator <=> (this const CData3& self, const CData3& op2)
{
    // Nun die Daten vergleichen
    // Aufruf des operators ==
    return (self == op2) <=> true;
}
// Vergleich auf Gleichheit
bool CData3::operator == (const CData3& op2) const
{
    // Nun die Daten vergleichen
    return text == op2.text;
}
