Skip to content

Commit 62298d2

Browse files
committed
Add guardrail helpers for invoking Fn/FnMut/FnOnce
They ensure the right overload is called, should the callable object have more than one operator() with const and/or reference qualifiers.
1 parent 598f6b3 commit 62298d2

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

subspace/fn/run_fn.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
#include <type_traits>
18+
19+
#include "subspace/mem/forward.h"
20+
#include "subspace/mem/move.h"
21+
22+
namespace sus::fn {
23+
24+
// clang-format off
25+
26+
/// Invokes a `FnOnce` type, ensuring that it is invoked as an rvalue.
27+
///
28+
/// TODO: A Subspace clang-tidy check encourages the use of run_once() any time
29+
/// a function invokes through type that has been matched against the `FnOnce`
30+
/// concept.
31+
template <class F, class... Args>
32+
requires(std::is_rvalue_reference_v<F&&> &&
33+
!std::is_const_v<std::remove_reference_t<F&&>>)
34+
constexpr inline decltype(auto) run_once(F&& fn_once, Args&&... args) {
35+
return ::sus::move(fn_once)(::sus::forward<Args>(args)...);
36+
}
37+
38+
/// Invokes a `FnMut` type, ensuring that it is invoked as a mutable lvalue
39+
/// object.
40+
///
41+
/// This encourages the `FnMut` to be either stored or passed by value which
42+
/// defines the scope of effect for the `FnMut`'s mutation during execution.
43+
///
44+
/// TODO: A Subspace clang-tidy check encourages the use of run_mut() any time a
45+
/// function invokes through type that has been matched against the `FnMut`
46+
/// concept.
47+
template <class F, class... Args>
48+
constexpr inline decltype(auto) run_mut(F& fn_mut, Args&&... args) {
49+
return fn_mut(::sus::forward<Args>(args)...);
50+
}
51+
52+
/// Invokes a `Fn` type, ensuring that it is invoked as a const object.
53+
///
54+
/// TODO: A Subspace clang-tidy check encourages the use of run() any time a
55+
/// function invokes through type that has been matched against the `Fn`
56+
/// concept.
57+
template <class F, class... Args>
58+
constexpr inline decltype(auto) run(const F& fn, Args&&... args) {
59+
return fn(::sus::forward<Args>(args)...);
60+
}
61+
62+
// clang-format on
63+
64+
} // namespace sus::fn
65+
66+
// Promote the run helpers into the `sus` namespace.
67+
namespace sus {
68+
using ::sus::fn::run;
69+
using ::sus::fn::run_mut;
70+
using ::sus::fn::run_once;
71+
} // namespace sus

0 commit comments

Comments
 (0)