I came across two interviews (here and here) of Alexander Stepanov, the father of STL. There are quite a lot of interesting bits. For example, he thinks C++ is the best programming language to realize his goal, but he is also strongly against OOP at the same time. In addition, he has paid a lot of efforts on efficiency, which we can see from STL. He said: “It is silly to abstract an algorithm in such a way that when you instantiate it back it becomes inefficient”. I like these two interviews because I think in the same way. The only exception is I do not use STL, although I think it is the best generic library and I like it a lot. But why?
Two reasons. Firstly, STL is written in C++, which makes it unavailable to all C projects. It is possible to only use STL and forget all the other features in C++, but people rarely do so. At least I have not seen such a project where STL is combined with procedural programming. In addition, C++ projects are usually less portable than C projects and STL makes it worse. It puts a lot of stress on C++ compilers. Even Stepanov agreeed, by the time of the interview, that “The unfortunate reality is that a lot of code in the present implementation of STL is suboptimal because of the compiler limitations and bugs of the compilers I had to use when I was developing STL”. Secondly, using STL also means much longer compiling time. I remembered I used to compile a customized Linux kernel for my old laptop in an hour. Probably I would spend more than a day to compile if it was written using C++/STL.
A generic container library would benefit a lot of C programmers, but so far I am not aware of any efficient implementation. Glib tries to achieve so, but it uses void* and this inevitably will incur overhead and complicate interfaces. And finally, I decide to write my own one. Ideally (but probably impractically) I want to achieve four goals: a) efficiency in speed and space; b) elegance in interface; c) independency between functinality and d) simplicity in codes. However, currently I am not competent enough to achieve all these goals and I am not a professional programmer at all (and so cannot invest enough time). As I said in my About page, I mainly do this to please myself.
Ah, so you want templates in C. It can be done with horrifying preprocessor magic. That’s how they came to C++.
Maybe sglib?
As to sglib, the idea is fine, but the implementation is not as good. I do not recommend it.
There are indeed people that do insist in the use of the void pointer as generic. Actually, most of C programmers do.
Yet, there is nothing generic to it. Okay, the void pointer is generic when it comes to pointers. Any pointer type will do just as fine (say int pointer).
If someone wants generality, someone may design data structures that reserve memory for the user needs. Say, if a list storing strings is required, one will write code implementing a list that reserves space in the list nodes. Sort of `sizeof(node) + string length (+ 1)’.
Such techniques are well known, and well used. They do provide (very often) significant performance improvements (over the void pointer stuff). For once (and this is likely the most interesting part) modern computers are slow when it comes to memory. As such, when searching some (say) binary tree that does not stores data in the tree nodes, for each visited tree two memory locations are visited: the one storing the node (and the void pointer), and the one storing the actual data. When storing data in the node, only one location is visited, the speed improvements are huge most of the times.
Other advantages include lesser memory requirements (only one allocated memory block, no space to store void pointers), convenience (no need to allocate space to store data), etc, etc. Also, well written C code doing that is often very close to preprocessor (or template) code when it comes to speed. To well written preprocessor (or template) code, that is.
Yes, yours is an efficient strategy. Nonetheless, I think it is not so easy to use as you need to supply extra data structures. The point is a macro library can do most you want. If you want to keep the data in a tree node, you can do so; if you want to keep a pointer that points to an element in a preallocated array, you can also achieve. A macro library gives you flexibility and efficiency not possible by a void* library.