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