Flow 1.0.1
Flow project: Full implementation reference.
util_fwd.hpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
22#include <boost/asio.hpp>
23#include <boost/thread.hpp>
24#include <boost/thread/null_mutex.hpp>
25#include <iostream>
26#include <memory>
27
28/**
29 * Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module.
30 *
31 * Each symbol therein is typically used by at least 1 other Flow module; but all public symbols (except ones
32 * under a detail/ subdirectory) are intended for use by Flow user as well.
33 *
34 * @todo Since Flow gained its first users beyond the original author, some Flow-adjacent code has been written from
35 * which Flow can benefit, including additions to flow::util module. (Flow itself continued to be developed, but some
36 * features were added elsewhere for expediency; this is a reminder to factor them out into Flow for the benefit of
37 * all.) Some features to migrate here might be: conversion between boost.chrono and std.chrono types; (add more
38 * here).
39 */
40namespace flow::util
41{
42// Types.
43
44// Find doc headers near the bodies of these compound types.
45
46template<typename Key, typename Mapped, typename Hash = boost::hash<Key>, typename Pred = std::equal_to<Key>>
47class Linked_hash_map;
48template<typename Key, typename Hash = boost::hash<Key>, typename Pred = std::equal_to<Key>>
49class Linked_hash_set;
50
51class Null_interface;
52
53class Rnd_gen_uniform_range_base;
54template<typename range_t>
55class Rnd_gen_uniform_range;
56template<typename range_t>
57class Rnd_gen_uniform_range_mt;
58
59template<typename Value>
60class Scoped_setter;
61
62template<typename Target_ptr,
63 typename Const_target_ptr
64 = typename std::pointer_traits<Target_ptr>::template rebind<typename Target_ptr::element_type const>>
65class Shared_ptr_alias_holder;
66
67class String_ostream;
68
69class Unique_id_holder;
70
71/**
72 * Short-hand for standard thread class.
73 * We use/encourage use of boost.thread threads (and other boost.thread facilities) over std.thread counterparts --
74 * simply because it tends to be more full-featured. However, reminder: boost.thread IS (API-wise at least)
75 * std.thread, plus more (advanced?) stuff. Generally, boost.thread-using code can be converted to std.thread
76 * with little pain, unless one of the "advanced?" features is used.
77 */
78using Thread = boost::thread;
79
80/* (The @namespace and @brief thingies shouldn't be needed, but some Doxygen bug necessitated them.
81 * See flow::util::bind_ns for explanation... same thing here.) */
82
83/**
84 * @namespace flow::util::this_thread
85 * @brief Short-hand for standard this-thread namespace. Paired with util::Thread.
86 */
87namespace this_thread = boost::this_thread;
88
89/// Short-hand for an OS-provided ID of a util::Thread.
90using Thread_id = Thread::id;
91
92/**
93 * Short-hand for boost.asio event service, the central class of boost.asio.
94 *
95 * ### Naming ###
96 * The reasons for the rename -- as opposed to simply calling it `Io_service` (historically it was indeed so named) --
97 * are as follows. To start, a later version of Boost (to which we eventually moved) realigned
98 * boost.asio's API to match the feedback boost.asio received when submitted as a candidate for inclusion into
99 * the official STL (sometime after C++17); in this reorg they renamed it from `io_service` to `io_context`.
100 * That's not the actual reason but more of a symptom of similar reasoning to the following:
101 * - "Service" sounds like something that has its own thread(s) perhaps, which `io_service` actually doesn't;
102 * it *can* (and typically is) used to take over at least one thread, but that's not a part of its "essence," so
103 * to speak. I've noticed that when boost.asio neophytes see "service" they intuitively draw incorrect assumptions
104 * about what it does, and then one must repeatedly dash those assumptions.
105 * - Furthermore (though apparently boost.asio guys didn't agree or didn't agree strongly enough) "I/O" implies
106 * an `io_service` is all about working with various input/output (especially networking). While it's true
107 * that roughly 50% of the utility of boost.asio is its portable sockets/networking API, the other 50% is about
108 * its ability to flexibly execute user tasks in various threads; and, indeed, `io_service` *itself* is more about
109 * the latter 50% rather than the former. Its two most basic and arguably oft-used features are simply
110 * `io_service::post()` (which executes the given task ASAP); and the `basic_waitable_timer` set of classes
111 * (which execute task at some specified point in the future). Note these have nothing to do with networking or
112 * I/O of any kind. The I/O comes from the "I/O object" classes/etc., such as `tcp::socket`, but those
113 * are *not* `io_service`; they merely work together with it to execute the user-specified success/failure handlers.
114 *
115 * So, neither "I/O" nor "service" is accurate. To fix both, then, we used this rename reasoning:
116 * - "I/O" can be replaced by the notion of it executing "tasks." boost.asio doesn't use or define the "task" term,
117 * sticking to "handler" or "functor" or "function," but we feel it's a reasonable term in this context.
118 * (Function, etc., doesn't cover all possibilities. Handler is OK, but when it's not in response to any event --
119 * as with vanilla `post()` -- what is it handling?)
120 * - "Service" is trickier to replace. It's a battle between "too generic" and "too specific and therefore long to
121 * type." Plus there's the usual danger of accidentally overloading a term already used elsewhere nearby.
122 * Some ideas considered were: manager, engine, execution engine, queue, queues, context (which boost.asio chose),
123 * and various abbreviations thereof. Ultimately it came down to context vs. engine, and I chose engine because
124 * context is just a little vague, or it suggests an arbitrary grouping of things -- whereas "engine" actually
125 * implies action: want to express this thing provides logical/algorithmic value as opposed to just bundling
126 * stuff together as "context" objects often do (e.g., "SSL context" in openssl). Indeed `io_service` does provide
127 * immense algorithmic value.
128 * - Manager: generic but not bad; clashes with "Windows task manager" and such.
129 * - Execution engine: good but long.
130 * - Queue: early candidate, but at the very least it's not a *single* queue; if there are multiple threads
131 * `io_service::run()`ning then to the extent there are any queues there might be multiple.
132 * - Queues, qs: better... but having a thing called `Task_qs` -- of which there could be multiple (plural) --
133 * was clumsy. (An early proof-of-concept used `Task_qs`; people were not fans.)
134 */
135using Task_engine = boost::asio::io_service;
136
137/// Short-hand for boost.asio strand, an ancillary class that works with #Task_engine for advanced task scheduling.
138using Strand = Task_engine::strand;
139
140/**
141 * boost.asio timer. Can schedule a function to get called within a set amount of time or at
142 * a certain specific time relative to some Epoch.
143 *
144 * @see schedule_task_from_now() (and friends) for a simpler task-scheduling API (which internally uses this
145 * `Timer). The notes below still apply however. Please read them even if you won't use `Timer` directly.
146 *
147 * Important: While one can schedule events using very precise units using #Fine_duration, the
148 * timer may not actually have that resolution. That is, I may schedule something to happen in 1
149 * millisecond and then measure the time passed, using a high-res clock like #Fine_clock, and discover that
150 * the wait was actually 15 milliseconds. This is not a problem for most timers. (In Flow itself, the most advanced
151 * use of timers by far is in flow::net_flow. Timers used in flow::net_flow -- delayed ACK timer, Drop Timer, simulated
152 * latency timer -- typically are for `n x 50` milliseconds time periods or coarser.) However that may not be the
153 * case for all timers. (In particular, flow::net_flow packet pacing may use finer time periods.)
154 *
155 * @note The flow::net_flow references in the present doc header speak of internal implementation details -- not
156 * of interest to the `net_flow` *user*. I leave them in this public doc header for practical purposes, as
157 * examples needed to discuss some Inside-Baseball topics involved.
158 *
159 * So I looked into what boost.asio provides. `deadline_timer` uses the system clock
160 * (`universal_time()`) as the time reference, while `basic_waitable_timer<Fine_clock>` uses the
161 * high-resolution clock (see #Fine_clock). I tested both (using `wait()`s of various lengths
162 * and using #Fine_clock to measure duration) and observed the following resolutions on certain OS
163 * (not listing the hardware):
164 *
165 * - Linux (2.6.x kernel): sub-2 millisecond resolution, with some variance.
166 * (Note: This Linux's `glibc` is too old to provide the `timerfd` API, therefore Boost falls back to
167 * using `epoll_wait()` directly; on a newer Linux this may get better results.)
168 * - Windows 7: 15 millisecond resolution, with little variance.
169 * - Mac OS X: untested. @todo Test Mac OS X timer fidelity.
170 *
171 * These results were observed for BOTH `deadline_timer` and `basic_waitable_timer<Fine_clock>`
172 * in Boost 1.50. Thus, there was no resolution advantage to using the latter -- only an interface advantage.
173 * Conclusion: we'd be well-advised not to rely on anything much smaller than 20 milliseconds when
174 * scheduling timer events. One technique might be, given any time T < 20 ms, to assume T = 0
175 * (i.e., execute immediately). This may or may not be appropriate depending on the situation.
176 *
177 * However, using `basic_waitable_timer<Fine_clock>` may get an additional nice property: #Fine_clock
178 * always goes forward and cannot be affected by NTP or user changes. `deadline_timer` may or may not
179 * be affected by such tomfoolery (untested, but the potential is clearly there). Therefore we do the best
180 * we can by using the #Fine_clock-based timer.
181 *
182 * @todo Upgrade to newer Boost and keep testing timer resolutions on the above and other OS versions.
183 * Update: As of this writing we are on Boost 1.74 now. Needless to say, it is time to reassess the above, as it
184 * has been years since 1.50 -- and we had been on 1.63 and 1.66 for long period of time, let alone 1.74.
185 * Update: No changes with Boost 1.75, the newest version as of this writing.
186 *
187 * @note One annoying, though fully documented, "feature" of this and all boost.asio timers is that `cancel()`ing it
188 * does not always cause the handler to fire with `operation_aborted` error code. Sometimes it was already "just
189 * about" to fire at `cancel()` time, so the handler will run with no error code regardless of the `cancel()`.
190 * Personally I have never once found this behavior useful, and there is much code currently written to work
191 * around this "feature." Furthermore, even a "successful" cancel still runs the handler but with `operation_aborted`;
192 * 99.999% of the time one would want to just not run it at all. Finally, in many cases, even having to create
193 * a timer object (and then the multiple steps required to actually schedule a thing) feels like more boiler-plate
194 * than should be necessary. To avoid all of these usability issues, see schedule_task_from_now() (and similar),
195 * which is a facility that wraps `Timer` for a boiler-plate-free experience sufficient in the majority of practical
196 * situations. `Timer` is to be used directly when that simpler facility is insufficient.
197 *
198 * @note `b_w_t<Fine_clock>` happens to equal `boost::asio::high_resolution_timer`. We chose to alias
199 * in terms of #Fine_clock merely to ensure that #Fine_duration is one-to-one compatible with it, as it
200 * is defined in terms of #Fine_clock also.
201 */
202using Timer = boost::asio::basic_waitable_timer<Fine_clock>;
203
204/// Helper type for setup_auto_cleanup().
205using Auto_cleanup = boost::shared_ptr<void>;
206
207/// Short-hand for the UDP endpoint (IP/port) type.
208using Udp_endpoint = boost::asio::ip::udp::endpoint;
209/// Short-hand for the IPv4 address type.
210using Ip_address_v4 = boost::asio::ip::address_v4;
211/// Short-hand for the IPv6 address type.
212using Ip_address_v6 = boost::asio::ip::address_v6;
213
214/// Short-hand for non-reentrant, exclusive mutex. ("Reentrant" = one can lock an already-locked-in-that-thread mutex.)
215using Mutex_non_recursive = boost::mutex;
216
217/// Short-hand for reentrant, exclusive mutex.
218using Mutex_recursive = boost::recursive_mutex;
219
220/**
221 * Short-hand for non-reentrant, shared-or-exclusive mutex.
222 * When locking one of these, choose one of:
223 * `Lock_guard<Mutex_shared_non_recursive>`, `Shared_lock_guard<Mutex_shared_non_recursive>`.
224 * The level of locking acquired (shared vs. exclusive) depends on which you chose and is thus highly significant.
225 *
226 * @todo Consider changing util::Mutex_shared_non_recursive from `boost::shared_mutex` to `std::shared_mutex`, as
227 * the former has a long-standing unresolved ticket about its impl being slow and/or outdated (as of Boost-1.80).
228 * However see also the note on util::Mutex_shared_non_recursive that explains why it might be best to avoid
229 * this type of mutex altogether in the first place (in most cases).
230 *
231 * ### When to use versus #Mutex_non_recursive ###
232 * Experts suggest fairly strongly that one should be very wary about using a shared mutex, over a simple
233 * non-recursive exclusive mutex, in almost any practical application. The reason there's a trade-off at all is
234 * that a #Mutex_non_recursive is extremely fast to lock and unlock; the entire perf cost is in waiting for
235 * another thread to unlock first; so without contention it's almost *free*. In contrast apparently any real
236 * impl of #Mutex_shared_non_recursive is much slower to lock/unlock. The trade-off is against allowing
237 * reads to proceed in parallel; but experts say this is "worth it" only when these read critical sections
238 * are lengthy and very frequently invoked. So, for example, if the lock/unlock is around an `unordered_map`
239 * lookup with a quick hashing function, it would be quite difficult to induce enough lock contention
240 * to make a shared mutex better than an exclusive one. (Note this is assuming even no perf issue with
241 * `boost::shared_mutex` specifically.)
242 */
243using Mutex_shared_non_recursive = boost::shared_mutex;
244
245/**
246 * Short-hand for a mutex type equivalent to util::Mutex_shared_non_recursive -- except that the lock/unlock mutex ops
247 * all do nothing. One can parameterize templates accordingly; so that an algorithm can be generically written to work
248 * in both single- and multi-threaded contexts without branching into 2 code paths, yet avoid the unnecessary actual
249 * locking in the former case.
250 */
251using Mutex_noop_shared_non_recursive = boost::null_mutex;
252
253/**
254 * Short-hand for advanced-capability RAII lock guard for any mutex, ensuring exclusive ownership of that mutex.
255 * Note the advanced API available for the underlying type: it is possible to relinquish ownership without unlocking,
256 * gain ownership of a locked mutex; and so on.
257 *
258 * @see To grab shared-level ownership of a shared-or-exclusive mutex: use #Shared_lock_guard.
259 *
260 * @tparam Mutex
261 * A non-recursive or recursive mutex type. Recommend one of:
262 * #Mutex_non_recursive, #Mutex_recursive, #Mutex_shared_non_recursive, #Mutex_noop_shared_non_recursive.
263 */
264template<typename Mutex>
265using Lock_guard = boost::unique_lock<Mutex>;
266
267/**
268 * Short-hand for *shared mode* advanced-capability RAII lock guard, particuarly for #Mutex_shared_non_recursive
269 * mutexes.
270 *
271 * @tparam Shared_mutex
272 * Typically #Mutex_shared_non_recursive, but any mutex type with that both-exclusive-and-shared API will work.
273 */
274template<typename Shared_mutex>
275using Shared_lock_guard = boost::shared_lock<Shared_mutex>;
276
277/**
278 * (Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for #Mutex_non_recursive mutexes.
279 *
280 * @todo #Lock_guard_non_recursive is deprecated, now that C++1x made the more flexible
281 * `Lock_guard<Mutex_non_recursive>` possible. Remove it and all (outside) uses eventually.
282 */
283using Lock_guard_non_recursive = boost::unique_lock<Mutex_non_recursive>;
284
285/**
286 * (Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for #Mutex_recursive mutexes.
287 *
288 * @todo #Lock_guard_recursive is deprecated, now that C++1x made the more flexible `Lock_guard<Mutex_recursive>`
289 * possible. Remove it and all (outside) uses eventually.
290 */
291using Lock_guard_recursive = boost::unique_lock<Mutex_recursive>;
292
293/**
294 * (Deprecated given C++1x) Short-hand for *shared mode* advanced-capability RAII lock guard for
295 * #Mutex_shared_non_recursive mutexes.
296 *
297 * @todo #Lock_guard_shared_non_recursive_sh is deprecated, now that C++1x made the more flexible
298 * `Shared_lock_guard<Mutex_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
299 */
300using Lock_guard_shared_non_recursive_sh = boost::shared_lock<Mutex_shared_non_recursive>;
301
302/**
303 * (Deprecated given C++1x) Short-hand for *exclusive mode* advanced-capability RAII lock guard for
304 * #Mutex_shared_non_recursive mutexes.
305 *
306 * @todo #Lock_guard_shared_non_recursive_ex is deprecated, now that C++1x made the more flexible
307 * `Lock_guard<Mutex_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
308 */
309using Lock_guard_shared_non_recursive_ex = boost::unique_lock<Mutex_shared_non_recursive>;
310
311/**
312 * (Deprecated given C++1x) Equivalent to #Lock_guard_shared_non_recursive_sh but applied to
313 * #Mutex_noop_shared_non_recursive.
314 *
315 * @todo #Lock_guard_noop_shared_non_recursive_sh is deprecated, now that C++1x made the more flexible
316 * `Shared_lock_guard<Mutex_noop_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
317 */
318using Lock_guard_noop_shared_non_recursive_sh = boost::shared_lock<Mutex_noop_shared_non_recursive>;
319
320/**
321 * (Deprecated given C++1x) Equivalent to #Lock_guard_shared_non_recursive_ex but applied to
322 * #Mutex_noop_shared_non_recursive.
323 *
324 * @todo #Lock_guard_noop_shared_non_recursive_ex is deprecated, now that C++1x made the more flexible
325 * `Lock_guard<Mutex_noop_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
326 */
327using Lock_guard_noop_shared_non_recursive_ex = boost::unique_lock<Mutex_noop_shared_non_recursive>;
328
329// Free functions.
330
331/**
332 * Equivalent to `val1.swap(val2)`.
333 *
334 * @relatesalso Linked_hash_map
335 * @param val1
336 * Object.
337 * @param val2
338 * Object.
339 */
340template<typename Key, typename Mapped, typename Hash, typename Pred>
342
343/**
344 * Equivalent to `val1.swap(val2)`.
345 *
346 * @relatesalso Linked_hash_set
347 * @param val1
348 * Object.
349 * @param val2
350 * Object.
351 */
352template<typename Key, typename Hash, typename Pred>
354
355/**
356 * Get the current POSIX (Unix) time as a duration from the Epoch time point.
357 *
358 * This is the amount of time -- according to the user-settable system clock time -- to have passed since the
359 * POSIX (Unix) Epoch -- January 1st, 1970, 00:00:00 UTC -- not counting leap seconds to have been inserted or deleted
360 * between then and now.
361 *
362 * The `boost::chrono` duration type is chosen so as to support the entire supported resolution of the
363 * OS-exposed system clock (but probably no more than that).
364 *
365 * ### Known use cases, alternatives ###
366 * - Logging of time stamps. Output the raw value; or use boost.locale to output `ceil<seconds>()` in the desired
367 * human-friendly form, splicing in the left-over microseconds where desired (boost.locale lacks formatters for
368 * sub-second-resolution time points). However see below for a typically-superior alternative.
369 * - By subtracting return values of this at various points in time from each other, as a crude timing mechanism.
370 * (Various considerations make it just that -- crude -- and best replaced by flow::Fine_clock and the like.
371 * Moreover see flow::perf::Checkpointing_timer.)
372 * - It's a decent quick-and-dirty random seed.
373 *
374 * ### Update/subtleties re. time stamp output ###
375 * Using this for time stamp output is no longer needed or convenient, as a much nicer way presents itself
376 * when combined with boost.chrono I/O-v2 `time_point`-outputting `ostream<<` overload. Just grab `time_point`
377 * `boost::chrono::system_clock::now()` (or another `system_clock`-originated value); its default-formatted
378 * `ostream<<` output will include date, time with microsecond+ precision, and time-zone specifier (one can choose
379 * UTC or local time).
380 *
381 * However, as of this writing, it is not possible to directly obtain *just* the microsecond+
382 * part of this, in isolation, according boost.chrono docs. (One could hack it by taking a substring.)
383 * Quote: "Unfortunately there are no formatting/parsing sequences which indicate fractional seconds." From:
384 * https://www.boost.org/doc/libs/1_76_0/doc/html/chrono/users_guide.html#chrono.users_guide.tutorial.i_o.system_clock_time_point_io)
385 *
386 * @return A duration representing how much time has passed since the Epoch reference point
387 * (could be negative if before it).
388 */
389boost::chrono::microseconds time_since_posix_epoch();
390
391/**
392 * Writes a multi- or single-line string representation of the provided binary data to an output stream, complete with
393 * a printable and hex versions of each byte.
394 * - Single-line mode is chosen by setting `bytes_per_line` to special value `-1`. In this mode, the output
395 * consists of `indentation`, followed by a pretty-printed hex dump of every byte in `data` (no matter how many),
396 * followed by a pretty-printed ASCII-printable (or '.' if not so printable) character for each byte; that's it.
397 * No newline is added, and `indentation` is included only the one time. It is recommended to therefore print
398 * "in-line" inside log messages (etc.) without surrounding newlines, etc., when using this mode.
399 * - Multi-line mode is chosen by setting `bytes_per_line` to a positive value; or 0 which auto-selects a decent
400 * default positive value. Then, each line represents up to that many bytes, which are pretty-printed similarly
401 * to single-line mode, in order of appearance in `data` (with the last such line representing the last few bytes,
402 * formatting nicely including accounting for potentially fewer than the desired # of bytes per line).
403 * Every line starts with `indentation` and ends with a newline -- including the last line.
404 * Therefore, it is recommended to precede this call with an output of a newline and to avoid doing so
405 * after that call (unless blank line is desired).
406 *
407 * Example with a single contiguous memory area, multi-line mode:
408 *
409 * ~~~
410 * array<uint8_t, 256 * 256> bytes(...);
411 *
412 * // Output to cout.
413 * cout
414 * << "Buffer contents: [\n";
415 * buffers_to_ostream(cout,
416 * boost::asio::buffer(bytes), // Turn a single memory array into a buffer sequence.
417 * " ");
418 * << "]."; // This will be on its own line at the end.
419 * ~~~
420 *
421 * See also buffers_dump_string() which returns a string and can thus be more easily used directly inside
422 * FLOW_LOG_DATA() and similar log macros.
423 *
424 * ### Performance ###
425 * This thing is slow... it's not trying to be fast and can't be all that fast anyway. As usual, though, if used
426 * in FLOW_LOG_DATA() (etc.) its slowness will only come into play if the log filter passes which (esp. for
427 * log::Severity::S_DATA) it usually won't.
428 *
429 * That said buffers_dump_string() is even slower, because it'll use an intermediate `ostream` independent of whatever
430 * `ostream` you may or may not be placing the resulting string. However it's easier to use with `FLOW_LOG_...()`,
431 * and since in that case perf is typically not an issue, it makes sense to use the easier thing typically.
432 *
433 * However, if you do want to avoid that extra copy and need to *also* use buffers_to_ostream() directly inside
434 * `FLOW_LOG_...()` then the following technique isn't too wordy and works:
435 *
436 * ~~~
437 * const array<uint8_t, 256 * 256> bytes(...);
438 *
439 * // Log with a flow::log macro.
440 * const flow::Function<ostream& (ostream&)> os_manip = [&](ostream& os) -> ostream&
441 * {
442 * return buffers_to_ostream(os, boost::asio::buffer(bytes), " ");
443 * };
444 * FLOW_LOG_INFO("Buffer contents: [\n" << os_manip << "].");
445 *
446 * // Above is probably more performant than:
447 * FLOW_LOG_INFO("Buffer contents: [\n"
448 * << buffers_dump_string(boost::asio::buffer(bytes), " ") // Intermediate+copy, slow....
449 * << "].");
450 * // flow::util::ostream_op_string() is a bit of an improvement but still. :-)
451 * ~~~
452 *
453 * ### Rationale ###
454 * The reason it returns `os` and takes a reference-to-mutable instead of the customary (for this project's
455 * style, to indicate modification potential at call sites) pointer-to-mutable is in order to be `bind()`able
456 * in such a way as to make an `ostream` manipulator. In the example above we use a lambda instead of `bind()`
457 * however.
458 *
459 * @tparam Const_buffer_sequence
460 * Type that models the boost.asio `ConstBufferSequence` concept (see Boost docs) which represents
461 * 1 or more scattered buffers in memory (only 1 buffer in a sequence is common).
462 * In particular `boost::asio::const_buffer` works when dumping a single buffer.
463 * @param os
464 * The output stream to which to write.
465 * @param data
466 * The data to write, given as an immutable sequence of buffers each of which is essentially a pointer
467 * and length. (Reminder: it is trivial to make such an object from a single buffer as well;
468 * for example given `array<uint8_t, 256> data` (an array of 256 bytes), you can just pass
469 * `boost::asio::buffer(data)`, as the latter returns an object whose type satisfies requirements of
470 * `Const_buffer_sequence` despite the original memory area being nothing more than a single
471 * byte array.)
472 * @param indentation
473 * The indentation to use at the start of every line of output.
474 * @param bytes_per_line
475 * If 0, act as-if a certain default positive value were passed; and then: If `-1`, single-line mode is invoked.
476 * If a positive value, multi-line mode is invoked, with all lines but the last one consisting of
477 * a dump of that many contiguous bytes of `data`. (Yes, multi-line mode is still in force, even if there
478 * are only enough bytes in `data` for one line of output anyway.)
479 * @return `os`.
480 */
481template<typename Const_buffer_sequence>
482std::ostream& buffers_to_ostream(std::ostream& os, const Const_buffer_sequence& data, const std::string& indentation,
483 size_t bytes_per_line = 0);
484
485/**
486 * Identical to buffers_to_ostream() but returns an `std::string` instead of writing to a given `ostream`.
487 *
488 * @see buffers_to_ostream() doc header for notes on performance and usability.
489 *
490 * @tparam Const_buffer_sequence
491 * See buffers_to_ostream().
492 * @param data
493 * See buffers_to_ostream().
494 * @param indentation
495 * See buffers_to_ostream().
496 * @param bytes_per_line
497 * See buffers_to_ostream().
498 * @return Result string.
499 */
500template<typename Const_buffer_sequence>
501std::string buffers_dump_string(const Const_buffer_sequence& data, const std::string& indentation,
502 size_t bytes_per_line = 0);
503
504/**
505 * Utility that converts a bandwidth in arbitrary units in both numerator and denominator to the same bandwidth
506 * in megabits per second. The input bandwidth is given in "items" per `Time_unit(1)`; where `Time_unit` is an
507 * arbitrary boost.chrono `duration` type that must be explicitly provided as input; and an "item" is defined
508 * as `bits_per_item` bits. Useful at least for logging. It's probably easiest to understand by example; see below;
509 * rather than by parsing that description I just wrote.
510 *
511 * To be clear (as C++ syntax is not super-expressive in this case) -- the template parameter `Time_unit` is
512 * an explicit input to the function template, essentially instructing it as to in what units `items_per_time` is.
513 * Thus all uses of this function should look similar to:
514 *
515 * ~~~
516 * // These are all equal doubles, because the (value, unit represented by value) pair is logically same in each case.
517 *
518 * // We'll repeatedly convert from 2400 mebibytes (1024 * 1024 bytes) per second, represented one way or another.
519 * const size_t MB_PER_SEC = 2400;
520 *
521 * // First give it as _mebibytes_ (2nd arg) per _second_ (template arg).
522 * const double mbps_from_mb_per_sec
523 * = flow::util::to_mbit_per_sec<chrono::seconds>(MB_PER_SEC, 1024 * 8);
524 *
525 * // Now give it as _bytes_ (2nd arg omitted in favor of very common default = 8) per _second_ (template arg).
526 * const double mbps_from_b_per_sec
527 * = flow::util::to_mbit_per_sec<chrono::seconds>(MB_PER_SEC * 1024 * 1024);
528 *
529 * // Now in _bytes_ per _hour_.
530 * const double mbps_from_b_per_hour
531 * = flow::util::to_mbit_per_sec<chrono::hours>(MB_PER_SEC * 1024 * 1024 * 60 * 60);
532 *
533 * // Finally give it in _bytes_ per _1/30th-of-a-second_ (i.e., per frame, when the frame rate is 30fps).
534 * const double mbps_from_b_per_30fps_frame
535 * = flow::util::to_mbit_per_sec<chrono::duration<int, ratio<1, 30>>(MB_PER_SEC * 1024 * 1024 / 30);
536 * ~~~
537 *
538 * @note Megabit (1000 x 1000 = 10^6 bits) =/= mebibit (1024 x 1024 = 2^20 bits); but the latter is only about 5% more.
539 * @todo boost.unit "feels" like it would do this for us in some amazingly pithy and just-as-fast way. Because Boost.
540 * @tparam Time_unit
541 * `boost::chrono::duration<Rep, Period>` for some specific `Rep` and `Period`.
542 * See `boost::chrono::duration` documentation.
543 * Example types: `boost::chrono::milliseconds`; `boost::chrono::seconds`; see example use code above.
544 * @tparam N_items
545 * Some (not necessarily integral) numeric type. Strictly speaking, any type convertible to `double` works.
546 * @param items_per_time
547 * The value, in items per `Time_unit(1)` (where there are `bits_per_item` bits in 1 item) to convert to
548 * megabits per second. Note this need not be an integer.
549 * @param bits_per_item
550 * Number of bits in an item, where `items_per_time` is given as a number of items.
551 * @return See above.
552 */
553template<typename Time_unit, typename N_items>
554double to_mbit_per_sec(N_items items_per_time, size_t bits_per_item = 8);
555
556/**
557 * Returns the result of the given non-negative integer divided by a positive integer, rounded up to the nearest
558 * integer. Internally, it avoids floating-point math for performance.
559 *
560 * @tparam Integer
561 * A signed or unsigned integral type.
562 * @param dividend
563 * Dividend; non-negative or assertion trips.
564 * @param divisor
565 * Divisor; positive or assertion trips.
566 * @return Ceiling of `(dividend / divisor)`.
567 */
568template<typename Integer>
569Integer ceil_div(Integer dividend, Integer divisor);
570
571/**
572 * Provides a way to execute arbitrary (cleanup) code at the exit of the current block. Simply
573 * save the returned object into a local variable that will go out of scope when your code block
574 * exits. Example:
575 *
576 * ~~~
577 * {
578 * X* x = create_x();
579 * auto cleanup = util::setup_auto_cleanup([&]() { delete_x(x); });
580 * // Now delete_x(x) will be called no matter how the current { block } exits.
581 * // ...
582 * }
583 * ~~~
584 *
585 * @todo setup_auto_cleanup() should take a function via move semantics.
586 *
587 * @tparam Cleanup_func
588 * Any type such that given an instance `Cleanup_func f`, the expression `f()` is valid.
589 * @param func
590 * `func()` will be called when cleanup is needed.
591 * @return A light-weight object that, when it goes out of scope, will cause `func()` to be called.
592 */
593template<typename Cleanup_func>
594Auto_cleanup setup_auto_cleanup(const Cleanup_func& func);
595
596/**
597 * Returns `true` if and only if the given value is within the given range, inclusive.
598 *
599 * @param min_val
600 * Lower part of the range.
601 * @param val
602 * Value to check.
603 * @param max_val
604 * Higher part of the range. Must be greater than or equal to `min_val`, or behavior is undefined.
605 * @tparam T
606 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
607 * `unsigned int`, #Fine_duration.
608 * @return `true` if and only if `val` is in [`min_val`, `max_val`].
609 */
610template<typename T>
611bool in_closed_range(T const & min_val, T const & val, T const & max_val);
612
613/**
614 * Returns `true` if and only if the given value is within the given range, given as a [low, high)
615 * pair.
616 *
617 * @param min_val
618 * Lower part of the range.
619 * @param val
620 * Value to check.
621 * @param max_val
622 * Higher part of the range. Must be greater than `min_val`, or behavior is undefined.
623 * @tparam T
624 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
625 * `unsigned int`, #Fine_duration.
626 * @return `true` if and only if `val` is in [`min_val`, `max_val`), i.e., `min_val` <= `val` < `max_val`.
627 */
628template<typename T>
629bool in_closed_open_range(T const & min_val, T const & val, T const & max_val);
630
631/**
632 * Returns `true` if and only if the given value is within the given range, given as a (low, high]
633 * pair.
634 *
635 * @param min_val
636 * Lower part of the range.
637 * @param val
638 * Value to check.
639 * @param max_val
640 * Higher part of the range. Must be greater than `min_val`, or behavior is undefined.
641 * @tparam T
642 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
643 * `unsigned int`, #Fine_duration.
644 * @return `true` if and only if `val` is in (`min_val`, `max_val`], i.e., `min_val` < `val` <= `max_val`.
645 */
646template<typename T>
647bool in_open_closed_range(T const & min_val, T const & val, T const & max_val);
648
649/**
650 * Returns `true` if and only if the given value is within the given range, given as a (low, high)
651 * pair.
652 *
653 * @param min_val
654 * Lower part of the range.
655 * @param val
656 * Value to check.
657 * @param max_val
658 * Higher part of the range. Must be at least 2 greater than `min_val`, or behavior is undefined.
659 * @tparam T
660 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
661 * `unsigned int`, #Fine_duration.
662 * @return `true` if and only if `val` is in (`min_val`, `max_val`), i.e., `min_val` < `val` < `max_val`.
663 */
664template<typename T>
665bool in_open_open_range(T const & min_val, T const & val, T const & max_val);
666
667/**
668 * Returns `true` if and only if the given key is present at least once in the given associative
669 * container.
670 *
671 * @tparam Container
672 * Associative container type (`boost::unordered_map`, `std::set`, etc.).
673 * In particular must have the members `find()`, `end()`, and `key_type`.
674 * @param container
675 * Container to search.
676 * @param key
677 * Key to find.
678 * @return See above.
679 */
680template<typename Container>
681bool key_exists(const Container& container, const typename Container::key_type& key);
682
683/**
684 * Performs `*minuend -= subtrahend`, subject to a floor of `floor`. Avoids underflow/overflow to the extent
685 * it's reasonably possible, but no more. The return value indicates whether
686 * the floor was hit; this allows one to chain high-performance subtractions like this:
687 *
688 * ~~~
689 * double t = 44;
690 * int x = rnd(); // Suppose x == 123, for example.
691 * // Avoids the 2nd, 3rd computation altogether, as the first detects that x >= 44, and thus t == 0 regardless.
692 * subtract_with_floor(&t, x) &&
693 * subtract_with_floor(&t, long_computation()) &&
694 * subtract_with_floor(&t, another_long_computation());
695 * ~~~
696 *
697 * @tparam Minuend
698 * Numeric type.
699 * @tparam Subtrahend
700 * Numeric type, such that given `Subtrahend s`, `Minuend(s)` is something reasonable for all `s` involved.
701 * @param minuend
702 * `*minuend` is set to either `(*minuend - subtrahend)` or `floor`, whichever is higher.
703 * @param subtrahend
704 * Ditto.
705 * @param floor
706 * Ditto. Negatives are OK. Typically it's best to keep the magnitude of this small.
707 * @return `true` if `*minuend == floor` at function exit; `false` if `*minuend > floor`.
708 */
709template<typename Minuend, typename Subtrahend>
710bool subtract_with_floor(Minuend* minuend, const Subtrahend& subtrahend, const Minuend& floor = 0);
711
712/**
713 * Answers the question *what's the smallest integer number of `To`s sufficient to verbatim store the given number of
714 * `From`s?*, where `From` and `To` are POD types.
715 *
716 * For example, one needs 1 `uint64_t` to store 1, 2, 3, or 4 `uint16_t`s, hence
717 * `size_unit_convert<uint16_t, uint64_t>(1 or 2 or 3 or 4) == 1`. Similarly, 5 or 6 or 7 or 8 -> 2.
718 * It works in the opposite direction, too; if we are storing `uint64_t`s in multiples of `uint16_t`, then
719 * 1 -> 4, 2 -> 8, 3 -> 12, etc.
720 *
721 * To be clear, when `From` bit width is smaller than `To` bit width, some of the bits will be padding and
722 * presumably unused. For example, raw data buffers of arbitrary bytes are often arranged in multi-byte "words."
723 *
724 * @tparam From
725 * The POD type of the values that must be encoded in `From`s.
726 * @tparam To
727 * The POD type of the array that would store the `From`s.
728 * @param num_froms
729 * How many `From`s does one want to encode in an array of `To`s?
730 * @return How many `To`s are sufficient to encode `num_from` `From`s verbatim?
731 */
732template<typename From, typename To>
733size_t size_unit_convert(From num_froms);
734
735/**
736 * Given a generic sequence (integer -> object) generates a generic map (object -> integer) providing inverse
737 * lookup. See the 3-arg overload if you want to provide a more complex lookup function to store something else based
738 * on each index.
739 *
740 * A naive way of implementing lookups otherwise would be a linear search for the object; using this will
741 * use RAM to avoid the slow searches.
742 *
743 * @tparam Sequence
744 * Sequence such as `std::vector<T>` or `std::array<T>`.
745 * Informally, `T` should be something light-weight and hence usable as a key type for a map type (`Map`).
746 * @tparam Map
747 * Map that maps `T` from `Sequence` to `size_t`. Example: `std::map<T, size_t>`.
748 * @param src_seq
749 * Input sequence.
750 * @param target_map
751 * Output map. Note it will *not* be pre-cleared; informally, this means one can shove 2+ lookup maps
752 * into one. If null behavior undefined (assertion may trip).
753 */
754template<typename Map, typename Sequence>
755void sequence_to_inverted_lookup_map(Sequence const & src_seq, Map* target_map);
756
757/**
758 * Similar to the 2-arg overload of sequence_to_inverted_lookup_map() but with the ability to store a value based
759 * on the index into the input sequence instead of that index itself. See the 2-arg overload.
760 *
761 * @tparam Sequence
762 * Sequence such as `std::vector<T>` or `std::array<T>`.
763 * Informally, `T` should be something light-weight and hence usable as a key type for a map type (`Map`).
764 * @tparam Map
765 * Map that maps `T` from `Sequence` to another type `X`. Example:
766 * `unordered_map<T, X>`, where an `X` can be computed from a `size_t` index.
767 * @param src_seq
768 * See 2-arg overload.
769 * @param target_map
770 * See 2-arg overload.
771 * @param idx_to_map_val_func
772 * Given an index `idx` into `src_seq`, `(*target_map)[]` shall contain `idx_to_map_val_func(idx)`.
773 * Use this arg to instead perform a second lookup before storing a value in `*target_map`.
774 * Use the 2-arg overload if you'd like to store the index itself.
775 */
776template<typename Map, typename Sequence>
778 (Sequence const & src_seq, Map* target_map,
779 const Function<typename Map::mapped_type (size_t)>& idx_to_map_val_func);
780
781/**
782 * Writes to the specified string, as if the given arguments were each passed, via `<<` in sequence,
783 * to an `ostringstream`, and then the result were appended to the aforementioned string variable.
784 *
785 * Tip: It works nicely, 99% as nicely as simply `<<`ing an `ostream`; but certain language subtleties mean
786 * you may have to fully qualify some template instances among `ostream_args`. Do so if you receive a
787 * "deduced incomplete pack" (clang) or similar error, as I have seen when using, e.g., `chrono::symbol_format`
788 * formatter (which the compile error forced me to qualify as: `symbol_format<char, ostream::traits_type>`).
789 *
790 * @see log::Thread_local_string_appender for an even more efficient version of this for some applications that can
791 * also enable a continuous stream across multiple stream-writing statements over time.
792 *
793 * @tparam ...T
794 * Each type `T` is such that `os << t`, with types `T const & t` and `ostream& os`, builds and writes
795 * `t` to `os`, returning lvalue `os`.
796 * Usually in practice this means the existence of `ostream& operator<<(ostream&, T const &)` or
797 * `ostream& operator<<(ostream&, T)` overload, the latter usually for basic types `T`.
798 * See also tip above, if compiler is unable to deduce a given `T` (even when it *would* deduce it
799 * in `os << t`).
800 * @param target_str
801 * Pointer to the string to which to append.
802 * @param ostream_args
803 * One or more arguments, such that each argument `arg` is suitable for `os << arg`, where
804 * `os` is an `ostream`.
805 */
806template<typename ...T>
807void ostream_op_to_string(std::string* target_str, T const &... ostream_args);
808
809/**
810 * Equivalent to ostream_op_to_string() but returns a new `string` by value instead of writing to the caller's
811 * `string`. This is useful at least in constructor initializers, where it is not possible to first
812 * declare a stack variable.
813 *
814 * With the C++11-y use of move semantics in STL it should be no slower than using
815 * `ostream_op_to_string()` -- meaning, it is no slower, period, as this library now requires C++11.
816 *
817 * @tparam ...T
818 * See ostream_op_to_string().
819 * @param ostream_args
820 * See ostream_op_to_string().
821 * @return Resulting `std::string`.
822 */
823template<typename ...T>
824std::string ostream_op_string(T const &... ostream_args);
825
826/**
827 * "Induction step" version of variadic function template that simply outputs arguments 2+ via
828 * `<<` to the given `ostream`, in the order given.
829 *
830 * @tparam ...T_rest
831 * See `...T` in ostream_op_to_string().
832 * @param remaining_ostream_args
833 * See `ostream_args` in ostream_op_to_string().
834 * @tparam T1
835 * Same as each of `...T_rest`.
836 * @param ostream_arg1
837 * Same as each of `remaining_ostream_args`.
838 * @param os
839 * Pointer to stream to which to sequentially send arguments for output.
840 */
841template<typename T1, typename ...T_rest>
842void feed_args_to_ostream(std::ostream* os, T1 const & ostream_arg1, T_rest const &... remaining_ostream_args);
843
844/**
845 * "Induction base" for a variadic function template, this simply outputs given item to given `ostream` via `<<`.
846 *
847 * @tparam T
848 * See each of `...T` in ostream_op_to_string().
849 * @param os
850 * Pointer to stream to which to sequentially send arguments for output.
851 * @param only_ostream_arg
852 * See each of `ostream_args` in ostream_op_to_string().
853 */
854template<typename T>
855void feed_args_to_ostream(std::ostream* os, T const & only_ostream_arg);
856
857/**
858 * Deserializes an `enum class` value from a standard input stream. Reads up to but not including the next
859 * non-alphanumeric-or-underscore character; the resulting string is then mapped to an `Enum`. If none is
860 * recognized, `enum_default` is the result. The recognized values are:
861 * - "0", "1", ...: Corresponds to the underlying-integer conversion to that `Enum`. (Can be disabled optionally.)
862 * - Case-[in]sensitive string encoding of the `Enum`, as determined by `operator<<(ostream&)` -- which must exist
863 * (or this will not compile). Informally we recommend the encoding to be the non-S_-prefix part of the actual
864 * `Enum` member; e.g., `"WARNING"` for log::Sev::S_WARNING.
865 * If the scanned token does not map to any of these, or if end-of-input is encountered immediately (empty token),
866 * then `enum_default` is returned.
867 *
868 * Error semantics: There are no invalid values or exceptions thrown; `enum_default` returned is the worst case.
869 * Do note `*is_ptr` may not be `good() == true` after return.
870 *
871 * Tip: It is convenient to implement `operator>>(istream&)` in terms of istream_to_enum(). With both
872 * `>>` and `<<` available, serialization/deserialization of the `enum class` will work; this enables a few key things
873 * to work, including parsing from config file/command line via and conversion from `string` via `lexical_cast`.
874 *
875 * Informal convention suggestion: `S_END_SENTINEL` should be the sentinel member of `Enum`. E.g., see log::Sev.
876 *
877 * @tparam Enum
878 * An `enum class` which must satisfy the following requirements or else risk undefined behavior (if it
879 * compiles): An element, `enum_lowest`, has a non-negative integer value.
880 * Subsequent elements are strictly monotonically increasing with increment 1, up to and including
881 * `enum_sentinel`. (Elements outside [`enum_lowest`, `enum_sentinel`] may exist, as long as their numeric
882 * values don't conflict with those in-range, but informally we recommend against this.)
883 * `ostream << Enum` exists and works without throwing for all values in range
884 * [`enum_lowest`, `enum_sentinel`). Each `<<`-serialized string must be distinct from the others.
885 * Each `<<`-serialized string must start with a non-digit and must consist only of alphanumerics and
886 * underscores. Exception: digit-leading is allowed if and only if `!accept_num_encoding`, though
887 * informally we recommend against it as a convention.
888 *
889 * @param is_ptr
890 * Stream from which to deserialize.
891 * @param enum_default
892 * Value to return if the token does not match either the numeric encoding (if enabled) or the `<<` encoding.
893 * `enum_sentinel` is a sensible (but not the only sensible) choice.
894 * @param enum_sentinel
895 * `Enum` value such that all valid deserializable values have numeric conversions strictly lower than it.
896 * @param accept_num_encoding
897 * If `true`, a numeric value is accepted as an encoding; otherwise it is not (and will yield `enum_default`
898 * like any other non-matching token).
899 * @param case_sensitive
900 * If `true`, then the token must exactly equal an `ostream<<` encoding of a non-sentinel `Enum`;
901 * otherwise it may equal it modulo different case.
902 * @param enum_lowest
903 * The lowest `Enum` value. Its integer value is very often 0, sometimes 1.
904 * Behavior undefined if it is negative.
905 * @return See above.
906 */
907template<typename Enum>
908Enum istream_to_enum(std::istream* is_ptr, Enum enum_default, Enum enum_sentinel,
909 bool accept_num_encoding = true, bool case_sensitive = false,
910 Enum enum_lowest = Enum(0));
911
912/**
913 * Sets certain `chrono`-related formatting on the given `ostream` that results in a consistent, desirable output
914 * of `duration`s and certain types of `time_point`s. As of this writing this includes enabling short unit format
915 * (e.g., "ms" instead of "milliseconds") and avoiding Unicode characters (the Greek letter for micro becomes
916 * a similar-looking "u" instead).
917 *
918 * @see log::beautify_chrono_logger_this_thread() to affect a Logger directly.
919 * @see flow::async in which new threads are set to use this formatting automatically. However you'll want to
920 * do this explicitly for the startup thread.
921 *
922 * @param os
923 * The stream to affect.
924 */
925void beautify_chrono_ostream(std::ostream* os);
926
927/**
928 * Estimate of memory footprint of the given value, including memory allocated on its behalf -- but
929 * excluding its shallow `sizeof`! -- in bytes.
930 *
931 * @param val
932 * Value.
933 * @return See above.
934 */
935size_t deep_size(const std::string& val);
936
937// Macros.
938
939/**
940 * Expands to an `ostream` fragment `X` (suitable for, for example: `std::cout << X << ": Hi!"`) containing
941 * the file name, function name, and line number at the macro invocation's context.
942 *
943 * It's a functional macro despite taking no arguments to convey that it mimics a free function sans args.
944 *
945 * @internal
946 *
947 * ### Performance ###
948 * The items `<<`ed onto the target `ostream` are each evaluated at compile-time.
949 * This includes the expression involving flow::util::get_last_path_segment() which is `constexpr`.
950 */
951#define FLOW_UTIL_WHERE_AM_I() \
952 FLOW_UTIL_WHERE_AM_I_FROM_ARGS(::flow::util::get_last_path_segment \
953 (::flow::util::String_view(__FILE__, sizeof(__FILE__) - 1)), \
954 ::flow::util::String_view(__FUNCTION__, sizeof(__FUNCTION__) - 1), \
955 __LINE__)
956
957/**
958 * Same as FLOW_UTIL_WHERE_AM_I() but evaluates to an `std::string`. It's probably a bit slower as
959 * well. Update: In fact, it's probably significantly slower as of this writing, as
960 * FLOW_UTIL_WHERE_AM_I() evaluates the `<<`ed items at compile-time, while this cannot due to how it's implemented.
961 *
962 * @internal
963 *
964 * flow::util::get_where_am_i_str() is too clever to become a `constexpr` function, even if it were radically rewritten,
965 * so this macro evaluates to a partially runtime-computed expression. Hence the note just above about perf.
966 *
967 * @todo See if FLOW_UTIL_WHERE_AM_I_STR() can be coaxed into a compile-time expression after all. It is used in
968 * quite a lot of frequently executed code, namely at the top of most Flow (and Flow-like) APIs that can emit errors.
969 * See notes inside flow::util::get_where_am_i_str() on this as of this writing.
970 */
971#define FLOW_UTIL_WHERE_AM_I_STR() \
972 ::flow::util::get_where_am_i_str(::flow::util::get_last_path_segment \
973 (::flow::util::String_view(__FILE__, sizeof(__FILE__) - 1)), \
974 ::flow::util::String_view(__FUNCTION__, sizeof(__FUNCTION__) - 1), \
975 __LINE__)
976
977/**
978 * Use this to create a semicolon-safe version of a "void" functional macro definition consisting of at least two
979 * statements; or of one statement that would become two statements by appending a semicolon.
980 *
981 * There may be other use cases where it might be useful, though none more has come to mind as of this writing.
982 * Loosely speaking, IF your sub-statements are always blocks, and you have a "void" functional macro to be used in
983 * the typical way (every use is a statement that looks like a function call), and the macro's definition is anything
984 * *other* than an expression with an intentionally missing trailing semicolon, THEN you should probably wrap
985 * that would-be macro definition in a FLOW_UTIL_SEMICOLON_SAFE(). However, read on if you want to know rationale
986 * and/or formalities.
987 *
988 * ### Formal use case requirements ###
989 * The following is assumed about every *use* of this macro; behavior is undefined otherwise.
990 *
991 * - The macro's invocation is the *entire definition* of another macro, M.
992 * - M is a functional macro taking 0 or more arguments (possibly variadic).
993 * - The following is true about every *use* of the macro M:
994 * - The invocation is written as if M is a free function in the C language, and it is being "called"
995 * as the *entirety* of the statement containing that "call." That is, it must look like this:
996 *
997 * ~~~
998 * M(...arg 1 value..., ...arg 2 value..., ...more...); // (Or however many args M actually allows.)
999 * ~~~
1000 *
1001 * ### Known use case 1: Macro definition is 2+ statements ###
1002 * Suppose your macro's value is a series of two or more statements executing in series without braces `{}`
1003 * around the whole thing. Then, in some contexts, invoking that macro as intended might result in
1004 * unexpected runtime misbehavior that the compiler wouldn't detect. A simple example with two
1005 * expressions as individual statements:
1006 *
1007 * ~~~
1008 * #define DOUBLE_AND_PRINT(arg) \
1009 * arg *= 2; // Statement 1. \
1010 * cout << arg // Statement 2. Note the lacking trailing semicolon (invoker must supply it after "call"). \
1011 * DOUBLE_AND_PRINT(x); // No problem. Both statements execute.
1012 * if (some_flag)
1013 * DOUBLE_AND_PRINT(x); // UNINTENDED BEHAVIOR! Statement 2 executes regardless of some_flag!
1014 * ~~~
1015 *
1016 * Granted, if the invoker used braces appropriately around the `if` statement body, there'd be no issue, but one
1017 * cannot always rely on invoker's good style, especially if the macro is part of a public library API.
1018 * Solution:
1019 *
1020 * ~~~
1021 * #define DOUBLE_AND_PRINT(arg) \
1022 * FLOW_UTIL_SEMICOLON_SAFE \
1023 * ( \
1024 * arg *= 2; // Statement 1. \
1025 * cout << arg; // Statement 2. Note necessity for trailing semicolon. \
1026 * )
1027 * DOUBLE_AND_PRINT(x); // No problem. Both statements execute.
1028 * if (some_flag)
1029 * DOUBLE_AND_PRINT(x); // No problem. Both statements execute; or neither one does.
1030 * ~~~
1031 *
1032 * One might ask: Why not simply surround the 2+ statements with braces `{}` to eliminate the problem more simply?
1033 * Answer: This actually would turn the use case into the following other problematic use case.
1034 *
1035 * ### Known use case 2: Required semicolon `;` trailing macro invocation leads to syntax error ###
1036 * Recall that the premise *requires* invoker to call your macro M like `M();`, meaning they will *always* put
1037 * a semicolon after the invocation. Now suppose that doing so will turn one statement (which is M's definition)
1038 * into two. Another way of putting it: Suppose M's body is already a complete statement, even without the required
1039 * trailing `;` (and there is no way to make it otherwise; usually [always?] because it ends with a `}`).
1040 * Then in some contexts it'll cause a syntax error. Example:
1041 *
1042 * ~~~
1043 * #define CHECK_AND_LOG(msg) \
1044 * if (filter()) \
1045 * { \
1046 * log(msg); \
1047 * } // Semicolon will always be added right here.
1048 * CHECK_AND_LOG("Hello."); // No problem. The empty ; statement introduced is harmless.
1049 * if (terminating)
1050 * CHECK_AND_LOG(msg); // SYNTAX ERROR! The empty ; will make the `else` illegal.
1051 * else
1052 * exit();
1053 * ~~~
1054 *
1055 * Removing the `;` from the invocation is no solution. Firstly it'll confuse many editors that will think the
1056 * "function call" (really macro invocation) is missing the usual semicolon. This might cause incorrect
1057 * auto-indentation in the file and who knows what else. Code analyzer tools may also be affected.
1058 * Even ignoring issues where the code is fed into a non-compiler, there are possible flow control problems.
1059 * In this example it'll attach the `else` in the invoking code to the inner `if` (from the macro)
1060 * instead of the outer `if` (in the invoking code) as intended. Wrapping the body of `CHECK_AND_LOG()` in
1061 * the proposed wrapper will resolve all stated problems. (Solution code omitted for brevity and obviousness
1062 * at this point.)
1063 *
1064 * @note Adding this wrapper would slightly adversely affect performance in the complete absence of compiler
1065 * optimization, but even the most basic optimizer (one capable of eliminating `if (false)` and similar)
1066 * should entirely eliminate any such performance degradation.
1067 *
1068 * @param ARG_func_macro_definition
1069 * The intended value of a functional macro, such that the "function" it approximates would have
1070 * return type `void`. Behavior is undefined if the value of this parameter ends in a semicolon, or
1071 * if the value contains a statement that includes another statement within it that is not a block
1072 * (`{ ... }`). (The rules in the last [English] statement may or may not be strictly necessary,
1073 * but requiring these allows me to generalize/reason more straightforwardly. In any case, one rule is
1074 * assumed good style anyway, while the other is simply practical in this context.)
1075 * @return Code to be used as the entire definition of a macro whose definition would have been
1076 * `ARG_func_macro_definition` if not for the resulting compile error or unexpected flow control
1077 * effects detailed above.
1078 */
1079#define FLOW_UTIL_SEMICOLON_SAFE(ARG_func_macro_definition) \
1080 do \
1081 { \
1082 ARG_func_macro_definition \
1083 } \
1084 while (false)
1085
1086} // namespace flow::util
An object of this class is a map that combines the lookup speed of a boost::unordered_map<> and order...
An object of this class is a set that combines the lookup speed of an unordered_set<> and ordering an...
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
Definition: basic_blob.hpp:29
boost::unique_lock< Mutex_recursive > Lock_guard_recursive
(Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for Mutex_recursive mutex...
Definition: util_fwd.hpp:291
bool in_closed_open_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, given as a [low,...
Definition: util.hpp:262
bool key_exists(const Container &container, const typename Container::key_type &key)
Returns true if and only if the given key is present at least once in the given associative container...
Definition: util.hpp:276
void beautify_chrono_ostream(std::ostream *os_ptr)
Sets certain chrono-related formatting on the given ostream that results in a consistent,...
Definition: util.cpp:173
Auto_cleanup setup_auto_cleanup(const Cleanup_func &func)
Provides a way to execute arbitrary (cleanup) code at the exit of the current block.
Definition: util.hpp:282
Thread::id Thread_id
Short-hand for an OS-provided ID of a util::Thread.
Definition: util_fwd.hpp:90
void sequence_to_inverted_lookup_map(Sequence const &src_seq, Map *target_map, const Function< typename Map::mapped_type(size_t)> &idx_to_map_val_func)
Similar to the 2-arg overload of sequence_to_inverted_lookup_map() but with the ability to store a va...
Definition: util.hpp:367
double to_mbit_per_sec(N_items items_per_time, size_t bits_per_item)
Utility that converts a bandwidth in arbitrary units in both numerator and denominator to the same ba...
Definition: util.hpp:212
std::string buffers_dump_string(const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line)
Identical to buffers_to_ostream() but returns an std::string instead of writing to a given ostream.
Definition: util.hpp:481
Enum istream_to_enum(std::istream *is_ptr, Enum enum_default, Enum enum_sentinel, bool accept_num_encoding, bool case_sensitive, Enum enum_lowest)
Deserializes an enum class value from a standard input stream.
Definition: util.hpp:498
boost::asio::ip::address_v6 Ip_address_v6
Short-hand for the IPv6 address type.
Definition: util_fwd.hpp:212
boost::asio::ip::address_v4 Ip_address_v4
Short-hand for the IPv4 address type.
Definition: util_fwd.hpp:210
bool subtract_with_floor(Minuend *minuend, const Subtrahend &subtrahend, const Minuend &floor)
Performs *minuend -= subtrahend, subject to a floor of floor.
Definition: util.hpp:299
size_t deep_size(const std::string &val)
Estimate of memory footprint of the given value, including memory allocated on its behalf – but exclu...
Definition: util.cpp:186
boost::unique_lock< Mutex > Lock_guard
Short-hand for advanced-capability RAII lock guard for any mutex, ensuring exclusive ownership of tha...
Definition: util_fwd.hpp:265
boost::shared_mutex Mutex_shared_non_recursive
Short-hand for non-reentrant, shared-or-exclusive mutex.
Definition: util_fwd.hpp:243
size_t size_unit_convert(From num_froms)
Answers the question what's the smallest integer number of Tos sufficient to verbatim store the given...
Definition: util.hpp:321
std::string ostream_op_string(T const &... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
Definition: util.hpp:356
boost::shared_lock< Mutex_shared_non_recursive > Lock_guard_shared_non_recursive_sh
(Deprecated given C++1x) Short-hand for shared mode advanced-capability RAII lock guard for Mutex_sha...
Definition: util_fwd.hpp:300
Integer ceil_div(Integer dividend, Integer divisor)
Returns the result of the given non-negative integer divided by a positive integer,...
Definition: util.hpp:233
void swap(Basic_blob< Allocator, S_SHARING_ALLOWED > &blob1, Basic_blob< Allocator, S_SHARING_ALLOWED > &blob2, log::Logger *logger_ptr)
Equivalent to blob1.swap(blob2).
bool in_open_open_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, given as a (low,...
Definition: util.hpp:270
bool in_open_closed_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, given as a (low,...
Definition: util.hpp:254
void ostream_op_to_string(std::string *target_str, T const &... ostream_args)
Writes to the specified string, as if the given arguments were each passed, via << in sequence,...
Definition: util.hpp:342
boost::unique_lock< Mutex_non_recursive > Lock_guard_non_recursive
(Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for Mutex_non_recursive m...
Definition: util_fwd.hpp:283
boost::recursive_mutex Mutex_recursive
Short-hand for reentrant, exclusive mutex.
Definition: util_fwd.hpp:218
boost::unique_lock< Mutex_shared_non_recursive > Lock_guard_shared_non_recursive_ex
(Deprecated given C++1x) Short-hand for exclusive mode advanced-capability RAII lock guard for Mutex_...
Definition: util_fwd.hpp:309
boost::shared_lock< Mutex_noop_shared_non_recursive > Lock_guard_noop_shared_non_recursive_sh
(Deprecated given C++1x) Equivalent to Lock_guard_shared_non_recursive_sh but applied to Mutex_noop_s...
Definition: util_fwd.hpp:318
std::ostream & buffers_to_ostream(std::ostream &os, const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line)
Writes a multi- or single-line string representation of the provided binary data to an output stream,...
Definition: util.hpp:388
Task_engine::strand Strand
Short-hand for boost.asio strand, an ancillary class that works with Task_engine for advanced task sc...
Definition: util_fwd.hpp:138
bool in_closed_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, inclusive.
Definition: util.hpp:246
boost::shared_ptr< void > Auto_cleanup
Helper type for setup_auto_cleanup().
Definition: util_fwd.hpp:205
boost::shared_lock< Shared_mutex > Shared_lock_guard
Short-hand for shared mode advanced-capability RAII lock guard, particuarly for Mutex_shared_non_recu...
Definition: util_fwd.hpp:275
boost::chrono::microseconds time_since_posix_epoch()
Get the current POSIX (Unix) time as a duration from the Epoch time point.
Definition: util.cpp:147
boost::unique_lock< Mutex_noop_shared_non_recursive > Lock_guard_noop_shared_non_recursive_ex
(Deprecated given C++1x) Equivalent to Lock_guard_shared_non_recursive_ex but applied to Mutex_noop_s...
Definition: util_fwd.hpp:327
boost::mutex Mutex_non_recursive
Short-hand for non-reentrant, exclusive mutex. ("Reentrant" = one can lock an already-locked-in-that-...
Definition: util_fwd.hpp:215
boost::asio::io_service Task_engine
Short-hand for boost.asio event service, the central class of boost.asio.
Definition: util_fwd.hpp:135
boost::asio::basic_waitable_timer< Fine_clock > Timer
boost.asio timer.
Definition: util_fwd.hpp:202
boost::null_mutex Mutex_noop_shared_non_recursive
Short-hand for a mutex type equivalent to util::Mutex_shared_non_recursive – except that the lock/unl...
Definition: util_fwd.hpp:251
boost::thread Thread
Short-hand for standard thread class.
Definition: util_fwd.hpp:78
boost::asio::ip::udp::endpoint Udp_endpoint
Short-hand for the UDP endpoint (IP/port) type.
Definition: util_fwd.hpp:208
void feed_args_to_ostream(std::ostream *os, T1 const &ostream_arg1, T_rest const &... remaining_ostream_args)
"Induction step" version of variadic function template that simply outputs arguments 2+ via << to the...
Definition: util.hpp:327