Source code for software projects:
Building Blocks Library (in C++)
The Building Blocks library is a general-purpose library written in C++ that provides a cross-platform layer for things like memory allocation, threading, synchronization, and asynchronous I/O.
You can also download the entire source code directory as a Tar file buildingBlocks.tar
- Makefiles buildingBlocksWin32.mak buildingBlocksLinux.mak makeFileCommonWin32.mak
Makefiles for the building blocks library. The building blocks library is packaged as a static library that may be linked into higher level programs statically at compile time. The file makeFileCommonWin32.mak is some common makefile rules used by all of my software projects.
- BuildingBlocks Manager buildingBlocksManager.cpp buildingBlocks.h buildNumber.h
The top level for initializing and shutting down the building blocks library.
- Serialized Object Base Class serializedObject.h serializedObject.cpp
This is a base class, and objects that inherit from this class can implement a single method (sort of like a RPC serializer function) that will serialize or deserialize the runtime state of the object. This overloaded method simply contains macros for each member variable of the object. Clients of the object, can call base class methods to serialize or deserialize an object from files like XML or streams like HTTP.
- PolyXMLDoc polyXMLDoc.h polyXMLDoc.cpp
polyXMLDocText.cpp
This is a very simple abstract interface for manipulating XML and HTML documents. The abstract interface can be implemented by native XML packages like libxml2 and more. Currently, there is a simple native implementation that is handy if external libraries are not loaded.
- PolyHTTP polyHTTPStream.h polyHTTPStream.cpp This is a very simple abstract interface for manipulating HTTP streams. The abstract interface can be implemented by native http packages like winhttp and more.
polyHTTPStreamBasic.cpp
This is the simple native implementation of the abstract base class that is handy if external libraries are not loaded
- AsyncIOStream asyncIOStream.cpp asyncIOStream.h
This implements an asynchronous stream interface on top of block IO devices like files, networks, and memory regions. It provides asynchronous reads and writes that invoke callback procedures when the operation completes. It also presents the data as a continuous stream of bytes, so it hides packet and block boundaries.
- BlockIO blockIO.cpp blockIO.h
fileBlockIO.cpp
netBlockIO.cpp
memoryBlockIO.cpp
This module implements an asynchronous block-device interface. It encapsulates both OS-dependencies and the differences between files, networks, and memory storage. Different subclasses implement each particular I/O system. The interface is used to implement the AsyncIOStream class above.
- URL url.cpp url.h
This defines an object that parses and formats URLs.
- Name Table nameTable.h nameTable.cpp
The module implements name binding, which maps string names to pointer values. The pointer may refer to an arbitrary data structure. A name table is implemented with a hash table, where each hash bucket is a balanced red-black tree of entries. This is also used to implement an expandable dictionary of strings, that dynamically builds lists of words such as element names during XML parsing.
- Red-Black Balanced Tree rbTree.cpp rbTree.h
The module implements a binary tree of named entries as balanced red-black tree, and the basic algorighm is adapted from "Introduction to Algorithms", by Cormen, Leiserson, and Rivest.
- StringParse stringParse.cpp stringParse.h
This module defines a parser object that parses strings using a grammar definition. The grammar syntax is based on the IETF Augmented BNF used in RFCs and W3C specs.
- Job Queues jobQueue.h jobQueue.cpp
This implements a job queue, which contains a pool of threads and a list of jobs. At any moment, there may be threads waiting on jobs, or jobs waiting on threads. A single job may be resubmitted many times, and the job is maintained in a higher level in the code. For example, the blockIO module uses jobs for pending block IO reads and writes. The higher level code will also decide when to delete a job. This is built on top of the basic thread module, which encapsulates different thread libraries on different operating systems.There are three classes that make up this abstraction:
- CJobQueue - A queue of jobs
- CJob - A single job
- CWorkerThread - A single worker thread
The job class is a pure virtual class; clients will define subclasses that contain information specific to a type of job. Each job contains a run method, which actually does the work of the job. A single job may have several pending requests. New requests may be submitted when the job is idle, or busy, including submitting requests as part of finishing a previous request. Any particular job may only be on ONE job queue at a time. There is support for multiple requests on a job within one job queue, but NO support for coordination between job queues.
- Queues queue.h queue.cpp
This implements a base class for any object that may be placed on a queue. Objects do not typically subclass CQueueHook because a single object may be on several different queues at the same time. Instead, objects contains instance variables for the "coat hanger" for each different type of queue. I could instead implement a queue as a list of pointers, like STL vectors, but then that requires allocating memory blocks for the pointer lists, which I try to avoid. There are no locks around queues, since that is wasteful when it is not needed. If a queue must be lock-protected, then the higher level module must also include a lock.
- Threads threads.cpp threads.h
This wraps the basic mechanisms of a threading library: threads, locks, semaphores. They are all in one module because they are usually implemented as a single package (like pthreads) and they also have inter-dependencies (like sometimes a semaphore grabs the lock when it wakes a thread).The lock is a reference counted lock, which allows several different related data structures to share a single lock. This reduces the number of locks required by higher level modules, which saves resources (each lock can create a kernel object) and also simplifies lock dependencies, which reduces deadlock opportunities. This is a recursive lock, so a single thread may reacquire the same lock multiple times in nested subroutine calls. Locks are built on top of the lower level basic lock in OSIndependentLayer, and add a few additional features, such as it will not implement the final release and delete the lock until the lock has been completely unlocked.
This module also defines the AutoLock object, which will aquire and release a lock when a variable enters and leaves scope. It's like a Mesa monitor lock, except it applies to any C scope, including the body of a procedure, a loop body, an if statement, and more.
This also implements a cross-platform binary semaphore as a reference-counted object.
- File Utilities fileUtils.cpp fileUtils.h
A few simple utilities like reading the contents of an entire file to a C-style string. These are generally more complex than the low level OS-independent file class, but not much.
- Reference Counted Objects refCount.cpp refCount.h
This module implements both a pure abstract interface class and a concrete base class for reference counted objects. The abstract class may be used with any other interface class to make it a reference counted object. A single concrete object may multiply inherit from the abstract class. The concrete base class implements reference counting with debugging support, such as tracking who AddRefs and Releases an object for leak detection, and a pending delete list that helps catch problems like double-releases or using an object after their final release.
- Memory Allocator memAlloc.cpp memAlloc.h
This implements the main memory allocator, which provides the basic functionality of malloc, plus leak detection, validity checks, and lots of debugging support. It also provides fast allocation by lazily recombining free blocks. This means the memory pool automatically tunes itself to act as a free list for the commonly allocated buffer sizes. As a result, you can use a single global memory pool instead of many different cell pools for fast allocation. This reduces the memory footprint, which offsets the cost of contention on a single pool.
- Debugging Utilities debugging.cpp debugging.h
This implements some general debugging utilities, including:- logf, a general procedure like printf except it prints formatted messages to a debug log file
- ASSERT macros
- Code to check the state of an object whenever we enter and leave a a method on the object.
- Code to record events in an audit trail stored in any debug object.
This module also defines a base class, CDebugObject, that provides these debugging functions to any inherited classes. Most classes in the Building Blocks library inherit from CDebugObject. This also provides utilities used by the internal regression test functions that are part of every module in the Building Blocks library. It has some simple code to print the status and results of tests to the console and the log.
- Logging log.cpp log.h
This module implements an append-only log file. This module can be used for any log file, not a single global log, since there may be different log files for debugging or admin statistics and more. This module can do a few things like rotate log files and optionally enforce a max logfile size.This only generates UTF-8 logs, since this module is below any text modules that would be aware of larger character sets like UTF-16. The goal is to make logging really simple so everything else that is more complicated can be built on top of logging.
- Configuration and User Preferences config.cpp config.h
This stores user configuration values, so it provides a simple database of strings, integers and booleans that are used to control various features throughout the product.This stores the data in a simple text file whose syntax resembles XML. Note, however, this is not *real* XML, it's just designed to provide the minimal file syntax for a config file. There is a more complete XML engine higher up in the BuildingBlocks library. Additionally, the config module only supports UTF8/ASCII files, not UTF16 or other alphabets.
- StringLib stringLib.h stringLib.cpp
This module defines some utility functions, like converting between UTF-16 and UTF-8.
- OS-Independent Layer osIndependantLayer.cpp osIndependantLayer.h
This module abstracts *some* of the simple and common OS-specific features. A lot of OS-dependent functions, like threading and network IO, are provided by higher level modules in the BuildingBlocks library. This particular module wraps some of the simpler functions that are also used the rest of the BuildingBlocks library. This is the lowest level module, so it cannot have any dependencies on other modules.