X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FMapUtil.h;h=7bdb60b734618f9300a456d5bc11078016f7145d;hp=227a1297f060d86df3d33aa3661300405cbd344f;hb=7da4ef82aee382777bb50aadd4af14a482739d10;hpb=546bd3f5f2ed1fdf3a0f5c2b6737a20c4bc2f561 diff --git a/folly/MapUtil.h b/folly/MapUtil.h index 227a1297..7bdb60b7 100644 --- a/folly/MapUtil.h +++ b/folly/MapUtil.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,12 @@ * limitations under the License. */ -#ifndef FOLLY_MAPUTIL_H_ -#define FOLLY_MAPUTIL_H_ +#pragma once + +#include +#include +#include +#include namespace folly { @@ -23,13 +27,88 @@ 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)); +} + +/** + * Give 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 < + 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 Key& key, Func&& dflt) { + auto pos = map.find(key); + return pos != map.end() ? pos->second : 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 < + 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 Key& key, + const std::string& exceptionStrPrefix = std::string()) { + auto pos = map.find(key); + if (pos != map.end()) { + return pos->second; + } + throw E(folly::to(exceptionStrPrefix, key)); +} + +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 Key& key, + const std::string& exceptionStrPrefix = std::string()) { + auto pos = map.find(key); + if (pos != map.end()) { + return pos->second; + } + throw E(folly::to(exceptionStrPrefix, key)); +} + +/** + * 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 +folly::Optional get_optional( + const Map& map, + const Key& key) { + auto pos = map.find(key); + if (pos != map.end()) { + return folly::Optional(pos->second); + } else { + return folly::none; + } } /** @@ -37,21 +116,59 @@ typename Map::mapped_type get_default( * 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 + * the map. + */ +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 Key& key, Func&& dflt) { + auto pos = map.find(key); + return (pos != map.end() ? pos->second : dflt()); +} + /** * 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); } @@ -59,13 +176,117 @@ 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); } -} // namespace folly +// TODO: Remove the return type computations when clang 3.5 and gcc 5.1 are +// the minimum supported versions. +namespace detail { +template < + class T, + size_t pathLength, + class = typename std::enable_if<(pathLength > 0)>::type> +struct NestedMapType { + using type = typename NestedMapType::type::mapped_type; +}; + +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, + * or nullptr if the key doesn't exist in the map. + */ +template +auto get_ptr( + const Map& map, + const Key1& key1, + const Key2& key2, + const Keys&... keys) -> + typename detail::NestedMapType::type const* { + auto pos = map.find(key1); + return pos != map.end() ? get_ptr(pos->second, key2, keys...) : nullptr; +} + +template +auto get_ptr(Map& map, const Key1& key1, const Key2& key2, const Keys&... keys) + -> typename detail::NestedMapType::type* { + auto pos = map.find(key1); + return pos != map.end() ? get_ptr(pos->second, 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. + * 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...); +} -#endif /* FOLLY_MAPUTIL_H_ */ +/** + * 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