Flow 1.0.0
Flow project: Public API.
|
Namespaces | |
namespace | flow |
Catch-all namespace for the Flow project: A collection of various production-quality modules written in modern C++17, originally by ygoldfel. | |
namespace | flow::util |
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module. | |
namespace | flow::util::this_thread |
Short-hand for standard this-thread namespace. | |
Macros | |
#define | FLOW_UTIL_WHERE_AM_I() |
Expands to an ostream fragment X (suitable for, for example: std::cout << X << ": Hi!" ) containing the file name, function name, and line number at the macro invocation's context. More... | |
#define | FLOW_UTIL_WHERE_AM_I_STR() |
Same as FLOW_UTIL_WHERE_AM_I() but evaluates to an std::string . More... | |
#define | FLOW_UTIL_SEMICOLON_SAFE(ARG_func_macro_definition) |
Use this to create a semicolon-safe version of a "void" functional macro definition consisting of at least two statements; or of one statement that would become two statements by appending a semicolon. More... | |
Typedefs | |
using | flow::util::Thread = boost::thread |
Short-hand for standard thread class. More... | |
using | flow::util::Thread_id = Thread::id |
Short-hand for an OS-provided ID of a util::Thread. | |
using | flow::util::Task_engine = boost::asio::io_service |
Short-hand for boost.asio event service, the central class of boost.asio. More... | |
using | flow::util::Strand = Task_engine::strand |
Short-hand for boost.asio strand, an ancillary class that works with Task_engine for advanced task scheduling. | |
using | flow::util::Timer = boost::asio::basic_waitable_timer< Fine_clock > |
boost.asio timer. More... | |
using | flow::util::Auto_cleanup = boost::shared_ptr< void > |
Helper type for setup_auto_cleanup(). | |
using | flow::util::Udp_endpoint = boost::asio::ip::udp::endpoint |
Short-hand for the UDP endpoint (IP/port) type. | |
using | flow::util::Ip_address_v4 = boost::asio::ip::address_v4 |
Short-hand for the IPv4 address type. | |
using | flow::util::Ip_address_v6 = boost::asio::ip::address_v6 |
Short-hand for the IPv6 address type. | |
using | flow::util::Mutex_non_recursive = boost::mutex |
Short-hand for non-reentrant, exclusive mutex. ("Reentrant" = one can lock an already-locked-in-that-thread mutex.) | |
using | flow::util::Mutex_recursive = boost::recursive_mutex |
Short-hand for reentrant, exclusive mutex. | |
using | flow::util::Mutex_shared_non_recursive = boost::shared_mutex |
Short-hand for non-reentrant, shared-or-exclusive mutex. More... | |
using | flow::util::Mutex_noop_shared_non_recursive = boost::null_mutex |
Short-hand for a mutex type equivalent to util::Mutex_shared_non_recursive – except that the lock/unlock mutex ops all do nothing. More... | |
template<typename Mutex > | |
using | flow::util::Lock_guard = boost::unique_lock< Mutex > |
Short-hand for advanced-capability RAII lock guard for any mutex, ensuring exclusive ownership of that mutex. More... | |
template<typename Shared_mutex > | |
using | flow::util::Shared_lock_guard = boost::shared_lock< Shared_mutex > |
Short-hand for shared mode advanced-capability RAII lock guard, particuarly for Mutex_shared_non_recursive mutexes. More... | |
using | flow::util::Lock_guard_non_recursive = boost::unique_lock< Mutex_non_recursive > |
(Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for Mutex_non_recursive mutexes. More... | |
using | flow::util::Lock_guard_recursive = boost::unique_lock< Mutex_recursive > |
(Deprecated given C++1x) Short-hand for advanced-capability RAII lock guard for Mutex_recursive mutexes. More... | |
using | flow::util::Lock_guard_shared_non_recursive_sh = boost::shared_lock< Mutex_shared_non_recursive > |
(Deprecated given C++1x) Short-hand for shared mode advanced-capability RAII lock guard for Mutex_shared_non_recursive mutexes. More... | |
using | flow::util::Lock_guard_shared_non_recursive_ex = boost::unique_lock< Mutex_shared_non_recursive > |
(Deprecated given C++1x) Short-hand for exclusive mode advanced-capability RAII lock guard for Mutex_shared_non_recursive mutexes. More... | |
using | flow::util::Lock_guard_noop_shared_non_recursive_sh = boost::shared_lock< Mutex_noop_shared_non_recursive > |
(Deprecated given C++1x) Equivalent to Lock_guard_shared_non_recursive_sh but applied to Mutex_noop_shared_non_recursive. More... | |
using | flow::util::Lock_guard_noop_shared_non_recursive_ex = boost::unique_lock< Mutex_noop_shared_non_recursive > |
(Deprecated given C++1x) Equivalent to Lock_guard_shared_non_recursive_ex but applied to Mutex_noop_shared_non_recursive. More... | |
Functions | |
template<typename Key , typename Mapped , typename Hash , typename Pred > | |
void | flow::util::swap (Linked_hash_map< Key, Mapped, Hash, Pred > &val1, Linked_hash_map< Key, Mapped, Hash, Pred > &val2) |
Equivalent to val1.swap(val2) . More... | |
template<typename Key , typename Hash , typename Pred > | |
void | flow::util::swap (Linked_hash_set< Key, Hash, Pred > &val1, Linked_hash_set< Key, Hash, Pred > &val2) |
Equivalent to val1.swap(val2) . More... | |
boost::chrono::microseconds | flow::util::time_since_posix_epoch () |
Get the current POSIX (Unix) time as a duration from the Epoch time point. More... | |
template<typename Const_buffer_sequence > | |
std::ostream & | flow::util::buffers_to_ostream (std::ostream &os, const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line=0) |
Writes a multi- or single-line string representation of the provided binary data to an output stream, complete with a printable and hex versions of each byte. More... | |
template<typename Const_buffer_sequence > | |
std::string | flow::util::buffers_dump_string (const Const_buffer_sequence &data, const std::string &indentation, size_t bytes_per_line=0) |
Identical to buffers_to_ostream() but returns an std::string instead of writing to a given ostream . More... | |
template<typename Time_unit , typename N_items > | |
double | flow::util::to_mbit_per_sec (N_items items_per_time, size_t bits_per_item=8) |
Utility that converts a bandwidth in arbitrary units in both numerator and denominator to the same bandwidth in megabits per second. More... | |
template<typename Integer > | |
Integer | flow::util::ceil_div (Integer dividend, Integer divisor) |
Returns the result of the given non-negative integer divided by a positive integer, rounded up to the nearest integer. More... | |
template<typename Cleanup_func > | |
Auto_cleanup | flow::util::setup_auto_cleanup (const Cleanup_func &func) |
Provides a way to execute arbitrary (cleanup) code at the exit of the current block. More... | |
template<typename T > | |
bool | flow::util::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. More... | |
template<typename T > | |
bool | flow::util::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, high) pair. More... | |
template<typename T > | |
bool | flow::util::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, high] pair. More... | |
template<typename T > | |
bool | flow::util::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, high) pair. More... | |
template<typename Container > | |
bool | flow::util::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. More... | |
template<typename Minuend , typename Subtrahend > | |
bool | flow::util::subtract_with_floor (Minuend *minuend, const Subtrahend &subtrahend, const Minuend &floor=0) |
Performs *minuend -= subtrahend , subject to a floor of floor . More... | |
template<typename From , typename To > | |
size_t | flow::util::size_unit_convert (From num_froms) |
Answers the question what's the smallest integer number of To s sufficient to verbatim store the given number of From s?, where From and To are POD types. More... | |
template<typename Map , typename Sequence > | |
void | flow::util::sequence_to_inverted_lookup_map (Sequence const &src_seq, Map *target_map) |
Given a generic sequence (integer -> object) generates a generic map (object -> integer) providing inverse lookup. More... | |
template<typename Map , typename Sequence > | |
void | flow::util::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 value based on the index into the input sequence instead of that index itself. More... | |
template<typename ... T> | |
void | flow::util::ostream_op_to_string (std::string *target_str, T const &... ostream_args) |
Writes to the specified string, as if the given arguments were each passed, via << in sequence, to an ostringstream , and then the result were appended to the aforementioned string variable. More... | |
template<typename ... T> | |
std::string | flow::util::ostream_op_string (T const &... ostream_args) |
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the caller's string . More... | |
template<typename T1 , typename ... T_rest> | |
void | flow::util::feed_args_to_ostream (std::ostream *os, T1 const &ostream_arg1, T_rest const &... remaining_ostream_args) |
"Induction step" version of variadic function template that simply outputs arguments 2+ via << to the given ostream , in the order given. More... | |
template<typename T > | |
void | flow::util::feed_args_to_ostream (std::ostream *os, T const &only_ostream_arg) |
"Induction base" for a variadic function template, this simply outputs given item to given ostream via << . More... | |
template<typename Enum > | |
Enum | flow::util::istream_to_enum (std::istream *is_ptr, Enum enum_default, Enum enum_sentinel, bool accept_num_encoding=true, bool case_sensitive=false, Enum enum_lowest=Enum(0)) |
Deserializes an enum class value from a standard input stream. More... | |
void | flow::util::beautify_chrono_ostream (std::ostream *os) |
Sets certain chrono -related formatting on the given ostream that results in a consistent, desirable output of duration s and certain types of time_point s. More... | |
size_t | flow::util::deep_size (const std::string &val) |
Estimate of memory footprint of the given value, including memory allocated on its behalf – but excluding its shallow sizeof ! – in bytes. More... | |
#define FLOW_UTIL_SEMICOLON_SAFE | ( | ARG_func_macro_definition | ) |
Use this to create a semicolon-safe version of a "void" functional macro definition consisting of at least two statements; or of one statement that would become two statements by appending a semicolon.
There may be other use cases where it might be useful, though none more has come to mind as of this writing. Loosely speaking, IF your sub-statements are always blocks, and you have a "void" functional macro to be used in the typical way (every use is a statement that looks like a function call), and the macro's definition is anything other than an expression with an intentionally missing trailing semicolon, THEN you should probably wrap that would-be macro definition in a FLOW_UTIL_SEMICOLON_SAFE(). However, read on if you want to know rationale and/or formalities.
The following is assumed about every use of this macro; behavior is undefined otherwise.
The following is true about every use of the macro M:
Suppose your macro's value is a series of two or more statements executing in series without braces {}
around the whole thing. Then, in some contexts, invoking that macro as intended might result in unexpected runtime misbehavior that the compiler wouldn't detect. A simple example with two expressions as individual statements:
Granted, if the invoker used braces appropriately around the if
statement body, there'd be no issue, but one cannot always rely on invoker's good style, especially if the macro is part of a public library API. Solution:
One might ask: Why not simply surround the 2+ statements with braces {}
to eliminate the problem more simply? Answer: This actually would turn the use case into the following other problematic use case.
;
trailing macro invocation leads to syntax errorRecall that the premise requires invoker to call your macro M like M();
, meaning they will always put a semicolon after the invocation. Now suppose that doing so will turn one statement (which is M's definition) into two. Another way of putting it: Suppose M's body is already a complete statement, even without the required trailing ;
(and there is no way to make it otherwise; usually [always?] because it ends with a }
). Then in some contexts it'll cause a syntax error. Example:
Removing the ;
from the invocation is no solution. Firstly it'll confuse many editors that will think the "function call" (really macro invocation) is missing the usual semicolon. This might cause incorrect auto-indentation in the file and who knows what else. Code analyzer tools may also be affected. Even ignoring issues where the code is fed into a non-compiler, there are possible flow control problems. In this example it'll attach the else
in the invoking code to the inner if
(from the macro) instead of the outer if
(in the invoking code) as intended. Wrapping the body of CHECK_AND_LOG()
in the proposed wrapper will resolve all stated problems. (Solution code omitted for brevity and obviousness at this point.)
if (false)
and similar) should entirely eliminate any such performance degradation.ARG_func_macro_definition | The intended value of a functional macro, such that the "function" it approximates would have return type void . Behavior is undefined if the value of this parameter ends in a semicolon, or if the value contains a statement that includes another statement within it that is not a block ({ ... } ). (The rules in the last [English] statement may or may not be strictly necessary, but requiring these allows me to generalize/reason more straightforwardly. In any case, one rule is assumed good style anyway, while the other is simply practical in this context.) |
ARG_func_macro_definition
if not for the resulting compile error or unexpected flow control effects detailed above. #define FLOW_UTIL_WHERE_AM_I | ( | ) |
Expands to an ostream
fragment X
(suitable for, for example: std::cout << X << ": Hi!"
) containing the file name, function name, and line number at the macro invocation's context.
It's a functional macro despite taking no arguments to convey that it mimics a free function sans args.
#define FLOW_UTIL_WHERE_AM_I_STR | ( | ) |
Same as FLOW_UTIL_WHERE_AM_I() but evaluates to an std::string
.
It's probably a bit slower as well. Update: In fact, it's probably significantly slower as of this writing, as FLOW_UTIL_WHERE_AM_I() evaluates the <<
ed items at compile-time, while this cannot due to how it's implemented.