1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
4  *   info_at_agrum_dot_org
5  *
6  *  This library is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License
17  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Implementation of the Set.
25  *
26  * @author Christophe GONZALES(_at_AMU) and Pierre-Henri WUILLEMIN(_at_LIP6)
27  */
28 
29 #include <agrum/tools/core/set.h>
30 
31 namespace gum {
32 
33   // ===========================================================================
34   // ===                          SAFE SET ITERATORS                         ===
35   // ===========================================================================
36 
37   // default constructor: the iterator points toward nothing
38   template < typename Key >
SetIteratorSafe()39   INLINE SetIteratorSafe< Key >::SetIteratorSafe() {
40     GUM_CONSTRUCTOR(SetIteratorSafe);
41   }
42 
43   // creates an iterator for a given set
44   template < typename Key >
45   template < typename Alloc >
SetIteratorSafe(const Set<Key,Alloc> & set,Position pos)46   INLINE SetIteratorSafe< Key >::SetIteratorSafe(const Set< Key, Alloc >& set, Position pos) :
47       _ht_iter_{pos == SetIteratorSafe< Key >::END ? set._inside_.cendSafe()
48                                                    : set._inside_.cbeginSafe()} {
49     GUM_CONSTRUCTOR(SetIteratorSafe);
50   }
51 
52   // copy constructor
53   template < typename Key >
SetIteratorSafe(const SetIteratorSafe<Key> & iter)54   INLINE SetIteratorSafe< Key >::SetIteratorSafe(const SetIteratorSafe< Key >& iter) :
55       _ht_iter_{iter._ht_iter_} {
56     GUM_CONS_CPY(SetIteratorSafe);
57   }
58 
59   // copy constructor
60   template < typename Key >
SetIteratorSafe(const SetIterator<Key> & iter)61   INLINE SetIteratorSafe< Key >::SetIteratorSafe(const SetIterator< Key >& iter) :
62       _ht_iter_{iter._ht_iter_} {
63     GUM_CONS_CPY(SetIteratorSafe);
64   }
65 
66   // move constructor
67   template < typename Key >
SetIteratorSafe(SetIteratorSafe<Key> && from)68   INLINE SetIteratorSafe< Key >::SetIteratorSafe(SetIteratorSafe< Key >&& from) :
69       _ht_iter_{std::move(from._ht_iter_)} {
70     GUM_CONS_MOV(SetIteratorSafe);
71   }
72 
73   // destructor
74   template < typename Key >
~SetIteratorSafe()75   INLINE SetIteratorSafe< Key >::~SetIteratorSafe() noexcept {
76     GUM_DESTRUCTOR(SetIteratorSafe);
77   }
78 
79   // assignment operator
80   template < typename Key >
81   INLINE SetIteratorSafe< Key >&
82      SetIteratorSafe< Key >::operator=(const SetIteratorSafe< Key >& from) {
83     _ht_iter_ = from._ht_iter_;
84     return *this;
85   }
86 
87   // assignment operator
88   template < typename Key >
89   INLINE SetIteratorSafe< Key >& SetIteratorSafe< Key >::operator=(const SetIterator< Key >& from) {
90     _ht_iter_ = from._ht_iter_;
91     return *this;
92   }
93 
94   // move operator
95   template < typename Key >
96   INLINE SetIteratorSafe< Key >&
97      SetIteratorSafe< Key >::operator=(SetIteratorSafe< Key >&& from) noexcept {
98     _ht_iter_ = std::move(from._ht_iter_);
99     return *this;
100   }
101 
102   // increments the iterator
103   template < typename Key >
104   INLINE SetIteratorSafe< Key >& SetIteratorSafe< Key >::operator++() noexcept {
105     // note that, if the hashtable's iterator points toward nothing, the
106     // hashtable's iterator incrementation will do nothing. In particular, it
107     // will not segfault.
108     ++_ht_iter_;
109     return *this;
110   }
111 
112   // makes the iterator point to i elements further in the set
113   template < typename Key >
114   INLINE SetIteratorSafe< Key >& SetIteratorSafe< Key >::operator+=(Size nb) noexcept {
115     _ht_iter_ += nb;
116     return *this;
117   }
118 
119   // returns a new iterator
120   template < typename Key >
121   INLINE SetIteratorSafe< Key > SetIteratorSafe< Key >::operator+(Size nb) const {
122     return SetIteratorSafe< Key >{*this} += nb;
123   }
124 
125   // indicates whether two iterators point to different elements or sets
126   template < typename Key >
127   INLINE bool
128      SetIteratorSafe< Key >::operator!=(const SetIteratorSafe< Key >& from) const noexcept {
129     return _ht_iter_ != from._ht_iter_;
130   }
131 
132   // indicates whether two iterators point toward the same element of a same
133   // set
134   template < typename Key >
135   INLINE bool
136      SetIteratorSafe< Key >::operator==(const SetIteratorSafe< Key >& from) const noexcept {
137     return _ht_iter_ == from._ht_iter_;
138   }
139 
140   // returns the element pointed to by the iterator
141   template < typename Key >
142   INLINE const Key& SetIteratorSafe< Key >::operator*() const {
143     // note that, if the hashtable's iterator points toward nothing, it will
144     // raise an UndefinedIteratorValue exception
145     return _ht_iter_.key();
146   }
147 
148   // returns aointer to the element pointed to by the iterator
149   template < typename Key >
150   INLINE const Key* SetIteratorSafe< Key >::operator->() const {
151     // note that, if the hashtable's iterator points toward nothing, it will
152     // raise an UndefinedIteratorValue exception
153     return &(_ht_iter_.key());
154   }
155 
156   // @brief makes the iterator point toward nothing (in particular, it is not
157   // related anymore to its current set) */
158   template < typename Key >
clear()159   INLINE void SetIteratorSafe< Key >::clear() noexcept {
160     _ht_iter_.clear();
161   }
162 
163   // ===========================================================================
164   // ===                         UNSAFE SET ITERATORS                        ===
165   // ===========================================================================
166 
167   // default constructor: the iterator points toward nothing
168   template < typename Key >
SetIterator()169   INLINE SetIterator< Key >::SetIterator() noexcept {
170     GUM_CONSTRUCTOR(SetIterator);
171   }
172 
173   // creates an iterator for a given set
174   template < typename Key >
175   template < typename Alloc >
SetIterator(const Set<Key,Alloc> & set,Position pos)176   INLINE SetIterator< Key >::SetIterator(const Set< Key, Alloc >& set, Position pos) :
177       _ht_iter_{pos == SetIterator< Key >::END ? set._inside_.cend() : set._inside_.cbegin()} {
178     GUM_CONSTRUCTOR(SetIterator);
179   }
180 
181   // copy constructor
182   template < typename Key >
SetIterator(const SetIterator<Key> & iter)183   INLINE SetIterator< Key >::SetIterator(const SetIterator< Key >& iter) noexcept :
184       _ht_iter_{iter._ht_iter_} {
185     GUM_CONS_CPY(SetIterator);
186   }
187 
188   // move constructor
189   template < typename Key >
SetIterator(SetIterator<Key> && from)190   INLINE SetIterator< Key >::SetIterator(SetIterator< Key >&& from) noexcept :
191       _ht_iter_{std::move(from._ht_iter_)} {
192     GUM_CONS_MOV(SetIterator);
193   }
194 
195   // destructor
196   template < typename Key >
~SetIterator()197   INLINE SetIterator< Key >::~SetIterator() noexcept {
198     GUM_DESTRUCTOR(SetIterator);
199   }
200 
201   // assignment operator
202   template < typename Key >
203   INLINE SetIterator< Key >&
204      SetIterator< Key >::operator=(const SetIterator< Key >& from) noexcept {
205     _ht_iter_ = from._ht_iter_;
206     return *this;
207   }
208 
209   // move operator
210   template < typename Key >
211   INLINE SetIterator< Key >& SetIterator< Key >::operator=(SetIterator< Key >&& from) noexcept {
212     _ht_iter_ = std::move(from._ht_iter_);
213     return *this;
214   }
215 
216   // increments the iterator
217   template < typename Key >
218   INLINE SetIterator< Key >& SetIterator< Key >::operator++() noexcept {
219     // note that, if the hashtable's iterator points toward nothing, the
220     // hashtable's iterator incrementation will do nothing. In particular, it
221     // will not segfault.
222     ++_ht_iter_;
223     return *this;
224   }
225 
226   // makes the iterator point to i elements further in the set
227   template < typename Key >
228   INLINE SetIterator< Key >& SetIterator< Key >::operator+=(Size nb) noexcept {
229     _ht_iter_ += nb;
230     return *this;
231   }
232 
233   // returns a new iterator
234   template < typename Key >
235   INLINE SetIterator< Key > SetIterator< Key >::operator+(Size nb) const noexcept {
236     return SetIterator< Key >{*this} += nb;
237   }
238 
239   // indicates whether two iterators point to different elements or sets
240   template < typename Key >
241   INLINE bool SetIterator< Key >::operator!=(const SetIterator< Key >& from) const noexcept {
242     return _ht_iter_ != from._ht_iter_;
243   }
244 
245   // indicates whether two iterators point toward the same element of a same
246   // set
247   template < typename Key >
248   INLINE bool SetIterator< Key >::operator==(const SetIterator< Key >& from) const noexcept {
249     return _ht_iter_ == from._ht_iter_;
250   }
251 
252   // returns the element pointed to by the iterator
253   template < typename Key >
254   INLINE const Key& SetIterator< Key >::operator*() const {
255     // note that, if the hashtable's iterator points toward nothing, it will
256     // raise an UndefinedIteratorValue exception
257     return _ht_iter_.key();
258   }
259 
260   // returns aointer to the element pointed to by the iterator
261   template < typename Key >
262   INLINE const Key* SetIterator< Key >::operator->() const {
263     // note that, if the hashtable's iterator points toward nothing, it will
264     // raise an UndefinedIteratorValue exception
265     return &(_ht_iter_.key());
266   }
267 
268   // @brief makes the iterator point toward nothing (in particular, it is not
269   // related anymore to its current set) */
270   template < typename Key >
clear()271   INLINE void SetIterator< Key >::clear() noexcept {
272     _ht_iter_.clear();
273   }
274 
275   // ===========================================================================
276   // ===                                 SETS                                ===
277   // ===========================================================================
278 
279   // returns the end iterator for other classes' statics
280   template < typename Key, typename Alloc >
endSafe4Statics()281   INLINE const SetIteratorSafe< Key >& Set< Key, Alloc >::endSafe4Statics() {
282     return *(
283        reinterpret_cast< const SetIteratorSafe< Key >* >(SetIteratorStaticEnd::endSafe4Statics()));
284   }
285 
286   // returns the end iterator for other classes' statics
287   template < typename Key, typename Alloc >
constEndSafe4Statics()288   INLINE const SetIteratorSafe< Key >& Set< Key, Alloc >::constEndSafe4Statics() {
289     return *(reinterpret_cast< const SetIteratorSafe< Key >* >(
290        SetIteratorStaticEnd::constEndSafe4Statics()));
291   }
292 
293   // returns the end iterator for other classes' statics
294   template < typename Key, typename Alloc >
end4Statics()295   INLINE const SetIterator< Key >& Set< Key, Alloc >::end4Statics() {
296     return *(reinterpret_cast< const SetIterator< Key >* >(SetIteratorStaticEnd::end4Statics()));
297   }
298 
299   // returns the end iterator for other classes' statics
300   template < typename Key, typename Alloc >
constEnd4Statics()301   INLINE const SetIterator< Key >& Set< Key, Alloc >::constEnd4Statics() {
302     return *(
303        reinterpret_cast< const SetIterator< Key >* >(SetIteratorStaticEnd::constEnd4Statics()));
304   }
305 
306   // default constructor
307   template < typename Key, typename Alloc >
Set(Size capacity,bool resize_policy)308   INLINE Set< Key, Alloc >::Set(Size capacity, bool resize_policy) :
309       // create the hash table without key uniqueness policy (as we will
310       // check
311       // ourselves the uniqueness of Keys before inserting new elements)
312       _inside_(capacity, resize_policy, false) {
313     GUM_CONSTRUCTOR(Set);
314 
315     // make sure the end() iterator is constructed properly
316     endSafe4Statics();
317     end4Statics();
318   }
319 
320   // initializer list constructor
321   template < typename Key, typename Alloc >
Set(std::initializer_list<Key> list)322   INLINE Set< Key, Alloc >::Set(std::initializer_list< Key > list) :
323       _inside_(Size(list.size()) / 2, true, false) {
324     GUM_CONSTRUCTOR(Set);
325     for (const auto& elt: list) {
326       insert(elt);
327     }
328 
329     // make sure the end() iterator is constructed properly
330     endSafe4Statics();
331     end4Statics();
332   }
333 
334   // copy constructor
335   template < typename Key, typename Alloc >
Set(const Set<Key,Alloc> & s)336   INLINE Set< Key, Alloc >::Set(const Set< Key, Alloc >& s) : _inside_(s._inside_) {
337     GUM_CONS_CPY(Set);
338   }
339 
340   // generalized copy constructor
341   template < typename Key, typename Alloc >
342   template < typename OtherAlloc >
Set(const Set<Key,OtherAlloc> & s)343   INLINE Set< Key, Alloc >::Set(const Set< Key, OtherAlloc >& s) : _inside_(s._inside_) {
344     GUM_CONS_CPY(Set);
345   }
346 
347   // move constructor
348   template < typename Key, typename Alloc >
Set(Set<Key,Alloc> && s)349   INLINE Set< Key, Alloc >::Set(Set< Key, Alloc >&& s) : _inside_(std::move(s._inside_)) {
350     GUM_CONS_MOV(Set);
351   }
352 
353   // destructor
354   template < typename Key, typename Alloc >
~Set()355   INLINE Set< Key, Alloc >::Set::~Set() {
356     GUM_DESTRUCTOR(Set);
357   }
358 
359   // removes all the elements, if any, from the set
360   template < typename Key, typename Alloc >
clear()361   INLINE void Set< Key, Alloc >::clear() {
362     // first we remove all the elements from the hashtable actually containing
363     // the elements of the set. Note that, doing so, all the hashtable iterators
364     // will be updated as well. In turn, this will imply that, whenever an
365     // operation will be performed on a SetIteratorSafe, this will raise an
366     // exception.
367     _inside_.clear();
368 
369     // Note that actually there is no need to update the end iterator as this
370     // one
371     // is not affected by changes within hashtables (adding/deleting elements).
372     // Hence, for speedup, we do not update the end iterator
373   }
374 
375   // copy operator
376   template < typename Key, typename Alloc >
377   Set< Key, Alloc >& Set< Key, Alloc >::operator=(const Set< Key, Alloc >& s) {
378     // avoid self assignment
379     if (&s != this) {
380       // remove the old content of the set. Actually, we remove all the elements
381       // from the underlying hashtable. Note that, doing so, all the hashtable
382       // iterators will be updated as well. In turn, this will imply that,
383       // whenever
384       // an operation will be performed on a SetIteratorSafe, this will raise an
385       // exception.
386       clear();
387 
388       // prepare the set for its new data
389       resize(s.capacity());
390       setResizePolicy(s.resizePolicy());
391 
392       // copy the set
393       _inside_ = s._inside_;
394 
395       // Note that actually there is no need to update the end iterator as this
396       // one
397       // is not affected by changes within hashtables (adding/deleting
398       // elements).
399       // Hence, for speedup, we do not update the end iterator
400     }
401 
402     return *this;
403   }
404 
405   // generalized copy operator
406   template < typename Key, typename Alloc >
407   template < typename OtherAlloc >
408   Set< Key, Alloc >& Set< Key, Alloc >::operator=(const Set< Key, OtherAlloc >& s) {
409     // avoid self assignment
410     if (this != reinterpret_cast< const Set< Key, Alloc >* >(&s)) {
411       // remove the old content of the set. Actually, we remove all the elements
412       // from the underlying hashtable. Note that, doing so, all the hashtable
413       // iterators will be updated as well. In turn, this will imply that,
414       // whenever
415       // an operation will be performed on a SetIteratorSafe, this will raise an
416       // exception.
417       clear();
418 
419       // prepare the set for its new data
420       resize(s.capacity());
421       setResizePolicy(s.resizePolicy());
422 
423       // copy the set
424       _inside_ = s._inside_;
425 
426       // Note that actually there is no need to update the end iterator as this
427       // one
428       // is not affected by changes within hashtables (adding/deleting
429       // elements).
430       // Hence, for speedup, we do not update the end iterator
431     }
432 
433     return *this;
434   }
435 
436   // move operator
437   template < typename Key, typename Alloc >
438   Set< Key, Alloc >& Set< Key, Alloc >::operator=(Set< Key, Alloc >&& from) {
439     _inside_ = std::move(from._inside_);
440     return *this;
441   }
442 
443   // mathematical equality between two sets
444   template < typename Key, typename Alloc >
445   template < typename OtherAlloc >
446   bool Set< Key, Alloc >::operator==(const Set< Key, OtherAlloc >& s2) const {
447     const HashTable< Key, bool, OtherAlloc >& h2 = s2._inside_;
448 
449     // check whether both sets have the same number of elements
450     if (size() != h2.size()) return false;
451 
452     // check the content of the sets
453     for (HashTableConstIterator< Key, bool > iter = _inside_.cbegin(); iter != _inside_.cend();
454          ++iter) {
455       if (!h2.exists(iter.key())) return false;
456     }
457 
458     return true;
459   }
460 
461   // mathematical inequality between two sets
462   template < typename Key, typename Alloc >
463   template < typename OtherAlloc >
464   INLINE bool Set< Key, Alloc >::operator!=(const Set< Key, OtherAlloc >& s2) const {
465     return !(operator==(s2));
466   }
467 
468   // the usual begin iterator to parse the set
469   template < typename Key, typename Alloc >
beginSafe()470   INLINE typename Set< Key, Alloc >::iterator_safe Set< Key, Alloc >::beginSafe() const {
471     return SetIteratorSafe< Key >{*this};
472   }
473 
474   // the usual begin iterator to parse the set
475   template < typename Key, typename Alloc >
cbeginSafe()476   INLINE typename Set< Key, Alloc >::const_iterator_safe Set< Key, Alloc >::cbeginSafe() const {
477     return SetIteratorSafe< Key >{*this};
478   }
479 
480   // the usual end iterator to parse the set
481   template < typename Key, typename Alloc >
482   INLINE const typename Set< Key, Alloc >::iterator_safe&
endSafe()483      Set< Key, Alloc >::endSafe() const noexcept {
484     return *(
485        reinterpret_cast< const SetIteratorSafe< Key >* >(SetIteratorStaticEnd::_SetIterEndSafe_));
486   }
487 
488   // the usual end iterator to parse the set
489   template < typename Key, typename Alloc >
490   INLINE const typename Set< Key, Alloc >::const_iterator_safe&
cendSafe()491      Set< Key, Alloc >::cendSafe() const noexcept {
492     return *(
493        reinterpret_cast< const SetIteratorSafe< Key >* >(SetIteratorStaticEnd::_SetIterEndSafe_));
494   }
495 
496   // the usual begin iterator to parse the set
497   template < typename Key, typename Alloc >
begin()498   INLINE typename Set< Key, Alloc >::iterator Set< Key, Alloc >::begin() const {
499     return SetIterator< Key >{*this};
500   }
501 
502   // the usual begin iterator to parse the set
503   template < typename Key, typename Alloc >
cbegin()504   INLINE typename Set< Key, Alloc >::const_iterator Set< Key, Alloc >::cbegin() const {
505     return SetIterator< Key >{*this};
506   }
507 
508   // the usual end iterator to parse the set
509   template < typename Key, typename Alloc >
end()510   INLINE const typename Set< Key, Alloc >::iterator& Set< Key, Alloc >::end() const noexcept {
511     return *(reinterpret_cast< const SetIterator< Key >* >(SetIteratorStaticEnd::_SetIterEnd_));
512   }
513 
514   // the usual end iterator to parse the set
515   template < typename Key, typename Alloc >
516   INLINE const typename Set< Key, Alloc >::const_iterator&
cend()517      Set< Key, Alloc >::cend() const noexcept {
518     return *(reinterpret_cast< const SetIterator< Key >* >(SetIteratorStaticEnd::_SetIterEnd_));
519   }
520 
521   // returns the size of the underlying hashtable containing the set
522   template < typename Key, typename Alloc >
capacity()523   INLINE Size Set< Key, Alloc >::capacity() const {
524     return _inside_.capacity();
525   }
526 
527   // changes the size of the underlying hashtable
528   template < typename Key, typename Alloc >
resize(Size new_size)529   INLINE void Set< Key, Alloc >::resize(Size new_size) {
530     _inside_.resize(new_size);
531 
532     // Note that actually there is no need to update the end iterator as this
533     // one
534     // is not affected by changes within hashtables (adding/deleting elements).
535     // Hence, for speedup, we do not update the end iterator
536   }
537 
538   // enables the user to change dynamically the resizing policy of the
539   // underlying hashtable
540   template < typename Key, typename Alloc >
setResizePolicy(const bool new_policy)541   INLINE void Set< Key, Alloc >::setResizePolicy(const bool new_policy) {
542     _inside_.setResizePolicy(new_policy);
543 
544     // Note that actually there is no need to update the end iterator as this
545     // one
546     // is not affected by changes within hashtables (adding/deleting elements).
547     // Hence, for speedup, we do not update the end iterator
548   }
549 
550   // returns the current resizing policy of the underlying hashtable
551   template < typename Key, typename Alloc >
resizePolicy()552   INLINE bool Set< Key, Alloc >::resizePolicy() const {
553     return _inside_.resizePolicy();
554   }
555 
556   // indicates whether a given elements belong to the set
557   template < typename Key, typename Alloc >
contains(const Key & k)558   INLINE bool Set< Key, Alloc >::contains(const Key& k) const {
559     return _inside_.exists(k);
560   }
561 
562 
563   template < typename Key, typename Alloc >
564   template < typename OtherAlloc >
isProperSubsetOf(const Set<Key,OtherAlloc> & s)565   INLINE bool Set< Key, Alloc >::isProperSubsetOf(const Set< Key, OtherAlloc >& s) const {
566     if (this->size() >= s.size()) { return false; }
567 
568     for (const auto& elt: *this) {
569       if (!s.contains(elt)) { return false; }
570     }
571     return true;
572   }
573 
574   template < typename Key, typename Alloc >
575   template < typename OtherAlloc >
isProperSupersetOf(const Set<Key,OtherAlloc> & s)576   INLINE bool Set< Key, Alloc >::isProperSupersetOf(const Set< Key, OtherAlloc >& s) const {
577     return s.isProperSubsetOf(*this);
578   }
579 
580 
581   template < typename Key, typename Alloc >
582   template < typename OtherAlloc >
isSubsetOrEqual(const Set<Key,OtherAlloc> & s)583   INLINE bool Set< Key, Alloc >::isSubsetOrEqual(const Set< Key, OtherAlloc >& s) const {
584     if (this->size() > s.size()) { return false; }
585 
586     for (const auto& elt: *this) {
587       if (!s.contains(elt)) { return false; }
588     }
589     return true;
590   }
591 
592   template < typename Key, typename Alloc >
593   template < typename OtherAlloc >
isSupersetOrEqual(const Set<Key,OtherAlloc> & s)594   INLINE bool Set< Key, Alloc >::isSupersetOrEqual(const Set< Key, OtherAlloc >& s) const {
595     return s.isSubsetOrEqual(*this);
596   }
597 
598   // indicates whether a given elements belong to the set
599   template < typename Key, typename Alloc >
exists(const Key & k)600   INLINE bool Set< Key, Alloc >::exists(const Key& k) const {
601     return _inside_.exists(k);
602   }
603 
604   // inserts a new element in the set
605   template < typename Key, typename Alloc >
insert(const Key & k)606   INLINE void Set< Key, Alloc >::insert(const Key& k) {
607     // WARNING: we shall always test whether k already belongs to the set before
608     // trying to insert it because we set  _inside_'s key uniqueness policy to
609     // false
610     if (!contains(k)) {
611       // insert the element
612       _inside_.insert(k, true);
613 
614       // Note that actually there is no need to update the end iterator as this
615       // one
616       // is not affected by changes within hashtables (adding/deleting
617       // elements).
618       // Hence, for speedup, we do not update the end iterator
619     }
620   }
621 
622   // inserts a new element in the set
623   template < typename Key, typename Alloc >
insert(Key && k)624   INLINE void Set< Key, Alloc >::insert(Key&& k) {
625     // WARNING: we shall always test whether k already belongs to the set before
626     // trying to insert it because we set  _inside_'s key uniqueness policy to
627     // false
628     if (!contains(k)) {
629       // insert the element
630       _inside_.insert(std::move(k), true);
631 
632       // Note that actually there is no need to update the end iterator as this
633       // one
634       // is not affected by changes within hashtables (adding/deleting
635       // elements).
636       // Hence, for speedup, we do not update the end iterator
637     }
638   }
639 
640   // emplace a new element in the set
641   template < typename Key, typename Alloc >
642   template < typename... Args >
emplace(Args &&...args)643   INLINE void Set< Key, Alloc >::emplace(Args&&... args) {
644     insert(std::move(Key(std::forward< Args >(args)...)));
645   }
646 
647   // erases an element from the set
648   template < typename Key, typename Alloc >
erase(const Key & k)649   INLINE void Set< Key, Alloc >::erase(const Key& k) {
650     // erase the element (if it exists)
651     _inside_.erase(k);
652 
653     // Note that actually there is no need to update the end iterator as this
654     // one
655     // is not affected by changes within hashtables (adding/deleting elements).
656     // Hence, for speedup, we do not update the end iterator
657   }
658 
659   // erases an element from the set
660   template < typename Key, typename Alloc >
erase(const SetIteratorSafe<Key> & iter)661   INLINE void Set< Key, Alloc >::erase(const SetIteratorSafe< Key >& iter) {
662     // erase the element
663     _inside_.erase(iter._ht_iter_);
664 
665     // Note that actually there is no need to update the end iterator as this
666     // one
667     // is not affected by changes within hashtables (adding/deleting elements).
668     // Hence, for speedup, we do not update the end iterator
669   }
670 
671   // adds a new element to the set
672   template < typename Key, typename Alloc >
673   INLINE Set< Key, Alloc >& Set< Key, Alloc >::operator<<(const Key& k) {
674     insert(k);
675     return *this;
676   }
677 
678   // adds a new element to the set
679   template < typename Key, typename Alloc >
680   INLINE Set< Key, Alloc >& Set< Key, Alloc >::operator<<(Key&& k) {
681     insert(std::move(k));
682     return *this;
683   }
684 
685   // removes an element from the set
686   template < typename Key, typename Alloc >
687   INLINE Set< Key, Alloc >& Set< Key, Alloc >::operator>>(const Key& k) {
688     erase(k);
689     return *this;
690   }
691 
692   // returns the number of elements in the set
693   template < typename Key, typename Alloc >
size()694   INLINE Size Set< Key, Alloc >::size() const noexcept {
695     return _inside_.size();
696   }
697 
698   // indicates whether the set is the empty set
699   template < typename Key, typename Alloc >
empty()700   INLINE bool Set< Key, Alloc >::empty() const noexcept {
701     return _inside_.empty();
702   }
703 
704   // Intersection operator
705   template < typename Key, typename Alloc >
706   template < typename OtherAlloc >
707   Set< Key, Alloc > Set< Key, Alloc >::operator*(const Set< Key, OtherAlloc >& s2) const {
708     Set< Key, Alloc >                         res;
709     const HashTable< Key, bool, OtherAlloc >& h2  = s2._inside_;
710     HashTable< Key, bool, Alloc >&            h_r = res._inside_;
711 
712     if (size() < h2.size()) {
713       for (HashTableConstIterator< Key, bool > iter = _inside_.cbegin(); iter != _inside_.cend();
714            ++iter) {
715         if (h2.exists(iter.key())) h_r.insert(iter.key(), true);
716       }
717     } else {
718       for (HashTableConstIterator< Key, bool > iter = h2.cbegin(); iter != h2.cend(); ++iter) {
719         if (_inside_.exists(iter.key())) h_r.insert(iter.key(), true);
720       }
721     }
722 
723     return res;
724   }
725 
726 
727   // Intersection update operator
728   template < typename Key, typename Alloc >
729   template < typename OtherAlloc >
730   const Set< Key, Alloc >& Set< Key, Alloc >::operator*=(const Set< Key, OtherAlloc >& s2) {
731     if (&s2 != this) {
732       const HashTable< Key, bool, OtherAlloc >& h2 = s2._inside_;
733       for (auto iter = _inside_.beginSafe(); iter != _inside_.endSafe(); ++iter) {
734         if (!h2.exists(iter.key())) _inside_.erase(iter);
735       }
736     }
737 
738     return *this;
739   }
740 
741 
742   // Union update operator
743   template < typename Key, typename Alloc >
744   template < typename OtherAlloc >
745   const Set< Key, Alloc >& Set< Key, Alloc >::operator+=(const Set< Key, OtherAlloc >& s2) {
746     if (&s2 != this) {
747       for (auto pair: s2._inside_) {
748         if (!_inside_.exists(pair.first)) _inside_.insert(pair.first, true);
749       }
750     }
751 
752     return *this;
753   }
754 
755 
756   // Union operator
757   template < typename Key, typename Alloc >
758   template < typename OtherAlloc >
759   Set< Key, Alloc > Set< Key, Alloc >::operator+(const Set< Key, OtherAlloc >& s2) const {
760     Set< Key, Alloc >                         res = *this;
761     const HashTable< Key, bool, OtherAlloc >& h2  = s2._inside_;
762     HashTable< Key, bool, Alloc >&            h_r = res._inside_;
763 
764     for (HashTableConstIterator< Key, bool > iter = h2.cbegin(); iter != h2.cend(); ++iter) {
765       if (!h_r.exists(iter.key())) h_r.insert(iter.key(), true);
766     }
767 
768     return res;
769   }
770 
771 
772   // Disjunction operator
773   template < typename Key, typename Alloc >
774   template < typename OtherAlloc >
775   Set< Key, Alloc > Set< Key, Alloc >::operator-(const Set< Key, OtherAlloc >& s2) const {
776     Set< Key, Alloc >                         res;
777     const HashTable< Key, bool, OtherAlloc >& h2  = s2._inside_;
778     HashTable< Key, bool, Alloc >&            h_r = res._inside_;
779 
780     for (HashTableConstIterator< Key, bool > iter = _inside_.cbegin(); iter != _inside_.cend();
781          ++iter)
782       if (!h2.exists(iter.key())) h_r.insert(iter.key(), true);
783 
784     return res;
785   }
786 
787   // to display the content of the set
788   template < typename Key, typename Alloc >
toString()789   INLINE std::string Set< Key, Alloc >::toString() const {
790     std::stringstream out;
791     bool              first = true;
792     out << "{";
793 
794     for (iterator iter = begin(); iter != end(); ++iter) {
795       if (first) {
796         out << *iter;
797         first = false;
798       } else {
799         out << "," << *iter;
800       }
801     }
802 
803     out << "}";
804 
805     std::string res;
806     out >> res;
807     return res;
808   }
809 
810   // to friendly display the content of the set
811   template < typename Key, typename Alloc >
812   std::ostream& operator<<(std::ostream& stream, const Set< Key, Alloc >& set) {
813     stream << set.toString();
814     return stream;
815   }
816 
817   // creates a hashtable of NewKey from the set
818   template < typename Key, typename Alloc >
819   template < typename NewKey, typename NewAlloc >
hashMap(NewKey (* f)(const Key &),Size size)820   HashTable< Key, NewKey, NewAlloc > Set< Key, Alloc >::hashMap(NewKey (*f)(const Key&),
821                                                                 Size size) const {
822     // determine the proper size of the hashtable
823     // by default, the size of the table is set so that the table does not take
824     // too much space while allowing to add a few elements without resizing
825     if (size == 0) size = std::max(Size(2), _inside_.size() / 2);
826 
827     // create a new table
828     HashTable< Key, NewKey, NewAlloc > table(size);
829 
830     // fill the new hash table
831     for (HashTableConstIterator< Key, bool > iter = _inside_.cbegin(); iter != _inside_.cend();
832          ++iter) {
833       table.insert(iter.key(), f(iter.key()));
834     }
835 
836     return table;
837   }
838 
839   // creates a hashtable of NewKey from the set
840   template < typename Key, typename Alloc >
841   template < typename NewKey, typename NewAlloc >
hashMap(const NewKey & val,Size size)842   HashTable< Key, NewKey, NewAlloc > Set< Key, Alloc >::hashMap(const NewKey& val,
843                                                                 Size          size) const {
844     // determine the proper size of the hashtable
845     // by default, the size of the table is set so that the table does not take
846     // too much space while allowing to add a few elements without resizing
847     if (size == 0) size = std::max(Size(2), _inside_.size() / 2);
848 
849     // create a new table
850     HashTable< Key, NewKey, NewAlloc > table(size);
851 
852     // fill the new hash table
853     for (HashTableConstIterator< Key, bool > iter = _inside_.cbegin(); iter != _inside_.cend();
854          ++iter) {
855       table.insert(iter.key(), val);
856     }
857 
858     return table;
859   }
860 
861   // a method to create a list of NewKey from the set
862   template < typename Key, typename Alloc >
863   template < typename NewKey, typename NewAlloc >
listMap(NewKey (* f)(const Key &))864   List< NewKey, NewAlloc > Set< Key, Alloc >::listMap(NewKey (*f)(const Key&)) const {
865     // create a new list
866     List< NewKey, NewAlloc > list;
867 
868     // fill the new list
869     for (HashTableConstIterator< Key, bool > iter = _inside_.cbegin(); iter != _inside_.cend();
870          ++iter) {
871       list.pushBack(f(iter.key()));
872     }
873 
874     return list;
875   }
876 
877   // Returns the value of a key as a Size
878   template < typename T, typename Alloc >
castToSize(const Set<T,Alloc> & key)879   INLINE Size HashFunc< Set< T, Alloc > >::castToSize(const Set< T, Alloc >& key) {
880     Size h = Size(0);
881     for (const auto& k: key) {
882       const auto hs = HashFunc< T >::castToSize(k);
883       h += hs * (hs ^ HashFuncConst::gold);
884     }
885 
886     return h;
887   }
888 
889 
890   // Returns the hashed value of a key.
891   template < typename T, typename Alloc >
operator()892   INLINE Size HashFunc< Set< T, Alloc > >::operator()(const Set< T, Alloc >& key) const {
893     return (castToSize(key) * HashFuncConst::gold) & this->hash_mask_;
894   }
895 
896 } /* namespace gum */
897