/*
 * @(#)mvalue.h    generated by: makeheader 4.21  Mon Dec 20 16:38:05 2004
 *
 *		built from:	../../src/include/copyright.h
 *				../../src/include/pragma_interface.h
 *				implementation/classdata.cpp
 *				implementation/classdatamanager.cpp
 *				implementation/implementation.cpp
 *				mcomplex/mcomplex.cpp
 *				mvlibm/libm_complex.cpp
 *				mvlibm/libm_implementation.cpp
 *				mvlibm/libm_proxy.cpp
 *				protected/protected.cpp
 *				proxy/abi.cpp
 *				proxy/mxarray_compat.cpp
 *				proxy/proxy.cpp
 *				refcount/refcount.cpp
 */

#ifndef mvalue_h
#define mvalue_h


/*
 * Copyright 1984-2003 The MathWorks, Inc.
 * All Rights Reserved.
 */



/* Copyright 2003 The MathWorks, Inc. */

/*
 * Prevent g++ from making copies of vtable and typeinfo data
 * in every compilation unit.  By allowing for only one, we can
 * save space and prevent some situations where the linker fails
 * to coalesce them properly into a single entry.
 *
 * References:
 *    http://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html#Vague%20Linkage
 *    http://gcc.gnu.org/onlinedocs/gcc/C---Interface.html
 */

#ifdef __cplusplus
#  ifdef __linux__
#    pragma interface
#  endif
#endif



#ifndef ARRAY_ACCESS_INLINING
#define ARRAY_ACCESS_INLINING 1
#endif
#ifndef UTIL_VERSION
#define UTIL_VERSION 2
#endif

#include "util.h"
#include "matrix.h"

//
// ******************************************************************************
//
// Mprotected_cptr is used to protect C objects on the C++ stack.  This
// can be instantiated for any C pointer that can be freed by a single function call.
// It is instantiated to protect mxArray pointers with mxDestroyArray().
//
// ******************************************************************************
//

template <class T, T *(*copy_fn)(T *other),void (*delete_fn)(T *p)> class Mprotected_cptr
{
protected:
    T *p;
    bool own;
public:
    Mprotected_cptr() { p = 0; own = false; }
    Mprotected_cptr( T *ip, bool iown = true ): p(ip),own(iown) { 
    }
    Mprotected_cptr( const Mprotected_cptr<T,copy_fn,delete_fn> &other ) {
        own = other.own;
        if (own)
            p = copy_fn( other.p );
        else
            p = other.p;
    }
    void operator =(const Mprotected_cptr<T,copy_fn,delete_fn> &other ) {
        if (other.p != p) {
            this->~Mprotected_cptr();
        }
        own = other.own;
        if (own)
            p = copy_fn( other.p );
        else
            p = other.p;
    }
    void operator =( T *ip  ) { 
        if (ip != p) {
            this->~Mprotected_cptr(); 
            own = true; 
            p = ip; 
        }
    }
    ~Mprotected_cptr() { if (own) delete_fn( p ); }
    T *Unprotect() { T *retval = p; own = false; p = 0; return retval; }
    operator T*() { return p; }
};

 
extern mxArray *mvCopymxArray( mxArray *p );


/* This function is a C++ function wrapped around mxDestroyArray to prevent
 * compiler warnings
 */
extern void mvDeletemxArray( mxArray *p );


class Mprotected_mxArray : public Mprotected_cptr<mxArray, mvCopymxArray, mvDeletemxArray> { 
public:
    mxArray *Unprotect() { 
        if (own && p && mxGetArrayScope(p) == mxLOCAL_SCOPE) {
            int t = mxGetReferenceCount(p);
            mxSetReferenceCount(p,0);
            mxSetArrayScope2Temp(p);
            mxSetReferenceCount(p,t);
        }
        return Mprotected_cptr<mxArray, mvCopymxArray, mvDeletemxArray>::Unprotect();
    }
    mxArray *Unprotect_copy() { if (!own) p = mxCreateSharedCopy(p); return Unprotect(); }
    Mprotected_mxArray() {  }
    void Unshare() {
        utAssert( own );  // You must own an array to unshare it because it
                          // will decrement the reference count upon unshare as if you did
        p = mxUnshare(p);
    }
    Mprotected_mxArray( mxArray *ip, bool iown = true ): Mprotected_cptr<mxArray, mvCopymxArray, mvDeletemxArray>(ip, iown) { }
    mxArray * operator->() { return p; }
};



#include "util.h"

#ifdef __cplusplus

//
// ******************************************************************************
//
// Use std::complex<double> for Mcomplex
//
// ******************************************************************************
//

#if 0
//
// This forces the class sorter to put the typedef for Mcomplex ahead
// of the references to it.
class Mcomplex { };
#endif

#ifdef _MSC_VER
#pragma warning( disable : 4275 ) /* dllexport class used with non dllexport members */
#endif

#include <complex>

typedef std::complex<double> Mcomplex;

#endif



#ifdef __cplusplus
#include <new>

//
// ******************************************************************************
//
// Reference counting classes.  These classes are used to implement reference
// counting in a thread safe manner
//
// ******************************************************************************
//
class EXPORT_CLASS Mrefcount_int  {
    unsigned int refcount;
    bool array;
public:    
    Mrefcount_int(bool iarray = false) : refcount(1),array(iarray) { }
    ~Mrefcount_int() { if (refcount !=1) throw "bad reference count"; }
    void copy() { refcount++; }
    bool destroy() { return (--refcount == 0); }
    bool isarray() { return array; }
    void dump() const { printf ("Refcount == %d (arr=%s)\n", refcount, array ? "True" : "False" ); }
    unsigned int count() { return refcount; }
};

class EXPORT_CLASS Mrefcount_threadsafe {
    ut_atomic_int refcount;
    bool array;
public:    
    Mrefcount_threadsafe(bool iarray = false) : array(iarray) { ut_atomic_set_one( &refcount ); }
    ~Mrefcount_threadsafe() { if (ut_atomic_value(&refcount) != 1) throw "bad reference count"; }
    void copy() { ut_atomic_add( 1, &refcount); }
    bool destroy() { return ( ut_atomic_subtract_and_test( 1, &refcount) ); }
    bool isarray() { return array; }
    void dump() const { printf ("Refcount == %d (arr=%s)\n", ut_atomic_value(&refcount), array ? "True" : "False" ); }
    unsigned int count() { return ut_atomic_value(&refcount); }
};

class EXPORT_CLASS Mrefcount_debugging {
    unsigned int begin_band;
    unsigned int refcount;
    bool array;
    unsigned int end_band;
    void checkband() const {
        utAssert( begin_band == 0xFEEDFACE && end_band == 0xFACEFEED );        
    }
public:    
    Mrefcount_debugging(bool iarray = false) : refcount(1),array(iarray) {
        begin_band = 0xFEEDFACE;
        end_band = 0xFACEFEED;
    }
    
    ~Mrefcount_debugging() { 
        checkband();
        if (refcount !=1) throw "bad reference count"; 
    }
    void copy() { checkband(); refcount++; }
    bool destroy() { checkband(); return (--refcount == 0); }
    bool isarray() { checkband(); return array; }
    void dump() const { checkband(); printf ("Refcount == %d (arr=%s)\n", refcount, array ? "True" : "False" ); }
    unsigned int count() const { checkband(); return refcount; }
};    

//
// ******************************************************************************
//
// The Mallocator hides the details of reference counting inside the placement new
// syntax.
//
// ******************************************************************************
//
#ifdef SIMPLE_INT_REFCOUNT
typedef Mrefcount_int Mrefcount;
#else
#ifdef DEBUG_REFCOUNT
typedef Mrefcount_debugging Mrefcount;
#else
typedef Mrefcount_threadsafe Mrefcount;
#endif
#endif


class EXPORT_CLASS Mallocator
{
public:
    Mallocator() {}
    ~Mallocator() {}
    void* alloc(size_t s, bool iarray = false) const {
        utAssert( (sizeof(Mrefcount) & 0x7) == 0 );
        void *p = ::utMalloc( s + sizeof(Mrefcount));
        Mrefcount *pt = new (p) Mrefcount(iarray);
        return (void *) (pt+1);
    }
    void free(void* where) const {
        Mrefcount *pt = ((Mrefcount *) where) - 1;
        ::utFree((void *)pt);
    }
    void dump(void* where) const {
        Mrefcount *pt = ((Mrefcount *) where) -1;
        pt->dump();
    }
    void copy(void* where) const {
        Mrefcount *pt = ((Mrefcount *) where) -1;
        pt->copy();
    }
    bool destroy(bool *array, void* where) const {
        Mrefcount *pt = ((Mrefcount *) where) - 1;
        *array = pt->isarray();
        return pt->destroy();
    }
    bool islonely(void *where) const {
        Mrefcount *pt = ((Mrefcount *) where) - 1;
        utAssert( pt->count() != 0 );
        return pt->count() == 1;
    }
};


//
// ******************************************************************************
//
// Global placement new and delete operators which use the Mallocator
// to allocate and free the storage.
//
// ******************************************************************************
//
inline void* operator new(size_t s, const Mallocator & a)
{
    return a.alloc(s);
}

// placement delete
inline void operator delete(void* p, const Mallocator& a)
{
    a.free(p);
}


#ifdef _MSC_VER
//
// ******************************************************************************
//
// The mathworks namespace introduced below prevents a problem using MSVC 6.0
// with this global new and delete array operator because it causes a spurious
// compilation diagnostic.
//
// ******************************************************************************
//
namespace mathworks {
#endif

inline void* operator new [](size_t s, const Mallocator& a)
{
    return a.alloc(s, true);
}
// placement delete
inline void operator delete [](void* p, const Mallocator& a)
{
    a.free(p);
}

#ifdef _MSC_VER
}
using namespace mathworks;
#endif

template <class T> inline void destroy( T *p, const Mallocator &a )
{
    bool array;
    if (a.destroy(&array, (void *)p)) {
        if (array)
            operator delete [] ( p, a );
        else
            operator delete( p, a );
    }
}
template  <class T> inline void mvDump( T *p, const Mallocator &a )
{
    a.dump((void *)p);
}
template  <class T> inline void mvCopy( T *p, const Mallocator &a )
{
    a.copy((void *) p);
}
template <class T> inline bool mvIslonely( T *p, const Mallocator &a)
{
    return a.islonely((void *) p );
}

#endif


#ifdef __cplusplus
#include <iostream>

enum Mvalue_partition {
    MVP_UNINITIALIZED,
    MVP_DOUBLE_SCALAR,
    MVP_COMPLEX_SCALAR,
    MVP_LOGICAL_SCALAR,
    MVP_MXARRAY,
    MVP_USER_DEFINED,
    MVP_OTHER = MVP_UNINITIALIZED   // Temporary bridge to be removed whenever everyone
                                    // gets promoted MVP_OTHER will then be unique from MVP_UNINITIALIZED
};

inline const char *mvCopyString( const char *s ) {    
    return s ? utStrdup( s ) : NULL;
}
inline void mvFreeString( const char *s ) {
    utFree((void *)s);
}

typedef Mprotected_cptr<const char , mvCopyString, mvFreeString> mvString;

//
// ******************************************************************************
//
// Mdirectdata defines the amount of storage other than the discriminant and flags
// that can be stored in direct data within the object.
// This space can be used in any-way for user-defined extentions to Mvalue.
//
// ******************************************************************************
//

struct Mdirectdata {
    void *data[3];
};
template <class T> inline const T *extract_data_pointer( const Mdirectdata &d )
{
    return (const T *) d.data;
}
template <class T> inline T *extract_data_pointer( Mdirectdata &d )
{
    return (T *) d.data;
}
template <class T> inline const Mdirectdata& pack_data_pointer( const T *p )
{
    return *((Mdirectdata *) p );
}

//
// ******************************************************************************
//
// Mclassdata is the virtual base class for user-defined extensions to the Mvalue
// system.  Any consumer who implements this class can allocate a new discriminant
// at run-time.
// This needs to be reviewed, and added to the official client-side interface for
// mvalue.  I would also like to investigate implementing all types in this fashion
// instead of fast/slow types.
//
// ******************************************************************************
//

class EXPORT_CLASS Mclassdata {
protected:
    bool direct;                                                       // Direct or indirect
    unsigned short disc;                                               // Discriminant used
    unsigned short default_flags;                                      // Default value for the flags    
    const char * discriminant_string;                                  // Discriminant string for the class    

    bool is_direct( void) const {
        return direct;
    }
    void DebugDump( std::ostream & str ) const;
    virtual double toDouble(const Mdirectdata &d) const = 0;                         // Conversion to double
    virtual Mcomplex toMcomplex(const Mdirectdata &d) const = 0;                     // Conversion to Mcomplex
    virtual bool toBool( const Mdirectdata &d ) const = 0;                           // Conversion to bool
    virtual Mprotected_mxArray toMprotected_mxArray(const Mdirectdata &d) const = 0; // Conversion to protected mxarray 
    virtual Mvalue_partition Partition(const Mdirectdata &d) const = 0;              // Partition function
    virtual mvString tomvString(const Mdirectdata &) const {        
        return mvString( NULL );
    }
    virtual int get_type(const Mdirectdata &) const {
        return mxUNKNOWN_CLASS;
    }
    virtual int get_attributes(const Mdirectdata &) const {
        return MX_UNKNOWN_ATTR;
    }
    
    virtual void DebugDump( const Mdirectdata &d, std::ostream &ostr ) const  = 0;
    virtual void copy( Mdirectdata &out, const Mdirectdata &in, const Mallocator &allocator ) const = 0;
    virtual bool is_lonely( const Mdirectdata &d, const Mallocator & allocator ) const = 0;        

    //
    // These are not used for direct classes, but are present in the base class for uniformity of type
    //
    virtual void destroy( Mdirectdata &d, const Mallocator &allocator) const = 0;     // Destroy function
    virtual void clone( Mdirectdata &out, const Mallocator &allocator ) const =0 ;          // Clone function    

    friend class Mimplementation;
    Mclassdata() {        
    }
    Mclassdata( bool idirect, unsigned short idisc, unsigned short idefault_flags, const char *idiscriminant_string ) :
        direct(idirect),
        disc(idisc),
        default_flags(idefault_flags),
        discriminant_string( idiscriminant_string ) {        
    }
    virtual ~Mclassdata() { }
};
#endif


//
// ******************************************************************************
//
// Mclassdatamanager manages user-defined discriminants and the map from discriminant
// to the classdata that implements that discriminant.
// For "Fast Direct" and "Fast Indirect" discriminants, the templates below implement
// everything that is not in switch statements within the implementation file.
//
// ******************************************************************************
//

class EXPORT_CLASS Mclassdatamanager {
    static void *operator new(size_t sz) { return utMalloc( sz ); }    
    static void operator delete(void *ptr) { utFree(ptr); }  
    static void *operator new[](size_t sz) { return utMalloc( sz ); }    
    static void operator delete[](void *ptr) { utFree(ptr); }  

    unsigned int next_disc;
    unsigned int max_alloc;
    const Mclassdata **info;
    void grow() {
        unsigned int i;
        max_alloc = max_alloc << 1;
        const Mclassdata **new_info = new const Mclassdata * [max_alloc];
        for (i=0; i<next_disc; i++) {
            new_info[i] = info[i];
        }
        delete [] info;
        info = new_info;
    }
    void set_class_data( unsigned int disc, const Mclassdata *classdata ) {
        utAssert( disc < next_disc );
        info[disc] = classdata;
    }
    const Mclassdata *get_class_data( unsigned int disc ) const {
        utAssert( disc < next_disc );
        return info[disc];
    }
    unsigned short add_new_class( const Mclassdata *classdata )
    {
        utAssert( next_disc == (unsigned short) next_disc );
        if (next_disc == max_alloc) {
            grow();
        }
        info[next_disc] = classdata;
        return next_disc++;
    }
    friend class Mimplementation;        
public:
    Mclassdatamanager( ) { }
    ~Mclassdatamanager() { }    
    void construct();
    void destruct();
};




#ifdef __cplusplus
#include <iostream>
#include "util.h"

#ifndef TEST_PUBLIC
#if defined(_MSC_VER)
#define TEST_PUBLIC public
#else
#define TEST_PUBLIC private
#endif
#endif

//
// ******************************************************************************
//
// The Mimplementation class uses a set "fast" pre-defined discriminants.  
// for direct and indirect data.  These are implemented by switch statements
// in this file.  Implementors of subtypes are allowed to subclass the Mclassdata
// class in order to implement user-defined types. 
// The next two macros pre-define the fast direct and indirect types.
// Users can then allocate new discriminants at run-time by call the 
// add_new_class function below.
//
// ******************************************************************************
// 
    
#define mvalue_fast_direct_types(X) \
X(double, d, MVP_DOUBLE_SCALAR ) \
X(bool, b, MVP_LOGICAL_SCALAR ) 

#define mvalue_fast_indirect_types(X) \
X(Mcomplex, c, MVP_COMPLEX_SCALAR ) \
X(mxArray, m, MVP_MXARRAY ) 


#define direct_enum_element(type, ignored, ignored2) MV_##type,
#define indirect_enum_element(type, ignored, ignored2) MV_##type, 

#define indirect_union_element(type, name, ignored) struct { unsigned int disc_flags; type *name; } i_##type;
#define direct_union_element(type, name, ignored) struct { unsigned int disc_flags; type name; } d_##type;

//
// ******************************************************************************
//
// The macros below define constructors for the fast direct types.
//
// ******************************************************************************
//

#define declare_init(type, name, part)                                          \
  inline void init(type name) {                                                 \
    v.disc.disc = MV_##type;                                                    \
    v.disc.flags = 0;                                                           \
    v.d_##type.name = name;                                                     \
  }                                                                             \
  inline void reinit(type name) {                                               \
    destroy();                                                                  \
    init(name );                                                                \
  }                                                                             \
  inline Mimplementation( type name ) {                                         \
      init(name);                                                               \
  }                                                                     

#define direct_case( type, name, ignored ) case MV_##type:
#define indirect_case( type, name, ignored ) case MV_##type: 

#define copy_fast_direct_data( type, name, ignored ) case MV_##type: v.d_##type.name = p_old.v.d_##type.name; break;

struct Mdisc {    
    unsigned short disc;
    unsigned short flags;
};


template <class T> class Mvalue_common;

// See page 1-5.
//
// Constants used to construct flags words.
// These cannot be declared in the class body because MSVC 6.0 does not support it.
//
const unsigned short MVF_MANAGED =0x1;
const unsigned short MVF_REFCOUNTED =0x2;


//
// ******************************************************************************
//
// The Mimplementation class defines the current implementation of Mvalue.
// It uses the allocator to perform reference counting on the managed objects.
// Each object can have the following flags:
//
//     MVF_MANAGED - The storage to indirect objects is being managed by the allocator here
//     MVF_REFCOUNTED - The indirect storage is using standard referenc counting
//                      using the allocator.  This is only used for mxArray.
//
// By default, indirect objects have only 1 indirected pointer.
//
// ******************************************************************************
//

class EXPORT_CLASS Mimplementation {
public:
    typedef enum {
        MV_uninitialized,
        mvalue_fast_direct_types(direct_enum_element)
        mvalue_fast_indirect_types(indirect_enum_element)  // The first one must be odd see is_unmanaged_indirect()
        MV_first_user_defined
    } mv_discriminant;
private:
    static Mallocator refalloc;
    static Mclassdatamanager cdmgr;
    friend class Mclassdata;    

    union {
        Mdisc disc;
        unsigned int disc_flags;
        mvalue_fast_indirect_types(indirect_union_element)  
        struct {
            unsigned int disc_flags;
            Mdirectdata d;
        } slow;
        mvalue_fast_direct_types(direct_union_element)
    } v;


    void destroy_indirect_data();
    inline void copy_indirect_data();
    
    void unshare_indirect();
    bool is_unmanaged_indirect() const {
        return ((v.disc.flags & MVF_MANAGED) == 0);
    }
    bool is_managed_indirect() const {
        return ((v.disc.flags & MVF_MANAGED) != 0);
    }
    bool is_refcounted_indirect() const {
        return ((v.disc.flags & MVF_REFCOUNTED) != 0);
    }
    void make_unmanaged_indirect() { v.disc.flags &= ~MVF_MANAGED; }
    void make_managed_indirect() { v.disc.flags |= MVF_MANAGED; }
    inline const Mclassdata *get_class_data() const {
        return cdmgr.get_class_data(v.disc.disc);
    }
    bool is_indirect() const { return !get_class_data()->is_direct(); };
    bool is_direct() const { return get_class_data()->is_direct(); };
    bool islonely() const {
        utAssert( v.disc.disc == MV_mxArray );
        return (mxGetRefCount == 0);
    }
    int get_type() const {
        return get_class_data()->get_type(v.slow.d);
    }
    int get_attributes() const {
        return get_class_data()->get_attributes(v.slow.d);
    }
    bool is_lonely() { 
        utAssert( is_indirect() );
        return is_managed_indirect() && 
            (is_refcounted_indirect() ? ::mvIslonely( v.slow.d.data[0], refalloc ) : 
             islonely() ); 
    }
TEST_PUBLIC:
//
// ******************************************************************************
//  
// Constructors, destructors, init methods
//
// ******************************************************************************
//

    static void *operator new(size_t sz) { return utMalloc( sz ); }    
    static void operator delete(void *ptr) { utFree(ptr); }  
    inline void maybe_destroy_indirect() {
        if (is_managed_indirect()) destroy_indirect_data();
    }

    inline void init() { v.disc.disc = MV_uninitialized; v.disc.flags = 0; }  
    inline void destroy() { maybe_destroy_indirect(); init(); }

    ~Mimplementation() {
        maybe_destroy_indirect();
    }    

    inline Mimplementation() { init(); }

    inline void init( mv_discriminant idisc, void *data,
                      unsigned short flags = MVF_MANAGED | MVF_REFCOUNTED ) {
        v.disc.disc = idisc;
        v.disc.flags = flags;
        v.slow.d.data[0] = data;
    }
    
    inline void reinit( mv_discriminant idisc, void *data,
                        unsigned short flags = MVF_MANAGED | MVF_REFCOUNTED ) {
        destroy();
        init( idisc, data, flags );
    }

    inline Mimplementation( mv_discriminant idisc, void *data ) {
        init( idisc, data );
    }

    inline void init(mv_discriminant idisc, const Mcomplex *c ) {
        init( idisc, (void *) c );
    }
        
    inline void reinit(mv_discriminant idisc, const Mcomplex *c ) {
        if (v.disc.disc == MV_Mcomplex && is_lonely() && !utEQZero(c->imag())) {
            *v.i_Mcomplex.c = *c;
        }
        else {
            destroy();
            init( idisc, c );
        }
    }  
    Mimplementation( mv_discriminant idisc, const Mcomplex *c ) {
        init(idisc, c );
    }
    mvalue_fast_direct_types(declare_init);

    inline void init( const Mcomplex & c) {
        if (utEQZero(c.imag())) {
            init( c.real() );
        }
        else {
            init( MV_Mcomplex, (void *) (new (refalloc) Mcomplex(c)) );
        }
    } 
    inline void reinit( const Mcomplex & c) {
        destroy();
        init( c );
    }

    inline void init( const Mimplementation &p_old ) {    
        v.disc = p_old.v.disc;
        switch (v.disc.disc) {
          default:
            get_class_data( )->copy( v.slow.d, p_old.v.slow.d, refalloc );
            break;
            mvalue_fast_indirect_types( indirect_case )            
                v.slow.d.data[0] = p_old.v.slow.d.data[0];
            if (is_managed_indirect()) {
                if (is_refcounted_indirect()) {
                    mvCopy( v.slow.d.data[0], refalloc );
                }
                else {
                    utAssert( v.disc.disc == MV_mxArray );
                    mxIncRefCount( v.i_mxArray.m );
                }
            }
            break;
            mvalue_fast_direct_types( copy_fast_direct_data );          
        }
    }
    inline void reinit( const Mimplementation &p_old ) {
        destroy();
        init( p_old );
    }

    inline Mimplementation( const Mimplementation &p_old ) {
        init( p_old );
    }

    void init( double re, double im ) {
        if (utEQZero(im)) {
            init( re );
        }
        else {
            init(MV_Mcomplex, new (refalloc) Mcomplex(re, im));
        }
    }
    void reinit( double re, double im ) {
        if (v.disc.disc == MV_Mcomplex && is_lonely() && !utEQZero(im)) {
            *(v.i_Mcomplex.c) = Mcomplex( re, im );
        }
        else {
            destroy();
            init( re, im );
        }
    }
    Mimplementation( double re, double im ) {
        init( re, im );
    }
    void init( mxArray *pa, bool own ) {
        if (own && (mxGetArrayScope(pa) == mxTEMPORARY_SCOPE)) {
            int t = mxGetReferenceCount(pa);
            mxSetReferenceCount(pa,0);
            mxSetArrayScope2Local(pa);
            mxSetReferenceCount(pa,t);
        }
        init( MV_mxArray, (void *) pa,
              own ? MVF_MANAGED : 0 );
    }
    void init( mxArray *pa ) {
        init( pa, mxIsTemp(pa) );  //  Mvalue owns only temporary arrays
    }
    void reinit( mxArray *pa ) {
        destroy();
        init(pa);
    }

    inline void operator =(Mimplementation &p_old) {
        this->~Mimplementation();
        init( p_old );
    }

//
// ******************************************************************************
//  
// User-defined type support
//
// ******************************************************************************
//
    inline void init( const Mdirectdata &d, const Mclassdata &cd, unsigned short flags ) {
        v.disc.disc = cd.disc;
        v.disc.flags = (flags == (unsigned short)-1) ? cd.default_flags : flags;
        v.slow.d = d;
    }
    inline void reinit( const Mdirectdata &d, const Mclassdata &cd, unsigned short flags ) {
        destroy();
        init( d, cd, flags );
    }


    static unsigned short add_new_class( Mclassdata *classdata )
    {
        unsigned short disc = cdmgr.add_new_class( classdata );
        return classdata->disc = disc;
    }

//
// ******************************************************************************
//  
// Type conversion operators
//
// ******************************************************************************
//
    inline bool toBool() const {      
        switch (v.disc.disc) {
          case MV_mxArray:
            utAssert(mxIsLogical(v.i_mxArray.m) && mxGetNumberOfElements(v.i_mxArray.m) == 1);
            return *mxGetLogicals( v.i_mxArray.m );
          case MV_bool:
            return v.d_bool.b;
          case MV_double:
            utAssert( mxGetNumberOfElements( v.i_mxArray.m ) == 1 && !mxIsComplex(v.i_mxArray.m));
            {
                double d = *mxGetPr( v.i_mxArray.m );
                if (utNEZero(d) && d != 1.0) {
                    /* Report a warning? */
                }
                return utNEZero(d);
            }          
          default:
            return get_class_data()->toBool( v.slow.d );
        }
    }
    inline double toDouble() const {
        switch (v.disc.disc) {
          case MV_mxArray:
            return mxGetScalar(v.i_mxArray.m);
          case MV_double:
            return v.d_double.d;
          case MV_bool:
            return v.d_bool.b;
          default:
            return get_class_data()->toDouble( v.slow.d );
        }
    }
    inline Mdirectdata toMdirectdata() const {
        utAssert( is_direct() );
        return v.slow.d;
    }
    inline Mcomplex toMcomplex() const {
        double re;
        switch (v.disc.disc) {
          case MV_mxArray: 
            re = mxGetScalar(v.i_mxArray.m);
            if (mxIsComplex(v.i_mxArray.m)) {
                return Mcomplex( re, *mxGetPi(v.i_mxArray.m));
            }
            else {
                return Mcomplex(re,0.0);
            }
            break;
          case MV_bool:
            return Mcomplex( (double) v.d_bool.b, 0.0 );
          case MV_double:
            return Mcomplex( v.d_double.d, 0.0 );
          case MV_Mcomplex:
            return *v.i_Mcomplex.c;
          default:
            return get_class_data()->toMcomplex( v.slow.d );
        }
    }
    inline mvString tomvString() const {
        switch (v.disc.disc) {
            case MV_mxArray: {
                mxArray *pmx = v.i_mxArray.m;
                if (mxIsChar(pmx)) {
                    return mvString( mxArrayToString( pmx ));
                }
                // Intentional fall through
            }
          default:
            return get_class_data()->tomvString( v.slow.d );
        }
    }
    inline Mprotected_mxArray toMprotected_mxArray() const {
        mxArray *retval;
        bool bown = true;

        switch (v.disc.disc) {
          case MV_bool:
            retval = mxCreateLogicalScalar(v.d_bool.b);
            break;
          case MV_double:
            retval = mxCreateDoubleScalar( v.d_double.d );
            break;
          case MV_Mcomplex:
            retval = mxCreateDoubleMatrix(1, 1, mxCOMPLEX );
            *mxGetPr(retval) = v.i_Mcomplex.c->real();
            *mxGetPi(retval) = v.i_Mcomplex.c->imag();
            break;        
          case MV_mxArray:
            retval = v.i_mxArray.m;
            bown = is_managed_indirect();
            if (bown) {
                mxIncRefCount( retval );
            }
            break;
          default:
            return get_class_data()->toMprotected_mxArray( v.slow.d );
        }
        return Mprotected_mxArray( retval, bown );
    } 

//
// ******************************************************************************
//  
// Partitioning, query API
//
// ******************************************************************************
//

    inline bool is_user_defined( const Mclassdata &classdata ) const {
        return v.disc.disc == classdata.disc;
    }
    inline Mvalue_partition Partition() const 
        {
            switch (v.disc.disc) {
              case MV_double:
                return MVP_DOUBLE_SCALAR;
              case MV_Mcomplex:
                return MVP_COMPLEX_SCALAR;
              case MV_bool:
                return MVP_LOGICAL_SCALAR;
              case MV_mxArray:
                if (mxIsScalarDoubleFlagSet(v.i_mxArray.m)) {
                    if (mxIsComplex(v.i_mxArray.m))
                        return MVP_COMPLEX_SCALAR;
                    else 
                        return MVP_DOUBLE_SCALAR;
                } else if (mxIsLogical(v.i_mxArray.m) 
                           && mxGetNumberOfElements(v.i_mxArray.m) == 1 ) {
                    return MVP_LOGICAL_SCALAR;
                }
                return MVP_MXARRAY;
              default:
                return get_class_data()->Partition(v.slow.d);
            }
            return MVP_OTHER;
        }



//
// ******************************************************************************
//  
// Debugging API
//
// ******************************************************************************
//  
    void debug_print() const;
    void DebugDump( std::ostream &ostr ) const;


//
// ******************************************************************************
//  
// Copy-on-write
//
// ******************************************************************************
//  
    inline void makeModifiable() {
        unshare_indirect( );
    }

//
// ******************************************************************************
//  
// Testing / performance metric API
// This function makes it possible to compare the boundary implementation
// to the thread safe reference counting implementation.
// ** This will be removed when we settle on an Mvalue implementation.
//
// ******************************************************************************
//  
    void create_boundary() {
    }

    // Friend declarations
    friend class Mvalue_common<Mimplementation>;
    friend class Mimplementation_indirect;
    friend class Mvalue_initializer;
    friend inline void sqrt( Mimplementation *p, const Mimplementation &in);
} ;


#endif



#include <math.h>


inline void sqrt(Mcomplex *z, const Mcomplex &in) {    
    double re = in.real();
    double im = in.imag();
    double ore, oim;
    utCsqrt( &re, &im, &ore, &oim );
    *z = Mcomplex( ore, oim );
}


inline void sqrt( Mimplementation *p, const Mimplementation &in) {
  switch (in.v.disc.disc) {
    case Mimplementation::MV_double:
      /*
       * This case is an example where the "output" discrminant depends upon the
       * value of the input argument, not just the discriminant of the argument.
       */
      {
        double d = in.v.d_double.d;
        if (d < 0.0)
            p->reinit( 0.0, ::sqrt(-d));
        else
            p->reinit(::sqrt(d));
      }
      break;
    case Mimplementation::MV_Mcomplex:
    {
        double ore, oim;
        double re = in.v.i_Mcomplex.c->real();
        double im = in.v.i_Mcomplex.c->imag();
        utCsqrt(&re, &im, &ore, &oim );
        p->reinit( ore, oim );
        break;
    }
    default:
      throw "sqrt is undefined on this value";
  }
}



#ifndef ARRAY_ACCESS_INLINING
#define ARRAY_ACCESS_INLINING 1
#endif
#include "matrix.h"

#ifdef __cplusplus

#if defined(_MSC_VER) && _MSC_VER < 1300
#define TFRIEND(name) name
#else
#define TFRIEND(name) name <>
#endif

template <class T> class Mvalue_common;

template <class T> inline void sqrt( Mvalue_common<T> *output, const Mvalue_common<T> &in );

//
// ******************************************************************************
//
// This is the Mvalue facade class.  it is a template in order to be able to support
// multiple implementations sharing the same user facade.
//
// ******************************************************************************
//

template <class T> class Mvalue_common {
private:
    T t;
public:
    static void *operator new(size_t sz) { return utMalloc( sz ); }    
    static void operator delete(void *ptr) { utFree(ptr); }  
    static void *operator new [](size_t sz) { return utMalloc( sz ); }    
    static void operator delete[](void *ptr) { utFree(ptr); }  


//
// ******************************************************************************
//
// Constructors / Destructors / Init methods
//
// ******************************************************************************
//
    ~Mvalue_common() {}
    void init()                                // replace with uninitialized
    {
        t.destroy();
    }
    Mvalue_common() { t.init(); }              // Default constructor 
    inline void init( double d )               // Replace with double
    {
        t.destroy();
        t.init(d);
    }
    Mvalue_common( double d )                  // Construct a double scalar (calls init)
    {
        t.init(d);
    }
    inline void init( bool b )
    {
        t.destroy();
        t.init(b);
    }
    Mvalue_common( bool b )
    {
        t.init(b);
    }
    inline void init( const Mdirectdata &d, const Mclassdata &cd, unsigned short flags ) 
    {
        t.destroy();
        t.init( d, cd, flags );
    }
    Mvalue_common( const Mdirectdata &d, const Mclassdata &cd, unsigned short flags ) 
    {
        t.init( d, cd, flags );
    }
    inline void init( double re, double im ) {
        t.destroy();
        t.init(re,im);
    }
    Mvalue_common( double re, double im ) {    // Construct a complex scalar (calls init)
        t.init(re, im );
    }
    inline void init( const Mcomplex &c ) {
        t.destroy();
        t.init(c);
    }

    Mvalue_common( const Mcomplex & c ) {
        t.init( c );
    }
    inline void init(const Mvalue_common<T> &other ) {        // Copy one Mvalue into another (copy constructor)
        t.destroy();
        t.init(other.t);
    }
    Mvalue_common( const Mvalue_common<T> &other )             // Copy constructor (calls init) 
    {
        t.init( other );
    }    
    inline void init( mxArray *p ) {
        t.destroy();
        t.init(p);
    }
    inline void init(mxArray *p, bool own ) {
        t.destroy();
        t.init( p, own );
    }
    Mvalue_common( mxArray *p ) {
        t.init( p );
    }
    Mvalue_common( mxArray *p, bool own ) {
        t.init( p, own );
    }

//
// ******************************************************************************
//
// Assignment operators
//
// ******************************************************************************
//

    Mvalue_common<T> &operator =( double d )      // Replace the current value with a double scalar
    {
        init(d);
        return *this;
    }
    Mvalue_common<T> &operator =( bool b )      // Replace the current value with a bool
    {
        init(b);
        return *this;
    }
    Mvalue_common<T> &operator =( const Mcomplex &c )  
                                        // Replace the current value with a complex scalar
    {
        init( c );
        return *this;
    }    
    Mvalue_common<T> &operator =( mxArray *p ) // Takes ownership of the array
    {
        init( p );
        return *this;
    }
    Mvalue_common<T> &operator =( const Mvalue_common<T> &other ) // Replace the current value with the value of the expression
    {
        init(other);
        return *this;
    }

//
// ******************************************************************************
//
// Type conversion operators
//
// ******************************************************************************
//
    double toDouble() const {
        return t.toDouble();
    }
    Mcomplex toMcomplex() const {
        return t.toMcomplex();
    }
    bool toBool() const {
        return t.toBool();
    }
    Mdirectdata toMdirectdata() const {
        return t.toMdirectdata();
    }
    Mprotected_mxArray toMprotected_mxArray() const {
        return t.toMprotected_mxArray();       // Must return a reference counted or shared array
    }
    mvString tomvString() const {
        return t.tomvString(); 
    }

    void canonicalize() {
        t.canonicalize();
    }

//
// ******************************************************************************
//
// Experimental interface needs to be approved in a specification review
//
// ******************************************************************************
//
    void debug_print() const {
        t.debug_print();
    }
    void DebugDump( std::ostream &ostr ) const {
        t.DebugDump( ostr );
    }
    Mvalue_common *clone() const                  // Returns an allocated copy of this Mvalue
    {
        return new Mvalue_common( *this );
    }
    Mvalue_partition Partition() const {
        return t.Partition();
    }
    int get_type() const {
        return t.get_type();
    }
    int get_attributes() const {
        return t.get_attributes();
    }
    void makeModifiable() {                    // Unshare for copy-on-write
        t.makeModifiable();
    }
    void create_boundary()              // Create a boundary (used for thread safety in the new design)
    {
        t.create_boundary();
    }
    void indexassign( int i, const Mvalue_common<T> &B, int j) {  // this[i] = B[j];
        t.indexassign( i, B.t, j );
    }
    
    static unsigned short add_new_class( Mclassdata *classdata )
    {
        return T::add_new_class( classdata );        
    }
    
    bool is_user_defined( const Mclassdata &classdata ) const {
        return t.is_user_defined( classdata );
    }

    friend void TFRIEND(sqrt)( Mvalue_common<T> *output, const Mvalue_common<T> &in );
    friend class Mvalue_dispatcher;
};

template <> inline void Mvalue_common<Mimplementation>::init(double re, double im) {
    t.reinit(re,im);
}
template <> inline void Mvalue_common<Mimplementation>::init(const Mcomplex &c) {
    t.reinit(c);
}
template <> inline void Mvalue_common<Mimplementation>::init(const Mvalue_common<Mimplementation> &other) {
    t.reinit(other.t);
}

#ifdef _MSC_VER
#define declare_mvalue(implementation_class)                                                            \
template <class T> T mvalue_cast( const Mvalue_common<implementation_class> & obj );                    \
                                                                                                        \
template <> inline double mvalue_cast<double>( const Mvalue_common<implementation_class> & obj )        \
{                                                                                                       \
    return obj.toDouble();                                                                              \
}                                                                                                       \
typedef Mvalue_common<implementation_class> Mvalue;
#else
#define declare_mvalue(implementation_class)                                                            \
template <class T> T mvalue_cast( const Mvalue_common<implementation_class> & obj );                    \
                                                                                                        \
template <> inline double mvalue_cast<double>( const Mvalue_common<implementation_class> & obj )        \
{                                                                                                       \
    return obj.toDouble();                                                                              \
}                                                                                                       \
                                                                                                        \
template <> inline Mcomplex mvalue_cast<Mcomplex>( const Mvalue_common<implementation_class> & obj )    \
{                                                                                                       \
    return obj.toMcomplex();                                                                            \
}                                                                                                       \
                                                                                                        \
typedef Mvalue_common<implementation_class> Mvalue;
#endif


#ifndef INHIBIT_MVALUE_TYPEDEF
declare_mvalue(Mimplementation)
#endif

#endif


#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
}
#endif

 
template <class T> inline void sqrt( Mvalue_common<T> *output, const Mvalue_common<T> &in )
{
    sqrt( &output->t, in.t );
}


extern "C" {
class Mvalue_virtual;


extern Mvalue_virtual *mvMvalue_virtualClassFactory( void );


}


class Mvalue_virtual {
    static void *operator new(size_t sz) { return utMalloc( sz ); }    
    static void operator delete(void *ptr) { utFree(ptr); }      
    Mvalue_common<Mimplementation> t;
    virtual ~Mvalue_virtual();                   // Calls the destructor
    virtual double toDouble() const;
    virtual Mcomplex toMcomplex() const;
    virtual void init();                         // default initializer
    virtual void init(double d);                 // initialize a double scalar value
    virtual void init( double re, double im );   // initialize a complex scalar value
    virtual void init( const Mcomplex &c );
    virtual void init( Mvalue_virtual &other );    // Copy one Mvalue into another (copy constructor)
    virtual void makeModifiable();                     // Unshare for copy-on-write
    virtual void create_boundary();             // Create a boundary (used for thread safety in the new design)
    friend class Mvalue_dispatcher;
    friend class Mimplementation_virtual;
    Mvalue_virtual() {}                            // Default constructor 
    friend Mvalue_virtual *mvMvalue_virtualClassFactory( void );
};

extern "C" {

extern Mvalue_virtual *mvMvalue_virtualClassFactory( void );


}

class Mimplementation_virtual {
    static void *operator new(size_t sz) { return utMalloc( sz ); }    
    static void operator delete(void *ptr) { utFree(ptr); }  
    Mvalue_virtual *p;
    Mimplementation_virtual() 
    {
        p = mvMvalue_virtualClassFactory();
    } 
    ~Mimplementation_virtual()
    {
        delete p;
    }
    double toDouble() const { return p->toDouble(); }
    Mcomplex toMcomplex() const { return p->toMcomplex(); }
    void init() { p->init(); }
    void init(double d) { p->init(d); }
    void init(double re, double im) { p->init(re,im); }
    void init(const Mcomplex &c) { p->init(c); }
    void init(const Mimplementation_virtual &other) { p->init( *other.p );  }
    void makeModifiable(void) { p->makeModifiable(); }
    void create_boundary(void) { p->create_boundary(); }    
    friend void sqrt( Mimplementation_virtual *out, const Mimplementation_virtual &in );
    friend class Mvalue_dispatcher;
    friend class Mvalue_common<Mimplementation_virtual>;
};

template <> inline void Mvalue_common<Mimplementation_virtual>::init() {
    t.init();
}
template <> inline void Mvalue_common<Mimplementation_virtual>::init(double d) {
    t.init(d);
}
template <> inline void Mvalue_common<Mimplementation_virtual>::init(double re, double im) {
    t.init(re,im);
}
template <> inline void Mvalue_common<Mimplementation_virtual>::init(const Mcomplex &c) {
    t.init(c);
}
template <> inline void Mvalue_common<Mimplementation_virtual>::init(const Mvalue_common<Mimplementation_virtual> &other) {
    t.init(other.t);
}

class Mvalue_dispatcher {
public:
    Mvalue_dispatcher() {}
    virtual void sqrt( Mimplementation_virtual *output, const Mimplementation_virtual &input );
};

extern "C" {

extern Mvalue_dispatcher *mvMvalue_dispatcherClassFactory( void );


}

inline void sqrt( Mimplementation_virtual *out, const Mimplementation_virtual &in )
{
    mvMvalue_dispatcherClassFactory()->sqrt( out, in );
}

typedef Mvalue_common<Mimplementation_virtual> Mvalue_abi;




#if defined(__cplusplus) && (UTIL_VERSION >= 2) && !defined(INHIBIT_MVALUE_TYPEDEF)

//
// These classes support full conversion from mxArray -> Mvalue
// and from Mvalue -> mxArray interfaces.  They handle all of the data
// conversion and impedance matching for this conversion.
// There are 4 seperate clases defined:
//
//
// Mvalue_to_mxArray_list_rhs    Converts the rhs of an Mvalue function into an rhs
//                               usable by an mxArray valued function.
// Mvalue_to_mxArray_list_lhs    Converts the lhs of an Mvalue function into an lhs
//                               usable by an mxArray valued function.
// mxArray_to_Mvalue_list_rhs    Convert the rhs of an mxArray function into an rhs
//                               usable by an Mvalue function.
// mxArray_to_Mvalue_list_lhs    Convert the lhs of an mxArray function into an lhs
//                               usable by an Mvalue function
//
// Mvalue_to_mxArray_list        Converts both the lhs and the rhs arrays from Mvalue 
//                               into arrays usable in the lhs and the rhs contexts.
// mxArray_to_Mvalue_list        Converts both the lhs and the rhs arrays from mxArray
//                               into Mvalue
//
// For example, say that you have a function that takes mxArray ** and wants to call a function
// defined to take Mvalue **.  You would write:
//
// void call_Mvalue_function( int nlhs, mxArray **plhs, int nrhs, mxArray **prhs )
// {
//    mxArray_to_Mvalue_list mv( nlhs, plhs, nrhs, prhs );
//    call_my_Mvalue_function( nlhs, mv.lhs(), nrhs, mv.rhs() );
// }
//
// In the other direction, say that you have a function that takes Mvalue ** and wants to call a function
// defined to take mxArray **.  You would write:
//
// void call_mxArray_function ( int nlhs, Mvalue **plhs, int nrhs, Mvalue **prhs )
// {    
//    Mvalue_to_mxArray_list mx( nrhs, prhs );
//    call_my_mxArray_function( nlhs, mx.lhs(), nrhs, mx.rhs() );
//    mx.copy_lhs();    // Necessary because if this is done in the destructor
//                     // problems with the array list cleanup can occur
// }
//


#include "util.h"
#include <stddef.h>

#define NUMBER_ON_STACK 20

struct mvNegativeLHSMarker {
    void *p;
    void *pad[2]; // to make PURIFY free of spurious SBR report
};

class mvNegativeLHSMarkerdata;

class EXPORT_CLASS mvNegativeLHS {
public:
    static mvNegativeLHSMarkerdata *mvnlhsd;
    static bool IsNegativeLHS( Mvalue *po );
    static mxArray *getNegativeLHS( Mvalue *po );
    static void putNegativeLHS( Mvalue &o, mxArray *p );
    static int count_negative_rhs( size_t nrhs, Mvalue **prhs ) {
        size_t i;
        for (i=0; i< nrhs && IsNegativeLHS( prhs[i] ); i++)
            ;
        return i;
    }
};

typedef Mcountlist<Mprotected_mxArray, NUMBER_ON_STACK> Mcounted_protected_mxArray;
typedef Mcountlist<mxArray *, NUMBER_ON_STACK> Mcounted_mxarray;

class Mvalue_to_mxArray_list_rhs {
    Mcounted_protected_mxArray protlist;
    Mcounted_mxarray array;
public:
    Mvalue_to_mxArray_list_rhs( size_t nrhs, Mvalue **prhs ) :
        protlist(nrhs - mvNegativeLHS::count_negative_rhs( nrhs, prhs)), 
        array(nrhs-mvNegativeLHS::count_negative_rhs(nrhs,prhs)) {
        size_t i;
        size_t negrhs = mvNegativeLHS::count_negative_rhs( nrhs, prhs );
        for (i=0; i<nrhs-negrhs; i++) {
            //
            // NOTE: The extra {} are required in the expression below because the
            // Solaris C++ compiler introduces a temporary for this expression and does
            // not destroy it until the end of the enclosing scope.
            //
            {
                protlist[i] = prhs[i+negrhs]->toMprotected_mxArray();
            }
            array[i] = (mxArray  *) protlist[i];
            if (mxGetReferenceCount( array[i] ) > 0 ) {
                protlist[i] = NULL;
                protlist[i].Unprotect();
            }
        }
    }
    ~Mvalue_to_mxArray_list_rhs() {
    }
    operator mxArray **() const { return array; }
};

template <typename Terr> class Mvalue_to_mxArray_list_lhs_errchk {
    Mcounted_mxarray array;
    Mvalue **plhs;
    size_t nlhs;
    size_t actnlhs;
    Terr *err;
public:
    Mvalue_to_mxArray_list_lhs_errchk( size_t inlhs, Mvalue **iplhs, 
                                       size_t nrhs, Mvalue **prhs,
                                       Terr &ierr ) :
        array(inlhs != 0 ? inlhs 
              : (mvNegativeLHS::count_negative_rhs(nrhs,prhs) == 0 ? 1 
                 : mvNegativeLHS::count_negative_rhs(nrhs,prhs))) {

        // Sometimes non-mxArray values are passed-in through plhs
        // In these cases, the called function does not return any normal values

        size_t neg = mvNegativeLHS::count_negative_rhs(nrhs,prhs);
        size_t i;
        utAssert( inlhs == 0 || neg == 0 );
        actnlhs = inlhs;
        nlhs = inlhs == 0 ? (neg ? 0:1) : inlhs;
        plhs = iplhs; 
        if (neg) {
            for (i = 0; i< neg; i++) {
                array[i] = mvNegativeLHS::getNegativeLHS( prhs[i] );
            }
        }
        else {
            for (i = 0; i< nlhs; i++) {
                array[i] = NULL;
            }
        }
        err = &ierr;
    }    
    Mvalue_to_mxArray_list_lhs_errchk( size_t inlhs, Mvalue **iplhs,
                                       Terr &ierr ) : array(inlhs == 0 ? 1 : inlhs) {
        size_t i;
        actnlhs = inlhs;
        nlhs = inlhs == 0 ? 1 : inlhs; // compensate for ans
        plhs = iplhs; 
        for (i = 0; i< nlhs; i++) {
            array[i] = NULL;
        }
        err = &ierr;
    }
    ~Mvalue_to_mxArray_list_lhs_errchk() {
    }
    operator mxArray **() const { return array; }
    void copy_lhs() {
        size_t i;
        if (nlhs == 0 || (actnlhs == 0 && array[(size_t)0] == NULL)) {
            return;
        }
        for (i = 0; i < nlhs; i++) {
            if (array[i] == NULL || mxIsClassUnknown(array[i])) {
                if (actnlhs != 0)
                    (*err)();

                if (array[i] == NULL)
                    plhs[i]->init();
                else
                    (*plhs[i]) = array[i];
            }
            else {
                (*plhs[i]) = array[i];
            }
        }        
    }
};

struct DefaultUnassignedOutputHandler {
    void operator()() {
        mxErrMsgIdAndTxt(MATLAB_COMPONENT "unassignedOutputs", "One or more output arguments not assigned.");
    }
};

class Mvalue_to_mxArray_list_lhs {
    // We don't subclass because of initialization-order awkwardness
    DefaultUnassignedOutputHandler err;
    Mvalue_to_mxArray_list_lhs_errchk<DefaultUnassignedOutputHandler> mv2mx;
public:
    Mvalue_to_mxArray_list_lhs(size_t inlhs, Mvalue **iplhs, size_t nrhs, Mvalue **prhs):
        err(),
        mv2mx(inlhs, iplhs, nrhs, prhs, err) {}
    Mvalue_to_mxArray_list_lhs(size_t inlhs, Mvalue **iplhs):
        mv2mx(inlhs, iplhs, err) {}
    ~Mvalue_to_mxArray_list_lhs() {}
    operator mxArray **() const { return (mxArray**)mv2mx; }
    void copy_lhs() { mv2mx.copy_lhs(); }
};

template <typename Terr> class Mvalue_to_mxArray_list_errchk {
    Mvalue_to_mxArray_list_lhs_errchk<Terr> mxlhs;
    Mvalue_to_mxArray_list_rhs              mxrhs;
    int local_nlhs;
    int local_nrhs;
public:
    Mvalue_to_mxArray_list_errchk( int nlhs_in, Mvalue **plhs, int nrhs_in, Mvalue **prhs, Terr &err ) :
        mxlhs( nlhs_in, plhs, nrhs_in, prhs, err ),
        mxrhs( nrhs_in, prhs ) {
        int neg = mvNegativeLHS::count_negative_rhs(nrhs_in,prhs);
        utAssert( nlhs_in == 0 || neg == 0);
        local_nrhs = nrhs_in - neg;
        local_nlhs = nlhs_in - neg;
    }
    int nlhs() const { return local_nlhs; }
    int nrhs() const { return local_nrhs; }
    mxArray **lhs() const { return mxlhs; }
    mxArray **rhs() const { return mxrhs; }
    void copy_lhs() {
        mxlhs.copy_lhs();
    }
};

class Mvalue_to_mxArray_list {
    // We don't subclass because of initialization-order awkwardness
    DefaultUnassignedOutputHandler err;
    Mvalue_to_mxArray_list_errchk<DefaultUnassignedOutputHandler> mv2mx;
public:
    Mvalue_to_mxArray_list(int nlhs_in, Mvalue **plhs, int nrhs_in, Mvalue **prhs):
        err(),
        mv2mx(nlhs_in, plhs, nrhs_in, prhs, err) {}
    int nlhs() const { return mv2mx.nlhs(); }
    int nrhs() const { return mv2mx.nrhs(); }
    mxArray **lhs() const { return mv2mx.lhs(); }
    mxArray **rhs() const { return mv2mx.rhs(); }
    void copy_lhs() {
        mv2mx.copy_lhs();
    }
};

typedef Mcountlist<Mvalue, NUMBER_ON_STACK> Mcounted_mvalue;
typedef Mcountlist<Mvalue *, NUMBER_ON_STACK> Mcounted_mvalue_star;

class mxArray_to_Mvalue_list_rhs {
    Mcounted_mvalue vrhs;
    Mcounted_mvalue_star mvprhs;
public:
    mxArray_to_Mvalue_list_rhs( size_t nrhs, mxArray **prhs, size_t negative_lhs = 0, mxArray **negrhs = NULL ) : 
        vrhs(nrhs+negative_lhs), mvprhs(nrhs+negative_lhs) {
        size_t i;
        for (i=0; i<negative_lhs; i++) {
            mvprhs[i] = &vrhs[i];
            mvNegativeLHS::putNegativeLHS( vrhs[i], negrhs[i] );
        }
        for (i=0; i < nrhs; i++) {
            mvprhs[i+negative_lhs] = &vrhs[i+negative_lhs];
            vrhs[i+negative_lhs].init( prhs[i], false );
        }
    }
    ~mxArray_to_Mvalue_list_rhs() {
    }
    operator Mvalue **() const { return mvprhs; }
};

class mxArray_to_Mvalue_list;

class mxArray_to_Mvalue_list_lhs {
    Mcounted_mvalue vlhs;
    Mcounted_mvalue_star mvplhs;
    size_t nlhs;
    mxArray **plhs;
public:
    mxArray_to_Mvalue_list_lhs( size_t inlhs, mxArray **iplhs ) 
        : vlhs(inlhs == 0 ? 1 : inlhs), 
          mvplhs(inlhs == 0 ? 1 : inlhs) {
        nlhs = (inlhs == 0 ? 1 : inlhs);
        plhs = iplhs;
        size_t i;
        for (i=0; i < nlhs; i++) {
            mvplhs[i] = &vlhs[i];
        }
    }
    ~mxArray_to_Mvalue_list_lhs() {
        size_t i;
        for (i=0; i< nlhs; i++) {
            if (vlhs[i].Partition() == MVP_UNINITIALIZED) {
                plhs[i] = NULL;
            } else {
                Mprotected_mxArray pa = vlhs[i].toMprotected_mxArray();
                plhs[i] = pa.Unprotect_copy();
            }
        }
    }
    operator Mvalue **() const { return mvplhs; }
    friend class mxArray_to_Mvalue_list;
};

class mxArray_to_Mvalue_list {
    mxArray_to_Mvalue_list_lhs mvlhs;
    mxArray_to_Mvalue_list_rhs mvrhs;
    int local_nlhs;
    int local_nrhs;
public:
    mxArray_to_Mvalue_list( int nlhs_in, mxArray **plhs, int nrhs_in, mxArray **prhs ) :
        mvlhs( nlhs_in >= 0 ? nlhs_in : 0, plhs ),
        mvrhs( nrhs_in, prhs, nlhs_in < 0 ? -nlhs_in : 0, plhs ) {
        if (nlhs_in < 0) {
            mvlhs.nlhs = 0;  /* Do not touch the output variables at all */
        }
        local_nlhs = nlhs_in >= 0 ? nlhs_in : 0;
        local_nrhs = nlhs_in >=0 ? nrhs_in  : nrhs_in + -nlhs_in; 
    }
    int nlhs() const { return local_nlhs; }
    int nrhs() const { return local_nrhs; }
    Mvalue **lhs() const { return mvlhs; }
    Mvalue **rhs() const { return mvrhs; }
};

#endif


#endif /* mvalue_h */
