Looking for a mechanism (hard to explain)

Started by
10 comments, last by Jan Wassenberg 19 years, 8 months ago
What i'm looking for is a mechanism, sort of like a Pluggable Factory, only not using the Prototype pattern and not a Factory either ;-) I have a Resource Manager. What i would like to be able to do is say: ResourceManager->LoadResourcesFor( "NameOfSomeClass" ); But i want it dynamically configured. The manager needs to maintain a list of classes with which it can negotiate the exchange of resources. BUT i want those classes automatically registered when the program begins. - I do not want to hand-code a list of classes that the manager can talk to, either in hard code or in a data file. I want the program to just run and have all classes that need resources just self-register. Ideally i should just be able to write a new resource-dependent class, recompile, and be ready to rock. - I should not have to edit or recompile the actual Resource Management code, nor any loaded data the manager may use. The question is now: How? What can i technically do to make a class talk to the manager when the app is executed and basically say "Hi. My name is [insert class name]. I might need some resources later. Here is where you can reach me." The basic idea is like a Pluggable Factory but i'm not trying to create anything, just pass some class-specific data to the manager when the app is started. But i do not know what sort of construct would do that. If you can help me, thank you! EDIT: I'll shoot this down before it even comes up. Q: "Why not just have a class talk to the manager the first time it is used?" A: I want resources pre-loaded for speed before i need them the first time ;-)
Advertisement
There is a neat little trick you can use.

If, in a source file (.cpp) at the global, you write:
static bool foo = some_func();

some_func() will be called before main(); so you use this trick to register your classes with Resource Manager.
#define REGISTER_THINGY(x) bool _register_##x##_fn() \{\x::RegisterSelf(); \return true; \}\static bool _register_##x##_var = _register_##x##_fn();

(EDIT: You will have to put the "\"s in yourself as when I pasted the code here with them it stuffed up :( )

Here is a macro that I wrote that should help you out. It assumes that your resource-managed classes have a static function that lets them register themselves but you can ammend this to your likings. For me I made the RegisterSelf() function private so I made this other macro:
#define FRIEND_THINGY(x) friend bool _register_##x##_fn();

for use in the classes' definition.

Then all you need to do is in the classes .cpp file (after the implementation) is write:
REGISTER_THINGY(foo);


I hope this helps.

[Edited by - Bugdude on August 17, 2004 6:07:45 AM]
Yes, that's basically what i was looking for. I'm not sure what you mean by slashes though, could you explain?

thanks a lot for the tip!
Quote:Original post by leiavoia
Yes, that's basically what i was looking for. I'm not sure what you mean by slashes though, could you explain?

thanks a lot for the tip!


In multiline macros you need to escape the newline character as macros are terminated by a newline.

eg

#define blah(x) \
int foo = x; \
doSomething();

Its just for some reason this board hates "\" [looksaround]

I wish this forum would let you preview your posts.

EDIT: I figured it out and have edited my original post.
I haven't studied the provided code thoroughly, but some alarmbells went of in my head when I read this:

static bool foo = some_func();


This might be called before main, but you will never know for certain that the resource manager exists at this point! Static variables are initialised before main is called, however, the program does not promise you anything about the order they are initialised. So this statement might be called before you even have a resource manager.
I should have pointed out that I was assuming that ResourceManager was a singleton like Loki::Singleton.
Quote:This might be called before main, but you will never know for certain that the resource manager exists at this point! Static variables are initialised before main is called, however, the program does not promise you anything about the order they are initialised. So this statement might be called before you even have a resource manager.


I thought about that last night. As bugdude already mentioned, it requires you to make a singleton out of the resource manager that self-initializes the first time it's used.
Another interesting, albeit non-portable way, is to use the linker to group init functions from each module into a table. This happens at compile time, and you can specify an ordering for each function. I got the idea from the CRT, and use it for Windows-specific modules shared between several projects.

Code snippets:
// each module has the linker add a pointer to its init and shutdown// function to a table (at a user-defined position).// zero runtime overhead, and there's no need for a central dispatcher// that knows about all the modules.//// disadvantage: requires compiler support (MS VC-specific).//// alternatives:// - initialize via constructor. however, that would leave the problem of//   shutdown order and timepoint, which is also taken care of here.// - register init/shutdown functions from a NLSO constructor://   clunky, and setting order is more complicated.// - on-demand initialization: complicated; don't know in what order//   things happen. also, no way to determine how long init takes.#define WIN_REGISTER_FUNC(func) static int func(); static int(*p##func)(void) = func#pragma data_seg(".LIB$WTA")WIN_REGISTER_FUNC(wsock_shutdown);#pragma data_seg()#pragma data_seg(".LIB$WTA")_PIFV shutdown_begin[] = { 0 };#pragma data_seg(".LIB$WTZ")_PIFV shutdown_end[] = { 0 };#pragma data_seg()// call all non-NULL function pointers in [begin, end).// note: the range may be larger than expected due to section padding.// that (and the COFF empty section problem) is why we need to ignore zeroes.static void call_func_tbl(_PIFV* begin, _PIFV* end){	for(_PIFV* p = begin; p < end; p++)		if(*p)			(*p)();}static void at_exit(void){	call_func_tbl(shutdown_begin, shutdown_end);	...}
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3
I think that's a little too on the evil side for me :-)
I think what you want to do is best accomplished by having a post-compile step that generates a CPP file containing all the registration information. Look into using Perl or Python for this.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis

This topic is closed to new replies.

Advertisement