home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-07-19 | 46.5 KB | 1,097 lines |
- Info file libg++.info, produced by Makeinfo, -*- Text -*- from input
- file libg++.texinfo.
-
- START-INFO-DIR-ENTRY
- * Libg++: (libg++). The g++ library.
- END-INFO-DIR-ENTRY
-
- This file documents the features and implementation of The GNU C++
- library
-
- Copyright (C) 1988, 1991, 1992 Free Software Foundation, Inc.
-
- Permission is granted to make and distribute verbatim copies of
- this manual provided the copyright notice and this permission notice
- are preserved on all copies.
-
- Permission is granted to copy and distribute modified versions of
- this manual under the conditions for verbatim copying, provided also
- that the section entitled "GNU Library General Public License" is
- included exactly as in the original, and provided that the entire
- resulting derived work is distributed under the terms of a permission
- notice identical to this one.
-
- Permission is granted to copy and distribute translations of this
- manual into another language, under the above conditions for modified
- versions, except that the section entitled "GNU Library General Public
- License" and this permission notice may be included in translations
- approved by the Free Software Foundation instead of in the original
- English.
-
- File: libg++.info, Node: Proto, Next: Representations, Prev: OK, Up: Top
-
- Introduction to container class prototypes
- ******************************************
-
- As a temporary mechanism enabling the support of generic classes,
- the GNU C++ Library distribution contains a directory (`g++-include')
- of files designed to serve as the basis for generating container
- classes of specified elements. These files can be used to generate
- `.h' and `.cc' files in the current directory via a supplied shell
- script program that performs simple textual substitution to create
- specific classes.
-
- While these classes are generated independently, and thus share no
- code, it is possible to create versions that do share code among
- subclasses. For example, using `typedef void* ent', and then
- generating a `entList' class, other derived classes could be created
- using the `void*' coercion method described in Stroustrup, pp204-210.
-
- This very simple class-generation facility is useful enough to serve
- current purposes, but will be replaced with a more coherent mechanism
- for handling C++ generics in a way that minimally disrupts current
- usage. Without knowing exactly when or how parametric classes might be
- added to the C++ language, provision of this simplest possible
- mechanism, textual substitution, appears to be the safest strategy,
- although it does require certain redundancies and awkward
- constructions.
-
- Specific classes may be generated via the `genclass' shell script
- program. This program has arguments specifying the kinds of base
- types(s) to be used. Specifying base types requires two arguments. The
- first is the name of the base type, which may be any named type, like
- `int' or `String'. Only named types are supported; things like `int*'
- are not accepted. However, pointers like this may be used by supplying
- the appropriate typedefs (e.g., editing the resulting files to include
- `typedef int* intp;'). The type name must be followed by one of the
- words `val' or `ref', to indicate whether the base elements should be
- passed to functions by-value or by-reference.
-
- You can specify basic container classes using `genclass base
- [val,ref] proto', where `proto' is the name of the class being
- generated. Container classes like dictionaries and maps that require
- two types may be specified via `genclass -2 keytype [val, ref],
- basetype [val, ref] proto', where the key type is specified first and
- the contents type second. The resulting classnames and filenames are
- generated by prepending the specified type names to the prototype
- names, and separating the filename parts with dots. For example,
- `genclass int val List' generates class `intList' residing in files
- `int.List.h' and `int.List.cc'. `genclass -2 String ref int val VHMap'
- generates (the awkward, but unavoidable) class name `StringintVHMap'.
- Of course, programmers may use `typedef' or simple editing to create
- more appropriate names. The existence of dot seperators in file names
- allows the use of GNU make to help automate configuration and
- recompilation. An example Makefile exploiting such capabilities may be
- found in the `libg++/proto-kit' directory.
-
- The `genclass' utility operates via simple text substitution using
- `sed'. All occurrences of the pseudo-types `<T>' and `<C>' (if there
- are two types) are replaced with the indicated type, and occurrences
- of `<T&>' and `<C&>' are replaced by just the types, if `val' is
- specified, or types followed by "&" if `ref' is specified.
-
- Programmers will frequently need to edit the `.h' file in order to
- insert additional `#include' directives or other modifications. A
- simple utility, `prepend-header' to prepend other `.h' files to
- generated files is provided in the distribution.
-
- One dubious virtue of the prototyping mechanism is that, because
- sources files, not archived library classes, are generated, it is
- relatively simple for programmers to modify container classes in the
- common case where slight variations of standard container classes are
- required.
-
- It is often a good idea for programmers to archive (via `ar')
- generated classes into `.a' files so that only those class functions
- actually used in a given application will be loaded. The test
- subdirectory of the distribution shows an example of this.
-
- Because of `#pragma interface' directives, the `.cc' files should
- be compiled with `-O' or `-DUSE_LIBGXX_INLINES' enabled.
-
- Many container classes require specifications over and above the
- base class type. For example, classes that maintain some kind of
- ordering of elements require specification of a comparison function
- upon which to base the ordering. This is accomplished via a prototype
- file `defs.hP' that contains macros for these functions. While these
- macros default to perform reasonable actions, they can and should be
- changed in particular cases. Most prototypes require only one or a few
- of these. No harm is done if unused macros are defined to perform
- nonsensical actions. The macros are:
-
- `DEFAULT_INITIAL_CAPACITY'
- The intitial capacity for containers (e.g., hash tables) that
- require an initial capacity argument for constructors. Default:
- 100
-
- `<T>EQ(a, b)'
- return true if a is considered equal to b for the purposes of
- locating, etc., an element in a container. Default: (a == b)
-
- `<T>LE(a, b)'
- return true if a is less than or equal to b Default: (a <= b)
-
- `<T>CMP(a, b)'
- return an integer < 0 if a<b, 0 if a==b, or > 0 if a>b. Default:
- (a <= b)? (a==b)? 0 : -1 : 1
-
- `<T>HASH(a)'
- return an unsigned integer representing the hash of a. Default:
- hash(a) ; where extern unsigned int hash(<T&>). (note: several
- useful hash functions are declared in builtin.h and defined in
- hash.cc)
-
- Nearly all prototypes container classes support container traversal
- via `Pix' pseudo indices, as described elsewhere.
-
- All object containers must perform either a `X::X(X&)' (or `X::X()'
- followed by `X::operator =(X&)') to copy objects into containers.
- (The latter form is used for containers built from C++ arrays, like
- `VHSets'). When containers are destroyed, they invoke `X::~X()'. Any
- objects used in containers must have well behaved constructors and
- destructors. If you want to create containers that merely reference
- (point to) objects that reside elsewhere, and are not copied or
- destroyed inside the container, you must use containers of pointers,
- not containers of objects.
-
- All prototypes are designed to generate *HOMOGENOUS* container
- classes. There is no universally applicable method in C++ to support
- heterogenous object collections with elements of various subclasses of
- some specified base class. The only way to get heterogenous structures
- is to use collections of pointers-to-objects, not collections of
- objects (which also requires you to take responsibility for managing
- storage for the objects pointed to yourself).
-
- For example, the following usage illustrates a commonly encountered
- danger in trying to use container classes for heterogenous structures:
-
- class Base { int x; ...}
- class Derived : public Base { int y; ... }
-
- BaseVHSet s; // class BaseVHSet generated via something like
- // `genclass Base ref VHSet'
-
- void f()
- {
- Base b;
- s.add(b); // OK
-
- Derived d;
- s.add(d); // (CHOP!)
- }
-
- At the line flagged with `(CHOP!)', a `Base::Base(Base&)' is called
- inside `Set::add(Base&)'--*not* `Derived::Derived(Derived&)'.
- Actually, in `VHSet', a `Base::operator =(Base&)', is used instead to
- place the element in an array slot, but with the same effect. So only
- the Base part is copied as a `VHSet' element (a so-called
- chopped-copy). In this case, it has an `x' part, but no `y' part; and
- a Base, not Derived, vtable. Objects formed via chopped copies are
- rarely sensible.
-
- To avoid this, you must resort to pointers:
-
- typedef Base* BasePtr;
-
- BasePtrVHSet s; // class BaseVHSet generated via something like
- // `genclass BasePtr val VHSet'
-
- void f()
- {
- Base* bp = new Base;
- s.add(b);
-
- Base* dp = new Derived;
- s.add(d); // works fine.
-
- // Don't forget to delete bp and dp sometime.
- // The VHSet won't do this for you.
- }
-
- Example
- =======
-
- The prototypes can be difficult to use on first attempt. Here is an
- example that may be helpful. The utilities in the `proto-kit' simplify
- much of the actions described, but are not used here.
-
- Suppose you create a class `Person', and want to make an Map that
- links the social security numbers associated with each person. You
- start off with a file `Person.h'
-
-
- #include <String.h>
-
- class Person
- {
- String nm;
- String addr;
- //...
- public:
- const String& name() { return nm; }
- const String& address() { return addr; }
- void print() { ... }
- //...
- }
-
- And in file `SSN.h',
-
- typedef unsigned int SSN;
-
- Your first decision is what storage/usage strategy to use. There are
- several reasonable alternatives here: You might create an "object
- collection" of Persons, a "pointer collection" of pointers-to-Persons,
- or even a simple String map, housing either copies of pointers to the
- names of Persons, since other fields are unused for purposes of the
- Map. In an object collection, instances of class Person "live" inside
- the Map, while in a pointer collection, the instances live elswhere.
- Also, as above, if instances of subclasses of Person are to be used
- inside the Map, you must use pointers. In a String Map, the same
- difference holds, but now only for the name fields. Any of these
- choices might make sense in particular applications.
-
- The second choice is the Map implementation strategy. Either a tree
- or a hash table might make sense. Suppose you want an AVL tree Map.
- There are two things to now check. First, as an object collection, the
- AVLMap requires that the elsement class contain an `X(X&)'
- constructor. In C++, if you don't specify such a constructor, one is
- constructed for you, but it is a very good idea to always do this
- yourself, to avoid surprises. In this example, you'd use something like
-
- class Person
- { ...;
- Person(const Person& p) :nm(p.nm), addr(p.addr) {}
- };
-
- Also, an AVLMap requires a comparison function for elements in order
- to maintain order. Rather than requiring you to write a particular
- comparison function, a `defs' file is consulted to determine how to
- compare items. You must create and edit such a file.
-
- Before creating `Person.defs.h', you must first make one additional
- decision. Should the Map member functions like `m.contains(p)' take
- arguments (`p') by reference (i.e., typed as `int Map::contains(const
- Person& p)' or by value (i.e., typed as `int Map::contains(const
- Person p)'. Generally, for user-defined classes, you want to pass by
- reference, and for builtins and pointers, to pass by value. SO you
- should pick by-reference.
-
- You can now create `Person.defs.h' via `genclass Person ref defs'.
- This creates a simple skeleton that you must edit. First, add
- `#include "Person.h"' to the top. Second, edit the `<T>CMP(a,b)' macro
- to compare on name, via
-
- #define <T>CMP(a, b) ( compare(a.name(), b.name()) )
-
- which invokes the `int compare(const String&, const String&)' function
- from `String.h'. Of course, you could define this in any other way as
- well. In fact, the default versions in the skelaton turn out to be OK
- (albeit inefficient) in this particular example.
-
- You may also want to create file `SSN.defs.h'. Here, choosing
- call-by-value makes sense, and since no other capabilities (like
- comparison functions) of the SSNs are used (and the defaults are OK
- anyway), you'd type
-
- genclass SSN val defs
-
- and then edit to place `#include "SSN.h"' at the top.
-
- Finally, you can generate the classes. First, generate the base
- class for Maps via
-
- genclass -2 Person ref SSN val Map
-
- This generates only the abstract class, not the implementation, in file
- `Person.SSN.Map.h' and `Person.SSN.Map.cc'. To create the AVL
- implementation, type
-
- genclass -2 Person ref SSN val AVLMap
-
- This creates the class `PersonSSNAVLMap', in `Person.SSN.AVLMap.h' and
- `Person.SSN.AVLMap.cc'.
-
- To use the AVL implementation, compile the two generated `.cc'
- files, and specify `#include "Person.SSN.AVLMap.h"' in the application
- program. All other files are included in the right ways automatically.
-
- One last consideration, peculiar to Maps, is to pick a reasonable
- default contents when declaring an AVLMap. Zero might be appropriate
- here, so you might declare a Map,
-
- PersonSSNAVLMap m((SSN)0);
-
- Suppose you wanted a `VHMap' instead of an `AVLMap' Besides
- generating different implementations, there are two differences in how
- you should prepare the `defs' file. First, because a VHMap uses a C++
- array internally, and because C++ array slots are initialized
- differently than single elements, you must ensure that class Person
- contains (1) a no-argument constructor, and (2) an assigment operator.
- You could arrange this via
-
- class Person
- { ...;
- Person() {}
- void operator = (const Person& p) { nm = p.nm; addr = p.addr; }
- };
-
- (The lack of action in the constructor is OK here because `Strings'
- posess usable no-argument constructors.)
-
- You also need to edit `Person.defs.h' to indicate a usable hash
- function and default capacity, via something like
-
- #include <builtin.h>
- #define <T>HASH(x) (hashpjw(x.name().chars()))
- #define DEFAULT_INITIAL_CAPACITY 1000
-
- Since the `hashpjw' function from `builtin.h' is appropriate here.
- Changing the default capacity to a value expected to exceed the actual
- capacity helps to avoid "hidden" inefficiencies when a new VHMap is
- created without overriding the default, which is all too easy to do.
-
- Otherwise, everything is the same as above, substituting `VHMap'
- for `AVLMap'.
-
- File: libg++.info, Node: Representations, Next: Expressions, Prev: Proto, Up: Top
-
- Variable-Sized Object Representation
- ************************************
-
- One of the first goals of the GNU C++ library is to enrich the
- kinds of basic classes that may be considered as (nearly) "built into"
- C++. A good deal of the inspiration for these efforts is derived from
- considering features of other type-rich languages, particularly Common
- Lisp and Scheme. The general characteristics of most class and friend
- operators and functions supported by these classes has been heavily
- influenced by such languages.
-
- Four of these types, Strings, Integers, BitSets, and BitStrings (as
- well as associated and/or derived classes) require representations
- suitable for managing variable-sized objects on the free-store. The
- basic technique used for all of these is the same, although various
- details necessarily differ from class to class.
-
- The general strategy for representing such objects is to create
- chunks of memory that include both header information (e.g., the size
- of the object), as well as the variable-size data (an array of some
- sort) at the end of the chunk. Generally the maximum size of an object
- is limited to something less than all of addressable memory, as a
- safeguard. The minimum size is also limited so as not to waste
- allocations expanding very small chunks. Internally, chunks are
- allocated in blocks well-tuned to the performance of the `new'
- operator.
-
- Class elements themselves are merely pointers to these chunks.
- Most class operations are performed via inline "translation" functions
- that perform the required operation on the corresponding
- representation. However, constructors and assignments operate by
- copying entire representations, not just pointers.
-
- No attempt is made to control temporary creation in expressions and
- functions involving these classes. Users of previous versions of the
- classes will note the disappearance of both "Tmp" classes and
- reference counting. These were dropped because, while they did improve
- performance in some cases, they obscure class mechanics, lead
- programmers into the false belief that they need not worry about such
- things, and occaisionally have paradoxical behavior.
-
- These variable-sized object classes are integrated as well as
- possible into C++. Most such classes possess converters that allow
- automatic coercion both from and to builtin basic types. (e.g., char*
- to and from String, long int to and from Integer, etc.). There are
- pro's and con's to circular converters, since they can sometimes lead
- to the conversion from a builtin type through to a class function and
- back to a builtin type without any special attention on the part of
- the programmer, both for better and worse.
-
- Most of these classes also provide special-case operators and
- functions mixing basic with class types, as a way to avoid
- constructors in cases where the operations do not rely on anything
- special about the representations. For example, there is a special
- case concatenation operator for a String concatenated with a char,
- since building the result does not rely on anything about the String
- header. Again, there are arguments both for and against this approach.
- Supporting these cases adds a non-trivial degree of (mainly inline)
- function proliferation, but results in more efficient operations.
- Efficiency wins out over parsimony here, as part of the goal to
- produce classes that provide sufficient functionality and efficiency
- so that programmers are not tempted to try to manipulate or bypass the
- underlying representations.
-
- File: libg++.info, Node: Expressions, Next: Pix, Prev: Representations, Up: Top
-
- Some guidelines for using expression-oriented classes
- *****************************************************
-
- The fact that C++ allows operators to be overloaded for user-defined
- classes can make programming with library classes like `Integer',
- `String', and so on very convenient. However, it is worth becoming
- familiar with some of the inherent limitations and problems associated
- with such operators.
-
- Many operators are *constructive*, i.e., create a new object based
- on some function of some arguments. Sometimes the creation of such
- objects is wasteful. Most library classes supporting expressions
- contain facilities that help you avoid such waste.
-
- For example, for `Integer a, b, c; ...; c = a + b + a;', the plus
- operator is called to sum a and b, creating a new temporary object as
- its result. This temporary is then added with a, creating another
- temporary, which is finally copied into c, and the temporaries are then
- deleted. In other words, this code might have an effect similar to
- `Integer a, b, c; ...; Integer t1(a); t1 += b; Integer t2(t1); t2 +=
- a; c = t2;'.
-
- For small objects, simple operators, and/or non-time/space critical
- programs, creation of temporaries is not a big problem. However, often,
- when fine-tuning a program, it may be a good idea to rewrite such code
- in a less pleasant, but more efficient manner.
-
- For builtin types like ints, and floats, C and C++ compilers already
- know how to optimize such expressions to reduce the need for
- temporaries. Unfortunately, this is not true for C++ user defined
- types, for the simple (but very annoying, in this context) reason that
- nothing at all is guaranteed about the semantics of overloaded
- operators and their interrelations. For example, if the above
- expression just involved ints, not Integers, a compiler might
- internally convert the statement into something like ` c += a; c += b;
- c+= a; ', or perhaps something even more clever. But since C++ does
- not know that Integer operator += has any relation to Integer operator
- +, A C++ compiler cannot do this kind of expression optimization
- itself.
-
- In many cases, you can avoid construction of temporaries simply by
- using the assignment versions of operators whenever possible, since
- these versions create no temporaries. However, for maximum flexibility,
- most classes provide a set of "embedded assembly code" procedures that
- you can use to fully control time, space, and evaluation strategies.
- Most of these procedures are "three-address" procedures that take two
- `const' source arguments, and a destination argument. The procedures
- perform the appropriate actions, placing the results in the
- destination (which is may involve overwriting old contents). These
- procedures are designed to be fast and robust. In particular, aliasing
- is always handled correctly, so that, for example `add(x, x, x); ' is
- perfectly OK. (The names of these procedures are listed along with the
- classes.)
-
- For example, suppose you had an Integer expression ` a = (b - a) *
- -(d / c); '
-
- This would be compiled as if it were ` Integer t1=b-a; Integer
- t2=d/c; Integer t3=-t2; Integer t4=t1*t3; a=t4;'
-
- But, with some manual cleverness, you might yourself some up with `
- sub(a, b, a); mul(a, d, a); div(a, c, a); '
-
- A related phenomenon occurs when creating your own constructive
- functions returning instances of such types. Suppose you wanted to
- write function `Integer f(const Integer& a) { Integer r = a; r += a;
- return r; }'
-
- This function, when called (as in ` a = f(a); ') demonstrates a
- similar kind of wasted copy. The returned value r must be copied out
- of the function before it can be used by the caller. In GNU C++, there
- is an alternative via the use of named return values. Named return
- values allow you to manipulate the returned object directly, rather
- than requiring you to create a local inside a function and then copy
- it out as the returned value. In this example, this can be done via
- `Integer f(const Integer& a) return r(a) { r += a; return; }'
-
- A final guideline: The overloaded operators are very convenient, and
- much clearer to use than procedural code. It is almost always a good
- idea to make it right, *then* make it fast, by translating expression
- code into procedural code after it is known to be correct.
-
- File: libg++.info, Node: Pix, Next: Headers, Prev: Expressions, Up: Top
-
- Pseudo-indexes
- **************
-
- Many useful classes operate as containers of elements. Techniques
- for accessing these elements from a container differ from class to
- class. In the GNU C++ library, access methods have been partially
- standardized across different classes via the use of pseudo-indexes
- called `Pixes'. A `Pix' acts in some ways like an index, and in some
- ways like a pointer. (Their underlying representations are just
- `void*' pointers). A `Pix' is a kind of "key" that is translated into
- an element access by the class. In virtually all cases, `Pixes' are
- pointers to some kind internal storage cells. The containers use these
- pointers to extract items.
-
- `Pixes' support traversal and inspection of elements in a
- collection using analogs of array indexing. However, they are
- pointer-like in that `0' is treated as an invalid `Pix', and unsafe
- insofar as programmers can attempt to access nonexistent elements via
- dangling or otherwise invalid `Pixes' without first checking for their
- validity.
-
- In general it is a very bad idea to perform traversals in the the
- midst of destructive modifications to containers.
-
- Typical applications might include code using the idiom
-
- for (Pix i = a.first(); i != 0; a.next(i)) use(a(i));
-
- for some container `a' and function `use'.
-
- Classes supporting the use of `Pixes' always contain the following
- methods, assuming a container `a' of element types of `Base'.
-
- `Pix i = a.first()'
- Set i to index the first element of a or 0 if a is empty.
-
- `a.next(i)'
- advance i to the next element of a or 0 if there is no next
- element;
-
- `Base x = a(i); a(i) = x;'
- a(i) returns a reference to the element indexed by i.
-
- `int present = a.owns(i)'
- returns true if Pix i is a valid Pix in a. This is often a
- relatively slow operation, since the collection must usually
- traverse through elements to see if any correspond to the Pix.
-
- Some container classes also support backwards traversal via
-
- `Pix i = a.last()'
- Set i to the last element of a or 0 if a is empty.
-
- `a.prev(i)'
- sets i to the previous element in a, or 0 if there is none.
-
- Collections supporting elements with an equality operation possess
-
- `Pix j = a.seek(x)'
- sets j to the index of the first occurrence of x, or 0 if x is
- not contained in a.
-
- Bag classes possess
-
- `Pix j = a.seek(x, Pix from = 0)'
- sets j to the index of the next occurrence of x following i, or 0
- if x is not contained in a. If i == 0, the first occurrence is
- returned.
-
- Set, Bag, and PQ classes possess
-
- `Pix j = a.add(x) (or a.enq(x) for priority queues)'
- add x to the collection, returning its Pix. The Pix of an item
- can change in collections where further additions and deletions
- involve the actual movement of elements (currently in OXPSet,
- OXPBag, XPPQ, VOHSet), but in all other cases, an item's Pix may
- be considered a permanent key to its location.
-
- File: libg++.info, Node: Headers, Next: Builtin, Prev: Pix, Up: Top
-
- Header files for interfacing C++ to C
- *************************************
-
- The following files are provided so that C++ programmers may invoke
- common C library and system calls. The names and contents of these
- files are subject to change in order to be compatible with the
- forthcoming GNU C library. Other files, not listed here, are simply
- C++-compatible interfaces to corresponding C library files.
-
- `values.h'
- A collection of constants defining the numbers of bits in builtin
- types, minimum and maximum values, and the like. Most names are
- the same as those found in `values.h' found on Sun systems.
-
- `std.h'
- A collection of common system calls and `libc.a' functions. Only
- those functions that can be declared without introducing new type
- definitions (socket structures, for example) are provided. Common
- `char*' functions (like `strcmp') are among the declarations. All
- functions are declared along with their library names, so that
- they may be safely overloaded.
-
- `string.h'
- This file merely includes `<std.h>', where string function
- prototypes are declared. This is a workaround for the fact that
- system `string.h' and `strings.h' files often differ in contents.
-
- `osfcn.h'
- This file merely includes `<std.h>', where system function
- prototypes are declared.
-
- `libc.h'
- This file merely includes `<std.h>', where C library function
- prototypes are declared.
-
- `math.h'
- A collection of prototypes for functions usually found in libm.a,
- plus some `#define'd constants that appear to be consistent with
- those provided in the AT&T version. The value of `HUGE' should be
- checked before using. Declarations of all common math functions
- are preceded with `overload' declarations, since these are
- commonly overloaded.
-
- `stdio.h'
- Declaration of `FILE' (`_iobuf'), common macros (like `getc'),
- and function prototypes for `libc.a' functions that operate on
- `FILE*''s. The value `BUFSIZ' and the declaration of `_iobuf'
- should be checked before using.
-
- `assert.h'
- C++ versions of assert macros.
-
- `generic.h'
- String concatenation macros useful in creating generic classes.
- They are similar in function to the AT&T CC versions.
-
- `new.h'
- Declarations of the default global operator new, the two-argument
- placement version, and associated error handlers.
-
- File: libg++.info, Node: Builtin, Next: New, Prev: Headers, Up: Top
-
- Utility functions for built in types
- ************************************
-
- Files `builtin.h' and corresponding `.cc' implementation files
- contain various convenient inline and non-inline utility functions.
- These include useful enumeration types, such as `TRUE', `FALSE' ,the
- type definition for pointers to libg++ error handling functions, and
- the following functions.
-
- `long abs(long x); double abs(double x);'
- inline versions of abs. Note that the standard libc.a version,
- `int abs(int)' is *not* declared as inline.
-
- `void clearbit(long& x, long b);'
- clears the b'th bit of x (inline).
-
- `void setbit(long& x, long b);'
- sets the b'th bit of x (inline)
-
- `int testbit(long x, long b);'
- returns the b'th bit of x (inline).
-
- `int even(long y);'
- returns true if x is even (inline).
-
- `int odd(long y);'
- returns true is x is odd (inline).
-
- `int sign(long x); int sign(double x);'
- returns -1, 0, or 1, indicating whether x is less than, equal to,
- or greater than zero (inline).
-
- `long gcd(long x, long y);'
- returns the greatest common divisor of x and y.
-
- `long lcm(long x, long y);'
- returns the least common multiple of x and y.
-
- `long lg(long x);'
- returns the floor of the base 2 log of x.
-
- `long pow(long x, long y); double pow(double x, long y);'
- returns x to the integer power y using via the iterative O(log y)
- "Russian peasant" method.
-
- `long sqr(long x); double sqr(double x);'
- returns x squared (inline).
-
- `long sqrt(long y);'
- returns the floor of the square root of x.
-
- `unsigned int hashpjw(const char* s);'
- a hash function for null-terminated char* strings using the
- method described in Aho, Sethi, & Ullman, p 436.
-
- `unsigned int multiplicativehash(int x);'
- a hash function for integers that returns the lower bits of
- multiplying x by the golden ratio times pow(2, 32). See Knuth,
- Vol 3, p 508.
-
- `unsigned int foldhash(double x);'
- a hash function for doubles that exclusive-or's the first and
- second words of x, returning the result as an integer.
-
- `double start_timer()'
- Starts a process timer.
-
- `double return_elapsed_time(double last_time)'
- Returns the process time since last_time. If last_time == 0
- returns the time since the last start_timer. Returns -1 if
- start_timer was not first called.
-
- File `Maxima.h' includes versions of `MAX, MIN' for builtin types.
-
- File `compare.h' includes versions of `compare(x, y)' for buitlin
- types. These return negative if the first argument is less than the
- second, zero for equal, and positive for greater.
-
- File: libg++.info, Node: New, Next: IOStream, Prev: Builtin, Up: Top
-
- Library dynamic allocation primitives
- *************************************
-
- Libg++ contains versions of `malloc, free, realloc' that were
- designed to be well-tuned to C++ applications. The source file
- `malloc.c' contains some design and implementation details. Here are
- the major user-visible differences from most system malloc routines:
-
- 1. These routines *overwrite* storage of freed space. This means
- that it is never permissible to use a `delete''d object in any
- way. Doing so will either result in trapped fatal errors or
- random aborts within malloc, free, or realloc.
-
- 2. The routines tend to perform well when a large number of objects
- of the same size are allocated and freed. You may find that it is
- not worth it to create your own special allocation schemes in
- such cases.
-
- 3. The library sets top-level `operator new()' to call malloc and
- `operator delete()' to call free. Of course, you may override
- these definitions in C++ programs by creating your own operators
- that will take precedence over the library versions. However, if
- you do so, be sure to define *both* `operator new()' and `operator
- delete()'.
-
- 4. These routines do *not* support the odd convention, maintained by
- some versions of malloc, that you may call `realloc' with a
- pointer that has been `free''d.
-
- 5. The routines automatically perform simple checks on `free''d
- pointers that can often determine whether users have accidentally
- written beyond the boundaries of allocated space, resulting in a
- fatal error.
-
- 6. The function `malloc_usable_size(void* p)' returns the number of
- bytes actually allocated for `p'. For a valid pointer (i.e., one
- that has been `malloc''d or `realloc''d but not yet `free''d)
- this will return a number greater than or equal to the requested
- size, else it will normally return 0. Unfortunately, a non-zero
- return can not be an absolutely perfect indication of lack of
- error. If a chunk has been `free''d but then re-allocated for a
- different purpose somewhere elsewhere, then `malloc_usable_size'
- will return non-zero. Despite this, the function can be very
- valuable for performing run-time consistency checks.
-
- 7. `malloc' requires 8 bytes of overhead per allocated chunk, plus a
- mmaximum alignment adjustment of 8 bytes. The number of bytes of
- usable space is exactly as requested, rounded to the nearest 8
- byte boundary.
-
- 8. The routines do *not* contain any synchronization support for
- multiprocessing. If you perform global allocation on a shared
- memory multiprocessor, you should disable compilation and use of
- libg++ malloc in the distribution `Makefile' and use your system
- version of malloc.
-
- File: libg++.info, Node: IOStream, Next: Stream, Prev: New, Up: Top
-
- The new input/output classes
- ****************************
-
- The iostream classes implement most of the features of AT&T version
- 2.0 iostream library classes, and most of the features of the ANSI
- X3J16 library draft (which is based on the AT&T design). The iostream
- classes replace all of the old stream classes in previous versions of
- libg++. It is not totally compatible, so you will probably need to
- change your code in places.
-
- The `streambuf' layer
- =====================
-
- The lower level abstraction is the `streambuf' layer. A
- `streambuf' (or one of the classes derived from it) implements a
- character source and/or sink, usually with buffering.
-
- Classes derived from `streambuf' include:
-
- * A `filebuf' is used for reading and writing from files.
-
- * A `strstreambuf' can raed and write from a string in main memory.
- The string buffer will be re-allocated as needed it, unless it is
- "frozen".
-
- * An `indirectbuf' just forwards all read/write requests to some
- other buffer.
-
- * A `procbuf' can read from or write to a Unix process.
-
- * A `parsebuf' has some useful features for scanning text: It
- keeps track of line and column numbers, and it guarantees to
- remember at least the current line (with the linefeeds at either
- end), so you can arbitrarily backup within that time. WARNING:
- The interface is likely to change.
-
- * An `edit_streambuf' reads and writes into a region of an
- `edit_buffer' called an `edit_string'. Emacs-like marks are
- supported, and sub-strings are first-class functions. WARNING:
- The interface is almost certain to change.
-
- The istream and ostream classes
- ===============================
-
- The stream layer provides an efficient, easy-to-use, and type-secure
- interface between C++ and an underlying `streambuf'.
-
- Most C++ textbooks will at least given an overview of the stream
- classes. Some libg++ specifics:
-
- `istream::get(char* s, int maxlength, char terminator='\n')'
- Behaves as described by Stroustrup. It reads at most maxlength
- characters into s, stopping when the terminator is read, and
- pushing the terminator back into the input stream.
-
- `istream::getline(char* s, int maxlength, char terminator = '\n')'
- Behaves like get, except that the terminator is read (and not
- pushed back), though it does not become part of the string.
-
- `istream::gets(char** ss, char terminator = '\n')'
- reads in a line (as in get) of unknown length, and places it in a
- free-store allocated spot and attaches it to `ss'. The programmer
- must take responsibility for deleting `*ss' when it is no longer
- needed.
-
- `ostream::form(const char* format...)'
- outputs `printf'-formated data.
-
- The SFile class
- ===============
-
- `SFile' (short for structure file) is provided both as a
- demonstration of how to build derived classes from `iostream', and as
- a useful class for processing files containing fixed-record-length
- binary data. They are created with constructors with one additional
- argument declaring the size (in bytes, i.e., `sizeof' units) of the
- records. `get', will input one record, `put' will output one, and the
- `[]' operator, as in `f[i]', will position to the i'th record. If the
- file is being used mainly for random access, it is often a good idea
- to eliminate internal buffering via `setbuf' or `raw'. Here is an
- example:
-
- class record
- {
- friend class SFile;
- char c; int i; double d; // or anything at all
- };
-
- void demo()
- {
- record r;
- SFile recfile("mydatafile", sizeof(record), ios::in|ios::out);
- recfile.raw();
- for (int i = 0; i < 10; ++i) // ... write some out
- {
- r = something();
- recfile.put(&r); // use '&r' for proper coercion
- }
- for (i = 9; i >= 0; --i) // now use them in reverse order
- {
- recfile[i].get(&r);
- do_something_with(r);
- }
- }
-
- The PlotFile Class
- ==================
-
- Class `PlotFile' is a simple derived class of `ofstream' that may
- be used to produce files in Unix plot format. Public functions have
- names corresponding to those in the `plot(5)' manual entry.
-
- C standard I/O
- ==============
-
- There is a complete implementation of the ANSI C stdio library that
- is built on *top* of the iostream facilities. Specifically, the type
- `FILE' is the same as the `streambuff' class. Also, the standard
- files are identical to the standard streams: `stdin == cin.rdbuf()'.
- This means that you don't have to synchronize C++ output with C
- output. It also means that C programs can use some of the specialized
- sub-classes of streambuf.
-
- The stdio library (`libstdio++')is not normally installed, because
- of some difficulties when used with the C libraries version of stdio.
- The stdio library provides binary compatibility with traditional
- implementation. Unfortunately, it takes a fair amount of care to avoid
- duplicate definitions when linking with both `libstdio++' and the C
- library.
-
- File: libg++.info, Node: Stream, Next: Obstack, Prev: IOStream, Up: Top
-
- The old I/O library
- *******************
-
- WARNING: This chapter describes classes that are *obsolete*. These
- classes are normally not available when libg++ is installed normally.
- The sources are currently included in the distribution, and you can
- configure libg++ to use these classes instead of the new iostream
- classes. This is only a temporary measure; you should convert your
- code to use iostreams as soon as possible. The iostream classes
- provide some compatibility support, but it is very incomplete (there
- is no longer a `File' class).
-
- File-based classes
- ==================
-
- The `File' class supports basic IO on Unix files. Operations are
- based on common C stdio library functions.
-
- `File' serves as the base class for istreams, ostreams, and other
- derived classes. It contains the interface between the Unix stdio file
- library and these more structured classes. Most operations are
- implemented as simple calls to stdio functions. `File' class
- operations are also fully compatible with raw system file reads and
- writes (like the system `read' and `lseek' calls) when buffering is
- disabled (see below). The `FILE*' stdio file pointer is, however
- maintained as protected. Classes derived from File may only use the
- IO operations provided by File, which encompass essentially all stdio
- capabilities.
-
- The class contains four general kinds of functions: methods for
- binding `File's to physical Unix files, basic IO methods, file and
- buffer control methods, and methods for maintaining logical and
- physical file status.
-
- Binding and related tasks are accomplished via `File' constructors
- and destructors, and member functions `open, close, remove, filedesc,
- name, setname'.
-
- If a file name is provided in a constructor or open, it is
- maintained as class variable `nm' and is accessible via `name'. If no
- name is provided, then `nm' remains null, except that `Files' bound to
- the default files stdin, stdout, and stderr are automatically given
- the names `(stdin), (stdout), (stderr)' respectively. The function
- `setname' may be used to change the internal name of the `File'. This
- does not change the name of the physical file bound to the File.
-
- The member function `close' closes a file. The `~File' destructor
- closes a file if it is open, except that stdin, stdout, and stderr are
- flushed but left open for the system to close on program exit since
- some systems may require this, and on others it does not matter.
- `remove' closes the file, and then deletes it if possible by calling
- the system function to delete the file with the name provided in the
- `nm' field.
-
- Basic IO
- ========
-
- * `read' and `write' perform binary IO via stdio `fread' and
- `fwrite'.
-
- * `get' and `put' for chars invoke stdio `getc' and `putc' macros.
-
- * `put(const char* s)' outputs a null-terminated string via stdio
- `fputs'.
-
- * `unget' and `putback' are synonyms. Both call stdio `ungetc'.
-
- File Control
- ============
-
- `flush', `seek', `tell', and `tell' call the corresponding stdio
- functions.
-
- `flush(char)' and `fill()' call stdio `_flsbuf' and `_filbuf'
- respectively.
-
- `setbuf' is mainly useful to turn off buffering in cases where
- nonsequential binary IO is being performed. `raw' is a synonym for
- `setbuf(_IONBF)'. After a `f.raw()', using the stdio functions
- instead of the system `read, write', etc., calls entails very little
- overhead. Moreover, these become fully compatible with intermixed
- system calls (e.g., `lseek(f.filedesc(), 0, 0)'). While intermixing
- `File' and system IO calls is not at all recommended, this technique
- does allow the `File' class to be used in conjunction with other
- functions and libraries already set up to operate on file descriptors.
- `setbuf' should be called at most once after a constructor or open,
- but before any IO.
-
- File Status
- ===========
-
- File status is maintained in several ways.
-
- A `File' may be checked for accessibility via `is_open()', which
- returns true if the File is bound to a usable physical file,
- `readable()', which returns true if the File can be read from (opened
- for reading, and not in a _fail state), or `writable()', which returns
- true if the File can be written to.
-
- `File' operations return their status via two means: failure and
- success are represented via the logical state. Also, the return values
- of invoked stdio and system functions that return useful numeric
- values (not just failure/success flags) are held in a class variable
- accessible via `iocount'. (This is useful, for example, in
- determining the number of items actually read by the `read' function.)
-
- Like the AT&T i/o-stream classes, but unlike the description in the
- Stroustrup book, p238, `rdstate()' returns the bitwise OR of `_eof',
- `_fail' and `_bad', not necessarily distinct values. The functions
- `eof()', `fail()', `bad()', and `good()' can be used to test for each
- of these conditions independently.
-
- `_fail' becomes set for any input operation that could not read in
- the desired data, and for other failed operations. As with all Unix
- IO, `_eof' becomes true only when an input operations fails because of
- an end of file. Therefore, `_eof' is not immediately true after the
- last successful read of a file, but only after one final read attempt.
- Thus, for input operations, `_fail' and `_eof' almost always become
- true at the same time. `bad' is set for unbound files, and may also
- be set by applications in order to communicate input corruption.
- Conversely, `_good' is defined as 0 and is returned by `rdstate()' if
- all is well.
-
- The state may be modified via `clear(flag)', which, despite its
- name, sets the corresponding state_value flag. `clear()' with no
- arguments resets the state to `_good'. `failif(int cond)' sets the
- state to `_fail' only if `cond' is true.
-
- Errors occuring during constructors and file opens also invoke the
- function `error'. `error' in turn calls a resetable error handling
- function pointed to by the non-member global variable
- `File_error_handler' only if a system error has been generated. Since
- `error' cannot tell if the current system error is actually
- responsible for a failure, it may at times print out spurious messages.
- Three error handlers are provided. The default,
- `verbose_File_error_handler' calls the system function `perror' to
- print the corresponding error message on standard error, and then
- returns to the caller. `quiet_File_error_handler' does nothing, and
- simply returns. `fatal_File_error_handler' prints the error and then
- aborts execution. These three handlers, or any other user-defined
- error handlers can be selected via the non-member function
- `set_File_error_handler'.
-
- All read and write operations communicate either logical or
- physical failure by setting the `_fail' flag. All further operations
- are blocked if the state is in a `_fail' or`_bad' condition.
- Programmers must explicitly use `clear()' to reset the state in order
- to continue IO processing after either a logical or physical failure.
- C programmers who are unfamiliar with these conventions should note
- that, unlike the stdio library, `File' functions indicate IO success,
- status, or failure solely through the state, not via return values of
- the functions. The `void*' operator or `rdstate()' may be used to
- test success. In particular, according to c++ conversion rules, the
- `void*' coercion is automatically applied whenever the `File&' return
- value of any `File' function is tested in an `if' or `while'. Thus,
- for example, an easy way to copy all of stdin to stdout until eof (at
- which point `get' fails) or some error is `char c; while(cin.get(c) &&
- cout.put(c));'.
-
- The current version of istreams and ostreams differs significantly
- from previous versions in order to obtain compatibility with AT&T 1.2
- streams. Most code using previous versions should still work. However,
- the following features of `File' are not incorporated in streams (they
- are still present in `File'): `scan(const char* fmt...), remove(),
- read(), write(), setbuf(), raw()'. Additionally, the feature of
- previous streams that allowed free intermixing of stream and stdio
- input and output is no longer guaranteed to always behave as desired.
-