diff --git a/sparsehash/internal/sparsehashtable.h b/sparsehash/internal/sparsehashtable.h index efdba9a..5fd6967 100644 --- a/sparsehash/internal/sparsehashtable.h +++ b/sparsehash/internal/sparsehashtable.h @@ -950,22 +950,8 @@ class sparse_hashtable { // INSERTION ROUTINES private: // Private method used by insert_noresize and find_or_insert. - iterator insert_at(const_reference obj, size_type pos) { - if (size() >= max_size()) { - throw std::length_error("insert overflow"); - } - if (test_deleted(pos)) { // just replace if it's been deleted - // The set() below will undelete this object. We just worry about - // stats - assert(num_deleted > 0); - --num_deleted; // used to be, now it isn't - } - table.set(pos, obj); - return iterator(this, table.get_iter(pos), table.nonempty_end()); - } - template - iterator emplace_at(size_type pos, Args&&... args) { + iterator insert_at(size_type pos, Args&&... args) { if (size() >= max_size()) { throw std::length_error("insert overflow"); } @@ -975,28 +961,13 @@ class sparse_hashtable { assert(num_deleted > 0); --num_deleted; // used to be, now it isn't } - table.set_inplace(pos, std::forward(args)...); + table.set(pos, std::forward(args)...); return iterator(this, table.get_iter(pos), table.nonempty_end()); } // If you know *this is big enough to hold obj, use this routine - std::pair insert_noresize(const_reference obj) { - // First, double-check we're not inserting delkey - assert( - (!settings.use_deleted() || !equals(get_key(obj), key_info.delkey)) && - "Inserting the deleted key"); - const std::pair pos = find_position(get_key(obj)); - if (pos.first != ILLEGAL_BUCKET) { // object was already there - return std::pair( - iterator(this, table.get_iter(pos.first), table.nonempty_end()), - false); // false: we didn't insert - } else { // pos.second says where to put it - return std::pair(insert_at(obj, pos.second), true); - } - } - template - std::pair emplace_noresize(K&& key, Args&&... args) { + std::pair insert_noresize(K&& key, Args&&... args) { // First, double-check we're not inserting delkey assert( (!settings.use_deleted() || !equals(key, key_info.delkey)) && @@ -1008,7 +979,7 @@ class sparse_hashtable { false); // false: we didn't insert } else { // pos.second says where to put it return std::pair( - emplace_at(pos.second, std::forward(args)...), + insert_at(pos.second, std::forward(args)...), true); } } @@ -1023,7 +994,7 @@ class sparse_hashtable { } resize_delta(static_cast(dist)); for (; dist > 0; --dist, ++f) { - insert_noresize(*f); + insert_noresize(get_key(*f), *f); } } @@ -1035,23 +1006,24 @@ class sparse_hashtable { public: // This is the normal insert routine, used by the outside world - std::pair insert(const_reference obj) { + template + std::pair insert(Arg&& obj) { resize_delta(1); // adding an object, grow if need be - return insert_noresize(obj); + return insert_noresize(get_key(std::forward(obj)), std::forward(obj)); } template std::pair emplace(K&& key, Args&&... args) { resize_delta(1); // here we push key twice as we need it once for the indexing, and the rest of the params are for the emplace itself - return emplace_noresize(std::forward(key), std::forward(key), std::forward(args)...); + return insert_noresize(std::forward(key), std::forward(key), std::forward(args)...); } template std::pair try_emplace(K&& key, Args&&... args) { resize_delta(1); // here we push key as we need it for the indexing, and the rest of the params are for the emplace itself - return emplace_noresize(std::forward(key), std::piecewise_construct, + return insert_noresize(std::forward(key), std::piecewise_construct, std::forward_as_tuple(std::forward(key)), std::forward_as_tuple(std::forward(args)...)); } @@ -1064,23 +1036,20 @@ class sparse_hashtable { typename std::iterator_traits::iterator_category()); } - // DefaultValue is a functor that takes a key and returns a value_type - // representing the default value to be inserted if none is found. - template - value_type& find_or_insert(const key_type& key) { + template + value_type& find_or_insert(K&& key) { // First, double-check we're not inserting delkey assert((!settings.use_deleted() || !equals(key, key_info.delkey)) && "Inserting the deleted key"); const std::pair pos = find_position(key); - DefaultValue default_value; if (pos.first != ILLEGAL_BUCKET) { // object was already there return *table.get_iter(pos.first); } else if (resize_delta(1)) { // needed to rehash to make room // Since we resized, we can't use pos, so recalculate where to // insert. - return *insert_noresize(default_value(key)).first; + return *insert_noresize(std::forward(key), std::forward(key), T()).first; } else { // no need to rehash, insert right here - return *insert_at(default_value(key), pos.second); + return *insert_at(pos.second, std::forward(key), T()); } } diff --git a/sparsehash/sparse_hash_map b/sparsehash/sparse_hash_map index 756134b..5fb0bb0 100644 --- a/sparsehash/sparse_hash_map +++ b/sparsehash/sparse_hash_map @@ -251,7 +251,7 @@ class sparse_hash_map { // If key is in the hashtable, returns find(key)->second, // otherwise returns insert(value_type(key, T()).first->second. // Note it does not create an empty T unless the find fails. - return rep.template find_or_insert(key).second; + return rep.template find_or_insert(key).second; } size_type count(const key_type& key) const { return rep.count(key); } diff --git a/sparsehash/sparsetable b/sparsehash/sparsetable index 66f3bdf..787116b 100644 --- a/sparsehash/sparsetable +++ b/sparsehash/sparsetable @@ -1140,30 +1140,11 @@ class sparsegroup { } public: - // This returns a reference to the inserted item (which is a copy of val). + // Creates the inserted item in-place, and returns a reference to the inserted item. // TODO(austern): Make this exception safe: handle exceptions from // value_type's copy constructor. - reference set(size_type i, const_reference val) { - size_type offset = - pos_to_offset(bitmap, i); // where we'll find (or insert) - if (bmtest(i)) { - // Delete the old value, which we're replacing with the new one - group[offset].~value_type(); - } else { - set_aux(offset, realloc_and_memmove_ok()); - ++settings.num_buckets; - bmset(i); - } - // This does the actual inserting. Since we made the array using - // malloc, we use "placement new" to just call the constructor. - new (&group[offset]) value_type(val); - return group[offset]; - } - - // Creates the inserted item in-place, and returns a reference to the inserted item. - // TODO: same as set() - handle exceptions from the constructor template - reference set_inplace(size_type i, Args&&... args) { + reference set(size_type i, Args&&... args) { size_type offset = pos_to_offset(bitmap, i); // where we'll find (or insert) if (bmtest(i)) { @@ -1637,25 +1618,16 @@ class sparsetable { groups[current_row].offset_to_pos(current_col)); } - // This returns a reference to the inserted item (which is a copy of val) + // This returns a reference to the inserted item, after creating it + // in-place by forwarding its constructor arguments. // The trick is to figure out whether we're replacing or inserting anew - reference set(size_type i, const_reference val) { - assert(i < settings.table_size); - typename group_type::size_type old_numbuckets = - which_group(i).num_nonempty(); - reference retval = which_group(i).set(pos_in_group(i), val); - settings.num_buckets += which_group(i).num_nonempty() - old_numbuckets; - return retval; - } - - // Creates the element to be inserted in-place by forwarding its constructor arguments template - reference set_inplace(size_type i, Args&&... args) { + reference set(size_type i, Args&&... args) { assert(i < settings.table_size); typename group_type::size_type old_numbuckets = which_group(i).num_nonempty(); reference retval = - which_group(i).set_inplace(pos_in_group(i), std::forward(args)...); + which_group(i).set(pos_in_group(i), std::forward(args)...); settings.num_buckets += which_group(i).num_nonempty() - old_numbuckets; return retval; }