template class ullmanset_iter; template class ullmanset_const_iter; template class ullmanset { private: friend class ullmanset_iter; friend class ullmanset_const_iter; 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 iter; typedef ullmanset_const_iter 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 void ullmanset::unref () { if (d && --d->refcount == 0) { delete [] (char *)d; d = 0; } } template void ullmanset::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 ullmanset::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 ullmanset::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 ullmanset::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 bool ullmanset::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 void ullmanset::push (unsigned k) { assert (d); assert (!operator % (k)); unsigned p = d->n ++; d->kp[p].key = k; d->kp[k - B].pos = p; } template void ullmanset::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 void ullmanset::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 ullmanset & ullmanset::operator |= (const ullmanset &s) { for (iter i = s; i; i ++) operator += (i.val ()); } template ullmanset & ullmanset::operator &= (const ullmanset &s) { for (iter i = *this; i; i ++) { unsigned k = i.val (); if (!s(k)) i.del (); } } template ullmanset & ullmanset::operator ^= (const ullmanset &s) { for (const_iter i = s; i; i ++) { int k = i.val (); if (operator % (k)) operator -= (k); else push (k); } return *this; } template void ullmanset::write_self (writer &w) const { write (w, size ()); write (w, card ()); for (const_iter i = *this; i; i ++) write (w, i.val ()); } template class ullmanset_iter { private: ullmanset &s; unsigned i; bool deleted; public: ullmanset_iter (ullmanset &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 class ullmanset_const_iter { private: const ullmanset &s; unsigned i; public: ullmanset_const_iter (const ullmanset &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 set &operator |= (set &s, const ullmanset &t) { for (ullmanset_const_iter i = t; i; i ++) s += i.val (); return s; } template ullmanset &operator |= (ullmanset &s, const set &t) { for (set_const_iter i = t; i; i ++) s += i.val (); return s; } template ullmanset &operator &= (ullmanset &s, const set &t) { for (ullmanset_const_iter i = s; i; i ++) { int k = i.val (); if (!t(k)) i.del (); } return s; } template ullmanset &operator ^= (ullmanset &s, const set &t) { for (set_const_iter i = t; i; i ++) { int k = i.val (); if (s % k) s -= (k); else s.push (k); } return s; }