Skip to content

Commit

Permalink
Allow ptr to map in folly MapUtils
Browse files Browse the repository at this point in the history
Summary:
Allow passing a ptr into `folly::get_ptr(map, key)`.

There is some code that looks like:

```
auto foo(const MyMap* map) {
  if (map != nullptr && map.contains(k)) {
     auto& v = map.at(k);
     // do stuff with v
  }
}
```

That can now be re-written as:

```
auto foo(const MyMap* map) {
  if (const auto* vPtr = folly::get_ptr(map, k)) {
     auto& v = *vPtr;
     // do stuff with v
  }
}
```

Reviewed By: yfeldblum

Differential Revision: D64054668

fbshipit-source-id: 7ef52d5f4ef751ad796ba4a950b8358e14c7d0c7
  • Loading branch information
cjhawley authored and facebook-github-bot committed Oct 9, 2024
1 parent 02547bf commit ec7513e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 5 deletions.
47 changes: 42 additions & 5 deletions folly/container/MapUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,20 +174,31 @@ const typename Map::mapped_type& get_ref_default(
* the key in the map, or nullptr if the key doesn't exist in the map.
*/
template <class Map, typename Key = typename Map::key_type>
const auto* get_ptr(const Map& map, const Key& key) {
auto get_ptr(const Map& map, const Key& key) {
auto pos = map.find(key);
return (pos != map.end() ? &pos->second : nullptr);
}
template <class Map, typename Key = typename Map::key_type>
const typename Map::mapped_type* FOLLY_NULLABLE
get_ptr(const Map* FOLLY_NULLABLE map, const Key& key) {
return map ? get_ptr(*map, key) : nullptr;
}

/**
* Non-const overload of the above.
*/
template <class Map, typename Key = typename Map::key_type>
auto* get_ptr(Map& map, const Key& key) {
auto get_ptr(Map& map, const Key& key) {
auto pos = map.find(key);
return (pos != map.end() ? &pos->second : nullptr);
}

template <class Map, typename Key = typename Map::key_type>
typename Map::mapped_type* FOLLY_NULLABLE
get_ptr(Map* FOLLY_NULLABLE map, const Key& key) {
return map ? get_ptr(*map, key) : nullptr;
}

/**
* Same as `get_ptr` but for `find` variants that search for two keys at once.
*/
Expand Down Expand Up @@ -226,7 +237,9 @@ template <
size_t pathLength,
class = typename std::enable_if<(pathLength > 0)>::type>
struct NestedMapType {
using type = typename NestedMapType<T, pathLength - 1>::type::mapped_type;
using type =
typename NestedMapType<std::remove_pointer_t<T>, pathLength - 1>::type::
mapped_type;
};

template <class T>
Expand Down Expand Up @@ -275,18 +288,42 @@ auto get_optional(
template <class Map, class Key1, class Key2, class... Keys>
auto get_ptr(
const Map& map, const Key1& key1, const Key2& key2, const Keys&... keys) ->
typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::type const* {
typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::type
const* FOLLY_NULLABLE {
auto pos = map.find(key1);
return pos != map.end() ? get_ptr(pos->second, key2, keys...) : nullptr;
}

template <class Map, class Key1, class Key2, class... Keys>
auto get_ptr(
const Map* FOLLY_NULLABLE map,
const Key1& key1,
const Key2& key2,
const Keys&... keys) ->
typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::type
const* FOLLY_NULLABLE {
return map ? get_ptr(*map, key1, key2, keys...) : nullptr;
}

template <class Map, class Key1, class Key2, class... Keys>
auto get_ptr(Map& map, const Key1& key1, const Key2& key2, const Keys&... keys)
-> typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::type* {
-> typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::
type* FOLLY_NULLABLE {
auto pos = map.find(key1);
return pos != map.end() ? get_ptr(pos->second, key2, keys...) : nullptr;
}

template <class Map, class Key1, class Key2, class... Keys>
auto get_ptr(
Map* FOLLY_NULLABLE map,
const Key1& key1,
const Key2& key2,
const Keys&... keys) ->
typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::
type* FOLLY_NULLABLE {
return map ? get_ptr(*map, key1, key2, keys...) : nullptr;
}

/**
* Given a map and a path of keys, return the value corresponding to the nested
* value, or a given default value if the path doesn't exist in the map.
Expand Down
9 changes: 9 additions & 0 deletions folly/container/test/MapUtilTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ TEST(MapUtil, getPtr) {
EXPECT_TRUE(get_ptr(m, 2) == nullptr);
*get_ptr(m, 1) = 4;
EXPECT_EQ(4, m.at(1));
EXPECT_EQ(4, *get_ptr(&m, 1));

std::map<int, int>* nullMap = nullptr;
EXPECT_EQ(nullptr, get_ptr(nullMap, 2));
}

TEST(MapUtil, getPtr2) {
Expand Down Expand Up @@ -184,6 +188,11 @@ TEST(MapUtil, getPtrPathSimple) {
EXPECT_EQ(6, *get_ptr(cm, 1, 2, 3, 4));
EXPECT_TRUE(get_ptr(cm, 1, 2, 3, 4));
EXPECT_FALSE(get_ptr(cm, 1, 2, 3, 0));

EXPECT_EQ(6, *get_ptr(&cm, 1, 2, 3, 4));

map<int, map<int, map<int, map<int, int>>>>* nullMap = nullptr;
EXPECT_EQ(nullptr, get_ptr(nullMap, 1, 2, 3, 4));
}

TEST(MapUtil, getPtrPathMixed) {
Expand Down

0 comments on commit ec7513e

Please sign in to comment.