summaryrefslogtreecommitdiff
path: root/src/lib/libast/man/cdt.3
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libast/man/cdt.3')
-rw-r--r--src/lib/libast/man/cdt.3617
1 files changed, 617 insertions, 0 deletions
diff --git a/src/lib/libast/man/cdt.3 b/src/lib/libast/man/cdt.3
new file mode 100644
index 0000000..46bfe13
--- /dev/null
+++ b/src/lib/libast/man/cdt.3
@@ -0,0 +1,617 @@
+.fp 5 CW
+.TH LIBCDT 3
+.SH NAME
+\fBCdt\fR \- container data types
+.SH SYNOPSIS
+.de Tp
+.fl
+.ne 2
+.TP
+..
+.de Ss
+.fl
+.ne 2
+.SS "\\$1"
+..
+.de Cs
+.nf
+.ft 5
+..
+.de Ce
+.ft 1
+.fi
+..
+.ta 1.0i 2.0i 3.0i 4.0i 5.0i
+.Cs
+#include <cdt.h>
+.Ce
+.Ss "DICTIONARY TYPES"
+.Cs
+Void_t*;
+Dt_t;
+Dtdisc_t;
+Dtmethod_t;
+Dtlink_t;
+Dtstat_t;
+.Ce
+.Ss "DICTIONARY CONTROL"
+.Cs
+Dt_t* dtopen(const Dtdisc_t* disc, const Dtmethod_t* meth);
+int dtclose(Dt_t* dt);
+void dtclear(dt);
+Dtdisc_t* dtdisc(Dt_t* dt, const Dtdisc_t* disc, int type);
+Dtmethod_t* dtmethod(Dt_t* dt, const Dtmethod_t* meth);
+Dt_t* dtview(Dt_t* dt, Dt_t* view);
+int dtcustomize(Dt_t* dt, int type, Void_t* arg);
+int dtoptimize(Dt_t* dt);
+int dtshare(Dt_t* dt, int type);
+int dtlock(Dt_t* dt, unsigned int key, int type);
+.Ce
+.Ss "STORAGE METHODS"
+.Cs
+Dtmethod_t* Dtset;
+Dtmethod_t* Dtbag;
+Dtmethod_t* Dtrhset;
+Dtmethod_t* Dtrhbag;
+Dtmethod_t* Dtoset;
+Dtmethod_t* Dtobag;
+Dtmethod_t* Dtlist;
+Dtmethod_t* Dtstack;
+Dtmethod_t* Dtqueue;
+Dtmethod_t* Dtdeque;
+.Ce
+.Ss "DISCIPLINE"
+.Cs
+#define DTOFFSET(struct_s,member)
+#define DTDISC(disc,key,size,link,makef,freef,comparf,hashf,memoryf,eventf)
+typedef Void_t* (*Dtmake_f)(Dt_t*, Void_t*, Dtdisc_t*);
+typedef void (*Dtfree_f)(Dt_t*, Void_t*, Dtdisc_t*);
+typedef int (*Dtcompar_f)(Dt_t*, Void_t*, Void_t*, Dtdisc_t*);
+typedef unsigned int (*Dthash_f)(Dt_t*, Void_t*, Dtdisc_t*);
+typedef Void_t* (*Dtmemory_f)(Dt_t*, Void_t*, size_t, Dtdisc_t*);
+typedef int (*Dtevent_f)(Dt_t*, int, Void_t*, Dtdisc_t*);
+.Ce
+.Ss "OBJECT OPERATIONS"
+.Cs
+Void_t* dtinsert(Dt_t* dt, Void_t* obj);
+Void_t* dtappend(Dt_t* dt, Void_t* obj);
+Void_t* dtdelete(Dt_t* dt, Void_t* obj);
+Void_t* dtattach(Dt_t* dt, Void_t* obj);
+Void_t* dtdetach(Dt_t* dt, Void_t* obj);
+Void_t* dtsearch(Dt_t* dt, Void_t* obj);
+Void_t* dtmatch(Dt_t* dt, Void_t* key);
+Void_t* dtfirst(Dt_t* dt);
+Void_t* dtnext(Dt_t* dt, Void_t* obj);
+Void_t* dtlast(Dt_t* dt);
+Void_t* dtprev(Dt_t* dt, Void_t* obj);
+Void_t* dtleast(Dt_t* dt, Void_t* obj);
+Void_t* dtmost(Dt_t* dt, Void_t* obj);
+int dtwalk(Dt_t* dt, int (*userf)(Dt_t*, Void_t*, Void_t*), Void_t*);
+Dtlink_t* dtflatten(Dt_t* dt);
+Dtlink_t* dtlink(Dt_t* dt, Dtlink_t* link);
+Void_t* dtobj(Dt_t* dt, Dtlink_t* link);
+Dtlink_t* dtextract(Dt_t* dt);
+Dtlink_t* dtrestore(Dt_t* dt, Dtlink_t* link);
+.Ce
+.Ss "DICTIONARY STATUS"
+.Cs
+Dt_t* dtvnext(Dt_t* dt);
+ssize_t dtvcount(Dt_t* dt);
+Dt_t* dtvhere(Dt_t* dt);
+ssize_t dtsize(Dt_t* dt);
+ssize_t dtstat(Dt_t* dt, Dtstat_t* st);
+.Ce
+.Ss "HASH FUNCTIONS"
+.Cs
+unsigned int dtstrhash(unsigned int h, char* str, int n);
+unsigned int dtcharhash(unsigned int h, unsigned char c);
+.Ce
+.SH DESCRIPTION
+.PP
+\fICdt\fP manages run-time dictionaries using standard container data types:
+unordered set/multiset, ordered set/multiset, list, stack, and queue.
+.PP
+.Ss "DICTIONARY TYPES"
+.PP
+.Ss " Void_t*"
+This type is used to pass objects between \fICdt\fP and application code.
+\f5Void_t\fP is defined as \f5void\fP for ANSI-C and C++
+and \f5char\fP for older C compilation environments.
+.PP
+.Ss " Dt_t"
+This is the type of a dictionary handle.
+.PP
+.Ss " Dtdisc_t"
+This defines the type of a discipline structure which define the lay-out of
+an object and functions to compare, hash, make, delete objects, etc. (see \f5dtdisc()\fP).
+.PP
+.Ss " Dtmethod_t"
+This defines the type of a container method.
+.PP
+.Ss " Dtlink_t"
+This is the type of a dictionary object holder (see \f5dtdisc()\fP.)
+.PP
+.Ss " Dtstat_t"
+This is the type of a structure to return dictionary statistics (see \f5dtstat()\fP.)
+.PP
+.Ss "DICTIONARY CONTROL"
+.PP
+.Ss " Dt_t* dtopen(const Dtdisc_t* disc, const Dtmethod_t* meth)"
+This creates a new dictionary.
+\f5disc\fP is a discipline structure to describe object format.
+\f5meth\fP specifies a manipulation method.
+\f5dtopen()\fP returns the new dictionary or \f5NULL\fP on error.
+See also the events \f5DT_OPEN\fP and \f5DT_ENDOPEN\fP below.
+.PP
+.Ss " int dtclose(Dt_t* dt)"
+This deletes \f5dt\fP and its objects.
+Note that \f5dtclose()\fP fails if \f5dt\fP is being viewed by
+some other dictionaries (see \f5dtview()\fP).
+\f5dtclose()\fP returns \f50\fP on success and \f5-1\fP on error.
+See also the events \f5DT_CLOSE\fP and \f5DT_ENDCLOSE\fP below.
+.PP
+.Ss " void dtclear(Dt_t* dt)"
+This deletes all objects in \f5dt\fP without closing \f5dt\fP.
+.PP
+.Ss " Dtdisc_t* dtdisc(Dt_t* dt, const Dtdisc_t* disc, int type)"
+If \f5disc\fP is \f5NULL\fP, \f5dtdisc()\fP returns the current discipline.
+Otherwise, it changes the discipline of \f5dt\fP to \f5disc\fP.
+Objects may be rehashed, reordered, or removed as appropriate.
+\f5type\fP can be any bit combination of \f5DT_SAMECMP\fP and \f5DT_SAMEHASH\fP.
+\f5DT_SAMECMP\fP means that objects will compare exactly the same as before
+thus obviating the need for reordering or removing new duplicates.
+\f5DT_SAMEHASH\fP means that hash values of objects remain the same
+thus obviating the need to rehash.
+\f5dtdisc()\fP returns the previous discipline on success
+and \f5NULL\fP on error.
+.PP
+.Ss " Dtmethod_t dtmethod(Dt_t* dt, const Dtmethod_t* meth)"
+If \f5meth\fP is \f5NULL\fP, \f5dtmethod()\fP returns the current method.
+Otherwise, it changes the storage method of \f5dt\fP to \f5meth\fP.
+Objects may be rehashed, reordered, or removed as appropriate.
+\f5dtmethod()\fP returns the previous method or \f5NULL\fP on error.
+.PP
+.Ss " Dt_t* dtview(Dt_t* dt, Dt_t* view)"
+A viewpath allows a search or walk starting from a dictionary to continue to another.
+\f5dtview()\fP first terminates any current view from \f5dt\fP to another dictionary.
+Then, if \f5view\fP is \f5NULL\fP, \f5dtview\fP returns the terminated view dictionary.
+If \f5view\fP is not \f5NULL\fP, a viewpath from \f5dt\fP to \f5view\fP is established.
+\f5dtview()\fP returns \f5dt\fP on success and \f5NULL\fP on error.
+.PP
+It is an error to have dictionaries on a viewpath with different storage methods.
+In addition, dictionaries on the same view path should
+treat objects in a consistent manner with respect to comparison or hashing.
+If not, undefined behaviors may result.
+.PP
+.Ss " int dtcustomize(Dt_t* dt, int type, Void_t* arg)"
+This customizes a storage method. The \f5type\fP argument
+indicates the type of customization and \f5arg\fP gives additional
+information for the operation. Here are the types:
+.Tp
+\f5DT_SHARE\fP:
+This turns on/off the share mode for a dictionary.
+Concurrent accesses of a dictionary not in share mode
+may exhibit undefined behaviors including memory segmentation.
+
+Share mode allows multiple accessors, threads or processes, to access objects.
+Such objects could be in the same directory in the case of threads or shared
+memory in the case of processes.
+.Tp
+\f5DT_OPTIMIZE\fP:
+This causes the underlying method to optimize its internal
+data structure. For example, the splay tree underlying \f5Dtoset\fP
+would be balanced.
+.PP
+.Ss " int dtoptimize(Dt_t* dt)"
+This is a short-hand for invoking \f5dtcustomize()\fP with the \f5DT_OPTIMIZE\fP event.
+.PP
+.Ss " int dtshare(Dt_t* dt, int type)"
+This turns on or off share mode for dictionary \f5dt\fP depending on whether \f5type\fP
+is positive or non-positive. It returns -1 on failure.
+.PP
+.Ss " int dtlock(Dt_t* dt, unsigned int key, int type)"
+This globally locks/unlocks a dictionary using the given \f5key\fP.
+It returns 0 on success and -1 on failure.
+The value of \f5key\fP must not be 0.
+The argument \f5type\fP is used as follows:
+.Tp
+\f5type < 0\fP:
+Unlock the dictionary if it was locked with \f5key\fP.
+An error will result if the dictionary was locked with a different key.
+.Tp
+\f5type == 0\fP:
+Attempt to lock the dictionary with \f5key\fP if it is unlocked.
+An error will result if the dictionary was already locked with a different key.
+.Tp
+\f5type > 0\fP:
+Attempt to lock the dictionary with \f5key\fP.
+If the dictionary is already locked with a different key,
+the call will loop and wait until the lock is open to lock it.
+
+.PP
+.Ss "STORAGE METHODS"
+.PP
+Storage methods are of type \f5Dtmethod_t*\fP.
+\fICdt\fP supports the following methods:
+.PP
+.Ss " Dtoset"
+.Ss " Dtobag"
+Objects are ordered by comparisons.
+\f5Dtoset\fP keeps unique objects.
+\f5Dtobag\fP allows repeatable objects.
+.PP
+.Ss " Dtset"
+.Ss " Dtbag"
+Objects are unordered.
+\f5Dtset\fP keeps unique objects.
+\f5Dtbag\fP allows repeatable objects.
+The underlying data structure is a hash table with chaining to handle collisions.
+.PP
+.Ss " Dtrhset"
+.Ss " Dtrhbag"
+These methods are like \f5Dtset\fP and \f5Dtbag\fP but are based on
+a recursive hashing data structure that allows table extension without
+object relocation. The data structure also supports lock-free
+concurrent search operations for share dictionaries.
+.PP
+.Ss " Dtlist"
+Objects are kept in a list.
+\fIA current object\fP is always defined to be either the head of
+the list or an object resulting from a recent search or insert operation.
+The call \f5dtinsert()\fP will insert a new object
+in front of such a current object
+while the call \f5dtappend()\fP will append in back of it.
+.PP
+.Ss " Dtdeque"
+Objects are kept in a deque. This is similar to \f5Dtlist\fP
+except that objects are always inserted at the front and appended at the tail
+of the list.
+.PP
+.Ss " Dtstack"
+Objects are kept in a stack, i.e., in reverse order of insertion.
+Thus, the last object inserted is at stack top
+and will be the first to be deleted.
+.PP
+.Ss " Dtqueue"
+Objects are kept in a queue, i.e., in order of insertion.
+Thus, the first object inserted is at queue head
+and will be the first to be deleted.
+.PP
+.Ss "DISCIPLINE"
+.PP
+Object format and associated management functions are
+defined in the type \f5Dtdisc_t\fP:
+.Cs
+ typedef struct
+ { ssize_t key, size;
+ ssize_t link;
+ Dtmake_f makef;
+ Dtfree_f freef;
+ Dtcompar_f comparf;
+ Dthash_f hashf;
+ Dtmemory_f memoryf;
+ Dtevent_f eventf;
+ } Dtdisc_t;
+.Ce
+.Ss " ssize_t key, size"
+Each object \f5obj\fP is identified by a key used for object comparison or hashing.
+\f5key\fP should be non-negative and defines an offset into \f5obj\fP.
+If \f5size\fP is negative, the key is a null-terminated
+string with starting address \f5*(Void_t**)((char*)obj+key)\fP.
+If \f5size\fP is zero, the key is a null-terminated string with starting address
+\f5(Void_t*)((char*)obj+key)\fP.
+Finally, if \f5size\fP is positive, the key is a byte array of length \f5size\fP
+starting at \f5(Void_t*)((char*)obj+key)\fP.
+.PP
+.Ss " ssize_t link"
+Let \f5obj\fP be an object to be inserted into \f5dt\fP.
+If \f5link\fP is negative, an object holder of type \f5Dtlink_t\fP
+will be allocated to hold \f5obj\fP.
+Otherwise, \f5obj\fP should have
+a \f5Dtlink_t\fP structure embedded \f5link\fP bytes into it,
+i.e., at address \f5(Dtlink_t*)((char*)obj+link)\fP.
+.PP
+.Ss " Void_t* (*makef)(Dt_t* dt, Void_t* obj, Dtdisc_t* disc)"
+If \f5makef\fP is not \f5NULL\fP,
+\f5dtinsert(dt,obj)\fP or \f5dtappend()\fP will call it
+to make a copy of \f5obj\fP suitable for insertion into \f5dt\fP.
+If \f5makef\fP is \f5NULL\fP, \f5obj\fP itself will be inserted into \f5dt\fP.
+.PP
+.Ss " void (*freef)(Dt_t* dt, Void_t* obj, Dtdisc_t* disc)"
+If not \f5NULL\fP,
+\f5freef\fP is used to destroy data associated with \f5obj\fP.
+.PP
+.Ss "int (*comparf)(Dt_t* dt, Void_t* key1, Void_t* key2, Dtdisc_t* disc)"
+If not \f5NULL\fP, \f5comparf\fP is used to compare two keys.
+Its return value should be \f5<0\fP, \f5=0\fP, or \f5>0\fP to indicate
+whether \f5key1\fP is smaller, equal to, or larger than \f5key2\fP.
+All three values are significant for method \f5Dtoset\fP and \f5Dtobag\fP.
+For other methods, a zero value
+indicates equality and a non-zero value indicates inequality.
+If \f5(*comparf)()\fP is \f5NULL\fP, an internal function is used
+to compare the keys as defined by the \f5Dtdisc_t.size\fP field.
+.PP
+.Ss " unsigned int (*hashf)(Dt_t* dt, Void_t* key, Dtdisc_t* disc)"
+If not \f5NULL\fP,
+\f5hashf\fP is used to compute the hash value of \f5key\fP.
+It is required that keys compared equal will also have same hash values.
+If \f5hashf\fP is \f5NULL\fP, an internal function is used to hash
+the key as defined by the \f5Dtdisc_t.size\fP field.
+.PP
+.Ss " Void_t* (*memoryf)(Dt_t* dt, Void_t* addr, size_t size, Dtdisc_t* disc)"
+If not \f5NULL\fP, \f5memoryf\fP is used to allocate and free memory.
+When \f5addr\fP is \f5NULL\fP, a memory segment of size \f5size\fP is requested.
+If \f5addr\fP is not \f5NULL\fP and \f5size\fP is zero, \f5addr\fP is to be freed.
+If \f5addr\fP is not \f5NULL\fP and \f5size\fP is positive,
+\f5addr\fP is to be resized to the given size.
+If \f5memoryf\fP is \f5NULL\fP, \fImalloc(3)\fP is used.
+.PP
+.Ss " int (*eventf)(Dt_t* dt, int type, Void_t* data, Dtdisc_t* disc)"
+If not \f5NULL\fP, \f5eventf\fP announces various events.
+Each event may have particular handling of the return values from \f5eventf\fP.
+But a negative return value typically means failure.
+Following are the events:
+.Tp
+\f5DT_OPEN\fP:
+This event is raised at the start of the process to open a new dictionary.
+The argument \f5data\fP will be a pointer to an object of type \f5Void_t*\fP
+initialized to \f5NULL\fP before the call. The return value of \f5eventf()\fP
+is significant as follows:
+
+On a negative return value, \f5dtopen()\fP will return failure.
+
+On a zero return value, \f5eventf()\fP may set \f5*(Void_t**)data\fP to some non-\f5NULL\fP
+value to indicate that the dictionary structure itself should be allocated
+along with the \f5Dtdisc_t.data\fP section.
+Otherwise, it will be allocated separately with \f5malloc(3)\fP.
+
+On a positive return value, the dictionary is being reconstructed
+based on existing states of some previous dictionary.
+In this case, \f5eventf()\fP should set \f5*(Void_t**)data\fP to point to
+the field \f5Dt_t.data\fP of the corresponding previous dictionary (see \f5DT_CLOSE\fP below).
+If the handle of the previous dictionary was created as discussed above
+in the case of the zero return value, it will be exactly restored.
+Otherwise, a new handle will be allocated with \f5malloc()\fP.
+The ability to create different dictionaries sharing the same set of objects
+allows for managing objects in shared and/or persistent memory.
+.Tp
+\f5DT_ENDOPEN\fP:
+This event is raised at the end of the process to open a dictionary.
+The return value of \f5eventf()\fP will be ignored.
+.Tp
+\f5DT_CLOSE\fP:
+This event is raised at the start of the process to close dictionary \f5dt\fP.
+The return value of \f5eventf\fP is significant as follows:
+
+On a negative return value, \f5dtclose()\fP will return failure.
+
+On a zero return value, all dictionary objects will be deleted and
+and all associated memory will be freed.
+
+On a positive return value, allocated objects and memory will be kept intact.
+This means that \f5dt->data\fP remains intact and can be reused in some future
+dictionary (see \f5DT_OPEN\fP above).
+Note, however, that \f5dt\fP itself would still be freed if it was allocated with \f5malloc(3)\fP.
+.Tp
+\f5DT_ENDCLOSE\fP:
+This event is raised at the end of the process to close a dictionary.
+The return value of \f5eventf()\fP will be ignored.
+.Tp
+\f5DT_DISC\fP:
+The discipline of \f5dt\fP is being changed to a new one given in
+\f5(Dtdisc_t*)data\fP.
+.Tp
+\f5DT_METH\fP:
+The method of \f5dt\fP is being changed to a new one given in
+\f5(Dtmethod_t*)data\fP.
+.Tp
+\f5DT_HASHSIZE\fP:
+This event is applicable to
+the methods \f5Dtset\fP, \f5Dtbag\fP, \f5Dtrhset\fP and \f5Dtrhbag\fP.
+It is typically issued when the respective internal data structure of
+a method is about to be initialized.
+If the return value of the event handling function is positive,
+\f5*(ssize_t*)data\fP is examined for further action;
+else, it is ignored.
+A positive return value means that the event function wishes to suggest a table size.
+It does that by setting \f5*(ssize_t*)data\fP to the desired size.
+Then, the actual table size will be the maximum of the absolute value
+of \f5*(ssize_t*)data\fP and some predefined value set by the method.
+In addition, if \f5*(ssize_t*)data\fP was negative,
+the \f5Dtset\fP and \f5Dtbag\fP methods will never resize the hash table.
+.Tp
+\f5DT_ERROR\fP:
+This event announces an error that occurred during some operations.
+The argument \f5(char*)data\fP is a null-terminated string describing the error.
+.PP
+.Ss "#define DTOFFSET(struct_s,member)"
+This macro function computes the offset of \f5member\fP from the start
+of structure \f5struct_s\fP. It is useful for getting the offset of
+a \f5Dtlink_t\fP embedded inside an object.
+.PP
+.Ss "#define DTDISC(disc,key,size,link,makef,freef,comparf,hashf,memoryf,eventf)"
+This macro function initializes the discipline pointed to by \f5disc\fP
+with the given values.
+.PP
+.Ss "OBJECT OPERATIONS"
+.PP
+.Ss " Void_t* dtinsert(Dt_t* dt, Void_t* obj)"
+.Ss " Void_t* dtappend(Dt_t* dt, Void_t* obj)"
+These functions add an object prototyped by \f5obj\fP into \f5dt\fP.
+\f5dtinsert()\fP and \f5dtappend()\fP perform the same function
+for all methods except for \f5Dtlist\fP (see \f5Dtlist\fP for details).
+If there is an existing object in \f5dt\fP matching \f5obj\fP
+and the storage method is \f5Dtset\fP, \f5Dtrhset\fP or \f5Dtoset\fP,
+\f5dtinsert()\fP and \f5dtappend()\fP will simply return the matching object.
+Otherwise, a new object is inserted according to the method in use.
+See \f5Dtdisc_t.makef\fP for object construction.
+The new object or a matching object as noted will be returned on success
+while \f5NULL\fP is returned on error.
+.PP
+.Ss " Void_t* dtdelete(Dt_t* dt, Void_t* obj)"
+If \f5obj\fP is \f5NULL\fP, methods \f5Dtstack\fP and \f5Dtqueue\fP
+delete respectively stack top or queue head while other methods do nothing.
+If \f5obj\fP is not \f5NULL\fP, an object matching \f5obj\fP is deleted.
+See \f5Dtdisc_t.freef\fP for object destruction.
+\f5dtdelete()\fP returns the deleted object (even if it was deallocated)
+or \f5NULL\fP on error.
+.PP
+.Ss " Void_t* dtattach(Dt_t* dt, Void_t* obj)"
+This function is similar to \f5dtinsert()\fP but \f5obj\fP itself
+will be inserted into \f5dt\fP even if a discipline
+function \f5makef\fP is defined.
+.PP
+.Ss " Void_t* dtdetach(Dt_t* dt, Void_t* obj)"
+This function is similar to \f5dtdelete()\fP but the object to be deleted
+from \f5dt\fP will not be freed (via the discipline \f5freef\fP function).
+.PP
+.Ss " Void_t* dtsearch(Dt_t* dt, Void_t* obj)"
+.Ss " Void_t* dtmatch(Dt_t* dt, Void_t* key)"
+These functions find an object matching \f5obj\fP or \f5key\fP either from \f5dt\fP or
+from some dictionary accessible from \f5dt\fP via a viewpath (see \f5dtview()\fP.)
+\f5dtsearch()\fP and \f5dtmatch()\fP return the matching object or
+\f5NULL\fP on failure.
+.PP
+.Ss " Void_t* dtfirst(Dt_t* dt)"
+.Ss " Void_t* dtnext(Dt_t* dt, Void_t* obj)"
+\f5dtfirst()\fP returns the first object in \f5dt\fP.
+\f5dtnext()\fP returns the object that follows an object matching \f5obj\fP.
+Objects are ordered based on the storage method in use.
+For \f5Dtoset\fP and \f5Dtobag\fP, objects are ordered by object comparisons.
+For \f5Dtstack\fP, objects are ordered in reverse order of insertion.
+For \f5Dtqueue\fP, objects are ordered in order of insertion.
+For \f5Dtlist\fP, objects are ordered by list position.
+For \f5Dtset\fP, \f5Dtbag\fP, \f5Dtrhset\fP and \f5Dtrhbag\fP,
+objects are ordered by some internal order defined at the time when these
+functions are called.
+
+Objects in a dictionary or a viewpath can be walked using
+a \f5for(;;)\fP loop as below.
+.Cs
+ for(obj = dtfirst(dt); obj; obj = dtnext(dt,obj))
+.Ce
+.PP
+.Ss " Void_t* dtlast(Dt_t* dt)"
+.Ss " Void_t* dtprev(Dt_t* dt, Void_t* obj)"
+\f5dtlast()\fP and \f5dtprev()\fP are like \f5dtfirst()\fP and \f5dtnext()\fP
+but work in reverse order.
+For \f5Dtset\fP, \f5Dtbag\fP, \f5Dtrhset\fP and \f5Dtrhbag\fP,
+both reverse and forward orders are the same.
+Note that dictionaries on a viewpath are still walked in the order
+of the viewpath.
+.PP
+.Ss " Void_t* dtleast(Dt_t* dt, Void_t* obj)"
+.Ss " Void_t* dtmost(Dt_t* dt, Void_t* obj)"
+\f5dtleast()\fP returns the smallest object greater or equal to \f5obj\fP.
+\f5dtmost()\fP returns the largest object smaller or equal to \f5obj\fP.
+Again, object ordering depends on the storage method in use.
+For example, with \f5Dtoset\fP and \f5Dtobag\fP, the ordering of objects
+is well-defined and it is possible to call \f5dtleast()\fP or \f5dtmost()\fP
+on an object not in the dictionary and still get a meaningful result.
+On the other hand, with \f5Dtset\fP or \f5Dtrhset\fP, such a call will
+essentially be the same as \f5dtsearch()\fP because without matching
+an object, it cannot be determined what comes before or after.
+.PP
+.Ss " dtwalk(Dt_t* dt, int (*userf)(Dt_t*, Void_t*, Void_t*), Void_t* data)"
+This function calls \f5(*userf)(walk,obj,data)\fP on each object in \f5dt\fP and
+other dictionaries viewable from it.
+\f5walk\fP is the dictionary containing \f5obj\fP.
+If \f5userf()\fP returns a \f5<0\fP value,
+\f5dtwalk()\fP terminates and returns the same value.
+\f5dtwalk()\fP returns \f50\fP on completion.
+.PP
+.Ss " Dtlink_t* dtflatten(Dt_t* dt)"
+.Ss " Dtlink_t* dtlink(Dt_t* dt, Dtlink_t* link)"
+.Ss " Void_t* dtobj(Dt_t* dt, Dtlink_t* link)"
+Using \f5dtfirst()/dtnext()\fP or \f5dtlast()/dtprev()\fP
+to walk a single dictionary can incur significant cost due to function calls.
+For efficient walking of a single directory (i.e., no viewpathing),
+\f5dtflatten()\fP and \f5dtlink()\fP can be used.
+Objects in \f5dt\fP are made into a linked list and walked as follows:
+.Cs
+ for(link = dtflatten(dt); link; link = dtlink(dt,link) )
+.Ce
+.PP
+Note that \f5dtflatten()\fP returns a list of type \f5Dtlink_t*\fP,
+not \f5Void_t*\fP. That is, it returns a dictionary holder pointer,
+not a user object pointer
+(although both are the same if the discipline field \f5link\fP is zero.)
+The macro function \f5dtlink()\fP
+returns the dictionary holder object following \f5link\fP.
+The macro function \f5dtobj(dt,link)\fP
+returns the user object associated with \f5link\fP,
+Beware that the flattened object list is unflattened on any
+dictionary operations other than \f5dtlink()\fP.
+.PP
+.Ss " Dtlink_t* dtextract(Dt_t* dt)"
+.Ss " Dtlink_t* dtrestore(Dt_t* dt, Dtlink_t* list)"
+\f5dtextract()\fP extracts the list of objects from \f5dt\fP and makes it appear empty.
+\f5dtrestore()\fP repopulates \f5dt\fP with
+a list of objects previously obtained via \f5dtextract()\fP.
+It is important that the same discipline and method are in use at both
+extraction and restoration. Otherwise, undefined behaviors may result.
+These functions return \f5NULL\fP on error.
+
+.PP
+.Ss "DICTIONARY INFORMATION"
+.PP
+.Ss " Dt_t* dtvnext(Dt_t* dt)"
+This returns the dictionary that \f5dt\fP is viewing, if any.
+.Ss " ssize_t dtvcount(Dt_t* dt)"
+This returns the number of dictionaries that view \f5dt\fP.
+.Ss " Dt_t* dtvhere(Dt_t* dt)"
+This returns the dictionary \f5v\fP viewable from \f5dt\fP
+where an object was found from the most recent search or walk operation.
+.Ss " ssize_t dtsize(Dt_t* dt)"
+This function returns the number of objects stored in \f5dt\fP.
+.PP
+.Ss " ssize_t dtstat(Dt_t *dt, Dtstat_t* st)"
+This function reports dictionary statistics.
+It returns the number of objects stored in \f5dt\fP.
+.PP
+\f5Dtstat_t\fP contains the below fields:
+.Tp
+\f5int meth\fP:
+This returns the method used for the dictionary, e.g., \f5DT_SET\fP, \f5DT_OSET\fP, etc.
+.Tp
+\f5ssize_t size\fP:
+This has the number of objects in the dictionary.
+.Tp
+\f5ssize_t mlev\fP:
+This returns the maximum number of levels in the data structure used for object storage, i.e.,
+the binary tree or the recursive hash table.
+For a hash table with chaining (i.e., \f5Dtset\fP and \f5Dtbag\fP),
+it gives the length of the longest chain.
+.Tp
+\f5ssize_t lsize[]\fP:
+This gives the object counts at each level.
+For a hash table with chaining (i.e., \f5Dtset\fP and \f5Dtbag\fP),
+a level is defined as objects at that position in their chains.
+Since chains can be arbitrarily long, the report is limited
+to objects at a level less than \f5DT_MAXSIZE\fP.
+.Tp
+\f5ssize_t tsize[]\fP:
+For a hash table using a trie structure, this counts the number of
+sub-tables at each level. For example, \f5tsize[0]\fP should be 1
+only for this hash table type.
+.PP
+.Ss "HASH FUNCTIONS"
+.PP
+.Ss " unsigned int dtcharhash(unsigned int h, char c)"
+.Ss " unsigned int dtstrhash(unsigned int h, char* str, int n)"
+These functions compute hash values from bytes or strings.
+\f5dtcharhash()\fP computes a new hash value from byte \f5c\fP and seed value \f5h\fP.
+\f5dtstrhash()\fP computes a new hash value from string \f5str\fP and seed value \f5h\fP.
+If \f5n\fP is positive, \f5str\fP is a byte array of length \f5n\fP;
+otherwise, \f5str\fP is a null-terminated string.
+.PP
+.SH IMPLEMENTATION NOTES
+\f5Dtlist\fP, \f5Dtstack\fP and \f5Dtqueue\fP are based on doubly linked list.
+\f5Dtoset\fP and \f5Dtobag\fP are based on top-down splay trees.
+\f5Dtset\fP and \f5Dtbag\fP are based on hash tables with
+move-to-front collision chains.
+\f5Dtrhset\fP and \f5Dtrhbag\fP are based on a recursive hashing data structure
+that avoids table resizing.
+.PP
+.SH AUTHOR
+Kiem-Phong Vo, kpv@research.att.com