Flow 2.0.0
Flow project: Full implementation reference.
common.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/* These are just so commonly used, that I (ygoldfel) decided to just shove them here for everyone because of the
23 * following boost.chrono I/O thing being nearby anyway. */
24#include <boost/chrono/chrono.hpp>
25#include <boost/chrono/ceil.hpp>
26#include <boost/chrono/round.hpp>
27/* boost.chrono I/O: This is subtle. chrono.hpp doesn't include I/O (including the invaluable ostream<< output of
28 * chrono::duration and chrono::time_point, especially when the latter is from chrono::system_clock). (Probably that
29 * is because std::chrono I/O support is spotty-to-non-existent, including lacking solid ostream<<.) One must include
30 * chrono/chrono_io.hpp... except, as it stands, this loads v1 -- not v2. (Looking inside the header shows it's based
31 * on some BOOST_ #define jungle, but the bottom line is every time I (ygoldfel) see Boost built, it loads v1, not v2.)
32 * However loading v2 is easy (and correct): #include the following 2 files instead; chrono_io.hpp would do so itself if
33 * the BOOST_ #define were set accordingly.
34 *
35 * This should be transparent, and transparently a good thing, for all `#include`ing devs. There are some subtleties
36 * however. In particular these bear mentioning:
37 * - Output of a time_point from system_clock (e.g., chrono::system_clock::now()) to an ostream will (in v2) yield a
38 * nice, predictably formatted, human-readable date/time string that includes the UTC +0000 specifier.
39 * (v1 said something fairly useless -- which v2 still, by necessity, does for non-system_clock values -- like
40 * "28374928742987 nanoseconds since Jan 1, 1970".) This is used directly by flow::log for example.
41 * With chrono::time_fmt(chrono::timezone::local) formatter applied to the ostream<<, it'll be in local time
42 * with the appropriate +xxxx specifier, instead. (There is also custom formatting available but never mind.)
43 * - Breaking change: `chrono::duration_{short|long}` don't work (v1); use chrono::{symbol|name}_format instead (v2).
44 * (This switches between, e.g., "5 ns" and "5 nanoseconds.")
45 * - As of Boost 1.76 at least, v2 includes some deprecated Boost headers which results in a #pragma message (not
46 * a warning/error but verbose and unsightly). -DBOOST_ALLOW_DEPRECATED_HEADERS will make it go away.
47 * - v1 and v2 cannot co-exist (some things, like ostream<<, become defined 2x). Therefore do not attempt to
48 * #include <boost/chrono/chrono_io.hpp>. At best it's redundant; at worst it will fail to compile. */
49#include <boost/chrono/io/duration_io.hpp>
50#include <boost/chrono/io/time_point_io.hpp>
51#include <functional>
52// For certains compile-time checks below.
53#ifdef __APPLE__
54# include <TargetConditionals.h>
55#endif
56
57/**
58 * @mainpage
59 *
60 * Welcome to the Flow project. The documentation you're viewing has been generated using Doxygen directly from Flow
61 * source code and comments. I recommend reading the documentation of `namespace` ::flow as the starting point; then
62 * that will direct one to the documentation of one or more of its sub-namespaces, depending on which Flow module(s)'s
63 * functionality interests that person.
64 */
65
66/* We build in C++17 mode ourselves (as of this writing), but linking user shouldn't care about that so much.
67 * The APIs and header-inlined stuff (templates, constexprs, possibly explicitly-inlined functions [though we avoid
68 * those]), however, also requires C++17 or newer; and that applies to the linking user's `#include`ing .cpp file(s)!
69 * Therefore enforce it by failing compile unless compiler's C++17 or newer mode is in use.
70 *
71 * Note this isn't academic; as of this writing there's at least a C++14-requiring constexpr feature in use in one
72 * of the headers. So at least C++14 has been required for ages in actual practice. Later, notched it up to C++17
73 * by similar logic.
74 *
75 * Update: We continue to target C++17 (by default) in our build -- but now also support (and, outside
76 * the source code proper, test) C++20 mode build, albeit without using any C++20-only language or STL features. It is
77 * conceivable that at some point in the future we'll target C++20 by default (and drop support for C++17 and older).
78 * Naturally at that point we'd begin using C++20 language/STL features when convenient. */
79#if (!defined(__cplusplus)) || (__cplusplus < 201703L)
80// Would use static_assert(false), but... it's C++11 and later only. So.
81# error "To compile a translation unit that `#include`s any flow/ API headers, use C++17 compile mode or later."
82#endif
83
84// Macros. These (conceptually) belong to the `flow` namespace (hence the prefix for each macro).
85
86#ifdef FLOW_DOXYGEN_ONLY // Compiler ignores; Doxygen sees.
87
88/// Macro that is defined if and only if the compiling environment is Linux.
89# define FLOW_OS_LINUX
90
91/// Macro that is defined if and only if the compiling environment is Mac OS X or higher macOS (not iOS and such!).
92# define FLOW_OS_MAC
93
94/// Macro that is defined if and only if the compiling environment is Windows.
95# define FLOW_OS_WIN
96
97#else // if !defined(FLOW_DOXYGEN_ONLY)
98
99// Now the actual definitions compiler sees (Doxygen ignores).
100
101/* Used this delightful page for this logic:
102 * https://web.archive.org/web/20140625123925/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system */
103# ifdef __linux__
104# define FLOW_OS_LINUX
105# elif defined(__APPLE__) && (TARGET_OS_MAC == 1)
106# define FLOW_OS_MAC
107# elif defined(_WIN32) || defined(_WIN64)
108# define FLOW_OS_WIN
109# endif
110
111#endif // elif !defined(FLOW_DOXYGEN_ONLY)
112
113/**
114 * Catch-all namespace for the Flow project: A collection of various production-quality modules written in modern
115 * C++17, originally by ygoldfel. (The very first version was in Boost-y C++03, back around 2010. Later, ~2019, it
116 * moved to C++14 in style and substance; and in 2022 to C++17 -- a relatively minor upgrade.)
117 * While the modules are orthogonal to each other in terms of functionality
118 * provided, they all share a common set of stylistic conventions and happen to use each other internally; hence
119 * they are distributed together as of this writing.
120 *
121 * From the user's perspective, one should view this namespace as the "root," meaning it consists of two parts:
122 * - Sub-namespaces (like flow::log, flow::util, flow::async, flow::net_flow),
123 * each of which represents a *Flow module* providing certain
124 * grouped functionality. Each module is self-contained from the point of view of the user, meaning:
125 * While the various modules may use each other internally (and hence cannot be easily distributed separately), from
126 * user's perspective each one can be directly `include`d/referenced without directly `include`ing/referring to the
127 * others. E.g., one can directly reference `namespace log` *and/or* `namespace util` *and/or* `namespace net_flow`
128 * *and/or* .... Further documentation can be found in the doc headers for each individual sub-namespace.
129 * - Symbols directly in `flow`: The absolute most basic, commonly used symbols (such as `uint32_t` or `Error_code`).
130 * There should be only a handful of these, and they are likely to be small.
131 * - In particular this includes `enum class Flow_log_component` which defines the set of possible
132 * flow::log::Component values logged from within all modules of Flow (again, including flow::util, flow::async,
133 * flow::net_flow, etc.). See end of common.hpp.
134 *
135 * Reiterating: Non-`namespace` symbols directly inside `namespace flow` are to be only extremely ubiquitous items
136 * such as the basic integer types and the log component `enum`. Anything beyond that should go into a sub-`namespace`
137 * of `flow`; if it is something miscellaneous then put it into flow::util.
138 *
139 * Here we summarize topics relevant to all of Flow. It is recommend one reads this before using any individual module,
140 * for topics like file organization and style conventions, topics arguably not of huge practical value right away.
141 * However, all the actual functionality is in the sub-modules, so once you're ready to actually do stuff, I reiterate:
142 * See the list of sub-namespaces of `flow` and start with the doc header of the one(s) of interest to you.
143 *
144 * Documentation / Doxygen
145 * -----------------------
146 *
147 * All code in the project proper follows a high standard of documentation, almost solely via comments therein
148 * (as opposed to ancillary doc files/READMEs/etc.). Additionally, a subset of comments are Doxygen-targeted,
149 * meaning the comment starts with a special character sequence to cause the Doxygen utility to treat that comment
150 * as a doc header for a nearby symbol (class, method, etc.). (If you're not familiar with Doxygen: It's like Javadoc
151 * but better -- although mostly compatible with Javadoc-targeted comments as well -- not that we care about that.)
152 *
153 * From the same source code (the entire Flow tree) 2 (two) web docs are generated by Doxygen utility -- depending on
154 * which of the 2 Doxygen configuration files is chosen. You can determine which web docs you're reading currently
155 * (if indeed you are doing that, as opposed to reading raw code) via the wording of the title/header in every web page:
156 * - *Flow project: Full implementation reference*: This scans every header and translation unit file, including
157 * those in detail/ sub-directories at all levels; and all Doxygen-targeted comments (including this one)
158 * are fully scanned. Full browsable source code is included in the output also. As a result, it's basically
159 * an ultra-nice viewer of the entire source code (implementation included), with special emphasis on
160 * doc headers such as this one.
161 * - *Flow project: Public API*: Only headers are scanned; and all detail/ sub-directories at all levels are ignored.
162 * Additionally, any text following the (optional) `"@internal"` Doxygen command within each given Doxygen comment
163 * is ignored. Browsable source code is omitted. As a result, a clean public API documentation is generated with
164 * no "fat."
165 *
166 * While an important (achieved) goal is to keep the documentation of the library (internal and external, as noted)
167 * self-contained -- within the source code or auto-generated by taking that source code as input -- nevertheless some
168 * satellite documentation is likely to exist; for example to cover such things as the logistical state of the project,
169 * its test harness, perhaps the license, etc. Look outside the root src/flow directory.
170 *
171 * @todo As of this writing the *exact* nature of where the project will permanently reside (and who will maintain it
172 * vs. use it) is in flux. Therefore for now I have removed the section covering certain topics and replaced it with
173 * the to-do you're reading. This should be undone when things settle down (obviously ensuring the brought-back section
174 * is made accurate). The topics to cover: `"@author"` (including contact info); GitHub/other address indicating where
175 * to browse the project source; link(s) to the latest auto-generated web docs (if any); a section on the
176 * history of the project; and licensing info (if deemed needed) or pointer to it. (Reminder: Also update any
177 * similar sections of the historically significant net_flow::Node doc header.)
178 *
179 * @todo Since Flow gained its first users beyond the original author, some Flow-adjacent code has been written from
180 * which Flow can benefit, including a potential `io` module/namespace for general networking/local I/O.
181 * (Flow itself continued to be developed, but some features were added
182 * elsewhere for expediency; this is a reminder to factor them out into Flow for the benefit of
183 * all.) Some features to migrate here might be: boost.asio extensions to UDP receive APIs to obtain receipt time
184 * stamps and destination IP (`recvmsg()` with ancillary data extensions) and to receive multiple datagrams in one
185 * call (`recvmmsg()`); boost.asio-adjacent facility to add custom socket options similarly to how boost.asio does it
186 * internally; boost.asio support for (local) transmission of native socket handles and security data over stream
187 * sockets (`SCM_RIGHTS`, etc.).
188 *
189 * Using Flow modules
190 * ------------------
191 *
192 * This section discusses usability topics that apply to all Flow modules including hopefully any future ones but
193 * definitely all existing ones as of this writing.
194 *
195 * ### Error reporting ###
196 * Similarly to boost.asio, all public methods that may return errors can either do so via an
197 * error code or an exception encapsulating that same error code. If user passes in non-null pointer to a
198 * flow::Error_code variable, the latter is set to success (falsy) or a specific failure (truthy `enum` value). If
199 * user passes in null pointer, an exception `exc` is thrown only in case of error and will encapsulate that error code
200 * (accessible via `exc.code()`).
201 *
202 * For details about error reporting, see doc headers for flow::Error_code (spoiler alert: a mere alias to
203 * `boost::system::error_code`) and `namespace` flow::error.
204 *
205 * ### Logging ###
206 * The flow::log namespace (see especially log::Logger and the various `FLOW_LOG_...*()` macros in
207 * log/log.hpp) provides a logging facility -- used by Flow modules' often-extensive logging, and equally available
208 * to the Flow user. Ultimately, you may tweak the log level and then observe the given Flow module's internal behavior
209 * to whatever level of detail you desire. Similarly, as the user, you may use this system for your own logging,
210 * even if you use no Flow module other than flow::log itself. Either way, you can hook up flow::log to log via your
211 * own log output device in arbitrary fashion (e.g., save the log messages in a database, if that's what you want).
212 *
213 * For details about logging, see doc header for `namespace` flow::log.
214 *
215 * @internal
216 *
217 * Implementation notes
218 * --------------------
219 *
220 * There is a high standard of consistency and style, as well as documentation, in Flow. Before making changes to
221 * the code, you must read doc-coding_style.cpp.
222 *
223 * ### Source file tree organization ###
224 * See doc-coding_style.cpp which covers this topic.
225 *
226 * ### Libraries used; Boost ###
227 * We use STL and several Boost libraries (notably boost.asio) extensively.
228 * See doc-coding_style.cpp which covers this topic.
229 *
230 * ### Exceptions ###
231 * For reasons of speed (hearsay or reputational though they may be) we avoid exception-throwing
232 * boost.asio routines inside the modules' implementations, even though using them would make the code a bit simpler
233 * in many areas. Similarly, we avoid throwing our own exceptions only to catch them higher in the back-trace.
234 * In both cases, we typically use error codes/return values. These are not absolute/hard rules, as exceptions may be
235 * used where minuscule speed improvements are immaterial (like the initialization and shutdown of a long-lived object
236 * such as net_flow::Node).
237 *
238 * After a recent look at performance implications of exceptions, the following is the basic conclusion: Exceptions have
239 * no processor cycle cost, unless actually thrown, in which case the perf cost can be non-trivial. Since we consider
240 * internal performance of paramount importance, we generally avoid throwing exceptions -- only to catch them
241 * internally -- as noted in the preceding paragraph. Arguably such situations are rare anyway, so using an exception
242 * internally wouldn't actually slow anything down, but we haven't performed a code audit to verify that stipulation;
243 * and in the meantime the consistent avoidance of using internally caught exceptions has proved to be a very reasonable
244 * policy. (For some modules this may be arguably mostly moot: Consider flow::net_flow specifically: Since --
245 * internally -- mostly boost.asio `async_*()` methods are used, and those
246 * by definition report errors as codes passed into async handler functions; whether to use an exception or not is
247 * an ill-formed question in all such situations.) We recommend this practice continue, until there's a specific reason
248 * to reconsider.
249 *
250 * See doc-coding_style.cpp for more discussion of error handling and exceptions.
251 *
252 * Code style guidelines
253 * ---------------------
254 *
255 * ### General coding style requirements ###
256 * The formal guidelines are in doc-coding_style.cpp; read that file please.
257 *
258 * ### Documentation guidelines ###
259 * The standard for documentation of Flow modules is that someone reading the source code, and nothing else, would
260 * be able to understand that code (modulo having the intellectual sophistication/experience w/r/t the subject
261 * matter, of course). Simple but quite a task given how much code there is and the complexity. We also
262 * produce Doxygen output (2 web pages, as of this writing) by running the code through Doxygen.
263 *
264 * @see More on the technicalities of how we run Doxygen, and the philosophy behind all of that, can be found
265 * in a `doc/` or similar directory outside src/flow. It's rare something pertinent to the source code
266 * is not IN the source code (i.e., right here somewhere), but the README explains why that rare choice is
267 * made (among many more practical/interesting things). This is worth reading if you'll be contributing to the
268 * code.
269 *
270 * The actual guidelines are, as above, in doc-coding_style.cpp; read that file please.
271 *
272 * @todo Possibly document exceptions thrown explicitly via the Doxygen keyword meant for this purpose: `"@throws"`.
273 * Currently when we document explicitly throwing an exception, it is ALWAYS a flow::error::Runtime_error
274 * encapsulating a flow::Error_code (which is an `int`-like error code). This is very explicitly documented,
275 * but technically Doxygen has a keyword which will generate a special little readout for the exception
276 * (similarly as for each parameter, etc.). We don't use that keyword. We probably should, though this
277 * isn't totally cut-and-dried. Consider that we already document the exception on the `err_code` parameter
278 * in every case; so no information would really be gained (only arguably nicer formatting). On the other hand,
279 * the code would be somewhat more verbose (and boiler-platey, since each already boiler-platey `err_code`
280 * comment snippet would essentially grow in size). Furthermore, if we document this explicit exception, one might
281 * say it behooves us to now document all the other possible sources of exceptions such as `std::bad_alloc` when
282 * running out of heap memory. Perhaps then we have to talk about constructor-throwing-exception behavior and
283 * other C++ technicalities to do with exceptions. Do we really want to enter that land? I think maybe not;
284 * consider just leaving it alone. Though, maybe I'm over-dramatizing the impact of adding a `"@throws"`
285 * section on our various flow::error::Runtime_error-throwing methods. Well, it's a to-do; decide later.
286 *
287 * To-dos and future features
288 * --------------------------
289 *
290 * @todo The comments (as of this writing, all written by me, ygoldfel) in this library could use an edit to make
291 * them briefer. (I've found even a self-edit by me, with that express purpose, often does wonders.) Background:
292 * I write very extensive comments. I am quite convinced this is superior (far superior even) to next-to-no comments;
293 * and to the average amount of comments one tends to see in production code. *That said*, the top code review
294 * feedback I receive (not here specifically but in general) is that my comments tend to be too "discursive" (consisting
295 * of discourse) and/or at times unnecessarily in-depth. Discursive = as if I am talking to the reader (many prefer
296 * a terser, more formal style). Too in-depth = tends to go into history, related issues, future work, etc.
297 * (these elements can remain but can be cut down significant without losing much substance).
298 * In other words, there should be a happy middle in terms of comment volume, and this can
299 * be achieved by a comment edit run by Yuri or someone else (if reviewed by Yuri). To be clear, I believe this middle
300 * ground is to be closer to the status quo than to the average amount of comments in other projects.
301 *
302 * @todo Be more specific (cite date) when writing "as of this writing."
303 * I use a rhetorical trick when commenting the state of something that may not continue to be the case.
304 * Though I do avoid writing such things, often it is necessary; in that case I usually write "as of this writing" or
305 * something very similarly worded. That's fine and essentially the best one can do. It means technically the
306 * statement won't become false, even if the "sub-statement" (the thing that was true when written) does become false.
307 * However, obviously, to the reader of the comment at that later time, that's little consolation: they're still reading
308 * a possibly false statement and will want to know what the situation is THEN, or "as of the reading," to to speak.
309 * In order to at least try to be helpful, in those cases a date (numeric month/year -- like 4/2017 -- should be
310 * sufficient in most cases) should be supplied. The to-do is to convert all "as of this writing" instances -- and
311 * to always add a date when writing new instances of "as of this writing." The to-do can be removed once the
312 * conversion is completed. Example: this to-do has not been completed as of this writing (11/2017).
313 * (Side note: possibly goes without saying, but one is free to explain to an arbitrary degree of detail why something
314 * is true as of that writing, and how/why/when it might change. This to-do covers those cases where no such
315 * explanation is written. It would be impractically verbose to get into speculative detail for every
316 * as-of-this-writing instance; so at least a date should thus be inserted.)
317 *
318 * @todo There are some boost.thread "interruption points" throughout the code, so we should
319 * investigate whether we must catch `boost::thread_interrupted` in those spots, or what...?
320 *
321 * @todo Inline things: Or just use `gcc -O3` (and non-`gcc` equivalents) for prettier/faster-to-compile
322 * code? The latter is definitely tempting if it works sufficiently well. So far we've been using
323 * `gcc -O3` and equivalents, and it seems to be working well (turning off inlining results in huge
324 * performance losses). Still, I am not sure if it would be better to explicitly `inline` functions
325 * instead. Not having to do so definitely simplifies the code, so it is my great hope that the answer is
326 * no, and we can keep using `gcc -O3` and equivalents. In that case delete this paragraph.
327 * (To be clear: `gcc -O3` means that it ignores `inline` keyword and anything similar, including inlined
328 * method bodies inside `class {}` and `struct {}`. Instead it determines what to inline based on its own
329 * ideas on what will generate the fastest code (with reasonable code size). `gcc -O2`, on the other
330 * hand, will mostly inline things explicitly declared as such in code (again, via `inline` or inlining inside
331 * class bodies or other techniques).) Update: Now using clang (not gcc) with maximum auto-inlining AND FLTO
332 * (link-time optimization will allow inlining across object file boundaries) in at least some platforms.
333 * This should be close to as good as possible. Update: gcc auto-inlining+FLTO also works.
334 *
335 * @todo One space after period, not two:
336 * For some reason in this project I've been following the convention -- in comments and (I think) log
337 * messages -- of two spaces after a sentence-ending punctuator (usually period) before the next sentence's
338 * first character. I now regret trying this annoying convention. Go back to one space. (For the record,
339 * it does look sort of nice, but that's a matter of opinion, and single space looks fine too... AND doesn't
340 * confuse various editors' auto-formatting facilityies, among other problem.)
341 *
342 * @todo We use `0` instead of `NULL` or `nullptr` when needing a null pointer; perhaps we should use the latter.
343 * `NULL` is an anachronism from C, so we shouldn't use it. `nullptr` is at least no worse than `0`,
344 * however, other than being less concise. However, the main reason it exists --
345 * to avoid ambiguities in function overloading (e.g., when something could
346 * take either an `int` or a `char*`, `nullptr` would resolve to the latter, while `0` probably unintentionally
347 * to the former) -- is not a situation our style ever invokes, to my knowledge, so using `nullptr` would not
348 * solve any actual problems. However, it could be argued that using it more readily calls attention to the use
349 * of a pointer, as opposed to an integer, in the particular context at play. So it's something to consider
350 * (but, no doubt, the conversion process would be laborious, as there's no simple search-replace that would
351 * work).
352 *
353 * @todo `= default` for copy constructors and copy operators is now used in a few places; consider spreading
354 * this C++11 feature everywhere it's being done implicitly due to C++03 rules (good documentation practices suggest
355 * declaring them explicitly but of course leave the implementation to the compiler default, gaining best of both
356 * worlds -- proper class API docs yet maintenance-friendly default body).
357 *
358 * @todo Consider PIMPL and related topics. Recommend scouring Boost docs, particularly for the smart pointer library,
359 * which discuss how to potentially use smart pointers for easy PIMPLing. In general, research the state of the art
360 * on the topic of library interface vs. implementation/hiding.
361 *
362 * @todo `std::string_view` is a way to pass things around similarly to `const std::string&` without requiring
363 * that a `string` be created just for that purpose; it has a highly similar API but can be constructed from any
364 * character sequence in memory and internally stores nothing more than a pointer and length; we should use it wherever
365 * possible (within reason) instead of `const std::string&`. Much code now uses `String_view`; the remaining to-do
366 * is: scour the rest of the code for possible `const string&`s to convert and indeed convert those to
367 * util::String_view.
368 *
369 * @todo Return-by-copy binary operators of the form `T operatorBLAH(const T& x1, const Some_type& x2)` should be
370 * written as free functions instead of `T` members. I don't recall at this point why, but this tends to be recommended
371 * and done in STL and Boost. Maybe check the Meyer Effective C++ book on the theory; and if it makes sense find all
372 * such operators written as members and change them to be free functions. Should this be avoided if it requires
373 * `friend` though? Lastly, for Doxygen, use the `relatesalso T` command to link the free function to the class `T`
374 * in the documentation.
375 *
376 * @todo In many (most) cases we pass `shared_ptr`s (and their aliases) by value when it would be more performant to
377 * do so by `const` reference; at times possibly better to pass by raw pointer. Scott Meyer/Herb Sutter have opined
378 * on this to basically indicate that (1) it is often best to use a raw pointer, unless actual copying/ownership status
379 * is expected; but failing that (2) it is often best to use a `const&` when safe; and failing that passing by
380 * value is fine. This need not be a dogmatic change, but we should be more mindful than simply always passing by
381 * value. When searching for instances to potentially change, check for `shared_ptr`, `Ptr`, and `_ptr` tokens.
382 */
383namespace flow
384{
385
386// Types. They're outside of `namespace ::flow::util` for brevity due to their frequent use.
387
388// Integer short-hands and specific-bit-width types.
389
390/// Byte. Best way to represent a byte of binary data. This is 8 bits on all modern systems.
391using uint8_t = unsigned char;
392/// Signed byte. Prefer to use `uint8_t` when representing binary data. This is 8 bits on all modern systems.
393using int8_t = signed char;
394
395// Time-related short-hands.
396
397/**
398 * Clock used for delicate time measurements, such that the `now()` method gets the current time
399 * relative to some unknown but constant epoch (reference point). Used to measure durations of
400 * things. It has the following properties:
401 *
402 * - Steady: time cannot go backwards (e.g., via user time change, NTP); time values increment at
403 * a rate proportional to real time (no leap seconds for example).
404 * - High-resolution: the increments of time at which the clock runs are as small as supported
405 * by the OS+hardware. This should be at most a handful of microseconds in practice.
406 *
407 * So basically it's a precise clock with no surprises (which is more than can be said for stuff people
408 * tend to be forced to use, like `gettimeofday()`).
409 */
410using Fine_clock = boost::chrono::high_resolution_clock;
411
412/// A high-res time point as returned by `Fine_clock::now()` and suitable for precise time math in general.
413using Fine_time_pt = Fine_clock::time_point;
414
415/// A high-res time duration as computed from two `Fine_time_pt`s.
416using Fine_duration = Fine_clock::duration;
417
418/**
419 * Short-hand for a boost.system error code (which basically encapsulates an integer/`enum` error
420 * code and a pointer through which to obtain a statically stored message string); this is how Flow modules
421 * report errors to the user; and we humbly recommended all C++ code use the same techniques.
422 *
423 * @note It is not inside flow::error namespace due to its (`Error_code`'s) ubiquity.
424 * Very few other symbols should follow suit. We may decide to move it there after all.
425 *
426 * ### Basic error-emitting API semantics ###
427 *
428 * All error-reporting Flow APIs follow the following pattern of error reporting semantics.
429 * Each API looks something like:
430 *
431 * ~~~
432 * return_type Some_class::some_op(..., flow::Error_code* err_code)
433 * ~~~
434 *
435 * Then, there are two possibilities. If you pass in non-null `err_code`, then after return `*err_code` is
436 * success (falsy) or a truthy `enum`-like value, representing a specific error. If, instead, you pass in null,
437 * then a flow::error::Runtime_error() `exc` is thrown if and only if `*err_code` would have been set to truthy value
438 * `e_c` had a non-null `err_code` been passed in. If such an exception is thrown, `Error_code e_c` is
439 * encapsulated in exception object `exc`. If and only if no exception is thrown, there was no error (`*err_code` would
440 * have been falsy).
441 *
442 * Thus, you get the best of both worlds: you can get the simplicity and performance
443 * of an error code; or the various features of an exception (including access to the error code via
444 * `exc.code()` if desired), with the same API signature. (boost.asio
445 * follows a similar concept, though it requires two API signatures for each operation, one without
446 * an `Error_code` argument, and one with non-`const` `Error_code&` out-arg. The above convention is more compact;
447 * plus we provide certain tools to reduce boiler-plate in connection with this.)
448 *
449 * ### Intro to `Error_code`, a/k/a boost.system `error_code` ###
450 * (I am restating boost.system documentation here, but that particular set of docs is notoriously
451 * formal-but-reader-unfriendly.)
452 *
453 * A truthy `Error_code` is a very lightweight -- `errno`-like in that regard -- value indicating
454 * the error that occurred. It stores an `int` code and a "category" pointer (basically, thing specifying to what code
455 * set this belongs). The `int` is to be converted from the error code set of choice, whereas the category pointer is
456 * internally magically determined based on the type of the error code value being converted to `Error_code`.
457 *
458 * An `Error_code` itself can be serialized into `ostream`s (and thus `string`s via `lexical_cast`, etc.) easily for
459 * logging purposes/etc. You can access both the numeric code and a human explanation of the error.
460 * Any and all error code sets are supported by this boost.system type. POSIX `errno`s are one possible set of codes;
461 * boost.asio has its own code set; and other modules in `flow` may introduce their own code sets. All are compatible
462 * for equality/assignment/etc. with this general `Error_code` type.
463 *
464 * As stated, all error-emitting Flow public APIs (regardless of module) use the above-described error-reporting
465 * conventions. In addition, we humbly recommend Flow *user* code adopt the same battle-tested conventions. However
466 * that is absolutely not required and is entirely independent of the fact that Flow modules use them. Do note this
467 * convention is battle-tested in boost.asio as well; though Flow's version is more compact; by using a pointer (which
468 * can be null) instead of a reference it cuts the number of error-emitting API functions in half.
469 *
470 * For each function (including each publicly exported error-reporting function within Flow) that indeed agrees to
471 * use the above convention, follow these instructions:
472 *
473 * To reduce boiler-plate, within reason, it is incumbent on each error-reporting method to use the following
474 * technique:
475 *
476 * - The method signature should be similar to the above (including naming it `err_code`) and use the above semantics.
477 * - Use FLOW_ERROR_EXEC_AND_THROW_ON_ERROR() (and/or nearby similar utilities in flow/error/error.hpp) for minimal
478 * boiler-plate that implements these semantics. See doc header for that macro for details.
479 * - You may or may not indicate the lack or presence of an error condition via some additional non-exception technique
480 * such as a `bool` return value.
481 * - The error behavior documentation should be *confined entirely* to the documentation of `err_code` parameter, so
482 * that the above semantics need not be repetitively restated a million times.
483 * The text of the parameter's doc should usually be as follows (you may copy/paste to start). In this example
484 * the function returns codes from the `net_flow::error::Code` code set `enum`; but please substitute your code set of
485 * choice (again; `errno` and boost.asio error codes are 2 possible other examples of code sets). Here we go:
486 *
487 * ~~~
488 * // param err_code
489 * // See flow::Error_code docs for error reporting semantics. net_flow::error::Code generated:
490 * // net_flow::error::Code::S_(...) (optional comment), ...more... , net_flow::error::Code::S_(...)
491 * // (optional comment).
492 * ~~~
493 *
494 * @see The doc header (and code inside) `namespace` flow::net_flow::error is a good primer showing how to create
495 * an `Error_code`-compatible set of error codes. This is easier to understand than boost.asio's counterpart
496 * for example.
497 *
498 * @note boost.system at some point -- I (ygoldfel) am fairly sure after I designed the above ages ago -- introduced
499 * an alternate idiom for passing an #Error_code out-arg that is to be ignored in favor of throwing an exception
500 * if omitted. We use the idiom: `Error_code*` out-arg, throw if null. They, instead propose:
501 * `Error_code&` out-arg, throw if it equals `boost::system::throws()`. That's great, too, but actually our
502 * idiom hews to another bit of the Flow coding style/guide, wherein out-args should be pointers, not
503 * non-`const` references -- and is otherwise very similar. So it's fine. Note that their idiom vs. ours =
504 * orthogonal to the main difficulty which is the boiler-plate associated with actually throwing vs. non-throwing;
505 * this would be required regardless of the API idiom chosen. The above (involving
506 * FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(), etc.) is really the main crux of it.
507 */
508using Error_code = boost::system::error_code;
509
510// See just below.
511template<typename Signature>
513
514/**
515 * Intended as the polymorphic function wrapper of choice for Flow, internally and externally; to be used
516 * instead of `std::function` or `boost::function`. Due to ubiquitous use of such function-object wrappers,
517 * this is one of the very few direct non-`namespace` members of the outer namespace `::flow`.
518 *
519 * In reality it *is* `std::function`, with a couple of added APIs (no data) to make it more similar to
520 * `boost::function` API-wise.
521 *
522 * ### Rationale ###
523 * By far the main reason this exists is: I (ygoldfel) conducted an investigation in 2022, with a not-too-old gcc
524 * in Linux, in C++17 mode, with Boost 1.78 (but built seemingly in C++03-supporting config) about the
525 * performance behavior of lambdas objects and `boost::function<>` and `std::function<>` wrappers thereof.
526 * I noticed these things:
527 * - Say one constructs a `boost::function` from a lambda that has 1 or more by-value captures `[x = std::move(x)]`,
528 * with those captures' types having move ctors different and faster than copy ctors. I found that this not only
529 * *copies* each of those captures (invokes their copy ctors), but it even does so several times!
530 * - However, constructing an `std::function` identically never invokes copy ctors -- only move ctors --
531 * and fewer times at that.
532 * - Say one constructs a `boost::function` from a lambda that has 1 or more by-value captures `[x = std::move(x)]`,
533 * with those captures' types having move ctors but `= delete`d copy ctors. I.e., say at least 1 capture is
534 * movable but not copyable; `unique_ptr` being a classic and practical example. Well: This does not compile;
535 * gcc complains `boost::function` needs `unique_ptr` to have a copy ctor, but it is `delete`d.
536 * In the case of `unique_ptr`, one can do `[x = shared_ptr(std::move(x))]` to get it work, though it's a bit
537 * more code, reduces perf by adding ref-counting, and reduces smart-ptr safety inside the lambda body.
538 * - However, constructing an `std::function` identically compiles and works fine.
539 *
540 * So, long story short, at least in that environment, `std::function` is just plain faster than `boost::function`,
541 * avoiding copying of captures; and it's easier to use with movable-not-copyable capture types.
542 *
543 * So we could have just done circa `using Function = std::function;`. Why the subclass? Answer: `std::function`
544 * lacks a couple of commonly used `boost::function` APIs that code tends to rely on (in the past we used
545 * `boost::function`). These are empty() and clear() as of this writing. See their doc headers (nothing amazing).
546 *
547 * Lastly: In the aforementioned environment, possibly because of having to support C++03 (which lacked
548 * param packs) -- unlike `std::function` which was introduced in C++11 to begin with (and
549 * probably conceptually based on `boost::function`) -- `boost::function`
550 * supports up to 10 args and does not compile when used with 11+ args. `std::function`, and therefore Function,
551 * lacks this limitation. It can be used with any number of args.
552 *
553 * @tparam Result
554 * See `std::function`.
555 * @tparam Args
556 * See `std::function`.
557 */
558template<typename Result, typename... Args>
559class Function<Result (Args...)> :
560 public std::function<Result (Args...)>
561{
562public:
563 // Types.
564
565 /// Short-hand for the base. We add no data of our own in this subclass, just a handful of APIs.
566 using Function_base = std::function<Result (Args...)>;
567
568 // Ctors/destructor.
569
570 /// Inherit all the constructors from #Function_base. Add none of our own.
571 using Function_base::Function_base;
572
573 // Methods.
574
575 /**
576 * Returns `!bool(*this)`; i.e., `true` if and only if `*this` has no target.
577 *
578 * ### Rationale ###
579 * Provided due to ubuiquity of code that uses `boost::function::empty()` which `std::function` lacks.
580 *
581 * @return See above.
582 */
583 bool empty() const noexcept;
584
585 /**
586 * Makes `*this` lack any target; i.e., makes it equal to a default-constructed object of this type, so that
587 * `empty() == true` is a post-condition.
588 *
589 * ### Rationale ###
590 * Provided due to ubuiquity of code that uses `boost::function::clear()` which `std::function` lacks.
591 */
592 void clear() noexcept;
593}; // class Function<Result (Args...)>
594
595#ifdef FLOW_DOXYGEN_ONLY // Actual compilation will ignore the below; but Doxygen will scan it and generate docs.
596
597/**
598 * The flow::log::Component payload enumeration comprising various log components used by Flow's own internal logging.
599 * Internal Flow code specifies members thereof when indicating the log component for each particular piece of
600 * logging code. Flow user specifies it, albeit very rarely, when configuring their program's logging
601 * such as via flow::log::Config::init_component_to_union_idx_mapping() and flow::log::Config::init_component_names().
602 *
603 * If you are reading this in Doxygen-generated output (likely a web page), be aware that the individual
604 * `enum` values are not documented right here, because flow::log auto-generates those via certain macro
605 * magic, and Doxygen cannot understand what is happening. However, you will find the same information
606 * directly in the source file `log_component_enum_declare.macros.hpp` (if the latter is clickable, click to see
607 * the source).
608 *
609 * ### Details regarding overall log system init in user program ###
610 *
611 * The following is a less formal reiteration of flow::log::Config documentation and is presented here -- even
612 * though technically in the present context Flow itself is nothing more than yet another module that uses
613 * flow::log for its own logging -- for your convenience. Flow's own logging can be seen as the canonical/model
614 * use of flow::log, so other flow::log users can read this to learn the basics of how to configure loggingg.
615 * That's why we re-explain this info here, in brief form:
616 *
617 * Your program -- that uses the present library -- can register this `enum` in order for these components
618 * (and particularly the log messages that specify them via flow::log::Log_context or
619 * FLOW_LOG_SET_CONTEXT()) to be logged properly in that program, co-existing correctly with other code bases
620 * that use flow::log for logging. Typically one constructs a `flow::log::Config C` and then at some point
621 * before logging begins:
622 * - For each `enum class X_log_component` (note that `Flow_log_component` is only one such `enum class`):
623 * -# `C.init_component_to_union_idx_mapping<X_log_component>(K)`, where `K` is a distinct numeric offset,
624 * maybe multiple of 1000.
625 * -# `C.init_component_names<X_log_component>(S_X_LOG_COMPONENT_NAME_MAP, ..., "X-")`.
626 * - Note the "X-" prefix, allowing one to prepend a namespace-like string prefix to avoid any output and config
627 * clashing.
628 * -# `C.configure_default_verbosity(Sev::S)`, where `S` is some default max severity.
629 * -# For each component `M` for which one desires a different max severity `S`:
630 * - `C.configure_component_verbosity<X_log_component>(Sev::S, X_log_component::M)`. OR:
631 * - `C.configure_component_verbosity_by_name(Sev::S, "X-M")`.
632 * - Apply `C` to the flow::log::Logger or `Logger`s you want to affect.
633 * - Pass the `Logger` or `Logger`s to appropriate APIs that want to log.
634 *
635 * One could make changes after logging has begun, but that's a separate topic.
636 */
638{
639 /**
640 * CAUTION -- see flow::Flow_log_component doc header for directions to find actual members of this
641 * `enum class`. This entry is a placeholder for Doxygen purposes only, because of the macro magic involved
642 * in generating the actual `enum class`.
643 */
645};
646
647/**
648 * The map generated by flow::log macro magic that maps each enumerated value in flow::Flow_log_component to its
649 * string representation as used in log output and verbosity config. Flow user specifies, albeit very rarely,
650 * when configuring their program's logging via flow::log::Config::init_component_names().
651 *
652 * As a Flow user, you can informally assume that if the component `enum` member is called `S_SOME_NAME`, then
653 * its string counterpart in this map will be auto-computed to be `"SOME_NAME"` (optionally prepended with a
654 * prefix as supplied to flow::log::Config::init_component_names()). This is achieved via flow::log macro magic.
655 *
656 * @see flow::Flow_log_component first.
657 */
658extern const boost::unordered_multimap<Flow_log_component, std::string> S_FLOW_LOG_COMPONENT_NAME_MAP;
659
660#endif // FLOW_DOXYGEN_ONLY
661
662// Template implementations.
663
664template<typename Result, typename... Args>
665bool Function<Result (Args...)>::empty() const noexcept
666{
667 return !*this;
668}
669
670template<typename Result, typename... Args>
671void Function<Result (Args...)>::clear() noexcept
672{
673 *this = {};
674}
675
676} // namespace flow
std::function< Result(Args...)> Function_base
Short-hand for the base. We add no data of our own in this subclass, just a handful of APIs.
Definition: common.hpp:566
Catch-all namespace for the Flow project: A collection of various production-quality modules written ...
Definition: async_fwd.hpp:75
boost::system::error_code Error_code
Short-hand for a boost.system error code (which basically encapsulates an integer/enum error code and...
Definition: common.hpp:508
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Definition: common.hpp:638
@ S_END_SENTINEL
CAUTION – see flow::Flow_log_component doc header for directions to find actual members of this enum ...
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:416
boost::chrono::high_resolution_clock Fine_clock
Clock used for delicate time measurements, such that the now() method gets the current time relative ...
Definition: common.hpp:410
signed char int8_t
Signed byte. Prefer to use uint8_t when representing binary data. This is 8 bits on all modern system...
Definition: common.hpp:393
Fine_clock::time_point Fine_time_pt
A high-res time point as returned by Fine_clock::now() and suitable for precise time math in general.
Definition: common.hpp:413
const boost::unordered_multimap< Flow_log_component, std::string > S_FLOW_LOG_COMPONENT_NAME_MAP
The map generated by flow::log macro magic that maps each enumerated value in flow::Flow_log_componen...
unsigned char uint8_t
Byte. Best way to represent a byte of binary data. This is 8 bits on all modern systems.
Definition: common.hpp:391