SGLIB - A Simple Generic Library for C

[Documentation] [License] [Publications] [Download] [Feedback]






1.) What is it about?

Sglib is a library defining useful macros for manipulating common data structures. The library currently provides generic implementation for:
  • sorting arrays
  • manipulating linked lists
  • manipulating sorted linked lists
  • manipulating double linked lists
  • manipulating red-black trees
  • manipulating hashed containers
A basic set of functions (macros) is provided for each data structure. They cover insertion, deletion, search and iterator traversal of elements. Moreover, additional (specific) functions are provided for each data structure, such as, concatenation, reverse or sort for lists.

Sglib provides algorithms, not data structures. Algorithms implemented in Sglib operate on user's types, for example, list macros are operational for any data structure containing a pointer to the same type.

Sglib consists of a single header file without any binary code. In order to use it just put #include "sglib.h" into your source code.

The library is implemented in the C programming language and written for C programmers, however it is freely inspired by the Standard Template Library.

Although I wish to keep the library as simple as possible all suggestions for new functionalities are welcomed. Currently, the implementation of queues, priority queues, hashed tables and AVL trees is in progress.

2.) Why is it different from existing C libraries?

  • Sglib is general.

    Sglib does not require its own data structures. You do not need to design your program to be used with Sglib from the beginning. You can start using Sglib at any stage of the development of your project with your existing data types.

    For example, let's suppose that you have a program working on a list of historical events represented by the structure:

    struct event {
      int time;
      char *title;
      char *description;
      struct category *category;
      struct event *nextEvent;
    };
    
    Let's suppose that you have a list of such events ordered by time. You are supposed to insert a new event to such list. First, you need to define a comparator. A comparator is a macro or function returning respectively a positive, negative or zero value for cases when the first parameter is greater, less or equal to the second. For example, the following macro is the comparator we need:
    #define CMP_EVENT(x,y) (x->time - y->time)
    
    Now you can insert a new event into the list (while keeping the list sorted) with the following code:
    SGLIB_SORTED_LIST_ADD(struct event, theList, newEvent, CMP_EVENT, nextEvent);
    
    This macro is expanded into a code inserting the newEvent onto the right place of theList.

    Note that the macro is also parameterized by the type of the list, the comparator used to order elements and by the name of the field pointing to the next element of the list. In consequence, the macro is very general and usable in nearly any circumstances.

  • Sglib is generic.

    Sglib is generic in the sense that each functionality is parametrized by the type on which it operates. It defines algorithms independent on types. In C++ this can be done easily using templates, in C this is achieved with the preprocessor. Preprocessor does not matter whether macro parameters are types or values. However, because the preprocessor is purely textual and does not respect the underlying programming language, an additional effort is required to prevent macros from a misuse.

    For example, let's take a program defining an array of two-dimensional points represented by their coordinates. The corresponding definition in C is:

    struct point {
       int x;
       int y;
    } thePointArray[SIZE];
    
    and a macro defining lexicographical ordering on points:
    #define CMP_POINT(p1,p2) ((p1.x!=p2.x)?(p1.x-p2.x):(p1.y-p2.y))
    
    In such case the following line of code is sorting the array using heap sort:
      SGLIB_ARRAY_SINGLE_HEAP_SORT(struct point, thePointArray, SIZE, CMP_POINT);
    
    Note that no pointers are involved in this implementation.
  • Sglib is fast.

    Sglib operates directly on your data structures. It does not require an additional pointer stored in its internal data representation. It does not contain any allocations and freeing of internal data structures neither. Moreover, macros are expanded in compile time saving the overhead related to function invocations.
  • Sglib is independent on memory management system.

    Sglib does not create/allocate or destruct/free any datas. It only manipulates them. For example, macros manipulating balanced trees are exclusively modifiying the "left_son" and "right_son" (or whatever names user chooses) fields of allocated cells. In consequence, Sglib is absolutely independent on any memory management system. It never calls malloc or similar function. It is perfectly usable in projects requiring high discipline in memory allocation.
  • Sglib is safe.

    Macros are known as being source of bugs because macro parameters may be evaluated several times and symbols inside parameters are resolved in the scope where parameters are used, not in the scope where the macro is invoked. For example, let's take the macro:
    #define LIST_LEN(type, list, result) {\\
      int i;\\
      type l;\\
      for(i=0,l=list; l!=NULL; l=l->next, i++) ;\\
      result = i;\\
    }
    
    invoked in the situation:
    int ilistlen(ilist *l) {
      int res;
      LIST_LEN(ilist, l, res);
      return(res);
    }
    
    Here, the symbol l in the line LIST_LEN(struct ilist, l, res); is logically expected to be resolved to the formal parameter of the function ilistlen. However in reality it is resolved to the local variable l defined by the line type l;\ inside the macro. This usually provokes compiler to complain about a use of an uninitialized variable.

    Sglib offers two mechanisms to avoid such problems.

    • First, Sglib is using particular naming conventions. All variables defined inside macros begins and ends with _ (underscore). As it is unusual to use such names in normal code this reduces the risk of conflicts. The above macro computing length of a list would be implemented as:
      #define LIST_LEN(type, list, result) { \\
        int _i_; \\
        type _l_; \\
        for(_i_=0,_l_=(list); _l_!=NULL; _l_=_l_->next, _i_++) ; \\
        (result) = _i_; \\
      }
      
    • Second, Sglib offers all its functionalities not only in form of macros, but also in form of standard C functions.

      Internally we call macros as a level - 0 user interface and functions as a level - 1 user interface. The level - 1 interface provides legal C functions for each particular type and those functions can be called from the main program without worrying about unwanted effects due to macro expansions.

      The level - 1 interface in praxis means, that you invoke one large macro at the beginning of your program. This macro is parametrized by the type and it generates all available functions for this type. Names of those functions will be composed from the prefix sglib_ followed by the name of your type and finishing by the name of the operation they implement.

      For example the invocation:

      SGLIB_DEFINE_SORTED_LIST_FUNCTIONS(ilist, ilist_comparator, next)
      
      is expanded into definitions of functions, such as sglib_ilist_len, sglib_ilist_sort, sglib_ilist_add, sglib_ilist_delete, etc. Those functions take parameter of the type ilist and they use the function (or macro) ilist_comparator to compare elements. You can use those functions without worrying about macro expansions. For example, the above function computing the length of a list would be:
      int ilistlen(ilist *l) {
        int res;
        res = sglib_ilist_len(l);
        return(res);
      }
      
      Note that there is practically no danger of conflicts when invoking the SGLIB_DEFINE_SORTED_LIST_FUNCTIONS macro, because this macro is invoked in the top level scope and because it is using exclusively non-expression parameters.


3.) Why to do it?

Everyone knows that the C preprocessor can be used to imitate genericity of other languages and everyone consider this idea dangerous and ugly. I don't. With experiences in my programming praxis I used macros parametrized by types more and more often. Finally, I realized that I need a really general and well designed generic library. After a research on the Internet I have found only sys/queue.h header which was far from what I needed. I was surprised that after 30 years of the existence of the C language, in the era of the Internet when everyone is doing everything for anybody, nobody have written such library. Even if I believed that one day I would find somewhere a similar library yet done, I decided to invest my time into creation of the Sglib. I have started by collecting all macros that I have written for Xrefactory giving them a uniform face.

In opposition to many cake eaters from my university, I believe that ideas behind Sglib are good because of my former research on modern (and generic) programming languages and because of my current work on a refactoring browser for C. From previous works I know that many generic constructions are implemented via some form of preprocessor. When working on the C refactoring browser I have written my own C preprocessor. During this work I have realized how much the preprocessor is standardized and how precisely it is defined in the current ANSI standard. Hence, even very advanced (you may say strange) preprocessor constructions are perfectly portable through compilers implementing ANSI standard.

4.) Is there any publication or documentation available?

Sglib comes with full reference manual in HTML format together with few samples.

For referencing Sglib in any kind of article, please cite:


M. Vittek, P. Borovansky, P.E. Moreau: A Simple Generic Library for C, in Reuse of Off-the-Shelf Components: Proceedings of
 9th International Conference on Software Reuse, Turin, pp. 423-426, 2006.

or, in bibtex format:
@Inproceedings{vittekBorovanskyMoreauTurin2006,
  author =       "Marian Vittek and Peter Borovansky and Pierre-Etienne Moreau",
  title =        "A Simple Generic Library for C",
  year =         "2006",
  pages =        "423-426",
  booktitle =    { Reuse of Off-the-Shelf Components: ,  Proceedings of 9th International Conference on Software Reuse, Tur
in, Italy},
  publisher =    {{Springer}}
}



5.) Under what license conditions it comes?

Basically, I only care that you do not remove the Copyright notice from the source code when using Sglib.

More precisely: you can use Sglib or its derivative forms (under the condition that the Copyright notice is preserved) in any project, whether commercial or not, free of charges. In particular, you can use Sglib under the terms of any license defined as an open source license by the Open Source Initiative (see http://www.opensource.org/). This includes most common open source licenses such as the BSD license and GNU GPL.

If you need to use sglib under any particular license conditions, contact the author.

WARRANTY

THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.

6.) Where to download it?

You can download
sglib together with full documentation from its sourceforge site.

7.) Where to post a feedback?

You can post your feedback to sglib
mailing list hosted on the sourceforge.