X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FMapUtil.h;h=433489273785a6f2677c6f36563ea2a292d8fb58;hp=063bb0f43ba24e2a7a5d35f5ff7ab255970d89e7;hb=5a07e203d79324b68d69f294fa38e43b9671e9b1;hpb=a2353bc0411329fa89e837bd06c869b5367381ba diff --git a/folly/MapUtil.h b/folly/MapUtil.h index 063bb0f4..43348927 100644 --- a/folly/MapUtil.h +++ b/folly/MapUtil.h @@ -18,6 +18,8 @@ #include #include +#include +#include namespace folly { @@ -25,13 +27,21 @@ namespace folly { * 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. */ -template -typename Map::mapped_type get_default( - const Map& map, const typename Map::key_type& key, - const typename Map::mapped_type& dflt = - typename Map::mapped_type()) { +template +typename Map::mapped_type get_default(const Map& map, const Key& 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::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(dflt)); } /** @@ -40,12 +50,13 @@ typename Map::mapped_type get_default( */ template < class Map, + typename Key = typename Map::key_type, typename Func, typename = typename std::enable_if::type, typename Map::mapped_type>::value>::type> typename Map::mapped_type -get_default(const Map& map, const typename Map::key_type& key, Func&& dflt) { +get_default(const Map& map, const Key& key, Func&& dflt) { auto pos = map.find(key); return pos != map.end() ? pos->second : dflt(); } @@ -54,10 +65,13 @@ get_default(const Map& map, const typename Map::key_type& key, Func&& dflt) { * Given a map and a key, return the value corresponding to the key in the map, * or throw an exception of the specified type. */ -template +template < + class E = std::out_of_range, + class Map, + typename Key = typename Map::key_type> const typename Map::mapped_type& get_or_throw( const Map& map, - const typename Map::key_type& key, + const Key& key, const std::string& exceptionStrPrefix = std::string()) { auto pos = map.find(key); if (pos != map.end()) { @@ -66,10 +80,13 @@ const typename Map::mapped_type& get_or_throw( throw E(folly::to(exceptionStrPrefix, key)); } -template +template < + class E = std::out_of_range, + class Map, + typename Key = typename Map::key_type> typename Map::mapped_type& get_or_throw( Map& map, - const typename Map::key_type& key, + const Key& key, const std::string& exceptionStrPrefix = std::string()) { auto pos = map.find(key); if (pos != map.end()) { @@ -82,9 +99,10 @@ typename Map::mapped_type& get_or_throw( * Given a map and a key, return a Optional if the key exists and None if the * key does not exist in the map. */ -template +template folly::Optional get_optional( - const Map& map, const typename Map::key_type& key) { + const Map& map, + const Key& key) { auto pos = map.find(key); if (pos != map.end()) { return folly::Optional(pos->second); @@ -98,14 +116,33 @@ folly::Optional get_optional( * key in the map, or the given default reference if the key doesn't exist in * the map. */ -template +template const typename Map::mapped_type& get_ref_default( - const Map& map, const typename Map::key_type& key, + const Map& map, + const Key& key, const typename Map::mapped_type& dflt) { auto pos = map.find(key); return (pos != map.end() ? pos->second : dflt); } +/** + * Passing a temporary default value returns a dangling reference when it is + * returned. Lifetime extension is broken by the indirection. + * The caller must ensure that the default value outlives the reference returned + * by get_ref_default(). + */ +template +const typename Map::mapped_type& get_ref_default( + const Map& map, + const Key& key, + typename Map::mapped_type&& dflt) = delete; + +template +const typename Map::mapped_type& get_ref_default( + const Map& map, + const Key& key, + const typename Map::mapped_type&& dflt) = delete; + /** * Given a map and a key, return a reference to the value corresponding to the * key in the map, or the given default reference if the key doesn't exist in @@ -113,16 +150,15 @@ const typename Map::mapped_type& get_ref_default( */ template < class Map, + typename Key = typename Map::key_type, typename Func, typename = typename std::enable_if::type, const typename Map::mapped_type&>::value>::type, typename = typename std::enable_if< std::is_reference::type>::value>::type> -const typename Map::mapped_type& get_ref_default( - const Map& map, - const typename Map::key_type& key, - Func&& dflt) { +const typename Map::mapped_type& +get_ref_default(const Map& map, const Key& key, Func&& dflt) { auto pos = map.find(key); return (pos != map.end() ? pos->second : dflt()); } @@ -131,9 +167,8 @@ const typename Map::mapped_type& get_ref_default( * Given a map and a key, return a pointer to the value corresponding to the * key in the map, or nullptr if the key doesn't exist in the map. */ -template -const typename Map::mapped_type* get_ptr( - const Map& map, const typename Map::key_type& key) { +template +const typename Map::mapped_type* get_ptr(const Map& map, const Key& key) { auto pos = map.find(key); return (pos != map.end() ? &pos->second : nullptr); } @@ -141,13 +176,14 @@ const typename Map::mapped_type* get_ptr( /** * Non-const overload of the above. */ -template -typename Map::mapped_type* get_ptr( - Map& map, const typename Map::key_type& key) { +template +typename Map::mapped_type* get_ptr(Map& map, const Key& key) { auto pos = map.find(key); return (pos != map.end() ? &pos->second : nullptr); } +// TODO: Remove the return type computations when clang 3.5 and gcc 5.1 are +// the minimum supported versions. namespace detail { template < class T, @@ -161,7 +197,26 @@ template struct NestedMapType { using type = typename T::mapped_type; }; + +template +struct DefaultType; + +template +struct DefaultType { + using type = Default; +}; + +template +struct DefaultType { + using type = typename DefaultType::type; +}; + +template +auto extract_default(const KeysDefault&... keysDefault) -> + typename DefaultType::type const& { + return std::get(std::tie(keysDefault...)); } +} // namespace detail /** * Given a map of maps and a path of keys, return a pointer to the nested value, @@ -185,4 +240,53 @@ auto get_ptr(Map& map, const Key1& key1, const Key2& key2, const Keys&... keys) return pos != map.end() ? get_ptr(pos->second, key2, keys...) : nullptr; } -} // namespace folly +/** + * 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. + * The default value is the last parameter, and is copied when returned. + */ +template < + class Map, + class Key1, + class Key2, + class... KeysDefault, + typename = typename std::enable_if::type> +auto get_default( + const Map& map, + const Key1& key1, + const Key2& key2, + const KeysDefault&... keysDefault) -> + typename detail::NestedMapType::type { + if (const auto* ptr = get_ptr(map, key1)) { + return get_default(*ptr, key2, keysDefault...); + } + return detail::extract_default(keysDefault...); +} + +/** + * Given a map and a path of keys, return a reference to the value corresponding + * to the nested value, or the given default reference if the path doesn't exist + * in the map. + * The default value is the last parameter, and must be a lvalue reference. + */ +template < + class Map, + class Key1, + class Key2, + class... KeysDefault, + typename = typename std::enable_if::type, + typename = typename std::enable_if::type>::value>::type> +auto get_ref_default( + const Map& map, + const Key1& key1, + const Key2& key2, + KeysDefault&&... keysDefault) -> + typename detail::NestedMapType::type + const& { + if (const auto* ptr = get_ptr(map, key1)) { + return get_ref_default(*ptr, key2, keysDefault...); + } + return detail::extract_default(keysDefault...); +} +} // namespace folly