The Battle for Wesnoth  1.19.27+dev
general.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2025
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include <algorithm>
18 #include <cctype>
19 #include <ctime>
20 #include <functional>
21 #include <string>
22 
23 namespace utils
24 {
25 /**
26  * Equivalent to as @c std::is_same_v except both types are passed through std::decay first.
27  *
28  * @tparam T1 The first type to compare.
29  * @tparam T2 The second type to compare.
30  */
31 template<typename T1, typename T2>
32 inline constexpr bool decayed_is_same = std::is_same_v<std::decay_t<T1>, std::decay_t<T2>>;
33 
34 /**
35  * Workaround for the fact that static_assert(false) is invalid.
36  * See https://devblogs.microsoft.com/oldnewthing/20200311-00/?p=103553
37  */
38 template<typename>
39 inline constexpr bool dependent_false_v = false;
40 
41 template<typename Enum>
42 constexpr std::underlying_type_t<Enum> to_underlying(Enum e) noexcept
43 {
44  return static_cast<std::underlying_type_t<Enum>>(e);
45 }
46 
47 namespace detail
48 {
49 /**
50  * A struct that exists to implement a generic wrapper for std::find.
51  * Container should "look like" an STL container of Values.
52  */
53 template<typename Container, typename Value>
55 {
56  static bool eval(const Container& container, const Value& value)
57  {
58  typename Container::const_iterator end = container.end();
59  return std::find(container.begin(), end, value) != end;
60  }
61 };
62 
63 /**
64  * A struct that exists to implement a generic wrapper for the find()
65  * member of associative containers.
66  * Container should "look like" an STL associative container.
67  */
68 template<typename Container>
69 struct contains_impl<Container, typename Container::key_type>
70 {
71  static bool eval(const Container& container, const typename Container::key_type& value)
72  {
73  return container.find(value) != container.end();
74  }
75 };
76 
77 } // namespace detail
78 
79 /**
80  * Returns true iff @a value is found in @a container.
81  *
82  * This should work whenever Container "looks like" an STL container of Values.
83  * Normally this uses std::find(), but a simulated partial template specialization
84  * exists when Value is Container::key_type. In this case, Container is assumed
85  * an associative container, and the member function find() is used.
86  */
87 template<typename Container, typename Value>
88 inline bool contains(const Container& container, const Value& value)
89 {
91 }
92 
93 /**
94  * Utility function for finding the type of thing caught with `catch(...)`.
95  * Not implemented for other compilers at this time.
96  *
97  * @return For the GCC/clang compilers, the unmangled name of an unknown exception that was caught.
98  */
99 std::string get_unknown_exception_type();
100 
101 /**
102  * Convenience wrapper for using std::remove_if on a container.
103  *
104  * @todo c++20 use C++20's std::erase_if instead. The C++20 function returns the number of elements
105  * removed; this one could do that but it seems unnecessary to add it unless something is using it.
106  */
107 template<typename Container, typename Predicate>
108 void erase_if(Container& container, const Predicate& predicate)
109 {
110  container.erase(std::remove_if(container.begin(), container.end(), predicate), container.end());
111 }
112 
113 /**
114  * Convenience wrapper for using std::remove on a container.
115  *
116  * @todo C++20: use std::erase
117  */
118 template<typename Container, typename Value>
119 std::size_t erase(Container& container, const Value& value)
120 {
121  auto iter = std::remove(container.begin(), container.end(), value);
122  auto num_removed = container.end() - iter;
123  container.erase(iter, container.end());
124  return num_removed;
125 }
126 
127 /**
128  * Convenience wrapper for using std::sort on a container.
129  *
130  * @todo C++20: use std::ranges::sort
131  */
132 template<typename Container, typename Predicate>
133 void sort_if(Container& container, const Predicate& predicate)
134 {
135  std::sort(container.begin(), container.end(), predicate);
136 }
137 
138 /**
139  * Convenience wrapper for using find on a container without needing to comare to end()
140  */
141 template<typename Container, typename Value>
142 auto* find(Container& container, const Value& value)
143 {
144  auto res = container.find(value);
145  return (res == container.end()) ? nullptr : &*res;
146 }
147 
148 /**
149  * Convenience wrapper for using find_if on a container without needing to comare to end()
150  */
151 template<typename Container, typename Predicate>
152 auto* find_if(Container& container, const Predicate& predicate)
153 {
154  auto res = std::find_if(container.begin(), container.end(), predicate);
155  return (res == container.end()) ? nullptr : &*res;
156 }
157 
158 /**
159  * Returns a vector whose elements are initialized from the given range.
160  *
161  * @todo C++23: use std::vector and co's from_range constructor
162  */
163 template<typename T, typename Range>
164 inline std::vector<T> from_range(Range&& range)
165 {
166  return std::vector<T>(range.begin(), range.end());
167 }
168 
169 
170 /*
171  * Portable, re-entrant/thread-safe replacement for std::localtime(), which
172  * would otherwise return a pointer to a statically-allocated buffer shared
173  * across all callers (and threads).
174  */
175 inline std::tm* localtime_r(const std::time_t* time, std::tm* result)
176 {
177 #ifdef _WIN32
178  return ::localtime_s(result, time) == 0 ? result : nullptr;
179 #else
180  return ::localtime_r(time, result);
181 #endif
182 }
183 
184 
185 /*
186  * convienience function to turn different lambdas into a single function object.
187  */
188 template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
189 template<class... Ts> overload(Ts...) -> overload<Ts...>;
190 
191 
192 /**
193  * Conveniences wrapper for range algorithms.
194  *
195  * @todo C++20: use std::ranges
196  */
197 namespace ranges
198 {
199 namespace implementation
200 {
201 struct identity
202 {
203  template<typename T>
204  constexpr T&& operator()(T&& t) const noexcept
205  {
206  return std::forward<T>(t);
207  }
208 };
209 
210 } // namespace implementation
211 
212 template<typename Container, typename Value, typename Projection = implementation::identity>
213 auto find(Container& container, const Value& value, const Projection& projection = {})
214 {
215  auto end = container.end();
216  for(auto iter = container.begin(); iter != end; ++iter) {
217  if(std::invoke(projection, *iter) == value) {
218  return iter;
219  }
220  }
221 
222  return end;
223 }
224 
225 } // namespace ranges
226 
227 } // namespace utils
double t
Definition: astarsearch.cpp:63
T end(const std::pair< T, T > &p)
void remove()
Removes a tip.
Definition: tooltip.cpp:94
Contains the implementation details for lexical_cast and shouldn't be used directly.
auto find(Container &container, const Value &value, const Projection &projection={})
Definition: general.hpp:213
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
Definition: general.hpp:32
std::size_t erase(Container &container, const Value &value)
Convenience wrapper for using std::remove on a container.
Definition: general.hpp:119
std::vector< T > from_range(Range &&range)
Returns a vector whose elements are initialized from the given range.
Definition: general.hpp:164
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition: general.hpp:88
auto * find_if(Container &container, const Predicate &predicate)
Convenience wrapper for using find_if on a container without needing to comare to end()
Definition: general.hpp:152
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition: general.cpp:23
std::tm * localtime_r(const std::time_t *time, std::tm *result)
Definition: general.hpp:175
void erase_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::remove_if on a container.
Definition: general.hpp:108
overload(Ts...) -> overload< Ts... >
constexpr bool dependent_false_v
Workaround for the fact that static_assert(false) is invalid.
Definition: general.hpp:39
void sort_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::sort on a container.
Definition: general.hpp:133
constexpr std::underlying_type_t< Enum > to_underlying(Enum e) noexcept
Definition: general.hpp:42
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:142
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition: sound.cpp:139
static bool eval(const Container &container, const typename Container::key_type &value)
Definition: general.hpp:71
A struct that exists to implement a generic wrapper for std::find.
Definition: general.hpp:55
static bool eval(const Container &container, const Value &value)
Definition: general.hpp:56
constexpr T && operator()(T &&t) const noexcept
Definition: general.hpp:204
#define e