boggle/lib/StanfordCPPLib/set.h
2024-09-11 17:33:32 +02:00

629 lines
15 KiB
C++
Executable File

/*
* File: set.h
* -----------
* This file exports the <code>Set</code> class, which implements a
* collection for storing a set of distinct elements.
*/
#ifndef _set_h
#define _set_h
#include <iostream>
#include "foreach.h"
#include "map.h"
#include "vector.h"
/*
* Class: Set<ValueType>
* ---------------------
* This class stores a collection of distinct elements.
*/
template <typename ValueType>
class Set {
public:
/*
* Constructor: Set
* Usage: Set<ValueType> set;
* --------------------------
* Creates an empty set of the specified element type.
*/
Set();
/*
* Destructor: ~Set
* ----------------
* Frees any heap storage associated with this set.
*/
virtual ~Set();
/*
* Method: size
* Usage: count = set.size();
* --------------------------
* Returns the number of elements in this set.
*/
int size() const;
/*
* Method: isEmpty
* Usage: if (set.isEmpty()) ...
* -----------------------------
* Returns <code>true</code> if this set contains no elements.
*/
bool isEmpty() const;
/*
* Method: add
* Usage: set.add(value);
* ----------------------
* Adds an element to this set, if it was not already there. For
* compatibility with the STL <code>set</code> class, this method
* is also exported as <code>insert</code>.
*/
void add(const ValueType & value);
void insert(const ValueType & value);
/*
* Method: remove
* Usage: set.remove(value);
* -------------------------
* Removes an element from this set. If the value was not
* contained in the set, no error is generated and the set
* remains unchanged.
*/
void remove(const ValueType & value);
/*
* Method: contains
* Usage: if (set.contains(value)) ...
* -----------------------------------
* Returns <code>true</code> if the specified value is in this set.
*/
bool contains(const ValueType & value) const;
/*
* Method: isSubsetOf
* Usage: if (set.isSubsetOf(set2)) ...
* ------------------------------------
* Implements the subset relation on sets. It returns
* <code>true</code> if every element of this set is
* contained in <code>set2</code>.
*/
bool isSubsetOf(const Set & set2) const;
/*
* Method: clear
* Usage: set.clear();
* -------------------
* Removes all elements from this set.
*/
void clear();
/*
* Operator: ==
* Usage: set1 == set2
* -------------------
* Returns <code>true</code> if <code>set1</code> and <code>set2</code>
* contain the same elements.
*/
bool operator==(const Set & set2) const;
/*
* Operator: !=
* Usage: set1 != set2
* -------------------
* Returns <code>true</code> if <code>set1</code> and <code>set2</code>
* are different.
*/
bool operator!=(const Set & set2) const;
/*
* Operator: +
* Usage: set1 + set2
* set1 + element
* ---------------------
* Returns the union of sets <code>set1</code> and <code>set2</code>, which
* is the set of elements that appear in at least one of the two sets. The
* right hand set can be replaced by an element of the value type, in which
* case the operator returns a new set formed by adding that element.
*/
Set operator+(const Set & set2) const;
Set operator+(const ValueType & element) const;
/*
* Operator: *
* Usage: set1 * set2
* ------------------
* Returns the intersection of sets <code>set1</code> and <code>set2</code>,
* which is the set of all elements that appear in both.
*/
Set operator*(const Set & set2) const;
/*
* Operator: -
* Usage: set1 - set2
* set1 - element
* ---------------------
* Returns the difference of sets <code>set1</code> and <code>set2</code>,
* which is all of the elements that appear in <code>set1</code> but
* not <code>set2</code>. The right hand set can be replaced by an
* element of the value type, in which case the operator returns a new
* set formed by removing that element.
*/
Set operator-(const Set & set2) const;
Set operator-(const ValueType & element) const;
/*
* Operator: +=
* Usage: set1 += set2;
* set1 += value;
* ---------------------
* Adds all of the elements from <code>set2</code> (or the single
* specified value) to <code>set1</code>. As a convenience, the
* <code>Set</code> package also overloads the comma operator so
* that it is possible to initialize a set like this:
*
*<pre>
* Set<int> digits;
* digits += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
*</pre>
*/
Set & operator+=(const Set & set2);
Set & operator+=(const ValueType & value);
/*
* Operator: *=
* Usage: set1 *= set2;
* --------------------
* Removes any elements from <code>set1</code> that are not present in
* <code>set2</code>.
*/
Set & operator*=(const Set & set2);
/*
* Operator: -=
* Usage: set1 -= set2;
* set1 -= value;
* ---------------------
* Removes the elements from <code>set2</code> (or the single
* specified value) from <code>set1</code>. As a convenience, the
* <code>Set</code> package also overloads the comma operator so
* that it is possible to remove multiple elements from a set
* like this:
*
*<pre>
* digits -= 0, 2, 4, 6, 8;
*</pre>
*
* which removes the values 0, 2, 4, 6, and 8 from the set
* <code>digits</code>.
*/
Set & operator-=(const Set & set2);
Set & operator-=(const ValueType & value);
/*
* Method: first
* Usage: ValueType value = set.first();
* -------------------------------------
* Returns the first value in the set in the order established by the
* <code>foreach</code> macro. If the set is empty, <code>first</code>
* generates an error.
*/
ValueType first() const;
/*
* Method: toString
* Usage: string str = set.toString();
* -----------------------------------
* Converts the set to a printable string representation.
*/
std::string toString();
/*
* Method: mapAll
* Usage: set.mapAll(fn);
* ----------------------
* Iterates through the elements of the set and calls <code>fn(value)</code>
* for each one. The values are processed in ascending order, as defined
* by the comparison function.
*/
void mapAll(void (*fn)(ValueType)) const;
void mapAll(void (*fn)(const ValueType &)) const;
template <typename FunctorType>
void mapAll(FunctorType fn) const;
/*
* Additional Set operations
* -------------------------
* In addition to the methods listed in this interface, the Set class
* supports the following operations:
*
* - Stream I/O using the << and >> operators
* - Deep copying for the copy constructor and assignment operator
* - Iteration using the range-based for statement and STL iterators
*
* The iteration forms process the Set in ascending order.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
private:
Map<ValueType,bool> map; /* Map used to store the element */
bool removeFlag; /* Flag to differentiate += and -= */
public:
/*
* Hidden features
* ---------------
* The remainder of this file consists of the code required to
* support the comma operator, deep copying, and iteration.
* Including these methods in the public interface would make
* that interface more difficult to understand for the average client.
*/
/* Extended constructors */
template <typename CompareType>
explicit Set(CompareType cmp) : map(Map<ValueType,bool>(cmp)) {
/* Empty */
}
Set & operator,(const ValueType & value) {
if (this->removeFlag) {
this->remove(value);
} else {
this->add(value);
}
return *this;
}
/*
* Iterator support
* ----------------
* The classes in the StanfordCPPLib collection implement input
* iterators so that they work symmetrically with respect to the
* corresponding STL classes.
*/
class iterator : public std::iterator<std::input_iterator_tag,ValueType> {
private:
typename Map<ValueType,bool>::iterator mapit; /* Iterator for the map */
public:
iterator() {
/* Empty */
}
iterator(typename Map<ValueType,bool>::iterator it) : mapit(it) {
/* Empty */
}
iterator(const iterator & it) {
mapit = it.mapit;
}
iterator & operator=(const iterator & it) {
if(*this != it){
mapit = it.mapit;
}
return *this;
}
iterator & operator++() {
++mapit;
return *this;
}
iterator operator++(int) {
iterator copy(*this);
operator++();
return copy;
}
bool operator==(const iterator & rhs) {
return mapit == rhs.mapit;
}
bool operator!=(const iterator & rhs) {
return !(*this == rhs);
}
ValueType operator*() {
return *mapit;
}
ValueType *operator->() {
return mapit;
}
};
iterator begin() const {
return iterator(map.begin());
}
iterator end() const {
return iterator(map.end());
}
};
extern void error(std::string msg);
template <typename ValueType>
Set<ValueType>::Set() {
/* Empty */
}
template <typename ValueType>
Set<ValueType>::~Set() {
/* Empty */
}
template <typename ValueType>
int Set<ValueType>::size() const {
return map.size();
}
template <typename ValueType>
bool Set<ValueType>::isEmpty() const {
return map.isEmpty();
}
template <typename ValueType>
void Set<ValueType>::add(const ValueType & value) {
map.put(value, true);
}
template <typename ValueType>
void Set<ValueType>::insert(const ValueType & value) {
map.put(value, true);
}
template <typename ValueType>
void Set<ValueType>::remove(const ValueType & value) {
map.remove(value);
}
template <typename ValueType>
bool Set<ValueType>::contains(const ValueType & value) const {
return map.containsKey(value);
}
template <typename ValueType>
void Set<ValueType>::clear() {
map.clear();
}
template <typename ValueType>
bool Set<ValueType>::isSubsetOf(const Set & set2) const {
iterator it = begin();
iterator end = this->end();
while (it != end) {
if (!set2.map.containsKey(*it)) return false;
++it;
}
return true;
}
/*
* Implementation notes: set operators
* -----------------------------------
* The implementations for the set operators use iteration to walk
* over the elements in one or both sets.
*/
template <typename ValueType>
bool Set<ValueType>::operator==(const Set & set2) const {
if (size() != set2.map.size()) return false;
iterator it1 = begin();
iterator it2 = set2.map.begin();
iterator end = this->end();
while (it1 != end) {
if (map.compareKeys(*it1, *it2) != 0) return false;
++it1;
++it2;
}
return true;
}
template <typename ValueType>
bool Set<ValueType>::operator!=(const Set & set2) const {
return !(*this == set2);
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator+(const Set & set2) const {
Set<ValueType> set = *this;
foreach (ValueType value in set2) {
set.add(value);
}
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator+(const ValueType & element) const {
Set<ValueType> set = *this;
set.add(element);
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator*(const Set & set2) const {
Set<ValueType> set = *this;
set.clear();
foreach (ValueType value in *this) {
if (set2.contains(value)) set.add(value);
}
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator-(const Set & set2) const {
Set<ValueType> set = *this;
foreach (ValueType value in set2) {
set.remove(value);
}
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator-(const ValueType & element) const {
Set<ValueType> set = *this;
set.remove(element);
return set;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator+=(const Set & set2) {
foreach (ValueType value in set2) {
this->add(value);
}
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator+=(const ValueType & value) {
this->add(value);
this->removeFlag = false;
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator*=(const Set & set2) {
Vector<ValueType> toRemove;
foreach (ValueType value in *this) {
if (!set2.map.containsKey(value)) toRemove.add(value);
}
foreach (ValueType value in toRemove) {
this->remove(value);
}
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator-=(const Set & set2) {
Vector<ValueType> toRemove;
foreach (ValueType value in *this) {
if (set2.map.containsKey(value)) toRemove.add(value);
}
foreach (ValueType value in toRemove) {
this->remove(value);
}
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator-=(const ValueType & value) {
this->remove(value);
this->removeFlag = true;
return *this;
}
template <typename ValueType>
ValueType Set<ValueType>::first() const {
if (isEmpty()) error("first: set is empty");
return *begin();
}
template <typename ValueType>
std::string Set<ValueType>::toString() {
ostringstream os;
os << *this;
return os.str();
}
template <typename ValueType>
void Set<ValueType>::mapAll(void (*fn)(ValueType)) const {
map.mapAll(fn);
}
template <typename ValueType>
void Set<ValueType>::mapAll(void (*fn)(const ValueType &)) const {
map.mapAll(fn);
}
template <typename ValueType>
template <typename FunctorType>
void Set<ValueType>::mapAll(FunctorType fn) const {
map.mapAll(fn);
}
template <typename ValueType>
std::ostream & operator<<(std::ostream & os, const Set<ValueType> & set) {
os << "{";
bool started = false;
foreach (ValueType value in set) {
if (started) os << ", ";
writeGenericValue(os, value, true);
started = true;
}
os << "}";
return os;
}
template <typename ValueType>
std::istream & operator>>(std::istream & is, Set<ValueType> & set) {
char ch;
is >> ch;
if (ch != '{') error("operator >>: Missing {");
set.clear();
is >> ch;
if (ch != '}') {
is.unget();
while (true) {
ValueType value;
readGenericValue(is, value);
set += value;
is >> ch;
if (ch == '}') break;
if (ch != ',') {
error(std::string("operator >>: Unexpected character ") + ch);
}
}
}
return is;
}
// hashing functions for sets; defined in hashmap.cpp
int hashCode(const Set<std::string>& s);
int hashCode(const Set<int>& s);
int hashCode(const Set<char>& s);
int hashCode(const Set<long>& s);
int hashCode(const Set<double>& s);
#endif