Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
unordered_set.h
00001 ///\file 00002 00003 /****************************************************************************** 00004 The MIT License(MIT) 00005 00006 Embedded Template Library. 00007 https://github.com/ETLCPP/etl 00008 http://www.etlcpp.com 00009 00010 Copyright(c) 2016 jwellbelove 00011 00012 Permission is hereby granted, free of charge, to any person obtaining a copy 00013 of this software and associated documentation files(the "Software"), to deal 00014 in the Software without restriction, including without limitation the rights 00015 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 00016 copies of the Software, and to permit persons to whom the Software is 00017 furnished to do so, subject to the following conditions : 00018 00019 The above copyright notice and this permission notice shall be included in all 00020 copies or substantial portions of the Software. 00021 00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00024 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 00025 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00026 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00027 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00028 SOFTWARE. 00029 ******************************************************************************/ 00030 00031 #ifndef __ETL_UNORDERED_SET__ 00032 #define __ETL_UNORDERED_SET__ 00033 00034 #include <stddef.h> 00035 #include <iterator> 00036 #include <functional> 00037 #include <algorithm> 00038 #include <functional> 00039 #include <utility> 00040 00041 #include "platform.h " 00042 #include "container.h " 00043 #include "pool.h " 00044 #include "vector.h " 00045 #include "intrusive_forward_list.h " 00046 #include "hash.h " 00047 #include "type_traits.h " 00048 #include "parameter_type.h " 00049 #include "nullptr.h " 00050 #include "error_handler.h " 00051 #include "exception.h " 00052 #include "error_handler.h " 00053 #include "debug_count.h " 00054 00055 #undef ETL_FILE 00056 #define ETL_FILE "23" 00057 00058 //***************************************************************************** 00059 ///\defgroup unordered_set unordered_set 00060 /// A unordered_set with the capacity defined at compile time. 00061 ///\ingroup containers 00062 //***************************************************************************** 00063 00064 namespace etl 00065 { 00066 //*************************************************************************** 00067 /// Exception for the unordered_set. 00068 ///\ingroup unordered_set 00069 //*************************************************************************** 00070 class unordered_set_exception : public etl::exception 00071 { 00072 public: 00073 00074 unordered_set_exception(string_type reason_, string_type file_name_, numeric_type line_number_) 00075 : etl::exception(reason_, file_name_, line_number_) 00076 { 00077 } 00078 }; 00079 00080 //*************************************************************************** 00081 /// Full exception for the unordered_set. 00082 ///\ingroup unordered_set 00083 //*************************************************************************** 00084 class unordered_set_full : public etl::unordered_set_exception 00085 { 00086 public: 00087 00088 unordered_set_full(string_type file_name_, numeric_type line_number_) 00089 : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:full", ETL_FILE"A"), file_name_, line_number_) 00090 { 00091 } 00092 }; 00093 00094 //*************************************************************************** 00095 /// Out of range exception for the unordered_set. 00096 ///\ingroup unordered_set 00097 //*************************************************************************** 00098 class unordered_set_out_of_range : public etl::unordered_set_exception 00099 { 00100 public: 00101 00102 unordered_set_out_of_range(string_type file_name_, numeric_type line_number_) 00103 : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:range", ETL_FILE"B"), file_name_, line_number_) 00104 {} 00105 }; 00106 00107 //*************************************************************************** 00108 /// Iterator exception for the unordered_set. 00109 ///\ingroup unordered_set 00110 //*************************************************************************** 00111 class unordered_set_iterator : public etl::unordered_set_exception 00112 { 00113 public: 00114 00115 unordered_set_iterator(string_type file_name_, numeric_type line_number_) 00116 : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:iterator", ETL_FILE"C"), file_name_, line_number_) 00117 { 00118 } 00119 }; 00120 00121 //*************************************************************************** 00122 /// The base class for specifically sized unordered_set. 00123 /// Can be used as a reference type for all unordered_set containing a specific type. 00124 ///\ingroup unordered_set 00125 //*************************************************************************** 00126 template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > 00127 class iunordered_set 00128 { 00129 public: 00130 00131 typedef TKey value_type; 00132 typedef TKey key_type; 00133 typedef THash hasher; 00134 typedef TKeyEqual key_equal; 00135 typedef value_type& reference; 00136 typedef const value_type& const_reference; 00137 typedef value_type* pointer; 00138 typedef const value_type* const_pointer; 00139 typedef size_t size_type; 00140 00141 typedef typename etl::parameter_type<TKey>::type key_parameter_t; 00142 00143 typedef etl::forward_link<0> link_t ; 00144 00145 // The nodes that store the elements. 00146 struct node_t : public link_t 00147 { 00148 node_t(const value_type& key_) 00149 : key(key_) 00150 { 00151 } 00152 00153 value_type key; 00154 }; 00155 00156 private: 00157 00158 typedef etl::intrusive_forward_list<node_t, link_t> bucket_t; 00159 typedef etl::ipool pool_t; 00160 00161 public: 00162 00163 // Local iterators iterate over one bucket. 00164 typedef typename bucket_t::iterator local_iterator; 00165 typedef typename bucket_t::const_iterator local_const_iterator; 00166 00167 //********************************************************************* 00168 class iterator : public std::iterator<std::forward_iterator_tag, TKey> 00169 { 00170 public: 00171 00172 typedef typename iunordered_set::value_type value_type; 00173 typedef typename iunordered_set::key_type key_type; 00174 typedef typename iunordered_set::hasher hasher; 00175 typedef typename iunordered_set::key_equal key_equal; 00176 typedef typename iunordered_set::reference reference; 00177 typedef typename iunordered_set::const_reference const_reference; 00178 typedef typename iunordered_set::pointer pointer; 00179 typedef typename iunordered_set::const_pointer const_pointer; 00180 typedef typename iunordered_set::size_type size_type; 00181 00182 friend class iunordered_set; 00183 00184 //********************************* 00185 iterator() 00186 { 00187 } 00188 00189 //********************************* 00190 iterator(const iterator& other) 00191 : pbuckets_end(other.pbuckets_end), 00192 pbucket(other.pbucket), 00193 inode(other.inode) 00194 { 00195 } 00196 00197 //********************************* 00198 iterator& operator ++() 00199 { 00200 ++inode; 00201 00202 // The end of this node list? 00203 if (inode == pbucket->end()) 00204 { 00205 // Search for the next non-empty bucket. 00206 ++pbucket; 00207 while ((pbucket != pbuckets_end) && (pbucket->empty())) 00208 { 00209 ++pbucket; 00210 } 00211 00212 // If not past the end, get the first node in the bucket. 00213 if (pbucket != pbuckets_end) 00214 { 00215 inode = pbucket->begin(); 00216 } 00217 } 00218 00219 return *this; 00220 } 00221 00222 //********************************* 00223 iterator operator ++(int) 00224 { 00225 iterator temp(*this); 00226 operator++(); 00227 return temp; 00228 } 00229 00230 //********************************* 00231 iterator operator =(const iterator& other) 00232 { 00233 pbuckets_end = other.pbuckets_end; 00234 pbucket = other.pbucket; 00235 inode = other.inode; 00236 return *this; 00237 } 00238 00239 //********************************* 00240 reference operator *() 00241 { 00242 return inode->key; 00243 } 00244 00245 //********************************* 00246 const_reference operator *() const 00247 { 00248 return inode->key; 00249 } 00250 00251 //********************************* 00252 pointer operator &() 00253 { 00254 return &(inode->key); 00255 } 00256 00257 //********************************* 00258 const_pointer operator &() const 00259 { 00260 return &(inode->key); 00261 } 00262 00263 //********************************* 00264 pointer operator ->() 00265 { 00266 return &(inode->key); 00267 } 00268 00269 //********************************* 00270 const_pointer operator ->() const 00271 { 00272 return &(inode->key); 00273 } 00274 00275 //********************************* 00276 friend bool operator == (const iterator& lhs, const iterator& rhs) 00277 { 00278 return lhs.compare(rhs); 00279 } 00280 00281 //********************************* 00282 friend bool operator != (const iterator& lhs, const iterator& rhs) 00283 { 00284 return !(lhs == rhs); 00285 } 00286 00287 private: 00288 00289 //********************************* 00290 iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) 00291 : pbuckets_end(pbuckets_end_), 00292 pbucket(pbucket_), 00293 inode(inode_) 00294 { 00295 } 00296 00297 //********************************* 00298 bool compare(const iterator& rhs) const 00299 { 00300 return rhs.inode == inode; 00301 } 00302 00303 //********************************* 00304 bucket_t& get_bucket() 00305 { 00306 return *pbucket; 00307 } 00308 00309 //********************************* 00310 bucket_t*& get_bucket_list_iterator() 00311 { 00312 return pbucket; 00313 } 00314 00315 //********************************* 00316 local_iterator get_local_iterator() 00317 { 00318 return inode; 00319 } 00320 00321 bucket_t* pbuckets_end; 00322 bucket_t* pbucket; 00323 local_iterator inode; 00324 }; 00325 00326 //********************************************************************* 00327 class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey> 00328 { 00329 public: 00330 00331 typedef typename iunordered_set::value_type value_type; 00332 typedef typename iunordered_set::key_type key_type; 00333 typedef typename iunordered_set::hasher hasher; 00334 typedef typename iunordered_set::key_equal key_equal; 00335 typedef typename iunordered_set::reference reference; 00336 typedef typename iunordered_set::const_reference const_reference; 00337 typedef typename iunordered_set::pointer pointer; 00338 typedef typename iunordered_set::const_pointer const_pointer; 00339 typedef typename iunordered_set::size_type size_type; 00340 00341 friend class iunordered_set; 00342 friend class iterator; 00343 00344 //********************************* 00345 const_iterator() 00346 { 00347 } 00348 00349 //********************************* 00350 const_iterator(const typename iunordered_set::iterator& other) 00351 : pbuckets_end(other.pbuckets_end), 00352 pbucket(other.pbucket), 00353 inode(other.inode) 00354 { 00355 } 00356 00357 //********************************* 00358 const_iterator(const const_iterator& other) 00359 : pbuckets_end(other.pbuckets_end), 00360 pbucket(other.pbucket), 00361 inode(other.inode) 00362 { 00363 } 00364 00365 //********************************* 00366 const_iterator& operator ++() 00367 { 00368 ++inode; 00369 00370 // The end of this node list? 00371 if (inode == pbucket->end()) 00372 { 00373 // Search for the next non-empty bucket. 00374 00375 ++pbucket; 00376 while ((pbucket != pbuckets_end) && (pbucket->empty())) 00377 { 00378 ++pbucket; 00379 } 00380 00381 // If not past the end, get the first node in the bucket. 00382 if (pbucket != pbuckets_end) 00383 { 00384 inode = pbucket->begin(); 00385 } 00386 } 00387 00388 return *this; 00389 } 00390 00391 //********************************* 00392 const_iterator operator ++(int) 00393 { 00394 const_iterator temp(*this); 00395 operator++(); 00396 return temp; 00397 } 00398 00399 //********************************* 00400 const_iterator operator =(const const_iterator& other) 00401 { 00402 pbuckets_end = other.pbuckets_end; 00403 pbucket = other.pbucket; 00404 inode = other.inode; 00405 return *this; 00406 } 00407 00408 //********************************* 00409 const_reference operator *() const 00410 { 00411 return inode->key; 00412 } 00413 00414 //********************************* 00415 const_pointer operator &() const 00416 { 00417 return &(inode->key); 00418 } 00419 00420 //********************************* 00421 const_pointer operator ->() const 00422 { 00423 return &(inode->key); 00424 } 00425 00426 //********************************* 00427 friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) 00428 { 00429 return lhs.compare(rhs); 00430 } 00431 00432 //********************************* 00433 friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) 00434 { 00435 return !(lhs == rhs); 00436 } 00437 00438 private: 00439 00440 //********************************* 00441 const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) 00442 : pbuckets_end(pbuckets_end_), 00443 pbucket(pbucket_), 00444 inode(inode_) 00445 { 00446 } 00447 00448 //********************************* 00449 bool compare(const const_iterator& rhs) const 00450 { 00451 return rhs.inode == inode; 00452 } 00453 00454 //********************************* 00455 bucket_t& get_bucket() 00456 { 00457 return *pbucket; 00458 } 00459 00460 //********************************* 00461 bucket_t*& get_bucket_list_iterator() 00462 { 00463 return pbucket; 00464 } 00465 00466 //********************************* 00467 local_iterator get_local_iterator() 00468 { 00469 return inode; 00470 } 00471 00472 bucket_t* pbuckets_end; 00473 bucket_t* pbucket; 00474 local_iterator inode; 00475 }; 00476 00477 typedef typename std::iterator_traits<iterator>::difference_type difference_type; 00478 00479 //********************************************************************* 00480 /// Returns an iterator to the beginning of the unordered_set. 00481 ///\return An iterator to the beginning of the unordered_set. 00482 //********************************************************************* 00483 iterator begin() 00484 { 00485 return iterator(pbuckets + number_of_buckets, first, first->begin()); 00486 } 00487 00488 //********************************************************************* 00489 /// Returns a const_iterator to the beginning of the unordered_set. 00490 ///\return A const iterator to the beginning of the unordered_set. 00491 //********************************************************************* 00492 const_iterator begin() const 00493 { 00494 return const_iterator(pbuckets + number_of_buckets, first, first->begin()); 00495 } 00496 00497 //********************************************************************* 00498 /// Returns a const_iterator to the beginning of the unordered_set. 00499 ///\return A const iterator to the beginning of the unordered_set. 00500 //********************************************************************* 00501 const_iterator cbegin() const 00502 { 00503 return const_iterator(pbuckets + number_of_buckets, first, first->begin()); 00504 } 00505 00506 //********************************************************************* 00507 /// Returns an iterator to the beginning of the unordered_set bucket. 00508 ///\return An iterator to the beginning of the unordered_set bucket. 00509 //********************************************************************* 00510 local_iterator begin(size_t i) 00511 { 00512 return pbuckets[i].begin(); 00513 } 00514 00515 //********************************************************************* 00516 /// Returns a const_iterator to the beginning of the unordered_set bucket. 00517 ///\return A const iterator to the beginning of the unordered_set bucket. 00518 //********************************************************************* 00519 local_const_iterator begin(size_t i) const 00520 { 00521 return pbuckets[i].cbegin(); 00522 } 00523 00524 //********************************************************************* 00525 /// Returns a const_iterator to the beginning of the unordered_set bucket. 00526 ///\return A const iterator to the beginning of the unordered_set bucket. 00527 //********************************************************************* 00528 local_const_iterator cbegin(size_t i) const 00529 { 00530 return pbuckets[i].cbegin(); 00531 } 00532 00533 //********************************************************************* 00534 /// Returns an iterator to the end of the unordered_set. 00535 ///\return An iterator to the end of the unordered_set. 00536 //********************************************************************* 00537 iterator end() 00538 { 00539 return iterator(pbuckets + number_of_buckets, last, last->end()); 00540 } 00541 00542 //********************************************************************* 00543 /// Returns a const_iterator to the end of the unordered_set. 00544 ///\return A const iterator to the end of the unordered_set. 00545 //********************************************************************* 00546 const_iterator end() const 00547 { 00548 return const_iterator(pbuckets + number_of_buckets, last, last->end()); 00549 } 00550 00551 //********************************************************************* 00552 /// Returns a const_iterator to the end of the unordered_set. 00553 ///\return A const iterator to the end of the unordered_set. 00554 //********************************************************************* 00555 const_iterator cend() const 00556 { 00557 return const_iterator(pbuckets + number_of_buckets, last, last->end()); 00558 } 00559 00560 //********************************************************************* 00561 /// Returns an iterator to the end of the unordered_set bucket. 00562 ///\return An iterator to the end of the unordered_set bucket. 00563 //********************************************************************* 00564 local_iterator end(size_t i) 00565 { 00566 return pbuckets[i].end(); 00567 } 00568 00569 //********************************************************************* 00570 /// Returns a const_iterator to the end of the unordered_set bucket. 00571 ///\return A const iterator to the end of the unordered_set bucket. 00572 //********************************************************************* 00573 local_const_iterator end(size_t i) const 00574 { 00575 return pbuckets[i].cend(); 00576 } 00577 00578 //********************************************************************* 00579 /// Returns a const_iterator to the end of the unordered_set bucket. 00580 ///\return A const iterator to the end of the unordered_set bucket. 00581 //********************************************************************* 00582 local_const_iterator cend(size_t i) const 00583 { 00584 return pbuckets[i].cend(); 00585 } 00586 00587 //********************************************************************* 00588 /// Returns the bucket index for the key. 00589 ///\return The bucket index for the key. 00590 //********************************************************************* 00591 size_type get_bucket_index(key_parameter_t key) const 00592 { 00593 return key_hash_function(key) % number_of_buckets; 00594 } 00595 00596 //********************************************************************* 00597 /// Returns the size of the bucket key. 00598 ///\return The bucket size of the bucket key. 00599 //********************************************************************* 00600 size_type bucket_size(key_parameter_t key) const 00601 { 00602 size_t index = bucket(key); 00603 00604 return std::distance(pbuckets[index].begin(), pbuckets[index].end()); 00605 } 00606 00607 //********************************************************************* 00608 /// Returns the maximum number of the buckets the container can hold. 00609 ///\return The maximum number of the buckets the container can hold. 00610 //********************************************************************* 00611 size_type max_bucket_count() const 00612 { 00613 return number_of_buckets; 00614 } 00615 00616 //********************************************************************* 00617 /// Returns the number of the buckets the container holds. 00618 ///\return The number of the buckets the container holds. 00619 //********************************************************************* 00620 size_type bucket_count() const 00621 { 00622 return number_of_buckets; 00623 } 00624 00625 //********************************************************************* 00626 /// Assigns values to the unordered_set. 00627 /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space. 00628 /// If asserts or exceptions are enabled, emits unordered_set_iterator if the iterators are reversed. 00629 ///\param first The iterator to the first element. 00630 ///\param last The iterator to the last element + 1. 00631 //********************************************************************* 00632 template <typename TIterator> 00633 void assign(TIterator first_, TIterator last_) 00634 { 00635 #if defined(ETL_DEBUG) 00636 difference_type d = std::distance(first_, last_); 00637 ETL_ASSERT(d >= 0, ETL_ERROR(unordered_set_iterator)); 00638 ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_set_full)); 00639 #endif 00640 00641 clear(); 00642 00643 while (first_ != last_) 00644 { 00645 insert(*first_++); 00646 } 00647 } 00648 00649 //********************************************************************* 00650 /// Inserts a value to the unordered_set. 00651 /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full. 00652 ///\param value The value to insert. 00653 //********************************************************************* 00654 std::pair<iterator, bool> insert(const value_type& key) 00655 { 00656 std::pair<iterator, bool> result(end(), false); 00657 00658 ETL_ASSERT(!full(), ETL_ERROR(unordered_set_full)); 00659 00660 // Get the hash index. 00661 size_t index = get_bucket_index(key); 00662 00663 // Get the bucket & bucket iterator. 00664 bucket_t* pbucket = pbuckets + index; 00665 bucket_t& bucket = *pbucket; 00666 00667 // The first one in the bucket? 00668 if (bucket.empty()) 00669 { 00670 // Get a new node. 00671 node_t& node = *pnodepool->allocate<node_t>(); 00672 ::new (&node.key) value_type(key); 00673 ++construct_count; 00674 00675 // Just add the pointer to the bucket; 00676 bucket.insert_after(bucket.before_begin(), node); 00677 00678 result.first = iterator(pbuckets + number_of_buckets, pbucket, pbucket->begin()); 00679 result.second = true; 00680 00681 adjust_first_last_markers(pbucket); 00682 } 00683 else 00684 { 00685 // Step though the bucket looking for a place to insert. 00686 local_iterator inode_previous = bucket.before_begin(); 00687 local_iterator inode = bucket.begin(); 00688 00689 while (inode != bucket.end()) 00690 { 00691 // Do we already have this key? 00692 if (inode->key == key) 00693 { 00694 break; 00695 } 00696 00697 ++inode_previous; 00698 ++inode; 00699 } 00700 00701 // Not already there? 00702 if (inode == bucket.end()) 00703 { 00704 // Get a new node. 00705 node_t& node = *pnodepool->allocate<node_t>(); 00706 ::new (&node.key) value_type(key); 00707 ++construct_count; 00708 00709 // Add the node to the end of the bucket; 00710 bucket.insert_after(inode_previous, node); 00711 ++inode_previous; 00712 00713 result.first = iterator(pbuckets + number_of_buckets, pbucket, inode_previous); 00714 result.second = true; 00715 } 00716 } 00717 00718 return result; 00719 } 00720 00721 //********************************************************************* 00722 /// Inserts a value to the unordered_set. 00723 /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full. 00724 ///\param position The position to insert at. 00725 ///\param value The value to insert. 00726 //********************************************************************* 00727 iterator insert(const_iterator position, const value_type& key) 00728 { 00729 return insert(key).first; 00730 } 00731 00732 //********************************************************************* 00733 /// Inserts a range of values to the unordered_set. 00734 /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space. 00735 ///\param position The position to insert at. 00736 ///\param first The first element to add. 00737 ///\param last The last + 1 element to add. 00738 //********************************************************************* 00739 template <class TIterator> 00740 void insert(TIterator first_, TIterator last_) 00741 { 00742 while (first_ != last_) 00743 { 00744 insert(*first_++); 00745 } 00746 } 00747 00748 //********************************************************************* 00749 /// Erases an element. 00750 ///\param key The key to erase. 00751 ///\return The number of elements erased. 0 or 1. 00752 //********************************************************************* 00753 size_t erase(key_parameter_t key) 00754 { 00755 size_t n = 0; 00756 size_t index = get_bucket_index(key); 00757 00758 bucket_t& bucket = pbuckets[index]; 00759 00760 local_iterator iprevious = bucket.before_begin(); 00761 local_iterator icurrent = bucket.begin(); 00762 00763 // Search for the key, if we have it. 00764 while ((icurrent != bucket.end()) && (icurrent->key != key)) 00765 { 00766 ++iprevious; 00767 ++icurrent; 00768 } 00769 00770 // Did we find it? 00771 if (icurrent != bucket.end()) 00772 { 00773 bucket.erase_after(iprevious); // Unlink from the bucket. 00774 icurrent->key.~value_type(); // Destroy the value. 00775 pnodepool->release(&*icurrent); // Release it back to the pool. 00776 n = 1; 00777 --construct_count; 00778 } 00779 00780 return n; 00781 } 00782 00783 //********************************************************************* 00784 /// Erases an element. 00785 ///\param ielement Iterator to the element. 00786 //********************************************************************* 00787 iterator erase(const_iterator ielement) 00788 { 00789 // Make a note of the next one. 00790 iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator()); 00791 ++inext; 00792 00793 bucket_t& bucket = ielement.get_bucket(); 00794 local_iterator iprevious = bucket.before_begin(); 00795 local_iterator icurrent = ielement.get_local_iterator(); 00796 00797 // Find the node previous to the one we're interested in. 00798 while (iprevious->etl_next != &*icurrent) 00799 { 00800 ++iprevious; 00801 } 00802 00803 bucket.erase_after(iprevious); // Unlink from the bucket. 00804 icurrent->key.~value_type(); // Destroy the value. 00805 pnodepool->release(&*icurrent); // Release it back to the pool. 00806 --construct_count; 00807 00808 return inext; 00809 } 00810 00811 //********************************************************************* 00812 /// Erases a range of elements. 00813 /// The range includes all the elements between first and last, including the 00814 /// element pointed by first, but not the one pointed to by last. 00815 ///\param first Iterator to the first element. 00816 ///\param last Iterator to the last element. 00817 //********************************************************************* 00818 iterator erase(const_iterator first_, const_iterator last_) 00819 { 00820 // Make a note of the last. 00821 iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); 00822 00823 // Get the starting point. 00824 bucket_t* pbucket = first_.get_bucket_list_iterator(); 00825 local_iterator iprevious = pbucket->before_begin(); 00826 local_iterator icurrent = first_.get_local_iterator(); 00827 local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. 00828 00829 // Find the node previous to the first one. 00830 while (iprevious->etl_next != &*icurrent) 00831 { 00832 ++iprevious; 00833 } 00834 00835 while (icurrent != iend) 00836 { 00837 00838 local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. 00839 icurrent->key.~value_type(); // Destroy the value. 00840 pnodepool->release(&*icurrent); // Release it back to the pool. 00841 --construct_count; 00842 00843 icurrent = inext; 00844 00845 // Are we there yet? 00846 if (icurrent != iend) 00847 { 00848 // At the end of this bucket? 00849 if ((icurrent == pbucket->end())) 00850 { 00851 // Find the next non-empty one. 00852 do 00853 { 00854 ++pbucket; 00855 } while (pbucket->empty()); 00856 00857 iprevious = pbucket->before_begin(); 00858 icurrent = pbucket->begin(); 00859 } 00860 } 00861 } 00862 00863 return result; 00864 } 00865 00866 //************************************************************************* 00867 /// Clears the unordered_set. 00868 //************************************************************************* 00869 void clear() 00870 { 00871 initialise(); 00872 } 00873 00874 //********************************************************************* 00875 /// Counts an element. 00876 ///\param key The key to search for. 00877 ///\return 1 if the key exists, otherwise 0. 00878 //********************************************************************* 00879 size_t count(key_parameter_t key) const 00880 { 00881 return (find(key) == end()) ? 0 : 1; 00882 } 00883 00884 //********************************************************************* 00885 /// Finds an element. 00886 ///\param key The key to search for. 00887 ///\return An iterator to the element if the key exists, otherwise end(). 00888 //********************************************************************* 00889 iterator find(key_parameter_t key) 00890 { 00891 size_t index = get_bucket_index(key); 00892 00893 bucket_t* pbucket = pbuckets + index; 00894 bucket_t& bucket = *pbucket; 00895 00896 // Is the bucket not empty? 00897 if (!bucket.empty()) 00898 { 00899 // Step though the list until we find the end or an equivalent key. 00900 local_iterator inode = bucket.begin(); 00901 local_iterator iend = bucket.end(); 00902 00903 while (inode != iend) 00904 { 00905 // Do we have this one? 00906 if (key_equal_function(key, inode->key)) 00907 { 00908 return iterator(pbuckets + number_of_buckets, pbucket, inode); 00909 } 00910 00911 ++inode; 00912 } 00913 } 00914 00915 return end(); 00916 } 00917 00918 //********************************************************************* 00919 /// Finds an element. 00920 ///\param key The key to search for. 00921 ///\return An iterator to the element if the key exists, otherwise end(). 00922 //********************************************************************* 00923 const_iterator find(key_parameter_t key) const 00924 { 00925 size_t index = get_bucket_index(key); 00926 00927 bucket_t* pbucket = pbuckets + index; 00928 bucket_t& bucket = *pbucket; 00929 00930 // Is the bucket not empty? 00931 if (!bucket.empty()) 00932 { 00933 // Step though the list until we find the end or an equivalent key. 00934 local_iterator inode = bucket.begin(); 00935 local_iterator iend = bucket.end(); 00936 00937 while (inode != iend) 00938 { 00939 // Do we have this one? 00940 if (key_equal_function(key, inode->key)) 00941 { 00942 return iterator(pbuckets + number_of_buckets, pbucket, inode); 00943 } 00944 00945 ++inode; 00946 } 00947 } 00948 00949 return end(); 00950 } 00951 00952 //********************************************************************* 00953 /// Returns a range containing all elements with key 'key' in the container. 00954 /// The range is defined by two iterators, the first pointing to the first 00955 /// element of the wanted range and the second pointing past the last 00956 /// element of the range. 00957 ///\param key The key to search for. 00958 ///\return An iterator pair to the range of elements if the key exists, otherwise end(). 00959 //********************************************************************* 00960 std::pair<iterator, iterator> equal_range(key_parameter_t key) 00961 { 00962 iterator f = find(key); 00963 iterator l = f; 00964 00965 if (l != end()) 00966 { 00967 ++l; 00968 } 00969 00970 return std::pair<iterator, iterator>(f, l); 00971 } 00972 00973 //********************************************************************* 00974 /// Returns a range containing all elements with key 'key' in the container. 00975 /// The range is defined by two iterators, the first pointing to the first 00976 /// element of the wanted range and the second pointing past the last 00977 /// element of the range. 00978 ///\param key The key to search for. 00979 ///\return A const iterator pair to the range of elements if the key exists, otherwise end(). 00980 //********************************************************************* 00981 std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const 00982 { 00983 const_iterator f = find(key); 00984 const_iterator l = f; 00985 00986 if (l != end()) 00987 { 00988 ++l; 00989 } 00990 00991 return std::pair<const_iterator, const_iterator>(f, l); 00992 } 00993 00994 //************************************************************************* 00995 /// Gets the size of the unordered_set. 00996 //************************************************************************* 00997 size_type size() const 00998 { 00999 return pnodepool->size(); 01000 } 01001 01002 //************************************************************************* 01003 /// Gets the maximum possible size of the unordered_set. 01004 //************************************************************************* 01005 size_type max_size() const 01006 { 01007 return pnodepool->max_size(); 01008 } 01009 01010 //************************************************************************* 01011 /// Checks to see if the unordered_set is empty. 01012 //************************************************************************* 01013 bool empty() const 01014 { 01015 return pnodepool->empty(); 01016 } 01017 01018 //************************************************************************* 01019 /// Checks to see if the unordered_set is full. 01020 //************************************************************************* 01021 bool full() const 01022 { 01023 return pnodepool->full(); 01024 } 01025 01026 //************************************************************************* 01027 /// Returns the remaining capacity. 01028 ///\return The remaining capacity. 01029 //************************************************************************* 01030 size_t available() const 01031 { 01032 return pnodepool->available(); 01033 } 01034 01035 //************************************************************************* 01036 /// Returns the load factor = size / bucket_count. 01037 ///\return The load factor = size / bucket_count. 01038 //************************************************************************* 01039 float load_factor() const 01040 { 01041 return static_cast<float>(size()) / static_cast<float>(bucket_count()); 01042 } 01043 01044 //************************************************************************* 01045 /// Returns the function that hashes the keys. 01046 ///\return The function that hashes the keys.. 01047 //************************************************************************* 01048 hasher hash_function() const 01049 { 01050 return key_hash_function; 01051 } 01052 01053 //************************************************************************* 01054 /// Returns the function that compares the keys. 01055 ///\return The function that compares the keys.. 01056 //************************************************************************* 01057 key_equal key_eq() const 01058 { 01059 return key_equal_function; 01060 } 01061 01062 //************************************************************************* 01063 /// Assignment operator. 01064 //************************************************************************* 01065 iunordered_set& operator = (const iunordered_set& rhs) 01066 { 01067 // Skip if doing self assignment 01068 if (this != &rhs) 01069 { 01070 assign(rhs.cbegin(), rhs.cend()); 01071 } 01072 01073 return *this; 01074 } 01075 01076 protected: 01077 01078 //********************************************************************* 01079 /// Constructor. 01080 //********************************************************************* 01081 iunordered_set(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_) 01082 : pnodepool(&node_pool_), 01083 pbuckets(pbuckets_), 01084 number_of_buckets(number_of_buckets_) 01085 { 01086 } 01087 01088 //********************************************************************* 01089 /// Initialise the unordered_set. 01090 //********************************************************************* 01091 void initialise() 01092 { 01093 if (!empty()) 01094 { 01095 // For each bucket... 01096 for (size_t i = 0; i < number_of_buckets; ++i) 01097 { 01098 bucket_t& bucket = pbuckets[i]; 01099 01100 if (!bucket.empty()) 01101 { 01102 // For each item in the bucket... 01103 local_iterator it = bucket.begin(); 01104 01105 while (it != bucket.end()) 01106 { 01107 // Destroy the value contents. 01108 it->key.~value_type(); 01109 ++it; 01110 --construct_count; 01111 } 01112 01113 // Now it's safe to clear the bucket. 01114 bucket.clear(); 01115 } 01116 } 01117 01118 // Now it's safe to clear the entire pool in one go. 01119 pnodepool->release_all(); 01120 } 01121 01122 first = pbuckets; 01123 last = first; 01124 } 01125 01126 private: 01127 01128 //********************************************************************* 01129 /// Adjust the first and last markers according to the new entry. 01130 //********************************************************************* 01131 void adjust_first_last_markers(bucket_t* pbucket) 01132 { 01133 if (pbucket < first) 01134 { 01135 first = pbucket; 01136 } 01137 else if (pbucket > last) 01138 { 01139 last = pbucket; 01140 } 01141 } 01142 01143 // Disable copy construction. 01144 iunordered_set(const iunordered_set&); 01145 01146 /// The pool of data nodes used in the list. 01147 pool_t* pnodepool; 01148 01149 /// The bucket list. 01150 bucket_t* pbuckets; 01151 01152 /// The number of buckets. 01153 const size_t number_of_buckets; 01154 01155 /// The first and last iterators to buckets with values. 01156 bucket_t* first; 01157 bucket_t* last; 01158 01159 /// The function that creates the hashes. 01160 hasher key_hash_function; 01161 01162 /// The function that compares the keys for equality. 01163 key_equal key_equal_function; 01164 01165 /// For library debugging purposes only. 01166 etl::debug_count construct_count; 01167 }; 01168 01169 //*************************************************************************** 01170 /// Equal operator. 01171 ///\param lhs Reference to the first unordered_set. 01172 ///\param rhs Reference to the second unordered_set. 01173 ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> 01174 ///\ingroup unordered_set 01175 //*************************************************************************** 01176 template <typename TKey, typename TMapped, typename TKeyCompare> 01177 bool operator ==(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs) 01178 { 01179 return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); 01180 } 01181 01182 //*************************************************************************** 01183 /// Not equal operator. 01184 ///\param lhs Reference to the first unordered_set. 01185 ///\param rhs Reference to the second unordered_set. 01186 ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> 01187 ///\ingroup unordered_set 01188 //*************************************************************************** 01189 template <typename TKey, typename TMapped, typename TKeyCompare> 01190 bool operator !=(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs) 01191 { 01192 return !(lhs == rhs); 01193 } 01194 01195 //************************************************************************* 01196 /// A templated unordered_set implementation that uses a fixed size buffer. 01197 //************************************************************************* 01198 template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > 01199 class unordered_set : public etl::iunordered_set<TKey, THash, TKeyEqual> 01200 { 01201 private: 01202 01203 typedef etl::iunordered_set<TKey, THash, TKeyEqual> base; 01204 01205 public: 01206 01207 static const size_t MAX_SIZE = MAX_SIZE_; 01208 static const size_t MAX_BUCKETS = MAX_BUCKETS_; 01209 01210 //************************************************************************* 01211 /// Default constructor. 01212 //************************************************************************* 01213 unordered_set() 01214 : base(node_pool, buckets, MAX_BUCKETS) 01215 { 01216 base::initialise(); 01217 } 01218 01219 //************************************************************************* 01220 /// Copy constructor. 01221 //************************************************************************* 01222 unordered_set(const unordered_set& other) 01223 : base(node_pool, buckets, MAX_BUCKETS) 01224 { 01225 base::assign(other.cbegin(), other.cend()); 01226 } 01227 01228 //************************************************************************* 01229 /// Constructor, from an iterator range. 01230 ///\tparam TIterator The iterator type. 01231 ///\param first The iterator to the first element. 01232 ///\param last The iterator to the last element + 1. 01233 //************************************************************************* 01234 template <typename TIterator> 01235 unordered_set(TIterator first_, TIterator last_) 01236 : base(node_pool, buckets, MAX_BUCKETS) 01237 { 01238 base::assign(first_, last_); 01239 } 01240 01241 //************************************************************************* 01242 /// Destructor. 01243 //************************************************************************* 01244 ~unordered_set() 01245 { 01246 base::initialise(); 01247 } 01248 01249 //************************************************************************* 01250 /// Assignment operator. 01251 //************************************************************************* 01252 unordered_set& operator = (const unordered_set& rhs) 01253 { 01254 // Skip if doing self assignment 01255 if (this != &rhs) 01256 { 01257 base::assign(rhs.cbegin(), rhs.cend()); 01258 } 01259 01260 return *this; 01261 } 01262 01263 private: 01264 01265 /// The pool of nodes used for the unordered_set. 01266 etl::pool<typename base::node_t, MAX_SIZE> node_pool; 01267 01268 /// The buckets of node lists. 01269 etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_]; 01270 }; 01271 } 01272 01273 #undef ETL_FILE 01274 01275 #endif 01276
Generated on Tue Jul 12 2022 14:05:45 by
