Talk About Network

Google


Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Programming > C++ Moderated > Comment on my a...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 7 Topic 9758 of 9984
Post > Topic >>

Comment on my adapter concept

by Oncaphillis <oncaphillis@[EMAIL PROTECTED] > Jun 30, 2008 at 08:58 AM

Hello,

I'm working on an adapter for a C plugin API. Plugins which are loaded
as dynamical libraries are expected  to provide a function which fills
a  struct  of  function pointers  to service  routines.  Two  of these
functions are expected to  allocate and deallocate the plugins private
data. The C-Style "base class" of this data is defined as.

struct plugin_data {
   PLUGIN_DATA;
};

where    PLUGIN_DATA  is  a chunk  of     data  neccessary for  plugin
maintainance. A plugin structure might look like:


struct plugin {
   void * (*alloc)();                    // alloc pd_data
   void   (*free)(void *pd);             // free  pd_data
   int    (*do_foo1)( void *pd,foo * );  // do some with foo and pd_data
   int    (*do_foo2)( void *pd,foo * );  // do some more with foo and
pd_data
   int    (*do_foobar)( void *pd,foo *,bar *); // do some with foo and bar
and pd_data
};

and  after it is  properly set  up the main   application code might do
something like:

if( (pd = p.alloc())!=NULL) {
   if(p.do_foo1!=NULL) {
    (*p.do_foo1)(pd,&f);
   } else{
    printf("Skipping do_foo1\n");
   }
   p.free(pd);
}

I'd like to transform the alloc/free functions into CTors and DTors of
a   module  class and the calling    via function pointers into method
invokations and came up with the following:

My plugin_data is a templated struct which holds a module object M like:

template<M>
struct plugin_data {
  PLUGIN_DATA;
  M module;
}

Types of plugin function pointers  and module member function pointers
are collected in traits structs accordingly like

template<class P>
struct plugin_traits {
   typedef void * (*alloc_fptr_t)();
   typedef void   (*free_fptr_t)(void *);
   typedef int    (*foo_fptr_t)(void *,::foo *);
   typedef int    (*foobar_fptr_t)(void *,::foo *,::bar *);
};

module_traits also contains an enum  which indicates which methods are
actually   implemented by the concrete  module.  The existence of  the
corresponding method will be determined via SFINAE

template<class M>
struct module_traits {
   typedef M module_t;
   typedef int (M:: * foo_fptr_t   )(Foo &       );
   typedef int (M:: * foobar_fptr_t)(Foo &, Bar &);
   struct has_function {
   enum {
    do_foo1  = true,
    do_foo2  = true,
    do_foobar= false
   };
};

For each function pointer  I implemented a corresponding  struct which
provides a static function pointer "ptr" which is eiher NULL or points
to a static member function   "go" that translates plugin_data  struct
into a module  reference and calls  the appropriate module method via a
member function pointer.  All of these adapters  which share the  same
signature share the same base class. So a group of functions like

  int do_foo1( ::foo *)
  int do_foo2( ::foo *)

is represented by

  template<class D,class MT,class PT,bool B>
  struct foo_adapter_base;

  template<class D,class MT,class PT>
  struct foo_adapter_base<D,MT,PT,true> {
  private:
   typedef typename MT::module_t    module_t;
  protected:
   static int go(  void *p, ::foo * f ) {
    plugin_data<module_t> *pd = (plugin_data<module_t> *)p;
    Foo foo(f);
    return (pd->module.*D::mfptr)(foo);
   }
   private:
    foo_adapter_base();
   public:
    static const typename PT::foo_fptr_t ptr;
   };


template<class D,class MT,class PT>
const typename PT::foo_fptr_t foo_adapter_base<D,MT,PT,true>::ptr = D::go;

template<class D, class MT,class PT>
struct foo_adapter_base<D,MT,PT,false> {
  static const typename PT::foo_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::foo_fptr_t foo_adapter_base<D,MT,PT,false>::ptr=NULL;


The static  method "go" allocates   objects encapsulating the argument
pointer and calls a method  within the module  which is expected to be
held within the static variable "mfptr" of D. If the last template arg
is true "ptr" points to the function D::go. If D does not provide such a
static function this should  default to the "go"  function of the base
class  since concrete adapters   should  provide themself as D.
This allows static overwritin via CRTP.

A concrete adapter for int do_foo1(Foo &) would look like:

template<class M,class MT=module_traits<M>,class PT=plugin_traits<
::plugin
>,bool B=MT::has_function::do_foo1>
struct do_foo1_adapter : public foo_adapter_base<
do_foo1_adapter<M,MT,PT,B>,MT,PT,B > {
};

template<class M,class MT,class PT>
struct do_foo1_adapter<M,MT,PT,true> : public foo_adapter_base<
do_foo1_adapter<M,MT,PT,true>, MT,PT,true > {
   static typename MT::foo_fptr_t mfptr;
};

template<class M,class MT,class PT>
typename MT::foo_fptr_t do_foo1_adapter<M,MT,PT,true>::mfptr =
&M::do_foo1;

So it just has to define "mfptr" if B is true, which is taken from the
module_traits::has_function struct. Otherwise it can be empty.

The alloc adapter would just create an instance of plugin_data<M> and
return the result.

In the end you may setup the plugin struct with:

p->init    = init_adapter<my_module>::ptr;
p->free    = free_adapter<my_module>::ptr;
p->do_foo1 = do_foo1_adapter<my_module>::ptr;


So, if you managed  to read all of this  you might want to share  your
thoughts about this    concept.   Every  comment will    be    hightly
appreciated. Is there a way to make it leaner ? Are there any pitfalls
aspecially with regard to the C/C++ calling conventions etc.

I've also attached a  self contained program  which compiles/runs fine
here under Fedora 8 with g++ 4.3.1 but since I used a lot of template
magic
it  would  be great if   someone finds the time  to  squeeze  it thought
h(is|er) compiler.

Thank you very much indeed.

<snip>

#include <iostream>

extern "C" {
#define PLUGIN_DATA int id

   struct foo {};
   struct bar {};

   struct plugin {

     void * (*alloc)();
     void   (*free)(void *p);

     int    (*do_foo1)( void *pd,foo * );
     int    (*do_foo2)( void *pd,foo * );
     int    (*do_foobar)( void *pd,foo *,bar *);
   };
}


struct Foo {
   Foo(::foo *) {
   }
};

struct Bar {
   Bar(::bar *) {
   }
};

class my_module {
public:
   int do_foo1(Foo &) {
     std::cerr << "my_module::do_foo1" << std::endl;
     return 0;
   }
   int do_foo2(Foo &) {
     std::cerr << "my_module::do_foo2" << std::endl;
     return 0;
   }
};

template<class M>
struct plugin_data {
   PLUGIN_DATA;
   M module;
};

template<class M>
struct module_traits {
   typedef M module_t;
   typedef int (M:: * foo_fptr_t   )(Foo &       );
   typedef int (M:: * foobar_fptr_t)(Foo &, Bar &);
   struct has_function {
     enum {
       do_foo1  = true,
       do_foo2  = true,
       do_foobar= false
     };
   };
};

template<class P>
struct plugin_traits {
   typedef void * (*alloc_fptr_t)();
   typedef void   (*free_fptr_t)(void *);
   typedef int    (*foo_fptr_t)(void *,::foo *);
   typedef int    (*foobar_fptr_t)(void *,::foo *,::bar *);
};

// ALLOC
//

template<class D,class MT,class PT >
struct alloc_adapter_base {
private:
   typedef typename MT::module_t    module_t;
protected:
   static void *  go() {
     plugin_data<module_t> * p;
     try {
       std::cerr << "init::go" << std::endl;
       p=new plugin_data<module_t>();
     } catch(std::exception & ex) {
       std::cerr << "FAILED TO ALLOC" << std::endl;
       return NULL;
     }
     return p;
   }
private:
   alloc_adapter_base();
public:
   static const typename PT::alloc_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::alloc_fptr_t alloc_adapter_base<D,MT,PT>::ptr = D::go;

template< class M, class MT = module_traits<M>, class PT =
plugin_traits< ::plugin > >
struct alloc_adapter : public alloc_adapter_base<
alloc_adapter<M,MT,PT>,MT,PT> {
};

// FREE
//

template<class D,class MT,class PT >
struct free_adapter_base {
private:
   typedef typename MT::module_t    module_t;
protected:
   static void go(  void *p ) {
     plugin_data<module_t> *pd = (plugin_data<module_t> *)p;
     delete pd;
   }
private:
   free_adapter_base();
public:
   static const typename PT::free_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::free_fptr_t free_adapter_base<D,MT,PT>::ptr = D::go;

template< class M, class MT = module_traits<M>, class PT =
plugin_traits< ::plugin > >
struct free_adapter : public free_adapter_base<
free_adapter<M,MT,PT>,MT,PT>
{
};

// FOO
//

template<class D,class MT,class PT,bool B>
struct foo_adapter_base;

template<class D,class MT,class PT>
struct foo_adapter_base<D,MT,PT,true> {
private:
   typedef typename MT::module_t    module_t;
protected:
   static int go(  void *p, ::foo * f ) {
     plugin_data<module_t> *pd = (plugin_data<module_t> *)p;
     Foo foo(f);
     return (pd->module.*D::mfptr)(foo);
   }
private:
   foo_adapter_base();
public:
   static const typename PT::foo_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::foo_fptr_t foo_adapter_base<D,MT,PT,true>::ptr = D::go;

template<class D, class MT,class PT>
struct foo_adapter_base<D,MT,PT,false> {
   static const typename PT::foo_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::foo_fptr_t foo_adapter_base<D,MT,PT,false>::ptr=NULL;


// DO FOO1
//

template<class M,class MT=module_traits<M>,class PT=plugin_traits<
::plugin
>,bool B=MT::has_function::do_foo1>
struct do_foo1_adapter : public foo_adapter_base<
do_foo1_adapter<M,MT,PT,B>,MT,PT,B > {
};

template<class M,class MT,class PT>
struct do_foo1_adapter<M,MT,PT,true> : public foo_adapter_base<
do_foo1_adapter<M,MT,PT,true>, MT,PT,true > {
   static typename MT::foo_fptr_t mfptr;
};

template<class M,class MT,class PT>
typename MT::foo_fptr_t do_foo1_adapter<M,MT,PT,true>::mfptr =
&M::do_foo1;

// DO FOO2
//


template<class M,class MT=module_traits<M>,class PT=plugin_traits<
::plugin
>,bool B=MT::has_function::do_foo2>
struct do_foo2_adapter : public foo_adapter_base<
do_foo2_adapter<M,MT,PT,B>,MT,PT,B > {
};

template<class M,class MT,class PT>
struct do_foo2_adapter<M,MT,PT,true> : public foo_adapter_base<
do_foo2_adapter<M,MT,PT,true>, MT,PT,true > {
private:
   typedef foo_adapter_base< do_foo2_adapter<M,MT,PT,true>, MT,PT,true >
super;
private:
   static int go( void *p,::foo *f) {
     std::cerr << " >> Custom do_foo2_adapter" << std::endl;
     int i = super::go(p,f);
     std::cerr << " << Custom do_foo2_adapter" << std::endl;
     return i;
   }

   static typename MT::foo_fptr_t mfptr;

   friend class foo_adapter_base< do_foo2_adapter<M,MT,PT,true>,
MT,PT,true
>;
};

template<class M,class MT,class PT>
typename MT::foo_fptr_t do_foo2_adapter<M,MT,PT,true>::mfptr =
&M::do_foo2;

// FOOBAR
//

template<class D,class MT,class PT,bool B>
struct foobar_adapter_base;

template<class D,class MT,class PT>
struct foobar_adapter_base<D,MT,PT,true> {
private:
   typedef typename MT::module_t    module_t;
protected:
   static int go(  void *p, ::foo * f, ::bar *b ) {
     plugin_data<module_t> *pd = (plugin_data<module_t> *)p;
     Foo foo(f);
     Bar bar(f);
     return (pd->module.*D::mfptr)(foo,bar);
   }
private:
   foobar_adapter_base();
public:
   static const typename PT::foobar_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::foobar_fptr_t foobar_adapter_base<D,MT,PT,true>::ptr =
D::go;

template<class D, class MT,class PT>
struct foobar_adapter_base<D,MT,PT,false> {
   static const typename PT::foobar_fptr_t ptr;
};

template<class D,class MT,class PT>
const typename PT::foobar_fptr_t
foobar_adapter_base<D,MT,PT,false>::ptr=NULL;

// DO FOO BAR
//

template<class M, class MT=module_traits<M>, class
PT=plugin_traits< ::plugin >, bool B=MT::has_function::do_foobar >
struct do_foobar_adapter : public foobar_adapter_base<
do_foobar_adapter<M,MT,PT,B>,MT,PT,B> {
};

template<class M, class MT, class PT >
struct do_foobar_adapter<M,MT,PT,true> : public foobar_adapter_base<
do_foobar_adapter<M,MT,PT,true>,MT,PT,true> {
   static typename MT::foobar_fptr_t mfptr;
};

template<class M, class MT, class PT >
typename MT::foobar_fptr_t do_foobar_adapter<M,MT,PT,true>::mfptr =
&M::do_foobar;

// PLUGIN SETUP

template<class M>
void plugin_setup(plugin * p) {
   p->alloc     = alloc_adapter<M>::ptr;
   p->free      = free_adapter<M>::ptr;
   p->do_foo1   = do_foo1_adapter<M>::ptr;
   p->do_foo2   = do_foo2_adapter<M>::ptr;
   p->do_foobar = do_foobar_adapter<M>::ptr;
};

extern "C" {
   int main() {

     struct plugin p;
     struct foo    f;
     struct bar    b;

     plugin_setup<my_module>(&p);

     void *pd;

     if( (pd = p.alloc())!=NULL) {

       if(p.do_foo1!=NULL) {
         (*p.do_foo1)(pd,&f);
       } else{
         printf("Skipping do_foo1\n");
       }

       if(p.do_foo2!=NULL) {
         (*p.do_foo2)(pd,&f);
       } else{
         printf("Skipping do_foo2\n");
       }

       if(p.do_foobar!=NULL) {
         (*p.do_foobar)(pd,&f,&b);
       } else{
         printf("Skipping do_foobar\n");
       }

       p.free(pd);
     }
   }
};
</snip>

-- 
      [ See http://www.gotw.ca/resources/clcm.htm
for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
 




 7 Posts in Topic:
Comment on my adapter concept
Oncaphillis <oncaphill  2008-06-30 08:58:26 
Re: Comment on my adapter concept
Le Chaud Lapin <jaibud  2008-07-02 03:33:34 
Re: Comment on my adapter concept
Oncaphillis <oncaphill  2008-07-02 11:10:19 
Re: Comment on my adapter concept
Le Chaud Lapin <jaibud  2008-07-03 03:28:04 
Re: Comment on my adapter concept
Oncaphillis <oncaphill  2008-07-03 08:54:24 
Re: Comment on my adapter concept
Thomas Richter <thor@[  2008-07-05 04:58:05 
Re: Comment on my adapter concept
Oncaphillis <oncaphill  2008-07-05 16:54:21 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Sun Sep 7 8:34:21 CDT 2008.