/* * @(#)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 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 &other ) { own = other.own; if (own) p = copy_fn( other.p ); else p = other.p; } void operator =(const Mprotected_cptr &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 { 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::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(ip, iown) { } mxArray * operator->() { return p; } }; #include "util.h" #ifdef __cplusplus // // ****************************************************************************** // // Use std::complex 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 typedef std::complex Mcomplex; #endif #ifdef __cplusplus #include // // ****************************************************************************** // // 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 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 inline void mvDump( T *p, const Mallocator &a ) { a.dump((void *)p); } template inline void mvCopy( T *p, const Mallocator &a ) { a.copy((void *) p); } template inline bool mvIslonely( T *p, const Mallocator &a) { return a.islonely((void *) p ); } #endif #ifdef __cplusplus #include 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 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 inline const T *extract_data_pointer( const Mdirectdata &d ) { return (const T *) d.data; } template inline T *extract_data_pointer( Mdirectdata &d ) { return (T *) d.data; } template 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 #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 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; friend class Mimplementation_indirect; friend class Mvalue_initializer; friend inline void sqrt( Mimplementation *p, const Mimplementation &in); } ; #endif #include 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 Mvalue_common; template inline void sqrt( Mvalue_common *output, const Mvalue_common &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 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 &other ) { // Copy one Mvalue into another (copy constructor) t.destroy(); t.init(other.t); } Mvalue_common( const Mvalue_common &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 &operator =( double d ) // Replace the current value with a double scalar { init(d); return *this; } Mvalue_common &operator =( bool b ) // Replace the current value with a bool { init(b); return *this; } Mvalue_common &operator =( const Mcomplex &c ) // Replace the current value with a complex scalar { init( c ); return *this; } Mvalue_common &operator =( mxArray *p ) // Takes ownership of the array { init( p ); return *this; } Mvalue_common &operator =( const Mvalue_common &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 &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 *output, const Mvalue_common &in ); friend class Mvalue_dispatcher; }; template <> inline void Mvalue_common::init(double re, double im) { t.reinit(re,im); } template <> inline void Mvalue_common::init(const Mcomplex &c) { t.reinit(c); } template <> inline void Mvalue_common::init(const Mvalue_common &other) { t.reinit(other.t); } #ifdef _MSC_VER #define declare_mvalue(implementation_class) \ template T mvalue_cast( const Mvalue_common & obj ); \ \ template <> inline double mvalue_cast( const Mvalue_common & obj ) \ { \ return obj.toDouble(); \ } \ typedef Mvalue_common Mvalue; #else #define declare_mvalue(implementation_class) \ template T mvalue_cast( const Mvalue_common & obj ); \ \ template <> inline double mvalue_cast( const Mvalue_common & obj ) \ { \ return obj.toDouble(); \ } \ \ template <> inline Mcomplex mvalue_cast( const Mvalue_common & obj ) \ { \ return obj.toMcomplex(); \ } \ \ typedef Mvalue_common Mvalue; #endif #ifndef INHIBIT_MVALUE_TYPEDEF declare_mvalue(Mimplementation) #endif #endif #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif template inline void sqrt( Mvalue_common *output, const Mvalue_common &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 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; }; template <> inline void Mvalue_common::init() { t.init(); } template <> inline void Mvalue_common::init(double d) { t.init(d); } template <> inline void Mvalue_common::init(double re, double im) { t.init(re,im); } template <> inline void Mvalue_common::init(const Mcomplex &c) { t.init(c); } template <> inline void Mvalue_common::init(const Mvalue_common &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 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 #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 Mcounted_protected_mxArray; typedef Mcountlist 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; itoMprotected_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 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 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 class Mvalue_to_mxArray_list_errchk { Mvalue_to_mxArray_list_lhs_errchk 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 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 Mcounted_mvalue; typedef Mcountlist 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= 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 */