Commit 5a07e203 authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook Github Bot

Split get_default() into two for deferred default construction and added...

Split get_default() into two for deferred default construction and added forwarding to speed up default element construction with rvalues

Summary:
As it stood currently folly::get_default() would unnecessarily
construct a value into the third parameter, which was unnecessary in the code
path where the element was found in the map.  Also the default value can be
forwarded to the return type in the code path where the element is not found
and an rvalue parameter is passed as the default value

Reviewed By: yfeldblum

Differential Revision: D6390315

fbshipit-source-id: ef692b827d5a36751b4eb1e12042869e8fbba2e5
parent d7629090
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/Optional.h> #include <folly/Optional.h>
#include <folly/functional/Invoke.h>
#include <tuple> #include <tuple>
namespace folly { namespace folly {
...@@ -26,13 +27,21 @@ namespace folly { ...@@ -26,13 +27,21 @@ namespace folly {
* Given a map and a key, return the value corresponding to the key in the map, * Given a map and a key, return the value corresponding to the key in the map,
* or a given default value if the key doesn't exist in the map. * or a given default value if the key doesn't exist in the map.
*/ */
template <class Map, typename Key = typename Map::key_type> template <typename Map, typename Key>
typename Map::mapped_type get_default( typename Map::mapped_type get_default(const Map& map, const Key& key) {
const Map& map,
const Key& key,
const typename Map::mapped_type& dflt = typename Map::mapped_type()) {
auto pos = map.find(key); auto pos = map.find(key);
return (pos != map.end() ? pos->second : dflt); return (pos != map.end()) ? (pos->second) : (typename Map::mapped_type{});
}
template <
class Map,
typename Key = typename Map::key_type,
typename Value = typename Map::mapped_type,
typename std::enable_if<!is_invocable<Value>::value>::type* = nullptr>
typename Map::mapped_type
get_default(const Map& map, const Key& key, Value&& dflt) {
using M = typename Map::mapped_type;
auto pos = map.find(key);
return (pos != map.end()) ? (pos->second) : M(std::forward<Value>(dflt));
} }
/** /**
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <folly/MapUtil.h> #include <folly/MapUtil.h>
#include <cstddef>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
...@@ -246,3 +247,52 @@ TEST(MapUtil, get_ref_default_path_temporary) { ...@@ -246,3 +247,52 @@ TEST(MapUtil, get_ref_default_path_temporary) {
EXPECT_FALSE(GetRefDefaultPathCompiles<const int&&>::value); EXPECT_FALSE(GetRefDefaultPathCompiles<const int&&>::value);
EXPECT_FALSE(GetRefDefaultPathCompiles<int&&>::value); EXPECT_FALSE(GetRefDefaultPathCompiles<int&&>::value);
} }
namespace {
class TestConstruction {
public:
TestConstruction() {
EXPECT_TRUE(false);
}
TestConstruction(TestConstruction&&) {
EXPECT_TRUE(false);
}
TestConstruction(const TestConstruction&) {
EXPECT_TRUE(false);
}
explicit TestConstruction(std::string&& string)
: string_{std::move(string)} {}
explicit TestConstruction(int&& integer) : integer_{integer} {}
TestConstruction& operator=(const TestConstruction&) = delete;
TestConstruction& operator=(TestConstruction&&) = delete;
int integer_{};
std::string string_{};
};
} // namespace
TEST(MapUtil, test_get_default_deferred_construction) {
auto map = std::unordered_map<int, TestConstruction>{};
map.emplace(
std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(1));
EXPECT_EQ(map.at(1).integer_, 1);
{
auto val = get_default(map, 0, 1);
EXPECT_EQ(val.integer_, 1);
EXPECT_EQ(val.string_, "");
}
{
auto val = get_default(map, 0, "something");
EXPECT_EQ(val.integer_, 0);
EXPECT_EQ(val.string_, "something");
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment