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