home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-04-01 | 258.8 KB | 9,280 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave
-
- Tools.h++
-
- Class Library
-
- Version 4.0
-
-
-
-
-
-
-
-
-
-
-
-
- License Agreement
-
- c Copyright Rogue Wave Associates, 1989, 1990, 1991.
-
-
- This software package and its documentation are subject to the
- following license agreement. By opening the diskette package seal,
- you are implicitly accepting these terms and conditions.
-
- Permission is given to the buyer of this package to use this software
- on one computer at a time, make one backup copy, and make one printed
- copy of the source code. You may utilize and/or modify this program
- for use in your projects. You may distribute and sell any executable
- which results from using this code in your applications, except a
- utility program of similar nature to this product. You may NOT
- redistribute the source code or resultant object modules or libraries
- of object modules in any form, put it on a bulletin board system, or
- sell it. You may not use, copy, modify, merge, or transfer the
- program, or manual or any portion of the program or manual, except as
- expressly provided above in this agreement.
-
- A multi-user license may be purchased to allow the software to be
- used on more than one computer at the same time; including a shared
- disk system. Contact Rogue Wave for information on site licenses.
-
- This material is sold "as is". Rogue Wave makes no warranties, either
- expressed or implied, regarding the enclosed computer software
- package, its merchantability, or its fitness for any particular
- purpose. Information in this document is subject to change without
- notice and does not represent a commitment on the part of Rogue Wave
- . While every effort is made to insure that the above mentioned
- product and its documentation are free of defects, Rogue Wave shall
- not be held responsible for any loss of profit or any other
- commercial damage, including but not limited to special, incidental,
- consequential or other damages occasioned by the use of this product.
-
- It is assumed that purchasers of this product are familiar with basic
- programming skills (e.g., setting up a path with MS-DOS). This is a
- highly technical product, offered in a rapidly evolving programming
- environment. Rogue Wave recognizes this fact, and will provide
- limited support to purchasers of this product for 60 days after its
- purchase (of course, bug reports and comments are always welcome).
- Questions and comments may be submitted either by mail or telephone.
- Rogue Wave reserves the right to respond to questions or comments in
- writing or by telephone.
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave acknowledges all trademarks found in this manual and in the source
- code documentation. This acknowledgement includes, but is not limited to:
- AT&T/UNIX, Microsoft, MS-DOS, Zortech, Borland, Oregon Software, HCR,
- ParcPlace, Smalltalk-80, SCO, Free Software Foundation, Glockenspiel,
- Windows.
-
-
-
-
-
-
-
-
-
-
- Table of Contents
-
- PART I
-
-
- 1. Introduction....................................................1
- 1.1 Overview and features....................................1
- 1.2 Supported compilers......................................4
- 1.3 Philosophy ............................................4
- 1.4 Conventions ............................................5
- 1.5 Reading this manual......................................6
-
- 2. Installation....................................................9
- 2.1 Installation overview....................................9
- 2.2 Installation: MS-DOS..........................11
- 2.2.1 Installation: Zortech.........................13
- 2.2.2 Installation: Glockenspiel....................13
- 2.3 Recompiling the library: MS-DOS.........................14
- 2.3.1 Borland.......................................15
- 2.3.2 Zortech.......................................16
- 2.3.3 Glockenspiel..................................17
- 2.4 Recompiling and installation: Unix......................17
- 2.4.1 AT&T..........................................19
- 2.4.2 Oregon Software...............................19
- 2.4.3 All Unix compilers............................19
- 2.5 Working with the Rogue Wave Math.h++ library............20
- 2.6 Recompiling the library: Creating a debug version.......20
-
- 3. Compiling Programs............................................21
- 3.1 Header files ...........................................21
- 3.2 Compiling a program.....................................25
- 3.2.1 Compiling a program: DOS......................26
- 3.2.1.1 Compiling a program: Borland ..............26
- 3.2.1.2 Using the Tools.h++ DLL with Borland C++ ..26
- 3.2.1.3 Compiling a program: Zortech ..............27
- 3.2.1.4 Compiling a program: Glockenspiel .........29
- 3.2.2 Compiling a program: Unix.....................29
- 3.2.2.1 Compiling a program: AT&T .................29
-
- 4. Stream I/O.....................................................31
-
- 5. Class Overview.................................................33
-
-
- Rogue Wave Tools.h++ Class Library i
-
-
-
-
-
-
-
-
-
-
- 5.1 Common member functions.................................34
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Tools.h++ Class Library ii
-
-
-
-
-
-
-
-
-
-
-
- 6. Using Class RWString...........................................39
- 6.1 Example ...........................................39
- 6.2 Reference counting......................................40
- 6.3 Member functions........................................43
- 6.4 SubStrings: ...........................................44
- 6.5 Pattern matching........................................44
- 6.5.1 Regular expressions...........................45
- 6.6 Tokenizer ...........................................47
-
- 7. Using Class RWDate.............................................49
- 7.1 Constructors ...........................................49
- 7.2 Member functions........................................50
- 7.3 Example ...........................................50
-
- 8. Using Class RWTime.............................................51
- 8.1 Setting the time zone...................................51
- 8.2 Constructors ...........................................53
- 8.3 Member functions........................................53
-
- 9. Virtual Streams................................................55
- 9.1 Specializing virtual streams............................58
- 9.2 Simple example..........................................58
- 9.3 Windows_ Clipboard and DDE streambufs...................61
- 9.4 DDE example ...........................................61
- 9.5 Recap ...........................................63
-
- 10. Using Class RWFile............................................65
- 10.1 Example ...........................................65
-
- 11. Using Class RWFileManager.....................................67
- 11.1 Construction ...........................................67
- 11.2 Member functions........................................68
-
- 12. Using Class RWBTreeOnDisk.....................................73
- 12.1 Construction ...........................................75
- 12.2 Example ...........................................75
-
- 13. Introduction to Collection Classes............................79
- 13.1 Introduction ...........................................79
- 13.1.1 Some general concepts.........................79
- 13.1.1.1An object's identity ......................80
-
-
- Rogue Wave Tools.h++ Class Library iii
-
-
-
-
-
-
-
-
-
-
- 13.1.1.2Shallow versus deep copies ................82
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Tools.h++ Class Library iv
-
-
-
-
-
-
-
-
-
-
-
- 14. "Generic" Collection Classes..................................85
- 14.1 Example ...........................................86
- 14.2 Declaring generic collection classes....................88
- 14.3 User-defined functions..................................88
- 14.3.1 Tester functions..............................89
- 14.3.2 Apply functions...............................92
-
- 15. Smalltalk_-like Collection Classes............................95
- 15.1 Introduction ...........................................95
- 15.2 Example ..........................................101
- 15.3 Virtual functions inherited from RWCollection..........103
- 15.3.1 insert().....................................103
- 15.3.2 find() and friends...........................103
- 15.3.3 remove() functions...........................106
- 15.3.4 apply() functions............................107
- 15.3.5 Functions clear()............................108
- 15.4 Other functions shared by all RWCollections............108
- 15.4.1 Class conversions............................108
- 15.4.2 Inserting and removing other collections.....108
- 15.4.3 Selection....................................109
- 15.5 Virtual functions inherited from RWSequenceable........109
- 15.6 Iterators ..........................................111
- 15.7 Dictionaries ..........................................112
- 15.8 A note on how objects are found........................114
- 15.8.1 Hash collections.............................114
- 15.9 Storage and retrieval of "Collectable" objects.........116
- 15.10 Designing an RWCollectable class..................120
- 15.10.1 Virtual functions inherited from RWCollectable120
- 15.10.2 An example...................................121
- 15.10.3 Object destruction...........................123
- 15.10.4 Virtual function isA().......................123
- 15.10.5 Virtual function compareTo().................123
- 15.10.6 Virtual function isEqual()...................125
- 15.10.7 Virtual function hash()......................126
- 15.10.8 Virtual function newSpecies()................127
- 15.10.9 Virtual functions saveGuts(RWFile&) and
- saveGuts(RWvostream&)........................127
- 15.10.10 Virtual functions restoreGuts(RWFile&) and
- restoreGuts(RWvistream&).....................127
- 15.10.11 Putting it all together......................128
- 15.10.12 Summary......................................131
-
-
- Rogue Wave Tools.h++ Class Library v
-
-
-
-
-
-
-
-
-
-
- 15.11 More on storing and retrieving RWCollectables 131
- 15.11.1 Reading and writing collections..............135
- 15.12 Architectural notes .......................135
- 16. Implementation Notes.........................................139
- 16.1 Errors.......................................139
- 16.1.1 Violated preconditions.......................139
- 16.1.2 Invalid input................................140
- 16.1.3 Asynchronous errors..........................141
- 16.1.4 Changing the default error handler...........143
- 16.1.5 Error numbers and messages...................143
- 16.2 Dynamic Link Library...................................144
- 16.2.1 Example......................................144
- 17. Examples.....................................................157
- 17.1 Example 1: The RWTime and RWDate classes .............157
- 17.2 Example 2: The RWString class ........................158
- 17.3 Example 3: GDlist - A class for generic
- doubly-linked lists .......................158
- 17.4 Example 4: RWBinaryTree - A sorted collection of
- RWCollectableStrings ......................158
- 17.5 Example 5: RWHashDictionary - A dictionary of
- keys and values ...........................161
- 17.6 Example 6: RWBTreeOnDisk .............................161
- 17.7 Example7 & 8: Class RWFileManager.....................162
-
- Part II
- Class Reference..................................................165
- GBitVec(size) .............................................167
- GDlist(type) ..........................................171
- GDlistIterator(type)........................................176
- GQueue(type) ..........................................179
- GSlist(type) ..........................................182
- GSlistIterator(type)........................................186
- GSortedVector(val)..........................................189
- GStack(type) ..........................................193
- GVector(val) ..........................................196
- RWBag ..........................................198
- RWBagIterator ..........................................202
- RWBinaryTree ..........................................204
- RWBinaryTreeIterator........................................208
- RWbistream ..........................................210
- RWBitVec ..........................................215
- RWbostream ..........................................221
-
-
- Rogue Wave Tools.h++ Class Library vi
-
-
-
-
-
-
-
-
-
-
- RWBTree ..........................................225
- RWBTreeDictionary ..........................................229
- RWBTreeOnDisk ..........................................233
- RWCacheManager ..........................................236
- RWCLIPstreambuf ..........................................239
- RWCollectable ..........................................242
- RWCollectableDate ..........................................246
- RWCollectableInt ..........................................248
- RWCollectableString.........................................251
- RWCollectableTime ..........................................253
- RWCollection ..........................................255
- RWDate ..........................................260
- RWDDEstreambuf ..........................................267
- RWDlistCollectables.........................................273
- RWDlistCollectablesIterator.................................278
- RWErrObject ..........................................281
- RWFactory ..........................................284
- RWFile ..........................................286
- RWFileManager ..........................................290
- RWHashDictionary ..........................................292
- RWHashDictionaryIterator....................................296
- RWIdentityDictionary........................................298
- RWIdentitySet ..........................................299
- RWInteger ..........................................300
- RWIterator ..........................................302
- RWOrdered ..........................................303
- RWOrderedIterator ..........................................307
- RWpistream ..........................................308
- RWpostream ..........................................314
- RWRegexp ..........................................319
- RWSequenceable ..........................................323
- RWSet ..........................................325
- RWSetIterator ..........................................329
- RWSlistCollectables.........................................331
- RWSlistCollectablesIterator.................................336
- RWSlistCollectablesQueue....................................339
- RWSlistCollectablesStack....................................342
- RWSortedVector ..........................................345
- RWString ..........................................350
- RWSubString ..........................................359
- RWTime ..........................................363
- RWTokenizer ..........................................368
-
-
- Rogue Wave Tools.h++ Class Library vii
-
-
-
-
-
-
-
-
-
-
- RWvistream ..........................................370
- RWvostream ..........................................374
- Appendix A: Summary of typedefs and macros......................379
- Appendix B: Bibliography........................................381
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Tools.h++ Class Library viii
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1
-
-
- Introduction
-
-
-
-
- 1.1 Overview and features
-
-
-
- The Rogue Wave Tools.h++ Class Library is a set of C++ classes that
- can greatly simplify your programming while maintaining the
- efficiency for which C is famous. The package includes:
-
-
- l Smalltalk -like collection classes:
- A complete library of collection classes, modeled after the
- Smalltalk-80 programming environment: Set, Bag,
- OrderedCollection, SortedCollection, Dictionary, Stack, Queue,
- etc. All of these classes can be saved to disk and restored in a
- new address space, even on a different operating system! An
- object need only inherit the abstract base class RWCollectable to
- have full access to all of the functionality of the collection
- classes. The interface to the Smalltalk names is done as
- typedefs, allowing the actual implementation of, say, a
- Dictionary to be changed from its default of a hash table of
- associations, to, say, a B-Tree.
-
- l Generic collection classes
- Singly and doubly-linked lists, stacks, queues and vectors, using
- <generic.h>, the current C++ approximation to parameterized
- types.
-
- l RWFile Class
- Encapsulates standard file operations.
-
-
- Rogue Wave Introduction 1
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- l B-Tree disk retrieval
- Efficient keyed access of disk records, using B-Trees.
-
- l File Space Manager
- Allocates, deallocates and coalesces free space within a file.
-
- l String and character manipulation
- Class RWString offers a full suite of operators and functions to
- manipulate character strings, including concatenation,
- comparison, indexing (with optional bounds checking), I/O, case
- changes, stripping, and many other functions. Class RWSubString
- is available for extraction and assignment to substrings. Class
- RWRegexp implements pattern searches. Class RWTokenizer can be
- used to break strings into separate tokens.
-
- l Time and date handling classes
- Calculate the number of days between two dates, or the day of the
- week a date represents; read and write days or times in arbitrary
- formats; etc.
-
- l Still more classes...
- Bit vectors, virtual I/O streams, caching managers, ... a
- complete toolbox!
-
- l Persistent store
- A powerful and sophisticated persistent store facility that
- allows complex objects to be stored to disk or even exchanged
- through a heterogeneous network or Windows 3.0's Dynamic Data
- Exchange. The object's morphology (e.g., multiple pointers to
- the same object, or a circularly linked list) can be maintained.
-
- l A complete error handling facility
- Including a facility for handling exceptions, when they become
- available.
-
- l Microsoft Windows_ support:
-
- Specialized stream I/O classes for use with Windows Clipboard and
- DDE
- Allows the use of I/O streams, including Rogue Wave's virtual
- streams, to exchange data through the Clipboard or DDE facility.
-
-
-
- Rogue Wave Introduction 2
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- DLL version
- A Dynamic Link Library (DLL) version of Tools.h++ comes on the
- standard distribution disk. Classes and methods are dynamically
- linked to your code, decreasing the size of your executable.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Introduction 3
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 1.2 Supported compilers
-
-
-
- The Classes can be compiled without modification by a wide variety of
- C++ compilers:
-
- MS-DOS: Borland Turbo C++ V1.01 or greater
-
- Borland C++ V2.0 or greater
-
- Zortech V2.10 or greater
-
- Jensen and Partner's TopSpeed C++
-
- Glockenspiel V2.0c (DOS) or greater
-
- UNIX: Oregon Software V2.0 or greater
-
- Other AT&T V 2.0- or V2.1-compatible compilers
-
- Usually all that is required to port Tools.h++ to another compiler is
- to modify an appropriate makefile.
-
-
- 1.3 Philosophy
-
-
-
- The C++ language has several design goals that set it apart from most
- other object-oriented languages. The first and foremost is
- efficiency: it is possible to write production quality code that is
- every bit as efficient and small as code that has been written in C,
- yet more maintainable. A second is a "less is more" philosophy: no
- feature has been included in the language that will make non-users of
- the feature suffer. For example, you will not find built-in
- exception handling or garbage collection. The result is a skeletal,
- lean-and-mean language (at least as far as object-oriented languages
- go) that compiles fast and results in small, efficient, but not
- terribly general, code.
-
-
-
- Rogue Wave Introduction 4
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Towards getting the best out of the language, the Rogue Wave
- Tools.h++ class library has adopted similar goals: Efficiency,
- simplicity, compactness, and predictability.
-
- Efficiency. In general, you will find no feature that will slow
- things down for the non-user of the feature. As many decisions as
- possible are made at compile time, consistent with the C++ philosophy
- of static type checking. In most cases, we offer a choice between
- classes with extreme simplicity, but little generality, and classes
- that are a little more complex, but more general. We have chosen not
- to require that all classes inherit a secular base class (such as the
- class Object used by Smalltalk and The NIH Classes). Instead, only
- objects that are to be collected using the Smalltalk-like collection
- classes need inherit a base class RWCollectable. The advantage of
- this is that virtual base classes are not necessary, simplifying the
- inheritance tree and the difficult problem of casting from a base
- class back to its derived class.
-
- Simplicity. There is a temptation to keep adding subclasses to add
- power or convenience for the user or to demonstrate one's prowess
- with the language. We have avoided this. Although the overall
- architecture is sophisticated and integrated, each class usually
- plays just one well-defined, pivotal role. Most functions are
- extraordinarily simple: a few lines of code.
-
- Compactness. An important goal was to make sure that programs
- compiled small. This was to insure that they can be used in embedded
- systems or under MS-DOS.
-
- Predictability. Many new users of C++ become so giddy with the power
- of being able to overload esoteric operators like "&=" that they
- forget about tried-and-true function calls and start redefining
- everything in sight. Again, we have avoided this and have tried hard
- to make all of the familiar operators work just as you might expect -
- - there are no surprises. This approach gives great symmetry to the
- class library, making it possible to do such things as, say, change
- the implementation of a Dictionary from a hash table to a B-Tree with
- impunity.
-
- In general, whenever we considered a new feature, we tried to think
- as Stroustrup would: if there was already a way to do it, we left it
- out!
-
-
- Rogue Wave Introduction 5
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 1.4 Conventions
-
-
-
- All Rogue Wave class names (except generic classes) start with the
- letters "RW". All function names start with a lower case letter, but
- subsequent words are capitalized. There are no underline characters
- used in names. An example of a class name is RWHashDictionary, of a
- function compareTo(). Generally, abbreviations are not used in
- function names, making them easy to remember.
-
- Some of the class names may seem unnecessarily tedious (for example,
- a singly-linked list of collectables, accessible as a stack, is a
- RWSlistCollectablesStack). There are two reasons for this. First,
- using generic names like "Stack" invites a name collision with
- someone else's stack class, should you write a large program that
- combines many class libraries. We have tried very hard to avoid
- polluting the global name space with generic names like "String",
- "Vector", "Stack", etc. It is also for this reason (and not
- megalomania!) that class names and many of the potentially generic
- names have an "RW" prepended (e.g., "RWBoolean"). We have worked
- hard to make sure that Tools.h++ is compatible with other class
- libraries. Secondly, the names are intended to convey as precisely
- as possible what the class does.
-
- Nevertheless, there are a set of typedefs that give these various
- classes generic names like Stack or OrderedCollection that are
- consistent with the Smalltalk-80 names. These typedefs can easily be
- changed if there is a problem with duplicate names.
-
-
- 1.5 Reading this manual
-
-
-
- This manual is intended to serve two purposes: to be an introduction
- to using the Rogue Wave Tools.h++ Class Library and to be an
- intermediate-level tutorial on the language C++, using the Class
- Library as an aid to discussing some of the more subtle aspects of
- C++. It assumes that you are familiar with the basics of C++, but
- not yet an expert. The discussion is generally more detailed than
-
-
- Rogue Wave Introduction 6
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- what is necessary to actually use the library -- if you find yourself
- getting overwhelmed by details, by all means, abandon the coming
- sections and rely on the many examples of Section 15.
-
- If you are not familiar with C++ at all, we do not recommend trying
- to learn it from the three definitive reference books available:
- Stroustrup (1986), Lippman (1989), and Ellis and Stroustrup (1990;
- sometimes ominously referred to as "The ARM" -- Annotated Reference
- Manual). Their terse (but precise) style make them better suited as
- references to the language. i.Reference books;The best introductory
- books that we have seen are Weiskamp and Flamig (1990) and Eckel
- (1989), although both are weak in discussing V2.X features of C++.
-
- In what follows, there are several references to Stroustrup and
- Lippman's books -- it may be helpful to have a copy available.
-
- Occasionally there will be a highlighted paragraph explaining either
- a key point, or "An Aside". The latter can be ignored safely without
- losing the essential thread of the discussion.
-
- Throughout this manual, examples, operating system commands, and code
- fragments are shown in a courier font. Class names are shown in a
- Helvetica font. Vertical ellipses are used to indicate that some
- part of the code is missing:
-
-
- main()
- {
- .
- . // Something happens
- .
- }
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Introduction 7
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 2
-
-
- InstallationInstallation
-
-
-
-
- 2.1 Installation overview
-
-
-
- As of this writing, Tools.h++ comes on two diskettes. This could
- change. Included in the standard distribution is:
-
- o Header files;
-
- o C++ source code and appropriate makefiles;
-
- o A Borland Turbo C++ V1.01 precompiled library, using the large
- memory model;
-
- o A Borland C++ V2.0 precompiled library, using the large memory
- model;
-
- o A Zortech V2.18 (DOS) precompiled library, using the large memory
- model;
-
- o A Glockenspiel V2.0c (DOS) precompiled library, using the large
- memory model;
-
- o A Borland C++ V2.0 precompiled Windows DLL, using the large
- memory model.
-
- As new C++ compilers come on the market, additional precompiled
- libraries may be added.
-
- Makefiles have been supplied for both the MS-DOS and Unix operating
- systems and for all compilers. They will automatically take care of
- Rogue Wave Installation 9
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- a lot of the details involved in building or rebuilding the
- libraries.
-
- All C++ source code has a suffix of .cpp for all compilers and both
- operating systems. Because not all compilers expect this suffix,
- provisions have been made in the appropriate makefile to compensate.
- There is no need to rename any of the files when porting between
- operating systems or compilers.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Installation 10
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 2.2 Installation: MS-DOS
-
-
-
- Put the first diskette in the appropriate floppy disk drive and type:
-
- a:install
-
- Here "a:" has been used as the floppy drive. Substitute as
- appropriate. Follow the instructions on the screen.
-
- You will be left with five subdirectories:
-
- c:\rogue\rw
- Header files;
-
- c:\rogue\toolsrc
- Tools.h++ source code and makefiles;
-
- c:\rogue\lib
- A directory containing the precompiled libraries and DLL;
-
- c:\rogue\toolexam
- Tools.h++ sample programs;
-
- c:\rogue\dlldemo
- Windows 3.0 demonstration program that uses the Tools.h++ DLL.
-
-
-
- Compiler makefile name Precompiled DOS
- library
-
-
- Zortech makefile.ztc ztll.lib
-
- Borland Turbo C++ makefile.tcc ttll.lib
-
- Borland C++ makefile.tcc ttll.lib
-
- Glockenspiel makefile.glk gtll.lib
-
-
- Rogue Wave Installation 11
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Oregon Software makefile.occ (n/a)
-
- AT&T and compatibles makefile.att (n/a)
- under Unix
-
-
-
-
- Table 2-1. Compiler manufacturer and corresponding makefiles and
- precompiled libraries. Note that the Unix compilers do not come with
- a precompiled library.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Installation 12
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 2.2.1 Installation: Zortech
-
- One additional step must be done to install Tools.h++ for use by the
- Zortech compiler:
-
-
-
- IMPORTANT! Before starting, make a copy of the Zortech include file
- stream.hpp and call it stream.h, and a copy of generic.hpp and call
- it generic.h.
-
-
- For example:
-
- cd \zortech\include
- copy stream.hpp stream.h
- copy generic.hpp generic.h
-
- We have chosen to follow the lead set by Bjarne Stroustrup in his
- definitive reference manual (and followed by other compiler
- manufacturers) in calling the streams file "stream.h" and the generic
- header file "generic.h". Users of Zortech should be aware that
- Zortech is non-standard in this regard.
-
-
- 2.2.2 Installation: Glockenspiel
-
- Under MS-DOS, Tools.h++ will only work with V2.0c or greater of the
- Glockenspiel compiler, using Microsoft C 6.0 as the backend C
- compiler.
-
- To install the Tools.h++ Class Library for use with the Glockenspiel
- compiler, there are a few additional steps that you must take:
-
- 1. You must make versions of all your include files with suffixes of
- .h, instead of .hpp. For example:
-
- cd \cxx20\include
- copy generic.h++ generic.h
- copy iostream.h++ iostream.h
- etc.
-
- There is no "official" standard for the suffix of a C++ header
- Rogue Wave Installation 13
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- file. But, AT&T uses .h and it's their compiler. Most other
- manufacturers have followed suit. You will increase your
- portability by doing this step.
-
- 2. You must uncomment the following line in <compiler.h>:
-
- /* #define __MSDOS__ 1 */ /* For MS-DOS */
-
- 3. As per the Glockenspiel installation instructions, you must
- change the member "class" (a reserved keyword in C++) of the
- structure DOSERROR in <DOS.H> to something else. They suggest
- changing it to err_class.
-
- 4. Make sure you also read the directions in Section 3.2.1.4
- "Compiling a program: Glockenspiel"
-
-
- 2.3 Recompiling the library: MS-DOS
-
-
-
- If you wish to use a memory model other than large, or if you are
- using a compiler / version combination other than those for which a
- precompiled library is available, you will have to recompile the
- library. This is an easy chore that takes about 10 minutes on a
- modest 386, about 30 minutes on a 286. Start by using an appropriate
- makefile for you compiler, listed in Table 2-1. Specific
- instructions are given below.
-
- The resulting library name is coded as follows:
-
- ctlmwg.lib where:
-
- c Codes the compiler manufacturer: (t) Borland; (g) Glockenspiel;
- (z) Zortech.
-
- m Codes the memory model: (s) small; (c) compact; (m) medium; (l)
- large.
-
- w Codes whether it is a windows library: (absent) regular DOS
- library; (w) Windows auxilary library; (d) Windows DLL import
- library.
-
- g Codes whether it is a "debug" version of the library: (absent)
- Rogue Wave Installation 14
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- regular version; (g) debug.
-
-
- 2.3.1 Borland Turbo C++ and Borland C++
-
- The classes come with precompiled Turbo C++ and Borland C++
- libraries. Both use the large memory model. Should you wish to
- switch compilers or recompile using different compiler options, you
- will have to recompile. Note that binaries created with Turbo C++
- are almost, but (unfortunately) not quite, upwardly compatible with
- Borland C++. The difference is that a few member functions in the
- iostream facility were not inlined in Turbo C++ but were inlined in
- Borland C++, resulting in linker undefined reference errors when
- using the latter.
-
- Here's how to recompile Tools.h++, using the Borland compilers:
-
- 1. Be sure to use the Borland make command. In particular, the
- Microsoft make will not work.
-
- 2. If you are changing the memory model or switching between Turbo
- C++ and Borland C++, any old object modules should be removed.
- The makefile has an entry for this:
-
- make -fmakefile.tcc clean
-
- 3. Note that both the Turbo C++ and Borland C++ use the same
- makefile: makefile.tcc. Find the makefile macro CPP in this file
- and change it to reflect the compiler you wish to use. For
- example, to use Turbo C++, select:
-
- CPP= tcc
-
- To use Borland C++, select:
-
- CPP= bcc
-
- 4. Check makefile.tcc for the memory model you want. For example,
- if you wanted to compile with the medium memory model (large
- code, small data), the appropriate macro definition would be:
-
- MEMMODEL= m
-
- 5. Type:
- Rogue Wave Installation 15
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- make -fmakefile.tcc
-
- The result would be a library named ttlm.lib in the lib subdirectory.
-
-
- 2.3.2 Zortech
-
- The classes come with a precompiled library called ztll.lib that uses
- the Zortech large memory model. Should you wish to recompile using
- different compiler options or to make a change in the classes, you
- will have to recompile.
-
- Here's how:
-
- 1. Be sure to have read the directions in Section 2.2.1,
- Installation: Zortech.
-
- 2. Be sure to use the Zortech make command. In particular, the
- Microsoft make will not work.
-
- 3. If you are changing the memory model any old object modules
- should be removed. The makefile has an entry for this:
-
- make -f makefile.ztc clean
-
- 4. Check the top of makefile.ztc for the memory model that you want.
- For example, if you wanted to recompile with the medium memory
- model (large code, small data), the appropriate macro definitions
- would be:
-
- MEMMODEL= m
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Installation 16
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 5. Type:
-
- make -f makefile.ztc
-
- The result would be a library named ztlm.lib in the lib subdirectory.
-
-
- 2.3.3 Glockenspiel
-
- The classes come with a precompiled Glockenspiel library called
- gtll.lib that uses the Glockenspiel large memory model. Should you
- wish to recompile using different compiler options or to make a
- change in the classes, you will have to recompile.
-
- Here's how:
-
- 1. Be sure to have read the directions in Section 2.2.2,
- Installation: Glockenspiel.
-
- 2. Be sure to use the Microsoft nmk command.
-
- 3. If you are changing the memory model, any old object modules
- should be removed. The makefile has an entry for this:
-
- nmk -f makefile.glk clean
-
- 4. Check the top of makefile.glk for the memory model that you want.
- For example, if you wanted to recompile with the medium memory
- model (large code, small data), the appropriate macro definitions
- would be:
-
- MEMMODEL= m
-
- 5. Type:
-
- nmk -f makefile.glk
-
- The result would be a library named gtlm.lib in the lib subdirectory.
-
-
- 2.4 Recompiling and installation: Unix
-
-
-
- Rogue Wave Installation 17
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Because of the wide variety of hardware that supports Unix, it is
- impossible to provide precompiled libraries. Instead, they must be
- built from source.
-
- If you have not specified custom formatting, you will have to first
- follow the MS-DOS installation instructions above and then transfer
- the directory contents to your Unix host.
-
- The installation procedure is done from the toolsrc subdirectory.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Installation 18
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 2.4.1 AT&T compilers, including SCO (nee HCR), Glockenspiel, and Oasys
- compilers
-
- 1. You should use the makefile "makefile.att".
-
- 2. Check the tail end of makefile.att ("Conversions") to make sure
- that it is expecting the proper suffixes for your CC driver. The
- makefile.att has been set up to assume that the driver accepts .C
- and puts out .o. Yours may differ. Note that you do NOT have to
- change the names of the source files.
-
- 3. You will have to set your environment variables as usual.
-
-
- 2.4.2 Oregon Software compiler
-
- You should use the makefile "makefile.occ".
-
-
- 2.4.3 All Unix compilers
-
- 1. Make sure you are in the toolsrc subdirectory and type make with
- the name of the appropriate makefile as an argument:
-
- cd toolsrc
- make -f makefile.xxx
-
- 2. To make the example programs:
-
- cd ../toolexam
- make -f makefile.xxx
-
- 3. Finally, to install the package, check the makefile macros
- LIBDIR, and INCLDIR to see if the default installation locations
- suit you, then from the toolsrc subdirectory type:
-
- make -f makefile.xxx install
-
- 4. The resulting library will be installed in LIBDIR and named
- librwtool.a. The header files will be installed in INCLDIR.
-
-
-
- Rogue Wave Installation 19
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 2.5 Working with the Rogue Wave Math.h++ library
-
-
-
- The Rogue Wave Tools.h++ and Math.h++ class libraries are completely
- compatible. They use many of the same member function names and are
- designed to coexist. Both libraries put their header files in the
- subdirectory \rogue\rw and their compiled libraries in \rogue\lib.
-
-
- 2.6 Recompiling the library: Creating a debug version
-
-
-
- It is possible to create a "debug" version of the library. See
- Section 16.1.1 for additional information. If you do so, the name of
- the library will have a "g" appended to it. For example, a large
- model library using the Borland C++ compiler and with debugging
- options on, would be called "ttllg.lib".
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Installation 20
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 3
-
-
- Compiling Programs
-
-
-
- This section will tell you how to compile a program using the Rogue
- Wave Tools.h++ Class Library.Compiling a program
-
-
- 3.1 Header files
-
-
-
- All of the Rogue Wave header files have lower-case names for ease of
- porting between MS-DOS and UNIX. See Table 3-1 for a list of all of
- the classes, their type, and which header file must be included to
- use them.
-
-
-
-
-
- Generic class Description Header file
-
-
- GBitVec(size) Bit vector of length size <gbitvec.h>
-
- GDlist(type) Doubly-linked list <gdlist.h>
-
- GDlistIterator(type) Iterator for doubly-linked lists <gdlist.h>
-
- GSlist(type) Singly-linked list <gslist.h>
-
- GSlistIterator(type) Iterator for singly-linked lists <gslist.h>
-
- GSortedVector(val) Sorted vector <gsortvec.h>
-
- Rogue Wave Compiling Programs 21
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- GStack(type) Stack (Last In - First Out) <gstack.h>
-
- GQueue(type) Queue (First In - First Out) <gqueue.h>
-
- GVector(val) Vector of types <gvector.h>
-
-
-
-
- Table 3-1a. Generic collection classes and the header files that must be
- included to use them. The actual type of the objects to be collected
- is given by the macro argument "type" or "val", except for the class
- GBitVec, where the argument is the length of the bit vector. See
- Section14.
-
-
-
-
- Class Name Header file
- Smalltalk typedef
-
-
- RWBag Bag <rwbag.h>
-
- RWBagIterator BagIterator <rwbag.h>
-
- RWBinaryTree SortedCollection <bintree.h>
-
- RWBinaryTreeIterator SortedCollectionIterator <bintree.h>
-
- RWBTree <btree.h>
-
- RWBTreeDictionary <btrdict.h>
-
- RWCollection Collection <colclass.h>
-
- RWDlistCollectables <dlistcol.h>
-
- RWDlistCollectablesIterator <dlistcol.h>
-
- RWHashDictionary Dictionary <hashdict.h>
-
- RWHashDictionaryIterator DictionaryIterator <hashdict.h>
-
- Rogue Wave Compiling Programs 22
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWIdentityDictionary IdentityDictionary <idendict.h>
-
- RWIdentitySet IdentitySet <idenset.h>
-
- RWOrdered OrderedCollection <ordcltn.h>
-
- RWOrderedIterator OrderedCollectionIterator <ordcltn.h>
-
- RWSequenceable SequenceableCollection <seqcltn.h>
-
- RWSet Set <rwset.h>
-
- RWSetIterator SetIterator <rwset.h>
-
- RWSlistCollectables LinkedList <slistcol.h>
-
- RWSlistCollectablesIterator LinkedListIterator <slistcol.h>
-
- RWSlistCollectablesQueue Queue <queuecol.h>
-
- RWSlistCollectablesStack Stack <stackcol.h>
-
- RWSortedVector <sortvec.h>
-
-
-
-
-
-
-
- Table 3-1b. The Tools.h++ "Smalltalk-like" Collection classes, their
- Smalltalk typedef (if any), and the header files that must be
- included to use them. All objects to be collected using these
- classes must inherit the abstract base class RWCollectable. See
- Section 15.
-
-
-
-
-
-
-
-
-
- Rogue Wave Compiling Programs 23
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
-
-
-
- Class Name Header file
- Smalltalk typedef
-
-
- RWbistream <bstream.h>
-
- RWBitVec BitVec <bitvec.h>
-
- RWbostream <bstream.h>
-
- RWBTreeOnDisk <disktree.h>
-
- RWCacheManager <cacheman.h>
-
- RWCLIPstreambuf <winstrea.h>
-
- RWCollectable Object <collect.h>
-
- RWCollectableAssociation <collass.h>
-
- RWCollectableDate Date <colldate.h>
-
- RWCollectableInt Integer <collint.h>
-
- RWCollectableString String <collstr.h>
-
- RWCollectableTime Time <colltime.h>
-
- RWDate <rwdate.h>
-
- RWDDEstreambuf <winstrea.h>
-
- RWFactory <factory.h>
-
- RWFile <rwfile.h>
-
- RWFileManager <filemgr.h>
-
- RWInteger <rwint.h>
-
- Rogue Wave Compiling Programs 24
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWpistream <pstream.h>
-
- RWpostream <pstream.h>
-
- RWRegexp <regexp.h>
-
- RWString <rwstring.h>
-
- RWTime <rwtime.h>
-
- RWTokenizer <token.h>
-
- RWvistream <vstream.h>
-
- RWvostream <vstream.h>
-
-
-
-
- Table 3-1c. Other classes, Smalltalk typedef (if any), and the header files
- that must be included to use them.
-
- 3.2 Compiling a program
-
-
-
- Consider the following simple program called "test":
-
- #include <rwdate.h>
- #include <rstream.h>
- main()
- {
- // Construct a date with today's date:
- RWDate date;
-
- // Print it out:
- cout << date;
- }
-
- If this were a C program it would probably be given a suffix of .c.
- Unfortunately, there is no standard suffix for C++ programs: Zortech
- uses .cxx and .cpp; Turbo C++ uses .cpp; GNU uses .cc; Glockenspiel
- uses .cxx; while the AT&T compilers use .C (which is
- indistinguishable from .c under MS-DOS or VMS!). We have adopted
- Rogue Wave Compiling Programs 25
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- .cpp. Fortunately, most compilers can be forced to accept a
- different suffix.
-
-
- 3.2.1 Compiling a program: DOS
-
-
- 3.2.1.1 Compiling a program: Borland
-
- These instructions assume that the Borland include files and
- libraries are in the locations specified by the file TURBOC.CFG. If
- they are not, you will have to specify -I and -L flags as well, or
- change your configuration file (see the Borland User's Guide for
- instructions).
-
- If the file was named, say, test.cpp, then it could be compiled as
- follows:
-
- tcc -I\rogue\rw -ml test.cpp \rogue\lib\ttll.lib
-
- if you were using the Turbo C++ compiler and
-
- bcc -I\rogue\rw -ml test.cpp \rogue\lib\ttll.lib
-
- if you were using the Borland C++ compiler (substitute bccx for bcc
- to use the protected mode version of this compiler).
-
- These commands will compile and link in one step. The `-I' option
- tells the compiler where to find the Rogue Wave header files; the `-
- ml' option specifies the large memory model (the model used by the
- supplied precompiled library); the \rogue\lib\ttll.lib is the full
- pathname of the precompiled Borland library using the large memory
- model.
-
- Other useful Borland options are -f87 (inline 80x87 floating point
- instructions) and -Qx (use extended memory).
-
-
- 3.2.1.2 Using the Tools.h++ DLL with Borland C++
-
- The distribution disk includes a prebuilt DLL using the Borland C++
- large memory model. Using it involves several files:
-
-
- Rogue Wave Compiling Programs 26
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
-
- File Contents
-
-
- ttlld.dll The DLL
-
- ttlld.lib The DLL import library
-
- ttllw.lib The DLL "auxilary" library
-
-
-
-
- To use the DLL you must link with the import library and the auxilary
- library. The latter is necessary because it was not possible to
- "export" all classes from the DLL. In particular, some of the
- classes (RWvistream, RWbistream, for example) inherit from iostream
- classes which Borland does not implement as "exported" classes.
- Hence, they must be statically bound into your program.
-
- Finally, to run your program, make sure that ttlld.dll is in your
- path. Be sure to see Section 16.2 (Dynamic Link Library) for
- additional tips on using the DLL.
-
-
- 3.2.1.3 Compiling a program: Zortech
-
- Before starting, be sure that the Zortech environmental variables
- INCLUDE and LIB are set to the proper search path for system
- #include's and libraries, respectively.
-
- If the file was named, say, test.cpp, then it could be compiled as
- follows:
-
- ztc -I\rogue\rw -ml test.cpp \rogue\lib\ztll.lib
-
- This command will compile and link in one step. The `-I' option
- tells the compiler where to find the Rogue Wave header files; the `-
- ml' option specifies the large memory model (the model used by the
- supplied precompiled library); the \rogue\lib\ztll.lib is the full
- pathname of the precompiled Zortech library using the large memory
- model (substitute as appropriate).
-
- Rogue Wave Compiling Programs 27
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Other useful Zortech options are -f (inline 80x87 floating point
- instructions), -r (enforce strict prototyping), and -br (run in
- protected mode).
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Compiling Programs 28
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 3.2.1.4 Compiling a program: Glockenspiel
-
- Under MS-DOS, Tools.h++ will only work with V2.0c or greater of the
- Glockenspiel compiler, using Microsoft C 6.0 as the backend C
- compiler. A prebuilt library, using the large memory model, has been
- included. It is called gttl.lib.
-
- To use it, there are a few things you must do first:
-
- 1. Make sure you have followed the instructions under Installation
- about the Glockenspiel compiler.
-
- 2. You must always compile using the preprocessor flag "-
- D__GLOCK__".
-
- For example:
-
- ccxx -D__GLOCK__ -I\rogue\rw -c yourfile.cxx
-
- 3. For most programs, you will probably have to invoke link directly
- rather than using the front end "ccxx". This is because ccxx
- leaves out the /NOI (do not ignore case) qualifier when it
- invokes the link command. This is a bit of a hassle because you
- must list all of the libraries explicitly. See
- toolexam\makefile.glk for an example.
-
- 4. The default stacksize (0x0800) is too small for many of the
- Tools.h++ functions which depend heavily on recursion. You can
- specify a different size in the link command. 0x2000 is
- suggested. Again, see toolexam\makefile.glk for an example.
-
-
- 3.2.2 Compiling a program: Unix
-
-
- 3.2.2.1 Compiling a program: AT&T and compatibles, such as HCR
-
- The AT&T compilers accepts a suffix of .C as the default suffix for a
- C++ program. If the the program was named "test.C", it could be
- compiled using the AT&T Version 2.0 compiler, by using:
-
- CC -D__ATT2__ -I/usr/local/include/rw test.C -lrwtool
-
- Rogue Wave Compiling Programs 29
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- This command will compile and link in one step.
-
- 1. The -D__ATT2__ preprocessor directive is required, so that the
- Tools.h++ header files can identify that you are using the AT&T
- (or compatible) compiler.
-
- 2. The -I option tells the compiler where to find the Rogue Wave
- header files. The directory /usr/local/include/rw is the default
- installation location. Yours might differ.
-
- 3. The -lrwtool flag tells the compiler to include the library
- librwtool.a in the list of libraries to be searched for
- externals. If the library is not in a standard library "search
- path" the -L flag may have to be used.
-
- A Bourne shell script "ccpp" has been provided that can compile a
- program with suffix .cpp. It also defines the __ATT2__ preprocessor
- directive automatically.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Compiling Programs 30
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 4
-
-
- Stream I/OStream I/O
-
-
-
- Great pains have been taken to make all I/O independent of the type
- of stream class that your compiler might use. This is necessary
- because not all compiler manufacturers have upgraded to the
- relatively newer V2.X "iostream" type streams.
-
- For this reason, it is strongly recommended that the Rogue Wave
- header file <rstream.h> be included instead of <iostream.h> or
- <stream.h>. It will chose the appropriate header file based on the
- type of compiler being used. The macro "NL" is also available to
- indicate a "newline". For V2.X-type iostreams, it will be expanded
- to "endl", for V1.2-type streams, it will be expanded to "\n".
-
- Using these features will result in increased portability for your
- programs. See the table below.
-
-
-
- Compiler V1.2 V2.0 rstream.h Macro
-
- stream.h iostream.h chooses "NL"
-
- expands as
-
-
- AT&T V2.0, and compatibles X X <iostream.h> endl
-
- such as HCR and Glockenspiel
-
- Oregon Software V2.0 X X <iostream.h> endl
-
- Zortech V2.X X <stream.h> "\n"
-
-
- Rogue Wave Stream I/O 31
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Borland Turbo C++ and X X <iostream.h> endl
- Borland C++
-
-
-
-
- Table 4-1. This table indicates which types of streams a compiler supports.
- V1.2 stream.h refers to the "old-style" streams, V2.0 iostream.h refers
- to the "new-style" iostreams. The header file rstream.h is a Rogue
- Wave - supplied file that chooses an appropriate streams header file.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Stream I/O 32
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 5
-
-
- Class Overview
-
-
-
- The Tools.h++ classes generally fall into one of three categories:
-
- o Simple classes; many of which are discussed in sections 6 through
- 12.
-
- o Generic collection classes; discussed in section 14.
-
- o Smalltalk_-like collection classes; discussed in section 15.
-
- "Simple classes" are designed to stand alone and can be used in
- almost any context. Examples are the RWString, RWTime, or RWFile
- classes. They are frequently used as base classes in multiple
- inheritance situations in order to implement some more abstract
- functionality. For example, RWCollectableString multiply inherits
- from RWString and RWCollectable, giving it the functionality of a
- string, but the "collectability" of an RWCollectable class. It is in
- this manner that we avoid using a "cosmic object", which would force
- you into a particular class hierarchy, whether you want it or not.
- For additional details, see Section 15.12.
-
- "Generic collection classes" are so called because they use the
- <generic.h> preprocessor macros supplied with your C++ compiler, the
- current C++ approximation to templates. They offer the advantages of
- speed and type safe usage. Their code size can also be quite small
- when used sparingly. Their disadvantages are their limited
- generality and power and that, when used heavily, their code size can
- be quite large because there is almost no opportunity for code reuse.
- Because they depend heavily on the preprocessor, they can also be
- difficult to debug.
-
- The "Smalltalk_-like collection classes" are so called because they
- offer much of the functionality of their Smalltalk namesakes, such as
- Rogue Wave Class Overview 33
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Bag, SortedCollection, etc. However, they are not slavish imitations
- and instead pay homage to the strengths and weaknesses of C++. Their
- greatest advantages are their simple programming interface, powerful
- I/O abilities, and high code reuse. Their biggest disadvantages are
- their relatively high object code size when used in only small doses
- because of an initially high overhead in code machinery and their
- relative lack of type safeness. All objects to be used by the
- Smalltalk-like collection classes must also inherit from the abstract
- base class RWCollectable.
-
- Table 5-1 lists the class hierarchy of all of the public Tools.h++
- classes. In addition to these classes there are some additional
- classes that are used internally by the library.
-
-
- 5.1 Common member functions
-
-
-
- Whatever category a class might fall into, all classes share a number
- of member functions.
-
- void restoreFrom(RWFile&);
- void restoreFrom(RWvistream&);
- void saveOn(RWFile&) const;
- void saveOn(RWvostream&) const;
-
- These functions are used to store an object to and from an RWFile and
- to and from the Rogue Wave virtual streams facility.
-
- Class RWFile encapsulates ANSI-C file I/O and is discussed in detail
- in Section 10 as well as in the Class Reference. Objects saved using
- saveOn(RWFile&) are saved using a binary format, resulting in
- efficient storage and retrieval to files.
-
- Classes RWvistream and RWvostream are abstract base classes used by
- the Rogue Wave virtual streams facility. The final output format is
- determined by the specializing class. For example, RWpistream and
- RWpostream are two classes that derive from RWvistream and
- RWvostream, respectively, that store and retrieve objects using a
- "portable ASCII format". The results can be transferred between
- different operating systems. These classes are discussed in more
- detail in Section 9, as well as in the Class Reference.
-
- Rogue Wave Class Overview 34
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- It is up to the user to decide whether to store to RWFile's or
- virtual streams. The former offers the advantage of speed, but
- limits portability of the results to the host machine. The latter is
- not as fast, but there are specializing classes (RWpistream and
- RWpostream) that allow the results to be moved to any machine1.
-
- unsigned binaryStoreSize() const;
-
- This function returns the number of bytes of secondary storage
- necessary to store the object to a binary file (using class RWFile).
- It is useful for storing the object using classes RWFileManager and
- RWBTreeOnDisk.
-
- ostream& operator<<(ostream& ostr, const ClassName& x);
- istream& operator>>(istream& istr, const ClassName& x);
-
- The overloaded l-shift operator (<<) will print the contents of an
- object in a human-readable form. Conversely, the overloaded r-shift
- operator (>>) will read and parse an object from an istream, using a
- human-understandable format. Note that this contrasts with
- restoreFrom() and saveOn() which, although they may store and restore
- to a stream, will not necessarily do so in a form that could be
- called "human-readable".
-
- Finally, most classes have comparison and equality member functions:
-
- int compareTo(ClassName*) const;
- RWBoolean equalTo(ClassName*) const;
-
- and their logical operator counterparts:
-
- RWBoolean operator==(const ClassName&) const;
- RWBoolean operator!=(const ClassName&) const;
- RWBoolean operator<=(const ClassName&) const;
-
-
- 1 At the time of this writing, there is another important
- advantage of RWFile's over virtual streams --- not all
- compiler manufacturers have gotten the details right in
- implementing istreams and ostreams which are used to
- implement virtual streams. Some member functions that
- are known to have problems are seekg(), seekp(), gcount()
- and, perhaps, others.
-
- Rogue Wave Class Overview 35
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWBoolean operator>=(const ClassName&) const;
- RWBoolean operator<(const ClassName&) const;
- RWBoolean operator>(const ClassName&) const;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Class Overview 36
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- GBitVec(size)
- GVector(val)
- GSortedVector(val)
- ios
- RWvistream
- RWbistream
- RWpistream
- RWvostream
- RWbostream
- RWpostream
- RWBitVec
- RWBTreeOnDisk
- RWCacheManager
- RWCollectable
- RWCollection
- RWBag
- RWBinaryTree
- RWBTree
- RWBTreeDictionary
- RWSequenceable
- RWDlistCollectables
- RWOrdered
- RWSortedVector
- RWSlistCollectables
- RWSlistCollectablesQueue
- RWSlistCollectablesStack
- RWSet
- RWHashDictionary
- RWIdentityDictionary
- RWIdentitySet
- RWCollectableDate
- RWCollectableInt
- RWCollectableString
- RWCollectableTime
- RWDate
- RWErrObject
- RWFactory
- RWFile
- RWFileManager
- RWInteger
- RWIterator
- RWBagIterator
- RWBinaryTreeIterator
- RWDlistCollectablesIterator
- Rogue Wave Class Overview 37
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWSetIterator
- RWHashDictionaryIterator
- RWOrderedIterator
- RWSlistCollectablesIterator
- RWMemoryPool
- RWRegexp
- RWSlist
- GQueue(type)
- GSlist(type)
- GStack(type)
- RWDlist
- GDlist(type)
- RWSlistIterator
- GSlistIterator(type)
- RWDlistIterator
- GDlistIterator(type)
- RWString
- RWSubString
- RWTime
- RWTokenizer
- streambuf
- strstreambuf
- RWCLIPstreambuf
- RWDDEstreambuf
-
- Table 5-1. The class hierarchy of the public Tools.h++ classes. Classes
- which use multiple inheritance are shown in italics.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Class Overview 38
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 6
-
-
- Using Class RWStringRWString
-
-
-
- The RWString class has many powerful and convenient string processing
- features that are much more convenient than the standard C <string.h>
- functions, but just as efficient.
-
-
- 6.1 Example
-
-
-
- Here is a short example that exercises the RWString class:
-
- #include <rwstring.h>
- #include <regexp.h>
- #include <rstream.h>
-
- main()
- {
- RWString a;
-
- RWRegexp re("V[0-9]\.[0-9]+");
- while( a.readLine(cin) ){
- a(re) = "V4.0";
- cout << a << NL;
- }
- }
-
- Program input:
-
- This text describes V1.2. For more
- information see the file groggo.doc.
- The current version V1.2 implements...
-
- Rogue Wave Using Class RWString 39
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Program output:
-
- This text describes V4.0. For more
- information see the file groggo.doc.
- The current version V4.0 implements...
-
- This example reads lines from standard input and searches them for a
- pattern matching the regular expression "V[0-9]\.[0-9]+". This
- expression matches "version numbers" between V0 and V9: V1.2, V1.22,
- but not V12.3. If a match is found, then the pattern is replaced
- with the string "V4.0". The magic here is in the expression
-
- a(re) = "V4.0";
-
- The function call operator (i.e., RWString::operator()) has been
- overloaded to take an argument of type RWRegexp -- the regular
- expression. It returns a "substring" that delimits the regular
- expression, or a null substring if the expression is not found. The
- substring assignment operator is then called and replaces the
- delimited string with the contents of the right hand side, or does
- nothing if this is the null substring.
-
-
- 6.2 Reference counting
-
-
-
- Class RWString uses reference counting to minimize copying (see, for
- example, Stroustrup, 1986, Section 6). The great advantage to this
- approach is speed. Referencing old data via a pointer is much faster
- than copying it.
-
-
- Both the copy constructor
-
- RWString::RWString(const RWString&);
-
- and the assignment operator
-
- RWString& RWString::operator=(const RWString&);
-
-
-
-
- Rogue Wave Using Class RWString 40
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- use reference semantics. That is, they will merely reference the
- argument, rather than copy it. The result is a shallow copy (see
- Section 13.1.1.2).
-
-
- If a RWString is initialized with another RWString via the copy
- constructor
-
- RWString(const RWString&);
-
- then their data will share the same memory -- if one RWString is
- changed, the other will change. The following code fragment
- illustrates:
-
-
- RWString s1 = "this is a string"; // Construct a RWString.
- RWString s2 = s1; // Construct with shared data.
-
- cout << s1 << NL << s2 << NL;
-
- // Now change s2:
- s2(0) = 'T';
-
- cout << NL<< s1 << NL << s2 << NL;
-
- This will produce the following output:
-
- this is a string
- this is a string
-
- This is a string
- This is a string
-
- Note that the first element of both s1 and s2 changed -- they share
- the same data.
-
- This may sound confusing -- two objects sharing the same data -- but
- generally it is not a problem. The reason is that the copy
- constructor and assignment operator are frequently called upon to
- construct an object from a temporary. Consider an example that is
- perhaps more typical:
-
-
- Rogue Wave Using Class RWString 41
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWString a1 = "Pioneering ";
- RWString a2 = "does not pay.";
-
- RWString a3 = a1 + a2;
- cout << a3 << NL;
-
- The "+" operator has been overloaded for strings to concatenate its
- two arguments together. Hence, this will produce2:
-
- Pioneering does not pay.
-
- The results of a1 + a2 produces a temporary -- it is never given a
- name and it is destroyed "at the first opportunity". Hence, there
- will be only one copy of its data when a3 takes on its identity.
-
- Assignment to another RWString works in a similar manner. The
- following
-
- RWString name("Seldom seen Smith");
- RWString name2;
- name2 = name; // name2 references name's data
- name2(7) = `S'; // Changes both name and name2
- cout << name << NL << name2 << NL;
-
- produces:
-
- Seldom Seen Smith
- Seldom Seen Smith
-
-
- Note that only the copy constructor and the assignment operator that
- take an RWString as an argument are affected. In particular,
- construction from or assignment to a character string will copy the
- string.
-
-
- Here's an example:
-
- char dat[] = "eureka!";
- RWString a1(dat); // Construct from character string
-
-
- 2 Andrew Carnegie.
-
- Rogue Wave Using Class RWString 42
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWString a2;
- a2 = dat; // Assign to character string
- dat[0] = `E';
-
- cout << a1 << NL << a2 << NL << dat << NL;
-
- This will produce:
-
- eureka!
- eureka!
- Eureka!
-
- What if you want to construct a RWString from another RWString, but
- don't want them to share the same data?
-
-
-
- The member function copy() will return a distinct copy of a RWString
- and can be used where it is necessary to have unique data. That is,
- it will make a deep copy (see Section 13.1.1.2).
-
-
- Here's an example:
-
- RWString b1 = "Copy 1";
- RWString b2 = b1.copy(); // Construct b2 with its own data
-
- b2(5) = `2'; // Now changing b2 will not change b1
- cout << b1 << NL << b2 << NL;
-
- This will produce:
-
- Copy 1
- Copy 2
-
- 6.3 Member functions
-
-
-
- Class RWString has member functions to read, compare, store, restore,
- concatenate, prepend, and append RWStrings and char*'s. Operators
- allow access to individual characters, with or without bounds
- checking. The details of the RWString class capabilities are
- summarized in Part II: Class Reference. Example 2 in Section 17
- Rogue Wave Using Class RWString 43
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- illustrates the use of the RWString class. RWStrings are also used
- in various ways as keys and collectable objects in Examples 3-6.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWString 44
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- For example, a code fragment to read two RWStrings, concatenate them,
- convert to upper case, and output the results, is:
-
- RWString s1, s2;
- cin >> s1 >> s2;
- cout << toUpper(s1+s2);
-
- 6.4 SubStrings:RWString substrings
-
-
-
- A separate RWSubString class supports substring extraction and
- modification. There are no public constructors -- RWSubStrings are
- constructed indirectly by various member functions of RWString, and
- then destroyed at the first opportunity. The resulting substring can
- be used in a variety of situations.
-
- For example, a RWString can be constructed from a substring:
-
- RWString s("this is a string");
- // Construct a RWString from a substring:
- RWString s2 = s(0, 4); // "this"
-
- The result is a string s2 that contains a copy of the first four
- characters of s (it will not share memory with s).
-
- RWSubstrings may also be used as lvalues in an assignment, either to
- a character string, or to a RWString or RWSubString:
-
- // Construct a RWString:
- RWString article("the");
- RWString s("this is a string");
- s(0, 4) = "that"; // "that is a string"
- s(8, 1) = article; // "that is the string"
-
- Note that assignment is not a conformal operation: the two sides of
- the assignment operator need not have the same number of characters.
-
-
- 6.5 Pattern matching
-
-
-
- Class RWString supports string search and pattern matching using a
- Rogue Wave Using Class RWString 45
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Rabin-Karp hashing algorithm. This technique uses an efficient
- method to compute a hash value for a pattern of length N and checking
- it against N-sized segments within a text of length M (>N). The
- algorithm takes time proportional to N+M (brute force searching
- techniques take time NM). Since the method only finds a position in
- the text which has the same hash value as the pattern, the paranoid
- will still want to do a direct comparison. This can be done by
- calling the static member function setParanoidCheck(). However,
- because the effective hashing table is extremely large, it is very
- unlikely that two different patterns would hash to the same value.
-
- Here is an example. The code fragment:
-
- RWString s("curiouser and curiouser.");
- int i = s.index("curious");
-
- will find the start of the first occurrence of "curious" in s. The
- result is that i will be set to "0". To find the index of the next
- occurrence use:
-
- i = s.index("curious", i++);
-
- which will result in i being set to "14".
-
- Pattern searches can be made either case sensitive or insensitive by
- calling the static member function setCaseSensitive() first.
-
- Note that both setParanoidCheck() and setCaseSensitive() are static
- member functions -- all instances of RWString will share the same
- settings.
-
-
- 6.5.1 Regular expressions
-
- The Tools.h++ Class Library supports regular expression searches.
- See Part II: Class Reference, under RWRegexp, for details of the
- regular expression syntax. A regular expression can be used to
- return a substring. Here's an example that might be used to match
- all Windows messages (prefix of WM_):
-
-
-
-
-
- Rogue Wave Using Class RWString 46
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- #include <rwstring.h>
- #include <regexp.h>
- #include <rstream.h>
-
- main()
- {
- RWString a("A message named WM_CREATE");
-
- // Construct a Reg. Expr. to match Windows messages:
- RWRegexp re("WM_[A-Z]*");
- cout << a(re) << NL;
-
- Program output:
-
- WM_CREATE
-
- The function call operator for RWString has been overloaded to take
- an argument of type RWRegexp. It returns a RWSubString matching the
- expression, or the null substring if there is no such expression.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWString 47
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 6.6 Tokenizer
-
-
-
- Class RWTokenizer can be used to break a string up into tokens,
- separated by an arbitrary "white space". See Part II: Class
- Reference, under RWTokenizer, for additional details. Here's an
- example:
-
- #include <token.h>
- #include <rwstring.h>
- #include <rstream.h>
-
- main()
- {
-
- RWString a("a string with five tokens");
-
- RWTokenizer next(a);
-
- int i = 0;
-
- // Advance until the null string is returned:
- while( next() ) i++;
-
- cout << i << NL
-
- Program output:
-
- 5
-
- This program counts the number of tokens in the string. The function
- call operator for class RWTokenizer has been overloaded to mean
- "advance to the next token and return it as a RWSubString", much like
- any other iterator. When there are no more tokens, it returns the
- null substring. Because RWSubString has a type conversion to char*
- which has been defined to mean "return zero if this is the null
- substring, the start of the substring otherwise", the loop will be
- broken once the null substring is encountered.
-
-
-
-
- Rogue Wave Using Class RWString 48
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 7
-
-
- Using Class RWDateRWDate
-
-
-
- Class RWDate represents a date, stored as a Julian day number. It is
- based on algorithms from The NIH Class Library (K.E. Gorlen, see
- Appendix B).
-
- The algorithm to convert a Gregorian calendar date (for example
- January 10, 1990) to a Julian day number is given in: Algorithm 199
- from Communications of the ACM, Volume 6, No. 8, Aug. 1963, p. 444.
-
- The Gregorian calendar was introduced by Pope Gregory XIII in 1582,
- and was adopted by England on September 14, 1752. Class RWDate will
- not provide valid dates before 1582.
-
-
- 7.1 Constructors
-
-
-
- A RWDate may be constructed in several ways. For example:
-
- 1. Construct a RWDate with the current date:
-
- RWDate d;
-
- 2. Construct a RWDate for a given day of the year (1-365) and a
- given year (e.g., 1989 or 89)
-
- RWDate d(24, 1990); // 1/24/1990
- RWDate d2(24, 90); // 1/24/1990
-
- 3. Construct a RWDate for a given day of the month (1-31), month
- name (e.g., January, JAN, or Jan) or month number (1-12) and
- year:
- Rogue Wave Using Class RWDate 49
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWDate d(10, "MAR", 90); // 3/10/1990
-
- 4. Construct a RWDate from a RWTime:
-
- RWTime t; // Current time.
- RWDate d(t);
-
- 7.2 Member functions
-
-
-
- There are member functions to read, compare, store, restore, add and
- subtract RWDates. A RWDate may return (for example) the name of the
- month, whether it is a leap year, etc. Dates can be printed with a
- variety of formats. A complete list of member functions is included
- in Part II: Class Reference. Example 1 (see Section 17) illustrates
- the use of this class.
-
-
- 7.3 Example
-
-
-
- #include <rwdate.h>
- #include <rstream.h>
-
- main(){
- RWDate dd(6, "January", 1990);
- dd.setPrintOption(RWDate::terse);
- cout << dd<< ", a " << dd.nameOfDay() << NL;
-
- RWDate prev = dd.previous("Sunday");
-
- cout << "The previous Sunday is: " << prev << NL;
- }
-
- Program output:
-
- 1-Jan-90, a Saturday
- The previous Sunday is: 31-Dec-89
-
-
-
-
- Rogue Wave Using Class RWDate 50
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 8
-
-
- Using Class RWTimeRWTime
-
-
-
- Class RWTime represents a time, stored as the number of seconds since
- 1 January 1901. It is based on algorithms from The NIH Class Library
- (K.E. Gorlen, see Appendix B).
-
- For this class to function correctly, your computer's system clock
- must be set and functioning correctly. If you are using a PC, be
- sure the batteries that power the system clock are charged.
-
-
- 8.1 Setting the time zone
-
-
-
- The UNIX operating system provides for setting the local time zone
- and for establishing whether daylight savings time is locally
- observed. If these switches have been properly set for your system,
- class RWTime should function properly.
-
- For MS-DOS users, you will have to set these switches yourself. How
- you do this depends on the compiler you are using. If you do
- nothing, the class will function properly for local time, but may not
- give the proper Greenwich Mean Time (GMT) -- the computer has no
- other way of knowing the offset from local time to GMT.
-
- For Borland users, you must set your environment variable TZ to the
- appropriate time zone. For example:
-
- set TZ=PST8PDT
-
- See the documentation for function tzset() within the Borland Library
- Reference Guide for further information.
-
- Rogue Wave Using Class RWTime 51
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- For Zortech users, you must set the time zone manually in the file
- "rwtime.cpp". Time zones, in hours west of GMT, are provided as an
- enumeration in "rwtime.cpp". You must set the macro LOCAL_TIME_ZONE.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWTime 52
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- For example,
-
- LOCAL_TIME_ZONE = USEastern;
-
- sets the local time to Eastern Standard Time. The default is Pacific
- Standard Time. The file must be recompiled for the changes to take
- effect.
-
- For both compilers, you must also set the switch DST_OBSERVED to TRUE
- (the default) or FALSE, depending on whether or not daylight savings
- time is locally observed. Note that this does not mean whether
- daylight savings time is currently in effect -- Class RWTime will
- determine this -- just whether it is locally observed. The file must
- be recompiled for any changes to take effect.
-
-
- 8.2 Constructors
-
-
-
- A RWTime may be constructed in several ways:
-
- 1. Construct a RWTime with the local time:
-
- RWTime t;
-
- 2. Construct a RWTime with today's date, at the specified local hour
- (0-23), minute (0-59) and second (0-59):
-
- RWTime t(16, 45, 0); // 16:45:00
-
- 3. Construct a RWTime for a given date and local time:
-
- RWDate d(2, "June", 1952);
- RWTime t(d, 16, 45, 0); // 6/2/52 16:45:00
-
- 8.3 Member functions
-
-
-
- Class RWTime has member functions to compare, store, restore, add and
- subtract RWTimes. An RWTime may return hour, minute or second, local
- or GMT. A complete list of member functions is included in Part II:
- Class Reference. Example 1 (see Section 17.1) illustrates the use of
- Rogue Wave Using Class RWTime 53
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- this class.
-
- For example, a code fragment to output the (local) hour and (GMT)
- hour is:
-
-
- RWTime t;
- cout << t.hour();
- cout << t.hourGMT();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWTime 54
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 9
-
-
- Virtual Streams
-
-
-
- Virtual streamsThe new "iostream" facility, featured in C++ V2.X
- compiliant compilers, has proven to be a wonderfully adaptive
- resource, thanks to its clean and complete abstraction of input and
- output through sequential "streams" of bytes whose source and
- disposition is completely transparent to the user of those streams.
- It is well worth becoming familiar with its abilities.
-
- With the Rogue Wave "virtual streams" extensions, even the formatting
- of the items inserted into the streams can be made abstract.
- Furthermore, two sets of specialized streambufs are included with the
- Tools.h++ library that allow iostreams to be used to transfer data
- through the Microsoft Windows_ Clipboard or Dynamic Data Exchange
- (DDE) facilities. The result is that the same code that is used, for
- example, to store a complex structure to a conventional disk-based
- file can also be used to transfer that structure through the DDE
- facility to another application!
-
- A limited subset of these extensions is also available for users of
- the older C++ V1.2 style "stream" classes.
-
- Classes RWvistream and RWvostream are abstract base classes with a
- whole suite of pure virtual functions operator<<(), put(), get(), and
- the like, for all of the basic built in types and arrays of built in
- types:
-
-
-
-
-
-
-
-
- Rogue Wave Virtual Streams 55
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- class RWvistream : public ios {
- public:
- virtual RWvistream& operator>>(char&) = 0;
- virtual RWvistream& operator>>(double&) = 0;
- virtual int get() = 0;
- virtual RWvistream& get(char&) = 0;
- virtual RWvistream& get(double&) = 0;
- virtual RWvistream& get(char*, unsigned N) = 0;
- virtual RWvistream& get(double*, unsigned N) = 0;
- .
- .
- .
- };
-
- class RWvostream : public ios {
- public:
- virtual RWvostream& operator<<(char) = 0;
- virtual RWvostream& operator<<(double) = 0;
- virtual RWvostream& put(char) = 0;
- virtual RWvostream& put(double) = 0;
- virtual RWvostream& put(const char*, unsgined N) = 0;
- virtual RWvostream& put(const double*, unsigned N) = 0;
- .
- .
- .
- };
-
- Streams that inherit from RWvistream and RWvostream are intended to
- store builtins to specialized streams in a format that is transparent
- to the user of the classes. Note that they inherit from the V2.X
- iostreams base class ios3, hence all of the ios functions, such as
- good(), eof(), etc., can be used on them.
-
- Because the virtual streams do not retain any information about their
- underlying ios base class (or, more importantly, its associated
- streambuf), they can be freely interchanged with regular streams --
- using them does not lock you into doing all your file I/O with them.
-
-
- 3 Compilers that implement V2.X type iostreams only. When
- RWvistream and RWvostream are used with compilers that
- use V1.2 type streams, a different inheritance structure
- is used. See Part II: Class Reference.
-
- Rogue Wave Virtual Streams 56
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- The basic abstraction of the virtual streams facility is that
- builtins are "inserted" into a virtual output stream, "extracted"
- from a virtual input stream, without any regard for formatting. That
- is, there is no need to pad output with whitespace, commas, or any
- other kind of formatting. You are effectively telling RWvostream,
- "Here is a double. Please store it for me in whatever format is
- convenient and give it back to me in good shape when I ask for it".
-
- The results are extremely powerful. You can not only use, but also
- write, saveOn() and restoreFrom() functions without knowing anything
- about the final output medium or formatting that is to be used. For
- example, the output medium could be a disk, memory allocation, or
- even a network. The formatting could be in binary, ascii, or network
- packet. In all of these cases, the same saveOn() and restoreFrom()
- functions can be used.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Virtual Streams 57
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 9.1 Specializing virtual streams
-
-
-
- The Rogue Wave classes come with two types of classes that specialize
- RWvistream and RWvostream, one that uses a "portable ASCII"
- formatting, the other a binary formatting:
-
-
-
- Input class Output class
-
-
- Abstract base class RWvistream RWvostream
-
- Portable ASCII RWpistream RWpostream
-
- Binary RWbistream RWbostream
-
-
-
-
- The "portable ASCII" versions store their inserted items in an ASCII
- format that escapes special characters such as tabs, newlines, etc.,
- in such a manner that they will be restored properly, even under a
- new operating system. The "binary" versions do not reformat their
- inserted items and, instead, store them in their native format. For
- more information, see the respective entries in Part II: Class
- Reference.
-
-
- 9.2 Simple example
-
-
-
- Here's a simple example that exercises RWbostream and RWbistream
- through their respective abstract base classes, RWvostream and
- RWvistream:
-
- #include <bstream.h>
- #include <fstream.h>
- #include <rwstring.h>
-
- Rogue Wave Virtual Streams 58
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- void save(RWString& a, RWvostream& v)
- {
- a.saveOn(v); // Save to virtual output stream
- }
-
- RWString recover(RWvistream& v)
- {
- RWString dupe;
- dupe.restoreFrom(v);
- return dupe;
- }
-
- main()
- {
- RWString a("A string with\ttabs and a\nnewline.");
-
- {
- ofstream f("junk.dat", ios::out); // 1
- RWbostream bostr(f); // 2
- save(a, bostr);
- } // 3
-
- ifstream f("junk.dat", ios::in); // 4
- RWbistream bistr(f); // 5
- RWString b = recover(bistr); // 6
-
- cout << a << NL; // Compare the two strings// 7
- cout << b << NL;
- }
-
- Program output:
-
- A string with tabs and a
- newline.
- A string with tabs and a
- newline.
-
- The job of function save(RWString& a, RWvostream& v) is to save the
- string a to the virtual output stream v. Function
- recover(RWvistream&) restores the results. These functions do not
- know the ultimate format with which the string will be stored. Some
- additional comments on particular lines:
-
- 1 On this line, a file output stream f is created for the file
- Rogue Wave Virtual Streams 59
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- "junk.dat".
-
- 2 On this line, a RWbostream is created from f.
-
- 3 Because this clause in enclosed in brackets { ... }, the
- destructor for f will be called here. This will cause the file
- to be closed.
-
- 4 The file is reopened, this time for input.
-
- 5 Now a RWbistream is created from it.
-
- 6 The string is recovered from the file.
-
- 7 Finally, both the original and recovered strings are printed for
- comparison.
-
- This program could be simplified by using class fstream, which
- multiply inherits ofstream and ifstream, for both output and input.
- A seek to beginning-of-file would occur before reading the results
- back in. Unfortunately, at the time of this writing, most
- implementations of seekg() have not proven to be reliable. Hence,
- this approach was not chosen for this example.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Virtual Streams 60
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 9.3 Windows_ Clipboard and DDE streambufs
-
-
-
- Class "streambuf" is the underlying "sequencing" layer of the
- iostreams facility. It is responsible for producing and consuming
- sequences of characters. Your compiler comes with several versions.
- For example, class filebuf ultimately gets and puts its characters to
- a file. Class strstreambuf gets and puts to memory-based character
- streams (you can think of it as the iostream equivalent to ANSI-C's
- sprintf() function). Now Tools.h++ adds two Windows-based
- extensions:
-
- o Class RWCLIPstreambuf for getting and putting to the Clipboard;
-
- o Class RWDDEstreambuf for getting and putting through the DDE
- facility.
-
- They take care of the details of allocating and reallocating memory
- from Windows as buffers are over- and underflowed. In the case of
- class RWDDEstreambuf, the associated DDEDATA header is also filled in
- for you. Any class that inherits from class ios can be used with
- these streambufs. This includes the familiar istream and ostream, as
- well as the Rogue Wave virtual stream classes.
-
-
- 9.4 DDE example
-
-
-
- Let's look at a more complicated example: how one might exchange a
- SortedCollection through the Windows DDE facility (a similar
- technique can be used for Window's Clipboard), using class
- RWDDEstreambuf.
-
- #include <bintree.h>
- #include <collstr.h>
- #include <bstream.h>
- #include <winstream.h>
- #include <windows.h>
- #include <dde.h>
-
-
- Rogue Wave Virtual Streams 61
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- BOOL
- PostCollection(HWND hwndServer, WORD cFormat)
- {
- SortedCollection sc; // 1
- sc.insert(new RWCollectableString("Mary"));
- sc.insert(new RWCollectableString("Bill"));
- sc.insert(new RWCollectableString("Pierre"));
-
- // Allocate a RWDDEstreambuf and use it to initialize
- // a RWbostream:
- RWDDEstreambuf* sbuf = new RWDDEstreambuf(cFormat); // 2
- RWbostream bostr( sbuf ); // 3
-
- // Store the collection to the RWbostream:
- sc.saveOn(bostr); // 4
-
- // Lock the output stream, and get its handle:
- HANDLE hDDEData = sbuf->str(); // 5
-
- // Get an atom to identify the DDE Message:
- ATOM atom = GlobalAddAtom("SortedNames"); // 6
-
- // Post the DDE response:
- return PostMessage(0xFFFF, WM_DDE_DATA, hwndServer, // 7
- MAKELONG(hDDEData, atom));
- }
-
- The large memory model has been assumed. Here's the line-by-line
- description:
-
- 1 A SortedCollection is built and some items inserted into it.
-
- 2 An RWDDEstreambuf is allocated. The constructor takes several
- arguments. Here, all of the default arguments were used except
- for the first, the Windows clipboard format. In this example,
- the format type has been passed in as an argument, but in
- general, you will probably want to register a format with Windows
- (using RegisterClipboardFormat()) and then use that.
-
- The other, default, arguments have to do with the intricacies of
- DDE data exchange acknowledgments and memory management. See
- Part II, Class Reference for the list of arguments and, for
- example, Petzold (1990), Chapter 17, or the Microsoft Windows
- Guide to Programming, Chapter 22, for their meanings.
- Rogue Wave Virtual Streams 62
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 3 An RWbostream is constructed from the supplied RWDDEstreambuf.
- We could have used an RWpostream here, but DDE exchanges are done
- within the same machine architecture so, presumably, it is not
- worth the extra overhead of using the portable ASCII formats.
- Nevertheless, note how the disposition of the bytes (which is set
- by the type of streambuf) is cleanly separated from their
- formatting, which is set by the type of RWvostream.
-
- 4 The collection is saved to the RWbostream. Because the
- RWbostream's associated streambuf is actually an RWDDEstreambuf,
- the collection is actually being saved to a Window's global
- memory allocation with characteristic GMEM_DDESHARE. This
- allocation is automatically resized if it is overflowed. Like
- any other strstreambuf, you can change the size of the allocation
- chunks using member function setbuf().
-
- 5 The RWDDEstreambuf is locked. Once locked using str(), this
- streambuf, like any other strstreambuf, cannot be used again.
- Note, however, that RWDDEstreambuf::str() returns a handle,
- rather than a char*. The handle is unlocked before returning it.
-
- 6 An atom is constructed to identify this DDE data.
-
- 7 The handle returned by RWDDEstreambuf::str(), along with its
- identifying atom, is posted.
-
- A similar (actually, simpler) technique can be used for Clipboard
- exchanges.
-
- Note that there is nothing that constrains you to using the
- specialized streambufs RWDLIPstreambuf and RWDDEstreambuf with only
- the Rogue Wave virtual streams facility. One could quite easily use
- them with regular istreams and ostreams. You just wouldn't be able
- to set the formatting at runtime.
-
-
- 9.5 Recap
-
-
-
- We have seen how an object can be stored and recovered from streams
- without regard to the final destination of the bytes of that stream.
- They could reside in memory, or on disk. We have also seen how we
- need not be concerned with the final formatting of the stream. It
- Rogue Wave Virtual Streams 63
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- could be in ASCII or binary.
-
- It is also quite possible to write your own specializing "virtual
- stream" class, much like RWpostream and RWpistream, that could, for
- example, "store" an object to a network, perhaps using an XDR format.
- The great advantage of the virtual streams facility is that if you do
- write your own specialized virtual stream, there is no need to modify
- any of the code of the client classes -- you just use your stream
- class as an argument to saveOn(RWvostream&) and
- restoreFrom(RWvistream&).
-
- In addition to storing and retrieving an object to and from virtual
- streams, all of the classes can store and retrieve themselves in
- binary to and from an RWFile. This file encapsulates ANSI-C style
- file I/O. Although more limited in its abilities than stream I/O,
- this form of storage and retrieval is faster to and from disk because
- the virtual dispatching machinery is not needed.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Virtual Streams 64
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 0
-
-
- Using Class RWFileRWFile
-
-
-
- Class RWFile encapsulates the standard C file operations for binary
- read and write, using the ANSI-C function fopen(), fwrite(),
- fread(), etc. This class is based on class PFile of the Interviews
- Class Library (1987, Stanford University), but has been modified (and
- modernized) by Rogue Wave to use "const" modifiers, and to port to
- MS-DOS. The member function names begin with upper case letters in
- order to maintain compatibility with class PFile.
-
- The constructor for class RWFile has prototype
-
- RWFile(const char* filename);
-
- This constructor will open a binary file called filename for
- read/write, creating it if it does not already exist. The destructor
- for this class closes the file.
-
- There are member functions for flushing the file, and for testing
- whether the file is empty, has had an error, or is at the end-of-
- file.
-
-
- 10.1 Example
-
-
-
- Class RWFile has member functions to determine the status of a file,
- and to read and write a wide variety of built in types, either one at
- a time, or from and into blocks of n instances of a built-in type.
- The file pointer may be repositioned with functions SeekTo(),
- SeekToBegin(), and SeekToEnd(). The details of the RWFile class
- capabilities are summarized in Part II: Class Reference.
-
- Rogue Wave Using Class RWFile 65
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- For example, to create a RWFile with filename "test.dat", read an int
- (if the file is not empty), increment it, and write it back to the
- file:
-
- #include <rwfile.h>
-
- main()
- {
- RWFile file("test.dat"); // Construct the RWFile.
-
- // Check that the file exists, and that it has
- // read/write permission:
- if ( file.Exists() ) {
- int i;
- // Read the int if the file is not empty:
- if ( !file.IsEmpty() ) file.Read(i);
- i++;
- file.SeekToBegin();
- file.Write(i); // Rewrite the int.
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWFile 66
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 1
-
-
- Using Class RWFileManagerRWFileManager
-
-
-
- Class RWFileManager allocates, deallocates and coalesces free space
- in a disk file. This is done internally by maintaining on disk a
- linked-list of free space blocks.
-
- Two typedefs are used:
-
- typedef long RWoffset;
- typedef unsigned RWspace;
-
- The type RWoffset is used for the offset within the file to the start
- of a storage space; RWspace is the amount of storage space required.
- The actual typedef may vary depending on the system you are using.
-
- Class RWFile is a public base class of class RWFileManager, therefore
- the public member functions of class RWFile are available to class
- RWFileManager.
-
-
- 11.1 Construction
-
-
-
- The RWFileManager constructor has prototype:
-
- RWFileManager(const char* filename);
-
- The first argument is the name of the file that the RWFileManager is
- to manage. If a new file is specified, it will be initialized
- properly. Otherwise, if the file is not empty, the old data will be
- read. In this case, the data on the file must have been previously
- written by a RWFileManager.
-
- Rogue Wave Using Class RWFileManager 67
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 11.2 Member functions
-
-
-
- The class RWFileManager adds four additional member functions to
- those of class RWFile. They are:
-
- 1. RWoffset allocate(RWspace s);
-
- Allocate s bytes of storage in the file, returning the offset to
- the start of the allocation.
-
- 2. void deallocate(RWoffset t);
-
- Deallocate (free) the storage space starting at offset t. This
- space must have been previously allocated by the function
- allocate():
-
- 3. RWOffset endData();
-
- Return the offset to the last data in the file.
-
- 4. RWoffset start();
-
- Return the offset from the start of the file to the first space
- ever allocated by this RWFileManager, or return NIL4 if no space
- has been allocated, implying that this is a "newFile".
-
- The statement
-
- RWoffset a = F.allocate(sizeof(double));
-
- uses RWFileManager F to allocate the space required to store an
- object with the size of a double and returns the offset to that
- space. To write the object to the disk file, you should use Write().
- It is also your responsibility to maintain a record of the offsets
- necessary to read the stored object.
-
-
-
- 4 NIL is a macro whose actual value is system dependent.
- Typically, it is -1L.
-
- Rogue Wave Using Class RWFileManager 68
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- To help you do this, the first allocation ever made by a
- RWFileManager is considered "special"and can be returned by member
- function start() at any time. The RWFileManager will not allow you
- to deallocate it. This first block will typically hold information
- necessary to read the remaining data, perhaps the offset of a root
- node, or the head of a linked-list.
-
- The following example shows the use of class RWFileManager to
- construct a linked-list of ints on disk: The source code is included
- in the toolexam subdirectory as example7.cpp and example8.cpp.
-
-
- #include <filemgr.h> // 1
- #include <rstream.h>
-
- struct DiskNode { // 2
- int data; // 3
- RWoffset nextNode; // 4
- };
-
- main()
- {
- RWFileManager fm("linklist.dat"); // 5
-
- // Allocate space for offset to start of the linked list:
- fm.allocate(sizeof(RWoffset)); // 6
- // Allocate space for the first link:
- RWoffset thisNode = fm.allocate(sizeof(DiskNode)); // 7
-
- fm.SeekTo(fm.start()); // 8
- fm.Write(thisNode); // 9
-
- DiskNode n;
- int temp;
- RWoffset lastNode;
- cout << "Input a series of integers, then EOF to end:\n";
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWFileManager 69
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- while (cin >> temp) { // 10
- n.data = temp;
- n.nextNode = fm.allocate(sizeof(DiskNode)); // 11
- fm.SeekTo(thisNode); // 12
- fm.Write(n.data); // 13
- fm.Write(n.nextNode);
- lastNode = thisNode; // 14
- thisNode = n.nextNode;
- }
-
- fm.deallocate(n.nextNode); // 15
- n.nextNode = NIL; // 16
- fm.SeekTo(lastNode);
- fm.Write(n.data);
- fm.Write(n.nextNode);
- } // 17
-
- Here's a line-by-line description of the program:
-
- 1 Include the declarations for the class RWFileManager. The header
- file <rstream.h> includes either <iostream.h> or <stream.h> for
- input and output , depending on your compiler. See Section 4.
-
- 2 Struct DiskNode is a link in the linked-list. It contains:
-
- 3 The data (an int), and
-
- 4 The offset to the next link. RWoffset is typically "typedef'd"
- to a long int.
-
- 5 This is the constructor for a RWFileManager. It will create a
- new file, called "linklist.dat".
-
- 6 Allocate space on the file to store the offset to the first link.
- This first allocation is considered "special" and will be saved
- by the RWFileManager. It can be retrieved at any time by using
- the member function start().
-
- 7 Allocate space to store the first link. The member function
- allocate() returns the offset to this space. Since each DiskNode
- needs the offset to the next DiskNode, space for the next link
- must be allocated before the current link is written.
-
- 8 Seek to the position to write the offset to the first link. Note
- Rogue Wave Using Class RWFileManager 70
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- that the offset to this position is returned by the member
- function start(). Note also that fm has access to public member
- functions of class RWFile, since class RWFileManager is derived
- from class RWFile.
-
- 9 Write the offset to the first link.
-
- 10 A loop to read integers and store them in a linked-list5.
-
- 11 Allocate space for the next link, storing the offset to it in the
- nextNode field of this link.
-
- 12 Seek to the proper offset to store this link
-
- 13 Write this link.
-
- 14 Since we allocate the next link before we write the current link,
- the final link in the list will have an offset to an allocated
- block that is not used. It must be handled as a special case.
-
- 15 First, deallocate the final unused block.
-
- 16 Next, reassign the offset of the final link to be NIL. When the
- list is read, this will indicate the end of the linked list.
- Finally, re-write the final link, with the correct information.
-
- 17 The destructor for class RWFileManager, which closes the file,
- will be called here.
-
- Having created the linked-list on disk, how might we read it? Here
- is a program that reads the list and prints the stored integer field.
-
- #include <filemgr.h>
- #include <rstream.h>
-
-
-
-
-
- 5 This loop will not work as written with the Turbo C++
- V1.00 compiler due to a bug in the compiler. The stream
- state must be tested explicitly with member function
- good().
-
- Rogue Wave Using Class RWFileManager 71
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- struct DiskNode {
- int data;
- RWoffset nextNode;
- };
-
- main()
- {
- RWFileManager fm("linklist.dat"); // 1
-
- fm.SeekTo(fm.start()); // 2
- RWoffset next;
- fm.Read(next); // 3
-
- DiskNode n;
- while (next != NIL) { // 4
- fm.SeekTo(next); // 5
- fm.Read(n.data); // 6
- fm.Read(n.nextNode);
- cout << n.data << "\n"; // 7
- next = n.nextNode; // 8
- }
- } // 9
-
- Here's a line-by-line description of the program:
- 1 The RWFileManager has been constructed with an old File.
- 2 The member function start() returns the offset to the first space
- ever allocated in the file. In this case, that space will
- contain an offset to the start of the linked-list.
- 3 Read the offset to the first link.
- 4 A loop to read through the linked-list and print each entry.
- 5 Seek to the next link.
- 6 Read the next link.
- 7 Print the integer.
- 8 Get the offset to the next link.
- 9 The destructor for class RWFileManager, which closes the file,
- will be called here.
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWFileManager 72
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 2
-
-
- Using Class RWBTreeOnDiskRWBTreeOnDisk
-
-
-
- Class RWBTreeOnDisk has been designed to manage a B-Tree in a disk
- file. The class represents an ordered collection of associations of
- keys and values, where the ordering is determined internally by
- comparing keys. Given a key, a value can be retrieved. Duplicate
- keys are not allowed.
-
- Keys are arrays of chars. Nominally, they can have up to 16
- characters, although this can be changed by recompiling. The
- ordering in the B-Tree is determined by comparing keys
- lexicographically.
-
- The type of the values is set by a typedef. By default, this is:
-
- typedef long storedValue;
-
- Typically, the values represent an offset to a location in a file
- where an object is stored. Hence, given a key, one can find where an
- object is stored and retrieve it. However, as far as class
- RWBTreeOnDisk is concerned, the value has no special meaning -- it is
- up to you to interpret it.
-
- This class uses class RWFileManager to manage the allocation and
- deallocation of space for the nodes of the B-Tree. The same
- RWFileManager can also be used to manage the space for the objects
- themselves if the B-Tree and data are to be in the same file.
- Alternatively, a different RWFileManager, managing a different file,
- could be used if it is desirable to store the B-Tree and data in
- separate files.
-
- The member functions associated with class RWBTreeOnDisk are
- identical to those of class RWBTree, which manages a B-Tree in
- memory, except that keys are arrays of chars rather than
- Rogue Wave Using Class RWBTreeOnDisk 73
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWCollectable*'s. There are member functions to add a key-value
- pair, find a key, remove a key, operate on all key-value pairs in
- order, determine the height of the tree, return the number of entries
- in the tree, and determine if a key is contained in the tree.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWBTreeOnDisk 74
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 12.1 Construction
-
-
-
- A RWBTreeOnDisk is always constructed from a RWFileManager. If the
- RWFileManager is managing a "newFile", then the RWBTreeOnDisk will
- initialize it with an empty root node. For example, the following
- code fragment constructs a RWFileManager for a new file called
- "filename.dat" and then constructs a RWBTreeOnDisk from it:
-
- #include <disktree.h>
- #include <filemgr.h>
-
- main()
- {
- RWFileManager fm("filename.dat");
-
- // Initializes filename.dat with an empty root:
- RWBTreeOnDisk bt(fm);
- }
-
- 12.2 Example
-
-
-
- In this example, key-value pairs of character strings and offsets to
- RWDates, representing birthdays, are stored. Given a name, a
- birthdate can be retrieved from disk.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWBTreeOnDisk 75
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- #include "disktree.h"
- #include "filemgr.h"
- #include "rwdate.h"
- #include <iostream.h>
- #include <iomanip.h>
-
- main()
- {
- char name[16];
- RWDate birthday;
-
- RWFileManager fm("birthday.dat");
- RWBTreeOnDisk btree(fm);
-
- while(cin >> setw(sizeof(name)) >> name) {// 1
- cin >> birthday; // 2
- RWoffset loc = fm.allocate(birthday.binaryStoreSize()); // 3
- fm.SeekTo(loc); // 4
- birthday.saveOn(&fm); // 5
- btree.insertKeyAndValue(name, loc); // 6
- }
- }
-
- Here's the line-by-line description:
-
- 1 Read the name from standard input. This loop will exit when EOF
- is reached. The object setw() is an "I/O manipulator", a feature
- of the new "Version 2.0 style" iostreams. It insures that no
- more than 16 characters will be read.
-
- 2 Read the corresponding birthday.
-
- 3 Allocate enough space from the RWFileManager to store the
- birthday. Member function binaryStoreSize() is a member function
- that most Rogue Wave classes have. It returns the number of
- bytes necessary to store an object in a binary file.
-
- 4 Seek to the location where the RWDate will be stored.
-
- 5 Store the date at that location. Member function saveOn() is a
- member function that most Rogue Wave classes have. It stores the
- object in a binary file or on an ostream, depending on the type
- of its argument.
-
- Rogue Wave Using Class RWBTreeOnDisk 76
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 6 Insert the key and offset to the object in the B-Tree.
-
- Having stored the names and birthdates on a file, here's how one
- might retrieve them:
-
- #include "disktree.h"
- #include "filemgr.h"
- #include "rwdate.h"
- #include <iostream.h>
- #include <iomanip.h>
-
- main()
- {
- char name[16];
- RWDate birthday;
- RWFileManager fm("birthday.dat");
- RWBTreeOnDisk btree(fm);
- RWoffset loc;
-
- while(1){
- cout << "Give name: ";
- if ( !(cin >> setw(sizeof(name)) >> name) ) break; // 1
- btree.findKeyAndValue(name, loc); // 2
- if( loc==NIL ) // 3
- cerr << "Not found.\n";
- else {
- fm.SeekTo(loc); // 4
- birthday.restoreFrom(&fm); // 5
- cout << "Birthday is " << birthday << NL;// 6
- }
- }
- }
-
- Program description:
-
- 1 The program accepts names until encountering an EOF.
-
- 2 The name is used as a key to the RWBTreeOnDisk, which returns the
- associated value, an offset into the file.
-
- 3 Check to see whether the name was found.
-
- 4 If the name was valid, use the value to seek to the spot where
- the associated birthday is stored.
- Rogue Wave Using Class RWBTreeOnDisk 77
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 5 Read the birthdate from the file.
-
- 6 Print it out.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Using Class RWBTreeOnDisk 78
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 3
-
-
- Introduction to Collection ClassesCollection classesintroduction
-
-
-
-
- 13.1 Introduction
-
-
-
- The Tools.h++ class library has two different types of collection
- classes:
-
- l A set of "generic" collection classes, modeled after Stroustrup,
- Chapter 7.3.5.
-
-
- l A set of Smalltalk -like collection classes.
-
- Despite their very different implementations, the functionality of
- the two sets of classes, as well as the user-interface (member
- function names, etc.), is very similar.
-
-
- 13.1.1Some general concepts
-
- The general objective of the collection classes is to store and
- retrieve pointers to objects. Hence, when you "insert" an object
- into a collection, you are actually telling the collection class to
- store a pointer to it -- the object itself is not actually inserted.
- The storage and retrieval methods to get this pointer back is what
- makes each class different. For example, the linked-lists excel at
- "inserting" an object in the middle of the collection, but are
- relatively slow at finding an object (because each link must be
- searched). On the other hand, inserting an object into a hash table
- is slower, but retrieving it can be much faster. Which class you
- chose will depend on what is important for the application you have
- Rogue WaveIntroduction to Collection Classes 79
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- in mind.
-
- In general, you are responsible for the creation, maintenance and
- destruction of the actual objects themselves, although there are a
- few member function to help you do this.
-
- Now it is time to clarify a few concepts and to identify the jargon
- you are likely to encounter both here and in the literature.
-
-
- 13.1.1.1 An object's identity
-
- Every object that you create has three properties associated with it:
-
- 1. Its "type" (e.g., a RWString or a "double"). In C++, an object's
- type is set at creation. It cannot change.
-
- 2. Its "state" (i.e., the value of the string). The values of all
- the instance variables of an object determine its state. These
- can change.
-
- 3. Its "identity" (i.e., identifies an object uniquely and for all
- time). In C++, an object's identity is determined by its
- address. Each object is associated with one and only one
- address. Note that the reverse is not always true because of
- inheritance. Generally, an address and a type is necessary to
- disambiguate which object you mean within an inheritance
- hierarchy.
-
- Note that different languages use different methods for establishing
- an object's identity. For example, an object-oriented data base
- could use an "object ID" to identify a particular object. It is just
- a property of C++ that an object's address is used.
-
- How an object is "found" within a collection class depends on how you
- use these three properties.
-
-
-
- A key point is that there are two general methods for "finding" an
- object and you will have to keep in mind which you mean. Some
- collection classes can support either method, some can support only
- one.
-
- Rogue WaveIntroduction To Collection Classes 80
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 1. Find an object with a particular state. An example is testing
- two strings for the same value. In the literature, this is
- frequently referred to as two objects testing "isEqual", having
- "equality", "compares equal", having the same "value", or testing
- true for the "=" operator. Here, we will refer to the two
- objects as testing equal ("isEqual"). In general, it is
- necessary to have some knowledge of the two object's type (or
- subtype, in the case of inheritance) in order to find the
- appropriate instance variables to test for equality6.
-
- 2. Finding a particular object (that is, one with the same
- identity). In the literature, this is referred to as two objects
- testing "isSame", or having the same "identity", or testing true
- for the "==" operator. We will refer to this as two objects
- having the same identity.
-
-
-
- In C++, because of multiple inheritance, the address of a base class
- and its associated derived class may not be the same. Because of
- this, if you compare two pointers (i.e., two addresses) to test for
- identity, the types of the two pointers should be the same.
-
-
- Smalltalk uses the operator "=" to test for equality, the operator
- "==" to test for identity. However, in the C++ world, operator "="
- has become firmly attached to meaning assignment, operator "==" to
- generally meaning equality of values. This is the approach we have
- taken.
-
-
-
-
-
-
-
-
- 6 The Rogue Wave collection classes allow a generalized
- test of equality -- it is up to you to define what it
- means for two objects to "be equal". That is, a bit-by-
- bit comparison of the two objects is not done. You could
- define "equality" to mean that a panda is the same as a
- deer because, in your context, they are both mammals.
-
- Rogue WaveIntroduction To Collection Classes 81
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
-
- In the Rogue Wave Classes, the operator "==", when applied to two
- classes, generally means test for equality of values ("isEqual"). Of
- course, when applied to two pointers, it means test for identity.
-
-
- Whether to test for equality or identity will depend on the context
- of your problem. Here are some examples that might help.
-
- Suppose you were maintaining a mailing list. Given a person's name,
- you want to find his or her address. In this case, you would want to
- search for a name that is equal to the name at hand. A Dictionary
- would be appropriate. The key to the Dictionary would be the name,
- the value would be the address.
-
- Suppose you are writing a hypertext application. You need to know in
- which document a particular graphic occurs. This might be done by
- keeping a Dictionary of graphics and their corresponding document.
- In this case however, you would want an IdentityDictionary because
- you need to know in which document a particular graphic occurs. The
- graphic acts as the key, the document as the value.
-
- Suppose you were maintaining a disk cache. You might want to know
- whether a particular object is resident in memory. In this case, an
- IdentitySet might be appropriate. Given an object, you can check to
- see whether it exists in memory.
-
-
- 13.1.1.2 Shallow versus deep copies
-
- There are two ways to make a copy of an object: shallow copying and
- deep copying.
-
- 1. A shallow copy of an object is a new object whose instance
- variables are identical to the old object. For example, a
- shallow copy of a Set will have the same members as the old set.
- The new Set will share objects with the old Set (through
- pointers). Shallow copies are sometimes referred to as using
- reference semantics.
-
- 2. A deep copy of an object will make a copy with entirely new
- instance variables. The new object will not share objects with
- the old object. For example, a deep copy of a Set would not only
- Rogue WaveIntroduction To Collection Classes 82
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- make a new set, but the items inserted into it would also be
- copies of the old items. In a true deep copy, this copying is
- done recursively. Deep copies are sometimes referred to as using
- value semantics.
-
-
-
- The copy constructors of most (but not all) Rogue Wave objects make
- shallow copies. Some of the objects have a copy() member function
- that will return a new object with entirely new instance variables,
- although this copying is not done recursively (that is, the new
- instance variables are shallow copies of the old instance variables).
-
-
- Here's a graphical example. Imagine a Bag (an unordered collection
- of objects with duplicates allowed) that looks like this before a
- copy :
-
-
-
-
-
- A shallow and deep copy of this collection would look like
- (respectively):
-
-
-
-
-
- Note that the deep copy not only made a copy of the bag itself, but
- also, recursively, any objects within it.
-
- Although shallow copies can be useful (and fast, because less copying
- is done), one must be careful because two collections now reference
- the same object. If you delete all the items in one collection, you
- will leave the other collection pointing into nonsense.
-
- The issue of shallow versus deep copies can arise when an object is
- written to disk. If an object includes two or more pointers or
- references to the same object, then when it is restored it is
- important that this morphology be preserved. Classes which inherit
- from RWCollectable inherit a version of saveOn() which guarantees to
- preserve an object's morphology. More on this later.
-
- Rogue WaveIntroduction To Collection Classes 83
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 4
-
-
- "Generic" Collection ClassesCollection Classes generic
-
-
-
- This section describes the first general kind of collection classes
- included in the Tools.h++ Class Library: generic collection classes.
- They are so-called because they use the macros defined in
- <generic.h>, the current approximation to parameterized types in C++.
- For a review, see Stroustrup (1986, p. 209). This is an area of
- rapid evolution of the C++ language -- in the future the language is
- likely to offer built-in parameterized types (see, for example,
- Lippman, 1989) and at that point Rogue Wave expects to support them.
- But, at the moment, the <generic.h> approach is all that we have.
- There is no reason to expect code built on it to become uncompilable
- in the future; presumably it would just be more unwieldy than
- whatever replaces it7.
-
- The general objective of the "generic" collection classes is to store
- and retrieve pointers to objects of a specified type. However, there
- are two exceptions: class GVector(val) and class GSortedVector(val).
- In these classes, the type itself (which could be pointers to other
- objects) is stored.
-
- The storage and retrieval methods and criteria differ from class to
- class. You are responsible for managing the objects themselves.
-
-
-
-
-
-
- 7 Actually, the generic macros are very easy to use, they
- are just difficult to write. Because they are
- preprocessor macros, they must be "all on one line",
- making them very difficult to debug.
-
- Rogue Wave "Generic" Collection Classes 85
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 14.1 Example
-
-
-
- Here is an example of using a GStack (generic stack) to store a set
- of pointers to ints in a last-in, first-out (LIFO) stack. We will go
- through it line-by-line and explain what is happening:
-
- #include <gstack.h> // 1
- #include <rstream.h> // 2
-
- declare(GStack, int) // 3
-
- main()
- {
- GStack(int) gs; // 4
- gs.push(new int(1)); // 5
- gs.push(new int(2)); // 6
- gs.push(new int(3)); // 7
- gs.push(new int(4)); // 8
-
- cout << "Stack now has " << gs.entries() << " entries\n"; //
- 9
-
- int* ip; // 10
- while( ip = gs.pop() ) // 11
- cout << *ip << "\n"; // 12
- }
-
- Program output:
-
- Stack now has 4 entries
- 4
- 3
- 2
- 1
-
- Each program line is detailed below.
-
- 1 This #include defines the preprocessor macro GStackdeclare(type).
- This macro is an elaborate and ugly looking thing that continues
- for many lines and describes how a "generic stack" of objects of
- type type should behave. Mostly, it serves as a restricted
- Rogue Wave "Generic" Collection Classes 86
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- interface to the underlying implementation, which is a singly-
- linked list (class RWSlist). It is restricted because only
- certain member functions of RWSlist can be used (those
- appropriate to stacks) and because the items to be inserted into
- the stack must be of type type.
-
- 2 <rstream.h> is a special Rogue Wave supplied header file that
- includes either the <iostream.h> (new, Release 2.0-compatible I/O
- streams) or <stream.h> (old, Release 1.2-compatible I/O streams)
- header file, depending on what is appropriate for your compiler.
- See Section 4.
-
- 3 This line invokes the macro declare which is defined in the
- header file <generic.h>, supplied with your compiler. If called
- with arguments declare(Class, type), it calls the macro
- Classdeclare with argument type. Hence, in this case, the macro
- GStackdeclare will be called (which was defined in <gstack.h>)
- with argument int.
-
-
-
- To summarize, the result of calling the declare(GStack, int) macro is
- that a new class has been created, especially for your program. It
- will be a stack of pointers to ints. Its name, for all practical
- purposes, is GStack(int).
-
-
- 4 At this line an instance gs of the new class GStack(int) is
- created.
-
- 5-8Four ints were created off the heap and inserted into the stack.
- After statement 8 executes, a pointer to the int "4" will be at
- the top of the stack, a pointer to the int "1" will be at the
- bottom.
-
- 9 The member function entries() of class GStack(int) is called to
- verify how many items are on the stack.
-
- 10 A pointer to an int is declared and defined.
-
- 11 The stack is popped until empty. The member function pop() will
- return and remove a pointer to the item on the top of the stack.
- If there are no more items on the stack it will return zero,
- causing the while loop to terminate.
- Rogue Wave "Generic" Collection Classes 87
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 12 Each item is dereferenced and printed.
-
- Note that the macros have names starting with a capital "G". This
- was chosen so that a generic name like "Stack" wouldn't accidentally
- get expanded by the <gstack.h> macros.
-
-
- 14.2 Declaring generic collection classes
-
-
-
- All of the Tools.h++ generic collection classes are declared using
- the declare macro, defined in the header file <generic.h>, in a
- manner similar to the example above. However, there is one important
- difference in how the Tools.h++ classes are declared versus the
- pattern set by Stroustrup (1986, Section 7.3.5). This is summarized
- below:
-
- typedef int* intP;
- declare(GStack, intP) // Wrong!
- declare(GStack, int) // Correct.
-
- In Stroustrup, the class is declared using a typedef for a pointer to
- the collected item. The Rogue Wave generic classes are declared
- using the item name itself.
-
- There are two exceptions to this rule: classes GVector(val) and
- GSortedVector(val) where a vector of items of type val will be
- created:
-
- declare(GVector,int)
-
- GVector(int) iv;
-
- The vector iv will be a vector of ints (rather than pointers to
- ints).
-
-
- 14.3 User-defined functions
-
-
-
- Some of the member functions of the generic collection classes
- require a pointer to a user-defined function. There are two kinds,
- Rogue Wave "Generic" Collection Classes 88
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- discussed in the following two sections.
-
-
- 14.3.1Tester functions
-
- The first kind of user-defined function is a "tester function". It
- has the form:
-
- RWBoolean tester(const type* ty, const void* a)
-
- where tester is the name of the function, type is the type of the
- members of the collection class, and RWBoolean is a typedef for an
- int (whose only possible values are TRUE or FALSE). The job of the
- tester function is to signal when a certain member of the collection
- has been identified. The decision of how this is done, or what it
- means to have "identified" an object, is left to the user. The user
- can chose to compare addresses (test for two objects being
- "identical"), or look for certain values within the object (test for
- "isEqual"). The first variable ty will point to a member of the
- collection and can be thought of as a "candidate". The second
- variable a is available for your use to be tested against ty for a
- match. It can be thought of as "client data", used to make the
- decision of whether there is a match.
-
- Here is an example that expands on the example in Section 14.1. The
- problem is to push some values onto a stack and then to see if a
- certain value exists on the stack (test for "isEqual").
-
- The member function contains() of class GStack(type) has prototype:
-
- RWBoolean contains( RWBoolean (*t)(const type*, const void*),
- const void* a ) const;
-
- The first argument is RWBoolean (*t)(const type*, const void*). This
- is a pointer to the tester function, for which we will have to
- provide an appropriate definition:
-
-
-
-
-
-
-
-
- Rogue Wave "Generic" Collection Classes 89
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- #include <gstack.h>
- #include <rstream.h>
-
- declare(GStack, int)
-
- RWBoolean myTesterFunction(const int* jp, const void* a) // 1
- {
- return *jp == *(const int*)a; // 2
- }
-
- main()
- {
- GStack(int) gs; // 3
- gs.push(new int(1)); // 4
- gs.push(new int(2)); // 5
- gs.push(new int(3)); // 6
- gs.push(new int(4)); // 7
-
- int aValue = 2; // 8
- if ( gs.contains(myTesterFunction, &aValue) ) // 9
- cout << "Yup.\n";
- else
- cout << "Nope.\n";
- }
-
- Program output:
-
- Yup.
-
- A description of each program line follows.
-
- 1 This is the tester function. Note that the first argument is a
- pointer to the type of objects in the collection, ints in this
- case. The second argument points to an object that can be of any
- type. In this example, it also points to an int. Note that both
- arguments are declared const pointers -- in general the tester
- function should not change the value of the objects being pointed
- to.
-
- 2 The second argument is converted from a const void* to a const
- int*, then dereferenced. The result is a const int. This is
- then compared to the dereferenced first argument, which is also a
- const int. The net result is that this tester function considers
- a match to have occurred when the two ints have the same values
- Rogue Wave "Generic" Collection Classes 90
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- (i.e., they are equal). Note that we could have chosen to have
- identified a particular int (i.e., test for identity).
-
- 3-7These lines are the same as in the example in Section 14.1. A
- generic stack of (pointers to) ints is declared and defined, then
- 4 values are pushed onto it.
-
- 8 This is the value (i.e., "2") that we will look for in the stack.
-
- 9 Here the member function contains() is called, using the tester
- function. The second argument of contains() (a pointer to the
- variable aValue) will appear as the second argument of the tester
- function. The function contains() traverses the entire stack,
- calling the tester function for each item in turn, waiting for
- the tester function to signal a match. If it does, contains()
- returns TRUE, otherwise FALSE.
-
- Note that the second argument of the tester function does not
- necessarily have to be of the same type as the members of the
- collection (although it is in the example above). Here is another
- example where they are not of the same type:
-
- #include <gstack.h>
- #include <rstream.h>
-
- class Foo {
- public:
- int data;
- Foo(int i) {data = i;}
- };
-
- declare(GStack, Foo) // A stack of pointers to Foos
-
- RWBoolean anotherTesterFunction(const Foo* fp, const void* a)
- {
- return fp->data == *(const int*)a;
- }
-
-
-
-
-
-
-
- Rogue Wave "Generic" Collection Classes 91
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- main()
- {
- GStack(Foo) gs;
- gs.push(new Foo(1));
- gs.push(new Foo(2));
- gs.push(new Foo(3));
- gs.push(new Foo(4));
-
- int aValue = 2;
- if ( gs.contains(anotherTesterFunction, &aValue) )
- cout << "Yup.\n";
- else
- cout << "Nope.\n";
- }
-
- Here, a stack of (pointers to) Foos is declared and used, while the
- variable being passed as the second argument to the tester function
- is still a const int*. The tester function must take this into
- account.
-
-
- 14.3.2Apply functions
-
- The second kind of user-defined function is an "apply function". Its
- general form is:
-
- void yourApplyFunction(type* ty, void* a)
-
- where yourApplyFunction is the name of the function and type is the
- type of the members of the collection. Apply functions give you the
- opportunity to perform some operation on each member of a collection
- (perhaps print it out or draw it on a screen). The second argument
- is designed to hold "client data" to be used by the function (perhaps
- the handle of a window on which the object is to be drawn).
-
-
-
-
-
-
-
-
-
-
- Rogue Wave "Generic" Collection Classes 92
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Here is an example, using class GDlist(type) -- a generic doubly-
- linked list:
-
- #include <gdlist.h>
- #include <rstream.h>
-
- class Foo {
- public:
- int val;
- Foo(int i) {val = i;}
- };
-
- declare(GDlist, Foo)
-
- void printAFoo(Foo* ty, void* sp)
- {
- ostream* s = (ostream*)sp;
- (*s) << ty->val << "\n";
- }
-
- main()
- {
- GDlist(Foo) gd;
- gd.append(new Foo(1));
- gd.append(new Foo(2));
- gd.append(new Foo(3));
- gd.append(new Foo(4));
-
- gd.apply(printAFoo, &cout);
- }
-
- Program output:
-
- 1
- 2
- 3
- 4
-
- The items are appended at the tail of the list (see Part II: Class
- Reference). For each item, the apply() function calls the user-
- defined function printAFoo() with the address of the item as the
- first argument and the address of an ostream (an output stream) as
- the second argument. The job of printAFoo() is to print out the
- value of member data val. Because apply() scans the list from
- Rogue Wave "Generic" Collection Classes 93
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- beginning to end, the items will come out in the same order in which
- they were inserted.
-
- With some care, apply functions can be used to change the objects in
- a collection. For example, you could use an apply function to change
- the value of member data val in the example above, or to delete all
- member objects. But, in the latter case, you must be careful not to
- use the collection again.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave "Generic" Collection Classes 94
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 5
-
-
-
-
- Smalltalk -like Collection ClassesCollection Classes Smalltalk-like
-
-
-
-
- 15.1 Introduction
-
-
-
- The second general type of collection classes provided with the
- Tools.h++ Class Library is a set of "Smalltalk-80-like Collection
- Classes". In this approach, objects to be collected must inherit the
- abstract base class "RWCollectable" using either single or multiple
- inheritance. The principal advantage of this approach is that the
- programming-interface is much cleaner and the collection classes are
- far more powerful. The disadvantage is that the objects are slightly
- larger and the collection classes are slightly slower.
-
- Many of these classes have a typedef to either the corresponding
- Smalltalk names, or to a generic name. Table 15-1 summarizes.
-
-
-
- Class Iterator "Smalltalk" Implemented as
- typedef
-
-
- RWBag RWBagIterator Bag Dictionary of occurrences
-
- RWBinaryTree RWBinaryTree-Iterator SortedCollection Binary tree
-
- RWBTree B-Tree in memory
-
-
- Rogue Wave Smaltalk_-like Collection Classes 95
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWBTreeDictionary B-Tree of associations
-
- RWCollection RWIterator Collection Abstract base class
-
-
-
- Table 15-1. Smalltalk-like collection classes, their iterators and
- implementations.
- (continued next page)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 96
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Table 15-1. continued
-
-
-
- Class Iterator "Smalltalk" Implemented as
- typedef
-
-
- RWDlistCollectables RWDlistCollectables Doubly-linked list
-
- Iterator
-
- RWHashDictionary RWHashDictionary- Dictionary Hash table of
-
- Iterator associations
-
- RWIdentity RWHashDictionary- Identity Hash table of
-
- Dictionary Iterator Dictionary associations
-
- RWIdentitySet RWSetIterator IdentitySet Hash table
-
- RWOrdered RWOrderedIterator Ordered Vector of pointers
-
- Collection
-
- RWSequenceable RWIterator Sequenceable Abstract base class
-
- RWSet RWSetIterator Set Hash table
-
- RWSlist RWSlistCollectables- LinkedList Singly-linked list
-
- Collectables Iterator
-
- RWSlist (n/a) Queue Singly-linked list
-
- CollectablesQueue
-
- RWSlist (n/a) Stack Singly-linked list
-
- CollectablesStack
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 97
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWSortedVector RWSortedVector- Vector of pointers,
-
- Iterator using insertion sort
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 98
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
-
-
- RWCollectable
-
- RWCollection (abstract base class)
-
- RWBinaryTree
-
- RWBTree
-
- RWBTreeDictionary
-
- RWBag
-
- RWSequenceable (abstract base class)
-
- RWDlistCollectables (Doubly-linked lists)
-
- RWOrdered
-
- RWSortedVector
-
- RWSlistCollectables (Singly-linked lists)
-
- RWSlistCollectablesQueue
-
- RWSlistCollectablesStack
-
- RWSet
-
- RWIdentitySet
-
- RWHashDictionary
-
- RWIdentityDictionary
-
-
-
-
-
- Table 15-2. The class hierarchy of the Smalltalk_-like collection classes.
- Note that some of these classes use multiple-inheritance: this
- hierarchy is shown relative to the RWCollectable base class.
- Rogue WaveSmalltalk_-like Collection Classes 99
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 100
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.2 Example
-
-
-
- To get us oriented, it is always good to look at an example. This
- code uses a SortedCollection to store and order a set of
- RWCollectableStrings. We will go through it line-by-line and explain
- what is happening:
-
- #include <bintree.h> // 1
- #include <collstr.h> // 2
- #include <rstream.h>
-
- main()
- {
-
- // Construct an empty SortedCollection
- SortedCollection sc; // 3
-
- // Insert some RWCollectableStrings:
- sc.insert(new RWCollectableString("George")); // 4
- sc.insert(new RWCollectableString("Mary"));// 5
- sc.insert(new RWCollectableString("Bill"));// 6
- sc.insert(new RWCollectableString("Throkmorton")); // 7
-
- // Now iterate through the collection, printing all members:
- RWCollectableString* str; // 8
- RWSortedCollectionIterator sci(sc); // 9
- while( str = (RWCollectableString*)sci() )// 10
- cout << *str << NL; // 11
- }
-
- Program output:
-
- Bill
- George
- Mary
- Throkmorton
-
- SortedCollection is actually a typedef for a RWBinaryTree. Objects
- inserted into it are stored in order according to relative values
- returned by the virtual function compareTo() (see Section 15.10.5).
-
- Rogue WaveSmalltalk_-like Collection Classes 101
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 1 This first #include statement declares the class RWBinaryTree,
- the true identity of a SortedCollection.
-
- 2 The second #include declares class RWCollectableString which is a
- derived class with classes RWString and RWCollectable as base
- classes. Multiple inheritance was used to create this class.
- Most of its functionality is inherited from class RWString. Its
- ability to be "collected" was inherited from class RWCollectable.
-
- 3 An empty SortedCollection was created at this line.
-
- 4-7Four RWCollectableStrings were created off the heap and inserted
- into the collection. See Part II: Class Reference for details on
- constructors for RWCollectableStrings. The insertions were not
- done in any particular order.
-
- 8 A pointer to a RWCollectableString was declared and defined here.
-
- 9 An iterator was constructed from the SortedCollection sc.
-
- 10 The iterator is then used to step through the entire collection,
- retrieving each value in order. The function call operator
- (i.e., operator()) has been overloaded for the iterator to mean
- "step to the next item and return a pointer to it". All
- Tools.h++ iterators work this way. See Stroustrup (1986, Section
- 7.3.2) for an example and discussion of iterators, as well as
- Section 15.6 of this manual. The typecast
-
- str = (RWCollectableString*)sci()
-
- is necessary because the iterator returns a RWCollectable* (that
- is, a pointer to a RWCollectable) which must then be cast into
- its actual identity.
-
- 11 Finally, the pointer str is dereferenced and printed. The
- ability of a RWCollectableString to be printed is inherited from
- its base class RWString. The macro NL will print a newline,
- irregardless of the type of streams your compiler supports. See
- Section 4.
-
- When run, the program prints out the four collected strings "in
- order". For class RWCollectableString, this means in lexicographical
- order.
-
- Rogue WaveSmalltalk_-like Collection Classes 102
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.3 Virtual functions inherited from RWCollection
-
-
-
- The Smalltalk_-like collection classes inherited from the abstract
- base class RWCollection which, in turn, inherits from the abstract
- base class RWCollectable, described below (making it is possible to
- have collections of collections).
-
- An "abstract base class" is a class that is not intended to be used
- per se, but rather to be inherited by some other class. Its virtual
- functions provide a template of functionality that act as a surrogate
- for the derived class. The class RWCollection is such a class. It
- provides a template for "collection" classes by declaring various
- virtual functions such as insert(), remove(), entries(), etc.
-
- This section describes the virtual functions inherited by all of the
- Smalltalk-like collections. Any collection can be expected to
- understand them.
-
-
- 15.3.1insert()
-
- virtual RWCollectable* insert(RWCollectable*);
-
- A pointer to an object is put into a collection by using insert().
- It inserts in the "most natural way" for the collection. For a
- stack, this means it is pushed onto the stack. For a queue, the item
- is appended to the queue. For a sorted collection, the item is
- inserted such that items before it compare less than (or equal to if
- duplicates are allowed) itself, items after it compare greater than
- itself. See the example in Section 15.2 for an example of insert().
-
-
- 15.3.2find() and friends
-
- virtual RWBoolean contains(const RWCollectable*) const;
- virtual unsigned entries() const;
- virtual RWCollectable* find(const RWCollectable*) const;
- virtual RWBoolean isEmpty() const;
- virtual unsigned occurrencesOf(const RWCollectable*) const;
-
- These functions test how many objects the collection contains and
- Rogue WaveSmalltalk_-like Collection Classes 103
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- whether it contains a particular object. The function isEmpty()
- returns true if the collection contains no objects. The function
- entries() returns the total number of objects that the collection
- contains.
-
- The function contains() returns TRUE if the argument is equal to an
- item within the collection. The meaning of "is equal to" depends on
- the collection and the type of object being tested. Hashing
- collections use the virtual function isEqual() to test for equality
- (with the hash() function used to narrow the choices). Sorted
- collections search for an item that "compares equal" (i.e.
- compareTo() returns zero) to the argument.
-
- The virtual function occurrencesOf() is similar to contains(), but
- returns the number of items that are equal to the argument.
-
- The virtual function find() returns a pointer to an item that is
- equal to its argument.
-
- Here is an example that builds on the example in Section 15.2 and
- uses some of these functions:
-
- #include <bintree.h> // 1
- #include <collstr.h> // 2
- #include <rstream.h>
-
- main()
- {
-
- // Construct an empty SortedCollection
- SortedCollection sc; // 3
-
- // Insert some RWCollectableStrings:
- sc.insert(new RWCollectableString("George")); // 4
- sc.insert(new RWCollectableString("Mary"));// 5
- sc.insert(new RWCollectableString("Bill"));// 6
- sc.insert(new RWCollectableString("Throkmorton")); // 7
- sc.insert(new RWCollectableString("Mary"));// 8
-
- cout << sc.entries() << "\n"; // 9
-
- RWCollectableString dummy("Mary"); // 10
- RWCollectable* t = sc.find( &dummy ); // 11
-
- Rogue WaveSmalltalk_-like Collection Classes 104
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- if(t){ // 12
- if(t->isA() == dummy.isA()) // 13
- cout << *(RWCollectableString*)t << "\n"; // 14
- }
- else
- cout << "Object not found.\n"; // 15
-
- cout << sc.occurrencesOf(&dummy) << "\n";// 16
-
- Program output:
-
- 5
- Mary
- 2
-
- Here's the line-by-line description:
-
- 1-7These lines are as in Section 15.2.
-
- 8 Insert another instance with the value "Mary".
-
- 9 This statement prints out the total number of entries in the
- sorted collection: 5.
-
- 10 A throwaway variable "dummy" is constructed, to be used to test
- for the occurrences of strings containing "Mary".
-
- 11 The collection is asked to return a pointer to the first object
- encountered that compares equal to the argument. A nil pointer
- (zero) is returned if there is no such object.
-
- 12 The pointer is tested to make sure it is not nil.
-
- 13 Paranoid check. In this example, it is obvious that the items in
- the collection must be of type RWCollectableString. In general,
- it may not be obvious.
-
- 14 Because of the results of step 13, the cast to a
- RWCollectableString pointer is safe. The pointer is then
- dereferenced and printed.
-
- 15 If the pointer t was nil, then an error message would have been
- printed here.
-
- Rogue WaveSmalltalk_-like Collection Classes 105
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 16 The call to occurrencesOf() returns the number of items that
- compare equal to its argument. In this case, two items are found
- (the two occurrences of "Mary").
-
-
- 15.3.3remove() functions
-
- virtual RWCollectable* remove(const RWCollectable*);
- virtual void removeAndDestroy(const RWCollectable*);
-
- The function remove() looks for an item that is equal to its argument
- and removes it from the collection, returning a pointer to it. It
- returns nil if no item was found.
-
- The function removeAndDestroy() is similar except that rather than
- return the item, it deletes it, using the virtual destructor
- inherited by all RWCollectable items. You must be careful when using
- this function that the item was actually allocated off the heap (i.e.
- not the stack) and that it is not shared with another collection.
-
- Expanding on the example above:
-
- RWCollectable* oust = sc.remove(&dummy);// 17
- delete oust; // 18
-
- sc.removeAndDestroy(&dummy); // 19
-
- 17 Removes the first occurrence of the string containing "Mary" and
- returns a pointer to it. This pointer will be nil if there was
- no such item.
-
- 18 Delete the item (which was originally allocated off the heap).
- There is no need to check the pointer against nil because the
- language guarantees that it is always OK to delete a nil
- pointer8.
-
- 19 In this statement, the remaining occurrence of "Mary" is not only
- removed, but also deleted.
-
-
- 8 Actually, at the time of this writing, the Zortech V2.06
- through V2.18 compilers will abort if an attempt is made
- to delete a nil pointer.
-
- Rogue WaveSmalltalk_-like Collection Classes 106
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.3.4apply() functions
-
- virtual void apply(RWapplyCollectable ap, void* x);
-
- An efficient method for examining the members of a Smalltalk-like
- collection is member function apply(). The first argument
- (RWapplyCollectable) is a typedef:
-
- typedef void (*RWapplyCollectable)(RWCollectable*, void*);
-
- that is, a pointer to a function with prototype:
-
- void yourApplyFunction(RWCollectable* item, void* x)
-
- where yourApplyFunction is the name of the function. You must supply
- this function. It will be called for each item in the collection, in
- whatever order is appropriate for the collection, and passed a
- pointer to the item as its first argument. The second argument (x)
- is passed through from the call to apply() and is available for your
- use. It could be used, for example, to hold a handle to a window on
- which the object is to be drawn, etc.
-
- Note the similarity to the apply() function of the generic collection
- classes (Section 14.3.2). The difference is in the type of the first
- argument of the user-supplied function (RWCollectable* rather than
- type*). As with the generic classes, you must be careful that you
- cast the pointer item to the proper derived class.
-
- The apply functions generally employ the "most efficient method" for
- examining all members of the collection. This is their great
- advantage. Their disadvantage is that they are slightly clumsy to
- use, requiring the user to supply a separate function9.
-
-
-
-
- 9 The functional equivalent to apply() in the Smalltalk
- world is "do". It takes just one argument -- a piece of
- code to be evaluated for each item in the collection.
- This keeps the method and the block to be evaluated
- together in one place, resulting in cleaner code. As
- usual, the C++ approach is messier.
-
- Rogue WaveSmalltalk_-like Collection Classes 107
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.3.5Functions clear() and clearAndDestroy()
-
- virtual void clear();
- virtual void clearAndDestroy();
-
- The function clear() removes all items from the collection.
-
- The function clearAndDestroy() not only removes the items, but also
- calls the virtual destructor for each item. Although it does check
- to see if the same item occurs more than once in a collection (by
- building an IdentitySet internally) and thereby deletes each item
- only once, it must still be used with care. It cannot check to see
- whether an item is shared between two different collections. You
- must also be certain that all possible members of the collection were
- allocated off the heap.
-
-
- 15.4 Other functions shared by all RWCollections
-
-
-
- There are several other functions that are shared by all classes that
- inherit from RWCollection. Note that these are not virtual
- functions.
-
-
- 15.4.1Class conversions
-
- RWBag asBag() const;
- RWSet asSet() const;
- RWOrdered asOrderedCollection() const;
- RWBinaryTree asSortedCollection() const
-
- These functions allow any collection class to be converted into a
- RWBag, RWSet, RWOrdered, or a SortedCollection (i.e., a
- RWBinaryTree).
-
-
- 15.4.2Inserting and removing other collections
-
- void operator+=(const RWCollection&);
- void operator-=(const RWCollection&);
-
- Rogue WaveSmalltalk_-like Collection Classes 108
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- These functions insert or remove (respectively) the contents of their
- argument.
-
-
- 15.4.3Selection
-
- typedef RWBoolean
- (*testCollectable)(const RWCollectable*, const void*);
-
- RWCollection* select(testCollectable tst, void*);
-
- The function select() evaluates the function pointed to by tst for
- each item in the collection. It inserts those items for which the
- function returns TRUE into a new collection of the same type as self
- and returns a pointer to it. This new collection is allocated off
- the heap, hence you are responsible for deleting it when done.
-
-
- 15.5 Virtual functions inherited from RWSequenceable
-
-
-
- The abstract base class RWSequenceable is derived from RWCollection.
- Collections that inherit from it have an inate ordering. That is,
- the ordering is meaningful (unlike, say, a hash table).
-
- virtual RWCollectable*& at(int i);
- virtual const RWCollectable* at(int i) const;
-
- These virtual functions allow access to the i'th item in the
- collection, similar to subscripting an array. The compiler choses
- which function to use on the basis of whether or not your collection
- has been declared "const". If it has, the second variant is used,
- otherwise the first. The first can be used as an lvalue:
-
- RWOrdered od;
- od.insert(new RWCollectableInt(0)); // 0
- od.insert(new RWCollectableInt(1)); // 0 1
- od.insert(new RWCollectableInt(2)); // 0 1 2
-
- delete od(1); // Use variant available for RWOrdered
- od.at(1) = new RWCollectableInt(3); // 0 3 2
-
- These operation are very efficient for the class RWOrdered (which is
- Rogue WaveSmalltalk_-like Collection Classes 109
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- implemented as a vector) but, as you might expect, relatively
- inefficient for classes implemented as a linked-list (the entire list
- must be traversed in order to find a particular index).
-
- virtual RWCollectable* first() const;
- virtual RWCollectable* last() const;
-
- These functions return the first or last item in the collection,
- respectively, or nil if the collection is empty.
-
- virtual int index(const RWCollectable*) const;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 110
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- This function returns the index of the first object that is equal to
- the argument:
-
- RWOrdered od;
- od.insert(new RWCollectableInt(6)); // 6
- od.insert(new RWCollectableInt(2)); // 6 2
- od.insert(new RWCollectableInt(4)); // 6 2 4
-
- RWCollectableInt dummy(2);
- cout << od.index(&dummy) << "\n";
-
- Program output:
-
- 1
-
- virtual RWCollectable* insertAfter(int, RWCollectable*);
-
- This function inserts its second argument after the item at the index
- of the first argument.
-
- RWOrdered od;
- od.insert(new RWCollectableInt(6)); // 6
- od.insert(new RWCollectableInt(2)); // 6 2
- od.insertAfter(0, new RWCollectableInt(4)); // 6 4 2
-
- 15.6 Iterators
-
-
-
- An iterator is an alternative method to the apply() function for
- visiting all of the items in a collection. We saw an example of one
- in action in Section 15.2. The advantage of an iterator is that it
- maintains an internal state, allowing two important benefits: more
- than one iterator can be constructed from the same collection, and
- all of the items need not be visited in a single sweep.
-
- Iterators are always constructed from the collection itself. For
- example:
-
- SortedCollection sc;
- .
- .
- .
- SortedCollectionIterator sci(sc);
- Rogue WaveSmalltalk_-like Collection Classes 111
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- If you change the collection by adding or deleting objects while an
- iterator is active, the state of the iterator becomes undefined --
- using it could bring unpredictable results. The member function
- reset() will bring it back to its senses.
-
- At any given moment the iterator "marks" an object in the collection.
- You can think of it as the "current" object. There are various
- methods for moving this "mark".
-
- Most of the time you will probably be using member function
- operator(). It is designed to always advance to the next object,
- then return it. It always returns nil (i.e., zero) when the end of
- the collection is reached.
-
- Some iterators have other member functions for manipulating the mark,
- such as findNext() or removeNext().
-
- Member function key() always returns a pointer to the current object.
- For some collection classes, the "current object" is undefined
- immediately after the construction of an iterator (or after calling
- reset()) -- you must position the iterator first before calling
- key().
-
- For most collections, using member function apply() is much faster
- than using an iterator. This is particularly true for the sorted
- collections -- usually a tree has to be traversed, requiring that the
- parent of a node be stored on a stack. Function apply() uses the
- program's stack, while the sorted collection iterator must maintain
- its own. The former is much more efficient.
-
-
- 15.7 Dictionaries
-
-
-
- Tools.h++ provides two Smalltalk-like dictionary classes,
- RWHashDictionary (Dictionary class implemented as a hash table) and
- RWBTreeDictionary (Dictionary class implemented as a B-Tree), for the
- storage and retrieval of key-value pairs. Both keys and values must
- inherit abstract base class RWCollectable. Member functions are
- provided to insert a key-value pair, and to find or remove a key
- and/or a value, using a key. Function apply() is no longer
- appropriate, and a new function applyToKeyAndValue() visits each key-
- Rogue WaveSmalltalk_-like Collection Classes 112
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- value pair.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 113
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.8 A note on how objects are found
-
-
-
-
-
- It is important to note that it is the virtual functions of the
- object within the collection that gets called when comparing or
- testing a target for equality, not that of the target.
-
-
- For example, consider the following code fragment:
-
- SortedCollection sc;
- RWCollectableString member;
-
- sc.insert(&member);
-
- RWCollectableString target;
- RWCollectableString* p = (RWCollectableString*)sc.find(&target);
-
- It is the virtual functions of the objects within the collection,
- such as member, that will get called, not the virtual functions of
- target:
-
- member.compareTo(&target); // This will get called.
- target.compareTo(&member); // Not this.
-
- 15.8.1Hash collections
-
- Hashing is an efficient method for finding an object within a
- collection. All of the collection classes that use it use the same
- general strategy. First, member function hash() of the target gets
- called to find a candidate within the hash table. Because more than
- one key can hash to the same value, member function isEqual() of the
- candidate (see above) is called to confirm the match. If the match
- is not confirmed, the algorithm searches for additional candidates by
- using a secondary hash value, derived from the first hash value. If
- this leads to additional candidates, these are tested, in order, by
- using member function isEqual(). The search stops with either a
- successful match or when there are no more candidates.
-
- In general, because of this combination of primary and secondary
- Rogue WaveSmalltalk_-like Collection Classes 114
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- hashing values and the complexity of most hashing algorithms, the
- ordering of the objects within a hash collection will not make a lot
- of sense. Hence, when the apply() function or an iterator scans
- through the hashing table, the objects will not be visited in any
- particular order.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 115
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.9 Storage and retrieval of "Collectable" objects
-
-
-
- The storage and retrieval of objects that inherit from RWCollectable
- is a powerful and adaptable feature of the Tools.h++ Class Library.
- It is done through the following four functions:
-
- static RWCollectable* RWCollectable::restoreFrom(RWvistream&);
- static RWCollectable* RWCollectable::restoreFrom(RWFile&);
- void RWCollectable::saveOn(RWvostream&) const;
- void RWCollectable::saveOn(RWFile&) const
-
- These function not only allow the storage and retrieval of
- collections and their inserted objects, but also their morphology.
- For example, a collection with multiple pointers to the same object
- could be be saved and restored. Or a circularly linked list. Note
- that they are not virtual functions -- the declarations (and
- definitions) reside in the base class RWCollectable. You should not
- override them.
-
-
-
- Note that this ability to restore the morphology of an object is a
- property of the base class RWCollectable. It can be used by any
- object that inherits from RWCollectable, not just the collection
- classes (which inherit from RWCollection, a derived class of
- RWCollectable). We will see how to do this in Section 15.11.
-
-
- Here's an example of the use of these functions that builds on the
- example of Section 15.2:
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 116
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- #include <bintree.h>
- #include <collstr.h>
- #include <pstream.h>
-
- main()
- {
-
- // Construct an empty SortedCollection
- SortedCollection sc;
-
- // Insert, but to make things interesting, add an object twice.
-
- RWCollectableString* george =
- new RWCollectableString("George");
-
- sc.insert(george); // Insert once
- sc.insert(new RWCollectableString("Mary"));
- sc.insert(george); // Insert twice
- sc.insert(new RWCollectableString("Bill"));
- sc.insert(new RWCollectableString("Throkmorton"));
-
- // Store in ascii to standard output:
- sc.saveOn(RWpostream(cout));
- }
-
- Note that we have inserted one item into the collection twice. That
- is, two items in the collection are identical. Graphically, the
- SortedCollection looks something like this:
-
-
-
- The function saveOn() stores a shallow copy of a RWCollectable. That
- is, only only one copy of "George" is stored.
-
- The resulting image can be read back in and faithfully restored using
- the companion member function restoreFrom(). Note, however, that
- restoreFrom() is a static member function of class RWCollectable. It
- reads an object from the file or stream, figures out what type it is,
- and then creates it off the heap. It then calls this newly created
- object's virtual function restoreGuts() (to be described later) to
- read its state back in from the file or stream. Function
- restoreFrom() is declared static because in general, one does not
- know what type of object to expect when reading from the file, hence
- one cannot create it until "read-time".
- Rogue WaveSmalltalk_-like Collection Classes 117
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 118
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Enough said! It's time to read our collection back in:
-
- #include <bintree.h>
- #include <collstr.h>
- #include <pstream.h>
-
- main()
- {
- RWpistream str(cin);
-
- SortedCollection* sc =
- (SortedCollection*)RWCollectable::restoreFrom(str); // 1
-
- RWCollectableString temp("George"); // 2
-
- // Find a "George":
- RWCollectableString* g =
- (RWCollectableString*)sc->find(&temp); // 3
-
- // "g" now points to a string with the value "George"
- // How many occurrences of g are there in the collection?
-
- unsigned count = 0; // 4
- SortedCollectionIterator sci(*sc); // 5
- RWCollectableString* item;
- while ( item = (RWCollectableString*)sci() )// 6
- if ( item==g ) count++; // 7
- cout << count;
- }
-
- Program output:
-
- 2
-
- Here's the line-by-line description:
-
- 1 On this line, restoreFrom(RWvistream&) reads an object from the
- input stream cin, figures out that it is a SortedCollection and
- creates a new SortedCollection off the heap. Then, it calls
- SortedCollection's virtual function restoreGuts() which
- recursively calls restoreFrom() for each member of the
- collection. If restoreFrom() encounters a reference to a
- previous object, it just returns the old address, rather than
- create a new one off the heap.
- Rogue WaveSmalltalk_-like Collection Classes 119
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 2 A temporary string with value "George" is created in order to
- search for a string within the newly created SortedCollection
- with the same value.
-
- 3 The SortedCollection is searched for an occurrence of a string
- with value "George". The pointer "g" points to such a string.
-
- 4 Here's how we can prove that there are actually two entries in
- the collection that point to the same George. Initialize a
- counter to zero.
-
- 5 As before, create an iterator from the collection.
-
- 6 Iterate through the collection, item by item, returning a pointer
- for each item.
-
- 7 Test whether this pointer equals g. That is, test for identity,
- not just equality.
-
- The program's output is "2", indicating that there are actually two
- pointers to the same object "George".
-
-
- 15.10Designing an RWCollectable class
-
-
-
- In this section, we discuss the necessary steps to design a new
- RWCollectable class, perhaps one that you will use in your own work.
- Once designed, this class can take full advantage of all of the
- functionality of the Smalltalk-like collection classes.
-
-
- 15.10.1 Virtual functions inherited from RWCollectable
-
- The Smalltalk-like collection classes require that all objects to be
- collected inherit the abstract base class RWCollectable, either
- directly, or by using multiple inheritance.
-
- Class RWCollectable declares the following virtual functions (See
- Part II: Class Reference for a complete description of class
- RWCollectable):
-
-
- Rogue WaveSmalltalk_-like Collection Classes 120
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- virtual ~RWCollectable();
- virtual ClassID isA() const;
- virtual int compareTo(const RWCollectable*) const;
- virtual unsigned hash() const;
- virtual RWBoolean isEqual(const RWCollectable*) const;
- virtual RWCollectable* newSpecies() const;
- virtual void restoreGuts(RWvistream&);
- virtual void restoreGuts(RWFile&);
- virtual void saveGuts(RWvostream&) const;
- virtual void saveGuts(RWFile&) const;
-
- (RWBoolean is a typedef for an int and ClassID is a typedef for an
- unsigned short.) Any class that derives from class RWCollectable
- should be able to understand any of these methods. Although default
- definitions are given for all of them in the base class
- RWCollectable, it is best for the class designer to provide
- definitions that are tailored to the class at hand.
-
-
- 15.10.2 An example
-
- The best way to illustrate how to supply appropriate definitions is
- by using an example. Suppose we would like to collect and retrieve
- instances of an Automobile class. Its declaration might look
- something like this:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 121
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- class Automobile : public RWCollectable {
- private:
- RWString marque; // The manufacturer
- double price;
- int horsepower;
- public:
- // Constructor:
- Automobile() { } // Default constructor
- Automobile(RWString name, double pricetag, int hp) :
- marque(name), price(pricetag), horsepower(hp) { }
-
- // Inherited from class "RWCollectable":
- ClassID isA() const;
- int compareTo(const RWCollectable*) const;
- RWBoolean isEqual(const RWCollectable*) const;
- unsigned hash() const;
- RWCollectable* newSpecies() const;
- void restoreGuts(RWFile&);
- void restoreGuts(RWvistream&);
- void saveGuts(RWFile&) const;
- void saveGuts(RWvostream&) const;
- .
- .
- .
- // Possible, additional, functionality
- };
-
- All collectable classes are required to have a default constructor
- (i.e., one that takes no arguments). This is also a good habit to
- get into when working with C++. Appropriate definitions for the
- virtual functions must now be chosen.
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 122
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.10.3 Object destruction
-
- All objects inheriting from class RWCollectable inherit a virtual
- destructor. Hence, the actual type of the object need not be known
- until runtime in order to delete the object. This allows all items
- in a collection to be deleted without knowing their actual type.
-
-
- 15.10.4 Virtual function isA()
-
- virtual ClassID isA() const;
-
- The virtual function isA() returns a "class ID", a unique number that
- identifies the class. This number can be used to test which class an
- object belongs to. The name "ClassID" is actually a typedef to an
- unsigned short. Numbers from 0x8000 (hex) and up are reserved for
- use by Rogue Wave. There is a set of class symbols defined in
- <tooldefs.h> for the Tools.h++ Class Library . Generally, these
- follow the pattern of a double underscore followed by the class name
- with all letters in upper case. For example:
-
- RWCollectableString yogi;
- yogi.isA() == __RWCOLLECTABLESTRING; // Evaluates TRUE
-
- For our example, here is an appropriate definition:
-
- ClassID Automobile::isA() const {return 123;}
-
- 15.10.5 Virtual function compareTo()
-
- virtual int compareTo(const RWCollectable*) const;
-
- The virtual function compareTo() is used to order objects relative to
- each other in the collection classes that depend on such ordering,
- such as RWBinaryTree or RWBTree.
-
-
- The function "int compareTo(const RWCollectable*) const" should
- return a number greater than zero if self is "greater than" the
- argument, a number less than zero if self is "less than" the
- argument, and zero if self is "equal to" the argument. This last
- case is sometimes referred to as "comparing equal", not be be
- confused with "is equal" (see Section 15.10.6, below).
- Rogue WaveSmalltalk_-like Collection Classes 123
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- The definition (and meaning) of whether one object is greater than,
- less than, or equal to another object is left to the class designer.
- The default definition, as defined in class RWCollectable, is to
- compare the two addresses of the objects.
-
-
- Note that the default definition (comparing the addresses of the two
- objects) should really be thought of as a placeholder -- in practice,
- it is not very useful and could vary from run-to-run of a program.
-
- Here is an example that uses compareTo() as well as isEqual() and
- hash().
-
- RWCollectableString a("a");
- RWCollectableString b("b");
- RWCollectableString a2("a");
-
- a.compareTo(&b); // Returns -1
- a.compareTo(&a2); // Returns 0 ("compares equal")
- b.compareTo(&a); // Returns 1
-
- a.isEqual(&a2); // Returns TRUE
- a.isEqual(&b); // Returns FALSE
-
- a.hash() // Returns 96 (operating system dependent)
-
- Note that the compareTo() function for RWCollectableStrings has been
- defined to compare strings lexicographically. Either case-sensitive
- of case-insensitive comparisons can be done. See class RWString in
- Part II: Class Reference for details.
-
- Here is a possible definition of compareTo() for our example:
-
- int Automobile::compareTo(const RWCollectable* c) const
- {
- const Automobile* ap = (const Automobile*)c;
- if ( price == ap->price ) return 0;
- return price > ap->price ? 1 : -1;
- }
-
- Here, we are using the price of an automobile as a measure of its
- "ordering" relative to other automobiles. There are many other
- possible choices (such as the horsepower, lexicographical ordering of
- Rogue WaveSmalltalk_-like Collection Classes 124
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- the marque, etc.). Which one you chose will depend on your
- particular problem.
-
- Of course, there is a hazard here. We have been glib in assuming
- that the actual type of the RWCollectable which c points to is always
- an Automobile. If a careless user inserted, say, a
- RWCollectableString into the collection, then the results of the cast
- (const Automobile*)c would be invalid and dereferencing it could
- bring disaster. This is a glaring deficiency in C++ that the user
- must constently be aware of. The necessity for all virtual functions
- to have all the same signatures requires that they return the lowest
- common denominator, in this case, class RWCollectable. The net
- result is that all compile-time type checking breaks down.
-
-
-
- One must be careful that the members of a collection are either
- homogeneous (i.e., all of the same type), or that there is some way
- of telling them apart. The member function isA() can be used for
- this.
-
-
-
- 15.10.6 Virtual function isEqual()
-
- RWBoolean isEqual(const RWCollectable* c) const;
-
- The virtual function isEqual() plays a similar role to the "tester
- function" of the generic collection classes (Section 14.3.1).
-
-
-
- The function "RWBoolean isEqual(const RWCollectable*)" should return
- TRUE if the object and its argument are considered a "equal", FALSE
- otherwise. The definition of "equal" is left to the class designer.
- The default definition, as defined in class RWCollectable, is to test
- the two addresses for equality, that is to test for identity.
-
-
- Note that "isEqual" need not necessarily be defined as "being
- identical", that is, having the same address (although this is the
- default), but rather, that they are equivalent in some sense. In
- fact, the two objects need not even be of the same type. The only
- requirement is that the object passed as an argument inherit type
- Rogue WaveSmalltalk_-like Collection Classes 125
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- RWCollectable. However, you are responsible for making sure that any
- typecasts you do are appropriate.
-
- Also note that there is no formal requirement that two objects which
- "compare equal" (i.e., compareTo() returns zero) must also return
- TRUE from isEqual(), although it is hard to imagine a situation where
- this wouldn't be the case.
-
- For our example above, an appropriate definition might be:
-
- RWBoolean Automobile::isEqual(const RWCollectable* c) const
- {
- const Automobile* ap = (const Automobile*)c;
-
- return marque == ap->marque &&
- horsepower == ap->horsepower &&
- price == ap->price;
- }
-
- Here, we are casting the variable c, a pointer to the abstract base
- class RWCollectable, to a pointer to an Automobile, which we are
- calling "ap". Then all of the members of Automobile are checked for
- equality.
-
-
- 15.10.7 Virtual function hash()
-
- unsigned hash() const;
-
-
- The function hash() should return an appropriate hashing value for
- the object.
-
-
- A possible definition for hash() for our example might be:
-
- unsigned Automobile::hash() const
- {
- return marque.hash();
- }
-
- Here, we have just returned the hash value of the manufacturer's
- name.
-
- Rogue WaveSmalltalk_-like Collection Classes 126
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.10.8 Virtual function newSpecies()
-
- The job of this function is to return a pointer to a brand new object
- of the same class as self. Although you are responsible for putting
- in the prototype in the class declaration, a macro to be described in
- Section 15.10.11 will supply an appropriate definition.
-
-
- 15.10.9 Virtual functions saveGuts(RWFile&) and saveGuts(RWvostream&)
-
- These virtual functions are responsible for storing the internal
- state of an RWCollectable on either a binary file (using class
- RWFile) or on a virtual output stream (an RWvostream). This allows
- the object to be recovered at some later time. Here is a possible
- definition:
-
- void
- Automobile::saveGuts(RWFile& file)
- {
- marque.saveOn(file);
- file.Write(price);
- file.Write(horsepower);
- }
-
- void
- Automobile::saveGuts(RWvostream& strm)
- {
- marque.saveOn(strm);
- strm << price << horsepower;
- }
-
- Note how member function RWString::saveOn() was used to save the
- member data marque. Also note how price and horsepower were written
- out in function saveGuts(RWvostream&) without any formatting (e.g.,
- separating blanks) -- the specializing virtual output stream will do
- this, if necessary.
-
-
- 15.10.10 Virtual functions restoreGuts(RWFile&) and restoreGuts(RWvistream&)
-
- In a similar manner, these virtual functions are used to restore the
- internal state of an RWCollectable from a file or stream:
-
- Rogue WaveSmalltalk_-like Collection Classes 127
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- void
- Automobile::restoreGuts(RWFile& file)
- {
- marque.restoreFrom(file);
- file.Read(price);
- file.Read(horsepower);
- }
-
- void
- Automobile::restoreGuts(RWvistream& strm)
- {
- marque.restoreFrom(strm);
- strm >> price >> horsepower;
- }
-
- 15.10.11 Putting it all together
-
- There is one final detail that must be attended to when creating a
- new RWCollectable class. One must supply a function to create a new
- instance of your new class. This is done automatically for you by a
- macro DEFINE_COLLECTABLE(type). For our example the following must
- be included somewhere in a .cpp file:
-
- DEFINE_COLLECTABLE(Automobile)
-
- This magic incantation will allow a new instance of your class to be
- created given its ClassID:
-
- Automobile* newAuto = (Automobile*)theFactory->create(123);
-
- The pointer theFactory is a global pointer that points to a one-of-a-
- kind global instance of class RWFactory, used to create new instances
- of any class, given its ClassID. The use of RWFactory is generally
- transparent to the user. See Part II: Class Reference for more
- details on RWFactory.
-
- The macro DEFINE_COLLECTABLE also supplies a definition for the
- member function newSpecies().
-
- Here then, is the complete listing for our class Automobile:
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 128
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- AUTO.H:
-
- #ifndef __AUTO_H__
- #define __AUTO_H__
-
- class Automobile : public RWCollectable {
- private:
- RWString marque; // The manufacturer
- double price;
- int horsepower;
- public:
- // Constructor:
- Automobile() { } // Default constructor
- Automobile(RWString name, double pricetag, int hp) :
- marque(name), price(pricetag), horsepower(hp) { }
-
- // Inherited from class "RWCollectable":
- ClassID isA() const;
- int compareTo(const RWCollectable*) const;
- RWBoolean isEqual(const RWCollectable*) const;
- unsigned hash() const;
- RWCollectable* newSpecies() const;
- void restoreGuts(RWFile&);
- void restoreGuts(RWvistream&);
- void saveGuts(RWFile&) const;
- void saveGuts(RWvostream&) const;
- };
- #endif
-
- AUTO.CPP:
-
- // Magic incantation; see Section 15.10.11:
- DEFINE_COLLECTABLE(Automobile)
-
- // See Section 15.10.4:
- ClassID
- Automobile::isA() const
- {
- return 123;
- }
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 129
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- // See Section 15.10.5:
- int
- Automobile::compareTo(const RWCollectable* c) const
- {
- const Automobile* ap = (const Automobile*)c;
- if ( price == ap->price ) return 0;
- return price > ap->price ? 1 : -1;
- }
-
- // See Section 15.10.6:
- RWBoolean
- Automobile::isEqual(const RWCollectable* c) const
- {
- const Automobile* ap = (const Automobile*)c;
-
- return marque == ap->marque &&
- horsepower == ap->horsepower &&
- price == ap->price;
- }
-
- // See Section 15.10.7:
- unsigned
- Automobile::hash() const
- {
- return marque.hash();
- }
-
- // See Section 15.10.9:
- void
- Automobile::saveGuts(RWFile& file)
- {
- marque.saveOn(file);
- file.Write(price);
- file.Write(horsepower);
- }
-
- // See Section 15.10.9:
- void
- Automobile::saveGuts(RWvostream& strm)
- {
- marque.saveOn(strm);
- strm << price << horsepower;
- }
-
- Rogue WaveSmalltalk_-like Collection Classes 130
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- // See Section 15.10.10:
- void
- Automobile::restoreGuts(RWFile& file)
- {
- marque.restoreFrom(file);
- file.Read(price);
- file.Read(horsepower);
- }
-
- // See Section 15.10.10:
- void
- Automobile::restoreGuts(RWvistream& strm)
- {
- marque.restoreFrom(strm);
- strm >> price >> horsepower;
- }
-
- 15.10.12 Summary
-
- In general, you may not have to supply definitions for all of these
- virtual functions. For example, if you know that your class will
- never be used in sorted collections, then you do not need a
- definition for compareTo(). Nevertheless, it is a good idea to do it
- anyway because you never know!
-
-
- 15.11More on storing and retrieving RWCollectables
-
-
-
- The member functions saveOn() and restoreFrom() are responsible for
- maintaining the morphology of a class (i.e., the correct
- relationships between pointers) when the class is stored and
- restored. Note that they are not virtual functions -- you need not
- redefine them. In fact, as mentioned in Section 15.9, restoreFrom()
- is a static function and is not associated with any particular
- instance of a class.
-
- When working with RWCollectables, it is useful to understand how
- these functions work. Here is a brief description.
-
- When you call saveOn() for the first time for any collectable object,
- an IdentityDictionary is created internally. The object's address
- (i.e., "this") is put in the table, along with its ordinal position
- Rogue WaveSmalltalk_-like Collection Classes 131
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- in the output file (the first, the second, etc.). Once this has been
- done, a call is made to the virtual function saveGuts(). Because
- this is a virtual function, the call will go to the derived class's
- definition of saveGuts(). As we have seen, the job of saveGuts() is
- to store the internals of the object. If the object contains
- pointers to other objects (as all of the collection classes do, as
- well as many other classes), then the object's saveGuts(), if it has
- been written correctly, will call saveOn() recursively for each of
- these pointers. Subsequent invocations of saveOn() do not create a
- new IdentityDictionary, but do store the object's address in the
- already existing dictionary. If an address is encountered which is
- identical to a previously written object's address, then saveGuts()
- is not called. Instead, a reference is written that this object is
- identical to some previous object (say, the sixth).
-
- When the entire collection has been traversed and the initial call to
- saveGuts() returns, then the IdentityDictionary is deleted and the
- initial call to saveOn() returns.
-
- The function restoreFrom() essentially reverses this process and,
- when encountering a reference to an object that has already been
- created, merely returns the address of the old object rather than
- asking the RWFactory to create a new one.
-
- Here is a more sophisticated example of a class that uses these
- feature:
-
- class Tangle : public RWCollectable {
- Tangle* nextTangle;
- int someData;
-
- public:
-
- Tangle(Tangle* t = 0) {nextTangle=t; someData = 0;}
-
- // Redefined from class RWCollectable:
- virtual void saveGuts(RWFile&) const;
- virtual void restoreGuts(RWFile&);
- .
- .
- .
- };
-
-
- Rogue WaveSmalltalk_-like Collection Classes 132
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- void
- Tangle::saveGuts(RWFile& file) const
- {
- // Store any member data:
- file.Write(someData);
-
- // Then call saveOn() for the next object:
- if(nextTangle) nextTangle->saveOn(file);
- else nilCollectable->saveOn(file);
- }
-
- void
- Tangle::restoreGuts(RWFile& file)
-
- {
- // Restore my state:
- file.Read(someData);
-
- // Then get the address of the next object:
- nextTangle = (Tangle*)restoreFrom(file);
- if (nextTangle==nilCollectable) nextTangle = 0;
- }
-
- This class implements a (potentially) circularly linked list. What
- happens? When function saveOn(RWFile&) is called for the first time
- for an instance of Tangle, it sets up the IdentityDictionary, as
- described above, and then calls the Tangle's saveGuts() whose
- definition is shown above. This definition stores any member data of
- Tangle, then calls saveOn() for the next link. This recursion
- continues on around the chain.
-
- If the chain ends with a nil object (i.e., nextTangle is zero), then
- we mark it with the one-of-a-kind RWCollectable called
- nilCollectable. This special object is useful when the number of
- items is not known or if there is no other way to mark the end of a
- chain of objects.
-
- On the other hand, if the list is circular, then a call to saveOn()
- will eventually be made for the first instance of Tangle again, the
- one that started this whole chain. When this happens, saveOn() will
- recognize that it has already seen this instance before and, rather
- than call saveGuts() again, will just make a reference to the
- previously written link. This stops the series of recursive calls to
- saveOn() and the stack then unwinds.
- Rogue WaveSmalltalk_-like Collection Classes 133
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Restoration of the chain is done in a similar manner. A call to
- restoreFrom() will either create a new object off the heap and return
- a pointer to it, or return the address of a previously read object.
- The end of a non-circular chain can be detected by testing against
- the nilCollectable object. In the case of a circular chain, the
- recursive calls to restoreFrom() and restoreGuts() will stop and the
- stack unwinds.
-
-
-
- Note that because restoreFrom() returns a new item off the heap you
- are responsible for deleting it when you are done with it.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 134
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 15.11.1 Reading and writing collections
-
- All of the Smalltalk-like collection classes inherit the abstract
- base class RWCollection. Class RWCollection has a version of
- saveGuts() and restoreGuts() built into it that is sufficient for
- most collection classes. RWCollection::saveGuts() works by
- repeatedly calling saveOn() for each item in the collection.
- Similarly, RWCollection::restoreGuts() works by repeatedly calling
- restoreFrom(), followed by insert(), for each item in the collection.
-
- If you decide to write your own collection classes and inherit from
- class RWCollection, you will rarely have to define your own
- saveGuts() or restoreGuts().
-
- There are exceptions. For example, class RWBinaryTree has its own
- version of restoreGuts(). This is necessary because during a restore
- the incoming items will be inserted in order, resulting in a severely
- unbalanced tree (essentially, you would get the degenerate case of a
- linked list). Hence, RWBinaryTree's version of restoreGuts() first
- calls RWCollection::restoreGuts() and then RWBinaryTree::balance(),
- which then balances the tree.
-
-
- 15.12Architectural notes
-
-
-
- In Section 15.10, we built a Automobile class by inheriting from
- RWCollectable. If we had an existing Auto class at hand, we might
- have been able to use multiple inheritance to create a new class with
- the functionality of both Auto and RWCollectable, perhaps saving
- ourselves some work:
-
- class CollectableAuto : public RWCollectable, public Auto {
- .
- .
- .
- };
-
- This is the approach taken by many of the Rogue Wave collectable
- classes (e.g., class RWCollectableString, which inherits both class
- RWCollectable and class RWString). The general idea is to create
- your object first, and then tack on the RWCollectable class, making
- Rogue WaveSmalltalk_-like Collection Classes 135
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- the whole thing collectable. This way, you will be able to use your
- objects for other things, in other situations, where you might not
- want to inherit from class RWCollectable.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 136
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- There is another good reason for using this approach: avoiding
- ambiguous base classes. Here's an example:
- class A { };
-
- class B : public A { };
-
- class C : public A { };
-
- class D : public B, public C { };
-
- void fun(A&);
-
- main () {
- D d;
- fun(d); // Which A ?
- }
-
- There are two approaches to disambiguating the call to fun(). Either
- change it to:
- fun((B)d); // We mean B's occurrence of A
- or make A a virtual base class.
- The first approach is error prone -- the user must know the details
- of the inheritance tree so as to make the proper cast.
- The second approach, making A a virtual base class, solves this
- problem, but introduces another: it becomes nearly impossible to make
- a cast back to the derived class! This is because there are now two
- or more paths back through the inheritance hierarchy or, if you
- prefer a more physical reason, the compiler implements virtual base
- classes as pointers to the base class and you can't follow a pointer
- backwards. The only solution is to exhaustively search all possible
- paths in the object's inheritance hierarchy, looking for a match.
- (This is the approach of the NIH Classes.) Such a solution is slow
- (it must be done for every cast, although the search can be speeded
- up by "memoizing" the resulting addresses), bulky and always
- complicated. We decided that this was unacceptable.
- Hence, we chose the first route. This can be made acceptable by
- keeping the inheritance trees simple by not making everything derive
- from the same base class. Hence, rather than using a large secular
- base class (sometimes dubbed the "cosmic object"; an example is
- Smalltalk's "Object") with lots of functionality, we have chosen to
- tease out the separate bits of functionality into separate, smaller
- base classes.
- The idea is to first build your object, then tack on the base class
- that will supply the functionality that you need (such as
- Rogue WaveSmalltalk_-like Collection Classes 137
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- collectability), thus avoiding multiple base classes of the same type
- and the resulting ambiguous calls.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue WaveSmalltalk_-like Collection Classes 138
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 6
-
-
- Implementation NotesImplementation notes
-
-
-
-
- 16.1 Errors Errors -- when bad things happen to good programs
-
-
-
- Thinking about error handling is like thinking about where the
- garbage man hauls your trash -- it's a messy, unpredicatable, and
- sour topic, one that we don't like to think about. Yet, to write
- robust code, think about it we must.
-
- The Rogue Wave class libraries use an extensive and complete error
- handling facility, all based on the same model. Errors are divided
- into three categories: violated preconditions, invalid input, and
- asynchronous errors. The difference between them depends on who
- screwed up: the programmer, the final end user, or some
- external/internal software error. Each type of error requires a
- different approach to how it is handled. The following sections
- describe these approaches and how you can change how they are
- handled.
-
-
- 16.1.1Violated preconditions
-
- This type of error deals with failures to follow the programming
- rules set out by the Tools.h++ classes. If an indexing operator says
- not to ask for an index greater than a vector's length and you do so,
- then that is a violated precondition.
-
- A more formal description is given by Meyer (1988). Briefly,
- functions are regarded as a "contract" between caller and callee. If
- the caller abides by a set of "preconditions", then the callee
- guarantees to return results that satisfy a set of "postconditions".
- Rogue Wave Implementation Notes 139
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Typically, preconditions are such things as requiring that an index
- be within a set of bounds, that pointers be non-nil, etc. The ideal
- goal is that these types of errors will never happen. Because they
- will never happen, there is no need to provide a recovery mechanism
- or even to detect them!
-
- But, of course, they do happen. So, how do you guard against them?
- How do you detect them? The Rogue Wave classes have an extensive set
- of PRECONDITION and POSTCONDITION clauses at the beginning and end of
- critical functions. They can be activated by compiling the entire
- library with the preprocessor flag "DEBUG" defined. The entire
- library must be compiled with a single setting of the flag -- either
- defined or not defined. The resultant library will be slightly
- larger and slightly slower. See the appropriate makefile for
- additional directions.
-
- The pre- and postconditions are either implemented with "asserts" --
- a failure will cause the offending condition to be printed out, along
- with the file and line number where it occurred -- or through the
- Rogue Wave error facility.
-
- Again, the assumption is that these are programming errors and can
- and should be avoided. Hence, there are no facilities for error
- recovery.
-
-
- 16.1.2Invalid input
-
- This type of error is caused by an invalid input, usually on the part
- of the final end user (e.g., the user of the graphics program you are
- writing), rather than the programmer. For example, a user might
- specify a date of "31 June 1985", a day that doesn't exist. It would
- be a mean-spirited program that simply aborted when given such a
- date. It would be much preferred if the date's invalidity could be
- explicitly recognized, to be rejected or corrected.
-
- Nevertheless, the line between invalid input and a violated
- precondition can be fuzzy. For example, the rules could say, "don't
- give me an invalid date" and then the programmer would be responsible
- for detecting the bad date before handing it to the Tools.h++
- routines. Of course, this is a lot of work, and (in this example)
- the RWDate class would probably be better equipped than the caller to
- determine the validity of the date. Hence, this is an approach that
- is generally not taken.
- Rogue Wave Implementation Notes 140
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- How are these kinds of errors dealt with? Generally, by either
- returning a "special value" (perhaps a nil pointer), or by use of a
- member function that tests the validity of the resultant object.
- Continuing with the RWDate example,
-
- main() {
- RWDate theDate(31, "June", 1985);
-
- if( theDate.isValid() )
- cout << "OK!\n";
- else
- cout << "Not ok!\n";
- }
-
- In the case of dates, the member function isValid() is available for
- detecting the validity of the resultant RWDate. The above program
- would print out "Not ok!".
-
-
- 16.1.3Asynchronous errors
-
- These kinds of errors are difficult to predict and are generally due
- to a failure on the part of the operating system. By far the most
- common example is "out of memory". Others are failure to open a
- file, perhaps due to the lack of disk space, or a hardware failure.
-
- The usual response to these types of errors by the Tools.h++ Class
- Library is to throw an exception. At the time of this writing, the
- syntax and mechanism for exception handling, as outlined by Ellis and
- Stroustrup (1990), has been accepted into the ANSI X3J16 C++ draft.
- Unfortunately, none of the major commercial compiler manufacturers
- have implemented it.
-
- The Rogue Wave class libraries have been built to allow a smooth
- transition to exception handling when it becomes available. For now,
- the default error handler posts a note (either to standard output or
- to a Windows MessageBox, depending on whether or not the library has
- been compiled as a DLL) with the type of error, then aborts the
- program. This default handler can be changed.
-
- The code to implement exception handling is in place. Assuming that
- the syntax doesn't undergo a major change, all that is required to
- activate it is to define the preprocessor macro HAS_EXCEPTIONS and
- recompile the library. Here's how to use it:
- Rogue Wave Implementation Notes 141
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- main()
- {
- try {
- RWFile file("file.dat"); // Might fail, due to hardware
- }
- catch(RWErrObject eobj) {
- if( eobj.number() == CORE_OPERR )
- cerr << "Could not open file\n";
- else{
- cerr << "Unexpected error\n";
- exit(eobj.number());
- }
- }
- // Code that depends on "file" being opened
- }
-
-
- Don't try this if you compiler doesn't implement exceptions!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Implementation Notes 142
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 16.1.4Changing the default error handler
-
- The global function setRWErrHandler(RWErrHandler routine) is
- available for changing the default error handler. It takes an
- argument of type RWErrHandler which is a typedef:
-
- typedef void (* RWErrHandler)(RWErrObject, va_list);
-
- That is, a pointer to a function with prototype:
-
- void yourErrorHandler(RWErrObject, va_list);
-
- where yourErrorHandler is the name of your substitute error handler.
- The first argument, RWErrObject is a class that packages together the
- error number, its severity, and the class that invoked the error.
- See the Class Reference guide for more information. The second
- argument is a variable argument list of the style10 of Ellis and
- Stroustrup (1990), Section 8.3, and is defined in the header file
- <stdarg.h>. It contains supplemental information about the error.
-
-
- 16.1.5Error numbers and messages
-
- The error numbers are listed in the header files <coreerr.h> and
- <toolerr.h>. The former contains errors that can be thrown by any of
- the Rogue Wave class libraries, the latter are specific to the
- Tools.h++ Class Library. If you have source code, you can see the
- associated error messages in files coreerr.cpp and toolerr.cpp,
- respectively, and surmise the auxilary information contained in the
- va_list. For example, the error TOOL_INDEX is listed in toolerr.cpp
- as:
-
- RWFATAL, "[INDEX] Index (%d) out of range [0->%d]"
-
- This means that the default disposition of this error is to abort
- (RWFATAL), that the first argument in the va_list is the index the
- user attempted to use, and the second argument is the highest allowed
- index.
-
-
-
- 10 The "variable argument list" syntax is also defined by
- ANSI C.
- Rogue Wave Implementation Notes 143
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 16.2 Dynamic Link LibraryDLL" \t ""
-
-
-
- The Tools.h++ Class Library can be linked as a Microsoft Windows 3.0
- Dynamic Link Library (DLL). In a DLL, linking occurs at runtime when
- the routine is actually needed. This results in much smaller
- executables because routines are pulled in only on an "as needed"
- basis. Another advantage is that many applications can share the
- same code, rather than having it duplicated in each application.
-
- A prebuilt large model DLL, using the Borland C++ compiler, comes
- with Tools.h++.
-
- Because this is a rapidly evolving area of Windows and C++
- technology, be sure to see the file DLL.DOC, included on your
- distribution disk, for any last minute changes.
-
-
-
-
- Figure 16-1. The Demo program window.
-
- 16.2.1Example
-
- This section discusses a sample Windows application that uses the
- Tools.h++ DLL -- yet another tiresome "Hello World" example. The
- program is somewhat unique in that it maintains a linked list of
- "Drawable" objects that can be inserted into the window at run time.
- This list is implemented using class RWSlistCollectables. The
- program can be found in the subdirectory DLLDEMO. This discussion
- assumes that you are somewhat familiar with Windows 3.0 programming,
- but not with C++'s relationship to it.
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Implementation Notes 144
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- Here's the main program.
-
- DEMO.CPP
-
- /*
- * Sample Windows 3.0 program, using the Tools.h++ DLL.
- */
-
- #include "demowind.h"
-
- int PASCAL
- WinMain(HANDLE hInstance, HANDLE hPrevInstance,
- LPSTR , int nCmdShow) // 1
- {
- // Create an instance of the "DemoWindow" class:
- DemoWindow ww(hInstance, hPrevInstance, nCmdShow); // 2
-
- // Add some items to it:
- ww.insert( new RWRectangle(200, 50, 250, 100)); // 3
- ww.insert( new RWEllipse(50, 50, 100, 100));
- ww.insert( new RWText(20, 20, "Hello world, from Rogue Wave!"));
-
- ww.show(); // Show the window // 4
- ww.update(); // Update the window
-
- MSG msg;
-
- // Enter the message loop:
- while( GetMessage( &msg, NULL, 0, 0)) // 5
- {
- TranslateMessage( &msg );
- DispatchMessage( &msg );
- }
- return msg.wParam;
- }
-
- Here's the line-by-line description of the program.
-
- 1 This is the Windows program entry point, that every Windows
- program must have. It is equivalent to C's "main" function.
-
- 2 This creates an instance of the class DemoWindow, which we will
- see later. It represents an abstract window into which objects
- can be "inserted".
- Rogue Wave Implementation Notes 145
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 3 Here we insert three different objects into the DemoWindow: a
- rectangle, an ellipse, and a text string.
-
- 4 This tells the DemoWindow to show itself and to update itself.
-
- 5 Finally, the windows main event loop is entered.
-
- DEMOWIND.H
-
- #ifndef __DEMOWIND_H__
- #define __DEMOWIND_H__
-
- /*
- * A Demonstration Window class --- allows items that
- * inherit from the base class RWDrawable to be
- * "inserted" into it.
- */
-
- #include <slistcol.h>
- #include "shapes.h"
- #include <windows.h>
-
- class DemoWindow {
- HWND hWnd; // My window handle
- HANDLE myInstance; // My instance's handle
- int nCmdShow;
- RWSlistCollectables myList; // A list of items in the window
- public:
- DemoWindow(HANDLE mom, HANDLE prev, int);
- ~DemoWindow();
-
- // Add a new item to the window:
- void insert(RWDrawable*);
-
- HWND handle() {return hWnd;}
- int registerClass();
- void paint();
- int show()
- {return ShowWindow(hWnd,nCmdShow);}
-
- void update() {UpdateWindow(hWnd);}
- friend long FAR PASCAL _export
- DemoWindow_Callback(HWND, unsigned, WORD, LONG);
- };
- Rogue Wave Implementation Notes 146
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- DemoWindow* RWGetWindowPtr(HWND h);
- void RWSetWindowPtr(HWND h, DemoWindow* p);
-
- #endif
-
- This header files declares the class DemoWindow. A key features is
- the singly linked list called "myList" which holds the list of items
- that have been inserted into the window. Member function
- DemoWindow::insert(RWDrawable*) allows new items to be inserted.
- Only objects that inherit from class RWDrawable, to be defined in a
- moment, may be inserted.
-
- The member function paint() may be called when it is time to repaint
- the window. The list myList will be traversed and each item in it
- will be repainted onto the screen.
-
- Let's look at the definitions of these functions.
-
- DEMOWIND.CPP
-
- #include "demowind.h"
- #include "shapes.h"
- #include <stdlib.h>
- #include <string.h>
-
- /*
- * Construct a new window.
- */
- DemoWindow::DemoWindow(HANDLE mom, HANDLE prev, int cmdShow) // 1
- {
- myInstance = mom;
- nCmdShow = cmdShow;
-
- // Register the class if there was no previous instance:
- if(!prev) registerClass(); // 2
-
-
-
-
-
-
-
-
- Rogue Wave Implementation Notes 147
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- hWnd = CreateWindow("DemoWindow", // 3
- "DemoWindow",
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, 0,
- CW_USEDEFAULT, 0,
- NULL,
- NULL,
- myInstance,
- (LPSTR)this ); // Stash away 'this' // 4
-
- if(!hWnd) exit( FALSE );
- }
-
- /*
- * Register self. Called once only.
- */
- int
- DemoWindow::registerClass() // 5
- {
- WNDCLASS wndclass;
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc = ::DemoWindow_Callback; // 6
- wndclass.cbClsExtra = 0;
- // Request extra space to store the 'this' pointer
- wndclass.cbWndExtra = sizeof(this); // 7
- wndclass.hInstance = myInstance;
- wndclass.hIcon = 0;
- wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
- wndclass.hbrBackground = GetStockObject( WHITE_BRUSH );
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = "DemoWindow";
-
- if( !RegisterClass(&wndclass) ) exit(FALSE);
- return TRUE;
- }
-
- DemoWindow::~DemoWindow()
- {
- // Delete all items in my list:
- myList.clearAndDestroy(); // 8
- }
-
-
-
- Rogue Wave Implementation Notes 148
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- void
- DemoWindow::insert(RWDrawable* d)
- {
- // Add a new item to the window:
- myList.insert(d); // 9
- }
-
- void
- DemoWindow::paint() // 10
- {
- RWDrawable* shape;
- PAINTSTRUCT ps;
- BeginPaint( handle(), &ps); // 11
-
- // Draw all items in the list. Start by making an iterator:
- RWSlistCollectablesIterator next(myList);// 12
-
- // Now iterate through the collection, drawing each item:
- while( shape = (RWDrawable*)next() ) // 13
- shape->drawWith(ps.hdc); // 14
- EndPaint( handle(), &ps ); // 15
- }
-
- /*
- * The callback routine for this window class.
- */
- long FAR PASCAL _export
- DemoWindow_Callback(HWND hWnd, unsigned iMessage, // 16
- WORD wParam, LONG lParam)
- {
- DemoWindow* pDemoWindow;
-
- if( iMessage==WM_CREATE ){ // 17
- // Get the "this" pointer out of the create structure
- // and put it in the windows instance:
- LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
- pDemoWindow = (DemoWindow*) lpcs->lpCreateParams;
- RWSetWindowPtr(hWnd, pDemoWindow);
- return NULL;
- }
-
- // Get the appropriate "this" pointer
- pDemoWindow = RWGetWindowPtr(hWnd); // 18
-
- Rogue Wave Implementation Notes 149
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- switch( iMessage ){
- case WM_PAINT:
- pDemoWindow->paint(); // 19
- break;
- case WM_DESTROY:
- PostQuitMessage( 0 );
- break;
- default:
- return DefWindowProc(hWnd, iMessage, wParam, lParam);
- };
- return NULL;
- }
-
- void RWSetWindowPtr(HWND h, DemoWindow* p) // 20
- {
- SetWindowLong(h, 0, (LONG)p);
- }
-
- DemoWindow* RWGetWindowPtr(HWND h) // 21
- {
- return (DemoWindow*)GetWindowLong(h, 0);
- }
-
- 1 This is the constructor for DemoWindow. It requires the handle
- of the application instance creating it ("mom"), the handle of
- any previously existing instance ("prev") and whether to show the
- window in iconic form. These variables are as received from
- WinMain, the main windows procedure that we have already seen.
-
- 2 The constructor checks to see if any previous application
- instance has been run and, if not, registers the class.
-
- 3 The new window is created.
-
- 4 A key feature is the use of the Windows "extra data" feature to
- store the "this" pointer for this DemoWindow. The procedure to
- do this is somewhat cumbersome, but very useful. The value
- placed here will appear in the CREATESTRUCT structure which we
- can retrieve when processing the WM_CREATE message generated by
- the CreateWindow function.
-
- 5 This member function is only called for the first instance of an
- application.
-
- Rogue Wave Implementation Notes 150
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- 6 The global function DemoWindow_Callback is registered as the
- callback procedure for this window.
-
- 7 We ask Windows to set aside space for the "this" pointer in this
- Windows class. This will be used to associate a Windows handle
- with a particular DemoWindow.
-
- 8 The destructor calls clearAndDestroy() to delete all items that
- have been inserted into myList.
-
- 9 The member function insert(RWDrawable*) inserts a new item into
- the window. Because (as we shall see) RWDrawable inherits from
- RWCollectable, there is no need to do a cast when calling
- RWSlistCollectables::insert(RWCollectable*). By making myList
- private and offering a restricted insert that takes arguments of
- type RWDrawable* only, we insure that only "drawables" will be
- inserted into the window.
-
- 10 Here's the paint procedure, called when it is time to repaint the
- window.
-
- 11 We start by getting the handle for this window, and then calling
- BeginPaint to fill a PAINTSTRUCT with information about the
- painting.
-
- 12 An iterator is constructed in preparation for traversing the list
- of items to be painted.
-
- 13 Get the next item to be painted. If nil is returned then there
- are no more items and the while loop will finish.
-
- 14 For each item, call the virtual function drawWith, causing the
- item to paint itself onto the given device context.
-
- 15 The PAINTSTRUCT is returned.
-
- 16 Here's the callback routine to be called when it is necessary to
- process a message for this window. It uses Borland C++'s very
- convenient "_export" keyword to indicate that this function
- should be exported. If you do this, there is no need to list the
- function in an "Exports" section of the module definition file.
-
- 17 If the message is a WM_CREATE message then it was generated by
- the CreateWindow function and this is the first time through for
- Rogue Wave Implementation Notes 151
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- this procedure. Use the rather baroque procedure to fetch the
- "this" pointer from the CREATESTRUCT (recall, it was inserted at
- line 4) and put it into the Windows extra data. The function
- RWSetWindowPtr will be defined later.
-
- 18 The function RWGetWindowPtr(HWND) is used to retrieve the pointer
- to the appropriate DemoWindow, given a Windows HANDLE.
-
- 19 If a WM_PAINT has been retrieved, then call the paint() member
- function, which we have already seen.
-
- 20 This function is used to put a "this" pointer into the Windows
- extra data. The idea is to have a one-to-one mapping of Windows
- handles to instances of DemoWindow.
-
- 21 This function is used to fetch the "this" pointer back out.
-
- Finally, we have the subclasses of RWDrawable. Only one has been
- reprinted here: RWRectangle.
-
- SHAPES.H (excerpt)
-
- class RWDrawable : public RWCollectable {
- public:
- virtual void drawWith(HDC) const = 0;
- };
-
- class RWRectangle : public RWDrawable {
- RECT bounds; // The bounds of the rectangle
- public:
- RWRectangle() { }
- RWRectangle(int, int, int, int);
-
- // Inherited from RWDrawable:
- virtual void drawWith(HDC) const;
-
- // Inherited from RWCollectable:
- virtual unsigned binaryStoreSize() const
- {return 4*sizeof(int);}
- virtual unsigned hash() const;
- virtual ClassID isA() const {return 0x1000;}
- virtual RWBoolean isEqual(const RWCollectable*) const;
- virtual RWCollectable* newSpecies() const;
- virtual void restoreGuts(RWvistream& s);
- Rogue Wave Implementation Notes 152
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- virtual void restoreGuts(RWFile&);
- virtual void saveGuts(RWvostream& s) const;
- virtual void saveGuts(RWFile&) const;
- };
-
- Class RWDrawable is an abstract base class that inherits from the
- Tools.h++ class RWCollectable and adds a new member function
- drawWith(HDC). Subclasses specializing RWDrawable should implement
- this function to draw itself onto the supplied device context handle.
-
- Class RWRectangle inherits from RWDrawable. Note that it just uses
- the Windows-provided struct RECT as member data to hold the corners
- of the rectangle. For the purposes of this DLL demo, it really isn't
- necessary to provide definitions for any of the member functions
- inherited from RWCollectable but, for the sake of completeness, let's
- do it anyway.
-
- SHAPES.CPP (excerpt)
-
- #include "shapes.h"
- #include <vstream.h>
- #include <rwfile.h>
-
- DEFINE_COLLECTABLE(RWRectangle) // 1
-
- // Constructor
- RWRectangle::RWRectangle(int l, int t, int r, int b) // 2
- {
- bounds.left = l;
- bounds.top = t;
- bounds.right = r;
- bounds.bottom = b;
- }
-
- // Inherited from Drawable:
- void
- RWRectangle::drawWith(HDC hdc) const // 3
- {
- // Make the Windows call:
- Rectangle(hdc, bounds.left, bounds.top,
- bounds.right, bounds.bottom);
- }
-
-
- Rogue Wave Implementation Notes 153
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- // Inherited from RWCollectable:
- unsigned
- RWRectangle::hash() const // 4
- {
- return bounds.left ^ bounds.top ^ bounds.bottom ^ bounds.right;
- }
-
- RWBoolean
- RWRectangle::isEqual(const RWCollectable* c) const // 5
- {
- if(c->isA() != isA() ) return FALSE;
-
- const RWRectangle* r = (const RWRectangle*)c;
-
- return bounds.left == r->bounds.left &&
- bounds.top == r->bounds.top &&
- bounds.right == r->bounds.right &&
- bounds.bottom == r->bounds.bottom;
- }
-
- // Restore the RWRectangle from a virtual stream:
- void
- RWRectangle::restoreGuts(RWvistream& s) // 6
- {
- s >> bounds.left >> bounds.top;
- s >> bounds.right >> bounds.bottom;
- }
-
- // Restore from a RWFile:
- void
- RWRectangle::restoreGuts(RWFile& f) // 7
- {
- f.Read(bounds.left);
- f.Read(bounds.top);
- f.Read(bounds.right);
- f.Read(bounds.bottom);
- }
-
- void
- RWRectangle::saveGuts(RWvostream& s) const // 8
- {
- s << bounds.left << bounds.top;
- s << bounds.right << bounds.bottom;
- }
- Rogue Wave Implementation Notes 154
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- void
- RWRectangle::saveGuts(RWFile& f) const // 9
- {
- f.Write(bounds.left);
- f.Write(bounds.top);
- f.Write(bounds.right);
- f.Write(bounds.bottom);
- }
-
- 1 This is a macro that all subclasses of RWCollectable are required
- to compile once, and only once. See Section 15.10.11 for more
- details.
- 2 The constructor for RWRectangle. It fills in the RECT structure.
- 3 This is the definition of the virtual function drawWith(HDC). It
- simply makes a call to the Windows function "Rectangle()" with
- appropriate arguments.
- 4 Supplies an appropriate hashing value in case we ever want to
- retrieve this RWRectangle from a hash table.
- 5 Supplies an appropriate isEqual() implementation.
- 6 This function retrieves the RWRectangle from a virtual stream.
- 7 This function retrieves the RWRectangle from a RWFile.
- 8 This function stores the RWRectangle on a virtual stream. Note
- how there is no need to separate elements by white space -- this
- will be done by the virtual stream, if necessary.
- 9 This function stores the RWRectangle on a RWFile.
- The other shapes (RWEllipse and RWText) are implemented in a similar
- manner.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Implementation Notes 155
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- S e c t i o n 1 7
-
-
- Examples
-
-
-
- In this section we outline several examples that use the Rogue Wave
- Tools.h++ classes. The source code for these examples is included in
- the subdirectory toolexam. Sample input and output files, if needed,
- as well as makefiles are also included in the subdirectory.
-
-
- 17.1 Example 1: The RWTime and RWDate classes
-
-
-
- This example illustrates the use of the RWTime and RWDate classes. A
- RWDate is constructed with today's date, then printed with a variety
- of formats. A RWTime is constructed, then converted to a RWDate.
- Examples of the use of member functions to return information about
- RWDates and RWTimes are also given.
-
-
- 17.2 Example 2: The RWString class
-
-
-
- This example illustrates the use of the RWString and RWSubString
- classes. Representative member functions for the classes are
- illustrated, including constructors, concatenation and appending,
- pattern matching, converting to upper case, and input/output of
- strings. An example of using a RWSubString as an lvalue is given.
-
-
-
-
-
-
- Rogue Wave Examples 157
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 17.3 Example 3: GDlist - A class for generic doubly-linked lists
-
-
-
- This example illustrates the use of the "generic collection classes",
- with a doubly-linked list of ints. The macro
-
- declare(GDlist, int)
-
- declares a doubly-linked list of ints with class name GDlist(int).
- The constructor for an instance of a GDlist(int) with name L and no
- entries is:
-
- GDlist(int) L;
-
- Commands to insert and append ints to a linked-list are illustrated,
- as are commands to remove and print each entry.
-
- An iterator c for the linked-list is constructed with the statement:
-
- GDlistIterator(int) c(L);
-
- The iterator is exercised in various ways, to move around in the
- list, to search for and remove entries, and finally, to move through
- the list and print each entry.
-
-
- 17.4 Example 4: RWBinaryTree - A sorted collection of RWCollectableStrings
-
-
-
- This example uses class RWBinaryTree to store and retrieve
- collectable strings in a binary tree. The header file "collstr.h"
- contains the declarations for class RWCollectableString, which
- inherits class RWString and class RWCollectable. Most of the
- functionality of class RWCollectableString comes from class RWString.
- The virtual function compareTo(), which is inherited from class
- RWCollectable, has been redefined by RWCollectableString to compare
- strings lexicographically, and is used to sort the strings in the
- binary tree. The virtual function isEqual() has also been inherited
- from class RWCollectable, and is redefined to imply equality of
- strings.
-
- Rogue Wave Examples 158
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- A binary tree is first constructed with no entries:
-
- RWBinaryTree B;
-
- Then an input file "textfile.in" containing a group of words is
- opened, and the words are inserted into the tree. A loop to do
- various things to the tree is set up, with options:
-
- (i)nsert (s)earch (d)elete (l)ist e(x)it:
-
- These options enable you to insert new strings, search for strings,
- delete strings, list all the contents of the tree in order, and
- finally, to exit. These options exercise many of the member
- functions of the class RWBinaryTree.
-
- In order to list the contents of the binary tree, the member function
- apply() is used, which takes a pointer to a user-defined global
- function of the form:
-
- void yourApplyFunction(RWCollectable*, void*);
-
- and calls it for every member of the tree, in order. In the example,
- we use such a function to print each member of the tree:
-
- static void printStrings(RWCollectable* c, void*)
- {
- cout << * (RWCollectableString*) c ;
- }
-
- main()
- {
- RWBinaryTree B;
- .
- .
- .
- B.apply(printStrings, nil); // Traverse tree, printing members
- .
- .
- .
- }
-
- The cast in printStrings() is required. This is because the function
- takes an argument of type RWCollectable*, i.e., a pointer to the base
- class. In order to print the item it points to, it must first be
- Rogue Wave Examples 159
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- cast into its real identity, a pointer to a RWCollectableString, and
- then dereferenced. The result, which is a RWCollectableString,
- inherits its ability to print from class RWString.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Examples 160
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
-
- 17.5 Example 5: RWHashDictionary - A dictionary of keys and values
-
-
-
- This example is similar to the previous example and illustrates the
- use of the Dictionary collection class RWHashDictionary, which stores
- and retrieves key-value pairs, and which is implemented as a hash
- table. This example uses RWCollectableStrings as keys and
- RWCollectableInts as values.
-
- Since a hash table is used here, the virtual function hash() is being
- used to find the proper keys.
-
- A loop to perform various operations on the dictionary is set up,
- much as in the previous example. Here, however, keys and values are
- inserted, and a key is used to search for a value. The member
- function apply() for this class takes a pointer to a function of the
- form
-
- void
- anotherApplyFunction(RWCollectable* key,RWCollectable* value,
- void*);
-
- This function operates on both the key and the value (but should not
- alter the key).
-
-
- 17.6 Example 6: RWBTreeOnDisk - A B-Tree of keys and values, stored on disk
-
-
-
- This example exercises the class RWBTreeOnDisk, which maintains a
- Dictionary of key-value pairs on a disk file, where the keys are
- arrays of chars and the values are set by the typedef storedValue,
- typically a long int. The values may represent anything, but
- typically will represent offsets to objects that are stored on disk.
-
- A RWFileManager must be constructed first with the name of the disk
- file:
-
- RWFileManager fm(filename);
-
- The RWFileManager controls allocation, deallocation and coalescence
- Rogue Wave Examples 161
-
-
-
-
-
-
-
-
- USER'S GUIDE
-
- of free space on the disk file. After the RWFileManager has been
- constructed, it may be used to allocate space for the objects.
-
- The RWBTreeOnDisk is constructed from a RWFileManager:
-
- RWBTreeOnDisk B(fm);
-
- If the B-Tree is constructed from an old file, the old root node is
- read into memory; if it is constructed from a new file, a new B-Tree,
- with no entries, is constructed and written to disk. A file
- "example6.dat" contains a sample B-Tree with a number of entries.
-
- A loop does various things to the tree, as in the above examples.
- However, in this case, the changes are updated continuously on the
- disk file so that you can quit, then restart with the same filename.
-
-
- 17.7 Example7 & 8: Class RWFileManager
-
-
-
- These examples are described in Section 11.2." \t """ \t ""
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rogue Wave Examples 162