ExampleUtils.h

// ExampleUtils.h
//
// Author Jesse Pepper
// (C)opyright Cedanet Pty Ltd 2007

#include "Ceda/cxUtils/xstring.h"
#include "Ceda/cxUtils/TracerUtils.h"
@import "Ceda/cxObject/Object.h"

@def mTypedef(Class, Type, unitString, unitsPerBaseUnit, isIntegerType, FromClass0, FromClass1, FromClass2) =
{
    $struct FromClass0;
    $struct FromClass1;
    $struct FromClass2;
    
    $struct Class
    {
        typedef Type TypeName;
        
        Class(Type t) : m_value(t) {}
        
        @def mDeclConvFrom(FromClassN) = 
        {
            Class(const FromClassN& from);
        }
        
        mDeclConvFrom(FromClass0)
        mDeclConvFrom(FromClass1)
        mDeclConvFrom(FromClass2)
        
        //xostream& operator<<(xostream& os) { return os << m_value << unitString << '\n'; }
        
        operator Type() { return m_value; }
        operator const Type() const { return m_value; }
        
        static Type UnitsPer@@BaseUnit() { return unitsPerBaseUnit; }
        static Type BaseUnit@@sPerUnit() { return 1.0/unitsPerBaseUnit; }
                    
        template<typename T> Class& operator=(const T& other) const
        {
            return Convert(*this,other);
        }
        
        @def oper1pre(op) =
        {
            inline Class operator @unstr(op)() { return Class(@unstr(op)m_value); }
        }
        
        oper1pre("++")
        oper1pre("--")
        oper1pre("+")
        oper1pre("-")
        @if (isIntegerType) { oper1pre("~") }
        
        @def oper1prebool(op) =
        {
            inline bool operator @unstr(op)() { return @unstr(op)m_value; }
        }
        oper1prebool("!")
        
        @def oper1post(op) = 
        {
            inline Class operator @unstr(op)(int) { return Class(m_value@unstr(op)); }
        }

        oper1post("++")
        oper1post("--")
        
        @def oper2T(op) =
        {
            inline Class operator @unstr(op)(const Class& other) { return Class( m_value @unstr(op) other.m_value ); }
        }
        
        oper2T("+")
        oper2T("-")
        oper2T("*")
        oper2T("/")
        oper2T("<")
        oper2T(">")
        oper2T("+=")
        oper2T("-=")
        oper2T("*=")
        oper2T("/=")
        
        @if (isIntegerType) 
        { 
            oper2T("%")
            oper2T("^")
            oper2T("&")
            oper2T("|")
            oper2T("=")
            oper2T("%=")
            oper2T("^=")
            oper2T("&=")
            oper2T("|=")
            oper2T("<<")
            oper2T(">>")
            oper2T(">>=")
            oper2T("<<=")
        }
        
        
        @def oper2bool(op) =
        {
            inline bool operator @unstr(op) (const Type& other) { return m_value @unstr(op) other; }
        }
        
        oper2bool("==")
        oper2bool("!=")
        oper2bool("<=")
        oper2bool(">=")
        oper2bool("&&")
        oper2bool("||")

    private:
        Type m_value;
        
        friend xostream& operator<<(xostream& os, const Class& c);
    };
    
    xostream& operator<<(xostream& os, const Class& c) { return os << c.m_value << unitString << '\n'; }
}
    
@def mConvOutsideFromTo(FromClass, ToClass) = 
{
    ToClass::ToClass(const FromClass& from)
    {
        m_value = (((FromClass::TypeName)from)*
               ((FromClass::TypeName)FromClass::BaseUnitsPerUnit()) *
               ((ToClass::TypeName)UnitsPerBaseUnit()));
    }
}

/*
mTypedef(Distance, float64, " metres", 1.0, false, ImperialDistance, AstroDistance, AtomicDistance);
mTypedef(AstroDistance, float64, " Light Years", 9.5e12, false, Distance, ImperialDistance, AtomicDistance);
mTypedef(ImperialDistance, float64, " feet", 0.3042, false, Distance, AstroDistance, AtomicDistance);
mTypedef(AtomicDistance, float64, " Angstroms", 1e-10, false, Distance, AstroDistance, ImperialDistance);


mConvOutsideFromTo(ImperialDistance, Distance)
mConvOutsideFromTo(AstroDistance, Distance)
mConvOutsideFromTo(AtomicDistance, Distance)

mConvOutsideFromTo(Distance, ImperialDistance)
mConvOutsideFromTo(Distance, AstroDistance)
mConvOutsideFromTo(Distance, AtomicDistance)

mConvOutsideFromTo(AstroDistance, ImperialDistance)
mConvOutsideFromTo(AtomicDistance, ImperialDistance)

mConvOutsideFromTo(AtomicDistance, AstroDistance)
mConvOutsideFromTo(ImperialDistance, AstroDistance)

void TakesFloat32(float32 f)
{
    Tracer() << "TakesFloat32, f = " << f << '\n';
}

void TakesFloat64(float64 f)
{
    Tracer() << "TakesFloat64, f = " << f << '\n';
}

void TakesDistance(Distance f)
{
    Tracer() << "TakesDistance, f = " << f << '\n';
}

void TakesAstroDistance(AstroDistance f)
{
    Tracer() << "TakesAstroDistance, f = " << f << '\n';
}

void TakesImperialDistance(ImperialDistance f)
{
    Tracer() << "TakesImperialDistance, f = " << f << '\n';
}
    
void Foo()
{
    Distance a = 0.74;
    Distance b = 0.39;
    AstroDistance ad = 1.0;
    ImperialDistance id = 1.0;
    AtomicDistance atd = 1.0;
    
    Tracer() << "a + b = " << a + b << '\n';
    Tracer() << "a / b = " << a / b << '\n';
    Tracer() << "a * b = " << a * b << '\n';
    Tracer() << "a - b = " << a - b << '\n';
    Tracer() << "-a - +b = " << -a - +b << '\n';
    a *= b;
    Tracer() << "a after a *= b = " << a << '\n';
    
    TakesFloat32((float32)a);
    TakesFloat64(a);
    TakesDistance(a);
    TakesDistance(ad);
    TakesDistance(id);
    TakesDistance(atd);
    TakesAstroDistance(a);
    TakesAstroDistance(id);
    TakesAstroDistance(ad);
    TakesAstroDistance(atd);
    TakesImperialDistance(a);
    TakesImperialDistance(id);
    TakesImperialDistance(ad);
    TakesImperialDistance(atd);
    
    //Tracer() << "a == b = " << a == b << '\n';
}

$class TimeSpan
{
    xostream& PrintType(xostream& os)
    {
        float64 absValue = fabs(value);
        if (UseExponentialNotation()) return os << value << "s";
        else if (absValue == 0.0) os << value << "s";
        else if (0.0 < absValue && absValue < 1e-3) os << (value * 1e6) << "usec";
        else if (1e-3 <= absValue && absValue < 1.0) os << (value * 1e3) << "ms";
        else if (1.0 <= absValue && absValue < 60.0) os << (value) << "s";
        else if (60.0 <= absValue && absValue < 3600.0) 
        {
            int mins = (int)(value/60.0);
            os << mins << ':' << value - mins*60.0;
        }
        else if (3600.0 <= absValue && absValue < 3600.0*24) 
        {
            int hours = (int)(value/3600.0);
            int mins = (int)(value/60.0) - hours*60;
            float64 secs = value - mins*60.0;
            os << hours << ':' << mins << ':' << secs;
        }
        else if (3600.0*24 <= absValue && absValue < 3600.0*24*365.25) 
        {
            int hours = (int)(value/3600.0);
            int mins = (int)(value/60.0) - hours*60;
            float64 secs = value - mins*60.0
            os << hours << ':' << mins << ':' << value - mins*60.0;
        }
        //etc...
    }
    float64 value;
};
*/