CSCI 1730                    Programming Project 7                  Summer 2009

                           Hierarchy of Set Classes


This program is due by midnight on ### Thursday, July 30. ### 

In this assignment you will define and implement public set classes
BSet and StringSet< >.  Also, you will redefine your class NSet from Project
6B so as to be a subclass of BSet, but otherwise changing NSet as little as
possible.  BSet will serve as a base class for the hierarchy; it will 
contain some but not all of the features of NSet.  StringSet< > will be a
subclass of BSet.  For StringSet<T> to make sense (and to compile) the class
T will need to contain public members, specified below, which allow for a
translation between a fixed set of strings and {0, 1, 2, ..., k-1}, where
k is the number of strings in the set. 

Your code may make use of arrays and other basic C++ language features,
and most C++ Standard Library components such as those declared in <string>,
<iostream>, and <algorithm>.  However since your classes are special types
of containers you must never reference C++ Standard Library components for 
container classes (declared in <vector>, <list>, <deque>, <queue>, <stack>,
<map>, <set>, <valarray>, or <bitset>).

===============================  BSet  ======================================

Class BSet is to be a concrete class which represents an arbitrary
set of nonnegative integers.  It is more basic than NSet in that it does not
include any functions which require arithmetic operations on members. 
The required public functions for BSet, with their intended behaviors, are as
follows.  All are to be member functions of BSet if possible.

Constructors: supply a default constructor which creates an empty set,
  a copy constructor, and a constructor such that for any integer n >= 0,
  BSet( n ) creates the set of natural numbers which are  < n, i.e., the set
  {0, 1, ..., n-1}.  If n < 0 then BSet( n ) should throw an exception of
  type out_of_range.
  
Destructor: supply a destructor which deallocates any dynamically allocated
  memory.

Accessors: overload the stream insertion operator << so as to accept an object
    of type BSet and insert/display the elements of the set in increasing order,
    8 to a line.  In case the set is empty, insert/display the string
    "(empty Set)".
  Also supply functions which perform as follows for an arbitrary object
  myset of type BSet and arbitrary n >= 0.  If an argument n < 0 is passed
  then an exception of type out_of_range should be thrown.
    myset.card( ) returns the cardinality of myset.
    myset.minelt( n ) returns the smallest element of myset which is >= n,
      or -1 if there is no such element.  The default for n should be 0,
      so that myset.minelt( ) returns the same value as myset.minelt( 0 ).
    myset.maxelt( n ) returns the largest element of myset which is <= n, or
      -1 if there is no such element.  With no argument myset.maxelt( ) should
      return the largest element of myset, or -1 if there is no such element.
    myset.display( ) displays to standard output the contents of myset in the
      same format as the overloaded << operator.  NOTE: this is a change from
      Project 6.  *** Also, make display( ) virtual. ***
    Overload [ ] so that myset[ n ] returns true if n is an element of myset
      and false if not.
  
Comparators: declare overloaded operators which are intended to perform as
  follows for arbitrary objects lset and rset of type BSet.
    lset <= rset is true iff lset is a subset of rset. 
    lset >= rset is true iff lset is a superset of rset. 
    lset == rset is true iff lset is equal to rset.

Mutators: supply an overloaded stream extraction operator >>.  This should
    convert any sequence of natural numbers separated by whitespace into a
    BSet.
  Supply overloaded operators which perform as follows for arbitrary objects
  lset and rset of type BSet, and arbirary n >= 0.  If an argument n < 0 is
  passed then an exception of type out_of_range should be thrown.
    lset = rset replaces lset with a new copy of rset.
    lset |= rset replaces lset with the union of lset and rset.
    lset &= rset replaces lset with the intersection of lset and rset.
    lset -= rset replaces lset with the difference lset minus rset.
    lset ^= rset replaces lset with the symmetric difference of lset and rset.
    lset |= n adds n to lset (so no change to lset if it already contains n).
    lset -= n removes n from lset (so no change to lset if it doesn't contain
      n to begin with).
    lset ^= n toggles the membership of n in lset (nonmember to member
      and vice versa);
  
===============================  NSet  ======================================

Class NSet should behave exactly as it did for Project 6B *** except as noted
here.  One change is that the overloaded conversion operator (from Nset to NSet)
should be omitted. Instead, supply a constructor which creates an NSet from a
BSet.***  However, NSet is to be implemented as a subclass of BSet, so inherit
all functionality specified for BSet.  You can just move most of the
implementations from Project 6B to BSet.  Leave the implementations for the
overloaded versions of += and *= in NSet.  Do add the feature that if an
integer argument n < 0 is passed to += or *= then an exception of type
out_of_range is to be thrown.

===========================  StringSet< >  ==================================

Class StringSet<T> is to be a subclass of BSet which represents an arbitrary
subset of a fixed set of strings determined by the class T.  For StringSet<T>
to make sense (and to compile) the class T will need to contain public static
member functions usize( ), toa( ) and toi( ).  These are to allow for
a 1-1 translation between a fixed set of strings of cardinality usize( )
and the set of nonnegative integers < usize( ).  For purposes of discussion
call this set of strings Tsset.  Then T::usize( ) simply returns the 
cardinality of Tsset.  For any C-style (null terminated) string tstring,
T::toi( tstring ) is to throw an exception of type invalid_argument if tstring
is not a member of Tsset.  If it is a member of Tsset then T::toi( tstring )
should return a unique (to tstring) integer index i in the range 
0 <= i < T::usize( ).  Conversely, for any integer k in the range
0 <= k < T::usize( ), T::toa( k ) should return the unique string in Tsset
which has index k.  If k is not in this range then T::toa( k ) should throw
an exception of type out_of_range.

A class T with public members usize( ), toi( ) and toa( ) as described above
we'll call "suitable".  Note that the syntax for accessing static member
functions in C++ is not the same as the syntax in Java.  The "projects"
sub-page of the course web site contains a link to a sample suitable class
and tests of its public member functions, which are all static. 

For every suitable class T, the class StringSet<T> is to be a class
derived from BSet which represents arbitrary subsets of Tsset by
way of the corresponding set of indices.  This set of indices should be
represented as a BSet object and manipulated, as far as possible, using
member functions of BSet.  Only the interface should deal with strings.

The public members of Class BSet must all be adapted for the derived class
StringSet<T>.  The necessary changes in behavior are described below.

Constructor: the constructor taking an integer should just construct Tsset,
  no matter what value the argument takes.  That is, StringSet<T>( n )
  should be the full set of cardinality T.usize( ).
  
Accessors: the overloaded stream insertion operator << should  accept an object
    of type StringSet<T> and insert/display the elements of the set in
    increasing order (of index), one per line.  In case the set is empty,
    insert/display the string "(empty Set)".
  The functions which perform accessor operations for an object myset of type
  StringSet<T> and arbitrary n >= 0 should treat n as an index of an element
  of Tsset; the actual element (for instance, when an an element is returned)
  is a string.  If an argument n < 0 is passed then an exception of type
  out_of_range should be thrown.
    myset.minelt( n ) returns the element of myset which has the smallest 
      index >= n, or -1 if there is no such element.  The default for n should
      be 0, so that myset.minelt( ) returns the same value as myset.minelt( 0 ).
    myset.maxelt( n ) returns the element of myset which has the largest 
      index <= n, or -1 if there is no such element.  With no argument
      myset.maxelt( ) should return the element of myset with the largest index,
      or -1 if there is no such element.
    myset.display( ) displays to standard output the contents of myset in the
      same format as the overloaded << operator.  NOTE: this is a change from
      Project 6.
    Overload [ ] so that myset[ tstring ] returns true if tstring is an element
      of myset and false if not.  If tstring is not a member of Tsset then
      myset[ tstring ] should throw an exception of type invalid_argument.
  
Mutators: the overloaded stream extraction operator >>  should convert any
    sequence of strings separated by whitespace into a StringSet<T>, provided
    that each of the strings entered is in Tsset.  If not, an exception of type
    invalid_argument should be thrown.
  The functions which perform mutator operations for an object myset of type
  StringSet<T> by modifying the membership of some input parameter n should
  replace the integer n with a string tstring (say), and throw an exception
  of type invalid_argument if tstring is not a member of Tsset.
  
Your project submission should include header files bset.h, numset.h,
and strset.h (which has to declare and implement StingSet<T> all in the same
file, since it is templated).  The other implementation files to submit
are bset.cc, numset.cc, and a driver file proj7test.cc.  Also submit a
Makefile and a READ_ME file.  Your Makefile should allow for separate
compilation of object files bset.o, numset.o, and proj7test.o, along
with linking the object files to produce an executable file proj7test.
This executable file should include at least one test of each public member
function of your Bset and StringSet<T> classes. Your Makefile should compile
and link everything when "make" is executed in your project directory.

You may implement more functions than required.  Remember to include a test
for each public function you implement, whether or not the function is required.

Some things to note:

  *The behaviors of the public member functions should be as described,
   so that the teaching assistant and the instructor can test your Nset
   class and its functions without editing your code.  The same goes 
   for the name of the class, the names of the files submitted, and the
   names of the executable files generated by the Makefile.
   
  *Develop this program following proper methodology, starting with a 
   written plan.  Develop the code one function at a time, with readable 
   formatting, meaningful identifier names and illuminating comments.
   For each function, write the test code for it before writing the code for
   the function itself.

  *Design your class hierarchy to repeat or rewrite as little code as possible.
   In particular, all of the operations on sets which are needed for 
   StringSet<T> should be performed by member functions of BSet, aside from
   translating between strings and their indices.

  *The submission procedure and requirements common to all projects are
   described on a separate page which is linked from the course "projects"
   sub-page.  Follow the submission procedure carefully.

  *Your programs must be written in C++.
  
  *Your programs should be robust and include appropriate error checks.

  *Your project should compile on "odin", or on "albany" or one of the other
   Linux workstations in the 307 lab, using g++ for GCC 4.1.2.  Projects which
   compile properly will be scored out of 200 (if on time) based on
     (1) correctness of operation,
     (2) quality of design,
     (3) coding style and documentation of the source code, and
     (4) correctness and usefulness of the READ_ME file and the Makefile.