Changeset 1d5424a 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:
ac68088
Parents:
7320ca6
git-author:
Dzejrou <dzejrou@…> (2018-04-24 16:10:29)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:21)
Message:

cpp: added rehash, reserve, find for hash_table and also equal range for single hash table

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/internal/hash_table.hpp

    r7320ca6 r1d5424a  
    7979        list_node<Value>* head;
    8080
     81        hash_table_bucket()
     82            : head{}
     83        { /* DUMMY BODY */ }
     84
    8185        Size size() const noexcept
    8286        {
     
    104108        void clear()
    105109        {
     110            if (!head)
     111                return;
     112
    106113            auto current = head;
    107114            do
     
    176183            return 0;
    177184        }
     185
     186        template<class Table, class Key>
     187        static pair<
     188            typename Table::iterator,
     189            typename Table::iterator
     190        > equal_range(Table& table, const Key& key)
     191        {
     192            auto it = table.find(key);
     193            return make_pair(it, it);
     194        }
     195
     196        template<class Table, class Key>
     197        static pair<
     198            typename Table::const_iterator,
     199            typename Table::const_iterator
     200        > equal_range_const(Table& table, const Key& key)
     201        { // Note: We cannot overload by return type, so we use a different name.
     202            auto it = table.find(key);
     203            return make_pair(it, it);
     204        }
    178205    };
    179206
     
    215242        {
    216243            // TODO: erase all items with given key
     244        }
     245
     246        template<class Table, class Key>
     247        static pair<
     248            typename Table::iterator,
     249            typename Table::iterator
     250        > equal_range(Table& table, const Key& key)
     251        {
     252            // TODO: implement
     253        }
     254
     255        template<class Table, class Key>
     256        static pair<
     257            typename Table::const_iterator,
     258            typename Table::const_iterator
     259        > equal_range_const(Table& table, const Key& key)
     260        {
     261            // TODO: implement
    217262        }
    218263    };
     
    656701
    657702            hash_table(size_type buckets, float max_load_factor = 1.f)
    658                 : table_{new hash_table_bucket<value_type, size_type>[buckets]},
     703                : table_{new hash_table_bucket<value_type, size_type>[buckets]()},
    659704                  bucket_count_{buckets}, size_{}, hasher_{}, key_eq_{},
    660705                  key_extractor_{}, max_load_factor_{max_load_factor}
     
    714759
    715760            template<class Allocator, class... Args>
    716             iterator emplace(Allocator& alloc, Args&&... args)
    717             {
    718                 // TODO: implement
    719             }
    720 
    721             void insert(const hint_type& where, const value_type& val)
     761            void emplace(const hint_type& where, Allocator& alloc, Args&&... args)
    722762            {
    723763                if (!hint_ok_(where))
    724764                    return;
    725765
    726                 auto node = new list_node<value_type>{val};
     766                auto node = new list_node<value_type>{forward<Args&&>(args)...};
    727767                if (get<1>(where) == nullptr) // Append here will create a new head.
    728768                    get<0>(where)->append(node);
    729769                else // Prepending before an exact position is common in the standard.
     770                    get<1>(where)->prepend(node);
     771
     772                ++size_;
     773                // TODO: if we go over max load factor, rehash
     774            }
     775
     776            void insert(const hint_type& where, const value_type& val)
     777            {
     778                if (!hint_ok_(where))
     779                    return;
     780
     781                auto node = new list_node<value_type>{val};
     782                if (get<1>(where) == nullptr)
     783                    get<0>(where)->append(node);
     784                else
    730785                    get<1>(where)->prepend(node);
    731786
     
    787842            }
    788843
    789             template<class Allocator>
    790844            void swap(hash_table& other)
    791                 noexcept(allocator_traits<Allocator>::is_always_equal::value &&
     845                noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
    792846                         noexcept(swap(declval<Hasher&>(), declval<Hasher&>())) &&
    793847                         noexcept(swap(declval<KeyEq&>(), declval<KeyEq&>())))
     
    813867            iterator find(const key_type& key)
    814868            {
    815                 // TODO: implement
     869                auto idx = get_bucket_idx_(key);
     870                auto head = table_[idx].head;
     871
     872                if (!head)
     873                    return end();
     874
     875                auto current = head;
     876                do
     877                {
     878                    if (key_eq_(key, key_extractor_(current->value)))
     879                        return iterator{table_, idx, size_, current};
     880                    current = current->next;
     881                }
     882                while (current != head);
     883
     884                return end();
    816885            }
    817886
    818887            const_iterator find(const key_type& key) const
    819888            {
    820                 // TODO: implement
     889                auto idx = get_bucket_idx_(key);
     890                auto head = table_[idx].head;
     891
     892                if (!head)
     893                    return end();
     894
     895                auto current = head;
     896                do
     897                {
     898                    if (key_eq_(key, key_extractor_(current->value)))
     899                        return iterator{table_, idx, size_, current};
     900                    current = current->next;
     901                }
     902                while (current != head);
     903
     904                return end();
    821905            }
    822906
     
    828912            pair<iterator, iterator> equal_range(const key_type& key)
    829913            {
    830                 // TODO: implement
     914                return Policy::equal_range(*this, key);
    831915            }
    832916
    833917            pair<const_iterator, const_iterator> equal_range(const key_type& key) const
    834918            {
    835                 // TODO: implement
     919                return Policy::equal_range_const(*this, key);
    836920            }
    837921
     
    903987                 *       can have no effect.
    904988                 */
    905             }
    906 
    907             void rehash(size_type n)
    908             {
    909                 // TODO: implement
    910                 // TODO: exception thrown in rehash means the rehash
    911                 //       has no effect, so we create a new table, insert in it
    912                 //       and then swap
    913             }
    914 
    915             void reserve(size_type n)
    916             {
    917                 // TODO: implement
     989                // TODO: change max factor and rehash if needed
     990            }
     991
     992            void rehash(size_type count)
     993            {
     994                if (count < size_ / max_load_factor_)
     995                    count = size_ / max_load_factor_;
     996
     997                // Note: This is the only place where an exception can be
     998                //       thrown (no mem) in this function, so wrap it
     999                //       in try-catch-rethrow.
     1000                hash_table new_table{count, max_load_factor_};
     1001
     1002                for (std::size_t i = 0; i < bucket_count_; ++i)
     1003                {
     1004                    auto head = table_[i].head;
     1005                    if (!head)
     1006                        continue;
     1007
     1008                    auto current = head;
     1009
     1010                    do
     1011                    {
     1012                        auto next = current->next;
     1013
     1014                        current->next = current;
     1015                        current->prev = current;
     1016
     1017                        auto where = Policy::find_insertion_spot(
     1018                            new_table, key_extractor_(current->value)
     1019                        );
     1020
     1021                        /**
     1022                         * Note: We're rehashing, so we know each
     1023                         *       key can be inserted.
     1024                         */
     1025                        auto new_bucket = get<0>(where);
     1026                        auto new_successor = get<1>(where);
     1027
     1028                        if (new_successor)
     1029                            new_successor->append(current);
     1030                        else
     1031                            new_bucket->append(current);
     1032
     1033                        current = next;
     1034                    } while (current != head);
     1035
     1036                    table_[i].head = nullptr;
     1037                }
     1038
     1039                new_table.size_ = size_;
     1040                swap(new_table);
     1041
     1042                delete[] new_table.table_;
     1043                new_table.table_ = nullptr;
     1044            }
     1045
     1046            void reserve(size_type count)
     1047            {
     1048                rehash(count / max_load_factor_ + 1);
    9181049            }
    9191050
     
    9271058            {
    9281059                // Lists are deleted in ~hash_table_bucket.
    929                 delete[] table_;
     1060                if (table_)
     1061                    delete[] table_;
    9301062            }
    9311063
     
    9661098                //       that is something like:
    9671099                //          return get<1>(hint)->prev->key == key || !bucket.contains(key)
     1100                // TODO: also, make it public and make hint usage one level above?
     1101                //       (since we already have insert with decisive hint)
    9681102                return get<0>(hint) != nullptr && get<2>(hint) < bucket_count_;
    9691103            }
Note: See TracChangeset for help on using the changeset viewer.