knotkit/lib/ullmanset.h

353 lines
7.5 KiB
C
Raw Normal View History

template<unsigned B> class ullmanset_iter;
template<unsigned B> class ullmanset_const_iter;
template<unsigned B>
class ullmanset
{
private:
friend class ullmanset_iter<B>;
friend class ullmanset_const_iter<B>;
class keypos
{
public:
unsigned key;
unsigned pos;
};
class data
{
public:
unsigned refcount;
unsigned size;
unsigned n;
keypos kp[1];
};
data *d;
void ref (data *newd) { assert (!d); d = newd; if (d) d->refcount ++; }
void unref ();
inline void delete_at_pos (unsigned p);
public:
typedef ullmanset_iter<B> iter;
typedef ullmanset_const_iter<B> const_iter;
public:
ullmanset () : d(0) { }
ullmanset (unsigned size);
ullmanset (const ullmanset &s) : d(0) { ref (s.d); }
ullmanset (copy, const ullmanset &s);
// ullmanset (const unsignedset &t);
ullmanset (const bitset &t);
ullmanset (reader &r);
~ullmanset () { unref (); }
ullmanset &operator = (const ullmanset &s) { unref (); ref (s.d); return *this; }
// ullmanset &operator = (const unsignedset &t);
ullmanset &operator = (const bitset &t);
unsigned size () const { return d ? d->size : 0; }
bool is_empty () const { assert (d); return d->n == 0; }
unsigned card () const { assert (d); return d->n; }
unsigned head () const { assert (d); assert (d->n > 0); return d->kp[0].key; }
bool operator == (const ullmanset &s);
bool operator != (const ullmanset &s) { return !operator == (s); }
void restore (unsigned old_card)
{
assert (d);
assert (d->n >= old_card);
d->n = old_card;
}
void clear () { if (d) { d->n = 0; } }
inline void push (unsigned k);
inline void operator += (unsigned k); // ??? should these be inline?
inline void operator -= (unsigned k);
void yank (unsigned k) { assert (operator % (k)); operator -= (k); }
void toggle (unsigned k)
{
if (operator % (k))
operator -= (k);
else
operator += (k);
}
ullmanset &operator |= (const ullmanset &s);
ullmanset &operator &= (const ullmanset &s);
ullmanset &operator ^= (const ullmanset &s);
bool operator % (unsigned k) const
{
assert (d);
assert ((k - B) >= 0);
assert ((k - B) < d->size);
unsigned p = d->kp[k - B].pos;
return p < d->n && d->kp[p].key == k;
}
bool operator () (unsigned k) const { return operator % (k); }
// always 0-based
unsigned nth (unsigned p) const { assert (d); assert (p < d->n); return d->kp[p].key; }
unsigned position (unsigned k) const { assert (operator % (k)); return d->kp[k - B].pos; }
void write_self (writer &w) const;
};
template<unsigned B> void
ullmanset<B>::unref ()
{
if (d && --d->refcount == 0)
{
delete [] (char *)d;
d = 0;
}
}
template<unsigned B> void
ullmanset<B>::delete_at_pos (unsigned p)
{
assert (d);
assert (p < d->n);
unsigned n = --d->n;
if (p != n)
{
unsigned ell = d->kp[n].key;
d->kp[ell - B].pos = p;
d->kp[p].key = ell;
}
}
template<unsigned B>
ullmanset<B>::ullmanset (unsigned size)
: d(0)
{
data *newd = (data *)new char[sizeof (data)
+ sizeof (keypos) * size
- sizeof (keypos)];
newd->refcount = 0;
newd->size = size;
newd->n = 0;
ref (newd);
}
template<unsigned B>
ullmanset<B>::ullmanset (copy, const ullmanset &s)
: d(0)
{
if (s.d)
{
unsigned bytes = (sizeof (data)
+ sizeof (keypos) * s.d->size
- sizeof (keypos));
data *newd = (data *)new char[bytes];
memcpy (newd, s.d, bytes);
newd->refcount = 0;
ref (newd);
}
}
template<unsigned B>
ullmanset<B>::ullmanset (reader &r)
: d(0)
{
unsigned size_ = r.read_unsigned ();
if (size_ > 0)
{
data *newd = (data *)new char[sizeof (data) + sizeof (keypos) * (size_ - 1)];
newd->refcount = 0;
newd->size = size_;
newd->n = 0;
ref (newd);
}
unsigned card_ = r.read_unsigned ();
for (unsigned i = 0; i < card_; i ++)
push (r.read_unsigned ());
}
template<unsigned B> bool
ullmanset<B>::operator == (const ullmanset &s)
{
assert (d);
assert (s.d);
if (d->n != s.d->n)
return 0;
for (iter i = *this; i; i ++)
{
if (!s(i.val ()))
return 0;
}
return 1;
}
template<unsigned B> void
ullmanset<B>::push (unsigned k)
{
assert (d);
assert (!operator % (k));
unsigned p = d->n ++;
d->kp[p].key = k;
d->kp[k - B].pos = p;
}
template<unsigned B> void
ullmanset<B>::operator += (unsigned k)
{
assert (d);
assert ((k - B) >= 0);
assert ((k - B) < d->size);
if (!operator % (k))
{
unsigned p = d->n ++;
d->kp[p].key = k;
d->kp[k - B].pos = p;
}
}
template<unsigned B> void
ullmanset<B>::operator -= (unsigned k)
{
assert (d);
assert ((k - B) >= 0);
assert ((k - B) < d->size);
if (operator % (k))
{
unsigned p = d->kp[k - B].pos;
delete_at_pos (p);
}
}
template<unsigned B> ullmanset<B> &
ullmanset<B>::operator |= (const ullmanset &s)
{
for (iter i = s; i; i ++)
operator += (i.val ());
}
template<unsigned B> ullmanset<B> &
ullmanset<B>::operator &= (const ullmanset<B> &s)
{
for (iter i = *this; i; i ++)
{
unsigned k = i.val ();
if (!s(k))
i.del ();
}
}
template<unsigned B> ullmanset<B> &
ullmanset<B>::operator ^= (const ullmanset<B> &s)
{
for (const_iter i = s; i; i ++)
{
int k = i.val ();
if (operator % (k))
operator -= (k);
else
push (k);
}
return *this;
}
template<unsigned B> void
ullmanset<B>::write_self (writer &w) const
{
write (w, size ());
write (w, card ());
for (const_iter i = *this; i; i ++)
write (w, i.val ());
}
template<unsigned B>
class ullmanset_iter
{
private:
ullmanset<B> &s;
unsigned i;
bool deleted;
public:
ullmanset_iter (ullmanset<B> &s_) : s(s_), i(0), deleted(0) { assert (s_.d); }
~ullmanset_iter () { }
void del () { assert (!deleted); assert (i < s.d->n); s.delete_at_pos (i); }
unsigned val () const { assert (!deleted); assert (i < s.d->n); return s.d->kp[i].key; }
unsigned pos () const { assert (!deleted); assert (i < s.d->n); return i; }
operator bool () const { assert (!deleted); return i < s.d->n; }
void operator ++ () { if (deleted) deleted = 0; else i ++; }
void operator ++ (int) { operator ++ (); }
};
template<unsigned B>
class ullmanset_const_iter
{
private:
const ullmanset<B> &s;
unsigned i;
public:
ullmanset_const_iter (const ullmanset<B> &s_) : s(s_), i(0) { assert (s_.d); }
~ullmanset_const_iter () { }
unsigned val () const { assert (i < s.d->n); return s.d->kp[i].key; }
unsigned pos () const { assert (i < s.d->n); return i; }
operator bool () const { return i < s.d->n; }
void operator ++ () { i ++; }
void operator ++ (int) { i ++; }
};
/* interoperating with other set types */
template<unsigned B>
set<unsigned> &operator |= (set<unsigned> &s, const ullmanset<B> &t)
{
for (ullmanset_const_iter<B> i = t; i; i ++)
s += i.val ();
return s;
}
template<unsigned B>
ullmanset<B> &operator |= (ullmanset<B> &s, const set<unsigned> &t)
{
for (set_const_iter<unsigned> i = t; i; i ++)
s += i.val ();
return s;
}
template<unsigned B>
ullmanset<B> &operator &= (ullmanset<B> &s, const set<unsigned> &t)
{
for (ullmanset_const_iter<B> i = s; i; i ++)
{
int k = i.val ();
if (!t(k))
i.del ();
}
return s;
}
template<unsigned B>
ullmanset<B> &operator ^= (ullmanset<B> &s, const set<unsigned> &t)
{
for (set_const_iter<unsigned> i = t; i; i ++)
{
int k = i.val ();
if (s % k)
s -= (k);
else
s.push (k);
}
return s;
}