userver: userver/utils/algo.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
algo.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/algo.hpp
4/// @brief Small useful algorithms.
5/// @ingroup userver_universal
6
7#include <algorithm>
8#include <cstddef>
9#include <iterator>
10#include <optional>
11#include <string>
12#include <string_view>
13#include <type_traits>
14#include <utility>
15
16#include <userver/utils/checked_pointer.hpp>
17
18USERVER_NAMESPACE_BEGIN
19
20namespace utils {
21
22/// @brief Concatenates multiple `std::string_view`-convertible items
23template <typename ResultString = std::string, typename... Strings>
24ResultString StrCat(const Strings&... strings) {
25 return [](auto... string_views) {
26 std::size_t result_size = 0;
27 ((result_size += string_views.size()), ...);
28
29 ResultString result;
30 result.reserve(result_size);
31 (result.append(string_views), ...);
32 return result;
33 }(std::string_view{strings}...);
34}
35
36/// @brief Returns nullptr if no key in associative container, otherwise
37/// returns pointer to value.
38template <class Map, class Key>
39auto* FindOrNullptr(Map& map, const Key& key) {
40 const auto it = map.find(key);
41 return (it == map.end() ? nullptr : &it->second);
42}
43
44/// @brief Returns default value if no key in associative container, otherwise
45/// returns a copy of the stored value.
46template <class Map, class Key, class Default>
47typename Map::mapped_type FindOrDefault(Map& map, const Key& key,
48 Default&& def) {
49 const auto* ptr = utils::FindOrNullptr(map, key);
50 if (!ptr) {
51 return {std::forward<Default>(def)};
52 }
53 return *ptr;
54}
55
56/// @brief Returns default value if no key in associative container, otherwise
57/// returns a copy of the stored value.
58template <class Map, class Key>
59typename Map::mapped_type FindOrDefault(Map& map, const Key& key) {
60 const auto ptr = USERVER_NAMESPACE::utils::FindOrNullptr(map, key);
61 if (!ptr) {
62 return {};
63 }
64 return *ptr;
65}
66
67/// @brief Returns std::nullopt if no key in associative container, otherwise
68/// returns std::optional with a copy of value
69template <class Map, class Key>
70std::optional<typename Map::mapped_type> FindOptional(Map& map,
71 const Key& key) {
72 const auto ptr = utils::FindOrNullptr(map, key);
73 if (!ptr) {
74 return std::nullopt;
75 }
76 return {*ptr};
77}
78
79/// @brief Searches a map for an element and return a checked pointer to
80/// the found element
81template <typename Map, typename Key>
82auto CheckedFind(Map& map, const Key& key)
83 -> decltype(utils::MakeCheckedPtr(&map.find(key)->second)) {
84 if (auto f = map.find(key); f != map.end()) {
85 return utils::MakeCheckedPtr(&f->second);
86 }
87 return {nullptr};
88}
89
90/// @brief Converts one container type to another
91template <class ToContainer, class FromContainer>
92ToContainer AsContainer(FromContainer&& container) {
93 if constexpr (std::is_rvalue_reference_v<decltype(container)>) {
94 return ToContainer(std::make_move_iterator(std::begin(container)),
95 std::make_move_iterator(std::end(container)));
96 } else {
97 return ToContainer(std::begin(container), std::end(container));
98 }
99}
100
101namespace impl {
102template <typename Container, typename = void>
103struct HasKeyType : std::false_type {};
104
105template <typename Container>
106struct HasKeyType<Container, std::void_t<typename Container::key_type>>
107 : std::true_type {};
108
109template <typename Container>
110inline constexpr bool kHasKeyType = HasKeyType<Container>::value;
111} // namespace impl
112
113/// @brief Erased elements and returns number of deleted elements
114template <class Container, class Pred>
115auto EraseIf(Container& container, Pred pred) {
116 if constexpr (impl::kHasKeyType<Container>) {
117 auto old_size = container.size();
118 for (auto it = std::begin(container), last = std::end(container);
119 it != last;) {
120 if (pred(*it)) {
121 it = container.erase(it);
122 } else {
123 ++it;
124 }
125 }
126 return old_size - container.size();
127 } else {
128 auto it = std::remove_if(std::begin(container), std::end(container), pred);
129 const auto removed = std::distance(it, std::end(container));
130 container.erase(it, std::end(container));
131 return removed;
132 }
133}
134
135/// @brief Erased elements and returns number of deleted elements
136template <class Container, class T>
138 if constexpr (impl::kHasKeyType<Container>) {
139 return container.erase(elem);
140 } else {
141 // NOLINTNEXTLINE(readability-qualified-auto)
142 auto it = std::remove(std::begin(container), std::end(container), elem);
143 const auto removed = std::distance(it, std::end(container));
144 container.erase(it, std::end(container));
145 return removed;
146 }
147}
148
149/// @brief returns true if there is an element in container which satisfies
150/// the predicate
151template <typename Container, typename Pred>
152bool ContainsIf(const Container& container, Pred pred) {
153 return std::find_if(std::begin(container), std::end(container), pred) !=
154 std::end(container);
155}
156
157} // namespace utils
158
159USERVER_NAMESPACE_END