On 5/18/2012 4:14 AM, jacob navia wrote:
> When I presented an example of the interface here (thread CCL vs STL, a
> comparison), many posters complained about the syntax:
>
> int main(void)
> {
> List *L;
> int data;
>
> L = iList.Create(sizeof(int));
>
> data = 0;
> iList.Add(L,&data);
> iList.PushFront(L,&data);
> data = 2;
> iList.InsertAt(L,1,&data);
> // ...
> }
>
> It was said that passing a void pointer couldn't be checked by
> the compiler (what is trure of course) and that the whole wasn't
> very easy to use (maybe).
>
> I have developed a "generic" approach using a parametized file.
>
> For instance, if you want a list of integers, you write a small file
> like this:
>
> ---------------------------intlist.c (the implementation)
> #include "containers.h"
> #undef DATA_TYPE
> #define DATA_TYPE int
> #include "listgen.c"
> #undef DATA_TYPE
>
> ----------------------------intlist.h (the declarations)
> #include "containers.h"
> #undef DATA_TYPE
> #define DATA_TYPE int
> #include "listgen.h"
> #undef DATA_TYPE
>
> That's all. This defines following stuff:
>
> A type called "intList" that implements ALL the functions
> of the list container for the int data type. The requirements
> for the data type are that it must be a value type, i.e. the
> code assumes that it is passed by value. At the same time
> the "iintList" interface is defined with the same entry
> points as the generic list interface iList.
>
> Besides it must be a single token, for instance for using
> long long you must
>
> typedef long long longlong;
> #define DATA_TYPE longlong
>
> Besides those two points, the file allows now to do as follows:
>
> -------------------------------using specialized list container
> #include "containers.h"
> #include "intlist.h"
> static int PrintInt(int data,void *extraArgs)
> {
> fprintf(extraArgs,"%d ",data);
> }
> int main(void)
> {
> intList *L;
> int data;
>
> L = iintList.Create(sizeof(int));
> iintList.Add(L,0);
> iintList.PushFront(L,0);
> iintList.InsertAt(L,1,2);
>
> iintList.Add(L,5);
>
> iintList.Add(L,6);
> iintList.Apply(L,PrintInt,stdout);
> iintList.Finalize(L);
> }
>
> Note that the "Create" function still takes the same
> arguments as the original generic one. I want to keep
> all code compatible since it would be better to avoid code bloat.
>
> Each instanstiated type adds 18.6K to the program (x86+gcc/OS X Mac)
>
> If you have several types, code could be shared in many instances
> since the data type remains compatible, and the signatures weren't
> changed.
>
> For the time being code is NOT shared.
>
>
> What do you think?
>
I once did vaguely similar using an extended preprocessor and block macros.
#defmacro FOO(type)
....
lots of stuff...
....
#endmacro
....
FOO(int)
the block-macro differed from #define mostly in that it could handle
larger globs of code and didn't need endless '\' characters.
there were lots of other features as well (such as delayed preprocessor
commands, ...).
IMO, it is a little nicer, but didn't really get lots of use since it is
an extra hassle to set up code to be passed through an extra tool prior
to compilation (unless it stood between make and the compiler or
something, which it didn't do).
otherwise:
passing parameters into specialized header files via #define is a trick
I have used before. it works I guess.
a particular example is this of the "main loop" stub for my 3D engine,
where due to technical reasons I ended up having to "hijack" main (or
WinMain), and a special header generates the main loop.
parameters are used for, among other things, setting GC options (initial
heap-size limits, ...) and indicating which functions to call (functions
are called at various locations in order to do whatever, such as set-up
or tear-down app, redraw the window, ...).
or such...
|