template class ullmanset_iter; template class ullmanset_const_iter; template class ullmanset_const_stl_iter; template class ullmanset { private: friend class ullmanset_iter; friend class ullmanset_const_iter; friend class ullmanset_const_stl_iter; 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 d; public: typedef ullmanset_iter iter; typedef ullmanset_const_iter 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 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 begin () const; inline ullmanset_const_stl_iter 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 void ullmanset::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 ullmanset::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 ullmanset::ullmanset (unsigned size, initializer_list il) : ullmanset(size) { for (unsigned i : il) operator += (i); } template ullmanset::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 ullmanset::ullmanset (reader &r) : ullmanset(r.read_unsigned ()) { unsigned card_ = r.read_unsigned (); for (unsigned i = 0; i < card_; i ++) push (r.read_unsigned ()); } template bool ullmanset::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 void ullmanset::push (unsigned k) { 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 ((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 ((k - B) >= 0); assert ((k - B) < d->size); if (operator % (k)) { unsigned p = d->kp[k - B].pos; d->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_const_stl_iter { private: ptr::data> d; unsigned p; public: ullmanset_const_stl_iter (const ullmanset &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 ullmanset_const_stl_iter ullmanset::begin () const { return ullmanset_const_stl_iter (*this, 0); } template ullmanset_const_stl_iter ullmanset::end () const { return ullmanset_const_stl_iter (*this, d->n); } template class ullmanset_iter { private: ptr::data> d; unsigned i; bool deleted; public: ullmanset_iter (ullmanset &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 class ullmanset_const_iter { private: ptr::data> d; unsigned i; public: ullmanset_const_iter (const ullmanset &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 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; }