Flow 3.0.0
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 <boost/core/span.hpp>
26#include <iostream>
27#include <memory>
28#include <cstddef>
29
30/**
31 * Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module.
32 *
33 * Each symbol therein is typically used by at least 1 other Flow module; but all public symbols (except ones
34 * under a detail/ subdirectory) are intended for use by Flow user as well.
35 *
36 * @todo Since Flow gained its first users beyond the original author, some Flow-adjacent code has been written from
37 * which Flow can benefit, including additions to flow::util module. (Flow itself continued to be developed, but some
38 * features were added elsewhere for expediency; this is a reminder to factor them out into Flow for the benefit of
39 * all.) Some features to migrate here might be: conversion between boost.chrono and std.chrono types; (add more
40 * here).
41 */
42namespace flow::util
43{
44// Constants.
45
46/// Configures a #Span at compile-time to have a variable, rather than constant, length (use it as template arg).
47constexpr size_t DYNAMIC_EXTENT = boost::dynamic_extent;
48
49// Types.
50
51// Find doc headers near the bodies of these compound types.
52
53template<typename T, typename Allocator = std::allocator<T>>
55
56template<typename Key, typename Mapped, typename Hash = boost::hash<Key>, typename Pred = std::equal_to<Key>>
57class Linked_hash_map;
58template<typename Key, typename Hash = boost::hash<Key>, typename Pred = std::equal_to<Key>>
59class Linked_hash_set;
60
61template<typename Target_t, typename Mutex_t>
62class Locked_proxy;
63
64class Null_interface;
65
67template<typename range_t>
69template<typename range_t>
71
72template<typename Value_t>
73class Scoped_setter;
74
75template<typename Target_ptr,
76 typename Const_target_ptr
77 = typename std::pointer_traits<Target_ptr>::template rebind<typename Target_ptr::element_type const>>
79
80class String_ostream;
81
82template<typename Thread_local_state_t>
84template<typename Thread_local_state_t>
86template<typename Obj_t, typename Tag_t = void>
88class Poll_flag;
89template<typename Shared_state_t>
91
92template<typename Tag, typename... Args>
93class Action_registry;
94
96struct Thread_token;
97
98/**
99 * Short-hand for standard thread class.
100 * We use/encourage use of boost.thread threads (and other boost.thread facilities) over std.thread counterparts --
101 * simply because it tends to be more full-featured. However, reminder: boost.thread IS (API-wise at least)
102 * std.thread, plus more (advanced?) stuff. Generally, boost.thread-using code can be converted to std.thread
103 * with little pain, unless one of the "advanced?" features is used.
104 */
105using Thread = boost::thread;
106
107/* (The @namespace and @brief thingies shouldn't be needed, but some Doxygen bug necessitated them.
108 * See flow::log::fs for explanation... same thing here.) */
109
110/**
111 * @namespace flow::util::this_thread
112 * @brief Short-hand for standard this-thread namespace. Paired with util::Thread.
113 */
114namespace this_thread = boost::this_thread;
115
116/**
117 * Short-hand for an OS-provided ID of a util::Thread.
118 *
119 * @warning Various OS will recycle values, so a #Thread_id is only unique among currently-live threads, not
120 * across time. However:
121 * @see util::this_thread_unique_token() which provides a really-unique (for a given process) ID instead.
122 */
123using Thread_id = Thread::id;
124
125/**
126 * Short-hand for boost.asio event service, the central class of boost.asio.
127 *
128 * ### Naming ###
129 * The reasons for the rename -- as opposed to simply calling it `Io_service` (historically it was indeed so named) --
130 * are as follows. To start, a later version of Boost (to which we eventually moved) realigned
131 * boost.asio's API to match the feedback boost.asio received when submitted as a candidate for inclusion into
132 * the official STL (sometime after C++17); in this reorg they renamed it from `io_service` to `io_context`.
133 * That's not the actual reason but more of a symptom of similar reasoning to the following:
134 * - "Service" sounds like something that has its own thread(s) perhaps, which `io_service` actually doesn't;
135 * it *can* (and typically is) used to take over at least one thread, but that's not a part of its "essence," so
136 * to speak. I've noticed that when boost.asio neophytes see "service" they intuitively draw incorrect assumptions
137 * about what it does, and then one must repeatedly dash those assumptions.
138 * - Furthermore (though apparently boost.asio guys didn't agree or didn't agree strongly enough) "I/O" implies
139 * an `io_service` is all about working with various input/output (especially networking). While it's true
140 * that roughly 50% of the utility of boost.asio is its portable sockets/networking API, the other 50% is about
141 * its ability to flexibly execute user tasks in various threads; and, indeed, `io_service` *itself* is more about
142 * the latter 50% rather than the former. Its two most basic and arguably oft-used features are simply
143 * `io_service::post()` (which executes the given task ASAP); and the `basic_waitable_timer` set of classes
144 * (which execute task at some specified point in the future). Note these have nothing to do with networking or
145 * I/O of any kind. The I/O comes from the "I/O object" classes/etc., such as `tcp::socket`, but those
146 * are *not* `io_service`; they merely work together with it to execute the user-specified success/failure handlers.
147 *
148 * So, neither "I/O" nor "service" is accurate. To fix both, then, we used this rename reasoning:
149 * - "I/O" can be replaced by the notion of it executing "tasks." boost.asio doesn't use or define the "task" term,
150 * sticking to "handler" or "functor" or "function," but we feel it's a reasonable term in this context.
151 * (Function, etc., doesn't cover all possibilities. Handler is OK, but when it's not in response to any event --
152 * as with vanilla `post()` -- what is it handling?)
153 * - "Service" is trickier to replace. It's a battle between "too generic" and "too specific and therefore long to
154 * type." Plus there's the usual danger of accidentally overloading a term already used elsewhere nearby.
155 * Some ideas considered were: manager, engine, execution engine, queue, queues, context (which boost.asio chose),
156 * and various abbreviations thereof. Ultimately it came down to context vs. engine, and I chose engine because
157 * context is just a little vague, or it suggests an arbitrary grouping of things -- whereas "engine" actually
158 * implies action: want to express this thing provides logical/algorithmic value as opposed to just bundling
159 * stuff together as "context" objects often do (e.g., "SSL context" in openssl). Indeed `io_service` does provide
160 * immense algorithmic value.
161 * - Manager: generic but not bad; clashes with "Windows task manager" and such.
162 * - Execution engine: good but long.
163 * - Queue: early candidate, but at the very least it's not a *single* queue; if there are multiple threads
164 * `io_context::run()`ning then to the extent there are any queues there might be multiple.
165 * - Queues, qs: better... but having a thing called `Task_qs` -- of which there could be multiple (plural) --
166 * was clumsy. (An early proof-of-concept used `Task_qs`; people were not fans.)
167 */
168using Task_engine = boost::asio::io_context;
169
170/// Short-hand for boost.asio strand, an ancillary class that works with #Task_engine for advanced task scheduling.
171using Strand = Task_engine::strand;
172
173/**
174 * boost.asio timer. Can schedule a function to get called within a set amount of time or at
175 * a certain specific time relative to some Epoch.
176 *
177 * @see schedule_task_from_now() (and friends) for a simpler task-scheduling API (which internally uses this
178 * `Timer`). The notes below still apply however. Please read them even if you won't use `Timer` directly.
179 *
180 * Important: While one can schedule events using very precise units using #Fine_duration, the
181 * timer may not actually have that resolution. That is, I may schedule something to happen in 1
182 * millisecond and then measure the time passed, using a high-res clock like #Fine_clock, and discover that
183 * the wait was actually 15 milliseconds. This is not a problem for most timers. (In Flow itself, the most advanced
184 * use of timers by far is in flow::net_flow. Timers used in flow::net_flow -- delayed ACK timer, Drop Timer, simulated
185 * latency timer -- typically are for `n x 50` milliseconds time periods or coarser.) However that may not be the
186 * case for all timers. (In particular, flow::net_flow packet pacing may use finer time periods.)
187 *
188 * @note The flow::net_flow references in the present doc header speak of internal implementation details -- not
189 * of interest to the `net_flow` *user*. I leave them in this public doc header for practical purposes, as
190 * examples needed to discuss some Inside-Baseball topics involved.
191 *
192 * So I looked into what boost.asio provides. `deadline_timer` uses the system clock
193 * (`universal_time()`) as the time reference, while `basic_waitable_timer<Fine_clock>` uses the
194 * high-resolution clock (see #Fine_clock). I tested both (using `wait()`s of various lengths
195 * and using #Fine_clock to measure duration) and observed the following resolutions on certain OS
196 * (not listing the hardware):
197 *
198 * - Linux (2.6.x kernel): sub-2 millisecond resolution, with some variance.
199 * (Note: This Linux's `glibc` is too old to provide the `timerfd` API, therefore Boost falls back to
200 * using `epoll_wait()` directly; on a newer Linux this may get better results.)
201 * - Windows 7: 15 millisecond resolution, with little variance.
202 * - macOS: untested. @todo Test macOS timer fidelity.
203 *
204 * These results were observed for BOTH `deadline_timer` and `basic_waitable_timer<Fine_clock>`
205 * in Boost 1.50. Thus, there was no resolution advantage to using the latter -- only an interface advantage.
206 * Conclusion: we'd be well-advised not to rely on anything much smaller than 20 milliseconds when
207 * scheduling timer events. One technique might be, given any time T < 20 ms, to assume T = 0
208 * (i.e., execute immediately). This may or may not be appropriate depending on the situation.
209 *
210 * However, using `basic_waitable_timer<Fine_clock>` may get an additional nice property: #Fine_clock
211 * always goes forward and cannot be affected by NTP or user changes. `deadline_timer` may or may not
212 * be affected by such tomfoolery (untested, but the potential is clearly there). Therefore we do the best
213 * we can by using the #Fine_clock-based timer.
214 *
215 * @todo Upgrade to newer Boost and keep testing timer resolutions on the above and other OS versions.
216 * Update: As of this writing we are on Boost 1.74 now. Needless to say, it is time to reassess the above, as it
217 * 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.
218 * Update: No changes with Boost 1.75, the newest version as of this writing.
219 *
220 * @note One annoying, though fully documented, "feature" of this and all boost.asio timers is that `cancel()`ing it
221 * does not always cause the handler to fire with `operation_aborted` error code. Sometimes it was already "just
222 * about" to fire at `cancel()` time, so the handler will run with no error code regardless of the `cancel()`.
223 * Personally I have never once found this behavior useful, and there is much code currently written to work
224 * around this "feature." Furthermore, even a "successful" cancel still runs the handler but with `operation_aborted`;
225 * 99.999% of the time one would want to just not run it at all. Finally, in many cases, even having to create
226 * a timer object (and then the multiple steps required to actually schedule a thing) feels like more boiler-plate
227 * than should be necessary. To avoid all of these usability issues, see schedule_task_from_now() (and similar),
228 * which is a facility that wraps `Timer` for a boiler-plate-free experience sufficient in the majority of practical
229 * situations. `Timer` is to be used directly when that simpler facility is insufficient.
230 *
231 * @note `b_w_t<Fine_clock>` happens to equal `boost::asio::high_resolution_timer`. We chose to alias
232 * in terms of #Fine_clock merely to ensure that #Fine_duration is one-to-one compatible with it, as it
233 * is defined in terms of #Fine_clock also.
234 */
235using Timer = boost::asio::basic_waitable_timer<Fine_clock>;
236
237/// Helper type for setup_auto_cleanup().
238using Auto_cleanup = boost::shared_ptr<void>;
239
240/// Short-hand for the UDP endpoint (IP/port) type.
241using Udp_endpoint = boost::asio::ip::udp::endpoint;
242/// Short-hand for the IPv4 address type.
243using Ip_address_v4 = boost::asio::ip::address_v4;
244/// Short-hand for the IPv6 address type.
245using Ip_address_v6 = boost::asio::ip::address_v6;
246
247/// Short-hand for non-reentrant, exclusive mutex. ("Reentrant" = one can lock an already-locked-in-that-thread mutex.)
248using Mutex_non_recursive = boost::mutex;
249
250/// Short-hand for reentrant, exclusive mutex.
251using Mutex_recursive = boost::recursive_mutex;
252
253/**
254 * Short-hand for non-reentrant, shared-or-exclusive mutex.
255 * When locking one of these, choose one of:
256 * `Lock_guard<Mutex_shared_non_recursive>`, `Shared_lock_guard<Mutex_shared_non_recursive>`.
257 * The level of locking acquired (shared versus exclusive) depends on which you chose and is thus highly significant.
258 *
259 * @todo Consider changing util::Mutex_shared_non_recursive from `boost::shared_mutex` to `std::shared_mutex`, as
260 * the former has a long-standing unresolved ticket about its impl being slow and/or outdated (as of Boost-1.80).
261 * However see also the note on util::Mutex_shared_non_recursive that explains why it might be best to avoid
262 * this type of mutex altogether in the first place (in most cases).
263 *
264 * ### When to use versus #Mutex_non_recursive ###
265 * Experts suggest fairly strongly that one should be very wary about using a shared mutex, over a simple
266 * non-recursive exclusive mutex, in almost any practical application. The reason there's a trade-off at all is
267 * that a #Mutex_non_recursive is extremely fast to lock and unlock; the entire perf cost is in waiting for
268 * another thread to unlock first; so without contention it's almost *free*. In contrast apparently any real
269 * impl of #Mutex_shared_non_recursive is much slower to lock/unlock. The trade-off is against allowing
270 * reads to proceed in parallel; but experts say this is "worth it" only when these read critical sections
271 * are lengthy and very frequently invoked. So, for example, if the lock/unlock is around an `unordered_map`
272 * lookup with a quick hashing function, it would be quite difficult to induce enough lock contention
273 * to make a shared mutex better than an exclusive one. (Note this is assuming even no perf issue with
274 * `boost::shared_mutex` specifically.)
275 */
276using Mutex_shared_non_recursive = boost::shared_mutex;
277
278/**
279 * Short-hand for a mutex type equivalent to util::Mutex_shared_non_recursive -- except that the lock/unlock mutex ops
280 * all do nothing. One can parameterize templates accordingly; so that an algorithm can be generically written to work
281 * in both single- and multi-threaded contexts without branching into 2 code paths, yet avoid the unnecessary actual
282 * locking in the former case.
283 */
284using Mutex_noop_shared_non_recursive = boost::null_mutex;
285
286/**
287 * Short-hand for advanced-capability RAII lock guard for any mutex, ensuring exclusive ownership of that mutex.
288 * Note the advanced API available for the underlying type: it is possible to relinquish ownership without unlocking,
289 * gain ownership of a locked mutex; and so on.
290 *
291 * @see To grab shared-level ownership of a shared-or-exclusive mutex: use #Shared_lock_guard.
292 *
293 * @tparam Mutex
294 * A non-recursive or recursive mutex type. Recommend one of:
295 * #Mutex_non_recursive, #Mutex_recursive, #Mutex_shared_non_recursive, #Mutex_noop_shared_non_recursive.
296 */
297template<typename Mutex>
298using Lock_guard = boost::unique_lock<Mutex>;
299
300/**
301 * Short-hand for *shared mode* advanced-capability RAII lock guard, particuarly for #Mutex_shared_non_recursive
302 * mutexes.
303 *
304 * @tparam Shared_mutex
305 * Typically #Mutex_shared_non_recursive, but any mutex type with that both-exclusive-and-shared API will work.
306 */
307template<typename Shared_mutex>
308using Shared_lock_guard = boost::shared_lock<Shared_mutex>;
309
310/**
311 * (Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for #Mutex_non_recursive mutexes.
312 *
313 * @todo #Lock_guard_non_recursive is deprecated, now that C++1x made the more flexible
314 * `Lock_guard<Mutex_non_recursive>` possible. Remove it and all (outside) uses eventually.
315 */
316using Lock_guard_non_recursive = boost::unique_lock<Mutex_non_recursive>;
317
318/**
319 * (Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for #Mutex_recursive mutexes.
320 *
321 * @todo #Lock_guard_recursive is deprecated, now that C++1x made the more flexible `Lock_guard<Mutex_recursive>`
322 * possible. Remove it and all (outside) uses eventually.
323 */
324using Lock_guard_recursive = boost::unique_lock<Mutex_recursive>;
325
326/**
327 * (Deprecated given C++1x) Short-hand for *shared mode* advanced-capability RAII lock guard for
328 * #Mutex_shared_non_recursive mutexes.
329 *
330 * @todo #Lock_guard_shared_non_recursive_sh is deprecated, now that C++1x made the more flexible
331 * `Shared_lock_guard<Mutex_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
332 */
333using Lock_guard_shared_non_recursive_sh = boost::shared_lock<Mutex_shared_non_recursive>;
334
335/**
336 * (Deprecated given C++1x) Short-hand for *exclusive mode* advanced-capability RAII lock guard for
337 * #Mutex_shared_non_recursive mutexes.
338 *
339 * @todo #Lock_guard_shared_non_recursive_ex is deprecated, now that C++1x made the more flexible
340 * `Lock_guard<Mutex_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
341 */
342using Lock_guard_shared_non_recursive_ex = boost::unique_lock<Mutex_shared_non_recursive>;
343
344/**
345 * (Deprecated given C++1x) Equivalent to #Lock_guard_shared_non_recursive_sh but applied to
346 * #Mutex_noop_shared_non_recursive.
347 *
348 * @todo #Lock_guard_noop_shared_non_recursive_sh is deprecated, now that C++1x made the more flexible
349 * `Shared_lock_guard<Mutex_noop_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
350 */
351using Lock_guard_noop_shared_non_recursive_sh = boost::shared_lock<Mutex_noop_shared_non_recursive>;
352
353/**
354 * (Deprecated given C++1x) Equivalent to #Lock_guard_shared_non_recursive_ex but applied to
355 * #Mutex_noop_shared_non_recursive.
356 *
357 * @todo #Lock_guard_noop_shared_non_recursive_ex is deprecated, now that C++1x made the more flexible
358 * `Lock_guard<Mutex_noop_shared_non_recursive>` possible. Remove it and all (outside) uses eventually.
359 */
360using Lock_guard_noop_shared_non_recursive_ex = boost::unique_lock<Mutex_noop_shared_non_recursive>;
361
362/**
363 * Short-hand for `std::span`-like type; that is contiguous sequence of objects with the first element of the sequence
364 * at position zero.
365 *
366 * @todo Once we switch to C++20 (from C++17), #Span can be pointed at `std::span` instead of `boost::span`.
367 *
368 * @tparam T
369 * Element type.
370 * @tparam E
371 * Compile-time constant length of a span of this type; or `DYNAMIC_EXTENT` for it to be variable.
372 */
373template<typename T, size_t E = DYNAMIC_EXTENT>
374using Span = boost::span<T, E>;
375
376// Free functions.
377
378/**
379 * Returns a value conceptually similar to `this_thread::get_id()` -- a thread ID -- but that is never recycled
380 * for another thread, even after this one exits. In other words:
381 *
382 * Returns a process-wide-unique token identifying the calling thread -- the *thread-token*: a value that no
383 * other thread (past, present, or future, within this process) shall ever receive from this function.
384 *
385 * Contrast with util::Thread_id + `this_thread::get_id()`: the OS may -- and, e.g., in Linux/glibc,
386 * readily does -- reuse a dead thread's ID for a new thread; hence a *stored* `Thread_id`, compared against
387 * the current thread's, answers "is this the same thread that stored it?" with possible false positives, once
388 * the storing thread may have exited. A stored thread-token never false-matches: tokens are never reused for
389 * the life of the process. (If cross-time thread identity is not at stake -- e.g., when merely printing --
390 * `Thread_id` remains fine and more informative.)
391 *
392 * Properties:
393 * - The value never equals a default-constructed ("none") Thread_token. Hence a stored Thread_token needs
394 * no separate never-assigned sentinel: its default ctor is that.
395 * - It is stable: repeated calls in one thread yield one value.
396 * - Internally each thread's token comes from Unique_id_holder::create_unique_id() (so do not assume any
397 * relationship *between* the tokens of related threads -- e.g., consecutiveness -- just uniqueness).
398 * - Perf: past a given thread's first call, a call = a thread-local read (cheaper than
399 * `this_thread::get_id()`).
400 * - It is safe to call at any point in a thread's life, including during thread-local-storage teardown
401 * and static-deinit when exiting program.
402 *
403 * @return See above.
404 */
406
407/**
408 * Prints string representation of the given `Thread_token` to the given `ostream`: the *low 32 bits* of the
409 * underlying integer in fixed-width hex -- `0x` followed by exactly N (as of this writing N=8) zero-padded
410 * digits -- a token being an identity, not a quantity. Why the low bits only? Tokens come from a monotonic
411 * counter, so the high bits are zeros until the 2^32nd ID is issued process-wide -- i.e., in practice always --
412 * and would print as pure noise; like an abbreviated git hash, the short form identifies uniquely in all but
413 * shocking situations. (The stored value keeps all 64 bits regardless; print `Thread_token::id_t(val)` for
414 * the full value.)
415 *
416 * @relatesalso Thread_token
417 *
418 * @param os
419 * Stream to which to write.
420 * @param val
421 * Object to serialize.
422 * @return `os`.
423 */
424std::ostream& operator<<(std::ostream& os, Thread_token val);
425
426/**
427 * Hashes the given `Thread_token`; making it, e.g., boost.unordered-compatible as a key out of the box.
428 *
429 * @relatesalso Thread_token
430 *
431 * @param val
432 * Object to hash.
433 * @return The hash.
434 */
435size_t hash_value(Thread_token val);
436
437/**
438 * Equivalent to `val1.swap(val2)`.
439 *
440 * @relatesalso Linked_hash_map
441 * @param val1
442 * Object.
443 * @param val2
444 * Object.
445 */
446template<typename Key_t, typename Mapped_t, typename Hash_t, typename Pred_t>
449
450/**
451 * Equivalent to `val1.swap(val2)`.
452 *
453 * @relatesalso Linked_hash_set
454 * @param val1
455 * Object.
456 * @param val2
457 * Object.
458 */
459template<typename Key_t, typename Hash_t, typename Pred_t>
462
463/**
464 * Get the current POSIX (Unix) time as a duration from the Epoch time point.
465 *
466 * This is the amount of time -- according to the user-settable system clock time -- to have passed since the
467 * POSIX (Unix) Epoch -- January 1st, 1970, 00:00:00 UTC -- not counting leap seconds to have been inserted or deleted
468 * between then and now.
469 *
470 * The `boost::chrono` duration type is chosen so as to support the entire supported resolution of the
471 * OS-exposed system clock (but probably no more than that).
472 *
473 * ### Known use cases, alternatives ###
474 * - Logging of time stamps. Output the raw value; or use boost.locale to output `ceil<seconds>()` in the desired
475 * human-friendly form, splicing in the left-over microseconds where desired (boost.locale lacks formatters for
476 * sub-second-resolution time points). However see below for a typically-superior alternative.
477 * - By subtracting return values of this at various points in time from each other, as a crude timing mechanism.
478 * (Various considerations make it just that -- crude -- and best replaced by flow::Fine_clock and the like.
479 * Moreover see flow::perf::Checkpointing_timer.)
480 * - It's a decent quick-and-dirty random seed.
481 *
482 * ### Update/subtleties re. time stamp output ###
483 * Using this for time stamp output is no longer needed or convenient, as a much nicer way presents itself
484 * when combined with boost.chrono I/O-v2 `time_point`-outputting `ostream<<` overload. Just grab `time_point`
485 * `boost::chrono::system_clock::now()` (or another `system_clock`-originated value); its default-formatted
486 * `ostream<<` output will include date, time with microsecond+ precision, and time-zone specifier (one can choose
487 * UTC or local time).
488 *
489 * However, as of this writing, it is not possible to directly obtain *just* the microsecond+
490 * part of this, in isolation, according boost.chrono docs. (One could hack it by taking a substring.)
491 * Quote: "Unfortunately there are no formatting/parsing sequences which indicate fractional seconds." From:
492 * 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)
493 *
494 * @return A duration representing how much time has passed since the Epoch reference point
495 * (could be negative if before it).
496 */
497boost::chrono::microseconds time_since_posix_epoch();
498
499/**
500 * Writes a multi- or single-line string representation of the provided binary data to an output stream, complete with
501 * a printable and hex versions of each byte.
502 * - Single-line mode is chosen by setting `bytes_per_line` to special value `-1`. In this mode, the output
503 * consists of `indentation`, followed by a pretty-printed hex dump of every byte in `data` (no matter how many),
504 * followed by a pretty-printed ASCII-printable (or '.' if not so printable) character for each byte; that's it.
505 * No newline is added, and `indentation` is included only the one time. It is recommended to therefore print
506 * "in-line" inside log messages (etc.) without surrounding newlines, etc., when using this mode.
507 * - Multi-line mode is chosen by setting `bytes_per_line` to a positive value; or 0 which auto-selects a decent
508 * default positive value. Then, each line represents up to that many bytes, which are pretty-printed similarly
509 * to single-line mode, in order of appearance in `data` (with the last such line representing the last few bytes,
510 * formatting nicely including accounting for potentially fewer than the desired # of bytes per line).
511 * Every line starts with `indentation` and ends with a newline -- including the last line.
512 * Therefore, it is recommended to precede this call with an output of a newline and to avoid doing so
513 * after that call (unless blank line is desired).
514 *
515 * Example with a single contiguous memory area, multi-line mode:
516 *
517 * ~~~
518 * array<uint8_t, 256 * 256> bytes(...);
519 *
520 * // Output to cout.
521 * cout
522 * << "Buffer contents: [\n";
523 * buffers_to_ostream(cout,
524 * boost::asio::buffer(bytes), // Turn a single memory array into a buffer sequence.
525 * " ");
526 * << "]."; // This will be on its own line at the end.
527 * ~~~
528 *
529 * See also buffers_dump_string() which returns a string and can thus be more easily used directly inside
530 * FLOW_LOG_DATA() and similar log macros.
531 *
532 * ### Performance ###
533 * This thing is slow... it's not trying to be fast and can't be all that fast anyway. As usual, though, if used
534 * in FLOW_LOG_DATA() (etc.) its slowness will only come into play if the log filter passes which (esp. for
535 * log::Severity::S_DATA) it usually won't.
536 *
537 * That said buffers_dump_string() is even slower, because it'll use an intermediate `ostream` independent of whatever
538 * `ostream` you may or may not be placing the resulting string. However it's easier to use with `FLOW_LOG_...()`,
539 * and since in that case perf is typically not an issue, it makes sense to use the easier thing typically.
540 *
541 * However, if you do want to avoid that extra copy and need to *also* use buffers_to_ostream() directly inside
542 * `FLOW_LOG_...()` then the following technique isn't too wordy and works:
543 *
544 * ~~~
545 * const array<uint8_t, 256 * 256> bytes(...);
546 *
547 * // Log with a flow::log macro.
548 * const flow::Function<ostream& (ostream&)> os_manip = [&](ostream& os) -> ostream&
549 * {
550 * return buffers_to_ostream(os, boost::asio::buffer(bytes), " ");
551 * };
552 * FLOW_LOG_INFO("Buffer contents: [\n" << os_manip << "].");
553 *
554 * // Above is probably more performant than:
555 * FLOW_LOG_INFO("Buffer contents: [\n"
556 * << buffers_dump_string(boost::asio::buffer(bytes), " ") // Intermediate+copy, slow....
557 * << "].");
558 * // flow::util::ostream_op_string() is a bit of an improvement but still. :-)
559 * ~~~
560 *
561 * ### Rationale ###
562 * The reason it returns `os` and takes a reference-to-mutable instead of the customary (for this project's
563 * style, to indicate modification potential at call sites) pointer-to-mutable is in order to be `bind()`able
564 * in such a way as to make an `ostream` manipulator. In the example above we use a lambda instead of `bind()`
565 * however.
566 *
567 * @tparam Const_buffer_sequence
568 * Type that models the boost.asio `ConstBufferSequence` concept (see Boost docs) which represents
569 * 1 or more scattered buffers in memory (only 1 buffer in a sequence is common).
570 * In particular `boost::asio::const_buffer` works when dumping a single buffer.
571 * @param os
572 * The output stream to which to write.
573 * @param data
574 * The data to write, given as an immutable sequence of buffers each of which is essentially a pointer
575 * and length. (Reminder: it is trivial to make such an object from a single buffer as well;
576 * for example given `array<uint8_t, 256> data` (an array of 256 bytes), you can just pass
577 * `boost::asio::buffer(data)`, as the latter returns an object whose type satisfies requirements of
578 * `Const_buffer_sequence` despite the original memory area being nothing more than a single
579 * byte array.)
580 * @param indentation
581 * The indentation to use at the start of every line of output.
582 * @param bytes_per_line
583 * If 0, act as-if a certain default positive value were passed; and then: If `-1`, single-line mode is invoked.
584 * If a positive value, multi-line mode is invoked, with all lines but the last one consisting of
585 * a dump of that many contiguous bytes of `data`. (Yes, multi-line mode is still in force, even if there
586 * are only enough bytes in `data` for one line of output anyway.)
587 * @return `os`.
588 */
589template<typename Const_buffer_sequence>
590std::ostream& buffers_to_ostream(std::ostream& os, const Const_buffer_sequence& data, const std::string& indentation,
591 size_t bytes_per_line = 0);
592
593/**
594 * Identical to buffers_to_ostream() but returns an `std::string` instead of writing to a given `ostream`.
595 *
596 * @see buffers_to_ostream() doc header for notes on performance and usability.
597 *
598 * @tparam Const_buffer_sequence
599 * See buffers_to_ostream().
600 * @param data
601 * See buffers_to_ostream().
602 * @param indentation
603 * See buffers_to_ostream().
604 * @param bytes_per_line
605 * See buffers_to_ostream().
606 * @return Result string.
607 */
608template<typename Const_buffer_sequence>
609std::string buffers_dump_string(const Const_buffer_sequence& data, const std::string& indentation,
610 size_t bytes_per_line = 0);
611
612/**
613 * Utility that converts a bandwidth in arbitrary units in both numerator and denominator to the same bandwidth
614 * in megabits per second. The input bandwidth is given in "items" per `Time_unit{1}`; where `Time_unit` is an
615 * arbitrary boost.chrono `duration` type that must be explicitly provided as input; and an "item" is defined
616 * as `bits_per_item` bits. Useful at least for logging. It's probably easiest to understand by example; see below;
617 * rather than by parsing that description I just wrote.
618 *
619 * To be clear (as C++ syntax is not super-expressive in this case) -- the template parameter `Time_unit` is
620 * an explicit input to the function template, essentially instructing it as to in what units `items_per_time` is.
621 * Thus all uses of this function should look similar to:
622 *
623 * ~~~
624 * // These are all equal doubles, because the (value, unit represented by value) pair is logically same in each case.
625 *
626 * // We'll repeatedly convert from 2400 mebibytes (1024 * 1024 bytes) per second, represented one way or another.
627 * const size_t MB_PER_SEC = 2400;
628 *
629 * // First give it as _mebibytes_ (2nd arg) per _second_ (template arg).
630 * const double mbps_from_mb_per_sec
631 * = flow::util::to_mbit_per_sec<chrono::seconds>(MB_PER_SEC, 1024 * 8);
632 *
633 * // Now give it as _bytes_ (2nd arg omitted in favor of very common default = 8) per _second_ (template arg).
634 * const double mbps_from_b_per_sec
635 * = flow::util::to_mbit_per_sec<chrono::seconds>(MB_PER_SEC * 1024 * 1024);
636 *
637 * // Now in _bytes_ per _hour_.
638 * const double mbps_from_b_per_hour
639 * = flow::util::to_mbit_per_sec<chrono::hours>(MB_PER_SEC * 1024 * 1024 * 60 * 60);
640 *
641 * // Finally give it in _bytes_ per _1/30th-of-a-second_ (i.e., per frame, when the frame rate is 30fps).
642 * const double mbps_from_b_per_30fps_frame
643 * = flow::util::to_mbit_per_sec<chrono::duration<int, ratio<1, 30>>(MB_PER_SEC * 1024 * 1024 / 30);
644 * ~~~
645 *
646 * @note Megabit (1000 x 1000 = 10^6 bits) =/= mebibit (1024 x 1024 = 2^20 bits); but the latter is only about 5% more.
647 * @todo boost.unit "feels" like it would do this for us in some amazingly pithy and just-as-fast way. Because Boost.
648 * @tparam Time_unit
649 * `boost::chrono::duration<Rep, Period>` for some specific `Rep` and `Period`.
650 * See `boost::chrono::duration` documentation.
651 * Example types: `boost::chrono::milliseconds`; `boost::chrono::seconds`; see example use code above.
652 * @tparam N_items
653 * Some (not necessarily integral) numeric type. Strictly speaking, any type convertible to `double` works.
654 * @param items_per_time
655 * The value, in items per `Time_unit{1}` (where there are `bits_per_item` bits in 1 item) to convert to
656 * megabits per second. Note this need not be an integer.
657 * @param bits_per_item
658 * Number of bits in an item, where `items_per_time` is given as a number of items.
659 * @return See above.
660 */
661template<typename Time_unit, typename N_items>
662double to_mbit_per_sec(N_items items_per_time, size_t bits_per_item = 8);
663
664/**
665 * Returns the result of the given non-negative integer divided by a positive integer, rounded up to the nearest
666 * integer. Internally, it avoids floating-point math for performance.
667 *
668 * @note `constexpr`: can be used in compile-time expressions.
669 * @see round_to_multiple() which is essentially `return b * ceil_div(a, b)`.
670 *
671 * @tparam Integer
672 * A signed or unsigned integral type.
673 * @tparam Integer2
674 * Ditto.
675 * @param dividend
676 * Dividend; non-negative (else results undefined).
677 * @param divisor
678 * Divisor; positive (else results undefined).
679 * @return Ceiling of `(dividend / divisor)`.
680 */
681template<typename Integer, typename Integer2>
682constexpr Integer ceil_div(Integer dividend, Integer2 divisor);
683
684/**
685 * Returns the smallest integer >= the given integer `dividend` such that it is a multiple
686 * of the given integer `unit`. Essentially that is: `unit * ceil_div(dividend, unit)`.
687 *
688 * For example: 0 in 1024s => 0; 1 in 1024s => 1024; 1024 in 1024s => 1024; 1025 in 1024s => 2048.
689 *
690 * @note `constexpr`: can be used in compile-time expressions.
691 *
692 * @tparam Integer
693 * A signed or unsigned integral type.
694 * @tparam Integer2
695 * Ditto.
696 * @param dividend
697 * Dividend; non-negative (else results undefined).
698 * @param unit
699 * Divisor; positive (else results undefined).
700 * @return See above.
701 */
702template<typename Integer, typename Integer2>
703constexpr Integer round_to_multiple(Integer dividend, Integer2 unit);
704
705/**
706 * Compile-time check: `true` if and only if the given positive integer is a power of two: 1, 2, 4, 8, ....
707 * @tparam POSITIVE_INT
708 * A positive integer.
709 * @return See above.
710 */
711template<uint64_t POSITIVE_INT>
712constexpr bool is_power_of_two();
713
714/**
715 * Compile-time value: the most stringent alignment in the target architecture. Among other uses,
716 * `malloc()` (et al) shall always return a pointer values that is a multiple of this.
717 *
718 * E.g., in x86-64 this is 16, we've observed.
719 *
720 * @return See above.
721 */
722constexpr size_t max_align_sz();
723
724/**
725 * Compile-time calculation: Given a type `Data` returns the minimum size, in bytes, of a hypothetical buffer that
726 * is able to store 1 `Data` and has the specified alignment. In other words it is the smallest multiple
727 * of `ALIGN_SZ` that is at least `sizeof(Data)`.
728 *
729 * Among other potential uses: the width of the area reserved for the `Prefix` by
730 * aligned_prefix_before(), after_aligned_prefix().
731 *
732 * @tparam Data
733 * Hypothetical stored value's type. Its size can be anything positive, including even an odd number
734 * (e.g., `Data = array<uint8_t, 3>`).
735 * @tparam ALIGN_SZ
736 * The desired alignment of the hypothetical area storing `Data` at its start.
737 * Default is max_align_sz(). `1` would imply no alignment, resulting in the return value `sizeof(Data)`.
738 *
739 * @return The size of the hypothetical aligned area storing `Data` at its start.
740 */
741template<typename Data, size_t ALIGN_SZ = alignof(std::max_align_t)>
742constexpr size_t aligned_sz_of();
743
744/**
745 * Given a pointer to an aligned area, returns the pointer to a *prefix* area that is equally aligned, able
746 * to store a value of the specified type (size), and otherwise minimally sized. The alignment is specified
747 * via `ALIGN_SZ` compile-time parameter. The aforementioned minimal size is `aligned_sz_of<Prefix, ALIGN_SZ>()`.
748 *
749 * @todo Maybe aligned_prefix_before() and aligned_prefix_before() should allow "skew," meaning no prohibition
750 * against an unaligned input vaddr? Alignment would still be observed within the prefix-and-base
751 * combined buffer. At the moment it is formally UB, with an assert guard, which discourages footguns.
752 * One idea would be to have a "safe" version (like now but throw instead of `assert()`) and a
753 * "go-with-god" version (no anti-footgun check).
754 *
755 * @tparam Prefix
756 * Type of item one is hypothetically storing ahead of `*data_ptr`.
757 * @tparam Data
758 * Any pointee type. `void` is allowed. Whatever is convenient for your purposes is fine.
759 * @tparam ALIGN_SZ
760 * The required and guaranteed alignment.
761 * Default is max_align_sz(). `1` would imply no alignment, resulting in maximally compact storage.
762 * (However, in that case generally one should use `memcpy()` or equivalent byte-wise copying ops
763 * to store or load a `Prefix`-typed value at the returned address. Otherwise a fault may occur.)
764 * @param data_ptr
765 * Pointer at the base area. Must be aligned to `ALIGN_SZ`; otherwise undefined behavior/assert may trip.
766 * @return See above: pointer to an area ahead of `data_ptr`, sized `aligned_sz_of<Prefix, ALIGN_SZ>()`.
767 */
768template<typename Prefix, typename Data, size_t ALIGN_SZ = alignof(std::max_align_t)>
769Prefix* aligned_prefix_before(Data* data_ptr);
770
771/**
772 * Identical to the other aligned_prefix_before() overload but works with immutable memory.
773 * @tparam Prefix
774 * See above.
775 * @tparam Data
776 * See above.
777 * @tparam ALIGN_SZ
778 * See above.
779 * @param data_ptr
780 * See above.
781 * @return See above.
782 */
783template<typename Prefix, typename Data, size_t ALIGN_SZ = alignof(std::max_align_t)>
784const Prefix* aligned_prefix_before(const Data* data_ptr);
785
786/**
787 * The reverse of aligned_prefix_before(): given a prefix pointer, returns the base area following it.
788 * Hence the following holds:
789 * ~~~
790 * T* p = ...;
791 * assert(p == after_aligned_prefix<T, Prefix, ALIGN_SZ> // 2. Go forward to `p`.
792 * (aligned_prefix_before<Prefix, T, ALIGN_SZ>(p))); // 1. Go backward from `p`.
793 * ~~~
794 *
795 * @tparam Prefix
796 * See aligned_prefix_before().
797 * @tparam Data
798 * Any pointee type. `void` is allowed. Whatever is convenient for your purposes is fine.
799 * @tparam ALIGN_SZ
800 * See aligned_prefix_before().
801 * @param prefix_ptr
802 * Pointer at the prefix area.
803 * @return See above: pointer to an area after `prefix_ptr`, namely `aligned_sz_of<Prefix, ALIGN_SZ>()` bytes past it.
804 */
805template<typename Data, typename Prefix, size_t ALIGN_SZ = alignof(std::max_align_t)>
806Data* after_aligned_prefix(Prefix* prefix_ptr);
807
808/**
809 * Identical to the other after_aligned_prefix() overload but works with immutable memory.
810 * @tparam Prefix
811 * See above.
812 * @tparam Data
813 * See above.
814 * @tparam ALIGN_SZ
815 * See above.
816 * @param prefix_ptr
817 * See above.
818 * @return See above.
819 */
820template<typename Data, typename Prefix, size_t ALIGN_SZ = alignof(std::max_align_t)>
821const Data* after_aligned_prefix(const Prefix* prefix_ptr);
822
823/**
824 * Provides a way to execute arbitrary (cleanup) code at the exit of the current block. Simply
825 * save the returned object into a local variable that will go out of scope when your code block
826 * exits. Example:
827 *
828 * ~~~
829 * {
830 * auto resource_handle = create_huge_resource();
831 * const auto cleanup = util::setup_auto_cleanup([&]() { delete_huge_resource(resource_handle); });
832 * // Now `delete_huge_resource(resource_handle)` will be called no matter how the current { block } exits.
833 * // ...
834 * }
835 * ~~~
836 *
837 * @warning `func()` cannot throw. (Internally it uses `shared_ptr` to implement this, but its dtor is `nothrow` =>
838 * abort.)
839 *
840 * @todo Deprecate setup_auto_cleanup(): Boost-1.85 introduced `boost::scope` guards which will surely do this
841 * better with more options. If possible first write setup_auto_cleanup() in terms of the Boost `scope` API +
842 * declare it deprecated; then eventually eliminate it. Incidentally one guesses the cannot-throw limitation
843 * would go away.
844 *
845 * @tparam Cleanup_func
846 * Any type such that given an instance `Cleanup_func f`, the expression `f()` is valid.
847 * @param func
848 * `func()` will be called when cleanup is needed.
849 * @return A light-weight object that, when it goes out of scope, will cause `func()` to be called.
850 */
851template<typename Cleanup_func>
852Auto_cleanup setup_auto_cleanup(Cleanup_func&& func);
853
854/**
855 * Returns `true` if and only if the given value is within the given range, inclusive.
856 *
857 * @param min_val
858 * Lower part of the range.
859 * @param val
860 * Value to check.
861 * @param max_val
862 * Higher part of the range. Must be greater than or equal to `min_val`, or behavior is undefined.
863 * @tparam T
864 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
865 * `unsigned int`, #Fine_duration.
866 * @return `true` if and only if `val` is in [`min_val`, `max_val`].
867 */
868template<typename T>
869bool in_closed_range(T const & min_val, T const & val, T const & max_val);
870
871/**
872 * Returns `true` if and only if the given value is within the given range, given as a [low, high)
873 * pair.
874 *
875 * @param min_val
876 * Lower part of the range.
877 * @param val
878 * Value to check.
879 * @param max_val
880 * Higher part of the range. Must be greater than `min_val`, or behavior is undefined.
881 * @tparam T
882 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
883 * `unsigned int`, #Fine_duration.
884 * @return `true` if and only if `val` is in [`min_val`, `max_val`), i.e., `min_val` <= `val` < `max_val`.
885 */
886template<typename T>
887bool in_closed_open_range(T const & min_val, T const & val, T const & max_val);
888
889/**
890 * Returns `true` if and only if the given value is within the given range, given as a (low, high]
891 * pair.
892 *
893 * @param min_val
894 * Lower part of the range.
895 * @param val
896 * Value to check.
897 * @param max_val
898 * Higher part of the range. Must be greater than `min_val`, or behavior is undefined.
899 * @tparam T
900 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
901 * `unsigned int`, #Fine_duration.
902 * @return `true` if and only if `val` is in (`min_val`, `max_val`], i.e., `min_val` < `val` <= `max_val`.
903 */
904template<typename T>
905bool in_open_closed_range(T const & min_val, T const & val, T const & max_val);
906
907/**
908 * Returns `true` if and only if the given value is within the given range, given as a (low, high)
909 * pair.
910 *
911 * @param min_val
912 * Lower part of the range.
913 * @param val
914 * Value to check.
915 * @param max_val
916 * Higher part of the range. Must be at least 2 greater than `min_val`, or behavior is undefined.
917 * @tparam T
918 * A type for which the operation `x < y` is defined and makes sense. Examples: `double`, `char`,
919 * `unsigned int`, #Fine_duration.
920 * @return `true` if and only if `val` is in (`min_val`, `max_val`), i.e., `min_val` < `val` < `max_val`.
921 */
922template<typename T>
923bool in_open_open_range(T const & min_val, T const & val, T const & max_val);
924
925/**
926 * Returns `true` if and only if the given key is present at least once in the given associative
927 * container.
928 *
929 * @tparam Container
930 * Associative container type (`boost::unordered_map`, `std::set`, etc.).
931 * In particular must have the members `find()`, `end()`, and `key_type`.
932 * @param container
933 * Container to search.
934 * @param key
935 * Key to find.
936 * @return See above.
937 */
938template<typename Container>
939bool key_exists(const Container& container, const typename Container::key_type& key);
940
941/**
942 * Performs `*minuend -= subtrahend`, subject to a floor of `floor`. Avoids underflow/overflow to the extent
943 * it's reasonably possible, but no more. The return value indicates whether
944 * the floor was hit; this allows one to chain high-performance subtractions like this:
945 *
946 * ~~~
947 * double t = 44;
948 * int x = rnd(); // Suppose x == 123, for example.
949 * // Avoids the 2nd, 3rd computation altogether, as the first detects that x >= 44, and thus t == 0 regardless.
950 * subtract_with_floor(&t, x) &&
951 * subtract_with_floor(&t, long_computation()) &&
952 * subtract_with_floor(&t, another_long_computation());
953 * ~~~
954 *
955 * @tparam Minuend
956 * Numeric type.
957 * @tparam Subtrahend
958 * Numeric type, such that given `Subtrahend s`, `Minuend{s}` is something reasonable for all `s` involved.
959 * @param minuend
960 * `*minuend` is set to either `(*minuend - subtrahend)` or `floor`, whichever is higher.
961 * @param subtrahend
962 * Ditto.
963 * @param floor
964 * Ditto. Negatives are OK. Typically it's best to keep the magnitude of this small.
965 * @return `true` if `*minuend == floor` at function exit; `false` if `*minuend > floor`.
966 */
967template<typename Minuend, typename Subtrahend>
968bool subtract_with_floor(Minuend* minuend, const Subtrahend& subtrahend, const Minuend& floor = 0);
969
970/**
971 * Answers the question *what's the smallest integer number of `To`s sufficient to verbatim store the given number of
972 * `From`s?*, where `From` and `To` are POD types.
973 *
974 * For example, one needs 1 `uint64_t` to store 1, 2, 3, or 4 `uint16_t`s, hence
975 * `size_unit_convert<uint16_t, uint64_t>(1 or 2 or 3 or 4) == 1`. Similarly, 5 or 6 or 7 or 8 -> 2.
976 * It works in the opposite direction, too; if we are storing `uint64_t`s in multiples of `uint16_t`, then
977 * 1 -> 4, 2 -> 8, 3 -> 12, etc.
978 *
979 * To be clear, when `From` bit width is smaller than `To` bit width, some of the bits will be padding and
980 * presumably unused. For example, raw data buffers of arbitrary bytes are often arranged in multi-byte "words."
981 *
982 * @tparam From
983 * The POD type of the values that must be encoded in `From`s.
984 * @tparam To
985 * The POD type of the array that would store the `From`s.
986 * @param num_froms
987 * How many `From`s does one want to encode in an array of `To`s?
988 * @return How many `To`s are sufficient to encode `num_from` `From`s verbatim?
989 */
990template<typename From, typename To>
991size_t size_unit_convert(From num_froms);
992
993/**
994 * Given a generic sequence (integer -> object) generates a generic map (object -> integer) providing inverse
995 * lookup. See the 3-arg overload if you want to provide a more complex lookup function to store something else based
996 * on each index.
997 *
998 * A naive way of implementing lookups otherwise would be a linear search for the object; using this will
999 * use RAM to avoid the slow searches.
1000 *
1001 * @tparam Sequence
1002 * Sequence such as `std::vector<T>` or `std::array<T>`.
1003 * Informally, `T` should be something light-weight and hence usable as a key type for a map type (`Map`).
1004 * @tparam Map
1005 * Map that maps `T` from `Sequence` to `size_t`. Example: `std::map<T, size_t>`.
1006 * @param src_seq
1007 * Input sequence.
1008 * @param target_map
1009 * Output map. Note it will *not* be pre-cleared; informally, this means one can shove 2+ lookup maps
1010 * into one. If null behavior undefined (assertion may trip).
1011 */
1012template<typename Map, typename Sequence>
1013void sequence_to_inverted_lookup_map(Sequence const & src_seq, Map* target_map);
1014
1015/**
1016 * Similar to the 2-arg overload of sequence_to_inverted_lookup_map() but with the ability to store a value based
1017 * on the index into the input sequence instead of that index itself. See the 2-arg overload.
1018 *
1019 * @tparam Sequence
1020 * Sequence such as `std::vector<T>` or `std::array<T>`.
1021 * Informally, `T` should be something light-weight and hence usable as a key type for a map type (`Map`).
1022 * @tparam Map
1023 * Map that maps `T` from `Sequence` to another type `X`. Example:
1024 * `unordered_map<T, X>`, where an `X` can be computed from a `size_t` index.
1025 * @param src_seq
1026 * See 2-arg overload.
1027 * @param target_map
1028 * See 2-arg overload.
1029 * @param idx_to_map_val_func
1030 * Given an index `idx` into `src_seq`, `(*target_map)[]` shall contain `idx_to_map_val_func(idx)`.
1031 * Use this arg to instead perform a second lookup before storing a value in `*target_map`.
1032 * Use the 2-arg overload if you'd like to store the index itself.
1033 */
1034template<typename Map, typename Sequence>
1036 (Sequence const & src_seq, Map* target_map,
1037 const Function<typename Map::mapped_type (size_t)>& idx_to_map_val_func);
1038
1039/**
1040 * Writes to the specified string, as if the given arguments were each passed, via `<<` in sequence,
1041 * to an `ostringstream`, and then the result were appended to the aforementioned string variable.
1042 *
1043 * Tip: It works nicely, 99% as nicely as simply `<<`ing an `ostream`; but certain language subtleties mean
1044 * you may have to fully qualify some template instances among `ostream_args`. Do so if you receive a
1045 * "deduced incomplete pack" (clang) or similar error, as I have seen when using, e.g., `chrono::symbol_format`
1046 * formatter (which the compile error forced me to qualify as: `symbol_format<char, ostream::traits_type>`).
1047 *
1048 * @see log::Thread_local_string_appender for an even more efficient version of this for some applications that can
1049 * also enable a continuous stream across multiple stream-writing statements over time.
1050 *
1051 * @tparam T
1052 * Each type `T` is such that `os << t`, with types `T const & t` and `ostream& os`, builds and writes
1053 * `t` to `os`, returning lvalue `os`.
1054 * Usually in practice this means the existence of `ostream& operator<<(ostream&, T const &)` or
1055 * `ostream& operator<<(ostream&, T)` overload, the latter usually for basic types `T`.
1056 * See also tip above, if compiler is unable to deduce a given `T` (even when it *would* deduce it
1057 * in `os << t`).
1058 * @param target_str
1059 * Pointer to the string to which to append.
1060 * @param ostream_args
1061 * One or more arguments, such that each argument `arg` is suitable for `os << arg`, where
1062 * `os` is an `ostream`.
1063 */
1064template<typename... T>
1065void ostream_op_to_string(std::string* target_str, T&&... ostream_args);
1066
1067/**
1068 * Equivalent to ostream_op_to_string() but returns a new `string` by value instead of writing to the caller's
1069 * `string`. This is useful at least in constructor initializers, where it is not possible to first
1070 * declare a stack variable.
1071 *
1072 * With the C++11-y use of move semantics in STL it should be no slower than using
1073 * `ostream_op_to_string()` -- meaning, it is no slower, period, as this library now requires C++11.
1074 *
1075 * @tparam T
1076 * See ostream_op_to_string().
1077 * @param ostream_args
1078 * See ostream_op_to_string().
1079 * @return Resulting `std::string`.
1080 */
1081template<typename... T>
1082std::string ostream_op_string(T&&... ostream_args);
1083
1084/**
1085 * Function template that simply outputs arguments 2+ via `<<` to the given `ostream`, in the order given.
1086 *
1087 * @tparam T
1088 * See `T` in ostream_op_to_string().
1089 * @param ostream_args
1090 * See `ostream_args` in ostream_op_to_string().
1091 * @param os
1092 * Pointer to stream to which to sequentially send arguments for output.
1093 */
1094template<typename... T>
1095void feed_args_to_ostream(std::ostream* os, T&&... ostream_args);
1096
1097/**
1098 * Deserializes an `enum class` value from a standard input stream. Reads up to but not including the next
1099 * non-alphanumeric-or-underscore character; the resulting string is then mapped to an `Enum`. If none is
1100 * recognized, `enum_default` is the result. The recognized values are:
1101 * - "0", "1", ...: Corresponds to the underlying-integer conversion to that `Enum`. (Can be disabled optionally.)
1102 * - Case-[in]sensitive string encoding of the `Enum`, as determined by `operator<<(ostream&)` -- which must exist
1103 * (or this will not compile). Informally we recommend the encoding to be the non-S_-prefix part of the actual
1104 * `Enum` member; e.g., `"WARNING"` for log::Sev::S_WARNING.
1105 * If the scanned token does not map to any of these, or if end-of-input is encountered immediately (empty token),
1106 * then `enum_default` is returned.
1107 *
1108 * Error semantics: There are no invalid values or exceptions thrown; `enum_default` returned is the worst case.
1109 * Do note `*is_ptr` may not be `good() == true` after return.
1110 *
1111 * Tip: It is convenient to implement `operator>>(istream&)` in terms of istream_to_enum(). With both
1112 * `>>` and `<<` available, serialization/deserialization of the `enum class` will work; this enables a few key things
1113 * to work, including parsing from config file/command line via and conversion from `string` via `lexical_cast`.
1114 *
1115 * Informal convention suggestion: `S_END_SENTINEL` should be the sentinel member of `Enum`. E.g., see log::Sev.
1116 *
1117 * @tparam Enum
1118 * An `enum class` which must satisfy the following requirements or else risk undefined behavior (if it
1119 * compiles): An element, `enum_lowest`, has a non-negative integer value.
1120 * Subsequent elements are strictly monotonically increasing with increment 1, up to and including
1121 * `enum_sentinel`. (Elements outside [`enum_lowest`, `enum_sentinel`] may exist, as long as their numeric
1122 * values don't conflict with those in-range, but informally we recommend against this.)
1123 * `ostream << Enum` exists and works without throwing for all values in range
1124 * [`enum_lowest`, `enum_sentinel`). Each `<<`-serialized string must be distinct from the others.
1125 * Each `<<`-serialized string must start with a non-digit and must consist only of alphanumerics and
1126 * underscores. Exception: digit-leading is allowed if and only if `!accept_num_encoding`, though
1127 * informally we recommend against it as a convention.
1128 *
1129 * @param is_ptr
1130 * Stream from which to deserialize.
1131 * @param enum_default
1132 * Value to return if the token does not match either the numeric encoding (if enabled) or the `<<` encoding.
1133 * `enum_sentinel` is a sensible (but not the only sensible) choice.
1134 * @param enum_sentinel
1135 * `Enum` value such that all valid deserializable values have numeric conversions strictly lower than it.
1136 * @param accept_num_encoding
1137 * If `true`, a numeric value is accepted as an encoding; otherwise it is not (and will yield `enum_default`
1138 * like any other non-matching token).
1139 * @param case_sensitive
1140 * If `true`, then the token must exactly equal an `ostream<<` encoding of a non-sentinel `Enum`;
1141 * otherwise it may equal it modulo different case.
1142 * @param enum_lowest
1143 * The lowest `Enum` value. Its integer value is very often 0, sometimes 1.
1144 * Behavior undefined if it is negative.
1145 * @return See above.
1146 */
1147template<typename Enum>
1148Enum istream_to_enum(std::istream* is_ptr, Enum enum_default, Enum enum_sentinel,
1149 bool accept_num_encoding = true, bool case_sensitive = false,
1150 Enum enum_lowest = Enum(0));
1151
1152/**
1153 * Sets certain `chrono`-related formatting on the given `ostream` that results in a consistent, desirable output
1154 * of `duration`s and certain types of `time_point`s. As of this writing this includes enabling short unit format
1155 * (e.g., "ms" instead of "milliseconds") and avoiding Unicode characters (the Greek letter for micro becomes
1156 * a similar-looking "u" instead).
1157 *
1158 * @see log::beautify_chrono_logger_this_thread() to affect a Logger directly.
1159 * @see flow::async in which new threads are set to use this formatting automatically. However you'll want to
1160 * do this explicitly for the startup thread.
1161 *
1162 * @param os
1163 * The stream to affect.
1164 */
1165void beautify_chrono_ostream(std::ostream* os);
1166
1167/**
1168 * Estimate of memory footprint of the given value, including memory allocated on its behalf -- but
1169 * excluding its shallow `sizeof`! -- in bytes.
1170 *
1171 * @param val
1172 * Value.
1173 * @return See above.
1174 */
1175size_t deep_size(const std::string& val);
1176
1177/**
1178 * `std::construct_at()` equivalent; unavailable until C++20, so here it is. Placement-constructs a `T`
1179 * at the given location with the given ctor args, using the expression used by C++20's `construct_at()` per
1180 * cppreference.com.
1181 *
1182 * @tparam T
1183 * Object type.
1184 * @tparam Ctor_args
1185 * `T` ctor arg types.
1186 * @param obj
1187 * Pointer to uninitialized `T`.
1188 * @param ctor_args
1189 * Ctor args for `T::T()`.
1190 * @return `obj`.
1191 */
1192template<typename T, typename... Ctor_args>
1193T* construct_at(T* obj, Ctor_args&&... ctor_args);
1194
1195/**
1196 * Superficially similar to construct_at(), this default-initializes the `T` at the given location; this
1197 * can be useful to avoid object-lifetime formality pitfalls. Note that `T` must be *trivially* default-constructible.
1198 * That means the call itself is a no-op -- in particular things like `int` members will not be
1199 * zeroed -- but it can be used to inform the compiler of the nature of the area at `obj` as storing a `T`.
1200 *
1201 * @note We avoid describing the exact formalities of "inform the compiler of the nature of the area," so
1202 * you should know what you're doing before relying on this. `std::start_lifetime_as()` in C++23 is related.
1203 *
1204 * If `T` is not trivially default-constructible, and you still want to placement-`T{}`-construct it, then
1205 * just use construct_at() (with 1 arg) instead.
1206 *
1207 * @param obj
1208 * Pointer to `T`.
1209 * @return `obj`.
1210 */
1211template<typename T>
1212T* default_init_at(T* obj);
1213
1214/**
1215 * Serializes a Thread_local_state_registry to a standard output stream.
1216 *
1217 * @relatesalso Thread_local_state_registry
1218 *
1219 * @param os
1220 * Stream to which to serialize.
1221 * @param val
1222 * Value to serialize.
1223 * @return `os`.
1224 */
1225template<typename Thread_local_state_t>
1226std::ostream& operator<<(std::ostream& os, const Thread_local_state_registry<Thread_local_state_t>& val);
1227
1228// Macros.
1229
1230/**
1231 * Expands to an `ostream` fragment `X` (suitable for, for example: `std::cout << X << ": Hi!"`) containing
1232 * the file name, function name, and line number at the macro invocation's context.
1233 *
1234 * It's a functional macro despite taking no arguments to convey that it mimics a free function sans args.
1235 *
1236 * @internal
1237 *
1238 * ### Performance ###
1239 * The items `<<`ed onto the target `ostream` are each evaluated at compile-time.
1240 * This includes the expression involving flow::util::get_last_path_segment() which is `constexpr`.
1241 */
1242#define FLOW_UTIL_WHERE_AM_I() \
1243 FLOW_UTIL_WHERE_AM_I_FROM_ARGS(::flow::util::get_last_path_segment \
1244 (::flow::util::String_view(__FILE__, sizeof(__FILE__) - 1)), \
1245 ::flow::util::String_view(__FUNCTION__, sizeof(__FUNCTION__) - 1), \
1246 __LINE__)
1247// ^-- Using String_view{} instead of String_view() there creates macro problems. Not worth it.
1248
1249/**
1250 * Same as FLOW_UTIL_WHERE_AM_I() but evaluates to an `std::string`. It's probably a bit slower as
1251 * well. Update: In fact, it's probably significantly slower as of this writing, as
1252 * FLOW_UTIL_WHERE_AM_I() evaluates the `<<`ed items at compile-time, while this cannot due to how it's implemented.
1253 *
1254 * @internal
1255 *
1256 * flow::util::get_where_am_i_str() is too clever to become a `constexpr` function, even if it were radically rewritten,
1257 * so this macro evaluates to a partially runtime-computed expression. Hence the note just above about perf.
1258 *
1259 * @todo See if FLOW_UTIL_WHERE_AM_I_STR() can be coaxed into a compile-time expression after all. It is used in
1260 * quite a lot of frequently executed code, namely at the top of most Flow (and Flow-like) APIs that can emit errors.
1261 * See notes inside flow::util::get_where_am_i_str() on this as of this writing.
1262 */
1263#define FLOW_UTIL_WHERE_AM_I_STR() \
1264 ::flow::util::get_where_am_i_str(::flow::util::get_last_path_segment \
1265 (::flow::util::String_view(__FILE__, sizeof(__FILE__) - 1)), \
1266 ::flow::util::String_view(__FUNCTION__, sizeof(__FUNCTION__) - 1), \
1267 __LINE__)
1268// ^-- Using String_view{} instead of String_view() there creates macro problems. Not worth it.
1269
1270/**
1271 * Use this to create a semicolon-safe version of a "void" functional macro definition consisting of at least two
1272 * statements; or of one statement that would become two statements by appending a semicolon.
1273 *
1274 * There may be other use cases where it might be useful, though none more has come to mind as of this writing.
1275 * Loosely speaking, IF your sub-statements are always blocks, and you have a "void" functional macro to be used in
1276 * the typical way (every use is a statement that looks like a function call), and the macro's definition is anything
1277 * *other* than an expression with an intentionally missing trailing semicolon, THEN you should probably wrap
1278 * that would-be macro definition in a FLOW_UTIL_SEMICOLON_SAFE(). However, read on if you want to know rationale
1279 * and/or formalities.
1280 *
1281 * ### Formal use case requirements ###
1282 * The following is assumed about every *use* of this macro; behavior is undefined otherwise.
1283 *
1284 * - The macro's invocation is the *entire definition* of another macro, M.
1285 * - M is a functional macro taking 0 or more arguments (possibly variadic).
1286 * - The following is true about every *use* of the macro M:
1287 * - The invocation is written as if M is a free function in the C language, and it is being "called"
1288 * as the *entirety* of the statement containing that "call." That is, it must look like this:
1289 *
1290 * ~~~
1291 * M(...arg 1 value..., ...arg 2 value..., ...more...); // (Or however many args M actually allows.)
1292 * ~~~
1293 *
1294 * ### Known use case 1: Macro definition is 2+ statements ###
1295 * Suppose your macro's value is a series of two or more statements executing in series without braces `{}`
1296 * around the whole thing. Then, in some contexts, invoking that macro as intended might result in
1297 * unexpected runtime misbehavior that the compiler wouldn't detect. A simple example with two
1298 * expressions as individual statements:
1299 *
1300 * ~~~
1301 * #define DOUBLE_AND_PRINT(arg) \
1302 * arg *= 2; // Statement 1. \
1303 * cout << arg // Statement 2. Note the lacking trailing semicolon (invoker must supply it after "call"). \
1304 * DOUBLE_AND_PRINT(x); // No problem. Both statements execute.
1305 * if (some_flag)
1306 * DOUBLE_AND_PRINT(x); // UNINTENDED BEHAVIOR! Statement 2 executes regardless of some_flag!
1307 * ~~~
1308 *
1309 * Granted, if the invoker used braces appropriately around the `if` statement body, there'd be no issue, but one
1310 * cannot always rely on invoker's good style, especially if the macro is part of a public library API.
1311 * Solution:
1312 *
1313 * ~~~
1314 * #define DOUBLE_AND_PRINT(arg) \
1315 * FLOW_UTIL_SEMICOLON_SAFE \
1316 * ( \
1317 * arg *= 2; // Statement 1. \
1318 * cout << arg; // Statement 2. Note necessity for trailing semicolon. \
1319 * )
1320 * DOUBLE_AND_PRINT(x); // No problem. Both statements execute.
1321 * if (some_flag)
1322 * DOUBLE_AND_PRINT(x); // No problem. Both statements execute; or neither one does.
1323 * ~~~
1324 *
1325 * One might ask: Why not simply surround the 2+ statements with braces `{}` to eliminate the problem more simply?
1326 * Answer: This actually would turn the use case into the following other problematic use case.
1327 *
1328 * ### Known use case 2: Required semicolon `;` trailing macro invocation leads to syntax error ###
1329 * Recall that the premise *requires* invoker to call your macro M like `M();`, meaning they will *always* put
1330 * a semicolon after the invocation. Now suppose that doing so will turn one statement (which is M's definition)
1331 * into two. Another way of putting it: Suppose M's body is already a complete statement, even without the required
1332 * trailing `;` (and there is no way to make it otherwise; usually [always?] because it ends with a `}`).
1333 * Then in some contexts it'll cause a syntax error. Example:
1334 *
1335 * ~~~
1336 * #define CHECK_AND_LOG(msg) \
1337 * if (filter()) \
1338 * { \
1339 * log(msg); \
1340 * } // Semicolon will always be added right here.
1341 * CHECK_AND_LOG("Hello."); // No problem. The empty ; statement introduced is harmless.
1342 * if (terminating)
1343 * CHECK_AND_LOG(msg); // SYNTAX ERROR! The empty ; will make the `else` illegal.
1344 * else
1345 * exit();
1346 * ~~~
1347 *
1348 * Removing the `;` from the invocation is no solution. Firstly it'll confuse many editors that will think the
1349 * "function call" (really macro invocation) is missing the usual semicolon. This might cause incorrect
1350 * auto-indentation in the file and who knows what else. Code analyzer tools may also be affected.
1351 * Even ignoring issues where the code is fed into a non-compiler, there are possible flow control problems.
1352 * In this example it'll attach the `else` in the invoking code to the inner `if` (from the macro)
1353 * instead of the outer `if` (in the invoking code) as intended. Wrapping the body of `CHECK_AND_LOG()` in
1354 * the proposed wrapper will resolve all stated problems. (Solution code omitted for brevity and obviousness
1355 * at this point.)
1356 *
1357 * @note Adding this wrapper would slightly adversely affect performance in the complete absence of compiler
1358 * optimization, but even the most basic optimizer (one capable of eliminating `if (false)` and similar)
1359 * should entirely eliminate any such performance degradation.
1360 *
1361 * @param ARG_func_macro_definition
1362 * The intended value of a functional macro, such that the "function" it approximates would have
1363 * return type `void`. Behavior is undefined if the value of this parameter ends in a semicolon, or
1364 * if the value contains a statement that includes another statement within it that is not a block
1365 * (`{ ... }`). (The rules in the last [English] statement may or may not be strictly necessary,
1366 * but requiring these allows me to generalize/reason more straightforwardly. In any case, one rule is
1367 * assumed good style anyway, while the other is simply practical in this context.)
1368 * @return Code to be used as the entire definition of a macro whose definition would have been
1369 * `ARG_func_macro_definition` if not for the resulting compile error or unexpected flow control
1370 * effects detailed above.
1371 */
1372#define FLOW_UTIL_SEMICOLON_SAFE(ARG_func_macro_definition) \
1373 do \
1374 { \
1375 ARG_func_macro_definition \
1376 } \
1377 while (false)
1378
1379} // namespace flow::util
A registry of callbacks (actions) sharing a common signature, intended for fan-out invocation across ...
Allocator adaptor (useful for, e.g., vector that skips zero-filling) that turns a value-initializatio...
An object of this class is a map that combines the lookup speed of an unordered_flat_map<> and orderi...
An object of this class is a set that combines the lookup speed of an unordered_flat_set<> and orderi...
A simple locking-proxy class template (execute-around-pointer idiom): at construction locks the given...
Definition: util.hpp:249
An empty interface, consisting of nothing but a default virtual destructor, intended as a boiler-plat...
Definition: util.hpp:50
A single boolean flag, armed via arm_next_poll() (typically from another thread) and both checked and...
Definition: thread_lcl.hpp:819
Optional-use companion to Thread_local_state_registry that (together with Poll_flag) enables the Poll...
Definition: thread_lcl.hpp:991
Base class for Rnd_gen_uniform_range and Rnd_gen_uniform_range_mt for various aliases and similar,...
Definition: random.hpp:33
Identical to Rnd_gen_uniform_range but safe for concurrent RNG given a single object.
Definition: random.hpp:158
Simple, non-thread-safe uniform-range random number generator.
Definition: random.hpp:104
A simple RAII-pattern class template that, at construction, sets the specified location in memory to ...
Definition: util.hpp:150
Convenience class template that endows the given subclass T with nested aliases Ptr and Const_ptr ali...
Similar to ostringstream but allows fast read-only access directly into the std::string being written...
A thread_local object of type Obj, in effect, but with death-aware access: this_thread_obj_or_null() ...
boost::thread_specific_ptr replacement (augmentation) whose fast-path .get() touches only thread_loca...
Similar to Thread_local_ptr<T> (a perf-upgraded boost::thread_specific_ptr<T>) but allows iteration t...
Definition: thread_lcl.hpp:225
Each object of this class stores (at construction) and returns (on demand) a numeric ID unique from a...
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
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:324
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:497
constexpr size_t aligned_sz_of()
Compile-time calculation: Given a type Data returns the minimum size, in bytes, of a hypothetical buf...
Definition: util.hpp:440
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:511
constexpr bool is_power_of_two()
Compile-time check: true if and only if the given positive integer is a power of two: 1,...
Definition: util.hpp:428
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:174
Thread::id Thread_id
Short-hand for an OS-provided ID of a util::Thread.
Definition: util_fwd.hpp:123
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:586
T * default_init_at(T *obj)
Superficially similar to construct_at(), this default-initializes the T at the given location; this c...
Definition: util.hpp:809
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:386
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:699
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:716
boost::span< T, E > Span
Short-hand for std::span-like type; that is contiguous sequence of objects with the first element of ...
Definition: util_fwd.hpp:374
void feed_args_to_ostream(std::ostream *os, T &&... ostream_args)
Function template that simply outputs arguments 2+ via << to the given ostream, in the order given.
Definition: util.hpp:555
std::ostream & operator<<(std::ostream &os, const Thread_local_state_registry< Thread_local_state_t > &val)
Serializes a Thread_local_state_registry to a standard output stream.
boost::asio::ip::address_v6 Ip_address_v6
Short-hand for the IPv6 address type.
Definition: util_fwd.hpp:245
boost::asio::ip::address_v4 Ip_address_v4
Short-hand for the IPv4 address type.
Definition: util_fwd.hpp:243
bool subtract_with_floor(Minuend *minuend, const Subtrahend &subtrahend, const Minuend &floor)
Performs *minuend -= subtrahend, subject to a floor of floor.
Definition: util.hpp:527
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:187
constexpr Integer round_to_multiple(Integer dividend, Integer2 unit)
Returns the smallest integer >= the given integer dividend such that it is a multiple of the given in...
Definition: util.hpp:422
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:298
boost::shared_mutex Mutex_shared_non_recursive
Short-hand for non-reentrant, shared-or-exclusive mutex.
Definition: util_fwd.hpp:276
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:549
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:333
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:505
constexpr size_t DYNAMIC_EXTENT
Configures a Span at compile-time to have a variable, rather than constant, length (use it as templat...
Definition: util_fwd.hpp:47
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:489
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:316
constexpr size_t max_align_sz()
Compile-time value: the most stringent alignment in the target architecture.
Definition: util.hpp:434
Thread_token this_thread_unique_token()
Returns a value conceptually similar to this_thread::get_id() – a thread ID – but that is never recyc...
boost::recursive_mutex Mutex_recursive
Short-hand for reentrant, exclusive mutex.
Definition: util_fwd.hpp:251
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:342
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:351
Prefix * aligned_prefix_before(Data *data_ptr)
Given a pointer to an aligned area, returns the pointer to a prefix area that is equally aligned,...
Definition: util.hpp:447
void ostream_op_to_string(std::string *target_str, T &&... ostream_args)
Writes to the specified string, as if the given arguments were each passed, via << in sequence,...
Definition: util.hpp:561
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:607
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:171
Data * after_aligned_prefix(Prefix *prefix_ptr)
The reverse of aligned_prefix_before(): given a prefix pointer, returns the base area following it.
Definition: util.hpp:464
void swap(Basic_blob< Allocator_t, SHARING > &blob1, Basic_blob< Allocator_t, SHARING > &blob2, log::Logger *logger_ptr) noexcept
Equivalent to blob1.swap(blob2).
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:481
boost::shared_ptr< void > Auto_cleanup
Helper type for setup_auto_cleanup().
Definition: util_fwd.hpp:238
size_t hash_value(Thread_token val)
Hashes the given Thread_token; making it, e.g., boost.unordered-compatible as a key out of the box.
boost::asio::io_context Task_engine
Short-hand for boost.asio event service, the central class of boost.asio.
Definition: util_fwd.hpp:168
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:308
Auto_cleanup setup_auto_cleanup(Cleanup_func &&func)
Provides a way to execute arbitrary (cleanup) code at the exit of the current block.
Definition: util.hpp:517
std::string ostream_op_string(T &&... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
Definition: util.hpp:575
boost::chrono::microseconds time_since_posix_epoch()
Get the current POSIX (Unix) time as a duration from the Epoch time point.
Definition: util.cpp:148
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:360
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:248
boost::asio::basic_waitable_timer< Fine_clock > Timer
boost.asio timer.
Definition: util_fwd.hpp:235
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:284
boost::thread Thread
Short-hand for standard thread class.
Definition: util_fwd.hpp:105
boost::asio::ip::udp::endpoint Udp_endpoint
Short-hand for the UDP endpoint (IP/port) type.
Definition: util_fwd.hpp:241
T * construct_at(T *obj, Ctor_args &&... ctor_args)
std::construct_at() equivalent; unavailable until C++20, so here it is.
Definition: util.hpp:793
constexpr Integer ceil_div(Integer dividend, Integer2 divisor)
Returns the result of the given non-negative integer divided by a positive integer,...
Definition: util.hpp:407
An integer-like, type-safe wrapper for the thread-token concept – see this_thread_unique_token(),...