Flow 1.0.1
Flow project: Full implementation reference.
Namespaces | Macros | Typedefs | Functions
util_fwd.hpp File Reference
#include "flow/util/detail/util_fwd.hpp"
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/thread/null_mutex.hpp>
#include <iostream>
#include <memory>

Go to the source code of this file.

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. More...
 
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. More...
 
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(). More...
 
using flow::util::Udp_endpoint = boost::asio::ip::udp::endpoint
 Short-hand for the UDP endpoint (IP/port) type. More...
 
using flow::util::Ip_address_v4 = boost::asio::ip::address_v4
 Short-hand for the IPv4 address type. More...
 
using flow::util::Ip_address_v6 = boost::asio::ip::address_v6
 Short-hand for the IPv6 address type. More...
 
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.) More...
 
using flow::util::Mutex_recursive = boost::recursive_mutex
 Short-hand for reentrant, exclusive mutex. More...
 
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 Tos sufficient to verbatim store the given number of Froms?, 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 durations and certain types of time_points. 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...
 

Macro Definition Documentation

◆ FLOW_UTIL_SEMICOLON_SAFE

#define FLOW_UTIL_SEMICOLON_SAFE (   ARG_func_macro_definition)
Value:
do \
{ \
ARG_func_macro_definition \
} \
while (false)

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.

Formal use case requirements

The following is assumed about every use of this macro; behavior is undefined otherwise.

  • The macro's invocation is the entire definition of another macro, M.
  • M is a functional macro taking 0 or more arguments (possibly variadic).
  • The following is true about every use of the macro M:

    • The invocation is written as if M is a free function in the C language, and it is being "called" as the entirety of the statement containing that "call." That is, it must look like this:
    M(...arg 1 value..., ...arg 2 value..., ...more...); // (Or however many args M actually allows.)

Known use case 1: Macro definition is 2+ statements

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:

#define DOUBLE_AND_PRINT(arg) \
arg *= 2; // Statement 1. \
cout << arg // Statement 2. Note the lacking trailing semicolon (invoker must supply it after "call"). \
DOUBLE_AND_PRINT(x); // No problem. Both statements execute.
if (some_flag)
DOUBLE_AND_PRINT(x); // UNINTENDED BEHAVIOR! Statement 2 executes regardless of some_flag!

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:

#define DOUBLE_AND_PRINT(arg) \
FLOW_UTIL_SEMICOLON_SAFE \
( \
arg *= 2; // Statement 1. \
cout << arg; // Statement 2. Note necessity for trailing semicolon. \
)
DOUBLE_AND_PRINT(x); // No problem. Both statements execute.
if (some_flag)
DOUBLE_AND_PRINT(x); // No problem. Both statements execute; or neither one does.

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.

Known use case 2: Required semicolon ; trailing macro invocation leads to syntax error

Recall 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:

#define CHECK_AND_LOG(msg) \
if (filter()) \
{ \
log(msg); \
} // Semicolon will always be added right here.
CHECK_AND_LOG("Hello."); // No problem. The empty ; statement introduced is harmless.
if (terminating)
CHECK_AND_LOG(msg); // SYNTAX ERROR! The empty ; will make the `else` illegal.
else
exit();

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.)

Note
Adding this wrapper would slightly adversely affect performance in the complete absence of compiler optimization, but even the most basic optimizer (one capable of eliminating if (false) and similar) should entirely eliminate any such performance degradation.
Parameters
ARG_func_macro_definitionThe 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.)
Returns
Code to be used as the entire definition of a macro whose definition would have been ARG_func_macro_definition if not for the resulting compile error or unexpected flow control effects detailed above.

Definition at line 1079 of file util_fwd.hpp.

◆ FLOW_UTIL_WHERE_AM_I

#define FLOW_UTIL_WHERE_AM_I ( )
Value:
(::flow::util::String_view(__FILE__, sizeof(__FILE__) - 1)), \
::flow::util::String_view(__FUNCTION__, sizeof(__FUNCTION__) - 1), \
__LINE__)
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
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
#define FLOW_UTIL_WHERE_AM_I_FROM_ARGS(ARG_file, ARG_function, ARG_line)
Helper macro, same as FLOW_UTIL_WHERE_AM_I(), but takes the source location details as arguments inst...
Definition: util.hpp:112

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.

Performance

The items <<ed onto the target ostream are each evaluated at compile-time. This includes the expression involving flow::util::get_last_path_segment() which is constexpr.

Definition at line 951 of file util_fwd.hpp.

◆ FLOW_UTIL_WHERE_AM_I_STR

#define FLOW_UTIL_WHERE_AM_I_STR ( )
Value:
(::flow::util::String_view(__FILE__, sizeof(__FILE__) - 1)), \
::flow::util::String_view(__FUNCTION__, sizeof(__FUNCTION__) - 1), \
__LINE__)
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

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.

flow::util::get_where_am_i_str() is too clever to become a constexpr function, even if it were radically rewritten, so this macro evaluates to a partially runtime-computed expression. Hence the note just above about perf.

Todo:
See if FLOW_UTIL_WHERE_AM_I_STR() can be coaxed into a compile-time expression after all. It is used in quite a lot of frequently executed code, namely at the top of most Flow (and Flow-like) APIs that can emit errors. See notes inside flow::util::get_where_am_i_str() on this as of this writing.

Definition at line 971 of file util_fwd.hpp.