Google
 
Webnews.only-4-geeks.com
Interesting places
news.only-4-geeks.com Forum Index » C++

Comment on my adapter concept

 
Jump to:  
 
Oncaphillis
PostPosted: Mon Jun 30, 2008 2:58 pm    Post subject: Comment on my adapter concept
       
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
Quote:
,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
Quote:
,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
Quote:
,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
Quote:
;
};


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 LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Le Chaud Lapin
PostPosted: Wed Jul 02, 2008 9:33 am    Post subject: Re: Comment on my adapter concept
       
On Jun 30, 9:58 am, Oncaphillis <oncaphil...@snafu.de> wrote:
Quote:
Hello,

I'm working on an adapter for a C plugin API.

Why? What is it good for? :)

-Le Chaud Lapin-


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Oncaphillis
PostPosted: Wed Jul 02, 2008 5:10 pm    Post subject: Re: Comment on my adapter concept
       
Quote:
I'm working on an adapter for a C plugin API.

Why? What is it good for? :)


Well it irons your shirts, feeds your kids, walks the
dog and pays the mortgage :-)

It's just a C-Style plugin system where each time a new
plugin is meant to be written a couple of function pointers
have to be initialized to NULL or a valid function pointer.
The whole code is very C++-stylish already. They have
structs mimicking a std::string and things that look
like a streambuf. So I'm covering this all under a
C++-layer.

So e.g. something like

int_plugin(*p) {
p->alloc = my_alloc;
p->free = my_free;

p->do_foo1 = NULL;
p->do_foo2 = my_do_foo2;
...
...
...
}

becomes

int_plugin<M>(*p) {
p->alloc = module_adapter<M>::alloc;
p->free = module_adapter<M>::free;
p->do_foo1 = module_adapter<M>::do_foo1;
...
...
}

Notice that the second function is module independent
"do_foo1" will become NULL whenever the module class
doesn't declare a do_foo1 method. Whereas the first
approach has to be rewritten whenever the module interface
changes. This goes down to the module_traits<M>::has_function::do_xyz
enum. In my example code these values are set explicitly, but
I already check via SFINAE if the corresponding method exists.

Hope that explains why

O.




--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Le Chaud Lapin
PostPosted: Thu Jul 03, 2008 9:28 am    Post subject: Re: Comment on my adapter concept
       
On Jul 2, 12:10 pm, Oncaphillis <oncaphil...@snafu.de> wrote:
Quote:
I'm working on an adapter for a C plugin API.

Why? What is it good for? :)

Well it irons your shirts, feeds your kids, walks the
dog and pays the mortgage :-)

It's just a C-Style plugin system where each time a new
plugin is meant to be written a couple of function pointers
have to be initialized to NULL or a valid function pointer.
The whole code is very C++-stylish already. They have
structs mimicking a std::string and things that look
like a streambuf. So I'm covering this all under a
C++-layer.

So e.g. something like

int_plugin(*p) {
p->alloc = my_alloc;
p->free = my_free;

p->do_foo1 = NULL;
p->do_foo2 = my_do_foo2;
...
...
...

}

becomes

int_plugin<M>(*p) {
p->alloc = module_adapter<M>::alloc;
p->free = module_adapter<M>::free;
p->do_foo1 = module_adapter<M>::do_foo1;
...
...

}

Notice that the second function is module independent
"do_foo1" will become NULL whenever the module class
doesn't declare a do_foo1 method. Whereas the first
approach has to be rewritten whenever the module interface
changes. This goes down to the module_traits<M>::has_function::do_xyz
enum. In my example code these values are set explicitly, but
I already check via SFINAE if the corresponding method exists.

Hope that explains why

First, you should know, it took me a while to figure out the context,
meaning, it might help, while describing your facility, that you
specify an overall architecture. It is not clear [to me at least]
whether the plug-in thing was written in C++, and the other thing was C
++, or vice-versa. Maybe a one-line diagram showing the executable
pieces in Windows or Linux:

[executable thing]---[executable thing]

Which of these ^^^^ is the plug-in, and which language are these
things written in?

Also, but asking what is this good for...yes, we all know the syntax
of C++ and that amusing tricks can be done with templates and
pointers. Smile But surely you have a motivation beyond that! How about
a real example? That's what I meant when asking what it is good for.

Just curious,

-Le Chaud Lapin-



--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Oncaphillis
PostPosted: Thu Jul 03, 2008 2:54 pm    Post subject: Re: Comment on my adapter concept
       
Quote:
First, you should know, it took me a while to figure out the context,
meaning, it might help, while describing your facility, that you
specify an overall architecture. It is not clear [to me at least]
whether the plug-in thing was written in C++, and the other thing was C
++, or vice-versa. Maybe a one-line diagram showing the executable
pieces in Windows or Linux:

Sorry for that. The original plugin thingy is written in C and it meant to
stay that way.

Quote:
Which of these ^^^^ is the plug-in, and which language are these
things written in?

Also, but asking what is this good for...yes, we all know the syntax
of C++ and that amusing tricks can be done with templates and
pointers. Smile But surely you have a motivation beyond that! How about
a real example? That's what I meant when asking what it is good for.

The real example of what I have in mind actually is the

init_plugin<M>( ::plugin )

line. At least for this part of my API. There's already a wealth of plugins
around for the system with a lot of redundant code lines, like setting
up the plugin struct. Another part not mentioned here is the handling
of these streambuf like C-struct with a very complex read/write syntax
which is screaming for being converted into a basic_iostream.

The point is that I'm trying to eliminate the complexity in the plugin code
by raising the complexity in the library code, which is supposed to stay
hidden for a plugin developers.

Thank you for your reply

O.


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Thomas Richter
PostPosted: Sat Jul 05, 2008 10:58 am    Post subject: Re: Comment on my adapter concept
       
Oncaphillis schrieb:

Quote:
The real example of what I have in mind actually is the

init_plugin<M>( ::plugin )

line. At least for this part of my API. There's already a wealth of plugins
around for the system with a lot of redundant code lines, like setting
up the plugin struct. Another part not mentioned here is the handling
of these streambuf like C-struct with a very complex read/write syntax
which is screaming for being converted into a basic_iostream.

The point is that I'm trying to eliminate the complexity in the plugin code
by raising the complexity in the library code, which is supposed to stay
hidden for a plugin developers.

But again, it seems to me like a solved problem. All operating systems
I'm aware of offer something like this under the concept "shared
libraries", and the resolution of the "plugins" is left to an operating
system part known as dynamic linker. For Linux, "dlopen" is your friend,
and I'm sure win also offers an interface for handling dll's.

Besides, what's the relation of this to the C++ language which would
make your question on-topic?

So long,
Thomas

--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Oncaphillis
PostPosted: Sat Jul 05, 2008 10:54 pm    Post subject: Re: Comment on my adapter concept
       
Quote:
But again, it seems to me like a solved problem. All operating systems
I'm aware of offer something like this under the concept "shared
libraries", and the resolution of the "plugins" is left to an operating
system part known as dynamic linker. For Linux, "dlopen" is your friend,
and I'm sure win also offers an interface for handling dll's.

Besides, what's the relation of this to the C++ language which would
make your question on-topic?

The plugin is actually loaded via a call to dlopen. The style of plugin
initialization (stuffing a struct with function pointers), is just
the C-style legacy code I have to live with, and my primary idea was,
as I already stated, to reduce redundant code in plugins with all these
funny tricks (as Le Chaud Lapin) would have said. This approach has become
quite complex, therefor my initial question if there might be a way of
making it any leaner, while retaining the simplicity and flexibility
I think it provides. May be it's valuable or not, but I hope I'm at leats
not of-topic since I've used quite a lot of C++-specific code and my
approach is heavily template based.

Thanks for your thoughts

O.



--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

Page 1 of 1 .:.

Google
 
Webnews.only-4-geeks.com

Windows Update | C++ | C | PHP | JavaScript | Photoshop | Programming | Windows 2000 | Python | Windows XP | Object | Flash | Flash - ActionScript | Paint Shop Pro | Excel | PowerPoint | Access | Word | Windows 98 | Internet Explorer 6.0 | CorelDraw12 | Java | XML | asm x86 | Linux Mandrake | Linux RedHat | Outlook |  | news from newsgroups |_ | s

Web Templates

Awesome Website Templates ©

Kredyty Samochodowe agencja hostess srebro city gratka