userver: userver/utils/get_if.hpp Source File
Loading...
Searching...
No Matches
get_if.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/get_if.hpp
4/// @brief @copybrief utils::GetIf
5/// @ingroup userver_universal
6
7#include <functional>
8#include <memory>
9#include <type_traits>
10#include <utility>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace utils {
15
16namespace impl {
17
18template <typename T>
19concept IsPointerLike = requires(T& t) { t ? std::addressof(*std::declval<T&&>()) : nullptr; };
20
21} // namespace impl
22
23template <typename Leaf>
24constexpr auto* GetIf(Leaf&& leaf) {
25 if constexpr (impl::IsPointerLike<Leaf>) {
26 return leaf ? utils::GetIf(*std::forward<Leaf>(leaf)) : nullptr;
27 } else {
28 return std::addressof(std::forward<Leaf>(leaf));
29 }
30}
31
32/// @brief Dereferences a chain of indirections and compositions,
33/// returns nullptr if one of the chain elements is not set
34///
35/// @snippet universal/src/utils/get_if_test.cpp Sample Usage
36template <typename Root, typename Head, typename... Tail>
37constexpr auto* GetIf(Root&& root, Head&& head, Tail&&... tail) {
38 if constexpr (impl::IsPointerLike<Root>) {
39 return root ? utils::GetIf(*std::forward<Root>(root), std::forward<Head>(head), std::forward<Tail>(tail)...)
40 : nullptr;
41 } else {
42 return utils::GetIf(
43 std::invoke(std::forward<Head>(head), std::forward<Root>(root)),
44 std::forward<Tail>(tail)...
45 );
46 }
47}
48
49} // namespace utils
50
51USERVER_NAMESPACE_END