/* * 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 * * $Id$ * $CurLog$ */ \documentstyle[11pt,mydoc,twoside]{doc} \pagestyle{ENTETE} \makeindex \def\utils{CCU} \namedoc{CENA C++ Utilities} \begin{document} \maketitle \cleardoublepage \tableofcontents \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 linked lists, 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 hash tables. 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 handling 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 a regular expression package, that encacpuslates the regular expressions from the C library. \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. \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}, which contains headers for the different packages of CCU. \item \samepage {the archive file \com{libCcu.a}, which is usually instal\-led 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, dynamic sets of elements are often needed. Arrays provide a way to do this, but are inappropriate when these sets vary frequently and randomly, and especially when new elements have to be inserted 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. The classes \typ{CcuListIter} and \typ{CcuDListIter} provide such iterators. 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} #iclass CcuHashTable #iclass CcuHashCell \section{Iterating on hash tables} #iclass CcuHashCellIter #iclass CcuHashIter \section{Strings as keys: dictionnaries} #iclass CcuDictionnary \section{Generic classes} #iclass CcuHashTableOf #iclass CcuHashCellOf #iclass CcuHashCellIterOf #iclass CcuHashIterOf #iclass CcuDictionnaryOf \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 CcuIdTable #iclass CcuIdIter \chapter{Signal management} #class CcuSignalBlocker #class CcuBaseSignalHandler #class CcuSignalHandler \chapter{Time management} \section{Measuring time} \utils\ provides two classes for measuring time. The class \typ{CcuTimeStamp} provides a mean of dating events with reference to an absolute clock (the standard dating scheme of Unix), whereas the class \typ{CcuTime} makes it possible to measure time intervals. #iclass CcuTimeStamp #iclass CcuTime \section{Timers} #iclass CcuCoreTimer \subsection{Signal-based timers} #iclass CcuBaseTimer #iclass CcuTimer \subsection{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. 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 for (;;) pause (); } \end{ccode} \subsection{Deriving new kinds of timers} If you have another source of interruptions than signals and you want to map timers on it, you will need to derive a new class from \typ{CcuCoreTimer}. The derived class must implement the functions \fun{StartAlarm} and \fun{StopAlarm}. Its constructor must also provide a timer set to the constructor of \typ{CcuCoreTimer}. This timer set will hold all the timers of the new class. It will belong to the class \typ{CcuTimerSet}. #iclass CcuTimerSet \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{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} \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. \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}