Changeset e912cdf 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:
5ae8168
Parents:
ed9df7d
git-author:
Dzejrou <dzejrou@…> (2018-04-25 16:45:01)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:21)
Message:

cpp: refactored unordered_map's insertion functions and moved some logic to the underlying hash table, added rehashing to insertion when it's needed

Location:
uspace/lib/cpp/include
Files:
2 edited

Legend:

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

    red9df7d re912cdf  
    241241            pair<iterator, bool> emplace(Args&&... args)
    242242            {
    243                 // TODO: currently there is code repetition in
    244                 //       3 places, try to find a way to reduce it
     243                /**
     244                 * Note: Some of these modifier functions start off
     245                 *       by incrementing the table's element count and
     246                 *       decrement it when insertion does not take place.
     247                 *       This is because we need to cause rehashing if
     248                 *       there are too many elements, but rehashing itself
     249                 *       would invalidate all pointers we get from
     250                 *       find_insertion_spot, which would require us to
     251                 *       do another find. But this way we avoid two searches
     252                 *       with the possibility of a rehash that is not necessary
     253                 *       (but hardly a bad thing as the table needs just one
     254                 *       element more to rehash).
     255                 *
     256                 *       Also, there are 3 functions with similar bodies,
     257                 *       but the duplicit code cannot be moved to a common
     258                 *       sub-function because all three require different
     259                 *       handling of the value (move, forward and copy).
     260                 */
     261                table_.increment_size();
     262
    245263                auto val = value_type{forward<Args>(args)...};
    246264                auto key = table_.get_key(val);
     
    249267                auto idx = get<2>(spot);
    250268
    251                 if (bucket->head)
     269                if (!bucket)
     270                    return make_pair(end(), false);
     271
     272                auto target = table_.find_node_or_return_head(key, *bucket);
     273                if (target && table_.keys_equal(key, target->value))
    252274                {
    253                     auto head = bucket->head;
    254                     auto current = bucket->head;
    255 
    256                     do
    257                     {
    258                         if (table_.keys_equal(key, current->value))
    259                         {
    260                             return make_pair(iterator{
    261                                 table_.table(), idx,
    262                                 table_.bucket_count(),
    263                                 current
    264                             }, false);
    265                         }
    266                         else
    267                             current = current->next;
    268                     }
    269                     while (current != head);
     275                    table_.decrement_size();
     276                    return make_pair(
     277                        iterator{
     278                            table_.table(), idx, table_.bucket_count(),
     279                            target
     280                        },
     281                        false
     282                    );
    270283                }
    271 
    272                 auto node = new node_type{move(val)};
    273                 bucket->append(node);
    274                 table_.increment_size();
    275 
    276                 return make_pair(iterator{
    277                     table_.table(), idx,
    278                     table_.bucket_count(),
    279                     node
    280                 }, true);
     284                else
     285                {
     286                    auto node = new node_type{move(val)};
     287                    bucket->append(node);
     288
     289                    return make_pair(iterator{
     290                        table_.table(), idx,
     291                        table_.bucket_count(),
     292                        node
     293                    }, true);
     294                }
    281295            }
    282296
     
    289303            pair<iterator, bool> insert(const value_type& val)
    290304            {
     305                table_.increment_size();
     306
    291307                auto key = table_.get_key(val);
    292308                auto spot = table_.find_insertion_spot(key);
     
    294310                auto idx = get<2>(spot);
    295311
    296                 if (bucket->head)
     312                if (!bucket)
     313                    return make_pair(end(), false);
     314
     315                auto target = table_.find_node_or_return_head(key, *bucket);
     316                if (target && table_.keys_equal(key, target->value))
    297317                {
    298                     auto head = bucket->head;
    299                     auto current = bucket->head;
    300 
    301                     do
    302                     {
    303                         if (table_.keys_equal(key, current->value))
    304                         {
    305                             return make_pair(iterator{
    306                                 table_.table(), idx,
    307                                 table_.bucket_count(),
    308                                 current
    309                             }, false);
    310                         }
    311                         else
    312                             current = current->next;
    313                     }
    314                     while (current != head);
     318                    table_.decrement_size();
     319                    return make_pair(
     320                        iterator{
     321                            table_.table(), idx, table_.bucket_count(),
     322                            target
     323                        },
     324                        false
     325                    );
    315326                }
    316 
    317                 auto node = new node_type{val};
    318                 bucket->append(node);
     327                else
     328                {
     329                    auto node = new node_type{val};
     330                    bucket->append(node);
     331
     332                    return make_pair(iterator{
     333                        table_.table(), idx,
     334                        table_.bucket_count(),
     335                        node
     336                    }, true);
     337                }
     338            }
     339
     340            pair<iterator, bool> insert(value_type&& val)
     341            {
    319342                table_.increment_size();
    320343
    321                 return make_pair(iterator{
    322                     table_.table(), idx,
    323                     table_.bucket_count(),
    324                     node
    325                 }, true);
    326             }
    327 
    328             pair<iterator, bool> insert(value_type&& val)
    329             {
    330344                auto key = table_.get_key(val);
    331345                auto spot = table_.find_insertion_spot(key);
     
    333347                auto idx = get<2>(spot);
    334348
    335                 if (bucket->head)
     349                if (!bucket)
     350                    return make_pair(end(), false);
     351
     352                auto target = table_.find_node_or_return_head(key, *bucket);
     353                if (target && table_.keys_equal(key, target->value))
    336354                {
    337                     auto head = bucket->head;
    338                     auto current = bucket->head;
    339 
    340                     do
    341                     {
    342                         if (table_.keys_equal(key, current->value))
    343                         {
    344                             return make_pair(iterator{
    345                                 table_.table(), idx,
    346                                 table_.bucket_count(),
    347                                 current
    348                             }, false);
    349                         }
    350                         else
    351                             current = current->next;
    352                     }
    353                     while (current != head);
     355                    table_.decrement_size();
     356                    return make_pair(
     357                        iterator{
     358                            table_.table(), idx, table_.bucket_count(),
     359                            target
     360                        },
     361                        false
     362                    );
    354363                }
    355 
    356                 auto node = new node_type{forward<value_type>(val)};
    357                 bucket->append(node);
    358                 table_.increment_size();
    359                 // TODO: problem: rehashing here would invalidate the intel we have...
    360 
    361                 return make_pair(iterator{
    362                     table_.table(), idx,
    363                     table_.bucket_count(),
    364                     node
    365                 }, true);
     364                else
     365                {
     366                    auto node = new node_type{forward<value_type>(val)};
     367                    bucket->append(node);
     368
     369                    return make_pair(iterator{
     370                        table_.table(), idx,
     371                        table_.bucket_count(),
     372                        node
     373                    }, true);
     374                }
    366375            }
    367376
  • uspace/lib/cpp/include/internal/hash_table.hpp

    red9df7d re912cdf  
    10021002            void max_load_factor(float factor)
    10031003            {
    1004                 /**
    1005                  * Note: According to the standard, this function
    1006                  *       can have no effect.
    1007                  */
    1008                 // TODO: change max factor and rehash if needed
     1004                if (factor > 0.f)
     1005                    max_load_factor_ = factor;
     1006
     1007                rehash_if_needed();
    10091008            }
    10101009
     
    10811080            }
    10821081
    1083             void set_hint(const_iterator hint)
    1084             {
    1085                 // TODO: hint_ should be a ptr and we extract it here,
    1086                 //       then set it to nullptr after each operation
    1087             }
    1088 
    10891082            hint_type find_insertion_spot(const key_type& key)
    10901083            {
     
    11291122            {
    11301123                ++size_;
     1124
     1125                rehash_if_needed();
     1126            }
     1127
     1128            void decrement_size()
     1129            {
     1130                --size_;
     1131            }
     1132
     1133            node_type* find_node_or_return_head(const key_type& key,
     1134                                                const hash_table_bucket<value_type, size_type>& bucket)
     1135            {
     1136                if (bucket.head)
     1137                {
     1138                    auto head = bucket.head;
     1139                    auto current = bucket.head;
     1140
     1141                    do
     1142                    {
     1143                        if (keys_equal(key, current->value))
     1144                            return current;
     1145                        else
     1146                            current = current->next;
     1147                    }
     1148                    while (current != head);
     1149
     1150                    return head;
     1151                }
     1152                else
     1153                    return nullptr;
    11311154            }
    11321155
Note: See TracChangeset for help on using the changeset viewer.