Changeset 54618da in mainline


Ignore:
Timestamp:
2018-07-05T21:41:21Z (6 years ago)
Author:
Dzejrou <dzejrou@…>
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)
Message:

cpp: implemented - well mostly copypasted, but that's the beauty of our uber table - unordered_set

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/impl/unordered_set.hpp

    r6177cfd r54618da  
    4848        class Alloc = allocator<Key>
    4949    >
    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    };
    51568
    52569    /**
     
    82599                    unordered_set<Key, Hash, Pred, Alloc>& rhs)
    83600    {
    84         // TODO: implement
    85         return false;
     601        return lhs.table_.is_eq_to(rhs.table_);
    86602    }
    87603
     
    97613                    unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
    98614    {
    99         // TODO: implement
    100         return false;
     615        return lhs.table_.is_eq_to(rhs.table_);
    101616    }
    102617
Note: See TracChangeset for help on using the changeset viewer.