Comparisons.cpp

// Comparisons.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007

@import "Ceda/cxPython/cxPython.h"
#include "Ceda/cxUtils/TracerUtils.h"

@def mPrint(v) = print @str(v = ) + `v`

@def mShowComparisons(x,y) =
{
    print `x` + ' ' + `y` + ' : ',
    @def m(op) =
    {
        if x op y:
            print @str( op ),
    }
    m(==)
    m(!=)
    m(<)
    m(>)
    m(<=)
    m(>=)
    print
}


///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Class value comparisons
-----------------------

A reflected class/struct that has operator==() allows for equality comparisons in Python
using == and !=.

A reflected class/struct that has operator<() allows for order comparisons in Python
using <   >   <=  >=.
*/

namespace Comparisons1
{
    $struct+ X <<os returnbyvalue passbyvalue /*should only appear when no default ctor or dtor present */ >>
    {
        //X(ceda::int32 x = 0) : m_x(x) {}
        //~X() {}
        
        $ceda::int32 Get() const { return m_x; }
        void Set(int x) { m_x = x; }
        
        void Write(ceda::xostream& os) { os << m_x; }
        
        $ceda::int32 m_x;
    };
    
    bool operator==(X x1, X x2) { return x1.m_x == x2.m_x; }
    bool operator<(X x1, X x2) 
    { 
        Tracer() << "X::operator<(x1 = " << x1 << ", x2 = " << x2 << "\n";
        return x1.m_x < x2.m_x; 
    }
    bool operator<=(X x1, X x2) { return x1.m_x <= x2.m_x; }

	$function+ X CreateX(ceda::int32 x)
	{
        X ret;
        ret.m_x = x;
        Tracer() << "CreateX(), x = " << x << "\n";
        return ret;
	    //return X(x);
	}

    $function+ void SetX(X& x, ceda::int32 val)
    {
        x.m_x = val;
        Tracer() << "Setting x at " << &x << " to " << val << "\n";
    }
	
	void Run()
	{
		ceda::TraceGroup g("Class Comparisons");
		
        PyRun_SimpleString(
            @strx
            (
                Comparisons1 = rootnamespace.Comparisons1
                CreateX = Comparisons1.CreateX
                SetX = Comparisons1.SetX
                
                print 'Create x1'
                x1 = CreateX(100)
                #SetX(x1,99)
                print 'x1 = ' + `x1`
                x2 = CreateX(200)
                #SetX(x2,199)
                print 'x2 =' + `x2`
                Assert(x1 < x2)
                
                mShowComparisons(CreateX(100), CreateX(100))
                mShowComparisons(CreateX(100), CreateX(200))
                mShowComparisons(CreateX(200), CreateX(100))
            ));
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Vector comparisons
------------------

Two xvector<T> values in the same element type T can be compared as long a T can be compared.

xvectors can be compared in Python using the following operators

    ==  !=  <   >   <=  >=
*/

namespace Comparisons2
{
	$function+ ceda::xvector<ceda::int32> Create()
	{
	    return ceda::xvector<ceda::int32>();
	}
	
	void Run()
	{
		ceda::TraceGroup g("xvector Comparisons");
		
        PyRun_SimpleString(
            @strx
            (
                Create = rootnamespace.Comparisons2.Create
                
                mShowComparisons(Create(), Create())
                
                mShowComparisons(Create(), Create() + [1])
                mShowComparisons(Create() + [1], Create())
                
                mShowComparisons(Create() + [1], Create() + [1])
                mShowComparisons(Create() + [1], Create() + [2])
                mShowComparisons(Create() + [2], Create() + [1])

                mShowComparisons(Create() + [1,2,10], Create() + [1,2,10])
                mShowComparisons(Create() + [1,2,10], Create() + [1,2,20])
                mShowComparisons(Create() + [1,2,20], Create() + [1,2,10])
            ));
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/*
int64, uint64 comparisons
-------------------------

int64, uint64 can be compared in Python using the following operators

    ==  !=  <   >   <=  >=
*/

namespace Comparisons3
{
	void Run()
	{
		ceda::TraceGroup g("int64, uint64 comparisons");
		
        PyRun_SimpleString(
            @strx
            (
                i64 = rootnamespace.Int64.Make
                ui64 = rootnamespace.UInt64.Make
                
                mShowComparisons(i64(1,0), i64(1,0))
                mShowComparisons(i64(1,0), i64(2,0))
                mShowComparisons(i64(2,0), i64(1,0))

                mShowComparisons(ui64(1,0), ui64(1,0))
                mShowComparisons(ui64(1,0), ui64(2,0))
                mShowComparisons(ui64(2,0), ui64(1,0))
                
                mShowComparisons(i64(-1,-1), i64(0,0))
                mShowComparisons(i64(0,0), i64(-1,-1))

                mShowComparisons(ui64(-1,-1), ui64(0,0))
                mShowComparisons(ui64(0,0), ui64(-1,-1))
            ));
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////
/*
ptr<T> comparisons
------------------

ptr<T> can be compared in Python using the following operators

    ==  !=  <   >   <=  >=
    
This ends up comparing the AnyInterface.m_self values, and allows for identity comparison through
different implemented interfaces.
*/

namespace Comparisons4
{
    $interface+ Ix : ceda::IObject
    {
        void foo();
    };

    $interface+ Iy : ceda::IObject
    {
        void bar();
    };
    
    $struct+ X isa Ix,Iy
    {
        void foo() {}
        void bar() {}
    };
    
    $function+ ceda::ptr<Ix> CreateX() { return new X(); }

    $function+ ceda::ptr<Iy> AsIy(ceda::ptr<Ix> ix) { return ceda::qicast<Iy>(ix); }

	void Run()
	{
		ceda::TraceGroup g("ptr<T> comparisons");
		
        @if (true)
        {
            /*
            Appropriate if ptr<T>::operator==() only tests m_self.
            */
            PyRun_SimpleString(
                @strx
                (
                    CreateX = rootnamespace.Comparisons4.CreateX
                    AsIy = rootnamespace.Comparisons4.AsIy
                    
                    ix = CreateX()
                    iy = AsIy(ix)
                    Assert( ix == iy )
                    Assert( ix <= iy )
                    Assert( ix >= iy )
                    
                    ix1 = ix
                    Assert( ix1 == ix )

                    ix2 = CreateX()

                    Assert( ix1 != ix2 )
                ));
        }
        @else
        {
            /*
            Appropriate if ptr<T>::operator==() tests both the m_self and m_table pointers.
            */
            PyRun_SimpleString(
                @strx
                (
                    CreateX = rootnamespace.Comparisons4.CreateX
                    AsIy = rootnamespace.Comparisons4.AsIy
                    
                    ix = CreateX()
                    iy = AsIy(ix)
                    Assert( ix != iy )
                    
                    ix1 = ix
                    Assert( ix1 == ix )

                    ix2 = CreateX()

                    Assert( ix1 != ix2 )
                ));
        }
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
namespace Comparisons
{
    void Run()
    {
        Comparisons1::Run();
        Comparisons2::Run();
        Comparisons3::Run();
        Comparisons4::Run();
    }
}