Click here to Skip to main content
15,880,796 members
Articles / Programming Languages / C++

DynObj - C++ Cross Platform Plugin Objects

Rate me:
Please Sign up or sign in to vote.
4.95/5 (34 votes)
27 Sep 200727 min read 141.3K   3.4K   132  
DynObj is an open source library that provides a C++ application with run-time class loading facilities
// Copyright (c) 2007, Arne Steinarson
// Licensing for DynObj project - see DynObj-license.txt in this folder

#ifndef DORUNTIME_H
#define DORUNTIME_H

#ifndef DO_USE_RUNTIME 
    #warning DO_USE_RUNTIME  is not defined. Setting it from DoRunTime.h 
    #define DO_USE_RUNTIME 1
#endif

// %%DYNOBJ section general
// This section is auto-generated and manual changes will be lost when regenerated!!
#ifdef DO_IMPLEMENT_DORUNTIME
    #define DO_IMPLEMENTING     // If app has not defined it already
#endif
#include "dynobj/DynObj.h"

// --- Integer type ids for defined interfaces/classes ---
#define DORUNTIMEC_TYPE_ID 0xDCCF5000

// --- Forward class declarations ---
class DoRunTimeC;

// --- For each declared class, doTypeInfo template specializations ---
DO_DECL_TYPE_INFO(DoRunTimeC,DORUNTIMEC_TYPE_ID);

// %%DYNOBJ section end


#ifndef DO_MAIN
	#define DO_MAIN		// DoRunTime is always in the main module
#endif

#include "DoBaseI.h"
#include "DoError.h"

// Access global DoRunTimeI through this function

#include "DynObj.h"
#include "utils/ExpArr.hpp"
#include "utils/HashTable.hpp"
#include "utils/CharBuf.h"
#include "DoBase.hpp"
#include "DortInt.h"

#include "DynObjLib.h"
#include "DoNotifiable.hpp"
#include "NamedRef.h"

//class DynObjLib;
struct DynObjError;
struct DOError;
class DynStr;
class DoVtblType;



/** @ingroup ImplClass
 * The global instance of DoRunTime.
 * Holds shared types and resources available tyo main program and 
 * the loaded libraries.
 */
// %%DYNOBJ class(dyni) bases(DoRunTimeI,NotifierI,NamedRefI,DortInternalI)
class DoRunTimeC : public DoRunTimeI, public Notifier, public NamedRef, 
                   public DortInternalI {
public:
	DoRunTimeC();
	~DoRunTimeC(){ Dtor(); }
	void Dtor();

	/** Get the one and only instance */
	static DoRunTimeC &GetInstance();

    /** @name Virtuals
     *  Interface members */
    //@{ 

	// Base DynObj functions
	virtual DynObjType* docall doGetType( const DynI **pself=0 ) const;
	virtual void*       docall doGetObj( const char *type );
	virtual void        docall doDestroy( ){ delete this; }

	//@{ 
    /** Access shared functionality */
	virtual MutexI*  docall  GetMutex() const { return m_pmut; }
	virtual MallocI* docall  GetMalloc() const { return m_pmalloc; }
	virtual TextIoI* docall  GetTextIo() const { return m_ptio; }
    //@}
	
	/** Object creation 
      * @param lib Library name or NULL if automatic search
      * @param type Type name (of created class)
      * @param type_id Type ID (of created class)
      * @param pdi_init Argument to constructor of new object
      * @param obj_size Not used - Size of memory to allocate 
      * @return Pointer to new DynObj */
	virtual DynObj*    docall  Create( const char *lib, const char *type, int type_id, const DynI* pdi_init=NULL, int obj_size=0 );

	//@{ 
    /** Global error handling - per thread */
	virtual int         docall GetLastErrCode( int thid=-1 );
	virtual bool        docall GetLastErrStr( DynStr& ds, int thid=-1 );
	virtual bool        docall SetLastError( int err_code, const char *err_msg );
	virtual int         docall GetThreadId( );
    //@}

	//@{ 
    /** Module registration - internal use */
	virtual bool        docall RegisterModule( DoModuleC *pmi );
	virtual bool        docall UnRegisterModule( DoModuleC *pmi );
    //@}
	
	//@{ 
    /** Manage types based on VPTR (VTable pointer) */
	virtual bool        docall RegisterType( void **vtbl, DynObjType *pdt );
	virtual bool        docall UnRegisterType( void **vtbl );
	virtual DynObjType* docall GetTypeOf( void **vtbl );
    //@}
	
	//@{ 
    /** Handle per object errors */
    virtual bool docall SetObjectError( const VObj *pvo, const char *err_str, int err_code );
    virtual bool docall ClearObjectError( const VObj *pvo );
    virtual const char* docall GetObjectError( const VObj *pvo, int *perr_code );
    //@}

    //@}    // Virtuals
    
    /** @name Others 
     *  Utrility functions */
    //@{ 
    
	// Takes ownership of the library
    /** Add/remove libraries. These functions take ownership of the libraries
      * (until library is removed). The libraries are unloaded at application 
      * shutdown */
	bool AddDOLib( DynObjLib *pdol );
	bool RemoveDOLib( const DynObjLib *pdol );
	/** Returns NULL on success, otherwise error from library loader */
	const char *LoadLib( const char *lib_name );
	/** Returns an owned library (for temporary use) */
	DynObjLib* GetLib( const char *lib );
	
	// Does not take ownership for these objects
    /** Change the exposed memory allocator. Must do before memory 
      * allocation begins! */
	void SetMalloc( MallocI *pmi ){ m_pmalloc=pmi; }
    
    /** Set Text IoI currently used. This is where logging and printing
      * goes to. */
	void SetTextIo( TextIoI *ptio ){ m_ptio=ptio; }

    /** Returns true if DoRunTime is alive and well and not shutting down */
    bool IsOk();
    
    /** Template wrapper of create above.
      * It uses a clever algorithm to guess which library to allocate from, 
      * so a search is avoided in most cases. */
    template<class T>
	T* Create( doTypeWrapper<T>, const char *lib, const DynI* pdi_init=NULL, int obj_size=0 ) {
        if( !IsOk() || m_tmp_disable<0 ) return NULL;
        
        // Check library is OK.
        static int st_lib_cache_ix = -1;
        if( st_lib_cache_ix==-1 ){
            // First time around for this type, alloc an index
            st_lib_cache_ix = m_lib_cache_ix++;
            m_type_libs.Push(NULL);
        }
        const char *type = doTypeInfo<T>::Name();
        int type_id = doTypeInfo<T>::Id();
        
        T *pt;
        
        // Attempt to use last library it worked for
        DynObjLib *pdol = m_type_libs[st_lib_cache_ix];
        if( pdol && (!lib || !strcmp(pdol->GetLibName(),lib)) ){
            pt = (T*)pdol->Create(type,type_id,pdi_init,obj_size);
            if( pt ) return pt;
            // Fall through, try another lib
        }
        
        MutexLocker lock(m_pmut);
        pt = (T*)Create( lib, type, type_id, pdi_init, obj_size );
        if( pt )
            // Cache the library for this type
            m_type_libs[st_lib_cache_ix] = m_lib_last;
            
        return pt;
    }

    //@}    // Others
    virtual void docall OnObjectDestroy( DynObj *pdo );
    virtual void docall TempDisableCreate( bool disable );

protected:
    
	MutexI	 *m_pmut;		// No point in changing this one during execution
	MallocI  *m_pmalloc;
	TextIoI  *m_ptio;	
	
    DynObjLib *m_lib_last;
    int       m_lib_cache_ix;
	ExpArrP<DynObjLib*>     m_type_libs;
	ExpArrP<DynObjLib*>     m_libs;
    
	ExpArrP<DoModuleC*>     m_modules;
    
    // All registered types, associated with VTable pointers
	HashTable<void**,DynObjType*> m_types;
    
    // Global errors
	ExpArrP<DOError*>    m_errors;
    
    // Per object error handling
	HashTable<const VObj*,DOError*> m_obj_errors;
    ExpArrPOwn<DOError*> m_oe_allocated;
    ExpArrP<DOError*> m_oe_avail;
    
    int m_tmp_disable;
};

/// @cond internal

// A global error, per thread
struct DOError {
	DOError(int thid, int err_code, const char *err_str) : 
		m_thid(thid), m_err_code(err_code), m_err_str(err_str) { }
	bool operator == (int thid) { return m_thid==thid; }
	
	int     m_thid;
	int     m_err_code;
	CharBuf m_err_str;
};


// Solve different ways of handling args in do_new
// Parallel implementation in DynObjLib.h 
template<class T,class A, bool dyni_arg>
struct DoCreator;

template<class T,class A>
struct DoCreator<T,A,false> {
    static T *Create( A arg, const char *lib ){
        // Wrap arg
        DynData dd(arg);
        return DoRunTimeC::GetInstance().Create( doTypeWrapper<T>(), lib, &dd, 0 );
    }
};

template<class T,class A>
struct DoCreator<T,A*,true> {
    static T *Create( A* parg, const char *lib ){
        // Arg is already DynI
        return DoRunTimeC::GetInstance().Create( doTypeWrapper<T>(), lib, parg, 0 );
    }
};

template<class T,class A>
struct DoCreator<T,A&,true> {
    static T *Create( A& arg, const char *lib ){
        // Arg is already DynI
        return DoRunTimeC::GetInstance().Create( doTypeWrapper<T>(), lib, &arg, 0 );
    }
};

/// @endcond internal


/** @ingroup DynTemplate
 * Create a new DynObj based on C++ type.
 * Can take arbitrary type of argument and pass along to constructor of new object 
 * after wrapping it up in a DynData object. 
 * @param arg Constructor argument of arbitrary type 
 * @param lib_name Name of library to use or NULL for default (this is usually 
 * efficient)
 */
template <class T, class A>
T *do_new( A arg, const char *lib_name ){
//T *do_new( A arg, const char *lib_name=DOH_LIB_FIRST ){
    return DoCreator<T,A,DoIsTypeA<A,DynI>::v>::Create( arg, lib_name );
}

/** @ingroup DynTemplate
 * Create a new DynObj based on C++ type.
 * No argument version. New object will receive a NULL pointer in constructor.
 */
template <class T>
T *do_new( ){
    return DoCreator<T,DynI*,true>::Create( (DynI*)NULL, DOH_LIB_FIRST );
}


/*
// Creates a new object using the instance of DoRunTime
template <class T>
T *do_new( const DynI* pdi_init=NULL, const char *lib_name=DOH_LIB_FIRST ){
    // This is internal C++ linking
	return DoRunTimeC::GetInstance().Create( doTypeWrapper<T>(), lib_name, pdi_init, 0 );
}
*/

// %%DYNOBJ section implement
// This section is auto-generated and manual changes will be lost when regenerated!!
#ifdef DO_IMPLEMENT_DORUNTIME

// Generate type information that auto-registers on module load
DynObjType g_do_vtype_DoRunTimeC("DoRunTimeC:DoRunTimeI",DORUNTIMEC_TYPE_ID,1,sizeof(DoRunTimeC));
SideBaseDecl g_do_vtype_sbd_DoRunTimeC_1("DoRunTimeC","NotifierI",sizeof(NotifierI),sidebase_offset<DoRunTimeC,NotifierI>(),NULL,-1,NULL);
SideBaseDecl g_do_vtype_sbd_DoRunTimeC_2("DoRunTimeC","NamedRefI",sizeof(NamedRefI),sidebase_offset<DoRunTimeC,NamedRefI>(),NULL,-1,NULL);
SideBaseDecl g_do_vtype_sbd_DoRunTimeC_3("DoRunTimeC","DortInternalI",sizeof(DortInternalI),sidebase_offset<DoRunTimeC,DortInternalI>(),NULL,-1,NULL);
DynObjType* DoRunTimeC::doGetType( const DynI **pself ) const {
   if(pself) *pself=(const DynI*)(const void*)this;
   return &g_do_vtype_DoRunTimeC;
}
#endif //DO_IMPLEMENT_...
// %%DYNOBJ section end

#endif // DORUNTIME_H


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions