Copyright © 1996-2005 by the Regents of the University of California.

genlib Reference Manual

Gregory S. Couch
gregc@cgl.ucsf.edu
Computer Graphics Laboratory
University of California
San Francisco, California 94143-0446

Draft version. Last modified on 25 March 2005.

Table of Contents

  1. Description
  2. Class Relationships
  3. Command Line Use
  4. Statement Reference
  5. Container Class Description
  6. Collection Class Interface
  7. Generic Interfaces
  8. Toolkits

Description

Genlib assembles a set of C++ classes into a library as directed from the input file. The input may incorporate prebuilt interfaces and implementations from system and user toolkits. It may also supply additional members functions and data for the classes. The toolkit interfaces and implementations are written using a subset of the genlib input file syntax.

Genlib creates a subdirectory to perform its library assembly. After the library is built, there is a separate include file for each class, a library include file, and the library code archive. The generated library include file includes all the class header files and then lists all of the classes inline functions. The inline functions are in the library include file because they may depend on other class definitions. There are also several scratch files left in the subdirectory by default, a Makefile and one source and object code file for each class.

By fiat:

A familiarity with the ISO C++ standard library is assumed in this document.

Class Relationships

Genlib provides a simple scheme for storage management associated with class relationships.

Collection Relationships

One strength of genlib is its ability to manage collection classes, i.e., classes that contain instances of one or more other classes, each class in a separate container. The interface to the collected instances is generated such that the particular container classes used can be changed without any changes in dependent source code. By default, containers contain pointers to the collected class instances. This allows for instances to be collected in multiple collections while letting containers rearrange their contents as needed. If the pointer default is inappropriate for some reason, the collected instance may be collected by value. They also must have default constructors. Note: there is a limitation of the ISO C++ standard library where you must use the pointer default for maps.

Delete Relationships

A delete relationship between two classes means that instances of the collected class will be deleted when the collection class is deleted. Such collected classes are restricted to be on the heap (i.e., not local nor global variables, nor a data member of a class). The C++ technique to restrict a class to the heap is to make its destructor private. If the deleted classes has no owner (see next section), then a deleteMe member function is generated to access the destructor.

TODO: must delete relationships be asymmetric? Does genlib check for loops?

Owner Relationships

A collection class may be designated as the owner of a collected class. The owner class controls the creating and deleting of instances of the collected class; other collection classes can only add and remove pointers to instances from their container. An owner relationship implies a delete relationship.

Collected class may contain a "reverse" collection of the instances of the collection class they are in. If a reverse collection exists, it is used to speed up deletions in the case where a collection class is not the owner.

Example

An example collection class would be a Graph class that contains instances of both Vertexes and Edges. Vertex and Edge are also referred to as collected classes. Graph deletes and owns instances of both Vertex and Edge. In addition Vertexes delete Edges. Then by default, when an Edge is deleted, the Graph searches all of its Vertexes that contain the Edge and removes it from those Vertexes. If a reverse collection of Vertexes were present in an Edge, then instead of searching the list of all Vertexes, the Graph uses the reverse collection to find which Vertexes to remove the Edge from.

Command Line Use

Synopsis

genlib [ -i ] [ -I ] [ -r ] [ -v ] [ -c flags ] [ -C compiler ] [ -n name ] [ -t directory ] [ input-file ]

Options

-i
List known interfaces along with a one-line synopsis.
-I
List known implementations along with a one-line synopsis.
-r
Remove the files generated to build the library but not needed for further compiling (e.g. the Makefile, the source files, and the object files).
-v
Be verbosely liberal with warnings.
-c flags
Give additional flags to the compiler. The default flags are: '-I.. -I/usr/local/otf/include'.
-C compiler
Set which compiler to use. The default compiler is g++.
-n name
Change the name of the generated directory, include file and library. The default name is lib.
-t directory
Add a directory to the set of directories searched for toolkits. The default directories are the current directory and /usr/local/otf/resource/genlib/.

Example

genlib -c '-g -DFILENAME=\"xyzzy\"' input.gm

Statement Reference

File Types

Genlib statements are restricted in the various files used as follows:
Input File Format
All statement types are allowed, except for provide interface.
Implementation File Format
All statement types are allowed, except for the rename statement.
Interface File Format
All statement types are allowed with the following exceptions: code, destructor, implementation, inlinecode, provide, and rename. In addition the following statement types are modified: constructor statements end with a semi-colon after the arguments.

There should be no data declarations (not enforced). Only function declarations should be in members (not enforced). Auxiliary files should only be header files (not enforced).

C++-style comments (starting with // until the end of the line) are allowed anywhere. Comments that appear inside a C++ section of a statement are copied through.

Statement types

auxfile filename ;
Add the filename to the set of files in the generated subdirectory. If the filename has a suffix of .c, .cc, .C, .cpp .cxx, or .m, then it is added to the list of files to compile.
code class {
  additional code to implement interface
}
Additional code need to implement class.
constructor class [ ( arguments ) ] [ : member-initialization ] {
  additional initialization code
}
Give a constructor implementation. Error checking that implementations match interfaces is done by the compiler.
container name { options }
Add a container class with the given name to the list of legal container classes. The various options are detailed below.
destructor class [ virtual ] {
  additional cleanup code
}
Give a destructor implementation.
implementation name [ in class ] ;
Use a particular implementation (see Toolkits). The in clause indicates that name is a class-parameterized generic implementation.
includefile filename [ in class ] ;
Add the filename to the list of files that need to be included for a class's interface. If the class is missing then the filename is included in every class' interface.
inlinecode class {
  inline function declarations
}
Add inline function declarations.
members class [ : base-class-list ] {
  additional member declarations
}
Add declarations to a class' declaration. By default, additions to interfaces are public, and additions to implementations and input are private. The base-class-list is an unparsed C++ list of classes to inherit from.
provide interface interface [ in class ] ;
Indicates that this file provides an implementation of the named interface. The in clause indicates that interface is a class-parameterized generic interface.
provide container class [ owner expression ] in collection-class [ byvalue ] [ keytype type keymember expression [ keysfunc keysfunc ] ] using container [ extra parameters ] ;
Give the container class used to manage collections of class instances in collection-class. If the using clause is present, genlib will generate an implementation using the given container class. container's must be from the ISO C++ standard library or described in a container statement. The optional parameters override the ones given in the container class description. If (and only if) the keytype clause is present, then the container class must be a map-style class. The expression should be a member function of class that returns the map key of the right type.

The owner expression tells how the collection-class reaches the owner of the class when it is not the owner. If both the class and the collection-class have the same owner class, then instances are assumed to have the same owner and the owner expression is ignored.

If the keysfunc clause is present, then the generated containers function just returns the contained elements and a separate keysfunc function is generated that returns the all of the keys. The map is still available via the containerMap function.

provide container class in collection-class [ byvalue ] singular ;
Indicate that instances of the collection-class keep a reference to the class they are in. genlib generates an implementation using a pointer.
rename class to new-class ;
Rename a class to a different class name, new-class. This is so there can be multiple libraries using the same interface.
require interface interface [ in class ] ;
Indicate that the interface is a required part of the library. The in clause indicates that interface is a class-parameterized generic interface.
require container [ delete ] class in [ owner ] collection-class [ byvalue ] [ keytype type [ keysfunc keysfunc ] ] ;
Indicate that the collection-class maintains a collection of class instances. If (and only if) the keytype clause is present, then the container class used must be a map-style class.

If the delete is present, then the default destructor behavior of collection-class is to delete class instances that it contains when it is deleted.

If the owner keyword is given then the collection-class instances control access to class instances. A consequence is that the class constructors will be private. A class can only have one owner.

require container class in collection-class [ byvalue ] singular ;
Indicate that instances of the collection-class can access which instance of class they are in.
typedef class { type }
class is typedef'd as type. This precludes the class from having any constructors, destructors, or members.

Container Class Description

All container classes are assumed to be compatible with the ISO C++ standard library. Container types are generated as name<instance-type> or, for maps, name<key-type, instance-type>. Some container classes require additional template parameters. A default version of those parameters is given in the container class options and can be overridden in the provide statement. The options are:
append string
Tell how to append an instance to the container. (Must have trailing semicolon.)
extra string
Provide default additional template parameters to container class.
includefile filename
Specify which include file contains container description. Maybe be repeated.
integerindex
Indicates that the container can be indexed by integers, like the ISO C++ vector class.
keyslisttype
keyslist
map
Indicates that container is a mapping, like the ISO C++ std::map and std::multimap classes.
remove string
Tell how to remove an instance from the container. (Must have trailing semicolon.)
valueslisttype
valueslist
If there is no includefile clause given, then "name.h" is included.

The argument string's given above can be parameterized with the collected class type, FORCLASS; the collection class type, INCLASS; the container class type, TYPE; (if a map) the key type, KEYTYPE; the actual container instance, CONTAINER; the collected class instance, ELEMENT; and (if map) the key expression, EXPRESSION. Note that the various types above may or may not be pointer types, depending on the delete relationships. For example, the ISO C++ set class is described as follows:

container std::set {
	includefile <set>
	extra "less<FORCLASS>"
	append "CONTAINER.insert(ELEMENT);"
	remove "CONTAINER.erase(ELEMENT);"
}
Genlib knows about the following ISO C++ containers: std::deque, std::list, std::map, std::multimap, std::multiset, std::set, and std::vector. The descriptions for all of the standard ISO C++ container classes are kept in the genlib resource directory, /usr/local/otf/resource/genlib, in the containers.implementation file.

In addition, genlib knows about arrays as containers: use a container name of otf::Array with an extra parameter that is integral array size (e.g., for an array of two elements: provide container ... using otf::Array extra 2;). otf::Array is container class that adds ISO C++ iterators to C/C++ arrays. As implemented, arrays have several limitations as containers since they do not expand and contract as do the other ISO C++ containers. They do not support the erase(iterator) member function that removes a single element. Consequently, an array cannot be used as a container when a class must delete anther class. Nor do they have an append clause nor a remove clause in their description. That means that arrays are not automatically updated like other containers are. Despite these limitations, arrays can be very useful; especially when all of the elements of the collection are given in the class constructor.

Collection Class Interface

Collection classes control all access to collected classes through the following interface. For each type of collected class, the class name, ClassName, and the class name with the first character converted to lowercase, className, are used to generate several member functions.

In owner class

ClassName *newClassName(....)
Each generated private constructor has a corresponding new member function.
void deleteClassName(ClassName *instance)
Delete instance.

In non-owner class

void addClassName(ClassName *instance)
Add instance.
void removeClassName(ClassName *instance)
Remove instance.

In a singular collection

ClassName *className() const
Return pointer to collected class instance.

In a non-singular collection

ClassName *findClassName(type key)
Find an instance by its key. For container classes that are not maps, but can be indexed by non-negative integers, the type is int. Otherwise, this function is not generated.
typedef container<args> ClassNames
container type
const ClassNames &classNames() const
Returns the constant container instance.

In a map or indexable collection

ClassName *findClassName(keytype key) const
Find (first) element in collection with given key.
In addition, the following are generated for std::multiset and std::multimap:
typedef std::pair<ClassNames::const_iterator, ClassNames::const_iterator> RangeClassNames
Range type to simplify the use of the following find function.
RangeClassNames findRangeClassNames(keytype key) const
Return all of the element of the collection class that match the given key.

Example

Let Graph be the name of a collection class, and g be an instance of that class. Let Vertex be the name of a collected class that is owned by Graph. Then to iterate through all of the vertices, one would:

for (Graph::Vertexs::const_iterator i = g.vertexs().begin(); i != g.vertexs().end(); ++i) {
  proccessVertexPointer(*i);
}

Generic Interfaces

To provide the same interface in several classes, there are class-parameterized generic forms of the require, provide, and implementation statements. In the interface and implementation files, in every statement where a class name may be specified (except for the rename statement), the class name may be given as the word __CLASS__; and __CLASS__ is replaced with the class that contains the interface. Similarly, in the members, constructor, destructor, code and inlinecode statements, the C++ text is scanned for occurrences of __CLASS__ to replace.

Toolkits

The system toolkits are kept in the genlib resource directory /usr/local/otf/resource/genlib/. Each toolkit is kept in a separate subdirectory named toolkit.toolkit. In that directory are kept the interface and implementation files, respectively named interface.interface and implementation.implementation. An interface may have several implementations with different design trade-offs. Toolkits may be nested.

By default, interface and implementation names refer to ones in the current toolkit. To refer to one in a different toolkit, use a hierarchical notation of toolkit/name; a subtoolkit would be referred to as toolkit/subtoolkit/name.

The first line of the file should be a comment containing one-line synopsis of the contents.

Other Issues