Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source incl-master const-headers set.c
Document Actions

set.c

by Michael L Powell last modified 2007-01-26 03:20

Click here to get the file

Size 36.5 kB - File type text/plain

File contents

/*ident	"@(#)Set:incl/set.c	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 _set_C_
#define _set_C_

//  T is the type parameter;
//  H is the name of the hash function
//  (Set_zero should be used if the client does
//  not have an explicit function).

template <class T>
Bucketiter_ATTLC<T>::~Bucketiter_ATTLC()
{
    if ( my_set == 0 )
	return;

    if ( this == my_set->iter_head ) {
	//  Case 1: iterator at head of chain

	my_set->iter_head = next_it;
    }
    else {
	//  Case 2: iterator in middle of chain

	register Bucketiter_ATTLC<T>* x;

	register Bucketiter_ATTLC<T>* an_it;
	for ( an_it=my_set->iter_head ;
	      (x = an_it->next_it) != this ; an_it = x);

	an_it->next_it = next_it;
    }
}

template <class T>
Bucketiter_ATTLC<T>::Bucketiter_ATTLC(const Set<T>& s):
    my_set((Set<T>*)&s),
    next_it(s.iter_head)
{ 
    ((Set<T>*)(&s))->iter_head = this;
}

template <class T>
Bucketiter_ATTLC<T>::Bucketiter_ATTLC(const Bucketiter_ATTLC<T>& bi):
    my_set(bi.my_set),
    next_it(my_set->iter_head)
{ 
    my_set->iter_head = this;
}

template <class T>
Bucketiter_ATTLC<T>&
Bucketiter_ATTLC<T>::operator=(const Bucketiter_ATTLC<T>& bi)
{
	if (this == my_set->iter_head) {
		my_set->iter_head = next_it;
	} else {
		Bucketiter_ATTLC<T>* p = my_set->iter_head;
		while (p->next_it != this) {
		    p = p->next_it;
		}
		p->next_it = next_it;
	}
	my_set = bi.my_set;
	next_it = my_set->iter_head;
	my_set->iter_head = this;
	return *this;
}

//  first() and next() are similar to Shopiro's original
//  pset iterator functions  first() and next(); they
//  walk the leaves of the tree, returning Bucket(T))*.

template <class T>
const Bucket_ATTLC<T>*
Bucketiter_ATTLC<T>::first() 
{
    register Internal_item_ATTLC* itemp;
    register Internal_node_ATTLC* nodep;
    Bucket_ATTLC<T>* bp;

    if ( my_set == 0 )
	return 0;

    pos.curr_depth = -1;

    if ( my_set->contents.is_null() )
	return 0;

    if ( my_set->contents.is_leaf() ) {
	//  'contents' is a Bucket_ATTLC<T>*

	bp = (Bucket_ATTLC<T>*)my_set->contents.external_leaf();
    }
    else {
	//  'contents' is an Internal_node*.  Search the
	//  subtree rooted at this node looking for the
	//  leftmost leaf.

	nodep = my_set->contents.next_node();

	for ( ; ; ) {
#ifdef DEBUG_ATTLC
	    assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif
	    //  Scan this Internal_node from left to right looking
	    //  for a non-null Internal_item

	    for ( itemp = &nodep->item[0] ; ; itemp++ ) {
#ifdef DEBUG_ATTLC
		assert(itemp < &nodep->item[SET_NODE_SIZE_ATTLC]);
#endif

		if ( !itemp->is_null() )
		    break;
	    }
	    pos.curr_pos[++pos.curr_depth] = itemp;

//  If this Internal_item is a leaf, the search is over;
//  otherwise, iteratively 'recurse'

	    if ( itemp->is_leaf() )
		break;

	    nodep = itemp->next_node();
	}
	bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
    }

//  bp now points to a Bucket_ATTLC<T>

    pos.curr_value = bp->hashval;
    return bp;
}

template <class T>
const Bucket_ATTLC<T>*
Bucketiter_ATTLC<T>::next()
{
    register Internal_item_ATTLC* itemp;
    register Internal_node_ATTLC* nodep;
    register Bucket_ATTLC<T>* bp;

    if ( my_set == 0 )
	return 0;

    //  Search the index for pos.curr_value.  Since
    //  pos caches the result of the last iterator
    //  access, the loop should exit almost immediately,
    //  unless set mutation has occurred since the last
    //  access.

    if (pos.curr_depth == -1 )
	itemp = &my_set->contents;
    else
	itemp = pos.curr_pos[pos.curr_depth];

    int unshift = SET_INITIAL_SHIFT_ATTLC + SET_SHIFT_INCR_ATTLC +
    		  pos.curr_depth * SET_SHIFT_INCR_ATTLC;
    register long mask = SET_MASK_BITS_ATTLC << unshift;
    nodep = 0;

    for ( ; ; mask <<= SET_SHIFT_INCR_ATTLC, unshift += SET_SHIFT_INCR_ATTLC ) {
#ifdef DEBUG_ATTLC
	assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif
	if ( itemp->is_null() )
	    break;
	else if ( itemp->is_leaf() ) {
	    //  While searching for current_value, we have found
	    //  a leaf.  This may or may not be the leaf containing
	    //  the current value, depending on whether the Bucket
	    //  containing the current value has been deleted or not.

	    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	    Set_or_Bag_hashval hval = bp->hashval;

	    if ( hval == pos.curr_value || SET_LT_ATTLC(hval,pos.curr_value) )
		//  Case 1: we either (a) found the current value or
		//  (b) passed it (it must have been deleted).
		break;
	    else {
		//  The leaf points to a Bucket containing a hash value
		//  GREATER THAN the current value, so the current value
		//  must have been deleted.  The Bucket pointed to is,
		//  by definition, the "next" Bucket, the one we are
		//  looking for.

		pos.curr_value = hval;
		return bp;
	    }
	}
	else {
	    //  Node: search subindex

	    nodep = itemp->next_node();
#ifdef DEBUG_ATTLC
	    assert(nodep);
#endif
	    pos.curr_pos[++pos.curr_depth] = itemp =
	        &nodep->item[(((unsigned long)pos.curr_value) & mask) >> unshift];
	}
    }

    //  pos.curr_pos is now up-to-date and we are ready
    //  to locate the NEXT Bucket_ATTLC<T> starting from here.

    if ( pos.curr_depth == -1 )
	//  There was only one hash Bucket; the iteration
	//  is therefore terminated.
	return 0;

    //  Find the next Bucket_ATTLC<T>

    if ( nodep == 0 )
	if ( pos.curr_depth == 0 )
	    nodep =  my_set->contents.next_node();
	else
	    nodep =  pos.curr_pos[pos.curr_depth-1]->next_node();

    for ( ; ; ) {
#ifdef DEBUG_ATTLC
	assert(&nodep->item[0] <= itemp  &&  itemp < &nodep->item[SET_NODE_SIZE_ATTLC]);
#endif
	//  Scan rightward within this node, looking for a
	//  non-null item

	while ( itemp < &nodep->item[SET_NODE_SIZE_ATTLC-1] )
	    if ( !(++itemp)->is_null() )
		goto found;

	//  Scan reached end of node without finding anything;
	//  pop up one level in order to continue the walk

	if ( pos.curr_depth-- == 0 )
	    //  The set is exhausted, so the iteration is terminated
	    return 0;

	itemp = pos.curr_pos[pos.curr_depth];
	if ( pos.curr_depth == 0 )
	    nodep = my_set->contents.next_node();
	else
	    nodep = pos.curr_pos[pos.curr_depth-1]->next_node();
    }

found:

    //  itemp now points either to the leaf we're looking
    //  for or the root of a subtree containing the leaf.

    pos.curr_pos[pos.curr_depth] = itemp;

    while ( !itemp->is_leaf() ) {
#ifdef DEBUG_ATTLC
	assert(itemp->is_node());
#endif
	nodep = itemp->next_node();

	//  Scan to right within this node

	for ( itemp = &nodep->item[0] ; ; itemp++ ) {
#ifdef DEBUG_ATTLC
	    assert(itemp < &nodep->item[SET_NODE_SIZE_ATTLC]);
#endif

	    if ( !itemp->is_null() )
		break;
	}
	pos.curr_pos[++pos.curr_depth] = itemp;
    }
    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
    pos.curr_value = bp->hashval;
    return bp;
}

template <class T>
const T*
Setiter<T>::first()
{
    //  This version has been simplified by using
    //  Bucketiter::first()

    const Bucket_ATTLC<T>* bp = ((Bucketiter_ATTLC<T>*)this)->first();

    if (  bp == 0 )
	return 0;

    delete itp;
    itp=new Listiter<T>(((Bucket_ATTLC<T>*)bp)->collision_list);
    T* result;
    itp->next(result);

    //  Cast the pointer to const so the client can't
    //  modify the element

    return (const T*)result;
}

template <class T>
const T*
Setiter<T>::next()
{
    register Internal_item_ATTLC* itemp;
    register Internal_node_ATTLC* nodep;
    register Bucket_ATTLC<T>* bp;

    //  TBD_see if this code can be simplified by using
    //  Bucketiter_ATTLC<T>::next()

    if ( my_set == 0 )
	return 0;

    //  New List-style iterator has next() as only public
    //  member function; first() is private and called
    //  internally only if this is the first call to next(),
    //  i.e., only if inited=0.

    if ( inited==0 ) {
	const T* tp = first();
	if (tp) inited=1;
	return tp;
    }

    //  Search the index for the pos.curr_value.  Since
    //  pos normally caches the results of the
    //  most recent iterator access, the loop should
    //  exit almost immediately.

    if ( pos.curr_depth == -1 )
	itemp = &my_set->contents;
    else
	itemp = pos.curr_pos[pos.curr_depth];

    int unshift = SET_INITIAL_SHIFT_ATTLC + SET_SHIFT_INCR_ATTLC +
		  pos.curr_depth * SET_SHIFT_INCR_ATTLC;
    register long mask = SET_MASK_BITS_ATTLC << unshift;
    nodep = 0;

    for ( ; ; mask <<= SET_SHIFT_INCR_ATTLC, unshift += SET_SHIFT_INCR_ATTLC ) {
#ifdef DEBUG_ATTLC
	assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif

	if ( itemp->is_null() )
	    break;
	else if ( itemp->is_leaf()) {
	    //  While searching for current_value, we have found
	    //  a leaf.  This may or may not be the leaf containing
	    //  the current value, depending on whether the Bucket
	    //  containing the current value has been deleted or not.

	    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	    Set_or_Bag_hashval hval = bp->hashval;

	    if ( hval == pos.curr_value || SET_LT_ATTLC(hval,pos.curr_value) ) {
		//  Case 1: we either (a) found the current value or
		//  (b) passed it (it must have been deleted)
		break;
	    }
	    else {
		//  The leaf we have found points to a Bucket containing
		//  a next GREATER THAN the current value (the current
		//  value must have been deleted).

		pos.curr_value = hval;
		delete itp;
		itp = new Listiter<T>(((Bucket_ATTLC<T>*)bp)->collision_list);
		T* result;
		itp->next(result);
		return (const T*)result;
	    }

	}
	else {
	    //  Node: search subindex

	    nodep = itemp->next_node();
#ifdef DEBUG_ATTLC
	    assert(nodep);
#endif
	    pos.curr_pos[++pos.curr_depth] = itemp =
		&nodep->item[(((unsigned long)pos.curr_value) & mask) >> unshift];
	}
    }

    //  curr_pos is now up-to-date and we are ready
    //  to locate the next value starting from here.

    if ( pos.curr_depth == -1) {
	//  There is only one hash Bucket; if we have not
	//  not yet returned all values on the collision list,
	//  return the next one; otherwise, the iteration
	//  is terminated
	//
	//  TBD_note:  It is possible that Set mutation occurred
	//  that (1) deleted all the elements in a List and then
	//  (2) re-created a List with the same hash value.  In
	//  this case, *itp refers to a non-existeng List.  We
	//  guard against this case by using Listiter::the_list().

	if ( !itp->the_list() || itp->at_end() )
	    return 0;
	else {
	    T* result;
	    itp->next(result);
	    return (const T*)result;
	}
    }
    if ( itemp->is_leaf() &&
	((Bucket_ATTLC<T>*)itemp->external_leaf())->hashval == pos.curr_value &&
	!itp->at_end() )
    {
	//  There are still values on the collision list in
	//  the current Bucket

	T* result;
	itp->next(result);
	return (const T*)result;

    }
    else {
	//  Find the next leaf.
	//  TBD_can we use Bucketiter_ATTLC<T>::next() here?

	if ( nodep == 0 )
	    if ( pos.curr_depth == 0 )
		nodep = my_set->contents.next_node();
	    else
		nodep = pos.curr_pos[pos.curr_depth-1]->next_node();

	for (  ; ; ) {
#ifdef DEBUG_ATTLC
	    assert(&nodep->item[0] <= itemp  &&  itemp < &nodep->item[SET_NODE_SIZE_ATTLC]);
#endif
	    //  Scan rightward within this node, looking for a
	    //  non-null item

	    while ( itemp < &nodep->item[SET_NODE_SIZE_ATTLC-1] ) {
		if ( !(++itemp)->is_null() )
		    goto found;
	    }

	    //  Scan reached end of node without finding anything;
	    //  pop up one level in order to continue the walk

	    if ( pos.curr_depth-- == 0 )
		//  The set is exhausted, so the iteration is terminated
		return 0;

	    itemp = pos.curr_pos[pos.curr_depth];
	    if ( pos.curr_depth == 0 )
		nodep = my_set->contents.next_node();
	    else
		nodep = pos.curr_pos[pos.curr_depth-1]->next_node();
	}
found:
	//  itemp now points either to the leaf we're looking
	//  for or the root of a subindex containing the leaf.

	pos.curr_pos[pos.curr_depth] = itemp;

	while ( !itemp->is_leaf() ) {
#ifdef DEBUG_ATTLC
	    assert(itemp->is_node());
#endif
	    nodep = itemp->next_node();

	    //  Scan to right within this node

	    for ( itemp = &nodep->item[0];;itemp++ ) {
#ifdef DEBUG_ATTLC
		assert(itemp < &nodep->item[SET_NODE_SIZE_ATTLC]);
#endif
		if ( !itemp->is_null() )
		    break;
	    }
	    pos.curr_pos[++pos.curr_depth] = itemp;
	}
    }
    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
    pos.curr_value = bp->hashval;
    delete itp;
    itp = new Listiter<T>(((Bucket_ATTLC<T>*)bp)->collision_list);
    T* result;
    itp->next(result);
    return (const T*)result;
}

template <class T>
Set<T>::Set(const T& t0): sze(0), iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    insert(t0);
}

template <class T>
Set<T>::Set(const T& t0, const T& t1): sze(0), iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    insert(t0);
    insert(t1);
}

template <class T>
Set<T>::Set(const T& t0, const T& t1, const T& t2):
    sze(0),
    iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    insert(t0);
    insert(t1);
    insert(t2);
}

template <class T>
Set<T>::Set(const T& t0, const T& t1, const T& t2, const T& t3):
    sze(0),
    iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    insert(t0);
    insert(t1);
    insert(t2);
    insert(t3);
}

template <class T>
Set<T>::Set(const Set<T>& a, const Set<T>& b, Set_union_ATTLC*):
    sze(0),
    iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    make_setlogic(a,b,1);
}

template <class T>
Set<T>::Set(const Set<T>& a, const Set<T>& b, Set_inter_ATTLC*):
    sze(0),
    iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    make_setlogic(a,b,0);
}

template <class T>
Set<T>::Set(const Set<T>& a, const Set<T>& b, Set_diff_ATTLC*):
    sze(0),
    iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    make_setlogic(a,b,2);
}

template <class T>
Set<T>::Set(const Set<T>& a, const Set<T>& b, Set_xor_ATTLC*):
    sze(0),
    iter_head(0)

{
    pos.curr_depth = -1;
    contents.make_null();
    make_setlogic(a,b,3);
}

template <class T>
Set<T>&
Set<T>::operator=(const Set<T>& oo)
{
    if ( this != &oo ) {
	remove_all();
	Bucketiter_ATTLC<T> bi(oo);
	const Bucket_ATTLC<T>* bp = bi.first();

	while ( bp ) {
	    Listiter<T> li(((Bucket_ATTLC<T>*)bp)->collision_list);

	    while ( !li.at_end() ) {
		T* tp;
		li.next(tp);
		insert(*tp);
	    }
	    bp = bi.next();
	}
    }
    return *this;
}

template <class T>
int
Set<T>::containment(const Set<T>& b, int comp_type) const
{
    switch (comp_type) {
    case 0: // set equality
	if (size() != b.size() )
	    return 0;
	break;
    case 1: // subset
	if (size() > b.size() )
	    return 0;
	break;
    case 2: // strict subset
	if (size() >= b.size() )
	    return 0;
    }

    Bucketiter_ATTLC<T>     a_it(*this);
    Bucketiter_ATTLC<T>     b_it(b);
    register const Bucket_ATTLC<T>* ap = a_it.first();
    register const Bucket_ATTLC<T>* bp = b_it.first();

    while ( ap && bp ) {
	if ( ap->hashval == bp->hashval ) {
	    //  Make sure ap->collision_list is a subset of
	    //  bp->collision_list

	    if ( ap->collision_list.length() > bp->collision_list.length() )
		return 0;

	    Listiter<T> lia(((Bucket_ATTLC<T>*)ap)->collision_list);
	    Listiter<T> lib(((Bucket_ATTLC<T>*)bp)->collision_list);

	    while ( !lia.at_end() ) {
		T* atp;
		lia.next(atp);
		lib.reset();
		int found=0;

		while ( !lib.at_end() ) {
		    T* btp;
		    lib.next(btp);

		    if ( *atp == *btp ) {
			found=1;
			break;
		    }
		}
		if ( !found )
		    return 0;
	    }
	    ap = a_it.next();
	    bp = b_it.next();

	}
	else if ( comp_type == 0 || SET_LT_ATTLC(ap->hashval,bp->hashval) ) {
	    //  *ap contains values that can't be in oo, since we've
	    //  already passed the point where they would be found;
	    //  return failure

	    return 0;

	}
	else {
	    //  *ap contains values that may be in a future 
	    //  Bucket_ATTLC of oo; increment b_it

	    bp = b_it.next();
	}
    }

    //  The relation is true only if a_it is exhausted (for subset
    //  comparisons) or only if both iterators are exhausted (for
    //  equality comparison)

    if (comp_type == 0)
	return ap == bp;

    return ap == 0;
}

template <class T>
const T*
Set<T>::insert(const T& value,int count)
{
    if ( count<=0 )
	return 0;

    register Internal_item_ATTLC* itemp;
    register Internal_node_ATTLC* nodep;
    Bucket_ATTLC<T>* bp;
    T* result;

    //  Hash the value

    Set_or_Bag_hashval hval = hash(value);

    //  See how much of hval matches pos.curr_value
    //  (equivalently, see how much of pos is valid.)
    //  This will determine where we start looking for the
    //  insertion point.  This is an optimization that takes
    //  advantage of the phenomenon that many operations
    //  create a Set by walking an existing index and
    //  inserting its elements into the new Set.

    long mask = SET_MASK_BITS_ATTLC << SET_INITIAL_SHIFT_ATTLC;

    int depth;
    for ( depth = -1 ; depth < pos.curr_depth ;
	  depth++, mask <<= SET_SHIFT_INCR_ATTLC )
	if ( (pos.curr_value & mask) != (hval & mask) )
	    break;

    //  If depth = -1, no bits match;
    //  if depth = 0, bits 0..3 match, etc.

    register int unshift = SET_INITIAL_SHIFT_ATTLC + SET_SHIFT_INCR_ATTLC +
    			   depth * SET_SHIFT_INCR_ATTLC;
    if ( depth == -1 )
	itemp = &contents;
    else
	itemp = pos.curr_pos[depth];

    //  Clobber all the active iterators

    warn_iterators();

    //  Find the insertion point

    pos.curr_value = hval;
    nodep = 0;

    for ( pos.curr_depth = depth ; ;
	mask <<= SET_SHIFT_INCR_ATTLC, unshift += SET_SHIFT_INCR_ATTLC ) {
#ifdef DEBUG_ATTLC
	assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif

	if ( itemp->is_null() )
	    break;
	else if ( itemp->is_leaf() ) {
	    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	    if ( bp->hashval == hval ) {
		//  The 'value' goes in this Bucket

		Listiter<T> it(((Bucket_ATTLC<T>*)bp)->collision_list);
		T* tp;

		while ( it.next(tp) ) {
		    if ( *tp == value )
			//  The value is already in the Bucket; return failure
			return 0;
		}

		//  The value is not already in the Bucket; insert it

		sze++;
		it.insert_next(value);
		it.peek_next(result);
		return result;

	    }
	    else {
		//  This Bucket is not the one where the value belongs;
		//  a subindex will have to be created containing both
		//  this Bucket and a new one created to hold 'value'

		break;
	    }
	}
	else {
	    //  Node: search subindex

	    nodep = itemp->next_node();
#ifdef DEBUG_ATTLC
	    assert(nodep);
#endif
	    pos.curr_pos[++pos.curr_depth] = itemp =
		&nodep->item[(hval & mask) >> unshift];
	}
    }

    //  ASSERT: itemp is either null or is a leaf that must
    //  be moved down into a subindex containing BOTH the
    //  existing leaf and a new leaf pointing to a new Bucket
    //  containing 'value.'  In either case, the cardinality
    //  of the Set is increased by one.

    sze++;

    if ( itemp->is_null() ) {
	//  Make this null item into a leaf pointing to a new
	//  Bucket containing 'value'

	itemp->make_leaf( new Bucket_ATTLC<T> );
	bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	bp->hashval = hval;
	// bp->collision_list.insert_next(value);
	// bp->collision_list.peek_next(result);

	Listiter<T> cit(bp->collision_list);
	cit.insert_next(value);
	cit.peek_next(result);

	// bp->collision_list.put(value); result = value;

	if ( pos.curr_depth > 0 )
	    pos.curr_pos[pos.curr_depth-1]->next_node()->busy_count++;
	else if ( pos.curr_depth == 0 )
	    contents.next_node()->busy_count++;

	return result;
    }
    else {
#ifdef DEBUG_ATTLC
	assert(itemp->is_leaf());
#endif
	//  Replace this leaf by a subindex containing both the
	//  original leaf and a new leaf pointing to a new
	//  Bucket containing 'value'

	bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	Set_or_Bag_hashval temp = bp->hashval;
	int ind1,ind2;

	for ( ; ; mask <<= SET_SHIFT_INCR_ATTLC, unshift += SET_SHIFT_INCR_ATTLC )
	{
	    itemp->make_node(nodep = new Internal_node_ATTLC);
#ifdef DEBUG_ATTLC
	    assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif
	    ind1 = int(((unsigned long)temp & mask) >> unshift);
	    ind2 = int((hval & mask) >> unshift);

	    if ( ind1 != ind2 )
		//  Serendipitous case
		break;

	    nodep->busy_count = 1;
	    itemp = &nodep->item[ind1];
	    pos.curr_pos[++pos.curr_depth] = itemp;
	}

	//  Move the existing leaf down into the subindex

	nodep->item[ind1].make_leaf(bp);

	//  Make a new leaf and Bucket for 'value'

	itemp = &nodep->item[ind2];
	itemp->make_leaf( new Bucket_ATTLC<T> );
	bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	bp->hashval = hval;
	// bp->collision_list.insert_next(value);
	// bp->collision_list.peek_next(result);

	Listiter<T> bit(bp->collision_list);
	bit.insert_next(value);
	bit.peek_next(result);

	// bp->collision_list.put(value); result = value;

	pos.curr_pos[++pos.curr_depth] = itemp;
	nodep->busy_count = 2;
	return result;
    }
}

template <class T>
unsigned
Set<T>::remove(const T& value,int count)
{
    if ( count<=0 )
	return 0;

    register Internal_item_ATTLC* itemp;
    register Internal_node_ATTLC* nodep;
    Bucket_ATTLC<T>* bp=0;

    //  Hash the value

    Set_or_Bag_hashval hval = hash(value);

    //  See how much of hval matches pos.curr_value
    //  (equivalently, see how much of pos is valid.)
    //  This will determine where we start looking for the
    //  deletion point.  This is an optimization that takes
    //  advantage of the phenomenon that many operations
    //  create a Set by walking an existing index and inserting
    //  its elements into the new Set.

    register long mask = SET_MASK_BITS_ATTLC << SET_INITIAL_SHIFT_ATTLC;

    int depth;
    for ( depth = -1 ; depth < pos.curr_depth ;
	  depth++, mask <<= SET_SHIFT_INCR_ATTLC )
	if ( (pos.curr_value & mask) != (hval & mask) )
	    break;

    //  If depth = -1, no bits match;
    //  If depth = 0, bits 0...3 match, etc.

    register int unshift = SET_INITIAL_SHIFT_ATTLC + SET_SHIFT_INCR_ATTLC +
    			   depth * SET_SHIFT_INCR_ATTLC;
    if ( depth == -1 )
	itemp = &contents;
    else
	itemp = pos.curr_pos[depth];

    nodep = 0;
    pos.curr_value = hval;
    warn_iterators();

    //  Find the leaf pointing to the Bucket containing
    //  the value to be deleted.

    for ( pos.curr_depth = depth ; ;
	  mask <<= SET_SHIFT_INCR_ATTLC, unshift += SET_SHIFT_INCR_ATTLC ) {
#ifdef DEBUG_ATTLC
	assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif

	if ( itemp->is_null() ) {
	    //  The value must have been deleted already.
	    //  Return failure.

	    return 0;
	}
	if ( itemp->is_leaf() ) {
	    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	    if ( bp->hashval == hval ) {
		//  The value may be in the Bucket pointed to by
		//  this leaf.

		break;
	    }
	    else {
		//  The leaf must have been deleted and subsequently
		//  replaced by a different Bucket (one with a different
		//  hash value).  Return failure

		return 0;
	    }
	}
	else {
	    //  Node: search subindex

	    nodep = itemp->next_node();
#ifdef DEBUG_ATTLC
	    assert(nodep);
#endif
	    pos.curr_pos[++pos.curr_depth] = itemp =
	        &nodep->item[(pos.curr_value & mask)>>unshift];
	}
    }
#ifdef DEBUG_ATTLC
    assert(bp && bp->hashval==hval);
#endif
    
    //  We found the Bucket; locate the value in the
    //  collision list and remove it

    Listiter<T> it(((Bucket_ATTLC<T>*)bp)->collision_list);
    T* tp;
    int found=0;

    while ( it.next(tp) ) {
	if ( *tp == value ) {
	    found=1;
	    it.remove_prev();
	    break;
	}
    }
    if ( !found )
	//  The value was not found; return failure
	return 0;

    //  The value was found and deleted.  We must now
    //  worry about the Bucket becoming empty.

    sze--;
    if ( bp->collision_list.length() > 0 )
	//  The collision list still has one or more elements.
	return 1;

    //  The collision list has become empty as a result of
    //  this deletion; we must delete the Bucket and fix up
    //  the index accordingly.

    if ( pos.curr_depth == -1 ) {
	//  The Set had only one element in it

#ifdef DEBUG_ATTLC
	assert(sze == 0);
#endif
	delete bp;
	itemp->make_null();
	return 1;
    }

    //  Get the parent node (if not already known)

    if ( nodep == 0 )
	if ( pos.curr_depth == 0 )
	    nodep = contents.next_node();
	else
	    nodep = pos.curr_pos[pos.curr_depth-1]->next_node();

    if ( --(nodep->busy_count) > 1 ) {
	//  Easy case: node still has more than one busy item

	delete bp;
	itemp->make_null();
	return 1;
    }

    //  Hard case: node has only one busy item; since nodes
    //  ideally contain two or more busy items, we should
    //  try to absorb the item

#ifdef DEBUG_ATTLC
    assert(nodep->busy_count == 1);
#endif

    //  Find the busy item, itp

    register Internal_item_ATTLC* itp;
    for ( itp = &nodep->item[0] ;
	  itp < &nodep->item[SET_NODE_SIZE_ATTLC] ; itp++ )
	if ( itp != itemp && !itp->is_null() )
	    break;

    if ( !itp->is_leaf() ) {
	//  Complicated case: punt (we won't try to absorb
	//  a node)

	delete bp;
	itemp->make_null();
	return 1;
    }

    //  Relatively easy case: absorb a leaf

    Bucket_ATTLC<T>* temp = (Bucket_ATTLC<T>*)itp->external_leaf();
    delete bp;

    for ( ; ; ) {
	delete nodep;

	if ( pos.curr_depth-- == 0 ) {
	    contents.make_leaf(temp);
	    break;
	}
	if ( pos.curr_depth == 0 )
	    nodep = contents.next_node();
	else
	    nodep = pos.curr_pos[pos.curr_depth-1]->next_node();

	if ( nodep->busy_count > 1 ) {
	    pos.curr_pos[pos.curr_depth]->make_leaf(temp);
	    break;
	}
#ifdef DEBUG_ATTLC
	assert(nodep->busy_count == 1);
#endif
    }
    return 1;
}

template <class T>
unsigned 
Set<T>::remove_all()
{
    unsigned result = (unsigned)sze;
    warn_iterators();
    register Internal_item_ATTLC* itemp = &contents;

    if ( itemp->is_null() ) {
#ifdef DEBUG_ATTLC
	assert(sze == 0);
#endif
	return result;
    }
    if ( itemp->is_leaf() ) {
#ifdef DEBUG_ATTLC
	assert(sze >= 1);
#endif
	Bucket_ATTLC<T>* bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	delete bp;
	itemp->make_null();
	sze = 0;
	return result;
    }
    register Internal_node_ATTLC* nodep = itemp->next_node();
    itemp = &nodep->item[0];
    pos.curr_depth = -1;

    for ( ; ; ) {
	register Internal_item_ATTLC* stopper = &nodep->item[SET_NODE_SIZE_ATTLC];
	for ( ; itemp < stopper ; /* itemp++ */ ) {
	    if ( itemp->is_node() ) {
		pos.curr_pos[++pos.curr_depth] = itemp;
		nodep = itemp->next_node();
		itemp = &nodep->item[0];
		stopper = &nodep->item[SET_NODE_SIZE_ATTLC];
	    }
	    else itemp++;
	}

	//  Unlike Set_of_p, we must destroy the buckets
	//  pointed to by this node

	for ( itemp = &nodep->item[0] ; itemp < &nodep->item[BAG_NODE_SIZE_ATTLC] ; itemp++ )
	{
	    if ( itemp->is_leaf() ) {
		Bucket_ATTLC<T>* bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
		delete bp;
		itemp->make_null();
	    }
	}
	delete nodep;

	if ( pos.curr_depth < 0 )
	    break;

	itemp = pos.curr_pos[pos.curr_depth--] + 1;
	if ( pos.curr_depth < 0 )
	    nodep = contents.next_node();
	else
	    nodep = pos.curr_pos[pos.curr_depth]->next_node();
    }
    pos.curr_depth = -1;
    contents.make_null();
    sze = 0;
    return result;
}

template <class T>
const T*
Set<T>::contains(const T& value) const
{
    register Internal_item_ATTLC* itemp;
    register Internal_node_ATTLC* nodep;
    Bucket_ATTLC<T>* bp;

    //  Hash the value

    Set_or_Bag_hashval hval = hash(value);

    //  See how much of pos is still good

    register long mask = SET_MASK_BITS_ATTLC << SET_INITIAL_SHIFT_ATTLC;

    int depth;
    for ( depth = -1 ; depth < pos.curr_depth ; depth++, mask <<= SET_SHIFT_INCR_ATTLC )
	if ( (pos.curr_value & mask) != (hval & mask) )
	    break;

    register int unshift = SET_INITIAL_SHIFT_ATTLC + SET_SHIFT_INCR_ATTLC +
    			   depth * SET_SHIFT_INCR_ATTLC;
    if ( depth == -1 )
	itemp = &(((Set<T> *)this)->contents);
    else
	itemp = pos.curr_pos[depth];

    nodep = 0;
    ((Position_ATTLC *) &((Set<T>*)this)->pos)->curr_value = hval;

    for ( ((Position_ATTLC *) &((Set<T>*)this)->pos)->curr_depth = depth ; ;
	  mask <<= SET_SHIFT_INCR_ATTLC, unshift += SET_SHIFT_INCR_ATTLC )
    {
#ifdef DEBUG_ATTLC
	assert(pos.curr_depth < SET_POSITIONS_ATTLC);
#endif
	if ( itemp->is_null() )
	    return 0;

	if ( itemp->is_leaf() ) {
	    bp = (Bucket_ATTLC<T>*)itemp->external_leaf();
	    Listiter<T> it(((Bucket_ATTLC<T>*)bp)->collision_list);
	    T* tp;

	    while ( it.next(tp) )
		if ( value == *tp )
		    return tp;

	    return 0;
	}
	else {
	    nodep = itemp->next_node();
#ifdef DEBUG_ATTLC
	    assert(nodep);
#endif
	    ((Position_ATTLC *) &((Set<T>*)this)->pos)->curr_pos[++((Position_ATTLC *) &((Set<T>*)this)->pos)->curr_depth] = itemp =
		&nodep->item[(pos.curr_value & mask) >> unshift];
	}
    }
}

template <class T>
Set<T>&
Set<T>::operator|=(const Set<T>& oo)
{
    if ( this != &oo ) {
	Bucketiter_ATTLC<T> bi(oo);
	const Bucket_ATTLC<T>* bp = bi.first();

	while ( bp ) {
	    Listiter<T> li(((Bucket_ATTLC<T>*)bp)->collision_list);
	    while ( !li.at_end() ) {
		T* tp;
		li.next(tp);
		(void)insert(*tp);
	    }
	    bp = bi.next();
	}
    }
    return *this;
}

template <class T>
Set<T>&
Set<T>::operator-=(const Set<T>& oo)
{
    if ( this != &oo ) {
	Bucketiter_ATTLC<T> bi(oo);
	const Bucket_ATTLC<T>* bp = bi.first();

	while ( bp ) {
	    Listiter<T> li(((Bucket_ATTLC<T>*)bp)->collision_list);
	    while ( !li.at_end() ) {
		T* tp;
		li.next(tp);
		(void)remove(*tp);
	    }
	    bp = bi.next();
	}
    }
    else
	remove_all();

    return *this;
}

template <class T>
Set<T>&
Set<T>::operator&=(const Set<T>& oo)
{
    if ( this != &oo ) {
	Bucketiter_ATTLC<T> bi(*this);
	const Bucket_ATTLC<T>* bp = bi.first();

	while ( bp ) {
	    Listiter<T> li(((Bucket_ATTLC<T>*)bp)->collision_list);

	    //  remove() may delete the collision list;
	    //  beware of dangling list iterator;

	    while ( li.the_list() && !li.at_end() ) {
		T* tp;
		li.next(tp);
		if ( !oo.contains(*tp))
		    remove(*tp);
	    }
	    bp = bi.next();
	}
    }
    return *this;
}

template <class T>
Set<T>&
Set<T>::operator^=(const Set<T>& b)
{
    if ( this != &b ) {
	Bucketiter_ATTLC<T> a_it(*this); 
	Bucketiter_ATTLC<T> b_it(b);
	const Bucket_ATTLC<T>* ap = a_it.first(); 
	const Bucket_ATTLC<T>* bp = b_it.first();

	while ( ap && bp ) {
	    if ( ap->hashval == bp->hashval ) {
		//  The two hash values are equal; this means the two
		//  buckets may contain equal values (which must be 
		//  weeded out).

		Listiter<T> lia(((Bucket_ATTLC<T>*)ap)->collision_list);
		Listiter<T> lib(((Bucket_ATTLC<T>*)bp)->collision_list);

		lib.reset();

		while ( !lib.at_end() ) {
		    T* atp;
		    T* btp;
		    lib.next(btp);
		    int found=0;

		    //  Guard against the case where removing from this list
		    //  causes the list to disappear

		    if ( lia.the_list() ) {
			lia.reset();
			while ( !lia.at_end() ) {
			    lia.next(atp);
			    if ( *atp == *btp ) {
				found=1;
				break;
			    }
			}
		    }
		    if ( found )
			remove(*atp);
		    else
			insert(*btp);
		}
		ap = a_it.next();
		bp = b_it.next();
	    }
	    else if ( SET_LT_ATTLC(ap->hashval,bp->hashval) ) {
		ap = a_it.next();
	    }
	    else {
		Listiter<T> lib(((Bucket_ATTLC<T>*)bp)->collision_list);

		while ( !lib.at_end() ) {
		    T* btp;
		    lib.next(btp);
		    insert(*btp);
		}
		bp = b_it.next();
	    }
	}
	while ( bp ) {
	    Listiter<T> lib(((Bucket_ATTLC<T>*)bp)->collision_list);
	    while ( !lib.at_end() ) {
		T* btp;
		lib.next(btp);
		insert(*btp);
	    }
	    bp = b_it.next();
	}
    }
    else {
	remove_all();
    }
    return *this;
}

template <class T>
void
Set<T>::warn_iterators() const
{
    register Bucketiter_ATTLC<T>* it;
    for ( it = iter_head ; it ; it = it->next_it )
	it->clobber();
}

#ifdef __GNUG__
inline void dummyxxx() {
	Map<Set_or_Bag_hashval,unsigned> m1;
}
#endif
template <class T>
void Set<T>::histogram(Map<Set_or_Bag_hashval,unsigned>& m) const {
    //  Iterate over buckets, creating a Map from
    //  bp->hashval to bp->collision_list.length().

    Bucketiter_ATTLC<T> bi(*this);
    const Bucket_ATTLC<T>* bp = bi.first();
    m = Map<Set_or_Bag_hashval,unsigned>();

    while ( bp ) {
	m[bp->hashval] = bp->collision_list.length();
	bp = bi.next();
    }
}

template <class T>
void
Set<T>::check() const
{
    Bucketiter_ATTLC<T> bi(*this);
    const Bucket_ATTLC<T>* bp = bi.first();
#ifdef DEBUG_ATTLC
    Set_or_Bag_hashval oldhashval=0;  // initialize to avoid warning
#endif
    int first=1;

    while ( bp )
    {
	//  Buckets must be stored in increasing order of
	//  hash value

	if ( first )
	    first=0;
	else {
#ifdef DEBUG_ATTLC
	    assert(SET_LT_ATTLC(oldhashval,bp->hashval));
#endif
	}
#ifdef DEBUG_ATTLC
	oldhashval = bp->hashval;
#endif

	//  Collision lists may not be empty

#ifdef DEBUG_ATTLC
	assert(bp->collision_list.length()>0);
#endif

	//  Collision lists may not contain duplicates

	Listiter<T> it1(((Bucket_ATTLC<T>*)bp)->collision_list);
	Listiter<T> it2(((Bucket_ATTLC<T>*)bp)->collision_list);

	while ( !it1.at_end() ) {
	    it2.reset();
	    while ( !it2.at_end() ) {
		T* p1;
		T* p2;
		it1.next(p1);
		it2.next(p2);
#ifdef DEBUG_ATTLC
		assert(*p1 == *p2);
#endif
	    }
	}
	bp = bi.next();
    }
}

template <class T>
Set<T>::~Set()
{
    //  TBD_study this

/*
    for ( register Bucketiter_ATTLC<T>* it = iter_head ; it ; it = it->next_it )
    {
	//  Break const

	Set<T>	// cheat = (Set<T>//)&it->my_set;
	*cheat = 0;
    }
*/
    remove_all();
}

template <class T>
Set<T>::Set(const Set<T>& oo) : sze(0), iter_head(0)
{
    pos.curr_depth = -1;
    contents.make_null();
    Bucketiter_ATTLC<T> bi(oo);
    const Bucket_ATTLC<T>* bp = bi.first();

    while ( bp ) {
	Listiter<T> li(((Bucket_ATTLC<T>*)bp)->collision_list);
	while ( !li.at_end() ) {
	    T* tp;
	    li.next(tp);
	    insert(*tp);
	}
	bp = bi.next();
    }
}

template <class T>
void
Set<T>::make_setlogic(const Set<T>& a, const Set<T>& b, int l_type)
{
    //  l_type = 0 (intersection), 1 (union), 2 (set difference), 3 (xor)

#ifdef DEBUG_ATTLC
    assert(sze == 0);
#endif
    Bucketiter_ATTLC<T>     a_it(a), b_it(b);
    register const Bucket_ATTLC<T> *ap = a_it.first(), *bp = b_it.first();
    T *atp, *btp;

    while ( ap && bp ) {
	Listiter<T> lia(((Bucket_ATTLC<T>*)ap)->collision_list);
	Listiter<T> lib(((Bucket_ATTLC<T>*)bp)->collision_list);

	if ( ap->hashval == bp->hashval ) {
	    // insert all of the necessary items from B

	    if ( l_type == 1 ) {
		while ( !lib.at_end() ) {
		    lib.next(btp);
		    insert(*btp);
		}
	    }
	    else if ( l_type == 3 ) {
		while ( !lib.at_end() ) {
		    lib.next(btp);
		    lia.reset();
		    int found=0;
		    while ( !lia.at_end() ) {
			lia.next(atp);
			if ( *atp == *btp ) {
			    found=1;
			    break;
			}
		    }
		    if ( !found )
			insert(*btp);
		}
	    }

	    // insert all the necessary items from A

	    lia.reset();
	    while ( !lia.at_end() ) {
		lia.next(atp);
		lib.reset();
		int found=0;
		while ( !lib.at_end() ) {
		    lib.next(btp);
		    if ( *atp == *btp ) {
			found=1;
			break;
		    }
		}
		if ( found ) {
		    if ( l_type == 0 )
			insert(*atp);
		}
		else {
		    if ( l_type != 0 )
			insert(*atp);
		}
	    }
	    ap = a_it.next();
	    bp = b_it.next();
	}
	else if ( SET_LT_ATTLC(ap->hashval,bp->hashval) ) {
	    // an entire bucket of values in A but not in B

	    if (l_type != 0 )
		while ( !lia.at_end() )
		{
		    lia.next(atp);
		    insert(*atp);
		}

	    ap = a_it.next();
	}
	else {
	    // an entire bucket of values in B but not in A

	    if (l_type == 1 || l_type == 3 )
		while ( !lib.at_end() ) {
		    lib.next(btp);
		    insert(*btp);
		}

	    bp = b_it.next();
	}
    }

    //  Insert whatever's left over from a and b

    if ( l_type != 0 )
	for ( ;ap;ap = a_it.next() ) {
	    Listiter<T> lia(((Bucket_ATTLC<T>*)ap)->collision_list);
	    while ( !lia.at_end() ) {
		lia.next(atp);
		insert(*atp);
	    }
	}

    if ( l_type == 1 || l_type == 3 ) {
	for ( ; bp ; bp = b_it.next() ) {
	    Listiter<T> lib(((Bucket_ATTLC<T>*)bp)->collision_list);
	    while ( !lib.at_end() ) {
		lib.next(btp);
		insert(*btp);
	    }
	}
    }
}

template <class T>
const T*
Set<T>::select() const
{
    Bucketiter_ATTLC<T> bi(*this);
    const Bucket_ATTLC<T>* bp = bi.first();

    if ( !bp )
	return 0;

    Listiter<T> li(((Bucket_ATTLC<T>*)bp)->collision_list);
    T* tp;
    li.next(tp);
    return tp;
}

#include <stream.h>

template <class T>
ostream&
Set<T>::print(ostream& os) const
{
    os << "{";
    Setiter<T> it(*this);
    const T* tp;
    int first=1;

    while( tp = it.next() ) {
	if ( first )
	    first=0;
	else
	    os << ",";

	os << *tp;
    }
    os << "}";
    return os;
}

#endif
« April 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: