knotkit/lib/ullmanset.h

363 lines
7.7 KiB
C++

template<unsigned B> class ullmanset_iter;
template<unsigned B> class ullmanset_const_iter;
template<unsigned B> class ullmanset_const_stl_iter;
template<unsigned B>
class ullmanset
{
private:
friend class ullmanset_iter<B>;
friend class ullmanset_const_iter<B>;
friend class ullmanset_const_stl_iter<B>;
class keypos
{
public:
unsigned key;
unsigned pos;
};
class data : public refcounted
{
public:
unsigned size;
unsigned n;
keypos kp[1];
public:
inline void delete_at_pos (unsigned p);
};
ptr<data> d;
public:
typedef ullmanset_iter<B> iter;
typedef ullmanset_const_iter<B> const_iter;
public:
ullmanset (unsigned size);
ullmanset () : ullmanset(0) { }
ullmanset (const ullmanset &s) : d(s.d) { }
ullmanset (copy, const ullmanset &s);
ullmanset (const bitset &t);
ullmanset (unsigned size, initializer_list<unsigned> il);
ullmanset (reader &r);
~ullmanset () { }
ullmanset &operator = (const ullmanset &s) { d = s.d; return *this; }
ullmanset &operator = (const bitset &t);
// range-based for
inline ullmanset_const_stl_iter<B> begin () const;
inline ullmanset_const_stl_iter<B> end () const;
unsigned size () const { return d->size; }
bool is_empty () const { return d->n == 0; }
unsigned card () const { return d->n; }
unsigned head () const { 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->n >= old_card);
d->n = old_card;
}
void clear () { 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 ((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 (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>::data::delete_at_pos (unsigned p)
{
assert (p < n);
--n;
if (p != n)
{
unsigned ell = kp[n].key;
kp[ell - B].pos = p;
kp[p].key = ell;
}
}
template<unsigned B>
ullmanset<B>::ullmanset (unsigned size)
{
data *newd = (data *)new char[sizeof (data)
+ sizeof (keypos) * size
- sizeof (keypos)];
new (newd) data;
newd->size = size;
newd->n = 0;
d = newd;
}
template<unsigned B>
ullmanset<B>::ullmanset (unsigned size, initializer_list<unsigned> il)
: ullmanset(size)
{
for (unsigned i : il)
operator += (i);
}
template<unsigned B>
ullmanset<B>::ullmanset (copy, const ullmanset &s)
: ullmanset(s.size ())
{
d->n = s.d->n;
memcpy (&d->kp[0], &s.d->kp[0], sizeof (keypos) * d->n);
}
template<unsigned B>
ullmanset<B>::ullmanset (reader &r)
: ullmanset(r.read_unsigned ())
{
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)
{
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 (!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 ((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 ((k - B) >= 0);
assert ((k - B) < d->size);
if (operator % (k))
{
unsigned p = d->kp[k - B].pos;
d->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_const_stl_iter
{
private:
ptr<typename ullmanset<B>::data> d;
unsigned p;
public:
ullmanset_const_stl_iter (const ullmanset<B> &s, unsigned p_) : d(s.d), p(p_) { }
bool operator != (const ullmanset_const_stl_iter &end) const { return p != end.p; }
unsigned operator * () const { assert (p < d->n); return d->kp[p].key; }
ullmanset_const_stl_iter &operator ++ () { p ++; return *this; }
};
template<unsigned B> ullmanset_const_stl_iter<B>
ullmanset<B>::begin () const
{
return ullmanset_const_stl_iter<B> (*this, 0);
}
template<unsigned B> ullmanset_const_stl_iter<B>
ullmanset<B>::end () const
{
return ullmanset_const_stl_iter<B> (*this, d->n);
}
template<unsigned B>
class ullmanset_iter
{
private:
ptr<typename ullmanset<B>::data> d;
unsigned i;
bool deleted;
public:
ullmanset_iter (ullmanset<B> &s) : d(s.d), i(0), deleted(0) { }
~ullmanset_iter () { }
void del () { assert (!deleted); assert (i < d->n); d->delete_at_pos (i); }
unsigned val () const { assert (!deleted); assert (i < d->n); return d->kp[i].key; }
unsigned pos () const { assert (!deleted); assert (i < d->n); return i; }
operator bool () const { assert (!deleted); return i < d->n; }
void operator ++ () { if (deleted) deleted = 0; else i ++; }
void operator ++ (int) { operator ++ (); }
};
template<unsigned B>
class ullmanset_const_iter
{
private:
ptr<typename ullmanset<B>::data> d;
unsigned i;
public:
ullmanset_const_iter (const ullmanset<B> &s) : d(s.d), i(0) { }
~ullmanset_const_iter () { }
unsigned val () const { assert (i < d->n); return d->kp[i].key; }
unsigned pos () const { assert (i < d->n); return i; }
operator bool () const { return i < 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;
}