Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines helper functions for the standard library.
6 :
7 : #pragma once
8 :
9 : #include <array>
10 : #include <chrono>
11 : #include <cstdio>
12 : #include <ctime>
13 : #include <deque>
14 : #include <list>
15 : #include <map>
16 : #include <memory>
17 : #include <optional>
18 : #include <set>
19 : #include <sstream>
20 : #include <string>
21 : #include <tuple>
22 : #include <unordered_map>
23 : #include <unordered_set>
24 : #include <utility>
25 : #include <vector>
26 :
27 : #include "Utilities/PrintHelpers.hpp"
28 : #include "Utilities/Requires.hpp"
29 : #include "Utilities/StlStreamDeclarations.hpp"
30 : #include "Utilities/TypeTraits/IsStreamable.hpp"
31 :
32 : namespace StdHelpers_detail {
33 :
34 : // Helper classes for operator<< for tuples
35 : template <size_t N>
36 : struct TuplePrinter {
37 : template <typename... Args>
38 : static std::ostream& print(std::ostream& os, const std::tuple<Args...>& t) {
39 : TuplePrinter<N - 1>::print(os, t);
40 : os << ",";
41 : print_value(os, std::get<N - 1>(t));
42 : return os;
43 : }
44 : };
45 :
46 : template <>
47 : struct TuplePrinter<1> {
48 : template <typename... Args>
49 : static std::ostream& print(std::ostream& os, const std::tuple<Args...>& t) {
50 : print_value(os, std::get<0>(t));
51 : return os;
52 : }
53 : };
54 :
55 : template <>
56 : struct TuplePrinter<0> {
57 : template <typename... Args>
58 : static std::ostream& print(std::ostream& os,
59 : const std::tuple<Args...>& /*t*/) {
60 : return os;
61 : }
62 : };
63 : } // namespace StdHelpers_detail
64 :
65 : /*!
66 : * \ingroup UtilitiesGroup
67 : * \brief Output the items of a std::list
68 : */
69 : template <typename T>
70 1 : inline std::ostream& operator<<(std::ostream& os, const std::list<T>& v) {
71 : sequence_print_helper(os, std::begin(v), std::end(v));
72 : return os;
73 : }
74 :
75 : /*!
76 : * \ingroup UtilitiesGroup
77 : * \brief Output the items of a std::vector
78 : */
79 : template <typename T>
80 1 : inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
81 : sequence_print_helper(os, std::begin(v), std::end(v));
82 : return os;
83 : }
84 :
85 : /*!
86 : * \ingroup UtilitiesGroup
87 : * \brief Output the items of a std::deque
88 : */
89 : template <typename T>
90 1 : inline std::ostream& operator<<(std::ostream& os, const std::deque<T>& v) {
91 : sequence_print_helper(os, std::begin(v), std::end(v));
92 : return os;
93 : }
94 :
95 : /*!
96 : * \ingroup UtilitiesGroup
97 : * \brief Output the items of a std::array
98 : */
99 : template <typename T, size_t N>
100 1 : inline std::ostream& operator<<(std::ostream& os, const std::array<T, N>& a) {
101 : sequence_print_helper(os, begin(a), end(a));
102 : return os;
103 : }
104 :
105 : /*!
106 : * \ingroup UtilitiesGroup
107 : * \brief Stream operator for tuples
108 : */
109 : template <typename... Args>
110 1 : inline std::ostream& operator<<(std::ostream& os,
111 : const std::tuple<Args...>& t) {
112 : os << "(";
113 : StdHelpers_detail::TuplePrinter<sizeof...(Args)>::print(os, t);
114 : os << ")";
115 : return os;
116 : }
117 :
118 : /*!
119 : * \ingroup UtilitiesGroup
120 : * \brief Output all the key, value pairs of a std::unordered_map
121 : */
122 : template <typename K, typename V, typename H>
123 1 : inline std::ostream& operator<<(std::ostream& os,
124 : const std::unordered_map<K, V, H>& m) {
125 : unordered_print_helper(
126 : os, begin(m), end(m),
127 : [](std::ostream& out,
128 : const typename std::unordered_map<K, V, H>::value_type& value) {
129 : out << "[";
130 : print_value(out, value.first);
131 : out << ",";
132 : print_value(out, value.second);
133 : out << "]";
134 : });
135 : return os;
136 : }
137 :
138 : /*!
139 : * \ingroup UtilitiesGroup
140 : * \brief Output all the key, value pairs of a std::map
141 : */
142 : template <typename K, typename V, typename C>
143 1 : inline std::ostream& operator<<(std::ostream& os, const std::map<K, V, C>& m) {
144 : sequence_print_helper(
145 : os, begin(m), end(m),
146 : [](std::ostream& out,
147 : const typename std::map<K, V, C>::value_type& value) {
148 : out << "[";
149 : print_value(out, value.first);
150 : out << ",";
151 : print_value(out, value.second);
152 : out << "]";
153 : });
154 : return os;
155 : }
156 :
157 : /*!
158 : * \ingroup UtilitiesGroup
159 : * \brief Output the items of a std::unordered_set
160 : */
161 : template <typename T, typename H>
162 1 : inline std::ostream& operator<<(std::ostream& os,
163 : const std::unordered_set<T, H>& v) {
164 : unordered_print_helper(os, std::begin(v), std::end(v));
165 : return os;
166 : }
167 :
168 : /*!
169 : * \ingroup UtilitiesGroup
170 : * \brief Output the items of a std::unordered_multiset
171 : */
172 : template <typename T, typename H>
173 1 : inline std::ostream& operator<<(std::ostream& os,
174 : const std::unordered_multiset<T, H>& v) {
175 : unordered_print_helper(os, std::begin(v), std::end(v));
176 : return os;
177 : }
178 :
179 : /*!
180 : * \ingroup UtilitiesGroup
181 : * \brief Output the items of a std::set
182 : */
183 : template <typename T, typename C>
184 1 : inline std::ostream& operator<<(std::ostream& os, const std::set<T, C>& v) {
185 : sequence_print_helper(os, std::begin(v), std::end(v));
186 : return os;
187 : }
188 :
189 : /*!
190 : * \ingroup UtilitiesGroup
191 : * \brief Stream operator for std::unique_ptr
192 : */
193 : template <typename T, Requires<tt::is_streamable<std::ostream, T>::value>>
194 1 : inline std::ostream& operator<<(std::ostream& os, const std::unique_ptr<T>& t) {
195 : return os << *t;
196 : }
197 :
198 : /*!
199 : * \ingroup UtilitiesGroup
200 : * \brief Stream operator for std::shared_ptr
201 : */
202 : template <typename T, Requires<tt::is_streamable<std::ostream, T>::value>>
203 1 : inline std::ostream& operator<<(std::ostream& os, const std::shared_ptr<T>& t) {
204 : return os << *t;
205 : }
206 :
207 : /*!
208 : * \ingroup UtilitiesGroup
209 : * \brief Stream operator for std::pair
210 : */
211 : template <typename T, typename U>
212 1 : inline std::ostream& operator<<(std::ostream& os, const std::pair<T, U>& t) {
213 : os << "(";
214 : print_value(os, t.first);
215 : os << ", ";
216 : print_value(os, t.second);
217 : os << ")";
218 : return os;
219 : }
220 :
221 : /*!
222 : * \ingroup UtilitiesGroup
223 : * \brief Stream operator for std::optional
224 : */
225 : template <typename T>
226 1 : inline std::ostream& operator<<(std::ostream& os, const std::optional<T>& t) {
227 : // Match boost::optional behavior and print "--" when invalid
228 : if (t.has_value()) {
229 : print_value(os, t.value());
230 : return os;
231 : } else {
232 : return os << "--";
233 : }
234 : }
235 :
236 : /*!
237 : * \ingroup UtilitiesGroup
238 : * \brief Equivalent to `os << t`.
239 : *
240 : * For some reason this sometimes works when trying to stream directly
241 : * doesn't find our STL container stream operators.
242 : */
243 : template <typename T>
244 1 : void print_stl(std::ostream& os, const T& t) {
245 : using ::operator<<;
246 : os << t;
247 : }
248 :
249 : /*!
250 : * \ingroup UtilitiesGroup
251 : * \brief Construct a string containing the keys of a std::unordered_map
252 : */
253 : template <typename K, typename V, typename H>
254 1 : inline std::string keys_of(const std::unordered_map<K, V, H>& m) {
255 : std::ostringstream os;
256 : unordered_print_helper(
257 : os, begin(m), end(m),
258 : [](std::ostream& out,
259 : const typename std::unordered_map<K, V, H>::value_type& value) {
260 : print_value(out, value.first);
261 : });
262 : return os.str();
263 : }
264 :
265 : /*!
266 : * \ingroup UtilitiesGroup
267 : * \brief Construct a string containing the keys of a std::map
268 : */
269 : template <typename K, typename V, typename C>
270 1 : inline std::string keys_of(const std::map<K, V, C>& m) {
271 : std::ostringstream os;
272 : sequence_print_helper(
273 : os, begin(m), end(m),
274 : [](std::ostream& out,
275 : const typename std::map<K, V, C>::value_type& value) {
276 : print_value(out, value.first);
277 : });
278 : return os.str();
279 : }
280 :
281 : /*!
282 : * \ingroup UtilitiesGroup
283 : * \brief Format a string like printf
284 : *
285 : * Given a formatting string and arguments this returns the corresponding
286 : * string. Similar to printf but using std::strings.
287 : */
288 : template <typename... Args>
289 1 : std::string formatted_string(const std::string& fmt, Args... args) {
290 : #pragma GCC diagnostic push
291 : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
292 : // clang-tidy: do not use snprintf
293 : auto requiredBytes = static_cast<size_t>(std::snprintf( // NOLINT
294 : nullptr, 0, fmt.c_str(), args...)) +
295 : 1;
296 : std::string rtn;
297 : rtn.resize(requiredBytes);
298 : // clang-tidy: do not use snprintf
299 : std::snprintf(&rtn[0], requiredBytes, fmt.c_str(), args...); // NOLINT
300 : #pragma GCC diagnostic pop
301 : if (rtn[rtn.size() - 1] == '\0') {
302 : rtn.resize(rtn.size() - 1);
303 : }
304 : return rtn;
305 : }
306 :
307 : /*!
308 : * \ingroup UtilitiesGroup
309 : * \brief Get the current date and time
310 : */
311 1 : inline std::string current_date_and_time() {
312 : const auto now =
313 : std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
314 : return std::ctime(&now);
315 : }
|