~smspillaz/folly/folly-git-master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <folly/Conv.h>
#include <folly/Optional.h>
#include <folly/functional/Invoke.h>
#include <tuple>

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, typename Key>
typename Map::mapped_type get_default(const Map& map, const Key& key) {
  auto pos = map.find(key);
  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));
}

/**
 * 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<
        is_invocable_r<typename Map::mapped_type, Func>::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_exception<E>(folly::to<std::string>(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_exception<E>(folly::to<std::string>(exceptionStrPrefix, key));
}

/**
 * Given a map and a key, return a Optional<V> if the key exists and None if the
 * key does not exist in the map.
 */
template <class Map, typename Key = typename Map::key_type>
folly::Optional<typename Map::mapped_type> get_optional(
    const Map& map,
    const Key& key) {
  auto pos = map.find(key);
  if (pos != map.end()) {
    return folly::Optional<typename Map::mapped_type>(pos->second);
  } else {
    return folly::none;
  }
}

/**
 * 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>
const typename Map::mapped_type& get_ref_default(
    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 <class Map, typename Key = typename Map::key_type>
const typename Map::mapped_type& get_ref_default(
    const Map& map,
    const Key& key,
    typename Map::mapped_type&& dflt) = delete;

template <class Map, typename Key = typename Map::key_type>
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<
        is_invocable_r<const typename Map::mapped_type&, Func>::value>::type,
    typename = typename std::enable_if<
        std::is_reference<invoke_result_t<Func>>::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 <class Map, typename Key = typename Map::key_type>
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);
}

/**
 * Non-const overload of the above.
 */
template <class Map, typename Key = typename Map::key_type>
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,
    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;
};

template <typename... KeysDefault>
struct DefaultType;

template <typename Default>
struct DefaultType<Default> {
  using type = Default;
};

template <typename Key, typename... KeysDefault>
struct DefaultType<Key, KeysDefault...> {
  using type = typename DefaultType<KeysDefault...>::type;
};

template <class... KeysDefault>
auto extract_default(const KeysDefault&... keysDefault) ->
    typename DefaultType<KeysDefault...>::type const& {
  return std::get<sizeof...(KeysDefault) - 1>(std::tie(keysDefault...));
}
} // namespace detail

/**
 * Given a map of maps and a path of keys, return a Optional<V> if the nested
 * key exists and None if the nested keys does not exist in the map.
 */
template <class Map, class Key1, class Key2, class... Keys>
auto get_optional(
    const Map& map,
    const Key1& key1,
    const Key2& key2,
    const Keys&... keys)
    -> folly::Optional<
        typename detail::NestedMapType<Map, 2 + sizeof...(Keys)>::type> {
  auto pos = map.find(key1);
  return pos != map.end() ? get_optional(pos->second, key2, keys...)
                          : folly::none;
}

/**
 * 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;
}

/**
 * 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<sizeof...(KeysDefault) != 0>::type>
auto get_default(
    const Map& map,
    const Key1& key1,
    const Key2& key2,
    const KeysDefault&... keysDefault) ->
    typename detail::NestedMapType<Map, 1 + sizeof...(KeysDefault)>::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<sizeof...(KeysDefault) != 0>::type,
    typename = typename std::enable_if<std::is_lvalue_reference<
        typename detail::DefaultType<KeysDefault...>::type>::value>::type>
auto get_ref_default(
    const Map& map,
    const Key1& key1,
    const Key2& key2,
    KeysDefault&&... keysDefault) ->
    typename detail::NestedMapType<Map, 1 + sizeof...(KeysDefault)>::type
    const& {
  if (const auto* ptr = get_ptr(map, key1)) {
    return get_ref_default(*ptr, key2, keysDefault...);
  }
  return detail::extract_default(keysDefault...);
}
} // namespace folly