/*ident "@(#)Set:incl/bag.h 3.1" */ /****************************************************************************** * * C++ Standard Components, Release 3.0. * * Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc. * Copyright (c) 1988, 1989, 1990 AT&T. All Rights Reserved. * * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System * Laboratories, Inc. The copyright notice above does not evidence * any actual or intended publication of such source code. * ******************************************************************************/ #ifndef BAGH #define BAGH // The following include is required so that the instantiation // files that include bag.h will get what they need from Set.h #include class ostream; // The 32 bits of a Set_or_Bag_hashval are broken into // 8 4-bit groups. Each 4-bit group indexes // into a Internal_node of 16 Bag_internal_item_ATTLCs. static const int BAG_NODE_SIZE_ATTLC = 16; static const int BAG_POSITIONS_ATTLC = 8; static const int BAG_MASK_BITS_ATTLC = 0XF; static const int BAG_INITIAL_SHIFT_ATTLC = 0; static const int BAG_SHIFT_INCR_ATTLC = 4; extern int BAG_LT_ATTLC(Set_or_Bag_hashval a,Set_or_Bag_hashval b); // Index to non-parametric classes: class Bag_bucket_non_param_ATTLC; class Bag_internal_item_ATTLC; class Bag_internal_node_ATTLC; class Bag_position_ATTLC; // The following ATTLC class declarations are // needed to disambiguate the copy-avoidance // constructors: class Bag_select_ATTLC; class Bag_reject_ATTLC; class Bag_map_ATTLC; class Bag_union_ATTLC; class Bag_inter_ATTLC; class Bag_diff_ATTLC; class Bag_xor_ATTLC; extern Pool* bag_internal_node_pool_ptr_ATTLC; struct Bag_bucket_non_param_ATTLC { Set_or_Bag_hashval hashval; }; struct Bag_internal_item_ATTLC { // An Bag_internal_item_ATTLC is a single "slot" in an // Bag_internal_node_ATTLC. It may contain: // // o An Bag_internal_node_ATTLC* // o A Bag_bucket_non_param_ATTLC* // o NULL // // Bag_bucket_non_param_ATTLC* and Bag_internal_node_ATTLC* // pointers can't be byte-aligned, so the low order // bit is free to be used as the union discriminant. // // o When the low-order bit is 1, the item // is a Bag_bucket_non_param_ATTLC* // // o When the low order bit is 0, the item // is a Bag_internal_node_ATTLC* or NULL. union { void* ext_leaf; Bag_internal_node_ATTLC* nodep; long this_is_leaf; }; inline int is_leaf_or_null() const; inline int is_node() const; inline int is_leaf() const; inline int is_null() const; inline Bag_internal_node_ATTLC* next_node() const; inline void* external_leaf() const; inline void make_leaf(void*); inline void make_node(Bag_internal_node_ATTLC*); inline void make_null(); void show(int) const; }; struct Bag_internal_node_ATTLC { // A Bag_internal_node_ATTLC has 16 Internal_slots // plus a count of how many are in use. // Each Internal_slot is directly indexed // by a 4-bit chunk. static void initialize(); Bag_internal_item_ATTLC item[BAG_NODE_SIZE_ATTLC]; int busy_count; Bag_internal_node_ATTLC(); inline ~Bag_internal_node_ATTLC(); void* operator new(size_t); inline void operator delete(void*); void show(int) const; }; struct Bag_position_ATTLC { // A Bag_position_ATTLC caches the result of the most // recent search, down to the level of the // Bucket: // // o curr_value is the Set_or_Bag_hashval that we // searched for // // o curr_pos is a stack of pointers to // Bag_internal_item_ATTLCs which remembers a // path of Bag_internal_item_ATTLCs through the // index: // // o curr_pos[0] points to the Bag_internal_item_ATTLC // selected by the first 4 bit chunk // // o curr_pos[1] points to the Bag_internal_item_ATTLC // selected by the second 4 bit chunk // // o curr_pos[curr_depth] points to the // Bag_internal_item_ATTLC which points to // a Bucket // // If Bag mutation occurs, a Bag_position_ATTLC is // canceled by setting its curr_depth to -1; // curr_value can be used subsequently to rebuild // the cur_pos stack so that iteration can resume // Bag_internal_item_ATTLC* curr_pos[BAG_POSITIONS_ATTLC]; int curr_depth; Set_or_Bag_hashval curr_value; inline Bag_position_ATTLC(); void show() const; }; // Bag_internal_item_ATTLC inlines int Bag_internal_item_ATTLC::is_leaf_or_null() const { return this_is_leaf & 01; } int Bag_internal_item_ATTLC::is_node() const { return (!is_leaf_or_null() && nodep); } int Bag_internal_item_ATTLC::is_leaf() const { return (is_leaf_or_null() && ((long)ext_leaf & ~(long)01)); } int Bag_internal_item_ATTLC::is_null() const { return !nodep; } Bag_internal_node_ATTLC* Bag_internal_item_ATTLC::next_node() const { #ifdef DEBUG_ATTLC assert(is_node()); #endif return nodep; } void* Bag_internal_item_ATTLC::external_leaf() const { #ifdef DEBUG_ATTLC assert(is_leaf()); #endif return (void*)((long)ext_leaf & ~(long)01); } void Bag_internal_item_ATTLC::make_leaf(void* p) { #ifdef DEBUG_ATTLC assert(((long)p & 01) == 0); #endif ext_leaf = (void*)((long)p | 01); } void Bag_internal_item_ATTLC::make_node(Bag_internal_node_ATTLC* cp) { #ifdef DEBUG_ATTLC assert(((long)cp & 01) == 0); #endif nodep = cp; } void Bag_internal_item_ATTLC::make_null() { nodep = 0; } // Bag_internal_node_ATTLC inlines void Bag_internal_node_ATTLC::operator delete(void* p) { bag_internal_node_pool_ptr_ATTLC->free(p); } Bag_internal_node_ATTLC::~Bag_internal_node_ATTLC() { } // Bag_position_ATTLC inlines Bag_position_ATTLC::Bag_position_ATTLC(): curr_depth(-1), curr_value(0) { } // The following are for public consumption #ifdef __GNUG__ #pragma interface #endif template class Bag_pair; template class Bag_bucket_ATTLC; template class Bag_bucketiter_ATTLC; template class Bagiter; template class Bag; // Each leaf item in the tree-structured index // points to a pair of values: // // o 'hashval' is the hash key // o 'collision_list' is a list of pairs of // (values,count) pairs such that the value // hashes to hashval // // Note that ALIGN values in the original version // become Bag_bucket_ATTLC* values in this version. // template struct Bag_pair { T value; unsigned count; int operator==(const Bag_pair& b) { return (b.value==value && b.count==count); } }; template struct Bag_bucket_ATTLC : public Bag_bucket_non_param_ATTLC { List< Bag_pair > collision_list; void show() const; }; template class Bag_bucketiter_ATTLC { friend class Bag; protected: Bag* my_bag; Bag_bucketiter_ATTLC* next_it; Bag_position_ATTLC pos; public: Bag_bucketiter_ATTLC(const Bag&); Bag_bucketiter_ATTLC(const Bag_bucketiter_ATTLC&); ~Bag_bucketiter_ATTLC(); const Bag_bucket_ATTLC* first(); const Bag_bucket_ATTLC* next(); Bag_bucketiter_ATTLC& operator=(const Bag_bucketiter_ATTLC&); void clobber() { pos.curr_depth = -1; } }; template class Bagiter : public Bag_bucketiter_ATTLC { private: int inited; Listiter< Bag_pair >* itp; public: Bagiter(const Bag& b) : Bag_bucketiter_ATTLC(b), inited(0), itp(0) {} Bagiter(const Bagiter& bi) : Bag_bucketiter_ATTLC(bi), inited(0), itp(0) {} ~Bagiter() { if (itp) delete itp; } const Bag_pair* first(); const Bag_pair* next(); int next(const Bag_pair*& t) { t = next(); return t!=0; } void reset() { inited=0; } const Bag* the_bag() const { return my_bag; } Bagiter& operator=(const Bagiter& bi) { return (Bagiter&)((Bag_bucketiter_ATTLC&)(*this) = (const Bag_bucketiter_ATTLC&)bi); } }; template class Bag { friend class Bag_bucketiter_ATTLC; friend class Bagiter; private: int sze; int sze_unique; Bag_internal_item_ATTLC contents; Bag_bucketiter_ATTLC* iter_head; Bag_position_ATTLC pos; // The following functions are only used // on empty Bags void make_setlogic(const Bag&, const Bag&, int); Bag(const Bag&, const Bag&, Bag_union_ATTLC*); Bag(const Bag&, const Bag&, Bag_inter_ATTLC*); Bag(const Bag&, const Bag&, Bag_diff_ATTLC*); Bag(const Bag&, const Bag&, Bag_xor_ATTLC*); void warn_iterators() const; public: // Constructors Bag(); Bag(const T&); Bag(const T&, const T&); Bag(const T&, const T&, const T&); Bag(const T&, const T&, const T&, const T&); Bag(const Bag&); ~Bag(); // Size unsigned int size() const { return (unsigned)sze; } unsigned int size_unique() const { return (unsigned)sze_unique; } operator const void*() const { return (size()? (this): (0)); } // Assignment Bag& operator=(const Bag&); // Relations int operator==(const Bag& b) const { return containment(b, 0); } int operator!=(const Bag& b) const { return !(*this == b); } int operator<=(const Bag& b) const { return containment(b, 1); } int operator<(const Bag& b) const { return containment(b, 2); } int operator>=(const Bag& b) const { return b <= *this; } int operator>(const Bag& b) const { return b < *this; } private: int containment(const Bag&, int) const; public: // Membership const Bag_pair* contains(const T&) const; unsigned int count(const T&) const; // Insert and Remove elements const Bag_pair* insert(const T&, int count=1); unsigned int remove(const T&, int count=1); unsigned int remove_all(const T&); unsigned int remove_all(); // Select an arbitrary element const Bag_pair* select() const; // Bag algebra Bag operator|(const Bag& b) const { return Bag(*this,b,(Bag_union_ATTLC*)0); } Bag operator-(const Bag& b) const { return Bag(*this, b,(Bag_diff_ATTLC*)0); } Bag operator&(const Bag& b) const { return Bag(*this,b,(Bag_inter_ATTLC*)0); } Bag operator^(const Bag& b) const { return Bag(*this,b,(Bag_xor_ATTLC*)0); } Bag& operator|=(const Bag&); Bag& operator-=(const Bag&); Bag& operator&=(const Bag&); Bag& operator^=(const Bag&); // Performance tuning void histogram(Map&) const; // Debugging void check() const; void show() const; // Hash function static Set_or_Bag_hashval hash(const T&); ostream& print(ostream&) const; }; template ostream& operator<<(ostream&, const Bag&); template Set_or_Bag_hashval Bag::hash(const T&) { return 0; } // Debugging code - don't want to require including // Developer can uncomment for debugging #if 0 template void Bag_bucket_ATTLC::show() const { cout << " hashval=" << hashval << "\n"; cout << " collision_list="; Listiter< Bag_pair > it(collision_list); int first=1; cout << "<"; while ( !it.at_end() ) { if ( first ) first=0; else cout << ","; Bag_pair* result; it.next(result); cout << "(" << result->count << "," << result->value << ")"; } cout << ">\n"; } template void Bag::show() const { cout << "sze = " << sze << "\n"; cout << "sze_unique = " << sze_unique << "\n"; cout << "pos =\n"; pos.show(); cout << "contents =\n"; contents.show(0); } #endif template ostream& operator<<(ostream& os,const Bag& b) { Bag_bucketiter_ATTLC bi(b); const Bag_bucket_ATTLC* bp = bi.first(); os << "{"; while ( bp ) { Listiter< Bag_pair > li(((Bag_bucket_ATTLC*)bp)->collision_list); while ( !li.at_end() ) { Bag_pair* tp; li.next(tp); os << "(" << tp->count << "," << tp->value << ")" ; } bp = bi.next(); } os << "}"; return os; } #if (defined(__edg_att_40) || defined(__GNUG__)) && !defined(__IMPLICIT_INCLUDE) #include #endif #endif