Flow 1.0.1
Flow project: Full implementation reference.
util.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
23namespace flow::util
24{
25
26// Free functions: in *_fwd.hpp.
27
28// Template/constexpr implementations.
29
30template<typename Rep, typename Period>
31Fine_duration chrono_duration_to_fine_duration(const boost::chrono::duration<Rep, Period>& dur)
32{
33 using boost::chrono::duration;
34 using boost::chrono::ceil;
35 using User_duration = duration<Rep, Period>;
36
37 assert(dur.count() >= 0);
38 return (dur == User_duration::max()) ? Fine_duration::max() : ceil<Fine_duration>(dur);
39}
40
41template<typename Rep, typename Period>
42Fine_time_pt chrono_duration_from_now_to_fine_time_pt(const boost::chrono::duration<Rep, Period>& dur)
43{
44 using boost::chrono::duration;
45 using boost::chrono::ceil;
46 using User_duration = duration<Rep, Period>;
47
48 assert(dur.count() >= 0);
49 return (dur == User_duration::max())
50 ? Fine_time_pt()
51 : (Fine_clock::now() + ceil<Fine_duration>(dur));
52}
53
55{
56 String_view path(full_path); // This only copies the pointer and length (not the string).
57 // @todo Get it from boost::filesystem or something:
58# ifdef FLOW_OS_WIN
59 constexpr char SEP = '\\';
60# else
61 constexpr char SEP = '/';
62# endif
63 /* Here I just want to do path.rfind(SEP)... but gcc 5.4 (at least) refuses to compile it with the helpful
64 * message "Sorry, not implemented <some words about how there's a loop involved>." Hence I am doing it manually,
65 * and that worked, even though there's a loop involved.
66 * @todo Can probably change it back to rfind() in C++20 which allegedly will make all/most
67 * APIs in <algorithm> constexpr which would trickle down to rfind().
68 * Oh, also, one would think there's a backwards-searching standard function, like strrchr() but given a length
69 * as input, but I couldn't find one. If it existed it'd probably be constexpr (std::strlen() is for example).
70 * Doesn't matter though. */
71 const auto path_sz = path.size();
72 if (path_sz != 0)
73 {
74 const auto path_ptr = path.data();
75 for (auto path_search_ptr = path_ptr + path_sz - 1;
76 path_search_ptr >= path_ptr; --path_search_ptr)
77 {
78 if ((*path_search_ptr) == SEP)
79 {
80 path.remove_prefix((path_search_ptr - path_ptr) + 1);
81 break;
82 }
83 }
84 }
85 // else { Nothing to do. }
86
87 return path;
88} // get_last_path_segment()
89
90} // namespace flow::util
91
92// Macros.
93
94/**
95 * Helper macro, same as FLOW_UTIL_WHERE_AM_I(), but takes the source location details as arguments instead of
96 * grabbing them from `__FILE__`, `__FUNCTION__`, `__LINE__`. Arguably not useful outside of the `flow::util` module
97 * itself.
98 *
99 * ### Perf instructions ###
100 * For best perf results: for all `ARG_...` that you pass in as flow::util::String_view please follow instructions in
101 * doc header of log::Msg_metadata::m_msg_src_file and log::Msg_metadata::m_msg_src_function.
102 *
103 * @param ARG_file
104 * Full file name, as from `__FILE__`, as a `String_view`; or a fragment inside it (e.g., just the
105 * part past the last dir separator if any); depending on which part you'd prefer ultimately printed.
106 * @param ARG_function
107 * Full function name, as from `__FUNCTION__`, as a `String_view` (recommended for perf) or `const char*`.
108 * @param ARG_line
109 * Line number, as from `__LINE__`.
110 * @return `ostream` fragment `X` (suitable for, for example: `std::cout << X << ": Hi!"`).
111 */
112#define FLOW_UTIL_WHERE_AM_I_FROM_ARGS(ARG_file, ARG_function, ARG_line) \
113 ARG_file << ':' << ARG_function << '(' << ARG_line << ')'
114
115/**
116 * Helper macro, same as #FLOW_UTIL_WHERE_AM_I_FROM_ARGS(), but results in a list of comma-separated, instead of
117 * `<<` separated, arguments, although they are still to be passed to an `ostream` with exactly the same semantics
118 * as the aforementioned macro.
119 *
120 * ### Perf instructions ###
121 * See doc header for FLOW_UTIL_WHERE_AM_I_FROM_ARGS().
122 *
123 * @param ARG_file
124 * See FLOW_UTIL_WHERE_AM_I_FROM_ARGS().
125 * @param ARG_function
126 * See FLOW_UTIL_WHERE_AM_I_FROM_ARGS().
127 * @param ARG_line
128 * See FLOW_UTIL_WHERE_AM_I_FROM_ARGS().
129 * @return Exactly the same as FLOW_UTIL_WHERE_AM_I_FROM_ARGS() but with commas instead of `<<`.
130 */
131#define FLOW_UTIL_WHERE_AM_I_FROM_ARGS_TO_ARGS(ARG_file, ARG_function, ARG_line) \
132 ::flow::util::get_last_path_segment(ARG_file), ':', ARG_function, '(', ARG_line, ')'
133
134/**
135 * Helper macro: like FLOW_UTIL_WHERE_AM_I(), with a major relative strength -- its replacement is a string literal --
136 * and two differences: the function name must be supplied verbatim as an arg; and the source file name
137 * will contain the entire path as opposed to a massaged version with just the file-name component.
138 * The key is that the function name arg is not to be a string: it is *stringified* to get the string.
139 *
140 * Nevertheless, in perf-sensitive scenarios, this may well be worth it. For now we keep it in a detail/ header
141 * for use internally to Flow; we did in fact need this in flow::error.
142 *
143 * Other than the aforementioned difference and mild formatting tweaks for cosmetics (as of this writing an added
144 * space), the format of the replacement's contents is identical to that from FLOW_UTIL_WHERE_AM_I().
145 *
146 * ### Rationale ###
147 * Why need `ARG_function`? Why not simply use `__FUNCTION__` internally? Answer: Despite its similar look
148 * to `__FILE__`, actually `__FUNCTION__` is *not* a macro: it is an identifier (that refers to a `const char*`).
149 * The preprocessor knows what file (and line) it's scanning; but it has no idea what func it's scanning;
150 * that's only known at a later stage of compilation. So long story short: `__FUNCTION__` is not replaced
151 * by a string literal and thus cannot be used to compose a string literal by compile-time concatenation.
152 *
153 * (`constexpr` sweetness can be used for an otherwise compile-time-determined value; but we promised a literal
154 * here. `constexpr`ness is outside our scope. Though perhaps see FLOW_UTIL_WHERE_AM_I_FROM_ARGS() for that.)
155 *
156 * @param ARG_function
157 * Informally this is something akin to `ARG_function` to FLOW_ERROR_EXEC_AND_THROW_ON_ERROR().
158 * Formally this can be anything; it will be stringified via `#ARG_function` and output as the function name.
159 * (Do not attempt to pass here the name of a string-typed variable; that probably won't do
160 * what you want. E.g., if you invoke `FLOW_UTIL_WHERE_AM_I_LITERAL(func_name)`, and `func_name`
161 * is an `std::string` with a function name, then the macro replacement will be
162 * `"/some/file.cpp:func_name(332)"` --
163 * without `func_name` getting replaced by the contents of your `func_name` variable or whatever.)
164 * @return A string literal containing file name (and path; from `__FILE__`), function name given, and
165 * line number (from `__LINE__`).
166 * The string literal will be in the form `"stuff" "more stuff" "more stuff"` (etc.). There will be
167 * no surrounding parentheses (in case you want to compile-time-concatenate to even more literal segments).
168 */
169#define FLOW_UTIL_WHERE_AM_I_LITERAL(ARG_function) \
170 FLOW_UTIL_WHERE_AM_I_LITERAL_IMPL_OUTER(ARG_function, __LINE__)
171
172/**
173 * Impl helper macro from FLOW_UTIL_WHERE_AM_I_LITERAL(). This intermediate between
174 * that guy and the "true" impl macro FLOW_UTIL_WHERE_AM_I_LITERAL_IMPL_INNER() is needed in order for the
175 * preprocessor to substitute `__LINE__` instead of simply stringifying it as `"__LINE__"`.
176 *
177 * @param ARG_function
178 * See FLOW_UTIL_WHERE_AM_I_LITERAL().
179 * @param ARG_line
180 * Literally `__LINE__`.
181 */
182#define FLOW_UTIL_WHERE_AM_I_LITERAL_IMPL_OUTER(ARG_function, ARG_line) \
183 FLOW_UTIL_WHERE_AM_I_LITERAL_IMPL_INNER(ARG_function, ARG_line)
184
185/**
186 * Impl helper macro from FLOW_UTIL_WHERE_AM_I_LITERAL(). This is the real impl; see also
187 * FLOW_UTIL_WHERE_AM_I_LITERAL_IMPL_OUTER().
188 *
189 * @param ARG_function
190 * See FLOW_UTIL_WHERE_AM_I_LITERAL().
191 * @param ARG_line
192 * The line number integer as from `__LINE__`.
193 */
194#define FLOW_UTIL_WHERE_AM_I_LITERAL_IMPL_INNER(ARG_function, ARG_line) \
195 __FILE__ ": " #ARG_function "(" #ARG_line ")"
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
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