/*
* bag: T -> N bag
* (C) Porkolab Zoltan, ELTE, Budapest, Hungary
* (C) 2001
*/
template <class T>
class bad_value
{
public:
bad_value( const T& t) : m_value(t) { }
T value() { return m_value; }
private:
T m_value;
};
template <class T>
class bag
{
public:
bag() : head(0) { }
~bag();
bag( const bag& rhs);
const bag& operator=( const bag& rhs);
void put( const T& t);
bool remove( const T& t);
bool remove_all( const T& t);
int mul( const T& t) const;
int operator[]( const T& t) const;
private:
struct node
{
node( const T& t, int m, node *p, node *n)
: value(t), cnt(m), prev(p), next(n) { }
~node()
{
if ( prev ) prev->next = next;
if ( next ) next->prev = prev;
}
node *clone()
{
return new node( this->value, this->cnt, 0, 0);
}
T value;
int cnt;
node* prev;
node* next;
};
node* head;
node* find( const T& t);
const node* find( const T& t) const;
void copy( const bag& rhs);
void destroy();
};
template <class T>
bag<T>::~bag()
{
destroy();
}
template <class T>
void bag<T>::destroy()
{
node *r = head;
while ( r )
{
head = r->next;
delete r;
r = head;
}
}
template <class T>
bag<T>::bag( const bag& rhs)
{
copy(rhs);
}
template <class T>
const bag<T>& bag<T>::operator=( const bag& rhs)
{
if ( this != &rhs )
{
destroy();
copy(rhs);
}
return *this;
}
template <class T>
bag<T>::node* bag<T>::find(const T& t)
{
node *r = head;
while ( r && r->value != t )
r = r->next;
return r;
}
template <class T>
const bag<T>::node* bag<T>::find(const T& t) const
{
node *r = head;
while ( r && r->value != t )
r = r->next;
return r;
}
template <class T>
void bag<T>::copy(const bag& rhs)
{
node *r = rhs.head; node *last;
if ( r )
{
last = head = r->clone(); last->prev = 0; r = r->next;
}
while ( r )
{
last->next = r->clone(); last = last->next; last->prev = 0; r = r->next;
}
}
template <class T>
int bag<T>::mul( const T& t) const
{
if( const node<T>* np = find(t) )
{
return np->cnt;
}
else
{
return 0;
}
}
template <class T>
void bag<T>::put( const T& t)
{
if( node<T>* np = find(t) )
{
++np->cnt;
}
else
{
head = new node(t,1,0,head);
if (head->next) head->next->prev = head;
}
}
template <class T>
bool bag<T>::remove( const T& t)
{
if( node<T>* np = find(t) )
{
--np->cnt;
if ( 0 == np->cnt ) delete np;
return true;
}
else
{
return false;
}
}
template <class T>
bool bag<T>::remove_all( const T& t)
{
if( node<T>* np = find(t) )
{
delete np;
return true;
}
else
{
return false;
}
}
template <class T>
int bag<T>::operator[]( const T& t) const
{
if( int i = mul(t) )
return i;
else
throw bad_value<long>(t);
}