Changeset 54618da in mainline
- Timestamp:
- 2018-07-05T21:41:21Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7f379fe
- Parents:
- 6177cfd
- git-author:
- Dzejrou <dzejrou@…> (2018-04-25 20:15:42)
- git-committer:
- Dzejrou <dzejrou@…> (2018-07-05 21:41:21)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/cpp/include/impl/unordered_set.hpp
r6177cfd r54618da 48 48 class Alloc = allocator<Key> 49 49 > 50 class unordered_set; 50 class unordered_set 51 { 52 public: 53 using key_type = Key; 54 using value_type = Key; 55 using hasher = Hash; 56 using key_equal = Pred; 57 using allocator_type = Alloc; 58 using pointer = typename allocator_traits<allocator_type>::pointer; 59 using const_pointer = typename allocator_traits<allocator_type>::const_pointer; 60 using reference = value_type&; 61 using const_reference = const value_type&; 62 using size_type = size_t; 63 using difference_type = ptrdiff_t; 64 65 /** 66 * Note: Both the iterator and const_iterator (and their local variants) 67 * types are constant iterators, the standard does not require them 68 * to be the same type, but why not? :) 69 */ 70 using iterator = aux::hash_table_const_iterator< 71 value_type, const_reference, const_pointer, size_type 72 >; 73 using const_iterator = iterator; 74 using local_iterator = aux::hash_table_const_local_iterator< 75 value_type, const_reference, const_pointer 76 >; 77 using const_local_iterator = local_iterator; 78 79 /** 80 * Note: We need () to delegate the constructor, 81 * otherwise it could be deduced as the initializer 82 * list constructor when size_type is convertible 83 * to value_type. 84 */ 85 unordered_set() 86 : unordered_set(default_bucket_count_) 87 { /* DUMMY BODY */ } 88 89 explicit unordered_set(size_type bucket_count, 90 const hasher& hf = hasher{}, 91 const key_equal& eql = key_equal{}, 92 const allocator_type& alloc = allocator_type{}) 93 : table_{bucket_count, hf, eql}, allocator_{alloc} 94 { /* DUMMY BODY */ } 95 96 template<class InputIterator> 97 unordered_set(InputIterator first, InputIterator last, 98 size_type bucket_count = default_bucket_count_, 99 const hasher& hf = hasher{}, 100 const key_equal& eql = key_equal{}, 101 const allocator_type& alloc = allocator_type{}) 102 : unordered_set{bucket_count, hf, eql, alloc} 103 { 104 insert(first, last); 105 } 106 107 unordered_set(const unordered_set& other) 108 : unordered_set{other, other.allocator_} 109 { /* DUMMY BODY */ } 110 111 unordered_set(unordered_set&& other) 112 : table_{move(other.table_)}, allocator_{move(other.allocator_)} 113 { /* DUMMY BODY */ } 114 115 explicit unordered_set(const allocator_type& alloc) 116 : table_{default_bucket_count_}, allocator_{alloc} 117 { /* DUMMY BODY */ } 118 119 unordered_set(const unordered_set& other, const allocator_type& alloc) 120 : table_{other.table_}, allocator_{alloc} 121 { /* DUMMY BODY */ } 122 123 unordered_set(unordered_set&& other, const allocator_type& alloc) 124 : table_{move(other.table_)}, allocator_{alloc} 125 { /* DUMMY BODY */ } 126 127 unordered_set(initializer_list<value_type> init, 128 size_type bucket_count = default_bucket_count_, 129 const hasher& hf = hasher{}, 130 const key_equal& eql = key_equal{}, 131 const allocator_type& alloc = allocator_type{}) 132 : unordered_set{bucket_count, hf, eql, alloc} 133 { 134 insert(init.begin(), init.end()); 135 } 136 137 unordered_set(size_type bucket_count, const allocator_type& alloc) 138 : unordered_set{bucket_count, hasher{}, key_equal{}, alloc} 139 { /* DUMMY BODY */ } 140 141 unordered_set(size_type bucket_count, const hasher& hf, const allocator_type& alloc) 142 : unordered_set{bucket_count, hf, key_equal{}, alloc} 143 { /* DUMMY BODY */ } 144 145 template<class InputIterator> 146 unordered_set(InputIterator first, InputIterator last, 147 size_type bucket_count, const allocator_type& alloc) 148 : unordered_set{first, last, bucket_count, hasher{}, key_equal{}, alloc} 149 { /* DUMMY BODY */ } 150 151 template<class InputIterator> 152 unordered_set(InputIterator first, InputIterator last, 153 size_type bucket_count, const hasher& hf, const allocator_type& alloc) 154 : unordered_set{first, last, bucket_count, hf, key_equal{}, alloc} 155 { /* DUMMY BODY */ } 156 157 unordered_set(initializer_list<value_type> init, size_type bucket_count, 158 const allocator_type& alloc) 159 : unordered_set{init, bucket_count, hasher{}, key_equal{}, alloc} 160 { /* DUMMY BODY */ } 161 162 unordered_set(initializer_list<value_type> init, size_type bucket_count, 163 const hasher& hf, const allocator_type& alloc) 164 : unordered_set{init, bucket_count, hf, key_equal{}, alloc} 165 { /* DUMMY BODY */ } 166 167 ~unordered_set() 168 { /* DUMMY BODY */ } 169 170 unordered_set& operator=(const unordered_set& other) 171 { 172 table_ = other.table_; 173 allocator_ = other.allocator_; 174 175 return *this; 176 } 177 178 unordered_set& operator=(unordered_set&& other) 179 noexcept(allocator_traits<allocator_type>::is_always_equal::value && 180 is_nothrow_move_assignable<hasher>::value && 181 is_nothrow_move_assignable<key_equal>::value) 182 { 183 table_ = move(other.table_); 184 allocator_ = move(other.allocator_); 185 186 return *this; 187 } 188 189 unordered_set& operator=(initializer_list<value_type>& init) 190 { 191 table_.clear(); 192 table_.reserve(init.size()); 193 194 insert(init.begin(), init.end()); 195 196 return *this; 197 } 198 199 allocator_type get_allocator() const noexcept 200 { 201 return allocator_; 202 } 203 204 bool empty() const noexcept 205 { 206 return table_.empty(); 207 } 208 209 size_type size() const noexcept 210 { 211 return table_.size(); 212 } 213 214 size_type max_size() const noexcept 215 { 216 return table_.max_size(allocator_); 217 } 218 219 iterator begin() noexcept 220 { 221 return table_.begin(); 222 } 223 224 const_iterator begin() const noexcept 225 { 226 return table_.begin(); 227 } 228 229 iterator end() noexcept 230 { 231 return table_.end(); 232 } 233 234 const_iterator end() const noexcept 235 { 236 return table_.end(); 237 } 238 239 const_iterator cbegin() const noexcept 240 { 241 return table_.cbegin(); 242 } 243 244 const_iterator cend() const noexcept 245 { 246 return table_.cend(); 247 } 248 249 template<class... Args> 250 pair<iterator, bool> emplace(Args&&... args) 251 { 252 /** 253 * Note: Some of these modifier functions start off 254 * by incrementing the table's element count and 255 * decrement it when insertion does not take place. 256 * This is because we need to cause rehashing if 257 * there are too many elements, but rehashing itself 258 * would invalidate all pointers we get from 259 * find_insertion_spot, which would require us to 260 * do another find. But this way we avoid two searches 261 * with the possibility of a rehash that is not necessary 262 * (but hardly a bad thing as the table needs just one 263 * element more to rehash). 264 * 265 * Also, there are 3 functions with similar bodies, 266 * but the duplicit code cannot be moved to a common 267 * sub-function because all three require different 268 * handling of the value (move, forward and copy). 269 */ 270 table_.increment_size(); 271 272 auto val = value_type{forward<Args>(args)...}; 273 auto spot = table_.find_insertion_spot(val); 274 auto bucket = get<0>(spot); 275 auto idx = get<2>(spot); 276 277 if (!bucket) 278 return make_pair(end(), false); 279 280 auto target = table_.find_node_or_return_head(val, *bucket); 281 if (target && table_.keys_equal(val, target->value)) 282 { 283 table_.decrement_size(); 284 return make_pair( 285 iterator{ 286 table_.table(), idx, table_.bucket_count(), 287 target 288 }, 289 false 290 ); 291 } 292 else 293 { 294 auto node = new node_type{move(val)}; 295 bucket->append(node); 296 297 return make_pair(iterator{ 298 table_.table(), idx, 299 table_.bucket_count(), 300 node 301 }, true); 302 } 303 } 304 305 template<class... Args> 306 iterator emplace_hint(const_iterator, Args&&... args) 307 { 308 return emplace(forward<Args>(args)...).first; 309 } 310 311 pair<iterator, bool> insert(const value_type& val) 312 { 313 table_.increment_size(); 314 315 auto spot = table_.find_insertion_spot(val); 316 auto bucket = get<0>(spot); 317 auto idx = get<2>(spot); 318 319 if (!bucket) 320 return make_pair(end(), false); 321 322 auto target = table_.find_node_or_return_head(val, *bucket); 323 if (target && table_.keys_equal(val, target->value)) 324 { 325 table_.decrement_size(); 326 return make_pair( 327 iterator{ 328 table_.table(), idx, table_.bucket_count(), 329 target 330 }, 331 false 332 ); 333 } 334 else 335 { 336 auto node = new node_type{val}; 337 bucket->append(node); 338 339 return make_pair(iterator{ 340 table_.table(), idx, 341 table_.bucket_count(), 342 node 343 }, true); 344 } 345 } 346 347 pair<iterator, bool> insert(value_type&& val) 348 { 349 table_.increment_size(); 350 351 auto spot = table_.find_insertion_spot(val); 352 auto bucket = get<0>(spot); 353 auto idx = get<2>(spot); 354 355 if (!bucket) 356 return make_pair(end(), false); 357 358 auto target = table_.find_node_or_return_head(val, *bucket); 359 if (target && table_.keys_equal(val, target->value)) 360 { 361 table_.decrement_size(); 362 return make_pair( 363 iterator{ 364 table_.table(), idx, table_.bucket_count(), 365 target 366 }, 367 false 368 ); 369 } 370 else 371 { 372 auto node = new node_type{forward<value_type>(val)}; 373 bucket->append(node); 374 375 return make_pair(iterator{ 376 table_.table(), idx, 377 table_.bucket_count(), 378 node 379 }, true); 380 } 381 } 382 383 iterator insert(const_iterator, const value_type& val) 384 { 385 return insert(val).first; 386 } 387 388 iterator insert(const_iterator, value_type&& val) 389 { 390 return insert(forward<value_type>(val)).first; 391 } 392 393 template<class InputIterator> 394 void insert(InputIterator first, InputIterator last) 395 { 396 while (first != last) 397 insert(*first++); 398 } 399 400 void insert(initializer_list<value_type> init) 401 { 402 insert(init.begin(), init.end()); 403 } 404 405 iterator erase(const_iterator position) 406 { 407 return table_.erase(position); 408 } 409 410 size_type erase(const key_type& key) 411 { 412 return table_.erase(key); 413 } 414 415 iterator erase(const_iterator first, const_iterator last) 416 { 417 while (first != last) 418 first = erase(first); 419 420 return iterator{ 421 table_.table(), first.idx(), 422 table_.bucket_count(), table_.head(first.idx()) 423 }; // TODO: why do we pass table_.head(first.idx()) here? 424 } 425 426 void clear() noexcept 427 { 428 table_.clear(); 429 } 430 431 void swap(unordered_set& other) 432 noexcept(allocator_traits<allocator_type>::is_always_equal::value && 433 noexcept(std::swap(declval<hasher>(), declval<hasher>())) && 434 noexcept(std::swap(declval<key_equal>(), declval<key_equal>()))) 435 { 436 table_.swap(other.table_); 437 std::swap(allocator_, other.allocator_); 438 } 439 440 hasher hash_function() const 441 { 442 return table_.hash_function(); 443 } 444 445 key_equal key_eq() const 446 { 447 return table_.key_eq(); 448 } 449 450 iterator find(const key_type& key) 451 { 452 return table_.find(key); 453 } 454 455 const_iterator find(const key_type& key) const 456 { 457 return table_.find(key); 458 } 459 460 size_type count(const key_type& key) const 461 { 462 return table_.count(key); 463 } 464 465 pair<iterator, iterator> equal_range(const key_type& key) 466 { 467 return table_.equal_range(key); 468 } 469 470 pair<const_iterator, const_iterator> equal_range(const key_type& key) const 471 { 472 return table_.equal_range(key); 473 } 474 475 size_type bucket_count() const noexcept 476 { 477 return table_.bucket_count(); 478 } 479 480 size_type max_bucket_count() const noexcept 481 { 482 return table_.max_bucket_count(); 483 } 484 485 size_type bucket_size(size_type idx) const 486 { 487 return table_.bucket_size(idx); 488 } 489 490 size_type bucket(const key_type& key) const 491 { 492 return table_.bucket(key); 493 } 494 495 local_iterator begin(size_type idx) 496 { 497 return table_.begin(idx); 498 } 499 500 const_local_iterator begin(size_type idx) const 501 { 502 return table_.begin(idx); 503 } 504 505 local_iterator end(size_type idx) 506 { 507 return table_.end(idx); 508 } 509 510 const_local_iterator end(size_type idx) const 511 { 512 return table_.end(idx); 513 } 514 515 const_local_iterator cbegin(size_type idx) const 516 { 517 return table_.cbegin(idx); 518 } 519 520 const_local_iterator cend(size_type idx) const 521 { 522 return table_.cend(idx); 523 } 524 525 float load_factor() const noexcept 526 { 527 return table_.load_factor(); 528 } 529 530 float max_load_factor() const noexcept 531 { 532 return table_.max_load_factor(); 533 } 534 535 void max_load_factor(float factor) 536 { 537 table_.max_load_factor(factor); 538 } 539 540 void rehash(size_type bucket_count) 541 { 542 table_.rehash(bucket_count); 543 } 544 545 void reserve(size_type count) 546 { 547 table_.reserve(count); 548 } 549 550 private: 551 using table_type = aux::hash_table< 552 key_type, key_type, aux::key_no_value_key_extractor<key_type>, 553 hasher, key_equal, allocator_type, size_type, 554 iterator, const_iterator, local_iterator, const_local_iterator, 555 aux::hash_single_policy 556 >; 557 using node_type = typename table_type::node_type; 558 559 table_type table_; 560 allocator_type allocator_; 561 562 static constexpr size_type default_bucket_count_{16}; 563 564 template<class K, class H, class P, class A> 565 friend bool operator==(unordered_set<K, H, P, A>&, 566 unordered_set<K, H, P, A>&); 567 }; 51 568 52 569 /** … … 82 599 unordered_set<Key, Hash, Pred, Alloc>& rhs) 83 600 { 84 // TODO: implement 85 return false; 601 return lhs.table_.is_eq_to(rhs.table_); 86 602 } 87 603 … … 97 613 unordered_multiset<Key, Hash, Pred, Alloc>& rhs) 98 614 { 99 // TODO: implement 100 return false; 615 return lhs.table_.is_eq_to(rhs.table_); 101 616 } 102 617
Note:
See TracChangeset
for help on using the changeset viewer.