pref.h

// pref.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2006

/*
pref<T>
-------

A pref<T> is a smart pointer typically used within one persistent object to allow it to store a 
(typed) pointer to another persistent object.  T is an interface that must inherit directly or 
indirectly from IObject.  There is no requirement that T inherit from IPersistable.

Naturally the referenced persistent object must implement IPersistable (as well as T).

The following code shows an example of a pref<T>


    $interface IAutomobile : IObject
    {
        ptr<IEngine> GetEngine();
    }

    $class Automobile isa IAutomobile, IPersistable
    {
    public:
        Automobile() {}

        void VisitObjects(IObjectVisitor& v) const 
        { 
            v << m_engine;
        }

        const schema_t SCHEMA = 1;

        template<typename Archive>
        void Serialise(Archive& ar) const
        {
            SerialiseSchema(ar, SCHEMA);
            ar << m_engine;
        }

        template<typename Archive>
        void Deserialise(Archive& ar)
        {
            schema_t schema = DeserialiseSchema(ar,SCHEMA);
            ar >> m_engine;
        }

        ptr<IEngine> GetEngine() { return m_engine; }

    private:
        pref<IEngine> m_engine;
    };

A pref<T> can represent a null pointer.  In fact the default constructor initialises a pref<T> to
a null pointer.

A pref<T> can be compared to any raw IObject ptr, or any pref<S> for any S.  This will correctly
perform object identity testing.

A pref<T> stores the following members
    *   The 64 bit OID
    *   A ptr<T> pointer to the object in memory (or null)

When a pref<T> is serialised to an Archive, the 64 bit OID is written (or a null OID if the pref<T>
is a null pointer).

Typically, the memory pointer only binds to the object in memory when the pref<T> is dereferenced. 

A pref<T> can be de-referenced, using operator*().  This performs the following steps

    *   If the pref<T> is null then a "Dereference null pointer" exception error is thrown.

    *   Otherwise, if the pref<T> is already bound to an object in memory, then a reference to the
        object in memory is returned

    *   Otherwise, the Resident Object Table (ROT) is consulted to see whether the object with 
        given OID resides in memory.  If so then the pref<T> binds to the object, and a reference
        to the object in memory is returned

    *   Otherwise, the object is loaded from disk,  recorded in the ROT, then a reference to the
        object in memory is returned

In the literature this is called "software swizzling".

A class that has pref<T> members must ensure it visits them in its implementation of VisitObjects().

cref<T>
-------

This is an alternative to a pref<T> that can be used when there is no need or desire to deal with a 
class indirectly through an interface.  For example, this is used in the implementation of a PDeque
to allow the PDeque pages to form a double linked list without any need to define or implement
interfaces.

A cref<T> is actually implemented as a pref<IPersistable>.  T is assumed to be the concrete class of
the persistent object referenced by the cref<T>.  The void* self pointer stored within the 
ptr<IPersistable> is assumed to be a pointer to a T.  This assumption complies with the way 
interfaces are implemented.

Dangling prefs
--------------

TODO

Persistent garbage collection
-----------------------------

TODO

Weak references
---------------

To allow the framework to automatically clone graphs of objects it is necessary to distinguish 
between strong and weak references.

Pref visit mode
---------------

TODO

Implementation notes
--------------------

The framework needs to be able to deal with a pref<T>, despite the template parameter T. In 
particular it must be possible for the framework to set and get as an IPersistable.  This has 
the useful side effect of reducing code bloat.

As it turns out, an 8 byte interface that inherits (first) from IObject can be safely upcast to an
IObject.  Therefore the framework is able to get the IPersistable from the pref<T>.

Unfortunately it doesn't seem possible for the framework to set the pref<T> using a ptr<IObject>,
unless the framework knows the ReflectedInterface.

IDEA:  Perhaps we can assume that the framework deals with the reflection information and therefore
it indeed knows the ReflectedInterface associlated with the pref<T>.  This will allow it to set the
8 byte pointer.

class prefbase
{
    void SetWithPtr(ptr<IObject> p, const ReflectedInterface& ri)
    {
        if (p)
        {
            ptr<IPersistable> po = qicast<IPersistable>(p);
            if (!po) throw exception;
            m_oid = po->GetOid();    // Might be null OID if p is not reachable from persistent root
            m_ptr = p->QueryInterface(ri);
            if (!m_ptr) throw exception;
        }
        else
        {
            m_oid.SetNull();
            m_ptr = null;
        }
    }

    OID m_oid;
    ptr<IObject> m_ptr;     // Actually a ptr<T>, where T inherits first from IObject
}

Asynchronous binding of prefs
-----------------------------

We need a version of a pref that supports asynchronous loading of objects from disk, or downloading
of objects from a repository.   The PersistStore layer shouldn't know about repositories so a hook
will be provided to allow the repository system to be called back in order to fault in objects for
given OID on demand.

The asynchronous approach will work with the dependency graph system in order to 

*	establish the dependency on the pref so that when binding occurs, upstream nodes can be marked 
    as dirty
    
*	the active state of the pref as a dependent node causes it to asynchronously load the data.  If 
    the node transitions to inactive then the asynchronous download request will be cancelled.


Reasons for using prefs
-----------------------

Prefs are made to point at IPersistable objects for a variety of somewhat orthogonal 
reasons:

    *	Defining the granularity for clustering data on disk

    *	Defining the granularity for loading data from disk

    *	Defining the granularity for marking data as dirty and writing data to disk

    *	Allowing for open variants (e.g. an unbounded set of value types that represent 
        shapes)
        
    *	Allowing for null pointers which is like a variant with a void member.
    
    *	Independently editable objects that keep their identity when they're moved.

For this reason, it is dangerous to assume prefs are a satisfactory basis for defining
logical data models.  Instead it is better to regard them as a lower level implementation 
technique.  This has repercussions for how prefs appear in $models.
*/

@import "cxPersistStore.h"
@import "OID.h"
@import "IPersistable.h"
@import "Ceda/cxObject/Object.h"
@import "Ceda/cxObject/ReflectionByteCode.h"

namespace ceda
{

///////////////////////////////////////////////////////////////////////////////////////////////////
// Allow the visit mode for a pref<T> to be set in thread local storage

@if (false)
{
    $enum EPrefVisitMode
    {
        PVM_MEMORY,     // Visit pointer in memory if already faulted in memory  [default]
        PVM_DISK        // Fault into memory if necessary
    };

    class @api SetPrefVisitMode
    {
    public:
        SetPrefVisitMode(EPrefVisitMode pvm);
        ~SetPrefVisitMode();

    private:
        EPrefVisitMode m_prev;
    };

    @api EPrefVisitMode GetPrefVisitMode();
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// prefbase
// Allows some of the implementation of pref<T> or cref<T> to be implemented in pref.cpp to avoid 
// code bloat

class @api prefbase
{
public:
    prefbase();

    // Default copy ctor and operator= used

    void VisitObjects(IObjectVisitor& v) const;

    bool operator<(const prefbase& rhs) const;

    // Is this a null pointer?
    // Doesn't try to bind to the object and therefore this never blocks on I/O and never throws 
    // a dangling oid exception
    explicit operator bool() const;

    OID GetOid() const;
    void SetOid(OID oid);

    // p can be null
    void Set(ptr<IPersistable> p);
    
    // p can be null.  If p != null then qicast<IPersistable>(p) must not be null
    void Set2(ptr<IObject> p);
    
    // Same as Set(null)
    void Clear();

    void WriteToStream(xostream& os) const;

    // Serialise the pref from/to the given archive.  weakRef indicates whether the pref represents
    // a weak reference for the purposes of cloning an assembly of objects.
    void Serialise(Archive& ar, bool weakRef) const;
    void Deserialise(InputArchive& ar, bool weakRef);
    
    // Same as Get() except returns null if object has an OID assigned
    ptr<IPersistable> GetTransient() const;
    
    // Returns true if this pref is not null and points at a transient object (i.e. that has no oid
    // assigned).
    //bool IsTransient() const;

    //////////////// Binding that tries m_ptr ///////////////////

    // Has this pref bound to an object in memory?
    bool IsBound() const { return m_ptr != null; }

    // Get the pointer to the object if this pref has been bound
    ptr<IPersistable> GetBoundPtr() const { return m_ptr; }

    // Same as GetBoundPtr() but performs a subsequent qicast<> for the given interface.
    // May additionally throw TypeMismatchException
    AnyInterface qiGetBoundPtr(const ReflectedInterface& ri) const;

    //////////////// Binding that tries m_ptr then the ROT ///////////////////

    // Returns a ptr to the object if in memory.  Returns null if this pref is null or the 
    // object is not resident in memory (i.e. recorded in the Resident Object Table).
    ptr<IPersistable> GetInMemory() const;

    // Same as GetInMemory() but performs a subsequent qicast<> for the given interface.
    // May additionally throw TypeMismatchException
    AnyInterface qiGetInMemory(const ReflectedInterface& ri) const;

    //////////////// Binding that tries m_ptr then the ROT then the LSS ///////////////////

    /*
    If necessary, will load the object from the LSS.  Returns null if and only if this pref 
    is null.
    Failure to find the object in the LSS raises exception DerefDanglingOidException
    May throw   ReflectedClassNotFoundException
                DerefDanglingOidException 
                various deserialisation exceptions
    Calling this function requires that the PSPace of the persistable pointed to by this pref
    has been affiliated with the calling thread.
    */
    ptr<IPersistable> Get() const;
    
    // Same as Get() but performs a subsequent qicast<> for the given interface.
    // May additionally throw TypeMismatchException
    AnyInterface qiGet(const ReflectedInterface& ri) const;

    // Same as Get() but additionally throws DerefNullPrefException if the pref is null.
    // Therefore GetNotNull() never returns null.
    ptr<IPersistable> GetNotNull() const;

    // Same as GetNotNull() but performs a subsequent qicast<> for the given interface.
    // May additionally throw TypeMismatchException
    AnyInterface qiGetNotNull(const ReflectedInterface& ri) const;

    // Same as Get() but returns null rather than throwing DerefDanglingOidException if the
    // oid isn't found in the LSS.
    ptr<IPersistable> TryGet() const;
    
    // Same as TryGet() but performs a subsequent qicast<> for the given interface.
    // May additionally throw TypeMismatchException
    AnyInterface qiTryGet(const ReflectedInterface& ri) const;

    //////////////// Async binding that tries m_ptr then the ROT then the LSS ///////////////////

    ptr<IPersistable> AsyncGet() const;
    
    // Same as AsyncGet() but performs a subsequent qicast<> for the given interface.
    // May additionally throw TypeMismatchException
    AnyInterface qiAsyncGet(const ReflectedInterface& ri) const;

    /////////////////////////////////////////////////////////////////////////////////////////////////
    // TODO: Only needed by PersistStore

    // Used when delete a PO and it reverts back to a transient state.  The OID of its pref members
    // needs to be cleared.  Hmmm but only if the child object has been faulted into memory?
    void ClearOidOnly() const { m_oid = null; }
    
    // Used to promote eviction
    void ClearPtrOnly() const { m_ptr = null; }

protected:
    void InitOid() const;

protected:
    mutable OID m_oid;
    mutable ptr<IPersistable> m_ptr;

    friend @api bool operator==(const prefbase& p1, const prefbase& p2);
    friend @api bool operator==(const prefbase& p1, ptr<const IObject> p2);
};

@api bool operator==(const prefbase& p1, const prefbase& p2);
inline bool operator!=(const prefbase& p1, const prefbase& p2) { return !(p1 == p2); }

@api bool operator==(const prefbase& p1, ptr<const IObject> p2);
inline bool operator!=(const prefbase& p1, ptr<const IObject> p2) { return !(p1 == p2); }

inline xostream& operator<<(xostream& os, const prefbase& x)
{
    x.WriteToStream(os);
    return os;
}

template<typename Archive>
inline void Serialise(Archive& ar, const prefbase& x)
{
    x.Serialise(ar,false);  // By default assume a strong reference
}

template<typename Archive>
inline void Deserialise(Archive& ar, prefbase& x)
{
    x.Deserialise(ar,false);   // By default assume a strong reference
}

@if (false)
{
    struct IPrefSerialiser
    {
        virtual void WritePref(Archive& ar, const prefbase& p, bool weakRef) = 0;
        virtual void ReadPref(Archive& ar, prefbase& p, bool weakRef) = 0;
    };

    // Instantiate on the frame to set the current pref serialiser (in thread local storage) used when 
    // writing/reading prefs to/from an archive.
    class @api SetThePrefSerialiser
    {
    public:
        SetThePrefSerialiser(IPrefSerialiser* next);
        ~SetThePrefSerialiser();

    private:
        IPrefSerialiser* m_prev;
    };
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// pref<T>

template<typename T>
class pref : public prefbase
{
public:
    typedef ptr<T> pointer_type;

    pref() {}
    
    // Default copy ctor and operator= used

    // Allow implicit conversion from ptr<T>
    pref(ptr<T> p) { Set(p); }
    
    // Allow implicit conversion from P* if a conversion to ptr<T> exists
    template <typename P> pref(P* p) { Set(p); }

    pref<T>& operator=(ptr<T> p) { Set(p); return *this; }
    pref<T>& operator=(NullInterface) { Clear(); return *this; }
    pref<T>& operator=(std::nullptr_t) { Clear(); return *this; }

    // Can be used to set this pref to null
    // If ptr is not null then the object must implement IPersistable
    void Set(ptr<T> p)
    {
        prefbase::Set2(p);
    }    

    ptr<T> GetBoundPtr() const 
    { 
        AnyInterface a = qiGetBoundPtr(GetReflectedInterface<T>());
        return reinterpret_cast<ptr<T>&>(a);
    }
    ptr<T> GetInMemory() const 
    { 
        AnyInterface a = qiGetInMemory(GetReflectedInterface<T>());
        return reinterpret_cast<ptr<T>&>(a);
    }
    ptr<T> Get() const
    { 
        AnyInterface a = qiGet(GetReflectedInterface<T>());
        return reinterpret_cast<ptr<T>&>(a);
    }
    ptr<T> GetNotNull() const
    { 
        AnyInterface a = qiGetNotNull(GetReflectedInterface<T>());
        return reinterpret_cast<ptr<T>&>(a);
    }
    ptr<T> TryGet() const
    { 
        AnyInterface a = qiTryGet(GetReflectedInterface<T>());
        return reinterpret_cast<ptr<T>&>(a);
    }
    ptr<T> AsyncGet() const
    { 
        AnyInterface a = qiAsyncGet(GetReflectedInterface<T>());
        return reinterpret_cast<ptr<T>&>(a);
    }
    
    // May throw   DerefNullPrefException
    //             ReflectedClassNotFoundException
    //             TypeMismatchException
    //             various deserialisation exceptions
    // Calling these functions requires that the PSPace of the persistable pointed to by this pref
    // has been affiliated with the calling thread.
    //
    // The implementation of these functions is rather subtle.  AlwaysBind() necessarily returns an 
    // independent ptr<IObject> by value rather than a reference to the m_ptr member of this pref (because 
    // the GC thread is able to zero the m_ptr to allow for eviction)
    // It follows that operator*() and operator->() cannot return a reference or pointer to a T.
    // Instead we either return a T by value or else a ptr<T> by value.
    T operator*() const { return *GetNotNull(); }
    ptr<T> operator->() const { return GetNotNull(); }
};

// For some reason this is needed even though we have already defined equality testing for prefbase
// Has something to do with use of operator bool()
template <typename T1, typename T2>
bool operator==(const pref<T1>& p1, const pref<T2>& p2) 
{ 
    return (const prefbase&) p1 == (const prefbase&) p2; 
}

template <typename T1, typename T2>
bool operator!=(const pref<T1>& p1, const pref<T2>& p2) { return !(p1 == p2); }

///////////////////////////////////////////////////////////////////////////////////////////////////
// cref<T>

template<typename T>
class cref : public prefbase
{
public:
    typedef T* pointer_type;

    cref() {}
    
    // Default copy ctor and operator= used

    // Allow implicit conversion from T* to cref<T>
    cref(T* p) { Set(p); }

    cref<T>& operator=(T* p) { Set(p); return *this; }
    cref<T>& operator=(NullInterface) { Clear(); return *this; }
    cref<T>& operator=(std::nullptr_t) { Clear(); return *this; }

    T* GetBoundPtr() const { return (T*) m_ptr.m_self; }
    T* GetInMemory() const { return (T*) prefbase::GetInMemory().m_self; }
    T* Get() const { return (T*) prefbase::Get().m_self; }
    T* GetNotNull() const { return (T*) prefbase::GetNotNull().m_self; }
    T* TryGet() const { return (T*) prefbase::TryGet().m_self; }
    T* AsyncGet() const { return (T*) prefbase::AsyncGet().m_self; }

    // Can be used to set this cref to null
    // If ptr is not null then the object must implement IPersistable
    void Set(T* p) { prefbase::Set(p); }
    
    // May throw   DerefNullPrefException
    //             ReflectedClassNotFoundException
    //             TypeMismatchException
    //             various deserialisation exceptions
    // Calling these functions requires that the PSPace of the persistable pointed to by this pref
    // has been affiliated with the calling thread.
    T& operator*() const { return *GetNotNull(); }
    T* operator->() const { return GetNotNull(); }
};

template <>
class cref<void> : public prefbase
{
public:
    cref() {}
    
    // Default copy ctor and operator= used

    template<typename T> cref(T* p) { Set(p); }

    template<typename T> cref<void>& operator=(T* p) { Set(p); return *this; }
    cref<void>& operator=(void* p) { cxAssert(!p); Clear(); return *this; }

    void* GetBoundPtr() const { return m_ptr.m_self; }
    void* GetInMemory() const { return prefbase::GetInMemory().m_self; }
    void* Get() const { return prefbase::Get().m_self; }
    void* GetNotNull() const { return prefbase::GetNotNull().m_self; }
    void* TryGet() const { return prefbase::TryGet().m_self; }
    void* AsyncGet() const { return prefbase::AsyncGet().m_self; }

    template<typename T> void Set(T* p) { prefbase::Set(p); }
};

// For some reason this is needed even though we have already defined equality testing for prefbase
// Has something to do with use of operator bool()
template <typename T1, typename T2>
bool operator==(const cref<T1>& p1, const cref<T2>& p2) 
{ 
    return (const prefbase&) p1 == (const prefbase&) p2; 
}

template <typename T1, typename T2>
bool operator!=(const cref<T1>& p1, const cref<T2>& p2) { return !(p1 == p2); }

extern template @api const TypeOps& MakeTypeOps<prefbase>();

///////////////////////////////////////////////////////////////////////////////////////////////////
// _GetReflected

template <typename T>
ReflectionByteCode _GetReflected(const pref<const T>*)
{
    @if (CEDA_ENABLE_STRING_TABLES)
    {
        static octet_t bc[] = { FT_PREF, FT_CONST, FT_INTERFACE, 0x00, 0x00 };
        return ReflectionByteCode(bc,&GetReflectedInterface<T>().name);
    }
    @else
    {
        static_assert(false);
    }
}

template <typename T>
ReflectionByteCode _GetReflected(const pref<T>*)
{
    @if (CEDA_ENABLE_STRING_TABLES)
    {
        static octet_t bc[] = { FT_PREF, FT_INTERFACE, 0x00, 0x00 };
        return ReflectionByteCode(bc,&GetReflectedInterface<T>().name);
    }
    @else
    {
        static_assert(false);
    }
}

template <typename T>
ReflectionByteCode _GetReflected(const cref<const T>*)
{
    @if (CEDA_ENABLE_STRING_TABLES)
    {
        static octet_t bc[] = { FT_CREF, FT_CONST, FT_CLASS, 0x00, 0x00 };
        return ReflectionByteCode(bc,&GetReflectedClass<T>().name);
    }
    @else
    {
        static_assert(false);
    }
}

template <typename T>
ReflectionByteCode _GetReflected(const cref<T>*)
{
    @if (CEDA_ENABLE_STRING_TABLES)
    {
        static octet_t bc[] = { FT_CREF, FT_CLASS, 0x00, 0x00 };
        return ReflectionByteCode(bc,&GetReflectedClass<T>().name);
    }
    @else
    {
        static_assert(false);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////

/*
Indirection semantics on pref/cref
----------------------------------

When pref/cref are used in Ceda Data Models we have potential problems with the following
functions:

    -   copy constructor
    
    -   copy assignment
    
    -   The 6 comparison operators  < > <= >= == !=
    
There is a tendency for these operations to treat the pref/cref as a pointer, not as the
value of the variable that has been referenced.

We currently have some adhoc, limited solutions:

    -   Functions like IsEqualNonNullPrefdValues(), IsEqualPrefdValues()
        IsLessNonNullPrefdValues(), IsLessPrefdValues(),
        IsEqualMVectors_cref(), IsEqualMVectors()
        
The generated operators on models with pref/cref members don't give value semantics.  E.g.

    -   client must use $new to create new values to be inserted into a pref member.
    
    -   client can move objects from one xvector<pref> to another xvector<pref>, and it
        is the pref values which must be transferred.
        
    -   client must use operator*() or operator->() on prefs, not '.' operator
    
We can't hide the fact that prefs represent pointers in Ceda Data Models.  It is assumed that
the use of pointers can be hidden by logical layers defined on top.
*/

///////////////////////////////////////////////////////////////////////////////////////////////////
// Compare the values pointed to by the given prefs

// Comparison: ==

// Assumes x,y are not null.  Returns true if *x == *y.  More precisely comparison is based on 
// checking that *x, *y have the same reflected class and the comparison is performed with a
// call to the member TypeOps::equalsFn.
@api bool IsEqualNonNullPrefdValues(prefbase x, prefbase y);

template<typename T>
bool IsEqualNonNullPrefdValues(cref<T> x, cref<T> y)
{
    cxAssert(x);
    cxAssert(y);
    return *x == *y;
}

// Returns true if either
//      x,y are null; or 
//      x,y are not null and *x == *y
@api bool IsEqualPrefdValues(prefbase x, prefbase y);

template<typename T>
bool IsEqualPrefdValues(cref<T> x, cref<T> y)
{
    if (x)
    {
        if (y)
        {
            return *x == *y;
        }
        else
        {
            return false;
        }
    }
    else
    {
        if (y)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

// Comparison: <

// Assumes x,y are not null and have the same concrete type.  Returns true if *x < *y.  
// The comparison is performed with a call to the member TypeOps::lessFn.
@api bool IsLessNonNullPrefdValues(prefbase x, prefbase y);

template<typename T>
bool IsLessNonNullPrefdValues(cref<T> x, cref<T> y)
{
    cxAssert(x);
    cxAssert(y);
    return *x < *y;
}

// Returns true if either
//      x == null and y != null; or 
//      x,y are not null and *x < *y
@api bool IsLessPrefdValues(prefbase x, prefbase y);

template<typename T>
bool IsLessPrefdValues(cref<T> x, cref<T> y)
{
    if (x)
    {
        if (y)
        {
            return *x < *y;
        }
        else
        {
            return false;
        }
    }
    else
    {
        if (y)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Comparisons of mvectors

/*
Comparing two mvectors of tuple types is straightfoward, and can be written in terms of
the comparison operator on the elements.

Comparing mvectors of abstract types is slightly more complex, because it is necessary
to perform tun time type checking on the elements, and if they are the same type to
polymorphically invoke an appropriate comparison function.
*/

// Assuming T1,T2 are cref<T>, this tests whether they are equal
template <typename T1, typename T2>
bool IsEqualMVectors_cref(const xvector<T1>& x, const xvector<T2>& y)
{
    if (x.size() == y.size())
    {
        for (ssize_t i=0 ; i < x.size() ; ++i)
        {
            if (*x[i] != *y[i]) return false;
        }
        return true;
    }
    else
    {
        return false;
    }
}

/*
Can be used to compare two mvectors used in a CDM for value-equivalence.   The 
mvectors may be using prefs or crefs to the elements.  This function tests whether the 
two mvectors have the same number of elements and all elements are value-equivalent.
In order for two elements to be regarded as value-equivalent, they must have the exact same
type (i.e. ReflectedClass).
*/

@api bool IsEqualMVectors(const xvector<prefbase>& x, const xvector<prefbase>& y);

//////////////////////////////////////////////////////////////////////////////////////////////////
// cval<T>

template<typename T>
class cval : public cref<T>
{
public:
    cval() {}
    cval(T* p) { Set(p); }

    bool operator==(const cval<T>& rhs) const
    {
        return IsEqualPrefdValues(*this, rhs);
    }
    bool operator<(const cval<T>& rhs) const
    {
        return IsLessPrefdValues(*this, rhs);
    }
};

template<typename T>
bool operator!=(const cval<T>& x1, const cval<T>& x2) { return !(x1 == x2); }

template<typename T>
bool operator>(const cval<T>& x1, const cval<T>& x2) { return x2 < x1; }

template<typename T>
bool operator<=(const cval<T>& x1, const cval<T>& x2) { return !(x2 < x1); }

template<typename T>
bool operator>=(const cval<T>& x1, const cval<T>& x2) { return !(x1 < x2); }

//////////////////////////////////////////////////////////////////////////////////////////////////
// pval<T>

template<typename T>
class pval : public pref<T>
{
public:
    pval() {}
    pval(ptr<T> p) { Set(p); }

    bool operator==(const pval<T>& rhs) const
    {
        return IsEqualPrefdValues(*this, rhs);
    }
    bool operator<(const pval<T>& rhs) const
    {
        return IsLessPrefdValues(*this, rhs);
    }
};

template<typename T>
bool operator!=(const pval<T>& x1, const pval<T>& x2) { return !(x1 == x2); }

template<typename T>
bool operator>(const pval<T>& x1, const pval<T>& x2) { return x2 < x1; }

template<typename T>
bool operator<=(const pval<T>& x1, const pval<T>& x2) { return !(x2 < x1); }

template<typename T>
bool operator>=(const pval<T>& x1, const pval<T>& x2) { return !(x1 < x2); }

///////////////////////////////////////////////////////////////////////////////////////////////////
// OT_equiv

// Define an equivalence relation corresponding to OT.  This allows models to containing prefs
// to redefine operator==().
// Ideally xcpp will do this automatically - perhaps by using pval/cval instead of pref/cref,
// and using a different xmap datatype that acocunts for equivalence under OT.
// Another problem is that $variants containing prefs don't do the right thing.

template <typename T>
bool OT_equiv(const T& x, const T& y)
{
    return x == y;
}

template <typename T>
bool OT_equiv(const cref<T>& x, const cref<T>& y)
{
    if (x)
    {
        if (y)
        {
            return OT_equiv(*x,*y);
        }
        else
        {
            return false;
        }
    }
    else
    {
        if (y)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

template <typename T>
bool OT_equiv(const pref<T>& x, const pref<T>& y)
{
    return IsEqualPrefdValues(x,y);     // wrong!  ends up calling equalsFn on the TypeOps!
}

template <typename It1, typename It2>
bool OT_equiv(It1 x1, It1 x2, It2 y1)
{
    while (x1 != x2)
    {
        if (!OT_equiv(*x1, *y1)) return false;
        ++x1; ++y1;
    }
    return true;
}

template <typename T>
bool OT_equiv(const xvector<T>& x, const xvector<T>& y)
{
    return x.size() == y.size() && OT_equiv(x.begin(), x.end(), y.begin());
}

template <typename T>
bool OT_equiv(const xset<T>& x, const xset<T>& y)
{
    return x.size() == y.size() && OT_equiv(x.begin(), x.end(), y.begin());
}

template <typename T1, typename T2>
bool OT_equiv(const std::pair<T1,T2>& x, const std::pair<T1,T2>& y)
{
    return OT_equiv(x.first, y.first) && OT_equiv(x.second, y.second);
}

template <typename T, size_t N>
bool OT_equiv(const std::array<T,N>& x, const std::array<T,N>& y)
{
    for (size_t i=0 ; i < N ; ++i)
    {
        if (!OT_equiv(x[i], y[i])) return false;
    }
    return true;
}

/*
template <typename K, typename V>
bool OT_equiv(const xmap<K,V>& x, const xmap<K,V>& y)
{
    return x.size() == y.size() && OT_equiv(x.begin(), x.end(), y.begin());
}
*/

// A version of map equivalence that accounts for OT semantics
template <typename K, typename V>
bool OT_equiv(const xmap<K,V>& x, const xmap<K,V>& y)
{
    typename xmap<K,V>::const_iterator i = x.begin();
    typename xmap<K,V>::const_iterator j = y.begin();
    while(1)
    {
        // Skip past i where the payload is empty
        while(i != x.end() && i->second == V()) ++i;

        // Skip past j where the payload is empty
        while(j != y.end() && j->second == V()) ++j;
        
        if (i == x.end())
        {
            if (j == y.end())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            if (j == y.end())
            {
                return false;
            }
            else
            {
                // This actually calls OT_equiv for an std::pair
                if (!OT_equiv(*i,*j)) return false;
            }
        }
        ++i; ++j;
    }
    return true;
}

} // namespace ceda