return (pos != map.end() ? &pos->second : nullptr);
}
+namespace detail {
+template <
+ class T,
+ size_t pathLength,
+ class = typename std::enable_if<(pathLength > 0)>::type>
+struct NestedMapType {
+ using type = typename NestedMapType<T, pathLength - 1>::type::mapped_type;
+};
+
+template <class T>
+struct NestedMapType<T, 1> {
+ using type = typename T::mapped_type;
+};
+}
+
+/**
+ * Given a map of maps and a path of keys, return a pointer to the nested value,
+ * or nullptr if the key doesn't exist in the map.
+ */
+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* {
+ 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& map, const Key1& key1, const Key2& key2, const Keys&... keys)
+ -> typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::type* {
+ auto pos = map.find(key1);
+ return pos != map.end() ? get_ptr(pos->second, key2, keys...) : nullptr;
+}
+
} // namespace folly
#include <folly/MapUtil.h>
#include <map>
+#include <unordered_map>
#include <folly/portability/GTest.h>
*get_ptr(m, 1) = 4;
EXPECT_EQ(4, m.at(1));
}
+
+TEST(MapUtil, get_ptr_path_simple) {
+ using std::map;
+ map<int, map<int, map<int, map<int, int>>>> m{{1, {{2, {{3, {{4, 5}}}}}}}};
+ EXPECT_EQ(5, *get_ptr(m, 1, 2, 3, 4));
+ EXPECT_TRUE(get_ptr(m, 1, 2, 3, 4));
+ EXPECT_FALSE(get_ptr(m, 1, 2, 3, 0));
+ EXPECT_TRUE(get_ptr(m, 1, 2, 3));
+ EXPECT_FALSE(get_ptr(m, 1, 2, 0));
+ EXPECT_TRUE(get_ptr(m, 1, 2));
+ EXPECT_FALSE(get_ptr(m, 1, 0));
+ EXPECT_TRUE(get_ptr(m, 1));
+ EXPECT_FALSE(get_ptr(m, 0));
+ const auto& cm = m;
+ ++*get_ptr(m, 1, 2, 3, 4);
+ 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));
+}
+
+TEST(MapUtil, get_ptr_path_mixed) {
+ using std::map;
+ using std::unordered_map;
+ using std::string;
+ unordered_map<string, map<int, map<string, int>>> m{{"a", {{1, {{"b", 7}}}}}};
+ EXPECT_EQ(7, *get_ptr(m, "a", 1, "b"));
+ EXPECT_TRUE(get_ptr(m, "a", 1, "b"));
+ EXPECT_FALSE(get_ptr(m, "b", 1, "b"));
+ EXPECT_FALSE(get_ptr(m, "a", 2, "b"));
+ EXPECT_FALSE(get_ptr(m, "a", 1, "c"));
+ EXPECT_TRUE(get_ptr(m, "a", 1, "b"));
+ EXPECT_TRUE(get_ptr(m, "a", 1));
+ EXPECT_TRUE(get_ptr(m, "a"));
+ const auto& cm = m;
+ ++*get_ptr(m, "a", 1, "b");
+ EXPECT_EQ(8, *get_ptr(cm, "a", 1, "b"));
+ EXPECT_TRUE(get_ptr(cm, "a", 1, "b"));
+ EXPECT_FALSE(get_ptr(cm, "b", 1, "b"));
+}