©Copyright 1996 Rogue Wave Software If you are accessing this for the first time, please read the licensing statement. Tools.h++ also has a Class Reference. Tools.h++ 7.0 User's Guide Welcome to the Tools.h++ 7.0 User's Guide. You can view a Comprehensive Table of Contents showing all chapters, first- and second-level headings, or click on one of the chapter names below to go directly to that chapter. Each chapter begins with a chapter-level table of contents. Chapter 1: About Tools.
Chapter 11: Collection Class Templates Chapter 12: Generic Collection Classes Chapter 13: Smalltalk-Like Collection Classes Chapter 14: Persistence Chapter 15: Designing an RWCollectable Class Chapter 16: Internationalization Chapter 17: Error Handling Chapter 18: Advanced Topics Chapter 19: Common Mistakes Appendix A: Choosing A Collection Appendix B: Typedefs and Macros Appendix C: Messages Appendix D: Bibliography
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Table of Contents Chapter 1: About Tools.h++ ❍ Overview and Features of Tools.h++ ❍ Tools.h++ and the C++ Philosophy ❍ Tools.
■ Comparisons ❍ Memory Allocation and Deallocation ❍ Information Flow ❍ Multithread Safe ❍ Eight-bit Clean ❍ Embedded Nulls ❍ Indexing ❍ Version Chapter 3: Using the String Classes ❍ An Introductory Example ❍ Lexicographic Comparisons ❍ Substrings ❍ Pattern Matching ❍ ■ Simple Regular Expressions ■ Extended Regular Expressions String I/O ■ iostreams ■ Virtual Streams ❍ Tokenizer ❍ Multibyte Strings ❍ Wide Character Strings Chapter 4: Using Class RWDate ❍ Example ❍ C
Chapter 6: Using Virtual Streams ❍ Specializing Virtual Streams ❍ Simple Example ❍ Windows Clipboard and DDE Streambufs ❍ DDE Example ❍ RWAuditStreamBuffer ❍ Recap Chapter 7: Using Class RWFile ❍ Example Chapter 8: Using Class RWFileManager ❍ Construction ❍ Member Functions Chapter 9: Using Class RWBTreeOnDisk ❍ Construction ❍ Example Chapter 10: Collection Classes ❍ Storage Methods of Collection Classes ■ ❍ ❍ Copying Collection Classes ■ Copying Reference-based Collection Classes
Chapter 11: Collection Class Templates ❍ Introduction ❍ Template Overview ❍ ■ Template Naming Convention ■ Value vs. Reference Semantics in Templates ■ Intrusive Lists in Templates Tools.
Chapter 13: Smalltalk-Like Collection Classes ❍ Tables of the Smalltalk-like Classes ❍ Example ❍ Choosing a Smalltalk-like Collection Class ❍ ❍ ■ Bags Versus Sets Versus Hash Tables ■ Sequenceable Classes ■ Dictionaries Virtual Functions Inherited From RWCollection ■ insert() ■ find() and Friends ■ remove() Functions ■ apply() Functions ■ Functions clear() and clearAndDestroy() Other Functions Shared by All RWCollections ■ Class Conversions ■ Inserting and Removing Other Collectio
❍ ❍ ■ Designing Your Class to Use Isomorphic Persistence ■ Writing rwSaveGuts and rwRestoreGuts Functions ■ Isomorphic Persistence of a User-designed Class Polymorphic Persistence ■ Operators ■ Designing your Class to Use Polymorphic Persistence ■ Polymorphic Persistence Example A Few Friendly Warnings ■ Always Save an Object by Value before Saving the Identical Object by Pointer ■ Don't Save Distinct Objects with the Same Address ■ Don't Use Sorted RWCollections to Store Heterogeneous RW
■ Numbers ■ Currency ■ A Note on Setting Environment Variables Chapter 17: Error Handling ❍ The Tools.h++ Error Model ❍ Internal Errors ■ Non-recoverable Internal Errors ■ Recoverable Internal Errors ❍ External Errors ❍ Exception Architecture ■ ❍ Error Handlers The Debug Version of Tools.
❍ Match Memory Models and Other Qualifiers ❍ Keep Related Methods Consistent ❍ DLL ❍ Use the Capabilities of the Library! Appendix A: Choosing A Collection ❍ ❍ Selecting a Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 1: About Tools.h++ ❍ Overview and Features of Tools.h++ ❍ Tools.h++ and the C++ Philosophy ❍ Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Overview and Features of Tools.h++ Tools.h++ is a rich, robust, and versatile C++ foundation class library: a set of software parts you can use to build virtually any application. Tools.h++ is an industry standard. It is shipped by a wide variety of compiler vendors with every copy of their compilers. Preferred by thousands of users world wide, it is ported to numerous compilers and operating systems. Tools.
Tools.h++ helps you master time. ● Internationalization support You can internationalize your software with the convenient and easy-to-use framework of class RWLocale, and use class RWTimeZone to manipulate time zones and daylight-saving time. The entire library is eight-bit clean, so you can use it with any eight-bit character set. Embedded nulls are fully supported. ● Endian streams You can transfer information between operating systems with the efficiency of a binary stream.
SortedCollection, Dictionary, and more. ● Many other features: RWFile Class encapsulates standard file operations. B-tree disk retrieval uses B-trees for efficient keyed access to disk records. File Space Manager allocates, deallocates and coalesces free space within a file. A complete error handling facility, which takes advantage of C++ exceptions if they are available. Still more classes, including: bit vectors, virtual I/O streams, cache managers, and virtual arrays.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Tools.h++ and the C++ Philosophy If you're familiar with C++, you'll feel comfortable with Tools.h++. As a C++ class library, Tools.h++ shares many design goals with the C++ language itself. These mutual goals include: ● Efficiency. In general, you will find no feature in Tools.h++ that impairs non-users of the feature.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Tools.h++ and the Standardization of C++ Almost everybody sees the benefits of standardizing the C++ language and the Standard C++ Library. The trick is to keep working during the process. We call this a period of transition, and the C++ community is engaged in it now. Here is what the transition looks like: a standard nearing completion, but not yet fully stable.
template. You'll find a full explanation of templates in Chapter 11. Following are the major design goals for our integration of Tools.h++ and the Standard C++ Library, along with examples of how they are reflected in this version: ● Design Goal: Leverage To offer greater value by taking advantage of the Standard C++ Library to build upon a higher foundation than the base C++ language. For example, Tools.h++ offers collections that use Standard C++ Library containers for their implementations.
To protect our customers' investment in code written with previous versions of Tools.h++. For example, we have re-engineered the Tools.h++ Version 6.1 collection class templates to base them on Standard C++ Library containers. In almost all cases, your existing source code that used classes in the previous version of the library will compile with the new library without modification.
committees. ● Exception Hierarchy Tools.h++ continues to use its own exception hierarchy, which is similar to the exception hierarchy in the draft C++ Standard. We don't expect to change over until the standard exception hierarchy is more widely available. You are free to use standard exceptions in your application, but you must be prepared also to catch Tools.h++ exceptions when making calls into the Tools.h++ library from within your try blocks. ● Namespaces Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Reading This Manual This manual is an introduction to using Tools.h++, Rogue Wave's foundation class library. It assumes that you are familiar with C++. If you are not, you will find several books of interest in the Bibliography. If you're an advanced C++ user, you may want to accompany this manual with Stroustrup [1991], Lippman [1991], or Ellis and Stroustrup [1990].
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Rogue Wave Professional Training To help you get a head start on your project, Rogue Wave Professional Services provides training that can put the power of Tools.h++, or any other robust Rogue Wave library, into your hands in less than a week. Rogue Wave training and mentoring is available for all levels of project development, from analysis and design to implementation.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software On-line Documentation Rogue Wave provides on-line documentation that supplements this manual. On-line documentation is in the rogue\docs directory. The docs directory contains important information regarding specific compilers and operating systems, how to use shared libraries and DLLs, and information that became available after the manual was published.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Technical Support Rogue Wave is proud of its reputation for superior technical support. Our support policies are described in the technical support brochure that accompanies this product. Extended technical support contracts can be purchased from Rogue Wave or authorized partners. Your first line of technical support is the documentation provided with this product, both on-line and in the manual.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software How to Contact Technical Support You can contact technical support via any of the following paths: FAX: (541) 758-4761 Telephone: (541) 754-2311 BBS: (541) 754-5011 Mail: 850 SW 35th Street, Corvallis, OR 97333, USA e-mail: support@roguewave.com World Wide Web: http://www.roguewave.
Click on the banner to return to the user guide home page.
persistence, internationalization, and other issues, and a number of implementation classes that implement these interfaces. Although public, the implementation classes act like private classes. They are not designed to be used, and are therefore not documented. Some Tools.h++ classes are further categorized as collection classes, or collections. A central feature of Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Concrete Classes The concrete classes consist of: ● The simple classes representing dates, times, strings, and so on, discussed in Chapters 3 through 5 (3,4,5); ● The template-based collection classes, discussed in Chapter 11; ● The generic collection classes using the preprocessor facilities, discussed in Chapter 12. Simple Classes Tools.h++ provides a rich set of lightweight simple classes.
Generic Collection Classes Generic collection classes are those which use the preprocessor macros supplied with your C++ compiler. They can approximate templates, in the sense that they are typesafe, for compilers that do not support templates, and so are highly portable. However, because they depend heavily on the preprocessor, it can be difficult to use a debugger on code that contains them. See Chapter 12 for more information.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Abstract Base Classes Tools.h++ includes a set of abstract base classes and corresponding specializing classes that provides a framework for many issues. The list below identifies some of these issues and associates them with their respective abstract base classes. The description of each class in the Class Reference indicates if it is an abstract base class.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Smalltalk-like Collection Classes The Smalltalk-like collection classes of Tools.h++ give you much of the functionality of such Smalltalk namesakes as Bag and SortedCollection, along with some of the strengths and weaknesses of C++. The greatest advantages of the Smalltalk-like collections are their simple programming interface, powerful I/O abilities, and high code reuse.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Common Member Functions Whatever their category, all classes have similar programming interfaces. This section highlights their common functionality. Persistence Tools.
Rwspace Rwspace ClassName::binaryStoreSize() const; ClassName::recursiveStoreSize() const; The member functions use the function: RWFile& operator<<(RWFile& file, const ClassName&); The above member functions are good for storing objects using classes RWFileManager and RWBTreeOnDisk. For objects that inherit from RWCollectable, the second variant recursiveStoreSize()can calculate the number of bytes used in a recursive store.
RWBoolean operator>(const ClassName&) const;
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Memory Allocation and Deallocation When an object is allocated off the heap, who is responsible for deleting it? With some libraries, ownership can be a problem. Most of the Rogue Wave classes take a very simple approach: if you allocate something off the heap, then you are responsible for deallocating it. If the Rogue Wave library allocates something off the heap, then it is responsible for deallocating it.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Information Flow With the Rogue Wave libraries, information generally flows into a function via its arguments and out through a return value. Most functions do not modify their arguments. Indeed, if an argument is passed by value or as a const reference: void foo(const RWCString& a) you can be confident that the argument will not be modified.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Multithread Safe When compiled with the appropriate option according to the release notes for your compiler, Tools.h++ is multithread safe. In other words, all Tools.h++ functions behave the same in a multithreaded environment as in a single-threaded environment.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Eight-bit Clean All classes in Tools.h++ are eight-bit clean. This means they can be used with eight-bit code sets such as ISO Latin-1.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Embedded Nulls All classes in Tools.h++, including RWCString and RWWString, support character sets with embedded nulls. This allows them to be used with multibyte character sets.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Indexing Indexes have type size_t, an unsigned integral type defined by your compiler, usually in . Because size_t is unsigned, it allows indexes up to 64k minus one under 16-bit DOS. Invalid indexes are signified by the special value RW_NPOS, defined in .
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Version When programming, you may need to know the specific version number of Tools.h++ to perform certain operations. This number is given by the macro RWTOOLS, expressed as a hexadecimal number. For example, version 1.2.3 would be 0x123. This can be used for conditional compilations. If the version is needed at run time, you can find it via the function rwToolsVersion(), declared in header file .
RWSlistCollectablesQueue RWSlistCollectablesStack RWCollectableDate (&RWDate) RWCollectableInt (&RWInteger) RWCollectableString (&RWCString) RWCollectableTime (&RWTime) RWModelClient RWCRegexp RWCRExp RWCString RWCollectableString (&RWCollectable) RWCSubString RWCTokenizer RWDate RWCollectableDate (&RWCollectable) RWErrObject RWFile RWFileManager RWGBitVec(size) RWGDlist(type) RWGDlistIterator(type) RWGOrderedVector(val) RWGQueue(type) RWGSlist(type) RWGSlistIterator(type) RWGStack(type) RWGVector(val) RWGS
RWLocaleSnapshot RWMessage RWModel RWTime RWCollectableTime (&RWCollectable) RWTimer RWTBitVec RWTIsvDlist RWTIsvDlistIterator RWTIsvSlist RWTIsvSlistIterator RWTPtrDeque RWTPtrDlist RWTPtrDlistIterator RWTPtrHashMap RWTPtrHashMapIterator RWTPtrHashMultiMap RWTPtrHashMultiMapIterator RWTPtrHashMultiSet RWTPtrHashMultiSetIterator RWTPtrHashSet RWTPtrHashSetIterator
RWTRegularExpression RWTStack RWTValDeque RWTValDlist RWTValDlistIterator RWTValHashMap RWTValHashMapIterator RWTValHashMultiMap RWTValHashMultiMapIterator RWTValHashMultiSet RWTValHashMultiSetIterator RWTValHashSet RWTValHashSetIterator RWTValMap RWTValMapIterator RWTValMultiMap RWTValMultiMapIterator
RWeostream RWpostream RWXDRostream RWVirtualPageHeap RWBufferedPageHeap RWDiskPageHeap RWWString RWWSubString RWWTokenizer RWZone RWZoneSimple streambuf RWAuditStreamBuffer RWCLIPstreambuf RWDDEstreambuf xmsg RWxmsg RWExternalErr RWFileErr RWStreamErr RWInternalErr RWBoundsErr RWxalloc (&RWios)
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 3: Using the String Classes ❍ An Introductory Example ❍ Lexicographic Comparisons ❍ Substrings ❍ Pattern Matching ❍ ■ Simple Regular Expressions ■ Extended Regular Expressions String I/O ■ iostreams ■ Virtual Streams ❍ Tokenizer ❍ Multibyte Strings ❍ Wide Character Strings Manipulating strings is probably one of your most common tasks.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software An Introductory Example The following example calls on several essential features of the string classes. Basically, it shows the steps RWCString would take to substitute a new version number for the old ones in a piece of documentation. #include #include #include main(){ RWCString a; //1 create string object a RWCRegexp re("V[0-9]\\.
where() is an example of an overloaded operator. As you know, an overloaded operator is one which can perform more than one function, depending on context or argument. In the example, the function call operator RWCString::operator()is overloaded to take an argument of type RWCRegexp, the regular expression. The operator returns either a substring that delimits the regular expression, or a null substring if a matching expression cannot be found.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Lexicographic Comparisons If you're putting together a dictionary, you'll find the lexicographics comparison operators of RWCString particularly useful.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Substrings A separate RWCSubString class supports substring extraction and modification. There are no public constructors; RWCSubStrings are constructed indirectly by various member functions of RWCString, and destroyed at the first opportunity. You can use substrings in a variety of situations.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Pattern Matching Class RWCString supports a convenient interface for string searches. In the example below, the code fragment: RWCString s("curiouser and curiouser."); size_t i = s.index("curious"); will find the start of the first occurrence of curious in s. The comparison will be case sensitive, and the result will be that i is set to 0. To find the index of the next occurrence, you would use: i = s.
return 0; } Program Output: WM_CREATE The function call operator for RWCString has been overloaded to take an argument of type RWCRegexp. It returns an RWCSubString matching the expression, or the null substring if there is no such expression. Extended Regular Expressions This version of the Tools.h++ class library supports extended regular expression searches based on the POSIX.2 standard. (See the Bibliography.
Note that the function call operator for RWCString has been overloaded to take an argument of type RWCRExpr. It returns an RWCSubString matching the expression, or the null substring if there is no such expression.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software String I/O Class RWCString offers a rich I/O facility to and from both iostreams and Rogue Wave virtual streams.
count++; cout << count << " lines, skipping whitespace.\n"; } { int count = 0; ifstream istr("testfile.dat"); while (line.readLine(istr, FALSE)) // NB: Do not skip // whitespace count++; cout << count << " lines, not skipping whitespace.\n"; } return 0; } Program Input: line 1 line 5 Program Output: 2 lines, skipping whitespace. 5 lines, not skipping whitespace.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Tokenizer You can use the class RWCTokenizer to break up a string into tokens separated by arbitrary white spaces. Here's an example: #include #include #include main(){ RWCString a("a string with five tokens"); RWCTokenizer next(a); int i = 0; // Advance until the null string is returned: while( !next().
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Multibyte Strings Class RWCString provides limited support for multibyte strings, sometimes used in representing various alphabets (see Chapter 16: Localizing Alphabets...). Because a multibyte character can consist of two or more bytes, the length of a string in bytes may be greater than or equal to the number of actual characters in the string.
cout << b.length(); cout << strlen(b.data()); // Prints "3" // Prints "3" cout << c.length(); cout << strlen(c.data()); return 0; } // Prints "7" // Prints "3" You will notice that two different constructors are used above. The constructor in lines 1 and 2 takes a single argument of const char*, a null-terminated string. Because it takes a single argument, it may be used in type conversion (ARM 12.3.1). The length of the results is determined the usual way, by the number of bytes before the null.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Wide Character Strings Class RWWString , also used in representing various alphabets, is similar to RWCString except it works with wide characters. These are much easier to manipulate than multibyte characters because they are all the same size: the size of a wchar_t. Tools.h++ makes it easy to convert back and forth between multibyte and wide character strings.
main() { RWCString EnglishSun("Sunday"); assert(EnglishSun.isAscii()); // Ascii string // OK // Now convert from Ascii to wide characters: RWWString wEnglishSun(EnglishSun, RWWString::ascii); assert(wEnglishSun.isAscii()); RWCString check = wEnglishSun.toAscii(); assert(check==EnglishSun); return 0; } // OK // OK Note how the member functions RWCString::isAscii() and RWWString::isAscii() are used to ensure that the strings consist entirely of Ascii characters.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 4: Using Class RWDate ❍ Example ❍ Constructors Class RWDate represents a date, stored as a Julian day number. Commonly used in software, this compact representation allows rapid calendar calculations, shields you from details such as leap years, and performs easy conversions to and from conventional calendar formats. You don't need to know Julian day numbers to benefit from their use in Tools.h++.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Example The point is that RWDate allows you to quickly and easily manipulate the calendar dates you're most likely to use. Here is an example that demonstrates the virtuosity of the class. Let's print out the date when ENIAC first started, 14 February 1945, then calculate and print the date of the previous Sunday, using the global locale: #include #include
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Constructors You can construct an RWDate in several ways. For example: 1. Construct an RWDate with the current date[4]: RWDate d; 2. Construct an RWDate for a given day of the year (1-365) and a given year, e.g., 1989 or 89. Although the class supports 2-digit year specifiers, we urge you to use the 4-digit variety if possible to avoid difficulties at the turn of the century.
RWDate d(frenchDate, french); // OK // 2 cout << frenchDate << ((d.isValid()) ? " IS " : " IS NOT ") << "a valid date (french locale)." << endl << endl; RWDate bad = RWDate(frenchDate); // cout << frenchDate; cout << ((bad.isValid() && bad == d) ? " IS " : " IS NOT ") << "a valid date (default locale)." << endl << endl; bad = RWDate(americanDate, french); // cout << americanDate; cout << ((bad.isValid() && bad == d) ? " IS " : " IS NOT ") << "a valid date (french locale).
10.06.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 5: Using Class RWTime ❍ Setting the Time Zone ❍ Constructors ❍ Member Functions Class RWTime represents time, stored as the number of seconds since 1 January 1901 UTC. UTC is sometimes called GMT, for Greenwich Meridian Time. The number of seconds that can be stored is limited by the size of a long on your system.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Setting the Time Zone The question naturally arises, how does the library determine this local time? The UNIX operating system provides for setting the local time zone and for establishing whether DST is locally observed. Class RWTime uses various system calls to determine these values and sets itself accordingly. Class RWTime should function properly in North America or places where DST is not observed.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Constructors An RWTime may be constructed in several ways: 1. Construct an RWTime with the current time: RWTime t; 2. Construct an RWTime with today's date, at the specified local hour (0-23), minute (0-59), and second (0-59): RWTime t(16, 45, 0); // today, 16:45:00 3. Construct an RWTime for a given date and local time: RWDate d(2, "June", 1952); RWTime t(d, 16, 45, 0); // 6/2/52 16:45:003 4.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Member Functions Class RWTime has member functions to compare, store, restore, add, and subtract RWTimes. An RWTime may return hours, minutes or seconds, or fill a struct tm for any time zone. A complete list of member functions is included in the Class Reference. For example, here is a code fragment that outputs the hour in local and UTC zones, and then the complete local time and date: RWTime t; cout << t.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 6: Using Virtual Streams ❍ Specializing Virtual Streams ❍ Simple Example ❍ Windows Clipboard and DDE Streambufs ❍ DDE Example ❍ RWAuditStreamBuffer ❍ Recap The iostream facility that comes with every C++ compiler is a resource that should be familiar to you as a C++ developer.
Inheriting from RWvios are the abstract base classes RWvistream and RWvostream.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Specializing Virtual Streams The Rogue Wave classes include four types of classes that specialize RWvistream and RWvostream.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Simple Example Here's a simple example that exercises RWbostream and RWbistream through their respective abstract base classes, RWvostream and RWvistream: #include #include #include
RWCString b = recover(bistr); // 7 cout << a << endl; cout << b << endl; return 0; // 8 // Compare the two strings } Program Output: A string with newline. A string with newline. tabs and a tabs and a The job of function save(const RWCString& 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.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Windows Clipboard and DDE Streambufs In the previous section, you saw how the virtual streams facility abstracts the formatting of items inserted into the stream. The disposition of the items inserted into the streams has also been made abstract: it is set by the type of streambuf used. Class streambuf is the underlying sequencing layer of the iostreams facility.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software DDE Example Let's look at a more complicated example of how you might use class RWDDEstreambuf to exchange an RWBinaryTree through the Windows DDE facility. You would use a similar technique for the Windows Clipboard. #include #include #include #include #include #include
// Post the DDE response: return PostMessage(0xFFFF, WM_DDE_DATA, hwndServer, MAKELONG(hDDEData, atom)); //10 } In the code above, the large memory model has been assumed. Here's the line-by-line description: //1 An RWBinaryTree is built and some items inserted into it. //2-//5 An RWDDEstreambuf is allocated. The constructor takes several arguments. The first argument is the Windows Clipboard format.
set the formatting at run time.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software RWAuditStreamBuffer Classes RWDDEstreambuf and RWCLIPstreambuf specialize streambuf to hand off the characters according to the Windows API. But there are other useful specializations of a streambuf. Class RWAuditStreamBuffer allows you to count the bytes of any stream, while optionally calling a function of your choice for each character. See the code example in the Class Reference.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Recap In this section, you have seen how an object can be stored to and recovered from a stream without regard for the final destination of the bytes of that stream, whether memory or disk. You have also seen that you need not be concerned with the final formatting of the stream, whether ASCII or binary. You can also write your own specializing virtual stream class, much like RWpostream and RWpistream.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 7: Using Class RWFile ❍ Example Class RWFile encapsulates the standard C file operations for binary read and write, using the ANSI-C functions fopen(), fwrite(), fread(), etc. This class is patterned on class PFile of the Interviews Class Library (Stanford University, 1987), but has been modernized by Rogue Wave to use const modifiers, and to port to various operating systems.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Example Class RWFile also 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 as arrays. The file pointer may be repositioned with functions SeekTo(), SeekToBegin(), and SeekToEnd(). The details of the RWFile class capabilities are summarized in the Class Reference. The following example creates an RWFile with filename test.dat.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 8: Using Class RWFileManager ❍ Construction ❍ Member Functions 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.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Construction The RWFileManager constructor has the prototype: RWFileManager(const char* filename); The argument is the name of the file that the RWFileManager is to manage. If it exists, it must contain a valid RWFileManager; otherwise, one will be created.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software 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.
#include struct DiskNode { int data; Rwoffset nextNode; }; main(){ RWFileManager fm("linklist.dat"); // 2 // 3 // 4 // 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.
//5 This is the constructor for an 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.
fm.Read(next); DiskNode n; while (next != RWNIL) { fm.SeekTo(next); fm.Read(n.data); fm.Read(n.nextNode); cout << n.data << "\n"; next = n.nextNode; } return 0; } // 3 // 4 // 5 // 6 // 7 // 8 // 9 And this is 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.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 9: Using Class RWBTreeOnDisk ❍ Construction ❍ Example 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 char.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Construction An RWBTreeOnDisk is always constructed from an RWFileManager. If the RWFileManager is managing a new file, then the RWBTreeOnDisk will initialize it with an empty root node. For example, the following code fragment constructs an RWFileManager for a new file called filename.dat and then constructs an RWBTreeOnDisk from it: #include #include
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Example In this example, key-value pairs of character strings and offsets to RWDates representing birthdays are stored. Given a name, you can retrieve a birthdate from disk. #include #include #include #include #include main(){ RWCString name; RWDate birthday; RWFileManager fm("birthday.
//4 Allocate enough space from the RWFileManager to store the birthday. Function binaryStoreSize() is a member function in most Rogue Wave classes. It returns the number of bytes necessary to store an object in an RWFile. If you are storing an entire RWCollection, or using one of the methods recursiveSaveOn() or operator<<(RWFile&, RWCollectable), be sure to use recursiveStoreSize() instead. //5 Seek to the location where the RWDate will be stored. //6 Store the date at that location.
//1 The program accepts names until encountering an EOF. //2 The name is used as a key to RWBTreeOnDisk, which returns the associated value, an offset, into the file. //3 Check to see whether the name was found. //4 If the name is valid, use the value to seek to the spot where the associated birthdate is stored. //5 Read the birthdate from the file. //6 Print it out. With a little effort, you can easily have more than one B-tree active in the same file.
fm.SeekTo(fm.start()); fm.Read(rootArray, 3); // Recover locations of root nodes for (int itree=0; itree<3; itree++) { // Initialize the three trees: treeArray[itree] = new RWBTreeOnDisk(fm, 10, // Max. nodes cached RWBTreeOnDisk::autoCreate, // Will read old tree 16, // Key length FALSE, // Do not ignore nulls rootArray[itree] // Location of root ); } . . .
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 10: Collection Classes ❍ Storage Methods of Collection Classes ■ ❍ ❍ Copying Collection Classes ■ Copying Reference-based Collection Classes ■ Copying Value-based Collection Classes Retrieving Objects in Collections ■ ❍ A Note on Memory Management Retrieval Methods Iterators in Collection Classes ■ Traditional Tools.h++ Iterators The Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Storage Methods of Collection Classes The general objective of collection classes, called collections for short, is to store and retrieve objects. In fact, you can classify collection classes according to how they store objects. Value-based collections store the object itself; reference-based collections store a pointer or reference to the object.
A Note on Memory Management A reference-based collection can be very efficient because pointers are small and inexpensive to manipulate. However, with a reference-based collection, you must always remember that you are responsible for memory management: the creation, maintenance, and destruction of the actual objects themselves. If you create two pointers to the same object and prematurely delete the object, you'll leave the second pointer pointing into nonsense.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Copying Collection Classes Copying classes is a common software procedure. It happens every time a copy constructor is applied, or whenever a process needs a copy to work on. Copying value-based collection classes is straightforward. But special considerations arise in copying reference-based classes, and we deal with them here.
Making a shallow copy and a deep copy of Bag would produce the following results: You can see that the deep copy copies not only the bag itself, but recursively all objects within it. The copying approach you choose is important. For example, shallow copies can be useful and fast, because less copying is done, but you 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.
that is, an ordered vector template instantiated for RWCString. In this case, each string is embedded within the collection. When a copy of the collection class is made, not only the collection class itself is copied, but also the objects in it.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Retrieving Objects in Collections We have defined the major objective of collection classes as storing and retrieving objects. How you retrieve or find an object depends on its properties. Every object you create has three properties associated with it: 1. Type: for example, an RWCString or a double. In C++, the type of an object is set at creation, and cannot change. 2. State: the value of the string.
In C++, to test for identity_that is, to test whether two objects are the same object_you must see if they have the same address. Because of multiple inheritance, the address of a base class and its associated derived class may not be the same. Therefore, if you compare two pointers (addresses) to test for identity, the types of the two pointers should be the same. Smalltalk uses the operator = to test for equality, and the operator == to test for identity.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Iterators in Collection Classes Many of the collection classes have an associated iterator. The advantage of the iterator is that it maintains its own internal state, thus allowing two important benefits: ● More than one iterator can be constructed from the same collection class; ● All of the items need not be visited in a single sweep.
current object. There are various methods for moving this mark. For example, most of the time you will probably be using member function operator(). In Tools.h++, it is designed to always advance to the next object, then return either TRUE or a pointer to the next object, depending on whether the associated collection class is value-based or reference-based, respectively. It always returns FALSE (i.e., zero) when the end of the collection class is reached.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 11: Collection Class Templates ❍ Introduction ❍ Template Overview ❍ ■ Template Naming Convention ■ Value vs. Reference Semantics in Templates ■ Intrusive Lists in Templates Tools.
❍ Migration Guide: For Users of Previous Versions of Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Introduction As a developer, you no doubt periodically ask yourself, "Haven't I coded this before?" Clearly, one of the primary attractions of the C++ language is the promise of reuse, the lure of avoiding rewrites of the same old code, over and over again. The Tools.h++ collection classes take advantage of several C++ language features that support reuse.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Template Overview To gain some perspective, let's begin with a general example that shows how templates work. We'll explain concepts from the example throughout the section, though you'll probably follow this without difficulty now: #include #include #include #include
The preceding example demonstrates the basic operation of templates. Using the collection class template RWTValDList, we instantiate the object stringList, simply by specifying type RWCString. The template gives us complete flexibility in specifying the type of the list; we don't write code for the object, and Tools.h++ doesn't complicate its design with a separate class RWTValDListofRWCString. Without the template, we would be limited to types provided by the program, or forced to write the code ourselves.
RWTValDlist myBirthdayV; gives you a value-based list, where the values are of type pointer to RWDate. The collection class will concern itself only with the pointers, never worrying about the actual RWDate objects they refer to. Now consider: RWDate* d1 = new RWDate(29,12,55); // December 29, 1955 myBirthdayV.insert(d1); RWDate* d2 = new RWDate(29,12,55); // Different object, same date cout << myBirthdayV.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Tools.h++ Templates and the Standard C++ Library Most of the Tools.h++ collection class templates use the Standard C++ Library for their underlying implementation. The collection classes of the Standard C++ Library, called containers, act as an engine under the hood of the Tools.h++ templates. For example, the value-based Tools.
Library iterators. The Tools.h++ Class Reference contains entries for both the full and the subset interfaces for all of the templates that can be used either with or without the Standard C++ Library. There are two reasons you may want to use the restricted subset interface for a collection class template: 1. You may be operating in an environment that does not yet support a version of the Standard C++ Library compatible with this version of Tools.h++.
Associative container-based (set-based) RWTValSet RWTValMultiSet RWTPtrSet RWTPtrMultiSet Yes Yes (map-based) //Internal ordering, access by key Associative hash-based (set-based) RWTValMap RWTValMultiMap RWTPtrMap RWTPtrMultiMap Yes Yes RWTValHashSet RWTPtrHashSet RWTValHashMultiSet RWTPtrHashMultiSet No No (map-based) //No ordering, access by key RWTValHashMap RWTPtrHashMap RWTValHashMultiMap RWTPtrHashMultiMap No Yes Commonality of Interface To keep things simple and allow you to program wit
coll.removeLast(); } Thanks to the common interface, the above function template will work when instantiated with any of the Rogue Wave Sequence-based templates.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Parameter Requirements In order to use a Tools.h++ template collection class to collect objects of some type T, that type must satisfy certain minimal requirements. Unfortunately, some compilers may require the instantiating type or types to be more powerful than should be necessary.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Comparators The associative container-based and the sorted sequence-based collection classes maintain order internally. This ordering is based on a comparison object, an instance of a comparator class you must supply when instantiating the template.
comp(x,z) (transitivity). The truth of I.a implies that x must precede y within the collection class, while I.b says that y must precede x. More interesting is I.c. If this statement is true, we say that x and y are equivalent, and it doesn't matter in what order they occur within the collection class. This is the notion of equality that prevails for the templates that take a comparator as a parameter.
first rule of a total ordering relation.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Hash Functors and Equalitors The associative hash-based templates use a hash function object to determine how to place and locate objects within the collection class. An advantage of using hash function objects is efficient, constant-time retrieval of objects.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Iterators Tools.h++ provides several distinct methods for iterating over a collection class. Most collections offer an apply member function, which applies your supplied function to every element of a collection class before returning. Another form of iteration is provided by separate collaborating iterator classes associated with many of the collections.
Again, your standard library documentation will describe all the operators and functions available for each type of iterator. In addition to the iterators just described, the standard library-based collection class templates also provide two typedefs used to iterate over the items in a collection class: iterator, and const_iterator. You can use the iterator typedef to traverse a collection class and modify the elements within.
Map-Based Iteration and Pairs In the case of a map-based collection class, like RWMapVal, iterators refer to instances of the Standard C++ Library structure pair. As you iterate over a map-based collection, you have access to both the key and its associated data at each step along the traversal. The pair structure provides members first and second, which allow you to individually access the key and its data, respectively.
// set another iterator past the end: int* theEnd = intCollection + 10; // iterate through, looking for a 7: while (iter != theEnd) { // test for end of array if (*iter == 7) // use '*' to access current element return true; // found a 7 ++iter; // not a 7, try next element } return false; // never found a 7 If you compare this code fragment to the one using standard iterators toward the beginning of this section, you can see the similarities.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Iterators and the std() Gateway The Tools.h++ templates are meant to enhance the Standard C++ Library, not to stand as a barrier to it. The iterators described in the previous section are standard iterators, and you can use them in conjunction with any components offering a standard iterator-based interface.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software The Best of Both Worlds The following example is a complete program that creates a deck of cards and shuffles it. The purpose of the example is to show how the Tools.h++ template collections can be used in conjunction with the Standard C++ Library. See your Standard C++ Library documentation for more information on the features used in the example.
// generate the next Card Card operator()() { rankIdx = (rankIdx + 1) % 13; if (rankIdx == 0) // cycled through ranks, move on to next suit: suitIdx = (suitIdx + 1) % 4; return Card(Ranks[rankIdx], Suits[suitIdx]); } }; const char DeckGen::Suits[4] = {'S', const char DeckGen::Ranks[13] = {'A', '5', '9', 'H', '2', '6', 'T', 'D', '3', '7', 'J', 'C' }; '4', '8', 'Q', 'K' }; int main(){ // Tools.
The deck has been created The Ace of Spades is at position 1 The deck has been shuffled Now the Ace of Spades is at position 37 and the first card is Q-D */
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Using Templates Without the Standard Library Several of the Tools.h++ templates, such as RWTValVector, RWTPtrVector, RWTIsvSlist, and RWTIsvDlist, are not based on the Standard C++ Library. You can use them on any of our certified platforms.
10. is a portable declaration that will work with or without the Standard C++ Library. Again, do not use a comma to separate the element type from the macro. An Example Let's start with a simple example that uses RWTValVector, one of the classes that is not based on the Standard C++ Library. #include // 1 main() { RWTValVector vec(20, 0.0); int i; for (i=0; i<10; i++) for (i=11; i<20; i++) vec.reshape(30); for (i=21; i<30; i++) return 0; } // 2 vec[i] = 1.0; vec(i) = 2.
Count() : N(0) { } int operator++() { return ++N; } operator int() { return N; } // 2 // 3 // 4 }; unsigned hashString ( const RWCString& str ) { return str.hash(); } // 5 main() { RWTValHashDictionary hmap(hashString); //6 RWCString token; while ( cin >> token ) ++hmap[token]; // 7 // 8 RWTValHashDictionaryIterator next(hmap); // 9 cout.setf(ios::left, ios::adjustfield); while ( ++next ) cout << setw(20) << next.
//3 We supply a prefix increment operator. This will be used to increment the count in a convenient and pleasant way. //4 A conversion operator is supplied that allows Count to be converted to an int. This will be used to print the results. Alternatively, we could have supplied an overloaded operator<<() to teach a Count how to print itself, but this is easier. //5 This is a function that must be supplied to the dictionary constructor.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Migration Guide: For Users of Previous Versions of Tools.h++ As we explained in the introduction to this manual, one of our primary goals for this version of Tools.h++ is to protect your investment in existing code based on previous versions of the library.
Existing code using these templates will not provide the number of template arguments expected by this version of Tools.h++ when used with the Standard C++ Library. The solution to this problem is to use the macros discussed in in An Example of Using Templates Without the Standard Library. Using the macros described there will satisfy the compiler and preserve the semantics of your existing code.
As mentioned above, some compilers will require that the expression (t1 < t2) be defined for two instances of your element type. This is due to the inclusion of convenient member functions, such as sort() and min_element(),combined with certain compilers that instantiate all member functions whether used or not. You might have existing code that instantiates one of these templates on a type T for which no operator<() is defined. If that is the case, you will have to define one.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 12: Generic Collection Classes ❍ Example ❍ Declaring Generic Collection Classes ❍ User-Defined Functions ■ Tester Functions ■ Apply Functions Generic collection classes are the second major category of collection classes included in Tools.h++. We call them generic because they use the macros defined in
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Example Here is an example that uses an RWGStack , a 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 #include //1 //2 declare(RWGStack, int) //3 main(){ RWGStack(int) gs; gs.push(new int(1)); gs.push(new int(2)); gs.push(new int(3)); gs.
Each line of the program is detailed below. //1 This #include defines the preprocessor macro RWGStackdeclare(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, the macro serves as a restricted interface to the underlying implementation, which is a singly-linked list, class RWSlist.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Declaring Generic Collection Classes All the Tools.h++ generic collection classes are declared as in the example above, using the declare macro defined in the header file . 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).
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software 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 of these user-defined functions, discussed in the following two sections. Tester Functions The first kind of user-defined function is a tester function.
} main(){ RWGStack(int) gs; gs.push(new int(1)); gs.push(new int(2)); gs.push(new int(3)); gs.push(new int(4)); //3 //4 //5 //6 //7 int aValue = 2; //8 if ( gs.contains(myTesterFunction, &aValue) ) cout << "Yup.\n"; else cout << "Nope.\n"; //9 while(!gs.isEmpty()) delete gs.pop(); return 0; } 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.
//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, and waiting for the tester function to signal a match. If it does, contains() returns TRUE; otherwise, FALSE.
Apply 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 items are appended at the tail of the list. 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 beginning to end, the items will come out in the same order in which they were inserted. See the Class Reference for RWGDlist(type).
Click on the banner to return to the user guide home page.
typesafe, and their objects are slightly larger. These disadvantages are easily outweighed by the power of these classes, and their clean programming interface. Most importantly, the Smalltalk-like collection classes are well-suited for heterogeneous collections and polymorphic persistence. Many of the Tools.h++ Smalltalk-like classes have a typedef to either the corresponding Smalltalk names, or to a generic name. This typedef is activated by defining the preprocessor macro RW_STD_TYPEDEFS.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Tables of the Smalltalk-like Classes The following two tables summarize the Tools.h++ Smalltalk-like classes. Table 1 lists all 17 classes, along with their typedefs, iterators, and implementations. Table 2 illustrates the class hierachy.
RWSlistCollectables RWSlistCollectablesIterator LinkedList Singly-linked list RWSlistCollectablesQueue (n/a) Queue Singly-linked list RWSlistCollectablesStack (n/a) Stack Singly-linked list RWSortedVector RWSortedVectorIterator Vector of pointers, using insertion sort Note that some of these classes use multiple-inheritance: this hierarchy is shown relative to the RWCollectable base class.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Example To orient ourselves, we always like to start with an example. The following example uses a SortedCollection to store and order a set of RWCollectableStrings. SortedCollection is actually a typedef for the Smalltalk-like collection class RWBinaryTree. Objects inserted into it are stored in order according to their relative values as returned by the virtual function compareTo().
Throkmorton Let's go through the code line-by-line and explain what is happening: //1 By defining the preprocessor macro RW_STD_TYPEDEFS, we enable the set of Smalltalk-like typedefs. We can then use the typedef SortedCollection instead of RWBinaryTree, its true identity. //2 The second #include declares class RWCollectableString, a derived class that multiply inherits from its base classes RWCString and RWCollectable.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Choosing a Smalltalk-like Collection Class Now that you have reviewed the list of Smalltalk-like collection classes, their class hierarchy, and an example of how they work, you may be wondering how you can use them. This section gives an overview of the various Smalltalk-like collection classes to help you choose an appropriate one for your problem. You can also see Appendix A, on choosing.
you exceed the capacity of a vector-based collection class, it will automatically resize, but it may exact a significant performance penalty to do so. Note that the binary and B-tree classes can be considered sequenceable in the sense that they are sorted, and therefore have an innate ordering. However, their ordering is determined internally by the relative value of the collected objects, rather than by an insertion order.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Virtual Functions Inherited From RWCollection The Smalltalk-like collection classes inherit from the abstract base class RWCollection, which in turn inherits from the abstract base class RWCollectable, described in Chapters 13 (Tables of the Smalltalk-like Classes) and 15. (Thus do we produce collections of collections, but that is another story.
find() and Friends You can use the following virtual functions to test how many objects a collection contains, and whether it contains a particular object: 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; The function isEmpty() returns TRUE if the collection contains no objects.
RWCollectableString dummy("Mary"); RWCollectable* t = sc.find( &dummy ); //10 //11 if(t){ if(t->isA() == dummy.isA()) cout << *(RWCollectableString*)t << "\n"; } else cout << "Object not found.\n"; //12 //13 //14 cout << sc.occurrencesOf(&dummy) << "\n"; //16 //15 sc.clearAndDestroy(); return 0; } Program Output: 5 Mary 2 Here's the line-by-line description: //1 - //7 These lines are from the example in Chapter 13. //8 //9 //10 //11 //12 //13 Insert another instance with the value Mary.
remove() Functions To search for and remove particular items, you can use the functions remove() and removeAndDestroy(): 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 is found.
a window on which the object is to be drawn. Note that the apply() functions of the Smalltalk-like collections and the generic collections are similar. (Compare Chapter 12: Apply Functions.) The difference is in the type of the first argument of the user-supplied function: the Smalltalk-like collections use RWCollectable*, while the generic collections use type*. With both sets of collections, you must be careful that you cast the pointer item to the proper derived class.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software 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.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Virtual Functions Inherited from RWSequenceable Collections that inherit from the abstract base class RWSequenceable, which inherits from RWCollectable, have an innate, meaningful ordering. This section describes the virtual functions inherited from RWSequenceable which make use of that ordering.
we were searching for was found at position 1. RWOrdered od; od.insert(new RWCollectableInt(6)); od.insert(new RWCollectableInt(2)); od.insert(new RWCollectableInt(4)); // 6 // 6 2 // 6 2 4 RWCollectableInt dummy(2); size_t inx = od.index(&dummy); if (inx == RW_NPOS) cout << "Not found.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software A Note on How Objects are Found You may save yourself some difficulty by remembering the following point: the virtual functions of the object within the collection, not those of the target, are called when comparing or testing a target for equality. The following code fragment illustrates the point: SortedCollection sc; RWCollectableString member; sc.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 14: Persistence ❍ Levels of Persistence ■ A Note About Terminology ■ About the Examples in this Section ❍ No Persistence ❍ Simple Persistence ■ ❍ ❍ ❍ Two Examples of Simple Persistence Isomorphic Persistence ■ Isomorphic versus Simple Persistence ■ Isomorphic Persistence of a Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Levels of Persistence An object has one of four levels of persistence: ● No persistence. There is no mechanism for storage and retrieval of the object. ● Simple persistence. A level of persistence that provides storage and retrieval of individual objects to and from a stream or file. Simple persistence does not preserve pointer relationships among the persisted objects. ● Isomorphic persistence.
About the Examples in this Section For your convenience, all examples listed in this section are provided on disk in the directory rw/toolexam/manual. Each of the examples in this chapter has the name persist*.cpp.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software No Persistence Some Tools.h++ classes have no persistence. The Class Reference indicates "None" in the Persistence section for all such classes. Review the class reference entry for a particular class if you have a question about its level of persistence.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Simple Persistence Simple persistence is the storage and retrieval of an object to and from a stream. Table 1 lists the classes in Tools.h++ that use simple persistence. Category Description C++ fundamental types int, char, float, ...
The example uses the overloaded insertion operator operator<< to save the objects, and the overloaded extraction operator operator>> to restore the objects, much the same way as you use these operators to output and input objects in C++ streams. Note that the saving stream and the restoring stream are put into separate blocks. This is so that opening pi will cause it to be positioned at the beginning of the file. Here's the code: #include #include #include
Example Two: Simple Persistence and Pointers This example shows one of the shortcomings of simple persistence: its inability to maintain the pointer relationships among persisted objects. Let's say that you have a class Developer that contains a pointer to other Developer objects: Developer { public: Developer(const char* name, const Developer* anAlias = 0L) : name_(name), alias_(anAlias) {} RWCString name_; // Name of developer. const Developer* alias_; // Alias points to another Developer.
return 0; } Because this example uses simple persistence, which does not maintain pointer relationships, the restored team has different pointer relationships than the original team. Figure 1 shows what the created and restored teams look like in memory if you run the program. Figure 1. Simple Persistence As you can see in Figure 1, when objects that refer to each other are saved and then are restored with simple persistence, the morphology among the objects can change.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Isomorphic Persistence Isomorphic persistence is the storage and retrieval of objects to and from a stream such that the pointer relationships between the objects are preserved. If there are no pointer relationships, isomorphic persistence effectively saves and restores objects the same way as simple persistence.
as they did in the original collection. Figure 2. Saving and restoring with simple persistence. Figure 3. Saving and Restoring a Collection with Isomorphic Persistence In Figure 4, we attempt to save and restore a circularly-linked list, using simple persistence. As shown in the figure, any attempt to use simple persistence to save a circularly-linked list results in an infinite loop. The simple persistence mechanism creates a copy of each object that is pointed to and saves that object to a stream.
has saved. When the isomorphic persistence mechanism encounters a pointer to an unsaved object, it copies the object data, saves that object data_not the pointer_to the stream, then keeps track of the pointer in the save table. If the isomorphic persistence mechanism later encounters a pointer to the same object, instead of copying and saving the object data, the mechanism saves the save table's reference to the pointer.
Isomorphic Persistence of a Tools.h++ Class The following example shows the isomorphic persistence of a templatized collection of RWCollectable integers, RWTPtrDlist. RWTPtrDlist is a templatized, reference-based, doubly-linked list that uses isomorphic persistence to store pointer references to values in memory. This example uses RWCollectableInt instead of int because ints use simple persistence. By using RWCollectableInts, we can implement isomorphic persistence.
f >> // // // // // // dlist2; restore dlist2 from f dlist2 now contains 2 pointers to the same RWCollectableInt of value 1. However, this RWCollectableInt isn't at the same address as the value that "one" points to. } // See Figure 6 below to see what dlist1 and dlist2 // now look like in memory. assert(dlist2[0] == dlist2[1] && (*dlist2[0]) == *one); // dlist2[0] and dlist2[1] point to the same place // and that place has the same value as "one".
T(T& t); // copy constructor ● Class T must have an assignment operator defined as a member or as a global function: T& operator=(const T& t); // member function T& operator=(T& lhs, const T& rhs); // global function ● Class T cannot have any non-type template parameters. For example, in RWTBitVec, "size" is placeholder for a value rather than a type.
friend friend friend friend //... }; void void void void rwSaveGuts(RWvostream&, const Friendly&); rwRestoreGuts(RWFile&, Friendly&); rwSaveGuts(RWFile&, const Friendly&); rwRestoreGuts(RWvistream&, Friendly&); Or your class could have accessor functions to the restricted but necessary members: class Accessible { public: int secret(){return secret_} void secret(const int s){secret_ = s} //...
● For non-templatized classes, use RWDECLARE_PERSISTABLE. RWDECLARE_PERSISTABLE is a macro found in rw/edefs.h. To use it, add the following lines to your header file (*.h): #include
// For YourClass: RWDECLARE_PERSISTABLE_TEMPLATE_4(YourClass) Remember, if your templatized class has any non-type template parameters, it cannot be isomorphically persisted. ● If you need to persist templatized classes with five or more template parameters, you can write additional macros for RWDECLARE_PERSISTABLE_TEMPLATE_n. The macros are found in the header file rw/edefs.h.
RWDEFINE_PERSISTABLE_TEMPLATE(YourClass) will expand to generate the source code for the following global functions: template RWvostream& operator<< (RWvostream& strm, const YourClass& item) template RWvistream& operator>> (RWvistream& strm, YourClass& obj) template RWvistream& operator>> (RWvistream& strm, YourClass*& pObj) template RWFile& operator<<(RWFile& strm, const YourClass& item) template RWFile& operator>>(RWFile& strm, YourClass& obj) te
1. You can't use the RWDECLARE_PERSISTABLE_TEMPLATE and RWDEFINE_PERSISTABLE_TEMPLATE macros to persist any templatized class that has non-type template parameters. Templates with non-type template parameters, such as RWTBitVec, cannot be isomorphically persisted. 2. If you have defined any of the following global operators and you use the RWDEFINE_PERSISTABLE macro, you will get compiler ambiguity errors.
rwRestoreGuts(RWFile& f, YourClass& t) {/*_*/} templatevoid rwRestoreGuts(RWvistream& s, YourClass& t) {/*_*/} ● For templatized classes with more than one template parameter, define rwRestoreGuts and rwSaveGuts with the appropriate number of template parameters. Function rwSaveGuts saves the state of each class member necessary persistence to an RWvostream or an RWFile.
Wave classes, including RWCollectable, use the overloaded insertion operator operator<<. ● Saving members that are pointers to non-RWCollectable objects can be a bit tricky. This is because it is possible that a pointer does not point to any object at all. One way of dealing with the possibility of nil pointers is to check whether a pointer points to a valid object. If the pointer is valid, save a Boolean true, then save the dereferenced pointer.
The global overloaded functions: rwRestoreGuts(RWFile& f, YourClass& t) rwRestoreGuts(RWvostream& s, YourClass& t) are responsible for restoring the internal state of a YourClass object from either a binary file (using class RWFile) or from a virtual output stream (an RWvostream). The rwRestoreGuts functions that you write must restore the state of each member in YourClass, including the members of the class that you inherited from. The functions must restore member data in the order that it was saved.
stream >> isValid; // Is it a nil pointer? if (isValid) stream >> gut.pointerToAnObject_; else gut.pointerToAnObject_ = rwnil; // // // // No, restore the pointer. Yes, set pointer to nil. } void rwRestoreGuts(RWFile& stream, Gut& gut) { // The body of this function is identical to // rwRestoreGuts(RWvostream& stream, Gut& gut). } Isomorphic Persistence of a User-designed Class Example Two described some example code that implements simple persistence on a collection that includes pointers.
This code can distinguish between new Developers and existing Developers because the insertion operators generated by RWDEFINE_PERSISTABLE(Developer) keep track of Developers that have been stored previously. The insertion operator, operator<<, calls the rwSaveGuts if and only if a Developer has not yet been stored in the stream by operator<<. When a Developer object is restored, the extraction operator, operator>>, for Developer is called.
// operators: // RWvostream& operator<< // (RWvostream& strm, const Developer& item) // RWvistream& operator>>(RWvistream& strm, Developer& obj) // RWvistream& operator>>(RWvistream& strm, Developer*& pObj) // RWFile& operator<<(RWFile& strm, const Developer& item) // RWFile& operator>>(RWFile& strm, Developer& obj) // RWFile& operator>>(RWFile& strm, Developer*& pObj) void rwSaveGuts(RWFile& file, const Developer& developer){ // Called by: // RWFile& operator<<(RWFile& strm, const Developer& item) file <<
// Should developer.alias_ point to a Developer? RWBoolean alias; file >> alias; // If alias_ should point to a Developer, // then rwRestoreGuts restores the Developer object // and then updates alias_ to point to the new Developer. if (alias) // Yes. file >> developer.alias_; // Call: // RWFile& operator>>(RWFile& strm, Developer*& pObj) } void rwRestoreGuts(RWvistream& stream, Developer& developer) { // Called by: // RWvistream& operator>>(RWvistream& strm, Developer& obj) stream >> developer.
// RWFile& operator>>(RWFile& strm, Team& obj) // RWFile& operator>>(RWFile& strm, Team*& pObj) void rwSaveGuts(RWFile& file, const Team& team){ // Called by RWFile& operator<<(RWFile& strm, const Team& item) for (int i = 0; i < 3; i++) file << *(team.member_[i]); // Save Developer value.
//-------------------- main -------------------------main (){ Developer* kevin = new Developer("Kevin"); Developer* rudi = new Developer("Rudi", kevin); Team team1; team1.member_[0] = rudi; team1.member_[1] = rudi; team1.member_[2] = kevin; cout << "team1 (before save):" << endl << team1 << endl << endl; // Output to user. { RWFile f("team.dat"); f << team1; // Isomorphic persistence of team. } Team team2; { RWFile f("team.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Polymorphic Persistence Polymorphic persistence preserves pointer relationships (or morphology) among persisted objects, and also allows the restoring process to restore an object without prior knowledge of that object's type. Tools.h++ uses classes derived from RWCollectable to do polymorphic persistence. The objects created from those classes may be any of the different types derived from RWCollectable.
Rwvostream& RWFile& operator<<(RWvostream&, const RWCollectable*); operator<<(RWFile&, const RWCollectable*); Each pointer to an object is saved isomorphically with a class ID that uniquely identifies the object's class. Even nil pointers can be saved. ● Operators that restore already-existing RWCollectable objects: Rwvistream& RWFile& operator>>(RWvistream&, RWCollectable&); operator>>(RWFile&, RWCollectable&); Each RWCollectable-derived object is restored isomorphically.
Notice that example one creates and saves a collection that includes two copies of the same object and two other objects. The four objects have three different types. When example one saves the collection and when example two restores the collection, we see that: ● The morphology of the collection is maintained; ● The process that restores the collection does not know the object's type before it restores that object. Here's the first example: #include #include
Note that there are three types of objects stored in collection, an RWCollectableDate, and RWCollectableInt, and two RWCollectableStrings. The same RWCollectableString, george, is inserted into collection twice.
#define RW_STD_TYPEDEFS #include #include #include #include #include main(){ RWpistream istr(cin); RWOrdered collection2; // Even though this program does not need to have prior // knowledge of exactly what it is restoring, the linker // needs to know what the possibilities are so that the // necessary code is linked in for use by RWFactory. // RWFactory creates RWCollectable objects based on // class ID's.
// That is, test for identity, not just equality: if (item->isA() == __RWCOLLECTABLESTRING && item==g) georgeCount++; // Count the strings, dates and integers: switch (item->isA()) { case __RWCOLLECTABLESTRING: stringCount++; break; case __RWCOLLECTABLEINT: integerCount++; break; case __RWCOLLECTABLEDATE: dateCount++; break; default: unknownCount++; break; } } // Output results: cout << "There are:\n\t" << stringCount << " RWCollectableString(s)\n\t" << integerCount << " RWCollectableInt(s)\n\t" << dateCoun
Example Two Revisited It is worth looking at the second example again so that you can see the mechanisms used to implement polymorphic persistence. The expression: istr >> collection2; calls the overloaded extraction operator: RWvistream& operator>>(RWvistream& str, RWCollectable& obj); This extraction operator has been written to call the object's restoreGuts() virtual function.
RWCollectable: Rwvistream& operator>>(RWvistream&, RWCollectable&); instead of to a pointer to a reference to an RWCollectable: Rwvistream& operator>>(RWvistream&, RWCollectable*&); The collection was allocated on the stack: RWpistream istr(cin); RWOrdered collection2; istr >> collection2; ... collection2.clearAndDestroy(); instead of having operator>>(RWvistream&,RWCollectable*&) allocate the memory for the collection: RWpistream istr(cin); RWOrdered* pCollection2; istr >> pCollection2; ...
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software A Few Friendly Warnings Persistence is a useful quality, but requires care in some areas. Here are a few things to look out for when you use persistence on objects. Always Save an Object by Value before Saving the Identical Object by Pointer In the case of both isomorphic and polymorphic persistence of objects, you should never stream out an object by pointer before streaming out the identical object by value.
// Create a value for elroyPtr_ in memory // and change elroyPtr_ to point to that // value in memory: file >> elroyPtr_; // // // // // Assign reference to value. If elroyPtr_ == &elroy then the value of elroy_ will already be created but now elroyPtr_ != &elroy so an RWTOOL_REF exception will be thrown: file >> elroy_; } /* _ */ RWFile file("elmer.dat"); Elmer elmer; Elmer elmer2; elmer.elroyPtr_ = &(elmer.
operator<<(RWFile&, const Elroy&) is called, but this time the insertion operator notices from the isomorphic save table that *(elmer.elroyPtr_) has already been stored, so a reference to *(elmer.elroyPtr_) is stored to file instead of the value. Everything seems okay, but trouble is looming. Trouble arrives with the statement: file >> elmer2; This statement calls the extraction operator operator>>(RWFile&, const Elmer&).
Instead, you should write your functions the following way: // RIGHT! void rwSaveGuts(RWFile& file, const Elmer& elmer) { file << elroy_; file << *elroyPtr_; } void rwRestoreGuts(RWFile& file, Elmer& elmer){ file >> elroy_; file >> elroyPtr_; } If you correct rwRestoreGuts and rwSaveGuts as suggested above, then the isomorphic save and restore tables can use the address of Elmer::elroy_ to update Elmer::elroyPtr_ if necessary.
The problem is that on some compilers godzilla and godzilla.mothra_ have the same address! Upon restoration of godzilla, godzilla.mothra_ is streamed out as a value, and godzilla is streamed out as a reference to godzilla.mothra_. If godzilla and godzilla.mothra have the same address, the restore of godzilla fails because the extraction operator attempts to initialize godzilla with the contents of godzilla.mothra_. There are two ways to overcome this difficulty.
Define All RWCollectables That Will Be Restored Make certain that your program declares variables of all possible RWCollectable objects that you might restore. For an example of this practice, see example 2, above. These declarations are of particular concern when you save an RWCollectable in a collection, then attempt to take advantage of polymorphic persistence by restoring the collection in a different program, without using the RWCollectable that you saved.
Click on the banner to return to the user guide home page.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Why Design an RWCollectable Class? Before we get to the nuts and bolts of how to design an RWCollectable class, let's discuss a concrete example of why you might choose to design RWCollectable classes. Suppose you run a bus company. To automate part of your ridership tracking system, you want to write classes that represent a bus, its set of customers, and its set of actual passengers.
also given as the bus example in the toolexam directory.
that the same person is not entered into the customer list more than once. For the same reason, we have also chosen to implement the set of passengers using class RWSet. However, we have chosen to have this set live on the heap. This will help illustrate some points in the coming discussion.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software How to Create an RWCollectable Object Here's an outline of how to make your object inherit from RWCollectable. Additional information about how to do each step appears in the indicated section. 1. Define a default constructor. See below (Define a Default...). 2. Add the macro RWDECLARE_COLLECTABLE to your class declaration. See below (Add RWDECLARE_...). 3.
Default constructors are necessary in order to create vectors of objects in C++, so providing a default constructor is a good habit to get into anyway. Here's a possible definition of a default constructor for our Bus class. Bus::Bus() : busNumber_ (0), driver_ ("Unknown"), passengers_ (rwnil) { } Add RWDECLARE_COLLECTABLE() to your Class Declaration The example earlier in this chapter (An Example of RWCollectable Classes) includes the macro invocation RWDECLARE_COLLECTABLE(Bus) in the declaration for Bus.
or: RWDEFINE_NAMED_COLLECTABLE(Client, "a client") The first use provides a numeric ID 200 for class Bus, and the second provides a string ID, "a client", for class Client. In the remainder of this manual, we use RWDEFINITION_MACRO to indicate that you can choose either of these macros. In example code, we will pick one or the other macro. Either macro will automatically supply the definitions for the virtual functions isA() and newSpecies().
Add Definitions for Virtual Functions Class RWCollectable declares the following virtual functions: virtual virtual virtual virtual virtual virtual virtual virtual virtual virtual virtual Rwspace int unsigned RWClassID RWBoolean RWCollectable* void void void void ~RWCollectable(); binaryStoreSize() const; compareTo(const RWCollectable*) const; hash() const; isA() const; isEqual(const RWCollectable*) const; newSpecies() const; restoreGuts(RWvistream&); restoreGuts(RWFile&); saveGuts(RWvostream&) const; sav
int Bus::compareTo(const RWCollectable* c) const { const Bus* b = (const Bus*)c; if (busNumber_ == b->busNumber_) return 0; return busNumber_ > b->busNumber_ ? 1 : -1; } Here we are using the bus number as a measure of the ordering of buses. If we need to insert a group of buses into an RWBinaryTree, they would be sorted by their bus number. Note that there are many other possible choices_we could have used the driver name, in which case they would have been sorted by the driver name.
RWBoolean Bus::isEqual(const RWCollectable* c) const { const Bus* b = (const Bus*)c; return busNumber_ == b->busNumber_; } Here we are considering buses to be equal if their bus numbers are the same. Again, other choices are possible. Virtual Function hash() The function hash() should return an appropriate hashing value for the object.
lexicographically in a case sensitive manner. See class RWCString in the Class Reference for details. Object Destruction All objects inheriting from class RWCollectable inherit a virtual destructor. Hence, the actual type of the object need not be known until run time in order to delete the object. This allows all items in a collection to be deleted without knowing their actual type. As with any C++ class, objects inheriting from RWCollectable may need a destructor to release the resources they hold.
The saveGuts(RWFile&) and saveGuts(RWvostream&) virtual functions are responsible for polymorphically saving the internal state of an RWCollectable object on either a binary file, using class RWFile, or on a virtual output stream, using class RWvostream.[26] This allows the object to be restored at some later time, or in a different location. Here are some rules for defining a saveGuts() function: 1. Save the state of your base class by calling its version of saveGuts(). 2.
Member data busNumber_ is an int, a C++ primitive. It is stored directly using either RWFile::Write(int), or RWvostream::operator<<(int). Member data driver_ is an RWCString. It does not inherit from RWCollectable. It is stored using: RWvostream& operator<<(RWvostream&, const RWCString&); Member data customers_ is an RWSet. It does inherit from RWCollectable. It is stored using: RWvostream& operator<<(RWvostream&, const RWCollectable&); Finally, member data passengers_ is a little tricky.
If the original passengers_ is non-nil, then this function restores a new RWSet off the heap and returns a pointer to it. Otherwise, it returns a nil pointer. Either way, the old contents of passengers_ are replaced. Hence, we must call delete passengers_ first. Multiply-referenced Objects A passenger name can exist in the set pointed to by customers_ and in the set pointed to by passengers_; that is, both collections contain the same string.
function: RWspace RWCollectable::nilStoreSize(); ● For other objects, use member function binaryStoreSize(). Here's a sample definition of a binaryStoreSize() function for class Bus: RWspace Bus::binaryStoreSize() const{ RWspace count = RWCollectable::binaryStoreSize() + customers_.recursiveStoreSize() + sizeof(busNumber_) + driver_.
A Note on the RWFactory Let's review what the RWDEFINITION_MACROs look like: RWDEFINE_COLLECTABLE(className, numericID) or, using a string ID: RWDEFINE_NAMED_COLLECTABLE(className, stringID) In the .
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Summary In general, you may not have to supply definitions for all of these virtual functions when designing your own class. For example, if you know that your class will never be used in sorted collections, then you do not need a definition for compareTo().
RWSet RWSet* int RWCString customers_; passengers_; busNumber_; driver_; }; class Client : public RWCollectable { RWDECLARE_COLLECTABLE(Client) Client(); Client(const char* name); Rwspace binaryStoreSize() const; int compareTo(const RWCollectable*) const; RWBoolean isEqual(const RWCollectable*) const; unsigned hash() const; void restoreGuts(RWFile&); void restoreGuts(RWvistream&); void saveGuts(RWFile&) const; void saveGuts(RWvostream&) const; private: RWCString name_; //ignore other client information fo
Bus::~Bus() { customers_.clearAndDestroy(); delete passengers_; } RWspace Bus::binaryStoreSize() const { RWspace count = RWCollectable::binaryStoreSize() + customers_.recursiveStoreSize() + sizeof(busNumber_) + driver_.
void Bus::saveGuts(RWvostream& strm) const { RWCollectable::saveGuts(strm); // Save base class strm << busNumber_; // Write primitives directly strm << driver_ << customers_; // Use Rogue Wave // provided versions strm << passengers_; // Will detect nil pointer automatically } void Bus::restoreGuts(RWFile& f) RWCollectable::restoreGuts(f); f.
Client::binaryStoreSize() const { return name_->binaryStoreSize(); } int Client::compareTo(const RWCollectable* c) const return name_.compareTo(((Client*)c)->name_); } RWBoolean Client::isEqual(const RWCollectable* c) const return name_ == *(Client*)c; } { { unsigned Client::hash() const { return name_.
{ ifstream f("bus.str"); RWpistream stream(f); Bus* newBus; stream >> newBus; // Restore it from an ASCII stream cout << "Bus number " << newBus->number() << " has been restored; its driver is " << newBus->driver() << ".\n"; cout << "It has " << newBus->customers() << " customers and " << newBus->passengers() << " passengers.\n\n"; delete newBus; } return 0; } Program Output: Bus number 1 has been restored; its driver is Kesey. It has 4 customers and 2 passengers.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 16: Internationalization ❍ Localizing Alphabets with RWCString and RWWString ❍ Localizing Messages ❍ Challenges of Localizing Currencies, Numbers, Dates, and Times ❍ RWLocale and RWZone ■ Dates ■ Time ■ Numbers ■ Currency ■ A Note on Setting Environment Variables As a developer, you belong to an international community.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Localizing Alphabets with RWCString and RWWString Localizing alphabets begins with allowing them to be represented. As mentioned in Chapter 2 (Eight-bit Clean), Tools.h++ code is "8-bit clean" to accommodate the extended character set. All of the English alphabet is described in 7 bits, leaving the eighth free for umlauts, cedillas, and other diacritical marks and special characters.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Localizing Messages To accommodate a user's language, a program must display titles, menu choices, and status messages in that language. Usually such text is stored in a message catalog or resource file, separate from program code, so it may be easily edited or replaced. Tools.h++ does not display titles or menus directly, but does return status messages when errors occur. By default, Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Challenges of Localizing Currencies, Numbers, Dates, and Times If you write applications for cultures other than your own, you will soon confront the challenges of representing currencies, numbers, dates, and times. Currencies vary in both unit value and notation. Numbers are written differently; for example, Europe and the United States use periods and commas in opposite ways.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software RWLocale and RWZone Tools.h++ addresses these problems with the abstract classes RWLocale and RWZone. If you have used RWDate, you have already used RWLocale, perhaps unknowingly. Every time you convert a date or time to or from a string, a default argument carries along an RWLocale reference.
Dates Now suppose you are American and want to format a date in German, but don't want German to be the default. Construct a German locale: RWLocale& german = *new RWLocaleSnapshot("de"); //See footnote 1 You can format the same date for both local and German readers as follows: cout << today << endl << today.asString('x', german) << endl; See the definition of x in the entry for RWLocale in the Class Reference.
Time Let us first consider the time zone problem. We can easily see that there is no simple relationship between time zones and locales. All of Switzerland shares a single time zone, including daylight-saving time (DST) rules, but has four official languages: French, German, Italian, and Romansch. On the other hand, Hawaii and New York share a common language, but occupy time zones five hours apart_sometimes six hours apart, because Hawaii does not observe DST.
Europe, and "no DST". But what about places that follow other rules, such as Argentina, where spring begins in September and summer ends in March? RWZoneSimple is table-driven; if the rule is simple enough, you can construct your own table of type RWDaylightRule, and specify it as you construct an RWZoneSimple. For example, imagine that DST begins at 2 a.m. on the last Sunday in September, and ends the first Sunday in March.
the hour and once to extract the minute. This is an expensive operation. If you expect to work often with the components of a time or date, you may be better off disassembling the time only once: RWTime now = RWTime::now(); struct tm tmbuf; now.extract(&tmbuf); const RWLocale& here = RWLocale::global(); // the default // global locale cout << here.asString(&tmbuf, 'H') << ":" << here.
balance of $10.00 in the United States, you could say: double sawbuck = 1000.; This representation has the advantages of wide range, exactness, and portability. Wide range means you can exactly represent values from $0.00 up to and beyond $10,000,000,000,000.00 - larger than any likely budget. Exactness means that, representing monetary values without fractional parts, you can perform arithmetic on them and compare the results for equality: double price = 999.; // $9.99 double penny = 1.; // $.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 17: Error Handling ❍ The Tools.h++ Error Model ❍ Internal Errors ■ Non-recoverable Internal Errors ■ Recoverable Internal Errors ❍ External Errors ❍ Exception Architecture ■ ❍ Error Handlers The Debug Version of Tools.h++ Thinking about error handling is like anticipating root canal work - ten unpredictable, and painful topic, one we prefer to avoid.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software The Tools.h++ Error Model The following table categorizes and describes errors in the Tools.h++ error model. You can use the table as a quick overview, and return to it as a reference.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Internal Errors Internal errors are due to faulty logic or coding in the program. Common types of internal errors include: ● Bounds errors; ● Inserting a null pointer into a collection; ● Attempting to use a bad date. All of these errors should be preventable. For example, you always know the permissible range of indices for an array, so you can probably avoid a bounds error.
opportunity for recovering from them. Bounds errors are non-recoverable because the cost of checking to make sure an index is in range can well exceed the cost of the array access itself. If a program does a lot of array accesses, checking every one may result in a slow program. To avoid this, the library may require you to always use a valid index. Because a minimum level of correctness is demanded, non-recoverable errors are simple in concept and relatively easy to avoid.
register RWIsvSlink* link = head_.next_; while (i--) link = link->next_; return link; } In this code, note how the function always attempts to detect a bounds error. If it finds one, it throws an instance of RWBoundsErr, a class that inherits from RWInternalErr. This instance contains an internationalized message, discussed in Chapter 16 (Localizing Messages). The RWTHROW macro is discussed in Chapter 19 (Return Type of operator>>()).
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software External Errors External errors are due to events beyond the scope of the program. As we mentioned in the introduction, any non-trivial program should be prepared to recover from an external error. In general, external errors are: ● Not easily predicted in advance; ● Encountered at more abstract levels; ● Not costly to detect; ● Detected in both the production and the debug versions of the library.
while (1) { cout << "Give a date: "; cin >> date; if (date.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Exception Architecture When an exception is thrown a throw operand is passed. The type of the throw operand determines which handlers can catch it. Tools.h++ uses the following hierarchy for throw operands: xmsg RWxmsg RWInternalErr RWBoundsErr RWExternalErr RWFileErr RWStreamErr xalloc RWxalloc As you can see, the hierarchy parallels the error model outlined in the first part of this chapter.
void myOwnErrorHandler(const RWxmsg& error){ cout << "myOwnErrorHandler(" << error.why() << ")" << endl; } int main(){ rwSetErrHandler(myOwnErrorHandler); // Comment out this line // to get the default error handler. RWTHROW( RWExternalErr(RWMessage( RWCORE_GENERIC, 12345, "Howdy!") )); cout << "Done.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software The Debug Version of Tools.h++ You can build the Tools.h++ library in a debug mode, and gain a very powerful tool for uncovering and correcting internal errors in your code. To build a debug version of the library, you must compile the entire library with the preprocessor flag RWDEBUG defined. You must compile the entire library and application with a single setting of the flag - either defined or not defined.
The case just described would trigger a failure because operator[]would find that the PRECONDITION is not met. Here's a slightly more complicated example: template void List::insert(T* obj){ RWPRECONDITION( obj!= 0 ); head = new Link(head, obj); RWPOSTCONDITION( this->contains(obj) ); } In this example, the job of the function insert() is to insert the object pointed to by the argument into a linked list of pointers to objects of type T.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Chapter 18: Advanced Topics ❍ Dynamic Link Library ■ ❍ Copy on Write ■ ❍ The DLL Example A More Comprehensive Example RWStringID ■ Duration of Identifiers ■ Programming with RWStringIDs ■ Implementation Details of RWStringID ❍ More on Storing and Retrieving RWCollectables ❍ Multiple Inheritance You'll probably come to this section on Advanced Topics after you've had some experience with Tools.h++.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Dynamic Link Library The Tools.h++ Class Library can be linked as a Microsoft Windows 3.X Dynamic Link Library (DLL). In a DLL, linking occurs at run time when the routine is actually used. This results in much smaller executables because routines are pulled in only as needed. Another advantage is that many applications can share the same code, rather than duplicating it in each application.
Tools.h++ DLL. /* * Sample Windows 3.X program, using the Tools.h++ DLL. */ #include "demowind.h" int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR , int nCmdShow) { // Create an instance of the "DemoWindow" class: DemoWindow ww(hInstance, hPrevInstance, nCmdShow); // Add some items to it: ww.insert( new RWRectangle(200, 50, 250, 100)); ww.insert( new RWEllipse(50, 50, 100, 100)); ww.insert( new RWText(20, 20, "Hello world, from Rogue Wave!")); ww.show(); ww.
This header file declares the cla ss DemoWindow. A key feature is the singly linked list called myList, which holds the list of items that have been inserted into the window. The member function DemoWindow::insert(RWDrawable*) allows new items to be inserted. Only objects that inherit from class RWDrawable, to be defined later on, may be inserted. The member function paint() may be called when it is time to repaint the window.
DemoWindow* void RWGetWindowPtr(HWND h); RWSetWindowPtr(HWND h, DemoWindow* p); #endif The demowind.cpp File Now let's look at the definitions of the public functions of class DemoWindow: the DemoWindow constructor, the DemoWindow destructor, and the member functions insert(), registerClass(), and paint(). Detailed comments follow this listing. #include #include #include #include #include #include "demowind.h" "shapes.h" /* * Construct a new window.
*/ int DemoWindow::registerClass(){ WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = ::DemoWindow_Callback; wndclass.cbClsExtra = 0; // Request extra space to store the 'this' pointer wndclass.cbWndExtra = sizeof(this); wndclass.hInstance = myInstance; wndclass.hIcon = 0; wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = GetStockObject( WHITE_BRUSH ); wndclass.lpszMenuName = NULL; wndclass.
} /* * The callback routine for this window class.
//1 //2 //3 //4 //5 //6 //7 //8 //9 //10 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. The constructor checks to see if any previous application instance has been run and, if not, registers the class. The new window is created.
//17 If the message is a WM_CREATE message, it was generated by the CreateWindow function and this is the first time through for this procedure. Use the rather baroque procedure to fetch the this pointer from the CREATESTRUCT (recall it had been 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.
virtual virtual virtual virtual void void void void restoreGuts(RWvistream& s); restoreGuts(RWFile&); saveGuts(RWvostream& s) const; saveGuts(RWFile&) const; private: RECT bounds; // The bounds of the rectangle }; An Excerpt from SHAPES.CPP 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 let's do it anyway, for the sake of completeness. #include "shapes.h" #include #include
} RWBoolean RWRectangle::isEqual(const RWCollectable* c) const { if(c->isA() != isA() ) return FALSE; //5 const RWRectangle* r = (const RWRectangle*)c; return bounds.left bounds.top bounds.right bounds.bottom == == == == r->bounds.left && r->bounds.top && r->bounds.right && r->bounds.bottom; } // Restore the RWRectangle from a virtual stream: void RWRectangle::restoreGuts(RWvistream& s) { s >> bounds.left >> bounds.top; s >> bounds.right >> bounds.
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 Chapter 15 (How to Create an RWCollectable..) for more details. //2 This is the constructor for RWRectangle that 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.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Copy on Write Classes RWCString, RWWString, and RWTValVirtualArray use a technique called copy on write to minimize copying. This technique offers the advantage of easy-to-understand value semantics with the speed of reference counted pointer implementation. Here is how the technique works.
//4 //5 The function setGlobal() sets the value of g, the global RWCString, to the same value. Now the reference count is up to four, and there is still only one copy of the string kernel. Finally, object b tries to change the value of the string. It looks at the reference count and sees that it is greater than one, implying that the string is being shared by more than one object. At this point, a clone of the string is made and modified.
RWCString color("white"); window.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software RWStringID Many Rogue Wave clients have asked for a larger range of possible class identifiers for RWCollectable classes than is available using RWClassID. We did not change the meaning of RWClassID, in order to preserve backward compatibility for existing polymorphically persisted files, but we did add a new kind of class identifier, RWStringID. An RWStringID is an identifier for RWCollectables in Tools.
identifiers, than were possible under the old restriction. To accommodate the new identifiers, a temporary RWClassID is now generated for each RWCollectable class that has an RWStringID specified by the developer. These RWClassIDs are built as needed during the run of an executable, and remain constant throughout that run. However, they may be generated in a different order on a different executable or during a different run, so they are not suitable for permanent storage.
Implementation Details of RWStringID The next few sections cover implementation details of RWStringID. If you are curious about how we manage to provide virtual functionality without adding virtual methods, or if you are interested in issues of design, efficiency, and other specifics, these sections are for you. Automatic RWClassIDs Automatic RWClassIDs are created in a systematic way from unused RWClassIDs in the range 0x9200 to 0xDAFF.
● Anywhere the self-documenting feature of RWStringID adds enough value to compensate for its slight inefficiencies. RWStringIDs are generated for all RWCollectable classes that are compiled under the current version of Tools.h++. This additional code generation has only minor impact on programs that do not use the RWStringIDs.
Click on the banner to return to the user guide home page.
Here is a more sophisticated example of a class that uses these features: #include #include #include class Tangle : public RWCollectable { public: RWDECLARE_COLLECTABLE(Tangle) Tangle* nextTangle; int someData; Tangle(Tangle* t = 0, int dat = 0){nextTangle=t; someData=dat;} virtual void saveGuts(RWFile&) const; virtual void restoreGuts(RWFile&); }; void Tangle::saveGuts(RWFile& file) const{ RWCollectable::saveGuts(file); // Save the base class file.
p = p->nextTangle; i++; } } RWDEFINE_COLLECTABLE(Tangle, 100) main(){ Tangle *head = 0, *head2 = 0; for (int i=9; i >= 0; i--) head = new Tangle(head,i); checkList(head); // Check the original list { RWFile file("junk.dat"); file << head; } RWFile file2("junk.dat"); file2 >> head2; checkList(head2); return 0; // Check the restored list } In the above example, the class Tangle implements a circularly linked list.
read object, or return the null pointer. In the last two cases, the recursion stops and the stack unwinds.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Multiple Inheritance In Chapter 15, we built a Bus class by inheriting from RWCollectable. If we had an existing Bus class at hand, we might have saved ourselves some work by using multiple inheritance to create a new class with the functionality of both Bus and RWCollectable as follows: class CollectableBus : public RWCollectable, public Bus { . . .
or make A a virtual base class. The first approach is error-prone because the user must know the details of the inheritance tree in order to make the proper cast.
Click on the banner to return to the user guide home page.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Redefinition of Virtual Functions If you subclass off an existing class and override a virtual function, make sure that the overriding function has exactly the same signature as the overridden function. This includes any const modifiers! This problem arises particularly when creating new RWCollectable classes.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Iterators Since the drafting of the ANSI/ISO Standard C++ Library, there are now two kinds of iterators available for use in Tools.h++: the traditional iterators which we describe in detail throughout this manual, and the new "Standard Library" iterators.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Return Type of operator>>() An extremely common mistake is to forget that the functions: Rwvistream& operator>>(RWvistream&, RWCollectable*&); RWFile& operator>>(RWFile&, RWCollectable*&); return their results off the heap. This can result in a memory leak like the following: main(){ RWCollectableString* string = new RWCollectableString; RWFile file("mydata.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Avoid Persisting Value Collections of Pointers It may sometimes be reasonable to collect pointers into a value-based collection in order to deal with identies instead of values. However, you should never attempt to persist them, since a collection with value semantics will simply store the values of the pointers into the stream, rather than storing the information pointed to.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Include Path When you specify an include path to the Rogue Wave header files, make sure that it does not include a final rw: # Use this: CC -I/usr/local/include -c myprog.C # not this: CC -I/usr/local/include/rw -c myprog.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Match Memory Models and Other Qualifiers When it comes time to link your program to the Rogue Wave library, make sure that all the following match: qualifiers, compilation "mode" macros (such as RWDEBUG and RW_MULTI_THREAD), the choice to use (or not use) shared libraries, and memory models.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Keep Related Methods Consistent When you design classes that will be used with the Tools.h++ library, you may be tempted to take short cuts, like providing a simplistic hash method, or operator<(), since you "know it will never be used anyhow." Decisions like this can have disastrous maintenance consequences later.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software DLL Because the DLL version of Tools.h++ uses the large memory model, any data segment that uses it must be fixed. For example, if you were to create an RWCollectable object in your data segment and insert it into a Tools.h++ collection, that collection will be holding a four byte pointer. If your data segment were to move, the pointer would no longer be valid. Hence, be sure that your .
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Use the Capabilities of the Library! By far the most common mistake is not to use the full power of the library. If you find yourself writing a little "helper" class, consider why you are doing it. Or, if what you are writing is looking a little clumsy, then maybe there's a more elegant approach. A bit of searching through the Tools.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Appendix A: Choosing A Collection ❍ ❍ Selecting a Tools.
criteria that address issues such as whether to choose a pointer or value-based collections, when to use sequential collections, and what to use for disk-based access. The second part of this appendix presents a rough comparison of how much time and memory different collections and collection families need to perform common operations such as insertions, finds, and removals.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Selecting a Tools.h++ Collection Class The decision tree diagram includes questions about the data you plan to store in your collection. By traversing the tree you can quickly see which Tools.h++ collection classes will best suit your data and programming project. How to Use the Decision Tree The questions that appear on the decision tree are brief, so that the diagram will be easy to read.
When data is accessed by comparison with self, it is also necessary to know what kind of match is used: matching may be based on equality, which directly compares one object with another, or based on identity, which compares object addresses to see if the objects are the same. 7. Is the best method of access by following linked nodes? Collections that make use of linked nodes are usually called lists.
7. Do I wish to access objects within the collection based on a numerical index? Use a sequential or sorted collection. 8. Do I need to find values based on non-numeric keys? Use a map or dictionary. 9. Would I prefer to access objects within the collection by supplying an object for comparison? Use a set, map or hash-based collection. 10. Am I willing to forego meaningful ordering, and use some extra memory in return for constant-time look-up by key? Use a hash-based collection. 11.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Time and Space Considerations This section presents a very approximate analysis and comparison of the time and space requirements for a variety of common operations on different specific collections and collection families. We've presented the information as a set of tables that lists the operation, the time cost and the space cost. Any applicable comments appear at the bottom of the table.
differ radically among various implementations. However, it is generally true that a heap allocation (or deallocation) that translates to a system call is more expensive than most of the other constant costs. "Amortized" cost is averaged over the life of the collection. Any individual action may have a higher or lower cost than the amortized value.
Remove last C t + p (recovered) Remove in middle C (assumes that you have an iterator in position) t + p (recovered) Container overhead Comments (2p+i) + N(t+p) Allocation with each insert Iterators go forward only Grows or shrinks with each item.
Remove in middle N/2 Container overhead Comments 0 (Mt+ p + 2i) + 0 No iterators (use size_t index) Allocation only when the vector grows. Expands as needed by adding space for many entries at once.
Deques operation time cost; space cost Insert at end C t (amortized) Find (average item) N/2 0 Change/replace item C 0 Remove first C t (amortized, recovered) Remove last C t (amortized, recovered) Remove in middle N/2 t (amortized, recovered) Container overhead Comments (Mt + p + i) + 0 Implemented as circular queue in an array.
(multi)map and (multi)set family operation time cost; space cost Insert logN+C 2p+t Find (average item) logN 0 Change/replace item 2(logN+C) or C 0 Remove first logN (worst case) 2p+t (recovered) Remove last logN (worst case) 2p+t (recovered) Remove in middle logN (worst case) 2p+t (recovered) Container overhead re-balance may occur at each insert or remove (3p+i) + N(2p+t) Comments Insertion happens based on sort order.
Container overhead Re-balance may occur at each insert or remove. However it will happen less often than for a balanced binary tree. Comments Insertion based on sort order. The logarithm is approximately base ORDER which is the splay of the b-tree. (In fact the base is between ORDER and 2ORDER depending on the actual loading of the b-tree) Replace for b-tree requires remove then insert. For btreedictionary the value is copied in place This depends on how fully the nodes are packed.
Comments Insertion happens based on the hashing function. Constant time costs assume that the items are well scattered in the hash slots. Worst case is linear in the number of items per slot. Replace for dictionary or map: The new value is copied in place. Otherwise, requires remove then insert. Does not automatically resize. We recommend that the number of items be between one half and double the number of slots for most uses.
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Appendix B: Typedefs and Macros Constants: #define FALSE 0 // RWBoolean value (defs.h) #define TRUE 1 // RWBoolean value (defs.h) #define rwnil 0 // nil pointer (defs.h) #define RWTOOLS 0x700 // (The actual current version number const RWoffset RWNIL = -1L; // "no offset" in an RWFile (defs.h) const size_t RW_NPOS = ~(size_t)0; // "not found" as index into array (defs.
Enumerations: enum RWSeverity {RWWARNING, RWDEFAULT, RWFATAL} The following modify the behavior of member functions or constructors for the classes involved. The value in bold font is the default.
#define #define #define #define #define #define #define #define RWDECLARE_PERSISTABLE_TEMPLATE_IO_2(TEMPLATE, ISTR, OSTR) RWDECLARE_PERSISTABLE_TEMPLATE_IO_3(TEMPLATE, ISTR, OSTR) RWDECLARE_PERSISTABLE_TEMPLATE_IO_4(TEMPLATE, ISTR, OSTR) RWDECLARE_PERSISTABLE(CLASS) RWDECLARE_PERSISTABLE_TEMPLATE(TEMPLATE) RWDECLARE_PERSISTABLE_TEMPLATE_2(TEMPLATE) RWDECLARE_PERSISTABLE_TEMPLATE_3(TEMPLATE) RWDECLARE_PERSISTABLE_TEMPLATE_4(TEMPLATE) In file epersist.h // Macro bodies removed. See section on persistence.
typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef RWHashDictionaryIterator RWIdentityDictionary RWIdentitySet RWOrdered RWOrderedIterator RWSequenceable RWSet RWSetIterator RWSlistCollectables RWSlistCollectablesIterator RWSlistCollectablesQueue RWSlistCollectablesStack DictionaryIterator; IdentityDictionary; IdentitySet; OrderedCollection; OrderedCollectionIterator; SequenceableCollection; Set; SetIterator; LinkedList; LinkedListIterator; Queue; Stack;
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Appendix C: Messages Error messages are created by the macro DECLARE_MSG in files coreerr.cpp and toolerr.cpp. Table C-1: Core messages: These are messages used by all Rogue Wave libraries. The symbols are defined in . These messages belong to category "rwcore7.0".
TOOL_BADRE "[BADRE] Attempt to use invalid regular expression" TOOL_CRABS "[CRABS] RWFactory: attempting to create abstract class with ID %hu (0x%hx)" TOOL_FLIST "[FLIST] Free list size error: expected %ld, got %ld" TOOL_ID "[ID] Unexpected class ID %hu; should be %hu" TOOL_INDEX "[INDEX] Index (%u) out of range [0->%u]" TOOL_LOCK "[LOCK] Locked object deleted" TOOL_LONGINDEX "[LONGINDEX] Long index (%lu) out of range [0->%lu]" TOOL_MAGIC "[MAGIC] Bad magic number: %ld (should be %ld)" TOOL_NE
Click on the banner to return to the user guide home page. ©Copyright 1996 Rogue Wave Software Appendix D: Bibliography Ammeraal, L. Programs and Data Structures in C, John Wiley and Sons, 1989, ISBN 0-471-91751-6. Barton, John J., and Lee R. Nackman, Scientific and Engineering C++, Addison-Wesley, 1994, ISBN 0-201-53393-6 Booch, Grady, Object-Oriented Design with Applications, Second Edition, The Benjamin Cummings Publishing Company, Inc., 1994, ISBN 0-8053-5340-2.
Khoshafian, Setrag and Razmik Abnous, Object orientation: Concepts, Languages, Databases, User Interfaces, John Wiley and Sons, 1990, ISBN 0-471-51802-6. Knuth, Donald E., The Art of Computer Programming, Volume 3, Sorting and Searching, Addison-Wesley, 1973, ISBN 0-201-03803. Lippman, Stanley B. C++ Primer, Second Edition, Addison-Wesley, 1991, ISBN 0-201-54848-8. Maguire, Steve, Writing Solid Code, Microsoft Press, 1993, ISBN 1-55615-551-4.
Click on the banner to return to the user guide home page. Licensing Statement The Rogue Wave single-user license for this product allows a single user on a single platform to link against the product library. A site license allows a specified number of users to link against the library. The fact that both the library and this documentation are easy to copy does not make it legal to do so.