6. Basics: Streams and SequencesBack to Table of Contents It is often useful to perform some operation iteratively over the constituent parts of an object; for example, one might want to examine the properties of each atom or bond of a molecule. Two special object types, the stream and the sequence, provide a mechanism for doing this conveniently. Conceptually, a stream or a sequence is an ordered group of objects with a current position in the order. (Note: To clarify this concept, it is not the same as a set, since one object can appear several times; nor is it like LISP's list, as sequences can't be appended to one another, and there is no concept of the "tail" of a sequence being a valid sequence.)
6.1 Properties
6.1.1 Stream PropertiesStreams are used to enumerate the constituent parts of complex objects such as molecules, and are often the only way these constituent parts can be accessed. For example, if m is a molecule object, invoking atoms = dt_stream(m, TYP_ATOM)returns a stream containing all of the atoms in the molecule. Streams are deliberately limited in their capabilities in order to make them "cheap" (creating a stream of atoms as illustrated above takes very little computing time). In addition to the polymorphic functions that apply to all objects (described in the chapter entitled POLYMORPHIC FUNCTIONS), there are only four operations on streams:
Streams usually have a base object -- the object from which they are derived (see dt_base()). Most streams have one base object, and are deallocated if the base object is changed in a way that makes the stream invalid. For example, a stream of atoms from a molecule is deallocated if a new atom or bond is added to the molecule. Streams have several important properties:
6.1.2Sequence PropertiesThe properties of a sequence are a superset of stream properties; in addition to those listed above, sequences can perform the following operations:
6.1.3 ExampleThe following short code fragment illustrates how one might create both a stream and a sequence. Both the stream and the sequence will contain all the atom-objects from the molecule, but the sequence can later be modified if desired (the function dt_smilin() is documented in a later chapter). #include <dt_smiles.h> ... char smiles[20]; dt_Handle strm, seq, mol, atom; /**** create a stream of the atoms in benzene ****/ strcpy(smiles, "c1ccccc1"); mol = dt_smilin(strlen(smiles), smiles); strm = dt_stream(mol,TYP_ATOM); /**** copy the atoms from the stream into a sequence ****/ seq = dt_alloc_seq(); while (NULL_OB != (atom = dt_next(strm))) dt_append(seq, atom); ...Several other example programs that make use of sequences are supplied in the Daylight "contrib" directory ($DY_ROOT/contrib). 6.2 Functions on Streams and Sequences
6.3 Functions on Sequences OnlyThe following functions only apply to sequences; they modify a sequence or otherwise perform "direct access" to the objects it contains. These functions use the concept of a current object. The current object is the one that was most recently returned by dt_next(). When dt_reset() is called, the current object is thought to be an imaginary object before the first actual object; if the dt_next() reaches the end of the sequence, the current object is thought to be an imaginary object after the last object of the sequence.
6.4 An ExampleThe following C function returns the number of protons in an object. Some of the power of streams and the object-like approach is illustrated by the fact that object can be a molecule, atom, bond, or cycle. In each case, the number of protons associated with the object will be returned. For example, for an atom, the number of protons in the atom will be returned; for a bond, the sum of the protons in the atoms it joins will be returned; for a cycle, the sum of the protons in the atoms of the cycle will be returned; for a molecule, the number of protons in the whole molecule will be returned. Note also that if ob is not of an appropriate type (e.g. NULL_OB, or perhaps a string object), the function will correctly and quickly return zero. proton_count(dt_Handle ob) { dt_Handle atoms, atom; int pcount; atoms = dt_stream(ob, TYP_ATOM); pcount = 0; while (NULL_OB != (atom = dt_next(atoms))) pcount += dt_number(atom) + dt_imp_hcount(atom); dt_dealloc(atoms); return pcount; /* return result */ }Back to Table of Contents Go to previous chapter Basics: Strings and Number Objects Go to next chapter Molecules. |