]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/convenience.h
import ceph quincy 17.2.6
[ceph.git] / ceph / src / common / convenience.h
CommitLineData
11fdf7f2
TL
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
11fdf7f2
TL
24#ifndef CEPH_COMMON_CONVENIENCE_H
25#define CEPH_COMMON_CONVENIENCE_H
26
27namespace 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//
40template<typename T, typename F>
41auto 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//
54template<typename T, typename F, typename U>
55auto 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
69template<typename T, typename F>
70auto 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//
83template<typename T, typename F, typename U>
84auto 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
95namespace _convenience {
96template<typename... Ts, typename F, std::size_t... Is>
97inline 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}
101template<typename... Ts, typename F, std::size_t... Is>
102inline void for_each_helper(std::tuple<Ts...>& t, const F& f,
103 std::index_sequence<Is...>) {
104 (f(std::get<Is>(t)), ..., void());
105}
106template<typename... Ts, typename F, std::size_t... Is>
107inline void for_each_helper(const std::tuple<Ts...>& t, F& f,
108 std::index_sequence<Is...>) {
109 (f(std::get<Is>(t)), ..., void());
110}
111template<typename... Ts, typename F, std::size_t... Is>
112inline 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
118template<typename... Ts, typename F>
119inline void for_each(const std::tuple<Ts...>& t, const F& f) {
120 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
121}
122template<typename... Ts, typename F>
123inline void for_each(std::tuple<Ts...>& t, const F& f) {
124 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
125}
126template<typename... Ts, typename F>
127inline void for_each(const std::tuple<Ts...>& t, F& f) {
128 _convenience::for_each_helper(t, f, std::index_sequence_for<Ts...>{});
129}
130template<typename... Ts, typename F>
131inline 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