/* * CENA C++ Utilities * * by Stephane Chatty * * Copyright 1991-1993 * Laboratoire de Recherche en Informatique (LRI) * Centre d'Etudes de la Navigation Aerienne (CENA) * * documentation skeleton - to be updated * * $Id$ * $CurLog$ */ \namedoc{Ccu} \def\utils{CCU} \input{psfig} \chapter{Introduction} This documentation describes a number of classes that can be useful for developping C++ applications, and especially user interfaces. The packages are: \begin{itemize} \item a memory manager. As suggested by the C++ language designers it provides efficient allocation for small objects. This memory manager is well suited for the management of fixed size objects. \item dynamic arrays. \item a linked list package, with dynamic allocation of list cells. These lists are designed for the simple management of sets of any kind of elements in a linked form, without node sharing. There are two classes, for single and double linked lists. This package also provides list-based implementations of stacks and queues. \item a hash table package. Hash tables can be used for building associative arrays. Users can define their own hashing function. A derived class is also provided: it offers ready-to-use association tables with strings as keys, i.e. dictionaries. \item a signal handling package, which makes it possible to disable or handle signals. \item a time package. Two classes implement time stamps and wall clocks. Another class, based on the {\it UNIX BSD\/} interval timer, implements alarm clocks and timers. \item a basic string package. It is designed in order to avoid many \typ{(char *)} manipulations when using strings. \item a search path package, which mimics and generalizes the \com{PATH} environment variable of {\it UNIX}. \item {\em smart pointers}. Smart pointers are more secure than usual pointers because they manage a reference count of the pointed to data. This makes it easy to manage shared data structures. \item a regular expression package, that encacpuslates the regular expressions from the C library. \end{itemize} \section{Using \utils} \utils\ is installed as: \begin{enumerate} \item the header file \com{ccu.h}, which contains the definitions for classes, functions and constants provided by \utils. \item the directory \com{ccu} contains headers \item \samepage {the archive file \com{libCcu.a}, which is usually instal\-led in \com{/usr/lib} or in \com{/usr/loc\-al/lib}, contains the library procedures. It must be loaded with the object files which use \utils. This is usually performed by adding the flag \com{-lCcu} in the command line for your C++ compiler. For instance, you can type~: \begin{center} \com{CC -o demo demo.C -lCcu} \end{center}} \end{enumerate} \chapter{Memory allocators} \label{Memory management} #class CcuAllocator #class CcuAllocatorOf \section{Allocating small objects} When creating an instance of a C++ class, some memory is allocated for the object, if it is not a static one. That memory is allocated with the allocation mechanism of C++, which one might want to override for small objects. The following fragment of code is an example of this operation for a class \typ{POINT}, using an allocator: \begin{ccode} typedef int COORD; class POINT { private : static CcuAllocator* PtAlloc; COORD X, Y; public : inline POINT (COORD, COORD) : X (x), Y (y) {} void* operator new (int); void operator delete (void*); }; CcuAllocator* POINT::PtAlloc = 0; void* POINT :: operator new (int) { /* Initialize the allocator for POINTs, if not done. */ if (!PtAlloc) PtAlloc = new CcuAllocator (sizeof (POINT)); return PtAlloc->Alloc (); } void POINT :: operator delete (void *that) { PtAlloc->Free (that); } \end{ccode} Note that we do not use the argument of \fun{operator new}, because our allocator always allocates chunks the size of a \typ{POINT}. This will cause severe problems when deriving a class from class \typ{POINT}, if you do not overload \fun{operator new} again. A more secure implementation would check the size argument against the size of chunks allocated by the allocator being used. \chapter{Dynamic arrays} #class CcuArray #class CcuArrayOf \chapter{Lists} In most languages, you often need to maintain dynamic sets of elements. Arrays provide a way to do this, but are inappropriate when these sets vary frequently and randomly, and especially when you need to insert new elements at any position. The classes \typ{CcuList} and \typ{CcuDList} are designed to manage such sets. \typ{CcuList} implements single linked lists, while \typ{CcuDList} implements double linked lists. Elements of a list can be enumerated by an iterator. During the enumeration, several operations can be performed on the current element of the list. Lists can store objects of different types since the entries of the list are of type \typ{void *}. However you should be careful when using such heterogeneous lists. \section {Simple lists} #iclass CcuList \subsection {Iterating through lists} #iclass CcuListIter \subsection{Generic versions} #iclass CcuListOf #iclass CcuListIterOf \section {Bidirectionnal lists} #iclass CcuDList \subsection {Iterating} #iclass CcuDListIter \subsection{Generic versions} #iclass CcuDListOf #iclass CcuDListIterOf \section {Example} The following example illustrates a common usage of lists. \begin{ccode} String a = "a"; String b = "b"; String c = "c"; ListOf l; l.Append (&b); l.Prepend (&a); l.Append (&c); ListIterOf li (l); while (++li) printf ("%s\n", *li); \end{ccode} \chapter{Hash Tables} The following definitions are used by member functions of the class \typ{CcuHashTable}, and by them only: \index{HASH_F}\index{HCP_F}\index{HCMP_F}\index{HENUM_F}\index{HDEL_F} \begin{ccode} typedef int (*HASH_F) (HashItem*, int); typedef pointer (*HCP_F) (HashItem*); typedef int (*HCMP_F) (HashItem*, HashItem*); typedef int (*HENUM_F) (HashCell*, HashItem*); typedef void (*HDEL_F) (HashCell*); \end{ccode} #iclass CcuHashTable #class CcuHashCell #class CcuDictionnary #class CcuHashIter \section{Example} This example is an interactive program to create and use a dictionnary. The keys are entered by the user, and the program assigns the information. \begin{ccode} main () { CcuDictionnary table (16); char line [256]; char *s; int num = 0; CcuHashCell *h; int found; table.Reset (); printf ("? to get help\n"); for (;;) { s = gets (line); if (! s) break; if (strcmp (s, ".") == 0) break; /* help */ if (strcmp (s, "?") == 0) { printf ("name add name\n"); printf ("-name delete name\n"); printf ("# dump table\n"); printf ("%% statistics\n"); printf ("> rehash into smaller\n"); printf ("< rehash into larger\n"); printf (". quit\n"); continue; } /* stats, dump */ if (strcmp (s, "%") == 0) { table.CollStats (1); continue; } if (strcmp (s, "#") == 0) { HashCell* ce; HashIter iter (table); while (++iter) { ce = *iter; printf ("%s\n", ce->GetKey()); } continue; } /* rehashing */ if (strcmp (s, ">") == 0) { int s; s = table.GetSize() / 2; if (s < 1) { printf ("too small\n"); continue; } printf ("rehashing into smaller table : size %d\n", s); table.SetSize (s); continue; } if (strcmp (s, "<") == 0) { int s; s = table.GetSize () * 2; printf ("rehashing into larger table : size %d\n", s); table.Resize (s); continue; } /* delete */ if (*s == '-') { void* p; p = table.Remove (++s); if (! p) printf ("%s not found \n", s); else printf ("%s had info %d\n", s, (int) p); continue; } /* add */ table [s] = (pointer) num++; // the info is a simple number } } \end{ccode} \chapter{Identifier tables} #iclass IdTable \chapter{Signal management} #class CcuSignalBlocker #class CcuBaseSignalHandler #class CcuSignalHandler \chapter{Time management} #class CcuTimeStamp #class CcuTime #class CcuBaseTimer #class CcuTimer \section{Example} This example creates three real time timers: the first one counts seconds, the second one counts minutes, and the third one counts three minutes once. The third timer stops the two other ones when it expires. In this example, the main program waits for the timer to expire. In most programs, the timers are used for background tasks, so that waiting for a timer is seldom used. Section \ref{Queues example} shows another example where a timer is used. \begin{ccode} void tick () { write (1, ".", 1); // write a dot each second } void ding () { write (1, "\n", 1); // change line each minute } void done () { printf ("\nDONE!!\n"); exit (1); } main () { CcuTimer seconds (1000, tick); CcuTimer minutes (60000, ding); CcuTimer eggs (done, 180000, 0); // wait for the eggs ... // usual programs do other things meanwhile } \end{ccode} \chapter{Search paths} #class CcuDirPath \section{Example} The following example looks for several files in a search path made of the user's binaries directory and its current path, with \com{/etc} excluded. This example illustrates the use of the allocation mode with respect to destroying the returned string. \begin{ccode} CcuDirPath path; path.Append ("."); path.AppendEnvPath (getenv ("PATH")); path.Remove ("/etc"); const char* file1 = path.Find ("my_file"); const char* file2 = path.Find ("other_file"); /* file1 now refers to garbage */ const char* file2 = path.Find ("other_file", TRUE); path.SetAlloc (1); char* file3 = path.Find ("my_file"); FreeString (file1); // crash ! FreeString (file2); // safe FreeString (file3); // safe (default allocation now TRUE) \end{ccode} \chapter{Smart pointers} The classes described here implement what we call smart pointers. Usual C++ pointers have two major flaws. The first one is that you can delete an object even if there are pointers to it: \begin{ccode} class A; A* p = new A; A* q = p; delete p; q->something(); // bug \end{ccode} Dereferencing such pointers will have unpredictable consequences. The second problem is the opposite: a dynamically allocated object can become unreachable and will never be destroyed, wasting memory space. \begin{ccode} class A; A* p = new A; p = 0; // original object now unreachable \end{ccode} Smart pointers eliminate both problems, but of course with some run-time overhead. #class CcuSmartData #class CcuSmartPointerTo \section{Example} This short example shows how to declare a class and a smart pointer class to it. It also illustrates how smart pointers and usual pointers can be mixed. \begin{ccode} class OBJ : public DATA { private: STRING name; public: OBJ () : name ("?") {} OBJ (char* n) : name (n) {} ~OBJ () { printf ("%s says bye\n", name ()); } void print (char* m) { printf ("%s: %s\n", m, name ()); } }; PointerClass (REFOBJ, OBJ); // this declares the smart pointer class OBJ* fun (OBJ* o) { o->print ("fun(o)"); return new OBJ ("fun"); } main () { REFOBJ ref1 = new OBJ ("foo"); REFOBJ ref2 = new OBJ ("bar"); REFOBJ ref3 = ref2; printf ("start\n"); ref1->print ("ref1"); ref2->print ("ref2"); ref3->print ("ref3"); printf ("\nref3 = ref1\n"); ref3 = ref1; ref1->print ("ref1"); ref2->print ("ref2"); ref3->print ("ref3"); printf ("\nref2 = ref1\n"); ref2 = ref1; ref1->print ("ref1"); ref2->print ("ref2"); ref3->print ("ref3"); printf ("\nref2 = fun (ref1)\n"); ref2 = fun (ref1); ref1->print ("ref1"); ref2->print ("ref2"); ref3->print ("ref3"); printf ("\nthe end\n"); } \end{ccode} This program produces the following (reformatted) output: \begin{ccode} start ref1: foo ref2: bar ref3: bar ref3 = ref1 ref1: foo ref2: bar ref3: foo ref2 = ref1 bar says bye ref1: foo ref2: foo ref3: foo ref2 = fun (ref1) fun(o): foo ref1: foo ref2: fun ref3: foo the end fun says bye foo says bye \end{ccode} \com{bar} has been deleted as soon as it has been unreachable. \com{fun} takes a pointer as argument and returns a pointer. However it is called with a smart pointer and its value is assigned to a smart pointer. Finally the two object \com{fun} and \com{foo} are deleted when returning from main. \chapter{Regular expressions} #class CcuRegExp \section{Example} This procedure matches a string against a regular expression. \begin{ccode} int match (const char* exp, const char* s) { CcuRegExp re (exp); if (!re.Compile ()) { printf ("Cannot compile expression \"%s\"", exp); return 0; } return re.Match (s); } \end{ccode} \newpage \appendix \chapter{Class List} This chapter contains the list of the classes defined in \utils. The first section contains the inheritance tree of \utils\ classes. The second section contains for each class the ordered list of its base classes. The section number indicated after each class refers to the documentation of that class. Classes defined in \utils\ but which are not documented do not appear in the lists. \section{Inheritance Tree} This section contains the set of classes defined in \utils. Each base class is followed by the indented list of its subclasses. \input{inhtree.tex} \newpage \section{Inheritance List} This section contains the set of classes defined in \utils. Each class is followed by its base class, recursively. Thus, from a given class, one can follow the inheritance link and thus refer to the documentation for the inherited methods. \begin{inhlist}{XXXXXXXXXXXXXXXX} \input{inhlist.tex} \end{inhlist} \begin{theindex} \indexinc \end{theindex} \end{document}