Flow 2.0.0
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
24#include <boost/lexical_cast.hpp>
25#include <boost/algorithm/string.hpp>
26
27namespace flow::util
28{
29
30// Types.
31
32/**
33 * An empty interface, consisting of nothing but a default `virtual` destructor, intended as a boiler-plate-reducing
34 * base for any other (presumably `virtual`-method-having) class that would otherwise require a default `virtual`
35 * destructor.
36 *
37 * Usually, if you have a base class `C` at the top of a `virtual`-method-having hierarchy, then it needs a `virtual`
38 * destructor, even if it is `= default` or `{}`. Otherwise, trying to delete an object of subclass `C2 : public C`
39 * via a `C*` pointer will fail to call destructor `~C2()` -- which may not be empty, causing leaks and so on.
40 * Declaring `~C()` and its empty implementation is surprisingly verbose. So, instead, don't; and `public`ly derive
41 * from Null_interface.
42 *
43 * It is particularly useful for interface classes.
44 */
46{
47public:
48 // Destructor.
49
50 /**
51 * Boring `virtual` destructor.
52 *
53 * Why is it pure? Main reason: Then Null_interface becomes abstract and cannot be itself instantiated, which is good.
54 * Otherwise we'd need a `protected` constructor or something to prevent it.
55 *
56 * I (ygoldfel) actually thought this means a subclass *has* to now define a body (even if merely `= default` or
57 * `{}`): but no: the compiler will (and must) generate an empty (and, because of us, `virtual`) destructor for any
58 * subclass that doesn't explicitly define one. A destructor isn't a regular method, so that's how it works.
59 * There will not be a linker error.
60 */
61 virtual ~Null_interface() = 0;
62};
63
64/**
65 * Useful as a no-unique-address private member to make a type noncopyable while keeping that type an aggregate
66 * (can be direct-initialized).
67 *
68 * So you can do: `[[no_unique_address]] flow::util::Noncopyable m_nc{};`.
69 *
70 * ### Rationale ###
71 * The usual technique of deriving from `boost::noncopyable` disables aggregateness. In C++20 declaring
72 * a `= delete` copy ctor also disables it. This trick still works though.
73 */
75{
76 // Constructors/destructor.
77
78 /// Makes it possible to instantiate.
79 Noncopyable() = default;
80 /// Forbid copying.
81 Noncopyable(const Noncopyable&) = delete;
82
83 // Methods.
84
85 /// Forbid copying.
86 void operator=(const Noncopyable&) = delete;
87};
88
89/**
90 * A simple RAII-pattern class template that, at construction, sets the specified location in memory to a specified
91 * value, memorizing the previous contents; and at destruction restores the value. E.g.:
92 *
93 * ~~~
94 * thread_local int s_this_thread_val;
95 * ...
96 * {
97 * Scoped_setter<int> setter{&s_this_thread_val, 75}; // Set it to 75 and memorize (whatever).
98 * ...
99 * {
100 * Scoped_setter<int> setter{&s_this_thread_val, 125}; // Set it to 125 and memorize 75.
101 * ...
102 * } // Restored from 125 to 75.
103 * ...
104 * } // Restored from (probably) 75 to (whatever).
105 * ~~~
106 *
107 * The object is movable, not copyable (which is similar to `unique_ptr`) to prevent "double-restore." Related:
108 * one can easily return customized auto-setter/restorers:
109 *
110 * ~~~
111 * thread_local Widget s_widget;
112 * auto widget_setter_auto(Widget&& widget_moved)
113 * {
114 * return flow::util::Scoped_setter<Widget>{&s_widget, std::move(widget_moved)};
115 * }
116 * ...
117 * { // Later, some block: Set s_widget. Code here doesn't even know/care a Scoped_setter is involved.
118 * const auto setter_auto = widget_setter_auto({ ...widget-init... });
119 * ...
120 * } // Restore s_widget.
121 * ~~~
122 *
123 * ### Thready safety ###
124 * This is a simple object: it just performs a few assignments without any added
125 * concurrency protection. If the memory location can be accessed simultaneously by other threads, watch out.
126 *
127 * In particular it's a good fit for thread-local locations: `&X`, where `X` is declared `thread_local`, or
128 * `X == *(P.get())` where `P` is a `boost::thread_specific_ptr`.
129 *
130 * @tparam Value
131 * The stored type, which must be move-assignable and move-constructible.
132 * All `Value` writes are performed using exclusively these operations.
133 * Informally: For best performance when `Value` is a heavy-weight type, these operations should be
134 * be written to be light-weight, such as in terms of swapping a few scalars.
135 * In particular this is already the case for all STL-compliant container types.
136 *
137 * @internal
138 * ### Implementation ###
139 * An alternative implementation, which could even be reduced to just an alias, would have used `unique_ptr`.
140 * However in this case I (ygoldfel) wanted maximum control for perf. The use case originally driving this was
141 * the thread-local verbosity override: log::Config::this_thread_verbosity_override_auto(). flow::log is fairly
142 * paranoid about performance, in general, although admittedly this particular call isn't necessarily ubiquitous.
143 */
144template<typename Value>
146{
147public:
148 // Constructors/destructor.
149
150 /**
151 * Post-condition: `*target` contains was `val_src_moved` contained at ctor entry; and the destructor invocation shall
152 * reverse this, so that `*target` is restored to its value at entry.
153 *
154 * `*this` cannot be copied, but it can be moved. As a result, it is guaranteed that the aforementioned destructor
155 * will execute exactly once; however it can be move-constructed-from-`*this` other Scope_setter's destructor,
156 * while our own dtor therefore is a no-op.
157 *
158 * @param target
159 * The target object that shall be set to `val_src_moved` now and restored in our, or moved-object's, dtor.
160 * The current value of `*target` is saved internally via assignment of `move(*target)`.
161 * Behavior undefined (assertion may trip) if null.
162 * @param val_src_moved
163 * Value to save to `*target` immediately, via assignment of `move(val_src_moved)`.
164 */
165 explicit Scoped_setter(Value* target, Value&& val_src_moved);
166
167 /**
168 * Move constructor: `*this` acts as `src_moved` would-have, while `src_moved` becomes a no-op object permanently.
169 *
170 * @param src_moved
171 * Source object. Its destructor shall do nothing after this returns.
172 */
173 Scoped_setter(Scoped_setter&& src_moved);
174
175 /// Prohibit copying: for each `explicit` ctor invocation, there shall be exactly 1 non-no-op dtor invocation.
176 Scoped_setter(const Scoped_setter&) = delete;
177
178 /**
179 * Restores `*target` (from main ctor) to its value at entry to said ctor; or does nothing if `*this` has been
180 * moved-from via the move ctor.
181 */
183
184 // Methods.
185
186 /// Prohibit copying (see `delete`d copy ctor).
188
189 /// Prohibit modifying existing `*this`; except that moving-from is enabled via the move ctor.
191
192private:
193 // Data.
194
195 /// Target object location; see ctors; if null then this is a moved-from Scoped_setter that intentionally no-ops.
197
198 /// If and only if #m_target_or_null is non-null, this saves `*m_target_or_null`. Otherwise meaningless.
200}; // class Scoped_setter
201
202// Template implementations.
203
204// Scoped_setter template implementations.
205
206template<typename Value>
207Scoped_setter<Value>::Scoped_setter(Value* target, Value&& val_src_moved) :
208 m_target_or_null(target),
209 m_saved_value(std::move(*m_target_or_null))
210{
211 *m_target_or_null = std::move(val_src_moved);
212}
213
214template<typename Value>
215Scoped_setter<Value>::Scoped_setter(Scoped_setter&& src_moved) : // =default might work fine but to be clear/certain:
216 m_target_or_null(src_moved.m_target_or_null),
217 m_saved_value(std::move(src_moved.m_saved_value))
218{
219 assert(m_target_or_null && "Should not be moving-from a thing that has already been moved-from.");
220
221 src_moved.m_target_or_null = nullptr;
222 // As promised: Now src_moved's dtor will no-op.
223}
224
225template<typename Value>
227{
228 if (m_target_or_null)
229 {
230 *m_target_or_null = std::move(m_saved_value);
231 }
232 // else { `*this` must have been moved-from. No-op. }
233}
234
235// Free function template (and/or constexpr) implementations.
236
237template<typename Time_unit, typename N_items>
238double to_mbit_per_sec(N_items items_per_time, size_t bits_per_item)
239{
240 /* Let there be U/W seconds per Time_unit. Then the following holds:
241 *
242 * items_per_time items/Time_units * W/U Time_units/second * bits_per_item bits/item
243 * * 1/(1000*1000) megabits/bits
244 * = items_per_time * W / U * bits_per_item / 1000 / 1000 megabits/second.
245 *
246 * Notice the units work out. W and U are conveniently available in Time_unit::period, which is a boost::ratio. */
247
248 return
249 /* This zealously converts everything to double ASAP to avoid overflow. Could probably speed things up a bit
250 * by postponing some of those conversions until after some integer multiplications, but then overflows could
251 * creep in. It's best not to assume too much about the values of den and num, as this function is meant to
252 * be rather adaptable to various situations. I did try to avoid unnecessary divisions though in favor of
253 * multiplications, sort of guessing the latter are faster. Or not... *shrug*. */
254 double(items_per_time) * double(bits_per_item) * double(Time_unit::period::den)
255 / (double(Time_unit::period::num) * double(1000 * 1000));
256}
257
258template<typename Integer, typename Integer2>
259constexpr Integer ceil_div(Integer dividend, Integer2 divisor)
260{
261 // ceil(A : B) = (A + B - 1) / B, where : is floating point division, while / is integer division.
262 static_assert(std::is_integral_v<Integer>, "ceil_div<T, T2>: T must be an integer type.");
263 static_assert(std::is_integral_v<Integer2>, "ceil_div<T, T2>: T2 must be an integer type.");
264
265 // assert(dividend >= 0); // Cannot do that (or throw in C++17, can in C++20; @todo) in constexpr.
266 // assert(divisor > 0); // Ditto.
267
268 return (dividend + static_cast<Integer>(divisor) - static_cast<Integer>(1)) / static_cast<Integer>(divisor);
269 /* (Could one do further bitwise trickery? Perhaps but let optimizer do it. Wouldn't optimizer also just
270 * optimize a literal floating-point `ceil(a / b)`? Well, no. Probably not. So we wrote this function.) */
271}
272
273template<typename Integer, typename Integer2>
274constexpr Integer round_to_multiple(Integer dividend, Integer2 unit)
275{
276 return static_cast<Integer>(unit) * ceil_div(dividend, unit);
277}
278
279template<typename T>
280bool in_closed_range(T const & min_val, T const & val, T const & max_val)
281{
282 // This writes "(min_val <= val) && (val <= max_val)" by using only <, to support the greatest number of types.
283 return ((min_val < val) || (!(val < min_val))) &&
284 ((val < max_val) || (!(max_val < val)));
285}
286
287template<typename T>
288bool in_open_closed_range(T const & min_val, T const & val, T const & max_val)
289{
290 // This writes "(min_val < val) && (val <= max_val)" by using only <, to support the greatest number of types.
291 return (min_val < val) &&
292 ((val < max_val) || (!(max_val < val)));
293}
294
295template<typename T>
296bool in_closed_open_range(T const & min_val, T const & val, T const & max_val)
297{
298 // This writes "(val < max_val) && (min_val <= val)" by using only <, to support the greatest number of types.
299 return (val < max_val) &&
300 ((min_val < val) || (!(val < min_val)));
301}
302
303template<typename T>
304bool in_open_open_range(T const & min_val, T const & val, T const & max_val)
305{
306 return (min_val < val) && (val < max_val);
307}
308
309template<typename Container>
310bool key_exists(const Container& container, const typename Container::key_type& key)
311{
312 return container.find(key) != container.end();
313}
314
315template<typename Cleanup_func>
316Auto_cleanup setup_auto_cleanup(const Cleanup_func& func)
317{
318 /* This trick, from shared_ptr or bind Boost docs (if I recall correctly), uses shared_ptr's deleter feature. The
319 * Auto_cleanup gains "ownership" of null pointer, purely for the purpose of running a deleter on it when the object
320 * goes out of scope sometime later. Deleting 0 itself would have been useless no-op, and instead we ignore the null
321 * and simply call user's func(), which is what the goal is.
322 *
323 * Subtlety: shared_ptr docs say the passed-in deleter is saved by copy, so we needn't worry about it disappearing
324 * after we return.
325 *
326 * Subtlety: we need to make a copy (via capture) of func, as there's zero guarantee (and low likelihood in practice)
327 * that func is a valid object at the time cleanup is actually needed (sometime after we return). */
328 return Auto_cleanup{static_cast<void*>(nullptr),
329 [func](void*) { func(); }};
330}
331
332template<typename Minuend, typename Subtrahend>
333bool subtract_with_floor(Minuend* minuend, const Subtrahend& subtrahend, const Minuend& floor)
334{
335 assert(minuend);
336
337 /* Basically just avoid implicit conversions and anything that mind overflow or underflow.
338 * The one underflow we allow is the subtraction of `floor`: doc header says keep `floor` small.
339 * So it's their problem if it's not. */
340
341 const Minuend converted_subtrahend = Minuend{subtrahend};
342
343 // min - sub <= floor <===> min - floor <= sub.
344 if ((*minuend - floor) <= converted_subtrahend)
345 {
346 *minuend = floor;
347 return false;
348 }
349 // else
350 *minuend -= converted_subtrahend;
351 return true;
352}
353
354template<typename From, typename To>
355size_t size_unit_convert(From num_froms)
356{
357 return ((num_froms * sizeof(From)) + sizeof(To) - 1) / sizeof(To);
358}
359
360template<typename... T>
361void feed_args_to_ostream(std::ostream* os, T&&... ostream_args)
362{
363 (*os << ... << std::forward<T>(ostream_args));
364}
365
366template<typename... T>
367void ostream_op_to_string(std::string* target_str, T&&... ostream_args)
368{
369 using std::flush;
370
371 /* Pushes characters directly onto an `std::string`, instead of doing so into an `ostringstream` and then getting it
372 * by copy via `ostringstream::copy()`. This is for performance and may make a large difference
373 * overall, if this is used in logging for example. However, Thread_local_string_appender accomplishes
374 * better performance still and some other features. */
375 String_ostream os{target_str};
376 feed_args_to_ostream(&(os.os()), std::forward<T>(ostream_args)...);
377 os.os() << flush;
378}
379
380template<typename... T>
381std::string ostream_op_string(T&&... ostream_args)
382{
383 using std::string;
384
385 string result;
386 ostream_op_to_string(&result, std::forward<T>(ostream_args)...);
387 return result;
388}
389
390template<typename Map, typename Sequence>
392 (Sequence const & src_seq, Map* target_map,
393 const Function<typename Map::mapped_type (size_t)>& idx_to_map_val_func)
394{
395 size_t idx = 0;
396 for (const auto& src_element : src_seq)
397 {
398 (*target_map)[src_element] = idx_to_map_val_func(idx);
399 ++idx;
400 }
401}
402
403template<typename Map, typename Sequence>
404void sequence_to_inverted_lookup_map(Sequence const & src_seq, Map* target_map)
405{
406 sequence_to_inverted_lookup_map(src_seq, target_map, [](size_t idx) -> size_t
407 {
408 return idx;
409 });
410}
411
412template<typename Const_buffer_sequence>
413std::ostream& buffers_to_ostream(std::ostream& os,
414 const Const_buffer_sequence& data,
415 const std::string& indentation,
416 size_t bytes_per_line)
417{
418 using boost::io::ios_fill_saver;
419 using boost::io::ios_flags_saver;
420 using boost::io::ios_width_saver;
421 using boost::asio::buffers_iterator;
422 using std::isprint;
423
424 /* This sweet type will iterate over the buffer sequence (jumping between contained buffers, if ther are > 1).
425 * If `Bufs_iter it`, then *it is of type uint8_t. */
426 using Bufs_iter = buffers_iterator<Const_buffer_sequence, uint8_t>;
427
428 constexpr size_t BYTES_PER_LINE_DEFAULT = 16;
429 bool single_line_mode = false;
430 if (bytes_per_line == 0)
431 {
432 bytes_per_line = BYTES_PER_LINE_DEFAULT;
433 }
434 else if (bytes_per_line == size_t(-1))
435 {
436 /* Firstly just pretend exactly the bytes in the whole input = "max" bytes per line.
437 * This accomplishes the bulk of what "single-line mode" means. */
438 bytes_per_line = buffer_size(data);
439 // A bit slow potentially to need to enumerate all scattered buffers. Eh. Contract said we should be assumed slow.
440
441 // The rest of what it means is lacking a newline at the end in single-line mode. So just remember that part.
442 single_line_mode = true;
443 }
444
445 // Ensure format settings return to their previous values subsequently.
446 ios_flags_saver flags_saver{os};
447 ios_fill_saver fill_saver{os};
448 ios_width_saver width_saver{os};
449
450 /* Set formatting and output numeric value (hex) of first byte.
451 * @todo Is there a way to write this with manipulators too? */
452 os.setf(std::ios::right | std::ios::hex, std::ios::adjustfield | std::ios::basefield);
453 os << std::setfill('0');
454
455 const Bufs_iter end_byte_it = Bufs_iter::end(data);
456 for (Bufs_iter cur_byte_it = Bufs_iter::begin(data);
457 cur_byte_it != end_byte_it;
458 /* Advancing of cur_byte_it occurs within body of loop. */)
459 {
460 // The for() loop around us guarantees there is at least this first byte. Print the numeric value.
461 os << indentation << '['
462 << std::setw(2) << int(*cur_byte_it); // Numeric value in hex.
463
464 // Repeat for remaining bytes left in this line. Stop at bytes/line limit, or if reached end of buffers.
465 size_t n_bytes_printed;
466 for ((n_bytes_printed = 1), ++cur_byte_it; // Account for printing that first byte above.
467 (n_bytes_printed != bytes_per_line) && (cur_byte_it != end_byte_it);
468 ++cur_byte_it, ++n_bytes_printed)
469 {
470 os << ' ' << std::setw(2) << int(*cur_byte_it); // Numeric value in hex.
471 }
472
473 // Spaces as if rest of line still had a few ghost values to print (space + 2 spaces for the hex digits).
474 for (size_t n_bytes_printed_including_padding = n_bytes_printed;
475 n_bytes_printed_including_padding != bytes_per_line;
476 ++n_bytes_printed_including_padding)
477 {
478 os << " ";
479 }
480
481 // Backtrack and print those same bytes -- this time as printable characters (when printable, else dots).
482 cur_byte_it -= n_bytes_printed;
483
484 os << '|';
485 for (size_t n_chars_printed = 0;
486 n_chars_printed != n_bytes_printed;
487 ++cur_byte_it, ++n_chars_printed)
488 {
489 char c = *cur_byte_it;
490 os << (isprint(c) ? c : '.');
491 }
492 os << ']';
493 if (!single_line_mode)
494 {
495 os << '\n';
496 }
497 } // for (cur_byte_it)
498
499 return os;
500
501 // The formatting changes will be restored here as the savers exit scope.
502} // buffers_to_ostream()
503
504template<typename Const_buffer_sequence>
505std::string buffers_dump_string(const Const_buffer_sequence& data, const std::string& indentation,
506 size_t bytes_per_line)
507{
508 using std::flush;
509 using std::string;
510
511 // See comment in ostream_op_to_string() which applies here too (re. perf).
512
513 string target_str;
514 String_ostream os{&target_str};
515 buffers_to_ostream(os.os(), data, indentation, bytes_per_line);
516 os.os() << flush;
517
518 return target_str;
519}
520
521template<typename Enum>
522Enum istream_to_enum(std::istream* is_ptr, Enum enum_default, Enum enum_sentinel,
523 bool accept_num_encoding, bool case_sensitive,
524 Enum enum_lowest)
525{
526 using boost::lexical_cast;
527 using boost::bad_lexical_cast;
528 using boost::algorithm::equals;
529 using boost::algorithm::is_iequal;
530 using std::locale;
531 using std::string;
532 using std::isdigit;
533 using std::isalnum;
534 using Traits = std::char_traits<char>;
535 using enum_t = std::underlying_type_t<Enum>;
536
537 // Reminder: There are various assumptions about Enum this takes for granted; behavior undefined otherwise.
538
539 assert(enum_t(enum_lowest) >= 0); // Otherwise we'd have to allow '-' (minus sign), and we'd... just rather not.
540 auto& is = *is_ptr;
541 const is_iequal i_equal_func{locale::classic()};
542
543 // Read into `token` until (and not including) the first non-alphanumeric/underscore character or stream end.
544 string token;
545 char ch;
546 while (((ch = is.peek()) != Traits::eof()) && (isalnum(ch) || (ch == '_')))
547 {
548 token += ch;
549 is.get();
550 }
551
552 Enum val = enum_default;
553
554 if (!token.empty())
555 {
556 if (accept_num_encoding && isdigit(token.front())) // Hence ostream<< shouldn't serialize a digit-leading value.
557 {
558 enum_t num_enum;
559 try
560 {
561 num_enum = lexical_cast<enum_t>(token);
562 // This assumes a vanilla enum integer value ordering.
563 if ((num_enum >= enum_t(enum_sentinel) || (num_enum < enum_t(enum_lowest))))
564 {
565 num_enum = enum_t(enum_default);
566 }
567 val = Enum{num_enum};
568 }
569 catch (const bad_lexical_cast&)
570 {
571 assert(val == enum_default);
572 }
573 } // if (accept_num_encoding && isdigit())
574 else // if (!(accept_num_encoding && isdigit()))
575 {
576 enum_t idx;
577 // This assumes a vanilla enum integer value ordering within this [closed range].
578 for (idx = enum_t(enum_lowest); idx != enum_t(enum_sentinel); ++idx)
579 {
580 const auto candidate = Enum{idx};
581 /* Note -- lexical_cast<string>(Enum) == (operator<<(ostringstream&, Enum)).str() -- the symbolic
582 * encoding of Enum (as we promised to accept, case-[in]sensitively), not the numeric encoding. The numeric
583 * encoding is checked-for in the `if (accept_num_encoding...)` branch above using a non-looping technique. */
584 if (case_sensitive ? equals(token, lexical_cast<string>(candidate))
585 : equals(token, lexical_cast<string>(candidate), i_equal_func))
586 {
587 val = candidate;
588 break;
589 }
590 }
591 assert((idx != enum_t(enum_sentinel)) || (val == enum_default));
592 } // else if (!(accept_num_encoding && isdigit()))
593 } // if (!token.empty())
594
595 return val;
596} // istream_to_enum()
597
598} // namespace flow::util
An empty interface, consisting of nothing but a default virtual destructor, intended as a boiler-plat...
Definition: util.hpp:46
virtual ~Null_interface()=0
Boring virtual destructor.
A simple RAII-pattern class template that, at construction, sets the specified location in memory to ...
Definition: util.hpp:146
~Scoped_setter()
Restores *target (from main ctor) to its value at entry to said ctor; or does nothing if *this has be...
Definition: util.hpp:226
Value m_saved_value
If and only if m_target_or_null is non-null, this saves *m_target_or_null. Otherwise meaningless.
Definition: util.hpp:199
Scoped_setter(const Scoped_setter &)=delete
Prohibit copying: for each explicit ctor invocation, there shall be exactly 1 non-no-op dtor invocati...
Scoped_setter & operator=(const Scoped_setter &)=delete
Prohibit copying (see deleted copy ctor).
Value * m_target_or_null
Target object location; see ctors; if null then this is a moved-from Scoped_setter that intentionally...
Definition: util.hpp:196
Scoped_setter(Value *target, Value &&val_src_moved)
Post-condition: *target contains was val_src_moved contained at ctor entry; and the destructor invoca...
Definition: util.hpp:207
Scoped_setter & operator=(Scoped_setter &&)=delete
Prohibit modifying existing *this; except that moving-from is enabled via the move ctor.
Similar to ostringstream but allows fast read-only access directly into the std::string being written...
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
Definition: basic_blob.hpp:31
bool in_closed_open_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, given as a [low,...
Definition: util.hpp:296
bool key_exists(const Container &container, const typename Container::key_type &key)
Returns true if and only if the given key is present at least once in the given associative container...
Definition: util.hpp:310
Auto_cleanup setup_auto_cleanup(const Cleanup_func &func)
Provides a way to execute arbitrary (cleanup) code at the exit of the current block.
Definition: util.hpp:316
void sequence_to_inverted_lookup_map(Sequence const &src_seq, Map *target_map, const Function< typename Map::mapped_type(size_t)> &idx_to_map_val_func)
Similar to the 2-arg overload of sequence_to_inverted_lookup_map() but with the ability to store a va...
Definition: util.hpp:392
double to_mbit_per_sec(N_items items_per_time, size_t bits_per_item)
Utility that converts a bandwidth in arbitrary units in both numerator and denominator to the same ba...
Definition: util.hpp:238
std::string buffers_dump_string(const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line)
Identical to buffers_to_ostream() but returns an std::string instead of writing to a given ostream.
Definition: util.hpp:505
Enum istream_to_enum(std::istream *is_ptr, Enum enum_default, Enum enum_sentinel, bool accept_num_encoding, bool case_sensitive, Enum enum_lowest)
Deserializes an enum class value from a standard input stream.
Definition: util.hpp:522
void feed_args_to_ostream(std::ostream *os, T &&... ostream_args)
Function template that simply outputs arguments 2+ via << to the given ostream, in the order given.
Definition: util.hpp:361
bool subtract_with_floor(Minuend *minuend, const Subtrahend &subtrahend, const Minuend &floor)
Performs *minuend -= subtrahend, subject to a floor of floor.
Definition: util.hpp:333
constexpr Integer round_to_multiple(Integer dividend, Integer2 unit)
Returns the smallest integer >= the given integer dividend such that it is a multiple of the given in...
Definition: util.hpp:274
size_t size_unit_convert(From num_froms)
Answers the question what's the smallest integer number of Tos sufficient to verbatim store the given...
Definition: util.hpp:355
bool in_open_open_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, given as a (low,...
Definition: util.hpp:304
bool in_open_closed_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, given as a (low,...
Definition: util.hpp:288
void ostream_op_to_string(std::string *target_str, T &&... ostream_args)
Writes to the specified string, as if the given arguments were each passed, via << in sequence,...
Definition: util.hpp:367
std::ostream & buffers_to_ostream(std::ostream &os, const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line)
Writes a multi- or single-line string representation of the provided binary data to an output stream,...
Definition: util.hpp:413
bool in_closed_range(T const &min_val, T const &val, T const &max_val)
Returns true if and only if the given value is within the given range, inclusive.
Definition: util.hpp:280
boost::shared_ptr< void > Auto_cleanup
Helper type for setup_auto_cleanup().
Definition: util_fwd.hpp:217
std::string ostream_op_string(T &&... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
Definition: util.hpp:381
constexpr Integer ceil_div(Integer dividend, Integer2 divisor)
Returns the result of the given non-negative integer divided by a positive integer,...
Definition: util.hpp:259
Useful as a no-unique-address private member to make a type noncopyable while keeping that type an ag...
Definition: util.hpp:75
Noncopyable(const Noncopyable &)=delete
Forbid copying.
void operator=(const Noncopyable &)=delete
Forbid copying.
Noncopyable()=default
Makes it possible to instantiate.