The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
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
23namespace 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 */
31template<typename T1, typename T2>
32inline 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 */
38template<typename>
39inline constexpr bool dependent_false_v = false;
40
41template<typename Enum>
42constexpr std::underlying_type_t<Enum> to_underlying(Enum e) noexcept
43{
44 return static_cast<std::underlying_type_t<Enum>>(e);
45}
46
47namespace 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 */
53template<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 */
68template<typename Container>
69struct 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 */
87template<typename Container, typename Value>
88inline 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 */
99std::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 */
107template<typename Container, typename Predicate>
108void 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 */
118template<typename Container, typename Value>
119std::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 */
132template<typename Container, typename Predicate>
133void 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 */
141template<typename Container, typename Value>
142auto* 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 */
151template<typename Container, typename Predicate>
152auto* 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 */
163template<typename T, typename Range>
164inline 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 */
175inline 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 */
188template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
189template<class... Ts> overload(Ts...) -> overload<Ts...>;
190
191
192/**
193 * Conveniences wrapper for range algorithms.
194 *
195 * @todo C++20: use std::ranges
196 */
197namespace ranges
198{
200{
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
212template<typename Container, typename Value, typename Projection = implementation::identity>
213auto 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
Contains the implementation details for lexical_cast and shouldn't be used directly.
T end(const std::pair< T, T > &p)
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
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::size_t erase(Container &container, const Value &value)
Convenience wrapper for using std::remove on a container.
Definition general.hpp:119
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition general.cpp:23
constexpr std::underlying_type_t< Enum > to_underlying(Enum e) noexcept
Definition general.hpp:42
void erase_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::remove_if on a container.
Definition general.hpp:108
std::vector< T > from_range(Range &&range)
Returns a vector whose elements are initialized from the given range.
Definition general.hpp:164
constexpr bool dependent_false_v
Workaround for the fact that static_assert(false) is invalid.
Definition general.hpp:39
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
void sort_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::sort on a container.
Definition general.hpp:133
std::tm * localtime_r(const std::time_t *time, std::tm *result)
Definition general.hpp:175
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