]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/convenience.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / common / convenience.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <mutex>
16 #include <memory>
17 #include <optional>
18 #include <shared_mutex>
19 #include <type_traits>
20 #include <utility>
21
22 #include <boost/optional.hpp>
23
24 #ifndef CEPH_COMMON_CONVENIENCE_H
25 #define CEPH_COMMON_CONVENIENCE_H
26
27 namespace ceph {
28 // boost::optional is wonderful! Unfortunately it lacks a function for
29 // the thing you would most obviously want to do with it: apply a
30 // function to its contents.
31
32 // There are two obvious candidates. The first is a function that
33 // takes a function and an optional value and returns an optional
34 // value, either holding the return value of the function or holding
35 // nothing.
36 //
37 // I'd considered making more overloads for mutable lvalue
38 // references, but those are going a bit beyond likely use cases.
39 //
40 template<typename T, typename F>
41 auto maybe_do(const boost::optional<T>& t, F&& f) ->
42 boost::optional<std::result_of_t<F(const std::decay_t<T>)>>
43 {
44 if (t)
45 return { std::forward<F>(f)(*t) };
46 else
47 return boost::none;
48 }
49
50 // The other obvious function takes an optional but returns an
51 // ‘unwrapped’ value, either the result of evaluating the function or
52 // a provided alternate value.
53 //
54 template<typename T, typename F, typename U>
55 auto maybe_do_or(const boost::optional<T>& t, F&& f, U&& u) ->
56 std::result_of_t<F(const std::decay_t<T>)>
57 {
58 static_assert(std::is_convertible_v<U, std::result_of_t<F(T)>>,
59 "Alternate value must be convertible to function return type.");
60 if (t)
61 return std::forward<F>(f)(*t);
62 else
63 return std::forward<U>(u);
64 }
65
66
67 // Same thing but for std::optional
68
69 template<typename T, typename F>
70 auto maybe_do(const std::optional<T>& t, F&& f) ->
71 std::optional<std::result_of_t<F(const std::decay_t<T>)>>
72 {
73 if (t)
74 return { std::forward<F>(f)(*t) };
75 else
76 return std::nullopt;
77 }
78
79 // The other obvious function takes an optional but returns an
80 // ‘unwrapped’ value, either the result of evaluating the function or
81 // a provided alternate value.
82 //
83 template<typename T, typename F, typename U>
84 auto maybe_do_or(const std::optional<T>& t, F&& f, U&& u) ->
85 std::result_of_t<F(const std::decay_t<T>)>
86 {
87 static_assert(std::is_convertible_v<U, std::result_of_t<F(T)>>,
88 "Alternate value must be convertible to function return type.");
89 if (t)
90 return std::forward<F>(f)(*t);
91 else
92 return std::forward<U>(u);
93 }
94
95 namespace _convenience {
96 template<typename... Ts, typename F, std::size_t... Is>
97 inline void for_each_helper(const std::tuple<Ts...>& t, const F& f,
98 std::index_sequence<Is...>) {
99 (f(std::get<Is>(t)), ..., void());
100 }
101 template<typename... Ts, typename F, std::size_t... Is>
102 inline void for_each_helper(std::tuple<Ts...>& t, const F& f,
103 std::index_sequence<Is...>) {
104 (f(std::get<Is>(t)), ..., void());
105 }
106 template<typename... Ts, typename F, std::size_t... Is>
107 inline void for_each_helper(const std::tuple<Ts...>& t, F& f,
108 std::index_sequence<Is...>) {
109 (f(std::get<Is>(t)), ..., void());
110 }
111 template<typename... Ts, typename F, std::size_t... Is>
112 inline void for_each_helper(std::tuple<Ts...>& t, F& f,
113 std::index_sequence<Is...>) {
114 (f(std::get<Is>(t)), ..., void());
115 }
116 }
117
118 template<typename... Ts, typename F>
119 inline void for_each(const std::tuple<Ts...>& t, const F& f) {
120 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
121 }
122 template<typename... Ts, typename F>
123 inline void for_each(std::tuple<Ts...>& t, const F& f) {
124 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
125 }
126 template<typename... Ts, typename F>
127 inline void for_each(const std::tuple<Ts...>& t, F& f) {
128 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
129 }
130 template<typename... Ts, typename F>
131 inline void for_each(std::tuple<Ts...>& t, F& f) {
132 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
133 }
134 }
135 #endif // CEPH_COMMON_CONVENIENCE_H