// $Id: set.h,v 1.28 2004/05/31 08:29:51 elliott-oss Exp $ -*- c++ -*- // // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://ibm.com/developerworks/opensource/jikes. // Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002, 2003 International Business // Machines Corporation and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // #ifndef set_INCLUDED #define set_INCLUDED #include "platform.h" #include "lookup.h" #ifdef HAVE_JIKES_NAMESPACE namespace Jikes { // Open namespace Jikes block #endif class ShadowSymbol { public: ShadowSymbol* next; Symbol* symbol; unsigned pool_index; inline const NameSymbol* Identity() { return symbol -> Identity(); } ShadowSymbol(Symbol* symbol_) : symbol(symbol_), conflict(NULL) {} ~ShadowSymbol() { delete conflict; } Symbol* Conflict(unsigned i) { return (*conflict)[i]; } inline unsigned NumConflicts() { return conflict ? conflict -> Length() : 0; } inline void AddConflict(Symbol* conflict_symbol) { if (symbol != conflict_symbol && ! Find(conflict_symbol)) conflict -> Next() = conflict_symbol; } inline void RemoveConflict(int k) { unsigned last_index = conflict -> Length() - 1; if (k < 0) // when k is negative, it identifies the main symbol symbol = (*conflict)[last_index]; else (*conflict)[k] = (*conflict)[last_index]; conflict -> Reset(last_index); } private: Tuple* conflict; bool Find(Symbol* conflict_symbol) { if (! conflict) conflict = new Tuple(4); for (unsigned k = 0; k < conflict -> Length(); k++) if ((*conflict)[k] == conflict_symbol) return true; return false; } }; class SymbolSet { public: enum { DEFAULT_HASH_SIZE = 13, MAX_HASH_SIZE = 1021 }; SymbolSet(unsigned hash_size_ = DEFAULT_HASH_SIZE) : symbol_pool(256), main_index(0), sub_index(0) { hash_size = (hash_size_ <= 0 ? 1 : hash_size_); prime_index = -1; do { if (hash_size < primes[prime_index + 1]) break; prime_index++; } while (primes[prime_index] < MAX_HASH_SIZE); base = (ShadowSymbol**) memset(new ShadowSymbol*[hash_size], 0, hash_size * sizeof(ShadowSymbol*)); } ~SymbolSet(); // // Calculate the size of the set and return the value. // inline unsigned Size() { unsigned size = 0; for (unsigned i = 0; i < symbol_pool.Length(); i++) { ShadowSymbol* shadow = symbol_pool[i]; Symbol* symbol = shadow -> symbol; for (unsigned k = 0; symbol; symbol = (Symbol*) (k < shadow -> NumConflicts() ? shadow -> Conflict(k++) : NULL)) { size++; } } return size; } // // Empty out the set in question - i.e., remove all its elements // inline void SetEmpty() { for (unsigned i = 0; i < symbol_pool.Length(); i++) delete symbol_pool[i]; symbol_pool.Reset(); base = (ShadowSymbol**) memset(base, 0, hash_size * sizeof(ShadowSymbol*)); } // // Determine whether the set is empty. // bool IsEmpty() { return symbol_pool.Length() == 0; } // // Assignment of a set to another. // SymbolSet& operator=(const SymbolSet& rhs) { if (this != &rhs) { this -> SetEmpty(); this -> Union(rhs); } return *this; } // // Equality comparison of two sets // bool operator==(const SymbolSet&) const; // // NonEquality comparison of two sets // inline bool operator!=(const SymbolSet& rhs) const { return ! (*this == rhs); } // // Union the set in question with the set passed as argument: "set" // void Union(const SymbolSet&); // // Intersect the set in question with the set passed as argument: "set" // void Intersection(const SymbolSet&); // // Return a bolean value indicating whether or not the set in question // intersects the set passed as argument; i.e., is there at least one // element of set that is also an element of "this" set. // bool Intersects(const SymbolSet&) const; // // How many elements with this name symbol do we have? // inline unsigned NameCount(const Symbol* element) const { const NameSymbol* name_symbol = element -> Identity(); for (ShadowSymbol* shadow = base[name_symbol -> index % hash_size]; shadow; shadow = shadow -> next) { if (shadow -> Identity() == name_symbol) return shadow -> NumConflicts() + 1; } return 0; } // // Is "element" an element of the set in question ? // inline bool IsElement(const Symbol* element) const { assert(element); const NameSymbol* name_symbol = element -> Identity(); for (ShadowSymbol* shadow = base[name_symbol -> index % hash_size]; shadow; shadow = shadow -> next) { if (shadow -> Identity() == name_symbol) { Symbol* symbol = shadow -> symbol; for (unsigned k = 0; symbol; symbol = (Symbol*) (k < shadow -> NumConflicts() ? shadow -> Conflict(k++) : NULL)) { if (symbol == element) return true; } return false; } } return false; } // // Add element to the set in question if was not already there. // inline void AddElement(Symbol* element) { const NameSymbol* name_symbol = element -> Identity(); unsigned i = name_symbol -> index % hash_size; ShadowSymbol* shadow; for (shadow = base[i]; shadow; shadow = shadow -> next) { if (shadow -> Identity() == name_symbol) { shadow -> AddConflict(element); return; } } shadow = new ShadowSymbol(element); shadow -> pool_index = symbol_pool.Length(); symbol_pool.Next() = shadow; shadow -> next = base[i]; base[i] = shadow; // // If the set is "adjustable" and the number of unique elements in it // exceeds 2 times the size of the base, and we have not yet reached // the maximum allowable size for a base, reallocate a larger base // and rehash the elements. // if (symbol_pool.Length() > (hash_size << 1) && hash_size < MAX_HASH_SIZE) { Rehash(); } } void RemoveElement(const Symbol*); Symbol* FirstElement() { main_index = 0; sub_index = 0; return main_index < symbol_pool.Length() ? symbol_pool[main_index] -> symbol : (Symbol*) NULL; } Symbol* NextElement() { Symbol* symbol = NULL; if (main_index < symbol_pool.Length()) { if (sub_index < symbol_pool[main_index] -> NumConflicts()) symbol = symbol_pool[main_index] -> Conflict(sub_index++); else { main_index++; sub_index = 0; symbol = (main_index < symbol_pool.Length() ? symbol_pool[main_index] -> symbol : (Symbol*) NULL); } } return symbol; } protected: Tuple symbol_pool; unsigned main_index; unsigned sub_index; ShadowSymbol** base; unsigned hash_size; static unsigned primes[]; int prime_index; void Rehash(); }; // // Single-value Mapping from a name_symbol into a symbol with that name. // class NameSymbolMap : public SymbolSet { public: NameSymbolMap(unsigned hash_size_ = DEFAULT_HASH_SIZE) : SymbolSet(hash_size_) {} // // Is there an element with this name in the map ? // inline Symbol* Image(const NameSymbol* name_symbol) { assert(name_symbol); for (ShadowSymbol* shadow = base[name_symbol -> index % hash_size]; shadow; shadow = shadow -> next) { if (shadow -> Identity() == name_symbol) return shadow -> symbol; } return NULL; } // // Add element to the set in question if was not already there. // inline void AddElement(Symbol* element) { assert(element); ShadowSymbol* shadow = NULL; for (shadow = base[element -> Identity() -> index % hash_size]; shadow; shadow = shadow -> next) { if (shadow -> Identity() == element -> Identity()) break; } // // If an element was already mapped into that name, replace it. // Otherwise, add the new element. // if (shadow) shadow -> symbol = element; else SymbolSet::AddElement(element); } }; // // Single-value Mapping from an arbitrary key to an arbitrary value, based // on memory location (and not key contents). At the moment, the Map does // not support remapping a key to a new value. // // class Key must implement a hashing function: // unsigned HashCode(); // template class Map { public: enum { DEFAULT_HASH_SIZE = 13, MAX_HASH_SIZE = 1021 }; Map(unsigned hash_size_ = DEFAULT_HASH_SIZE); virtual ~Map() { for (unsigned i = 0; i < symbol_pool.Length(); i++) delete symbol_pool[i]; delete [] base; } // // Has key been mapped to an image, yet? If so, return the image. // inline Value* Image(Key* key) { assert(key); // Unsigned math prevents negative indices. unsigned k = key -> HashCode() % hash_size; for (Element* element = base[k]; element; element = element -> next) { if (element -> key == key) return element -> value; } return NULL; } // // Map or remap key to a given image. // void Add(Key*, Value*); private: struct Element { Element* next; Key* key; Value* value; }; Tuple symbol_pool; Element** base; unsigned hash_size; void Rehash(); void Resize(); }; // // Single-value Mapping from an arbitrary symbol into another arbitrary symbol. // class SymbolMap { public: enum { DEFAULT_HASH_SIZE = 13, MAX_HASH_SIZE = 1021 }; SymbolMap(unsigned hash_size_ = DEFAULT_HASH_SIZE); ~SymbolMap(); // // Has symbol been mapped to an image, yet? If so, return the image. // inline Symbol* Image(Symbol* symbol) { assert(symbol); unsigned k = symbol -> Identity() -> index % hash_size; for (Element* element = base[k]; element; element = element -> next) { if (element -> domain_element == symbol) return element -> image; } return NULL; } // // Map or remap symbol to a given image. // void Map(Symbol*, Symbol*); private: struct Element { Element* next; Symbol* domain_element; Symbol* image; }; Tuple symbol_pool; Element** base; unsigned hash_size; static unsigned primes[]; int prime_index; void Rehash(); }; class DefinitePair; class DefiniteAssignmentSet; // // This Bitset template class can be used to construct sets of // integers. The template takes as argument the address of an integer // variable, set_size, which indicates that the universe of the sets // is: {0..*set_size}. // class BitSet { typedef unsigned CELL; CELL* s; unsigned set_size; unsigned max_set_size; public: enum { EMPTY, UNIVERSE, cell_size = sizeof(CELL) * CHAR_BIT }; // // Produce the empty set. // void SetEmpty() { memset(s, 0, (set_size + cell_size - 1) / cell_size * sizeof(CELL)); } // // Produce the universe set. // void SetUniverse() { memset(s, ~((CELL) 0), (set_size + cell_size - 1) / cell_size * sizeof(CELL)); } // // This function takes as argument the size of a hash table, table_size. // It hashes a bitset into a location within the range <1..table_size-1>. // Note that a set's hash value changes when its bits change, so be careful // that only constant sets are used as hash keys. // unsigned Hash(int table_size) const { unsigned long hash_address = 0; for (int i = ((int) set_size - 1) / cell_size; i >= 0; i--) hash_address += s[i]; return hash_address % table_size; } // // Assignment of a bitset to another, the two sets must be the same size. // BitSet& operator=(const BitSet& rhs) { if (this != &rhs) { assert(set_size == rhs.set_size); memcpy(s, rhs.s, (set_size + cell_size - 1) / cell_size * sizeof(CELL)); } return *this; } // // Constructor of an uninitialized bitset. // #ifdef HAVE_EXPLICIT explicit #endif BitSet(unsigned set_size_) : set_size(set_size_), max_set_size(set_size_) { // // Note that some C++ compilers do not know how to allocate an // array of size 0. // int num_cells = (set_size + cell_size - 1) / cell_size; s = new CELL[num_cells ? num_cells : 1]; } // // Constructor of an initialized bitset. // BitSet(unsigned set_size_, int init) : set_size(set_size_), max_set_size(set_size_) { // // Note that some C++ compilers do not know how to allocate an // array of size 0. // int num_cells = (set_size + cell_size - 1) / cell_size; s = new CELL[num_cells ? num_cells : 1]; if (init == UNIVERSE) SetUniverse(); else SetEmpty(); } // // Constructor to clone a bitset. // BitSet(const BitSet& rhs) : set_size(rhs.set_size), max_set_size(set_size) { int num_cells = (set_size + cell_size - 1) / cell_size; s = new CELL[num_cells ? num_cells : 1]; memcpy(s, rhs.s, num_cells * sizeof(CELL)); } // // Destructor of a bitset. // ~BitSet() { delete [] s; } // // Return size of a bit set. // unsigned Size() const { return set_size; } // // Return a boolean value indicating whether or not the element i // is in the bitset in question. // bool operator[](const unsigned i) const { assert(i < set_size); return 0 != (s[i / cell_size] & (i % cell_size ? (CELL) 1 << (i % cell_size) : (CELL) 1)); } // // Insert an element i in the bitset in question. // void AddElement(const unsigned i) { assert(i < set_size); s[i / cell_size] |= (i % cell_size ? (CELL) 1 << (i % cell_size) : (CELL) 1); } // // Remove an element i from the bitset in question. // void RemoveElement(const unsigned i) { assert(i < set_size); s[i / cell_size] &= ~(i % cell_size ? (CELL) 1 << (i % cell_size) : (CELL) 1); } // // Yield a boolean result indicating whether or not two sets are // identical. // bool operator==(const BitSet& rhs) const { if (set_size != rhs.set_size) return false; int i = ((int) set_size - 1) / cell_size; if (set_size && ((s[i] ^ rhs.s[i]) & (i % cell_size ? ((CELL) 1 << (i % cell_size)) - (CELL) 1 : ~((CELL) 0))) != 0) { return false; } while (--i >= 0) { if (s[i] != rhs.s[i]) return false; } return true; } // // Yield a boolean result indicating whether or not two sets are // identical. // bool operator!=(const BitSet& rhs) const { return ! (*this == rhs); } // // Union of two bitsets. // BitSet operator+(const BitSet& rhs) const { return BitSet(*this) += rhs; } // // Union of an lvalue bitset and a rhs bitset. // BitSet& operator+=(const BitSet& rhs) { for (int i = ((int) set_size - 1) / cell_size; i >= 0; i--) s[i] |= rhs.s[i]; return *this; } // // Intersection of two bitsets. // BitSet operator*(const BitSet& rhs) const { return BitSet(*this) *= rhs; } // // Intersection of an lvalue bitset and a rhs bitset. // BitSet& operator*=(const BitSet& rhs) { for (int i = ((int) set_size - 1) / cell_size; i >= 0; i--) s[i] &= rhs.s[i]; return *this; } // // Difference of two bitsets. // BitSet operator-(const BitSet& rhs) const { return BitSet(*this) -= rhs; } // // Difference of an lvalue bitset and a rhs bitset. // BitSet& operator-=(const BitSet& rhs) { for (int i = ((int) set_size - 1) / cell_size; i >= 0; i--) s[i] &= (~ rhs.s[i]); return *this; } // // Changes the size of the set. Any new bits are given the value of init. // void Resize(const unsigned new_size, const int init = EMPTY) { if (new_size > max_set_size) { int new_cell_count = (new_size + cell_size - 1) / cell_size; int old_cell_count = (max_set_size + cell_size - 1) / cell_size; if (new_cell_count > old_cell_count && new_cell_count > 1) { // Must grow the storage for the set. CELL* tmp = s; s = new CELL[new_cell_count]; memcpy(s, tmp, old_cell_count * sizeof(CELL)); delete [] tmp; } max_set_size = new_size; } if (new_size > set_size) { // Initialize new bits. int i = (new_size - 1) / cell_size; while (i > ((int) set_size + cell_size - 1) / cell_size - 1) s[i--] = init == EMPTY ? (CELL) 0 : ~((CELL) 0); if (set_size) { if (init == EMPTY) s[i] &= (set_size % cell_size ? ((CELL) 1 << (set_size % cell_size)) - (CELL) 1 : ~((CELL) 0)); else s[i] |= (set_size % cell_size ? ~(((CELL) 1 << (set_size % cell_size)) - (CELL) 1) : (CELL) 0); } } set_size = new_size; } }; // // The DefinitePair class holds two Bitsets, one for definite assignment, // and one for definite unassignment. // class DefinitePair { public: BitSet da_set; BitSet du_set; // // Constructor to clone a definite pair. // inline DefinitePair(const DefinitePair& rhs) : da_set(rhs.da_set), du_set(rhs.du_set) {} // // Other useful constructors. // inline DefinitePair(unsigned size = 0) : da_set(size, BitSet::EMPTY), du_set(size, BitSet::UNIVERSE) {} inline DefinitePair(unsigned size, int init) : da_set(size, init), du_set(size, init) {} inline DefinitePair(const BitSet da, const BitSet du) : da_set(da), du_set(du) { assert(da.Size() == du.Size()); } // // Set to the results when true * results when false // inline DefinitePair(const DefiniteAssignmentSet& set); // // Set both bitsets. // inline void SetEmpty() { da_set.SetEmpty(); du_set.SetEmpty(); } inline void SetUniverse() { da_set.SetUniverse(); du_set.SetUniverse(); } inline void AssignAll() { da_set.SetUniverse(); du_set.SetEmpty(); } // // Resize the bitsets. // inline void Resize(const unsigned size) { da_set.Resize(size, BitSet::EMPTY); du_set.Resize(size, BitSet::UNIVERSE); } inline void Resize(const unsigned size, const int init) { da_set.Resize(size, init); du_set.Resize(size, init); } inline DefinitePair& operator=(const DefinitePair& rhs) { if (this != &rhs) { da_set = rhs.da_set; du_set = rhs.du_set; } return *this; } inline DefinitePair& operator=(const DefiniteAssignmentSet& rhs); inline unsigned Size() const { return da_set.Size(); } // // Modify element i in both bitsets. // inline void AddElement(unsigned i) { da_set.AddElement(i); du_set.AddElement(i); } inline void RemoveElement(unsigned i) { da_set.RemoveElement(i); du_set.RemoveElement(i); } // // An assignment statement adds to da, but removes from du; reclaim it when // the variable leaves scope. // inline void AssignElement(unsigned i) { da_set.AddElement(i); du_set.RemoveElement(i); } inline void ReclaimElement(unsigned i) { da_set.RemoveElement(i); du_set.AddElement(i); } // // da == da && du == du // inline bool operator==(const DefinitePair& rhs) const { return da_set == rhs.da_set && du_set == rhs.du_set; } inline bool operator!=(const DefinitePair& rhs) const { return ! (*this == rhs); } // // Union // inline DefinitePair operator+(const DefinitePair& rhs) const { return DefinitePair(*this) += rhs; } inline DefinitePair& operator+=(const DefinitePair& rhs) { da_set += rhs.da_set; du_set += rhs.du_set; return *this; } // // Intersection // inline DefinitePair operator*(const DefinitePair& rhs) const { return DefinitePair(*this) *= rhs; } inline DefinitePair& operator*=(const DefinitePair& rhs) { da_set *= rhs.da_set; du_set *= rhs.du_set; return *this; } // // Difference // inline DefinitePair operator-(const DefinitePair& rhs) const { return DefinitePair(*this) -= rhs; } inline DefinitePair& operator-=(const DefinitePair& rhs) { da_set -= rhs.da_set; du_set -= rhs.du_set; return *this; } }; class DefiniteAssignmentSet { public: DefinitePair true_pair; DefinitePair false_pair; inline DefiniteAssignmentSet(unsigned set_size) : true_pair(set_size), false_pair(set_size) {} inline DefiniteAssignmentSet(DefinitePair& true_pair_, DefinitePair& false_pair_) : true_pair(true_pair_), false_pair(false_pair_) {} inline DefiniteAssignmentSet(DefinitePair& pair) : true_pair(pair), false_pair(pair) {} inline BitSet DASet() const { return true_pair.da_set * false_pair.da_set; } inline BitSet DUSet() const { return true_pair.du_set * false_pair.du_set; } inline DefinitePair Merge() const { return DefinitePair(DASet(), DUSet()); } inline void AddElement(unsigned i) { true_pair.AddElement(i); false_pair.AddElement(i); } // // An assignment statement adds to da, but removes from du; reclaim it when // the variable leaves scope. // inline void AssignElement(unsigned i) { true_pair.AssignElement(i); false_pair.AssignElement(i); } }; template void Map::Rehash() { Resize(); for (unsigned i = 0; i < symbol_pool.Length(); i++) { Element* element = symbol_pool[i]; unsigned k = element -> key -> HashCode() % hash_size; element -> next = base[k]; base[k] = element; } } template void Map::Add(Key* key, Value* value) { assert(key); Element* element; unsigned k = key -> HashCode() % hash_size; for (element = base[k]; element; element = element -> next) { if (element -> key == key) break; } // // If this is a new element, add it to the map. // if (! element) { element = new Element(); element -> key = key; element -> next = base[k]; base[k] = element; symbol_pool.Next() = element; // // If the number of unique elements in the map exceeds 2 times // the size of the base, and we have not yet reached the maximum // allowable size for a base, reallocate a larger base and rehash // the elements. // if (symbol_pool.Length() > (hash_size << 1) && hash_size < (unsigned) MAX_HASH_SIZE) { Rehash(); } } else { assert(false && "WARNING: Attempt to remap a key, unsupported operation !!!"); } element -> value = value; } template Map::Map(unsigned hash_size_) { hash_size = (hash_size_ <= 0 ? 1 : hash_size_); base = NULL; Resize(); } template void Map::Resize() { static int prime_index = -1; static const unsigned primes[] = {DEFAULT_HASH_SIZE, 101, 401, MAX_HASH_SIZE}; while (hash_size >= primes[prime_index + 1] && hash_size < MAX_HASH_SIZE) { hash_size = primes[++prime_index]; } delete [] base; base = new Element*[hash_size]; memset(base, 0, hash_size * sizeof(Element*)); } #ifdef HAVE_JIKES_NAMESPACE } // Close namespace Jikes block #endif #endif // set_INCLUDED