ObjList Module

Header: ObjList.hpp
Module components: ObjList Module

Manual

ObjList module is a set of macros for defining doubly-linked list of objects. Lets say we have two classes: MyContainer and MyItem. We want to make each object of class MyContainer able to contain list of objects of class MyItem. Each objects of class MyItem will be able to lie within list of one of objects of type MyContainer (or none of them).

To do this, you have to use all related macros in the correct way. All of these macros have same parameters and are in form of:

#define OBJLIST_...(ListT, ItemT, Name)

Where:

For example:

// File MyContainer.hpp

class MyItem;

class MyContainer
{
public:
  MyContainer();
  ~MyContainer();
  
  OBJLIST_LIST_METHODS(MyContainer, MyItem, MyList)

private:
  OBJLIST_LIST_FIELDS(MyContainer, MyItem, MyList)
};

// File MyContainer.cpp

#include "MyContainer.hpp"
#include "Item.hpp"

OBJLIST_LIST_IMPL(MyContainer, MyItem, MyList)

MyContainer::MyContainer()
{
  OBJLIST_LIST_CTOR(MyContainer, MyItem, MyList)
}

MyContainer::~MyContainer()
{
  OBJLIST_LIST_DTOR(MyContainer, MyItem, MyList)
}

// File MyItem.hpp

class MyContainer;

class MyItem
{
  MyItem();
  ~MyItem();

  OBJLIST_ITEM_METHODS(MyContainer, MyItem, MyList)

private:
  OBJLIST_ITEM_FIELDS(MyContainer, MyItem, MyList)
};

// File MyItem.cpp

#include "MyItem.hpp"
#include "MyContainer.hpp"

MyItem::MyItem()
{
  OBJLIST_ITEM_CTOR(MyContainer, MyItem, MyList)
}

MyItem::~MyItem()
{
  OBJLIST_ITEM_DTOR(MyContainer, MyItem, MyList)
}

Now MyItem class has following public methods:

MyItem class also has following private declarations (you are discouraged to use them directly):

MyContainer class has following public methods:

MyContainer class also has following private declarations (you are discouraged to use them directly):

The list mechanism described here does not delete any objects or free any memory by itself. You are still responsible for freeing dynamically allocated objects of type MyContainer, as well as MyItem. List connections are automatically managed though. Deleting MyContainer object removes all contained MyItem objects from its list, so they no longer lie in the list. Deleting MyItem object removed itself from MyContainer list so the list no longer contains pointer to that object.

All methods listed above (except MyList_Clear) have computational complexity O(1), so inserting items into a list, removing items from the list, checking if item belongs to a list or retrieving list item count is very fast.

Here is example of using classes defined above, including iterating through the list:

MyContainer Container1;
MyItem Item1, Item2, Item3;

Container1.MyList_InsertBack(&Item1);
Container1.MyList_InsertBack(&Item2);
Container1.MyList_InsertBack(&Item3);

for (
  MyItem *item = Container1.MyList_GetFirst();
  item != NULL;
  item = item->MyList_GetNext() )
{
  std::cout << "Visiting item" << std::endl;
}

Object list gives you great flexibility. You can delete item objects and container objects whenever you want (as long as you do it on a single thread or protect all operations on the list with mutex). You can have item objects not belonging to any list. You can have multiple container objects and keep a list of (different) items inside each of them.

Static List

There is also a set of macros available for creating static list. This way you can make your container class having static fields and methods, so there will be only one single list with specified name. That list could be accessed without creating any object of container class, just by referencing the class itself. For example:

// File MyTest.hpp

class MyItem2
{
public:
  MyItem2();
  ~MyItem2();

  STATIC_OBJLIST_ITEM_METHODS(MyStaticContainer, MyItem2, MyStaticList)

private:
  STATIC_OBJLIST_ITEM_FIELDS(MyStaticContainer, MyItem2, MyStaticList)
};

class MyStaticContainer
{
public:
  STATIC_OBJLIST_LIST_METHODS(MyStaticContainer, MyItem2, MyStaticList)

private:
  STATIC_OBJLIST_LIST_FIELDS(MyStaticContainer, MyItem2, MyStaticList)
};

// File MyTest.cpp

MyItem2::MyItem2()
{
  STATIC_OBJLIST_ITEM_CTOR(MyStaticContainer, MyItem2, MyStaticList)
}

MyItem2::~MyItem2()
{
  STATIC_OBJLIST_ITEM_DTOR(MyStaticContainer, MyItem2, MyStaticList)
}

STATIC_OBJLIST_LIST_IMPL(MyStaticContainer, MyItem2, MyStaticList)

Code above defines following public methods in class MyItem2:

MyItem2 class also has following private declarations (you are discouraged to use them directly):

MyStaticContainer class has following static public methods:

MyStaticContainer class also has following private static fields (you are discouraged to use them directly):

Sample code:

MyItem2 Item1, Item2, Item3;

MyStaticContainer::MyStaticList_InsertBack(&Item1);
MyStaticContainer::MyStaticList_InsertBack(&Item2);
MyStaticContainer::MyStaticList_InsertBack(&Item3);

for (
  MyItem2 *item = MyStaticContainer::MyStaticList_GetFirst();
  item != NULL;
  item = item->MyStaticList_GetNext() )
{
  std::cout << "Visiting item" << std::endl;
}

Rationale

Why is this module designed like this, with all these strange macros instead of some clever template classes or why not just use std::list?

ObjList gives you better performance, because:

ObjList gives you better flexibility (especially thanks to custom name for any list).


Generated on Wed Dec 16 20:44:52 2009 for CommonLib by  doxygen 1.6.1