1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #pragma once
27
28 #include "predicates.h"
29 #include "optional.h"
30
31 #include <qcompilerdetection.h> // for Q_REQUIRED_RESULT
32
33 #include <algorithm>
34 #include <map>
35 #include <memory>
36 #include <set>
37 #include <tuple>
38 #include <unordered_map>
39 #include <unordered_set>
40
41 #include <QObject>
42 #include <QStringList>
43
44 #include <memory>
45
46 namespace Utils
47 {
48
49 //////////////////
50 // anyOf
51 /////////////////
52 template<typename T, typename F>
anyOf(const T & container,F predicate)53 bool anyOf(const T &container, F predicate)
54 {
55 return std::any_of(std::begin(container), std::end(container), predicate);
56 }
57
58 // anyOf taking a member function pointer
59 template<typename T, typename R, typename S>
anyOf(const T & container,R (S::* predicate)()const)60 bool anyOf(const T &container, R (S::*predicate)() const)
61 {
62 return std::any_of(std::begin(container), std::end(container), std::mem_fn(predicate));
63 }
64
65 // anyOf taking a member pointer
66 template<typename T, typename R, typename S>
anyOf(const T & container,R S::* member)67 bool anyOf(const T &container, R S::*member)
68 {
69 return std::any_of(std::begin(container), std::end(container), std::mem_fn(member));
70 }
71
72
73 //////////////////
74 // count
75 /////////////////
76 template<typename T, typename F>
count(const T & container,F predicate)77 int count(const T &container, F predicate)
78 {
79 return std::count_if(std::begin(container), std::end(container), predicate);
80 }
81
82 //////////////////
83 // allOf
84 /////////////////
85 template<typename T, typename F>
allOf(const T & container,F predicate)86 bool allOf(const T &container, F predicate)
87 {
88 return std::all_of(std::begin(container), std::end(container), predicate);
89 }
90
91 //////////////////
92 // erase
93 /////////////////
94 template<typename T, typename F>
erase(T & container,F predicate)95 void erase(T &container, F predicate)
96 {
97 container.erase(std::remove_if(std::begin(container), std::end(container), predicate),
98 std::end(container));
99 }
100
101
102 //////////////////
103 // contains
104 /////////////////
105 template<typename T, typename F>
contains(const T & container,F function)106 bool contains(const T &container, F function)
107 {
108 return anyOf(container, function);
109 }
110
111 template<typename T, typename R, typename S>
contains(const T & container,R (S::* function)()const)112 bool contains(const T &container, R (S::*function)() const)
113 {
114 return anyOf(container, function);
115 }
116
117 template<typename C, typename R, typename S>
contains(const C & container,R S::* member)118 bool contains(const C &container, R S::*member)
119 {
120 return anyOf(container, std::mem_fn(member));
121 }
122
123 //////////////////
124 // findOr
125 /////////////////
126 template<typename C, typename F>
127 Q_REQUIRED_RESULT
findOr(const C & container,typename C::value_type other,F function)128 typename C::value_type findOr(const C &container, typename C::value_type other, F function)
129 {
130 typename C::const_iterator begin = std::begin(container);
131 typename C::const_iterator end = std::end(container);
132
133 typename C::const_iterator it = std::find_if(begin, end, function);
134 return it == end ? other : *it;
135 }
136
137 template<typename T, typename R, typename S>
138 Q_REQUIRED_RESULT
findOr(const T & container,typename T::value_type other,R (S::* function)()const)139 typename T::value_type findOr(const T &container, typename T::value_type other, R (S::*function)() const)
140 {
141 return findOr(container, other, std::mem_fn(function));
142 }
143
144 template<typename T, typename R, typename S>
145 Q_REQUIRED_RESULT
findOr(const T & container,typename T::value_type other,R S::* member)146 typename T::value_type findOr(const T &container, typename T::value_type other, R S::*member)
147 {
148 return findOr(container, other, std::mem_fn(member));
149 }
150
151 //////////////////
152 // findOrDefault
153 //////////////////
154 // Default implementation:
155 template<typename C, typename F>
156 Q_REQUIRED_RESULT
157 typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
findOrDefault(const C & container,F function)158 findOrDefault(const C &container, F function)
159 {
160 return findOr(container, typename C::value_type(), function);
161 }
162
163 template<typename C, typename R, typename S>
164 Q_REQUIRED_RESULT
165 typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
findOrDefault(const C & container,R (S::* function)()const)166 findOrDefault(const C &container, R (S::*function)() const)
167 {
168 return findOr(container, typename C::value_type(), std::mem_fn(function));
169 }
170
171 template<typename C, typename R, typename S>
172 Q_REQUIRED_RESULT
173 typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
findOrDefault(const C & container,R S::* member)174 findOrDefault(const C &container, R S::*member)
175 {
176 return findOr(container, typename C::value_type(), std::mem_fn(member));
177 }
178
179 //////////////////
180 // index of:
181 //////////////////
182
183 template<typename C, typename F>
184 Q_REQUIRED_RESULT
indexOf(const C & container,F function)185 int indexOf(const C& container, F function)
186 {
187 typename C::const_iterator begin = std::begin(container);
188 typename C::const_iterator end = std::end(container);
189
190 typename C::const_iterator it = std::find_if(begin, end, function);
191 return it == end ? -1 : std::distance(begin, it);
192 }
193
194
195 //////////////////
196 // max element
197 //////////////////
198
199 template<typename T>
maxElementOr(const T & container,typename T::value_type other)200 typename T::value_type maxElementOr(const T &container, typename T::value_type other)
201 {
202 typename T::const_iterator begin = std::begin(container);
203 typename T::const_iterator end = std::end(container);
204
205 typename T::const_iterator it = std::max_element(begin, end);
206 if (it == end)
207 return other;
208 return *it;
209 }
210
211
212 //////////////////
213 // transform
214 /////////////////
215
216 namespace {
217 /////////////////
218 // helper code for transform to use back_inserter and thus push_back for everything
219 // and insert for QSet<>
220 //
221
222 // SetInsertIterator, straight from the standard for insert_iterator
223 // just without the additional parameter to insert
224 template <class Container>
225 class SetInsertIterator :
226 public std::iterator<std::output_iterator_tag,void,void,void,void>
227 {
228 protected:
229 Container *container;
230
231 public:
232 typedef Container container_type;
SetInsertIterator(Container & x)233 explicit SetInsertIterator (Container &x)
234 : container(&x) {}
235 SetInsertIterator<Container> &operator=(const typename Container::value_type &value)
236 { container->insert(value); return *this; }
237 SetInsertIterator<Container> &operator= (typename Container::value_type &&value)
238 { container->insert(std::move(value)); return *this; }
239 SetInsertIterator<Container >&operator*()
240 { return *this; }
241 SetInsertIterator<Container> &operator++()
242 { return *this; }
243 SetInsertIterator<Container> operator++(int)
244 { return *this; }
245 };
246
247 // for QMap / QHash, inserting a std::pair / QPair
248 template <class Container>
249 class MapInsertIterator :
250 public std::iterator<std::output_iterator_tag,void,void,void,void>
251 {
252 protected:
253 Container *container;
254
255 public:
256 typedef Container container_type;
MapInsertIterator(Container & x)257 explicit MapInsertIterator (Container &x)
258 : container(&x) {}
259 MapInsertIterator<Container> &operator=(const std::pair<const typename Container::key_type, typename Container::mapped_type> &value)
260 { container->insert(value.first, value.second); return *this; }
261 MapInsertIterator<Container> &operator=(const QPair<typename Container::key_type, typename Container::mapped_type> &value)
262 { container->insert(value.first, value.second); return *this; }
263 MapInsertIterator<Container >&operator*()
264 { return *this; }
265 MapInsertIterator<Container> &operator++()
266 { return *this; }
267 MapInsertIterator<Container> operator++(int)
268 { return *this; }
269 };
270
271 // inserter helper function, returns a std::back_inserter for most containers
272 // and is overloaded for QSet<> and other containers without push_back, returning custom inserters
273 template<typename C>
274 inline std::back_insert_iterator<C>
inserter(C & container)275 inserter(C &container)
276 {
277 return std::back_inserter(container);
278 }
279
280 template<typename X>
281 inline SetInsertIterator<QSet<X>>
inserter(QSet<X> & container)282 inserter(QSet<X> &container)
283 {
284 return SetInsertIterator<QSet<X>>(container);
285 }
286
287 template<typename K, typename C, typename A>
288 inline SetInsertIterator<std::set<K, C, A>>
inserter(std::set<K,C,A> & container)289 inserter(std::set<K, C, A> &container)
290 {
291 return SetInsertIterator<std::set<K, C, A>>(container);
292 }
293
294 template<typename K, typename H, typename C, typename A>
295 inline SetInsertIterator<std::unordered_set<K, H, C, A>>
inserter(std::unordered_set<K,H,C,A> & container)296 inserter(std::unordered_set<K, H, C, A> &container)
297 {
298 return SetInsertIterator<std::unordered_set<K, H, C, A>>(container);
299 }
300
301 template<typename K, typename V, typename C, typename A>
302 inline SetInsertIterator<std::map<K, V, C, A>>
inserter(std::map<K,V,C,A> & container)303 inserter(std::map<K, V, C, A> &container)
304 {
305 return SetInsertIterator<std::map<K, V, C, A>>(container);
306 }
307
308 template<typename K, typename V, typename H, typename C, typename A>
309 inline SetInsertIterator<std::unordered_map<K, V, H, C, A>>
inserter(std::unordered_map<K,V,H,C,A> & container)310 inserter(std::unordered_map<K, V, H, C, A> &container)
311 {
312 return SetInsertIterator<std::unordered_map<K, V, H, C, A>>(container);
313 }
314
315 template<typename K, typename V>
316 inline MapInsertIterator<QMap<K, V>>
inserter(QMap<K,V> & container)317 inserter(QMap<K, V> &container)
318 {
319 return MapInsertIterator<QMap<K, V>>(container);
320 }
321
322 template<typename K, typename V>
323 inline MapInsertIterator<QHash<K, V>>
inserter(QHash<K,V> & container)324 inserter(QHash<K, V> &container)
325 {
326 return MapInsertIterator<QHash<K, V>>(container);
327 }
328
329 // Helper code for container.reserve that makes it possible to effectively disable it for
330 // specific cases
331
332 // default: do reserve
333 // Template arguments are more specific than the second version below, so this is tried first
334 template<template<typename...> class C, typename... CArgs,
335 typename = decltype(&C<CArgs...>::reserve)>
reserve(C<CArgs...> & c,typename C<CArgs...>::size_type s)336 void reserve(C<CArgs...> &c, typename C<CArgs...>::size_type s)
337 {
338 c.reserve(s);
339 }
340
341 // containers that don't have reserve()
342 template<typename C>
reserve(C &,typename C::size_type)343 void reserve(C &, typename C::size_type) { }
344
345 } // anonymous
346
347 // --------------------------------------------------------------------
348 // Different containers for input and output:
349 // --------------------------------------------------------------------
350
351 // different container types for input and output, e.g. transforming a QList into a QSet
352
353 // function without result type deduction:
354 template<typename ResultContainer, // complete result container type
355 typename SC, // input container type
356 typename F> // function type
357 Q_REQUIRED_RESULT
decltype(auto)358 decltype(auto) transform(SC &&container, F function)
359 {
360 ResultContainer result;
361 reserve(result, typename ResultContainer::size_type(container.size()));
362 std::transform(std::begin(container), std::end(container), inserter(result), function);
363 return result;
364 }
365
366 // function with result type deduction:
367 template<template<typename> class C, // result container type
368 typename SC, // input container type
369 typename F, // function type
370 typename Value = typename std::decay_t<SC>::value_type,
371 typename Result = std::decay_t<std::result_of_t<F(Value&)>>,
372 typename ResultContainer = C<Result>>
373 Q_REQUIRED_RESULT
decltype(auto)374 decltype(auto) transform(SC &&container, F function)
375 {
376 return transform<ResultContainer>(std::forward<SC>(container), function);
377 }
378
379 template<template<typename, typename> class C, // result container type
380 typename SC, // input container type
381 typename F, // function type
382 typename Value = typename std::decay_t<SC>::value_type,
383 typename Result = std::decay_t<std::result_of_t<F(Value&)>>,
384 typename ResultContainer = C<Result, std::allocator<Result>>>
385 Q_REQUIRED_RESULT
decltype(auto)386 decltype(auto) transform(SC &&container, F function)
387 {
388 return transform<ResultContainer>(std::forward<SC>(container), function);
389 }
390
391 // member function without result type deduction:
392 template<template<typename...> class C, // result container type
393 typename SC, // input container type
394 typename R,
395 typename S>
396 Q_REQUIRED_RESULT
decltype(auto)397 decltype(auto) transform(SC &&container, R (S::*p)() const)
398 {
399 return transform<C>(std::forward<SC>(container), std::mem_fn(p));
400 }
401
402 // member function with result type deduction:
403 template<typename ResultContainer, // complete result container type
404 typename SC, // input container type
405 typename R,
406 typename S>
407 Q_REQUIRED_RESULT
decltype(auto)408 decltype(auto) transform(SC &&container, R (S::*p)() const)
409 {
410 return transform<ResultContainer>(std::forward<SC>(container), std::mem_fn(p));
411 }
412
413 // member without result type deduction:
414 template<typename ResultContainer, // complete result container type
415 typename SC, // input container
416 typename R,
417 typename S>
418 Q_REQUIRED_RESULT
decltype(auto)419 decltype(auto) transform(SC &&container, R S::*p)
420 {
421 return transform<ResultContainer>(std::forward<SC>(container), std::mem_fn(p));
422 }
423
424 // member with result type deduction:
425 template<template<typename...> class C, // result container
426 typename SC, // input container
427 typename R,
428 typename S>
429 Q_REQUIRED_RESULT
decltype(auto)430 decltype(auto) transform(SC &&container, R S::*p)
431 {
432 return transform<C>(std::forward<SC>(container), std::mem_fn(p));
433 }
434
435 // same container types for input and output, const input
436
437 // function:
438 template<template<typename...> class C, // container type
439 typename F, // function type
440 typename... CArgs> // Arguments to SC
441 Q_REQUIRED_RESULT
decltype(auto)442 decltype(auto) transform(const C<CArgs...> &container, F function)
443 {
444 return transform<C, const C<CArgs...> &>(container, function);
445 }
446
447 // member function:
448 template<template<typename...> class C, // container type
449 typename R,
450 typename S,
451 typename... CArgs> // Arguments to SC
452 Q_REQUIRED_RESULT
decltype(auto)453 decltype(auto) transform(const C<CArgs...> &container, R (S::*p)() const)
454 {
455 return transform<C, const C<CArgs...> &>(container, std::mem_fn(p));
456 }
457
458 // members:
459 template<template<typename...> class C, // container
460 typename R,
461 typename S,
462 typename... CArgs> // Arguments to SC
463 Q_REQUIRED_RESULT
decltype(auto)464 decltype(auto) transform(const C<CArgs...> &container, R S::*p)
465 {
466 return transform<C, const C<CArgs...> &>(container, std::mem_fn(p));
467 }
468
469 // same container types for input and output, non-const input
470
471 // function:
472 template<template<typename...> class C, // container type
473 typename F, // function type
474 typename... CArgs> // Arguments to SC
475 Q_REQUIRED_RESULT
decltype(auto)476 decltype(auto) transform(C<CArgs...> &container, F function)
477 {
478 return transform<C, C<CArgs...> &>(container, function);
479 }
480
481 // member function:
482 template<template<typename...> class C, // container type
483 typename R,
484 typename S,
485 typename... CArgs> // Arguments to SC
486 Q_REQUIRED_RESULT
decltype(auto)487 decltype(auto) transform(C<CArgs...> &container, R (S::*p)() const)
488 {
489 return transform<C, C<CArgs...> &>(container, std::mem_fn(p));
490 }
491
492 // members:
493 template<template<typename...> class C, // container
494 typename R,
495 typename S,
496 typename... CArgs> // Arguments to SC
497 Q_REQUIRED_RESULT
decltype(auto)498 decltype(auto) transform(C<CArgs...> &container, R S::*p)
499 {
500 return transform<C, C<CArgs...> &>(container, std::mem_fn(p));
501 }
502
503 // Specialization for QStringList:
504
505 template<template<typename...> class C = QList, // result container
506 typename F> // Arguments to C
507 Q_REQUIRED_RESULT
decltype(auto)508 decltype(auto) transform(const QStringList &container, F function)
509 {
510 return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), function);
511 }
512
513 // member function:
514 template<template<typename...> class C = QList, // result container type
515 typename R,
516 typename S>
517 Q_REQUIRED_RESULT
decltype(auto)518 decltype(auto) transform(const QStringList &container, R (S::*p)() const)
519 {
520 return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), std::mem_fn(p));
521 }
522
523 // members:
524 template<template<typename...> class C = QList, // result container
525 typename R,
526 typename S>
527 Q_REQUIRED_RESULT
decltype(auto)528 decltype(auto) transform(const QStringList &container, R S::*p)
529 {
530 return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), std::mem_fn(p));
531 }
532
533 //////////////////
534 // filtered
535 /////////////////
536 template<typename C, typename F>
537 Q_REQUIRED_RESULT
filtered(const C & container,F predicate)538 C filtered(const C &container, F predicate)
539 {
540 C out;
541 std::copy_if(std::begin(container), std::end(container),
542 inserter(out), predicate);
543 return out;
544 }
545
546 template<typename C, typename R, typename S>
547 Q_REQUIRED_RESULT
filtered(const C & container,R (S::* predicate)()const)548 C filtered(const C &container, R (S::*predicate)() const)
549 {
550 C out;
551 std::copy_if(std::begin(container), std::end(container),
552 inserter(out), std::mem_fn(predicate));
553 return out;
554 }
555
556 //////////////////
557 // partition
558 /////////////////
559
560 // Recommended usage:
561 // C hit;
562 // C miss;
563 // std::tie(hit, miss) = Utils::partition(container, predicate);
564
565 template<typename C, typename F>
566 Q_REQUIRED_RESULT
partition(const C & container,F predicate)567 std::tuple<C, C> partition(const C &container, F predicate)
568 {
569 C hit;
570 C miss;
571 auto hitIns = inserter(hit);
572 auto missIns = inserter(miss);
573 for (auto i : container) {
574 if (predicate(i))
575 hitIns = i;
576 else
577 missIns = i;
578 }
579 return std::make_tuple(hit, miss);
580 }
581
582 template<typename C, typename R, typename S>
583 Q_REQUIRED_RESULT
partition(const C & container,R (S::* predicate)()const)584 std::tuple<C, C> partition(const C &container, R (S::*predicate)() const)
585 {
586 return partition(container, std::mem_fn(predicate));
587 }
588
589 //////////////////
590 // filteredUnique
591 /////////////////
592
593 template<typename C>
594 Q_REQUIRED_RESULT
filteredUnique(const C & container)595 C filteredUnique(const C &container)
596 {
597 C result;
598 auto ins = inserter(result);
599
600 QSet<typename C::value_type> seen;
601 int setSize = 0;
602
603 auto endIt = std::end(container);
604 for (auto it = std::begin(container); it != endIt; ++it) {
605 seen.insert(*it);
606 if (setSize == seen.size()) // unchanged size => was already seen
607 continue;
608 ++setSize;
609 ins = *it;
610 }
611 return result;
612 }
613
614 //////////////////
615 // qobject_container_cast
616 /////////////////
617 template <class T, template<typename> class Container, typename Base>
qobject_container_cast(const Container<Base> & container)618 Container<T> qobject_container_cast(const Container<Base> &container)
619 {
620 Container<T> result;
621 auto ins = inserter(result);
622 for (Base val : container) {
623 if (T target = qobject_cast<T>(val))
624 ins = target;
625 }
626 return result;
627 }
628
629 //////////////////
630 // sort
631 /////////////////
632 template <typename Container>
sort(Container & container)633 inline void sort(Container &container)
634 {
635 std::sort(std::begin(container), std::end(container));
636 }
637
638 template <typename Container, typename Predicate>
sort(Container & container,Predicate p)639 inline void sort(Container &container, Predicate p)
640 {
641 std::sort(std::begin(container), std::end(container), p);
642 }
643
644 // pointer to member
645 template <typename Container, typename R, typename S>
sort(Container & container,R S::* member)646 inline void sort(Container &container, R S::*member)
647 {
648 auto f = std::mem_fn(member);
649 using const_ref = typename Container::const_reference;
650 std::sort(std::begin(container), std::end(container),
651 [&f](const_ref a, const_ref b) {
652 return f(a) < f(b);
653 });
654 }
655
656 // pointer to member function
657 template <typename Container, typename R, typename S>
sort(Container & container,R (S::* function)()const)658 inline void sort(Container &container, R (S::*function)() const)
659 {
660 auto f = std::mem_fn(function);
661 using const_ref = typename Container::const_reference;
662 std::sort(std::begin(container), std::end(container),
663 [&f](const_ref a, const_ref b) {
664 return f(a) < f(b);
665 });
666 }
667
668 //////////////////
669 // reverseForeach
670 /////////////////
671 template <typename Container, typename Op>
reverseForeach(const Container & c,const Op & operation)672 inline void reverseForeach(const Container &c, const Op &operation)
673 {
674 auto rend = c.rend();
675 for (auto it = c.rbegin(); it != rend; ++it)
676 operation(*it);
677 }
678
679 //////////////////
680 // toReferences
681 /////////////////
682 template <template<typename...> class ResultContainer,
683 typename SourceContainer>
toReferences(SourceContainer & sources)684 auto toReferences(SourceContainer &sources)
685 {
686 return transform<ResultContainer>(sources, [] (auto &value) { return std::ref(value); });
687 }
688
689 template <typename SourceContainer>
toReferences(SourceContainer & sources)690 auto toReferences(SourceContainer &sources)
691 {
692 return transform(sources, [] (auto &value) { return std::ref(value); });
693 }
694
695 //////////////////
696 // toConstReferences
697 /////////////////
698 template <template<typename...> class ResultContainer,
699 typename SourceContainer>
toConstReferences(const SourceContainer & sources)700 auto toConstReferences(const SourceContainer &sources)
701 {
702 return transform<ResultContainer>(sources, [] (const auto &value) { return std::cref(value); });
703 }
704
705 template <typename SourceContainer>
toConstReferences(const SourceContainer & sources)706 auto toConstReferences(const SourceContainer &sources)
707 {
708 return transform(sources, [] (const auto &value) { return std::cref(value); });
709 }
710
711 //////////////////
712 // take:
713 /////////////////
714
715 template<class C, typename P>
take(C & container,P predicate)716 Q_REQUIRED_RESULT Utils::optional<typename C::value_type> take(C &container, P predicate)
717 {
718 const auto end = std::end(container);
719
720 const auto it = std::find_if(std::begin(container), end, predicate);
721 if (it == end)
722 return Utils::nullopt;
723
724 Utils::optional<typename C::value_type> result = Utils::make_optional(std::move(*it));
725 container.erase(it);
726 return result;
727 }
728
729 // pointer to member
730 template <typename C, typename R, typename S>
decltype(auto)731 Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member)
732 {
733 return take(container, std::mem_fn(member));
734 }
735
736 // pointer to member function
737 template <typename C, typename R, typename S>
decltype(auto)738 Q_REQUIRED_RESULT decltype(auto) take(C &container, R (S::*function)() const)
739 {
740 return take(container, std::mem_fn(function));
741 }
742
743 } // namespace Utils
744