ReflectedInstance.h

// ReflectedInstance.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2020

@import "cxObject.h"
@import "ReflectionByteCode.h"
@import "PrintReflectedType.h"

// We use the term 'instance' to mean either a variable or value.  
// 'const' is not used to protect a value from being modified.

namespace ceda
{
@def CEDA_COERCE_TYPES = [bool, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, char8, char16, string8, string16]

///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedInstance

struct @api ReflectedInstance
{
    ReflectedInstance() : addr(nullptr) {}

    // Since there are implicit conversions from const ReflectedClass&  to ReflectionByteCode, 
    // this ctor also allows for setting up a ReflectedInstance for a class instance.
    // Similarly for various other specialised kinds of reflected instances.
    ReflectedInstance(ReflectionByteCode rbc, void* addr) : rbc(rbc), addr(addr) {}

    explicit ReflectedInstance(bool* v) : rbc(ReflectionByteCode::MakeLeaf(FT_BOOL)), addr(v) {}
    explicit ReflectedInstance(int8* v) : rbc(ReflectionByteCode::MakeLeaf(FT_INT8)), addr(v) {}
    explicit ReflectedInstance(int16* v) : rbc(ReflectionByteCode::MakeLeaf(FT_INT16)), addr(v) {}
    explicit ReflectedInstance(int32* v) : rbc(ReflectionByteCode::MakeLeaf(FT_INT32)), addr(v) {}
    explicit ReflectedInstance(int64* v) : rbc(ReflectionByteCode::MakeLeaf(FT_INT64)), addr(v) {}
    explicit ReflectedInstance(uint8* v) : rbc(ReflectionByteCode::MakeLeaf(FT_UINT8)), addr(v) {}
    explicit ReflectedInstance(uint16* v) : rbc(ReflectionByteCode::MakeLeaf(FT_UINT16)), addr(v) {}
    explicit ReflectedInstance(uint32* v) : rbc(ReflectionByteCode::MakeLeaf(FT_UINT32)), addr(v) {}
    explicit ReflectedInstance(uint64* v) : rbc(ReflectionByteCode::MakeLeaf(FT_UINT64)), addr(v) {}
    explicit ReflectedInstance(float32* v) : rbc(ReflectionByteCode::MakeLeaf(FT_FLOAT32)), addr(v) {}
    explicit ReflectedInstance(float64* v) : rbc(ReflectionByteCode::MakeLeaf(FT_FLOAT64)), addr(v) {}
    explicit ReflectedInstance(char8* v) : rbc(ReflectionByteCode::MakeLeaf(FT_CHAR8)), addr(v) {}
    explicit ReflectedInstance(char16* v) : rbc(ReflectionByteCode::MakeLeaf(FT_CHAR16)), addr(v) {}
    explicit ReflectedInstance(string8* v) : rbc(ReflectionByteCode::MakeLeaf(FT_STRING8)), addr(v) {}
    explicit ReflectedInstance(string16* v) : rbc(ReflectionByteCode::MakeLeaf(FT_STRING16)), addr(v) {}

    static ReflectedInstance FromConstString8Z(ConstString8Z* v) { return ReflectedInstance( ReflectionByteCode::ForConstString8Z(), v ); }
    static ReflectedInstance FromConstString16Z(ConstString16Z* v) { return ReflectedInstance( ReflectionByteCode::ForConstString16Z(), v ); }

    // throw UnsupportedException if not supported
    void Destruct();
    void Construct();
    void CopyConstruct(const void* rhs);        // Copy construct from variable of the same type
    void CopyAssign(const void* rhs);           // Copy assign from variable of the same type

    // return false if not supported
    bool TryCopyAssign(ReflectedInstance rhs, bool allowExplicitConversions);
    bool TryCopyConstruct(ReflectedInstance rhs, bool allowExplicitConversions);

    @for(T in CEDA_COERCE_TYPES)
    {
        bool TryCoerce(T& v, bool allowExplicitConversions=false);
        void Coerce(T& v, bool allowExplicitConversions=false);       // Throws UnsupportedException if cannot coerce

    }
    
    ReflectionByteCode rbc;
    void* addr;
};

@api void PrintReflectedInstance(xostream& os, ReflectedInstance v, bool allowMultiLine = true, const PrintTypeSettings& pts = PrintTypeSettings());

///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedClassInstance

struct ReflectedClassInstance
{
    ReflectedClassInstance() : rc(nullptr), addr(nullptr) {}
    ReflectedClassInstance(const ReflectedClass* rc, void* addr) : rc(rc), addr(addr) {}
    ReflectedClassInstance(ReflectedInstance r)
    {
        cxAssert(*r.rbc == FT_CLASS);
        rc = r.rbc.GetReflectedClass();
        addr = r.addr;
    }

    const ReflectedClass* rc;
    void* addr;
};

/*
// These throw UnsupportedException if the operation is not supported
inline bool operator==(ReflectedClassInstance a, ReflectedClassInstance b) { return CompareEqReflectedClassVariables(*a.rc, a.addr, *b.rc, b.addr); }
inline bool operator<(ReflectedClassInstance a, ReflectedClassInstance b)  { return CompareLtReflectedClassVariables(*a.rc, a.addr, *b.rc, b.addr); } 
inline bool operator!=(ReflectedClassInstance a, ReflectedClassInstance b) { return !(a==b); }
inline bool operator>(ReflectedClassInstance a, ReflectedClassInstance b) { return b < a; }
inline bool operator<=(ReflectedClassInstance a, ReflectedClassInstance b) { return !(b < a); }
inline bool operator>=(ReflectedClassInstance a, ReflectedClassInstance b) { return !(a < b); }
*/

///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedVariantInstance

struct ReflectedVariantInstance
{
    ReflectedVariantInstance() : rv(nullptr), addr(nullptr) {}
    ReflectedVariantInstance(const ReflectedVariant* rv, void* addr) : rv(rv), addr(addr) {}
    ReflectedVariantInstance(ReflectedInstance r)
    {
        cxAssert(*r.rbc == FT_VARIANT);
        rv = r.rbc.GetReflectedVariant();
        addr = r.addr;
    }

    const ReflectedVariant* rv;
    void* addr;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// Comparisons

@for(T in CEDA_COERCE_TYPES)
{
    inline bool operator==(ReflectedInstance a, const T& b)
    {
        T v;
        a.Coerce(v);
        return v == b;
    }
    inline bool operator<(ReflectedInstance a, const T& b)
    {
        T v;
        a.Coerce(v);
        return v < b;
    }
    inline bool operator<(const T& b, ReflectedInstance a)
    {
        T v;
        a.Coerce(v);
        return b < v;
    }
    inline bool operator==(const T& a, ReflectedInstance b) { return b == a; }

    inline bool operator!=(ReflectedInstance a, const T& b) { return !(a==b); }
    inline bool operator!=(const T& a, ReflectedInstance b) { return !(a==b); }

    inline bool operator>(ReflectedInstance a, const T& b) { return b < a; }
    inline bool operator>(const T& a, ReflectedInstance b) { return b < a; }

    inline bool operator<=(ReflectedInstance a, const T& b) { return !(b < a); }
    inline bool operator<=(const T& a, ReflectedInstance b) { return !(b < a); }

    inline bool operator>=(ReflectedInstance a, const T& b) { return b <= a; }
    inline bool operator>=(const T& a, ReflectedInstance b) { return b <= a; }

}

/*
Given T1<T2 and T1==T2, generate

    T1 != T2
    T2 > T1
    T2 <= T1
    T1 >= T2
*/

// These throw UnsupportedException if the operation is not supported
@api bool operator==(ReflectedInstance a, ReflectedInstance b);
@api bool operator<(ReflectedInstance a, ReflectedInstance b);

@api bool operator==(ReflectedClassInstance a, ReflectedClassInstance b);
@api bool operator<(ReflectedClassInstance a, ReflectedClassInstance b);

@api bool operator==(ReflectedVariantInstance a, ReflectedVariantInstance b);
@api bool operator<(ReflectedVariantInstance a, ReflectedVariantInstance b);

@api bool operator==(ReflectedInstance a, ReflectedClassInstance b);
inline bool operator==(ReflectedClassInstance a, ReflectedInstance b) { return b == a; }
@api bool operator<(ReflectedInstance a, ReflectedClassInstance b);
@api bool operator<(ReflectedClassInstance a, ReflectedInstance b);

@api bool operator==(ReflectedInstance a, ReflectedVariantInstance b);
inline bool operator==(ReflectedVariantInstance a, ReflectedInstance b) { return b == a; }
@api bool operator<(ReflectedInstance a, ReflectedVariantInstance b);
@api bool operator<(ReflectedVariantInstance a, ReflectedInstance b);

@api bool operator==(ReflectedClassInstance a, ReflectedVariantInstance b);
inline bool operator==(ReflectedVariantInstance a, ReflectedClassInstance b) { return b == a; }
@api bool operator<(ReflectedClassInstance a, ReflectedVariantInstance b);
@api bool operator<(ReflectedVariantInstance a, ReflectedClassInstance b);

/*
inline bool operator!=(ReflectedInstance a, ReflectedInstance b) { return !(a==b); }
inline bool operator>(ReflectedInstance a, ReflectedInstance b) { return b < a; }
inline bool operator<=(ReflectedInstance a, ReflectedInstance b) { return !(b < a); }
inline bool operator>=(ReflectedInstance a, ReflectedInstance b) { return !(a < b); }
*/

@def CEDA_GENERATE_REMAINING_FOUR_COMPARISON_OPERATIONS(L) =
{
    @for(T1 in L)
    {
        @for(T2 in L)
        {
            inline bool operator!=(const T1& a, const T2& b) { return !(a==b); }
            inline bool operator>(const T1& a, const T2& b) { return b < a; }
            inline bool operator<=(const T1& a, const T2& b) { return !(b < a); }
            inline bool operator>=(const T1& a, const T2& b) { return !(a < b); }

        }
    }
}

CEDA_GENERATE_REMAINING_FOUR_COMPARISON_OPERATIONS([ReflectedInstance, ReflectedClassInstance, ReflectedVariantInstance])

} // namespace ceda