Index: uspace/lib/cpp/include/impl/unordered_map.hpp
===================================================================
--- uspace/lib/cpp/include/impl/unordered_map.hpp	(revision e037873dc81a5f1341a6d29799ba53b5bf1f55f8)
+++ uspace/lib/cpp/include/impl/unordered_map.hpp	(revision 492377af7d41fc373aa032e7323a2c6d57476a35)
@@ -245,56 +245,5 @@
             pair<iterator, bool> emplace(Args&&... args)
             {
-                /**
-                 * Note: Some of these modifier functions start off
-                 *       by incrementing the table's element count and
-                 *       decrement it when insertion does not take place.
-                 *       This is because we need to cause rehashing if
-                 *       there are too many elements, but rehashing itself
-                 *       would invalidate all pointers we get from
-                 *       find_insertion_spot, which would require us to
-                 *       do another find. But this way we avoid two searches
-                 *       with the possibility of a rehash that is not necessary
-                 *       (but hardly a bad thing as the table needs just one
-                 *       element more to rehash).
-                 *
-                 *       Also, there are 3 functions with similar bodies,
-                 *       but the duplicit code cannot be moved to a common
-                 *       sub-function because all three require different
-                 *       handling of the value (move, forward and copy).
-                 */
-                table_.increment_size();
-
-                auto val = value_type{forward<Args>(args)...};
-                auto key = table_.get_key(val);
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
-
-                if (!bucket)
-                    return make_pair(end(), false);
-
-                auto target = table_.find_node_or_return_head(key, *bucket);
-                if (target && table_.keys_equal(key, target->value))
-                {
-                    table_.decrement_size();
-                    return make_pair(
-                        iterator{
-                            table_.table(), idx, table_.bucket_count(),
-                            target
-                        },
-                        false
-                    );
-                }
-                else
-                {
-                    auto node = new node_type{move(val)};
-                    bucket->append(node);
-
-                    return make_pair(iterator{
-                        table_.table(), idx,
-                        table_.bucket_count(),
-                        node
-                    }, true);
-                }
+                return table_.emplace(forward<Args>(args)...);
             }
 
@@ -307,74 +256,10 @@
             pair<iterator, bool> insert(const value_type& val)
             {
-                table_.increment_size();
-
-                auto key = table_.get_key(val);
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
-
-                if (!bucket)
-                    return make_pair(end(), false);
-
-                auto target = table_.find_node_or_return_head(key, *bucket);
-                if (target && table_.keys_equal(key, target->value))
-                {
-                    table_.decrement_size();
-                    return make_pair(
-                        iterator{
-                            table_.table(), idx, table_.bucket_count(),
-                            target
-                        },
-                        false
-                    );
-                }
-                else
-                {
-                    auto node = new node_type{val};
-                    bucket->append(node);
-
-                    return make_pair(iterator{
-                        table_.table(), idx,
-                        table_.bucket_count(),
-                        node
-                    }, true);
-                }
+                return table_.insert(val);
             }
 
             pair<iterator, bool> insert(value_type&& val)
             {
-                table_.increment_size();
-
-                auto key = table_.get_key(val);
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
-
-                if (!bucket)
-                    return make_pair(end(), false);
-
-                auto target = table_.find_node_or_return_head(key, *bucket);
-                if (target && table_.keys_equal(key, target->value))
-                {
-                    table_.decrement_size();
-                    return make_pair(
-                        iterator{
-                            table_.table(), idx, table_.bucket_count(),
-                            target
-                        },
-                        false
-                    );
-                }
-                else
-                {
-                    auto node = new node_type{forward<value_type>(val)};
-                    bucket->append(node);
-
-                    return make_pair(iterator{
-                        table_.table(), idx,
-                        table_.bucket_count(),
-                        node
-                    }, true);
-                }
+                return table_.insert(forward<value_type>(val));
             }
 
@@ -431,12 +316,9 @@
                 table_.increment_size();
 
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
+                auto [bucket, target, idx] = table_.find_insertion_spot(key);
 
                 if (!bucket)
                     return make_pair(end(), false);
 
-                auto target = table_.find_node_or_return_head(key, *bucket);
                 if (target && table_.keys_equal(key, target->value))
                 {
@@ -469,12 +351,9 @@
                 table_.increment_size();
 
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
+                auto [bucket, target, idx] = table_.find_insertion_spot(key);
 
                 if (!bucket)
                     return make_pair(end(), false);
 
-                auto target = table_.find_node_or_return_head(key, *bucket);
                 if (target && table_.keys_equal(key, target->value))
                 {
@@ -519,12 +398,9 @@
                 table_.increment_size();
 
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
+                auto [bucket, target, idx] = table_.find_insertion_spot(key);
 
                 if (!bucket)
                     return make_pair(end(), false);
 
-                auto target = table_.find_node_or_return_head(key, *bucket);
                 if (target && table_.keys_equal(key, target->value))
                 {
@@ -558,12 +434,9 @@
                 table_.increment_size();
 
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
+                auto [bucket, target, idx] = table_.find_insertion_spot(key);
 
                 if (!bucket)
                     return make_pair(end(), false);
 
-                auto target = table_.find_node_or_return_head(key, *bucket);
                 if (target && table_.keys_equal(key, target->value))
                 {
@@ -1046,27 +919,5 @@
             pair<iterator, bool> emplace(Args&&... args)
             {
-                table_.increment_size();
-
-                auto val = value_type{forward<Args>(args)...};
-                auto key = table_.get_key(val);
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
-
-                if (!bucket)
-                    return make_pair(end(), false);
-
-                auto target = table_.find_node_or_return_head(key, *bucket);
-                auto node = new node_type{move(val)};
-                if (target && table_.keys_equal(key, target->value))
-                    target->append(node);
-                else
-                    bucket->prepend(node);
-
-                return make_pair(iterator{
-                    table_.table(), idx,
-                    table_.bucket_count(),
-                    node
-                }, true);
+                return table_.emplace(forward<Args>(args)...);
             }
 
@@ -1079,52 +930,10 @@
             pair<iterator, bool> insert(const value_type& val)
             {
-                table_.increment_size();
-
-                auto key = table_.get_key(val);
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
-
-                if (!bucket)
-                    return make_pair(end(), false);
-
-                auto target = table_.find_node_or_return_head(key, *bucket);
-                auto node = new node_type{val};
-                if (target && table_.keys_equal(key, target->value))
-                    target->append(node);
-                else
-                    bucket->prepend(node);
-
-                return make_pair(iterator{
-                    table_.table(), idx,
-                    table_.bucket_count(),
-                    node
-                }, true);
+                return table_.insert(val);
             }
 
             pair<iterator, bool> insert(value_type&& val)
             {
-                table_.increment_size();
-
-                auto key = table_.get_key(val);
-                auto spot = table_.find_insertion_spot(key);
-                auto bucket = get<0>(spot);
-                auto idx = get<2>(spot);
-
-                if (!bucket)
-                    return make_pair(end(), false);
-
-                auto target = table_.find_node_or_return_head(key, *bucket);
-                auto node = new node_type{forward<value_type>(val)};
-                if (target && table_.keys_equal(key, target->value))
-                    target->append(node);
-                else
-                    bucket->prepend(node);
-
-                return make_pair(iterator{
-                    table_.table(), idx,
-                    table_.bucket_count(),
-                    node
-                }, true);
+                return table_.insert(forward<value_type>(val));
             }
 
Index: uspace/lib/cpp/include/internal/hash_table.hpp
===================================================================
--- uspace/lib/cpp/include/internal/hash_table.hpp	(revision e037873dc81a5f1341a6d29799ba53b5bf1f55f8)
+++ uspace/lib/cpp/include/internal/hash_table.hpp	(revision 492377af7d41fc373aa032e7323a2c6d57476a35)
@@ -215,4 +215,137 @@
             return make_pair(it, ++it);
         }
+
+        /**
+         * Note: We have to duplicate code for emplace, insert(const&)
+         *       and insert(&&) here, because the node (which makes distinction
+         *       between the arguments) is only created if the value isn't
+         *       in the table already.
+         */
+
+        template<class Table, class... Args>
+        static pair<
+            typename Table::iterator, bool
+        > emplace(Table& table, Args&&... args)
+        {
+            using value_type = typename Table::value_type;
+            using node_type  = typename Table::node_type;
+            using iterator   = typename Table::iterator;
+
+            table.increment_size();
+
+            auto val = value_type{forward<Args>(args)...};
+            const auto& key = table.get_key(val);
+            auto [bucket, target, idx] = table.find_insertion_spot(key);
+
+            if (!bucket)
+                return make_pair(table.end(), false);
+
+            if (target && table.keys_equal(key, target->value))
+            {
+                table.decrement_size();
+
+                return make_pair(
+                    iterator{
+                        table.table(), idx, table.bucket_count(),
+                        target
+                    },
+                    false
+                );
+            }
+            else
+            {
+                auto node = new node_type{move(val)};
+                bucket->prepend(node);
+
+                return make_pair(iterator{
+                    table.table(), idx,
+                    table.bucket_count(),
+                    node
+                }, true);
+            }
+        }
+
+        template<class Table, class Value>
+        static pair<
+            typename Table::iterator, bool
+        > insert(Table& table, const Value& val)
+        {
+            using node_type  = typename Table::node_type;
+            using iterator   = typename Table::iterator;
+
+            table.increment_size();
+
+            const auto& key = table.get_key(val);
+            auto [bucket, target, idx] = table.find_insertion_spot(key);
+
+            if (!bucket)
+                return make_pair(table.end(), false);
+
+            if (target && table.keys_equal(key, target->value))
+            {
+                table.decrement_size();
+
+                return make_pair(
+                    iterator{
+                        table.table(), idx, table.bucket_count(),
+                        target
+                    },
+                    false
+                );
+            }
+            else
+            {
+                auto node = new node_type{val};
+                bucket->prepend(node);
+
+                return make_pair(iterator{
+                    table.table(), idx,
+                    table.bucket_count(),
+                    node
+                }, true);
+            }
+        }
+
+        template<class Table, class Value>
+        static pair<
+            typename Table::iterator, bool
+        > insert(Table& table, Value&& val)
+        {
+            using value_type = typename Table::value_type;
+            using node_type  = typename Table::node_type;
+            using iterator   = typename Table::iterator;
+
+            table.increment_size();
+
+            const auto& key = table.get_key(val);
+            auto [bucket, target, idx] = table.find_insertion_spot(key);
+
+            if (!bucket)
+                return make_pair(table.end(), false);
+
+            if (target && table.keys_equal(key, target->value))
+            {
+                table.decrement_size();
+
+                return make_pair(
+                    iterator{
+                        table.table(), idx, table.bucket_count(),
+                        target
+                    },
+                    false
+                );
+            }
+            else
+            {
+                auto node = new node_type{forward<value_type>(val)};
+                bucket->prepend(node);
+
+                return make_pair(iterator{
+                    table.table(), idx,
+                    table.bucket_count(),
+                    node
+                }, true);
+            }
+        }
     };
 
@@ -340,4 +473,68 @@
             return make_pair(first, last);
         }
+
+        template<class Table, class... Args>
+        static pair<
+            typename Table::iterator, bool
+        > emplace(Table& table, Args&&... args)
+        {
+            using node_type  = typename Table::node_type;
+
+            auto node = new node_type{forward<Args>(args)...};
+
+            return insert(table, node);
+        }
+
+        template<class Table, class Value>
+        static pair<
+            typename Table::iterator, bool
+        > insert(Table& table, const Value& val)
+        {
+            using node_type  = typename Table::node_type;
+
+            auto node = new node_type{val};
+
+            return insert(table, node);
+        }
+
+        template<class Table, class Value>
+        static pair<
+            typename Table::iterator, bool
+        > insert(Table& table, Value&& val)
+        {
+            using value_type = typename Table::value_type;
+            using node_type  = typename Table::node_type;
+
+            auto node = new node_type{forward<value_type>(val)};
+
+            return insert(table, node);
+        }
+
+        template<class Table>
+        static pair<
+            typename Table::iterator, bool
+        > insert(Table& table, typename Table::node_type* node)
+        {
+            using iterator   = typename Table::iterator;
+
+            table.increment_size();
+
+            const auto& key = table.get_key(node->value);
+            auto [bucket, target, idx] = table.find_insertion_spot(key);
+
+            if (!bucket)
+                return make_pair(table.end(), false);
+
+            if (target && table.keys_equal(key, target->value))
+                target->append(node);
+            else
+                bucket->prepend(node);
+
+            return make_pair(iterator{
+                table.table(), idx,
+                table.bucket_count(),
+                node
+            }, true);
+        }
     };
 
@@ -885,51 +1082,18 @@
             }
 
-            template<class Allocator, class... Args>
-            void emplace(const hint_type& where, Allocator& alloc, Args&&... args)
-            {
-                if (!hint_ok_(where))
-                    return;
-
-                auto node = new list_node<value_type>{forward<Args&&>(args)...};
-                if (get<1>(where) == nullptr) // Append here will create a new head.
-                    get<0>(where)->append(node);
-                else // Prepending before an exact position is common in the standard.
-                    get<1>(where)->prepend(node);
-
-                ++size_;
-
-                rehash_if_needed();
-            }
-
-            void insert(const hint_type& where, const value_type& val)
-            {
-                if (!hint_ok_(where))
-                    return;
-
-                auto node = new list_node<value_type>{val};
-                if (get<1>(where) == nullptr)
-                    get<0>(where)->append(node);
-                else
-                    get<1>(where)->prepend(node);
-
-                ++size_;
-
-                rehash_if_needed();
-            }
-
-            void insert(const hint_type& where, value_type&& val)
-            {
-                if (!hint_ok_(where))
-                    return;
-
-                auto node = new list_node<value_type>{forward<value_type>(val)};
-                if (get<1>(where) == nullptr)
-                    get<0>(where)->append(node);
-                else
-                    get<1>(where)->prepend(node);
-
-                ++size_;
-
-                rehash_if_needed();
+            template<class... Args>
+            pair<iterator, bool> emplace(Args&&... args)
+            {
+                return Policy::emplace(*this, forward<Args>(args)...);
+            }
+
+            pair<iterator, bool> insert(const value_type& val)
+            {
+                return Policy::insert(*this, val);
+            }
+
+            pair<iterator, bool> insert(value_type&& val)
+            {
+                return Policy::insert(*this, forward<value_type>(val));
             }
 
@@ -1251,27 +1415,4 @@
             }
 
-            node_type* find_node_or_return_head(const key_type& key,
-                                                const hash_table_bucket<value_type, size_type>& bucket)
-            {
-                if (bucket.head)
-                {
-                    auto head = bucket.head;
-                    auto current = bucket.head;
-
-                    do
-                    {
-                        if (keys_equal(key, current->value))
-                            return current;
-                        else
-                            current = current->next;
-                    }
-                    while (current != head);
-
-                    return head;
-                }
-                else
-                    return nullptr;
-            }
-
         private:
             hash_table_bucket<value_type, size_type>* table_;
@@ -1290,16 +1431,4 @@
             }
 
-            bool hint_ok_(const hint_type& hint)
-            {
-                // TODO: pass this to the policy, because the multi policy
-                //       will need to check if a similar key is close,
-                //       that is something like:
-                //          return get<1>(hint)->prev->key == key || !bucket.contains(key)
-                // TODO: also, make it public and make hint usage one level above?
-                //       (since we already have insert with decisive hint)
-                return get<0>(hint) != nullptr && get<2>(hint) < bucket_count_;
-            }
-
-            // Praise C++11 for this.
             friend Policy;
     };
