Flow 1.0.0
Flow project: Full implementation reference.
util_fwd.hpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
22#include "flow/common.hpp"
23#include <boost/shared_ptr.hpp>
24
25/// @cond
26// -^- Doxygen, please ignore the following.
27
28/* This strangeness is a work-around a Boost bug which manifests itself at least in g++ and clang++ in
29 * C++11 mode, when trying to use ratio<>::num and ::den. Without this, those two symbols, per each ratio<>
30 * type directly used, each get an undefined reference linker error. See https://svn.boost.org/trac10/ticket/13191,
31 * not fixed as of this writing. @todo: Revisit. */
32#ifndef BOOST_NO_CXX11_CONSTEXPR
33template <boost::intmax_t N, boost::intmax_t D>
34const boost::intmax_t boost::ratio<N, D>::num;
35template <boost::intmax_t N, boost::intmax_t D>
36const boost::intmax_t boost::ratio<N, D>::den;
37#endif
38
39// -v- Doxygen, please stop ignoring.
40/// @endcond
41
42namespace flow::util
43{
44
45// Types.
46
47/* (The @namespace line shouldn't be needed, but there must be some Doxygen bug causing that doc header to get
48 * merged into the succeeding function's. Who knows? @todo Look into it more in copious spare time.
49 *
50 * Update: That was with Doxygen 1.8.11 through 1.8.15. In 1.8.16, it's still true; plus another bug appeared:
51 * The first sentence (up to the first period) is supposed to interpreted, with certain Doxygen config,
52 * as @brief, meaning the brief summary of the namespace; this feature is used constantly, not just in this
53 * spot. Well, for some reason that Doxygen version took the @brief to be blank (shows up as blank in the
54 * namespaces list page and the namespace page itself), whereas before it was fine. Since it's not happening
55 * for anything else I made it an explicit @brief here and called it a day; I guess the Doxygen parser is
56 * getting doubly confused; not sure. @todo Sigh, untangle this at some point; maybe Doxygen gets fixed;
57 * file bug against Doxygen. This is the only (documented) namespace alias in the code, as of this writing, so
58 * maybe that is why it is "special.") */
59
60/**
61 * @namespace flow::util::bind_ns
62 *
63 * @brief Hack namespace alias to enable use of `bind` and related utilities like `cref` in the face of strange observed
64 * compiler behavior.
65 *
66 * The code in the past used `bind` and its helpers `cref` and `ref` fairly extensively. (Vast majority of `bind`s are
67 * now replaced with superior uses of lambdas, with the upgrade to C++1x. So it's far less extensive than in past.)
68 * However, there is something odd going on with namespace resolution for
69 * these guys. At least in the clang version used as of this writing, `bind` somehow
70 * works without qualification, as does `cref` (and thus probably `ref`); I really don't know why. I'd like to use
71 * the `boost::` versions, though, specifically (for stylistic reasons explained elsewhere). More importantly, I don't
72 * want to use something that mysteriously works without qualification -- is `std::` somehow being forced with some
73 * phantom `using namespace` from some evil header somewhere? I am not sure as of this writing. In any case,
74 * this allows one to just say `using util::bind_ns::bind` and then use `bind()` without qualification in that
75 * block (typically function/method) without worrying that some weird unqualified guy will be used.
76 *
77 * Caveat 1: I don't know why, but in the aforementioned clang, `using util::bind_ns::cref` makes `cref()` become
78 * ambiguous with some `std::cref`; it's quite unclear why the same complaint then doesn't happen for `bind()` itself.
79 * In that case, when an error is encountered, get rid of the `using` and instead qualify it as `util::bind_ns::cref()`.
80 * It sucks, but at least it's clear.
81 *
82 * Caveat 2: I haven't built in MS Visual Studio in quite a while (though it did use to work at one point), but back
83 * then I remember some VC++-specific trouble with `bind()` resolution. Possibly it's related to the above.
84 * Anyway, use `bind_ns` as needed to get around any such compile errors.
85 *
86 * Note: Knowing of this phantom `bind()` that's magically available sans qualification, I also tried to use
87 * unqualified `cout` and `endl` in the same context but thankfully got the expected errors in clang saying
88 * these identifiers do not exist but suggesting the use of `std::cout` and `std::endl`. So, at least it's not
89 * all of `std` being forced on the code.
90 *
91 * @todo Investigate deeply the cause of the strange behavior with unqualified `bind()` and others described
92 * above this line in the source code.
93 */
94namespace bind_ns = boost;
95
96// Free functions.
97
98/**
99 * Helper that takes a non-negative duration of arbitrary precision/period and converts it to
100 * #Fine_duration, rounding up. Also, the input type's `max()` is translated to `Fine_duration::max()`.
101 *
102 * @tparam Rep
103 * See `boost::chrono::duration` documentation.
104 * @tparam Period
105 * See `boost::chrono::duration` documentation.
106 * @param dur
107 * A non-negative duration (or assertion trips).
108 * @return See above.
109 */
110template<typename Rep, typename Period>
111Fine_duration chrono_duration_to_fine_duration(const boost::chrono::duration<Rep, Period>& dur);
112
113/**
114 * Helper that takes a non-negative duration of arbitrary precision/period and converts it to
115 * #Fine_duration, rounding up; then adds it to `Fine_clock::now()` and returns the result.
116 * Also, the input type's `max()` is translated to `Fine_time_pt()` (Epoch-valued -- i.e., zero-valued -- time point).
117 *
118 * @tparam Rep
119 * See `boost::chrono::duration` documentation.
120 * @tparam Period
121 * See `boost::chrono::duration` documentation.
122 * @param dur
123 * A non-negative duration (or assertion trips).
124 * @return See above.
125 */
126template<typename Rep, typename Period>
127Fine_time_pt chrono_duration_from_now_to_fine_time_pt(const boost::chrono::duration<Rep, Period>& dur);
128
129/**
130 * Helper for FLOW_UTIL_WHERE_AM_I() that, given a pointer/length of a string in memory containing a path, returns
131 * a pointer/length into that same buffer that comprises the postfix
132 * just past the last directory separator or (if none exists) to all of it.
133 *
134 * ### Rationale for taking and returning #String_view this way ###
135 * There are 2 other alternatives. One is essentially to take `std::string` (or #String_view) and return new
136 * `std::string` (or some variation). That is un-great, because the main use case is to use this at log call sites,
137 * and creating temporary `std::string`s is best avoided; the ability to simply return a pointer into existing memory,
138 * -- particularly since it is likely to come from `__FILE__` (which is in static memory) -- might represent
139 * significant perf savings. So that leaves either the alternative we chose or a variation (which, historically, used
140 * to be the case) which is to take a `const char*` and return same, into that memory. The latter is an acceptable
141 * approach. #String_view, by comparison, does involve storing an extra bit of data, namely the length stored inside
142 * #String_view. We stipulate this is negligible in terms of RAM and copying costs when compared to doing same with
143 * the pointers alone... but what's the advantage? Answer: it may be small; but in order to search for the right-most
144 * dir separator character, one needs to internally find the NUL (a/k/a `strlen()`); with #String_view it is already
145 * available, so the linear search is unnecessary. Doesn't it cost cycles to set the length though? you ask.
146 * Answer: Not if one constructs the `#String_view`s involved cleverly. To wit:
147 *
148 * ### Instructions on how to best construct `String_view path` from `__FILE__` ###
149 * For max performance, do it in the same way as recommended when setting log::Msg_metadata::m_msg_src_file.
150 * Spoiler alert: Use `sizeof(__FILE__)` to obtain a compile-time length.
151 *
152 * ### `constexpr` ###
153 * Update: This function is now `constexpr`, so `path` must be known at compile-time; hence the above instructions
154 * (while still valid) apply in a different way. The raw performance doesn't necessarily matter (since it's "executed"
155 * by the compiler now). However, following those instructions (1) will help make `constexpr`ness easier to achieve
156 * (as the NUL-terminated #String_view ctor is less likely to be effectively `constexpr` depending on compiler; while
157 * the pointer+length ctor is more likely so); and (2) is good for perf in case `constexpr`ness is
158 * dropped in the future. It's less fragile is the point. Anyway, just do it!
159 *
160 * @param path
161 * String containing a path from a `__FILE__` macro. See instructions above for max perf.
162 * @return See above.
163 */
165
166/**
167 * Helper for FLOW_UTIL_WHERE_AM_I(), etc., that, given values for source code file name, function, and line number,
168 * returns an `std::string` equal to what FLOW_UTIL_WHERE_AM_I() would place into an `ostream`.
169 *
170 * For rationale of using #String_view instead of `const char*` for the string args see similar reasoning in
171 * get_last_path_segment() doc header. See also practical instructions on how to performantly obtain these args, in
172 * the doc header for `ARG_file` for FLOW_UTIL_WHERE_AM_I_FROM_ARGS().
173 *
174 * @param file
175 * See `ARG_file` in FLOW_UTIL_WHERE_AM_I_FROM_ARGS().
176 * @param function
177 * Full function name, as from `__FUNCTION__`. See instructions above for max perf.
178 * @param line
179 * Line number, as from `__LINE__`.
180 * @return String `X` (suitable for, for example: `std::cout << X << ": Hi!"`).
181 */
182std::string get_where_am_i_str(String_view file, String_view function, unsigned int line);
183
184} // namespace flow::util
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
Definition: basic_blob.hpp:29
constexpr String_view get_last_path_segment(String_view full_path)
Helper for FLOW_UTIL_WHERE_AM_I() that, given a pointer/length of a string in memory containing a pat...
Definition: util.hpp:54
std::string get_where_am_i_str(String_view file, String_view function, unsigned int line)
Helper for FLOW_UTIL_WHERE_AM_I(), etc., that, given values for source code file name,...
Definition: util.cpp:27
Fine_time_pt chrono_duration_from_now_to_fine_time_pt(const boost::chrono::duration< Rep, Period > &dur)
Helper that takes a non-negative duration of arbitrary precision/period and converts it to Fine_durat...
Definition: util.hpp:42
Fine_duration chrono_duration_to_fine_duration(const boost::chrono::duration< Rep, Period > &dur)
Helper that takes a non-negative duration of arbitrary precision/period and converts it to Fine_durat...
Definition: util.hpp:31
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:410
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:407